/* Hero and section patterns A–Q. Each section uses exactly one of these. J–Q and the split H are for sub pages only. */

/* Hero
   Without the scene (no script, reduced motion) it is a plain stack: centred words, then the photo card.
   With .is-scene (set by the script) the stage is pinned for one screen of scrolling: the words sit in the
   middle and the photo card rises over them until it nearly fills the screen. A white copy of the words
   inside the card moves against the card, so only the part of the words over the photo turns white. */

.hero {
  position: relative;
  background: var(--white);
}

.hero__layer {
  position: relative;
  padding: calc(var(--header-h) + var(--page-top)) var(--gutter) 0;
}

/* Side captions: one faint, light line of widely spaced capitals at each side of the words, level with their
   middle and lined up with the page edges (wide screens, where they stay clear of the words) */
.hero__side {
  display: none;
  position: absolute;
  top: 50%;
  margin: 0;
  font-size: var(--fs-caption);
  font-weight: var(--fw-thin);
  line-height: 1;
  letter-spacing: var(--ls-caption);
  color: var(--sage-200);
  white-space: nowrap;
  transform: translateY(-50%);
}

.hero__side--left {
  left: max(var(--gutter), calc((100% - var(--container)) / 2));
}

/* The spacing after the last letter is taken back so the words end exactly on the page edge */
.hero__side--right {
  right: max(var(--gutter), calc((100% - var(--container)) / 2));
  margin-right: calc(var(--ls-caption) * -1);
}

@media (min-width: 1280px) {
  .hero__side {
    display: block;
  }
}

.hero__head {
  position: relative;
  max-width: var(--container-narrow);
  margin-inline: auto;
  text-align: center;
}

/* A 5px white outline on the words (behind the letters), so the cube's lines stop just short of the type; the
   button gets the same clearance from the cube's drawing (main.js) */
.hero__layer:not(.hero__layer--light) .hero__head > * {
  paint-order: stroke fill;
  -webkit-text-stroke: 10px var(--white);
}

.hero__layer:not(.hero__layer--light) .hero__head .btn {
  -webkit-text-stroke: 0;
}

.hero__head .t-lead {
  margin-top: var(--gap-title-lead);
  max-width: 560px;
  margin-inline: auto;
}

.hero__head .btn {
  margin-top: var(--gap-lead-btn);
}

/* While the photo rises the button folds into its round arrow (--fold 0 to 1, main.js): the part left of the circle
   is cut away from the left and the circle moves to the middle. translate is kept apart from transform, which the
   entrance uses. */
.hero.is-scene .hero__head .btn {
  --fold: 0;
  clip-path: inset(0 0 0 calc((100% - var(--btn-h)) * var(--fold)) round var(--r-pill));
  translate: calc((var(--btn-h) / 2 - 50%) * var(--fold)) 0;
}

/* Until the first screen's motion starts (main.js adds .is-ready), the photo card and the side captions (and on the
   sub pages the English title and the photo) stay out of sight like the words, so the page never shows them in their resting places first and then takes them away */
.js:not(.is-ready) .hero__card,
.js:not(.is-ready) .hero__side,
.js:not(.is-ready) .page-head__en,
.js:not(.is-ready) .page-head__photo {
  visibility: hidden;
}

.hero__card {
  width: calc(100% - var(--hero-inset) * 2);
  margin: var(--gap-text-visual) auto var(--sp-8);
  aspect-ratio: 21 / 9;
  border-radius: var(--r-xl);
}

.hero__shade,
.hero__layer--light {
  display: none;
}

.hero.is-scene .hero__stage {
  position: relative;
  height: 100svh;
  overflow: hidden;
}

/* Cube behind the words (main.js draws it): the band between the header and the top of the photo card, nothing
   below. One large, faint wireframe cube turning slowly, a short label at each corner; it leans a little with the
   mouse and fades as the photo card rises. */
.hero__net {
  position: absolute;
  left: 0;
  right: 0;
  top: var(--header-h);
  height: calc(100svh - var(--hero-peek) - var(--header-h));
  width: 100%;
  pointer-events: none;
}

.hero:not(.is-scene) .hero__net {
  display: none;
}

/* The words sit midway between the bottom of the header and the top of the photo card as it first peeks in
   (--hero-peek of the screen; the script starts the card there), so the space above and below them is the same */
.hero.is-scene .hero__layer {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--header-h) var(--gutter) var(--hero-peek);
}

.hero.is-scene .hero__head {
  width: 100%;
}

.hero.is-scene .hero__side {
  top: calc((100% + var(--header-h) - var(--hero-peek)) / 2);
}

/* The photo moves inside the card on every scroll frame; its own layer keeps the card from being repainted */
.hero.is-scene .hero__card img {
  will-change: transform;
}

.hero.is-scene .hero__card {
  position: absolute;
  top: calc(var(--header-h) + var(--sp-3));
  left: var(--hero-inset);
  right: var(--hero-inset);
  bottom: var(--hero-inset);
  width: auto;
  margin: 0;
  aspect-ratio: auto;
  will-change: transform;
}

/* The light layer is the size of the stage: the card's box pushed back out by the card's own insets */
.hero.is-scene .hero__layer--light {
  display: flex;
  inset: auto;
  top: calc((var(--header-h) + var(--sp-3)) * -1);
  left: calc(var(--hero-inset) * -1);
  right: calc(var(--hero-inset) * -1);
  bottom: calc(var(--hero-inset) * -1);
  will-change: transform;
}

.hero.is-scene .hero__shade {
  display: block;
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(17, 25, 39, 0.3) 0%, rgba(17, 25, 39, 0.5) 100%);
}

.hero__layer--light .t-display { color: var(--color-on-dark); }
.hero__layer--light .t-lead { color: var(--color-on-dark-2); }
.hero__layer--light .hero__side { color: var(--color-on-dark-3); }

/* The blank in the title, as wide as the word it holds. Without the script it is one underline under the word;
   with it, every letter sits in its own slot with its own short underline, and grows up out of the slot. */
/* The gap after the blank keeps the last letter's outline off the word that follows */
.hero__blank {
  display: inline-block;
  margin-right: max(6px, 0.1em);
  border-bottom: max(1px, 0.025em) solid var(--color-accent);
}

.hero__blank.has-slots {
  border-bottom: 0;
}

.hero__fill {
  display: inline-block;
  color: var(--color-accent);
}

.hero__slot {
  position: relative;
  display: inline-block;
  clip-path: inset(-0.4em -0.1em 0 -0.1em);
}

.hero__slot::after {
  content: "";
  position: absolute;
  left: 0.03em;
  right: 0.03em;
  bottom: 0;
  height: max(1px, 0.025em);
  border-radius: var(--r-pill);
  background: currentColor;
}

.hero__letter {
  display: inline-block;
}

.hero__layer--light .hero__fill {
  color: var(--green-400);
}

.hero__layer--light .hero__blank {
  border-bottom-color: var(--green-400);
}


@media (max-width: 768px) {
  .hero__card {
    aspect-ratio: 4 / 5;
    margin-bottom: var(--sp-7);
  }
}

/* A. Statement: turns navy with white words while it sits in the middle of the screen (.is-lit, set by the script) */

.sec-statement .section__head {
  max-width: 880px;
}

/* Home statement with several sentences (data-phrases): they share one place; without the script only the first shows */
.phrases {
  display: grid;
}

/* A shorter sentence sits in the middle of the shared place, not at its top */
.phrase {
  grid-area: 1 / 1;
  align-self: center;
}

.char {
  display: inline-block;
}

/* Typewriter (home process, main.js): letters are hidden until typed; the last typed letter carries a blinking caret */
.process.is-typewriter .t-h3 .char,
.process.is-typewriter .t-body .char {
  visibility: hidden;
}

.process.is-typewriter .t-h3 .char.is-typed,
.process.is-typewriter .t-body .char.is-typed {
  visibility: visible;
}

.char.is-caret {
  position: relative;
}

.char.is-caret::after {
  content: "";
  position: absolute;
  top: 0.1em;
  bottom: 0.1em;
  right: -3px;
  width: 2px;
  background: var(--color-accent);
  animation: caret-blink 1s steps(1) infinite;
}

@keyframes caret-blink {
  50% { opacity: 0; }
}

.phrase + .phrase {
  display: none;
}

.sec-statement.is-scene .phrase + .phrase {
  display: block;
}

/* With the script, the section is one screen plus half a screen per sentence, and the words are placed by the
   script in the middle of whatever part of the section is on screen (translateY on the container) */
.sec-statement.is-scene {
  height: calc(100svh + 45svh + var(--phrase-count, 3) * 50svh);
  min-height: 0;
  padding-block: 0;
  overflow: hidden;
}

.sec-statement.is-scene > .container {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  will-change: transform;
}

/* Touch screens scroll natively, and words moved by the script on each scroll event trail the finger by a frame and
   shake; there the browser holds the tree and the words on screen instead (sticky, both one screen tall, the words
   pulled up over the tree's height so they sit on it; pulling the words, not the tree, lets the tree leave with the
   section). The words stand in the middle, or at 36% on a phone held
   upright, as the script would place them. */
.sec-statement.is-scene.is-sticky {
  overflow: clip;
}

.sec-statement.is-scene.is-sticky .statement-tree {
  position: sticky;
  top: 0;
  bottom: auto;
  will-change: auto;
}

.sec-statement.is-scene.is-sticky > .container {
  position: sticky;
  top: 0;
  margin-top: -100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 100svh;
  will-change: auto;
}

@media (max-width: 599px) and (orientation: portrait) {
  .sec-statement.is-scene.is-sticky > .container {
    padding-bottom: 28svh;
  }
}

.sec-statement {
  transition: background-color var(--dur-bg) var(--ease-inout);
}

/* The title intro (main.js): the first sentence's lead and the link wait until its title has settled (--intro-rest
   0 to 1); a filter, so it adds to whatever the letters and the link are doing themselves */
.sec-statement.is-scene .phrase:first-child .t-lead,
.sec-statement.is-scene .section__head > .link-arrow {
  filter: opacity(var(--intro-rest, 1));
}

.sec-statement .t-h1,
.sec-statement .t-lead,
.sec-statement .accent {
  transition: color var(--dur-bg) var(--ease-inout);
}

/* Phones: the sentences are long, so they are set a little smaller to stay on two lines */
@media (max-width: 599px) {
  .sec-statement .phrase .t-h1 {
    font-size: min(var(--fs-h1), 6vw);
  }
}

.sec-statement.is-lit { background-color: var(--ink-900); }
.sec-statement.is-lit .t-h1 { color: var(--color-on-dark); }
.sec-statement.is-lit .accent { color: var(--green-400); }
.sec-statement.is-lit .t-lead,
.sec-statement.is-lit .link-arrow { color: var(--color-on-dark-2); }

@media (hover: hover) {
  .sec-statement.is-lit .link-arrow:hover { color: var(--color-on-dark); }
}

.sec-statement.is-lit .rail {
  background: rgba(255, 255, 255, 0.15);
}

/* Behind the home statement: a layer that stays over the part of the section that is on screen (main.js moves it),
   holding two canvases the script draws on, fairy dust and a tree made of points. Both show only while the section
   is navy. */
.sec-statement > .container {
  position: relative;
}

.statement-tree {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 100svh;
  overflow: hidden;
  pointer-events: none;
  will-change: transform;
}

.statement-tree__dust,
.statement-tree__cloud {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity var(--dur-bg) var(--ease-inout);
}

.sec-statement.is-lit .statement-tree__dust,
.sec-statement.is-lit .statement-tree__cloud {
  opacity: 1;
}

/* B. Title + single visual */

/* 100vw includes the scrollbar; the part of the full-width photo under it is cut off here, not added to the page */
.sec-visual {
  overflow-x: clip;
}

/* B with a photo (home): the photo lies across the full width of the screen and is cut in to the page width with
   rounded corners; scrolling on after it has come in opens the cut to the screen edges (--open 0 to 1, main.js) */
.sec-visual .section__visual:has(> .media) {
  --side: max(var(--gutter), (100vw - var(--container-wide)) / 2);
  --open: 0;
  margin-inline: calc(50% - 50vw);
  clip-path: inset(0 calc(var(--side) * (1 - var(--open))) round calc(var(--r-xl) * (1 - var(--open))));
}

.sec-visual .section__visual:has(> .media) > .media {
  aspect-ratio: auto;
  height: calc((100vw - var(--side) * 2) * 9 / 16);
  border-radius: 0;
}

@media (max-width: 768px) {
  .sec-visual .section__visual:has(> .media) > .media {
    height: calc((100vw - var(--side) * 2) * 5 / 4);
  }
}

/* Forge scene (home): the visual spans the screen width and is cut only at the sides, so the windows' shadows run
   on below the stage; on a desktop the section is held while it plays */
.sec-forge .section__visual {
  margin-inline: calc(50% - 50vw);
  overflow-x: clip;
  overflow-y: visible;
}

.sec-forge.is-scene {
  padding-top: var(--header-h);
  padding-bottom: 0;
}

/* Held: the section is exactly one screen, and the stage takes whatever the words leave of it */
.sec-forge.is-scene .container--wide {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: var(--sp-6);
  height: calc(100svh - var(--header-h));
  /* the words settle a little down from the header, so the title does not climb all the way to the top */
  padding-top: clamp(var(--sp-6), 11svh, 120px);
  padding-bottom: var(--sp-6);
  box-sizing: border-box;
}

.sec-forge.is-scene .section__head {
  flex: none;
  margin-bottom: 0;
}

.sec-forge.is-scene .section__visual {
  display: flex;
  flex-direction: column;
  flex: 1 1 0;
  min-height: 0;
  margin-top: 0;
}

.sec-forge.is-scene .forge {
  flex: 1 1 0;
  height: auto;
  min-height: 240px;
}

/* Services page: the row's visual column is narrow, so the scene gets the whole row below the words */
.detail .section__visual:has(.forge) {
  grid-column: 1 / -1;
  margin-top: var(--sp-7);
}

.detail .section__visual:has(.forge) .forge {
  height: 560px;
}

.sec-visual .tile {
  max-width: 1040px;
  margin-inline: auto;
}

/* D. Split with pinned steps: step list on the left, one visual per step on the right.
   The visuals are a stack of paper cards: the next two wait just below the front one, and moving on flips the
   front card up and away around its top edge (perspective from the grid); going back flips it down again.
   On the home page a tree grows in a lane left of the text while the steps scroll (.tree). */

.steps-grid {
  display: grid;
  grid-template-columns: 5fr 7fr;
  grid-template-rows: auto repeat(4, auto);
  column-gap: var(--sp-8);
  align-content: center;
  perspective: 1800px;
  /* Seen from the right: the stack peeks out to the right, so the front card leans left as it turns over */
  perspective-origin: 100% 50%;
}

.steps-grid__head {
  grid-column: 1;
  grid-row: 1;
  margin-bottom: var(--sp-7);
}

.steps-grid__head .t-label + * { margin-top: var(--gap-label-title); }
.steps-grid__head .link-arrow { margin-top: var(--gap-title-lead); }

.step {
  position: relative;
  grid-column: 1;
  padding-left: var(--sp-5);
  border-left: 2px solid var(--ink-100);
}

/* The active step's line fills with green from the top */
.step::before {
  content: "";
  position: absolute;
  left: -2px;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--color-accent);
  transform: scaleY(0);
  transform-origin: center top;
  transition: transform var(--dur-base) var(--ease-inout);
}

.step + .step {
  margin-top: var(--sp-5);
}

/* Steps not in focus are thin and pale. Only the colour fades: animating the weight would re-lay out the
   pinned column on every frame and make the scrolling stutter, so the weight switches at once. */
.step .t-h3 {
  color: var(--ink-300);
  font-weight: var(--fw-regular);
  transition: color 0.5s var(--ease-out);
}

.step .t-body {
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height 0.6s var(--ease-inout), opacity 0.5s var(--ease-out), margin 0.6s var(--ease-inout);
}

.step.is-active::before {
  transform: scaleY(1);
}

.step.is-active .t-h3 {
  color: var(--ink-900);
  font-weight: var(--fw-bold);
}

.step.is-active .t-body {
  max-height: 160px;
  opacity: 1;
  margin-top: var(--sp-2);
}

/* With the grid (wider than a phone) the step titles keep their rows and only the active title is marked; all the
   descriptions share one place under the list and cross-fade there. Nothing changes height while the steps scroll,
   so the words never shift. */
@media (min-width: 769px) {
  .steps-grid {
    grid-template-rows: auto repeat(4, auto) auto;
  }
  .step {
    display: contents;
  }
  .step::before {
    content: none;
  }
  .step:nth-of-type(1) .t-h3 { grid-row: 2; }
  .step:nth-of-type(2) .t-h3 { grid-row: 3; }
  .step:nth-of-type(3) .t-h3 { grid-row: 4; }
  .step:nth-of-type(4) .t-h3 { grid-row: 5; }
  .step .t-h3 {
    position: relative;
    grid-column: 1;
    padding: var(--sp-2) 0 var(--sp-2) var(--sp-5);
    border-left: 2px solid var(--ink-100);
  }
  .step .t-h3::before {
    content: "";
    position: absolute;
    left: -2px;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--color-accent);
    transform: scaleY(0);
    transform-origin: center top;
    transition: transform var(--dur-base) var(--ease-inout);
  }
  .step.is-active .t-h3::before {
    transform: scaleY(1);
  }
  .step .t-body,
  .step.is-active .t-body {
    grid-row: 6;
    grid-column: 1;
    max-height: none;
    margin-top: var(--sp-6);
    padding-left: var(--sp-5);
    transform: translateY(8px);
    transition: opacity 0.5s var(--ease-out), transform 0.5s var(--ease-out);
  }
  .step.is-active .t-body {
    transform: none;
    transition-delay: 0.15s;
  }
}

/* The notebook cards are white on the grey section */
.step-visual .tile {
  background: var(--white);
}

/* The waiting cards sit a little to the right of and below the one in front, like a stack seen slightly from the side.
   Translate percentages follow the card's own size; the downward shift makes up for the shrinking from the top edge,
   so each card shows an 8px strip below the one in front as well as beside it. */
.step-visual {
  grid-column: 2;
  grid-row: 1 / 7;
  align-self: center;
  opacity: 0;
  transform-origin: center top;
  transform: translate(calc(3% + 16px), calc(6% + 16px)) scale(0.94);
  transition: transform 0.9s var(--ease-inout), opacity 0.5s var(--ease-out);
  backface-visibility: hidden;
  pointer-events: none;
  will-change: transform, opacity;
}

.step-visual.is-later {
  z-index: 1;
  opacity: 1;
  transform: translate(calc(3% + 16px), calc(6% + 16px)) scale(0.94);
}

.step-visual.is-next {
  z-index: 2;
  opacity: 1;
  transform: translate(calc(1.5% + 8px), calc(3% + 8px)) scale(0.97);
}

.step-visual.is-active {
  z-index: 3;
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

/* Flipped away: swings over the new front card, then fades once it has turned past edge-on */
.step-visual.is-before {
  z-index: 4;
  opacity: 0;
  transform: rotateX(100deg);
  transition: transform 0.9s var(--ease-inout), opacity 0.3s var(--ease-out) 0.6s;
}

[data-pin-steps] .steps-grid {
  min-height: 100svh;
}

/* Particle title (main.js): the dots that gather into a big title, over the screen-high top of its section */
.title-dust {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100svh;
  pointer-events: none;
  z-index: 2;
}

/* A title enlarged for its intro may be wider than the screen; what passes the sides is cut off rather than widening
   the page */
.has-intro {
  overflow-x: clip;
}

/* Title intro (main.js): while the title stands large, the words beside it (label, lead, link) and the rest of the
   section wait out of sight; they come up when the section loses .is-intro */
.has-intro .section__head > :not(.t-h1),
.has-intro .steps-grid__head > :not(.t-h1),
.has-intro .intro-rest {
  transition: opacity 0.5s var(--ease-out), translate 0.6s var(--ease-out);
}

.has-intro.is-intro .section__head > :not(.t-h1),
.has-intro.is-intro .steps-grid__head > :not(.t-h1),
.has-intro.is-intro .intro-rest {
  opacity: 0;
  translate: 0 24px;
}

.has-intro.is-intro .intro-rest {
  translate: 0 60px;
}

/* While the title intro plays (main.js), the steps, the notebook and the tree wait out of sight */
[data-pin-steps] .step .t-h3 {
  transition: color 0.5s var(--ease-out), opacity 0.6s var(--ease-out), translate 0.6s var(--ease-out);
}

[data-pin-steps] .step-visual .tile,
[data-pin-steps] .steps-spiral,
[data-pin-steps] .tree {
  transition: opacity 0.6s var(--ease-out), translate 0.6s var(--ease-out);
}

[data-pin-steps].is-intro .step .t-h3,
[data-pin-steps].is-intro .step-visual .tile,
[data-pin-steps].is-intro .steps-spiral,
[data-pin-steps].is-intro .tree {
  opacity: 0;
  translate: 0 40px;
}

[data-pin-steps].is-intro .step .t-body {
  visibility: hidden;
}

/* The waiting cards peek out to the right; on narrower screens that strip is cut off rather than widening the page */
[data-pin-steps] {
  overflow-x: clip;
}

/* Spiral binding along the top of the front card (desktop): the cards flip over it like the pages of a notebook.
   It shares the cards' place and height, so its top is the cards' top edge. Each ring is a white wire seen a little
   from the side: it comes up out of a punched hole, arches over the edge and goes down behind the card. */
.steps-spiral {
  display: none;
}

@media (min-width: 769px) {
  .steps-spiral {
    grid-column: 2;
    grid-row: 1 / 7;
    align-self: center;
    z-index: 5;
    display: flex;
    justify-content: space-between;
    height: calc(var(--showpiece-h) + var(--tile-pad) * 2);
    padding: 0 var(--sp-8);
    pointer-events: none;
  }
  .steps-spiral__defs {
    position: absolute;
  }
  .steps-spiral__ring {
    flex: none;
    width: 22px;
    height: 44px;
    margin-top: -16px;
    overflow: visible;
  }
  .steps-spiral__hole {
    fill: var(--ink-300);
  }
  .steps-spiral__wire {
    fill: none;
    stroke: url(#coilWire);
    stroke-width: 3.4;
    stroke-linecap: round;
  }
  .steps-spiral__light { stop-color: var(--white); }
  .steps-spiral__mid { stop-color: var(--ink-100); }
  .steps-spiral__dark { stop-color: var(--ink-300); }
}

/* Tree lane (home, desktop): the grid makes room on the left and the tree grows in that lane from the ground up */
.tree {
  display: none;
}

@media (min-width: 1025px) {
  .steps-grid--tree {
    position: relative;
    padding-left: calc(var(--tree-w) + var(--sp-7));
  }
  .tree {
    display: block;
    position: absolute;
    /* Pulled out into the page margin (up to --tree-reach) so the tree stands well apart from the words */
    left: max(calc((100% - 100vw) / 2 + var(--sp-5)), calc(var(--tree-reach) * -1));
    top: calc(var(--header-h) + var(--sp-7));
    bottom: var(--sp-7);
    width: var(--tree-w);
  }
  /* The drawing may run past the lane on the right, into the gap before the words */
  .tree svg {
    width: var(--tree-art);
    max-width: none;
    height: 100%;
    overflow: visible;
  }
}

/* Tree: an outline drawing traced after the user's reference tree (a round crown of separate leaves on fine forking
   branches, a short trunk spreading into roots along the ground), drawn in three passes that follow one another
   from the roots out to the branch tips (main.js): the outlines, then the pattern (grain, knots, midribs, the leaves'
   hatching), then the colour. Strokes keep their width however small the drawing is shown. */
.tree svg path {
  fill: none;
  stroke-width: 1.4px;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.tree__line {
  stroke: var(--bark-700);
}

/* heavier outline on the trunk and the great limbs */
.tree svg .tree__line--bold {
  stroke-width: 2px;
}

/* the grain: thin broken lines along the trunk and the thicker branches, and the knots */
.tree svg .tree__grain {
  stroke: var(--bark-700);
  stroke-opacity: 0.55;
  stroke-width: 0.8px;
}

/* each leaf's midrib */
.tree svg .tree__vein {
  stroke: var(--leaf-0);
  stroke-opacity: 0.7;
  stroke-width: 0.7px;
}

.tree svg .tree__leaf {
  stroke: var(--leaf-0);
  fill: url(#treeHatch);
  fill-opacity: 0;
}

/* the painting under the lines (main.js brings it in band by band after the lines and the pattern): bark lit from
   the upper left in three tones, and each leaf in one of five greens, light toward the sun and deep in the shade,
   its two halves either side of the midrib a step apart */
.tree svg .tree__wash {
  stroke: none;
  opacity: 0;
}

.tree svg .tree__wash--mid { fill: var(--bark-500); }
.tree svg .tree__wash--lit { fill: var(--bark-300); }
.tree svg .tree__wash--shade { fill: var(--bark-600); }
.tree svg .tree__wash--leaf1 { fill: url(#treeLeaf1); }
.tree svg .tree__wash--leaf2 { fill: url(#treeLeaf2); }
.tree svg .tree__wash--leaf3 { fill: url(#treeLeaf3); }
.tree svg .tree__wash--leaf4 { fill: url(#treeLeaf4); }
.tree svg .tree__wash--leaf5 { fill: url(#treeLeaf5); }
.tree__stop--0 { stop-color: var(--leaf-0); }
.tree__stop--1 { stop-color: var(--leaf-1); }
.tree__stop--2 { stop-color: var(--leaf-2); }
.tree__stop--3 { stop-color: var(--leaf-3); }
.tree__stop--4 { stop-color: var(--leaf-4); }
.tree__stop--5 { stop-color: var(--leaf-5); }

/* Once the tree is fully painted and on screen (.is-swaying, main.js), each leaf sways about its stalk in the breeze,
   each on its own beat */
.tree__sway {
  transform-box: fill-box;
  transform-origin: 0% 50%;
}

@media (prefers-reduced-motion: no-preference) {
  .tree.is-swaying .tree__sway {
    animation: leaf-sway 3.4s var(--ease-inout) infinite;
  }
  .tree svg > g:nth-of-type(3n + 1) .tree__sway { animation-duration: 4.1s; animation-delay: -1.3s; }
  .tree svg > g:nth-of-type(3n + 2) .tree__sway { animation-duration: 2.9s; animation-delay: -2.2s; }
  .tree svg > g:nth-of-type(4n) .tree__sway { animation-delay: -0.6s; }
  .tree svg > g:nth-of-type(5n + 3) .tree__sway { animation-duration: 3.7s; animation-delay: -2.8s; }
  .tree svg > g:nth-of-type(7n) .tree__sway { animation-duration: 4.6s; }
}

@keyframes leaf-sway {
  0%, 100% { transform: rotate(0deg); }
  30% { transform: rotate(12deg); }
  70% { transform: rotate(-9deg); }
}


.tree__hatch {
  stroke: var(--leaf-0);
  stroke-opacity: 0.35;
  stroke-width: 1;
}

@media (min-width: 769px) {
  .section[data-pin-steps] {
    padding-block: 0;
  }
}

/* Phones without the script: the steps are stacked, each with its card */
@media (max-width: 768px) {
  [data-pin-steps]:not(.is-pinned) .steps-grid {
    display: block;
  }
  [data-pin-steps]:not(.is-pinned) .steps-grid__head {
    margin-bottom: var(--sp-7);
  }
  [data-pin-steps]:not(.is-pinned) .step,
  [data-pin-steps]:not(.is-pinned) .step + .step {
    margin-top: 0;
  }
  [data-pin-steps]:not(.is-pinned) .step::before {
    transform: none;
  }
  [data-pin-steps]:not(.is-pinned) .step .t-h3 {
    color: var(--ink-900);
    font-weight: var(--fw-bold);
  }
  [data-pin-steps]:not(.is-pinned) .step .t-body {
    max-height: none;
    opacity: 1;
    margin-top: var(--sp-2);
  }
  [data-pin-steps]:not(.is-pinned) .step-visual {
    opacity: 1;
    transform: none;
    pointer-events: auto;
    margin: var(--sp-5) 0 var(--sp-7);
    transition: none;
  }
  [data-pin-steps]:not(.is-pinned) .step-visual:last-child {
    margin-bottom: 0;
  }

  /* Phones with the script: the same notebook as on a desktop, held for the steps. One column: the title, the
     notebook (cards of one fixed height, stacked, with the spiral binding along the top, turning over as the steps
     scroll), and under it the current step's name and words, which change with it in one place. */
  .section[data-pin-steps].is-pinned {
    padding-block: 0;
    --steps-card-h: clamp(250px, calc(100svh - 440px), 380px);
  }
  .is-pinned .steps-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto auto;
    align-content: center;
    min-height: 100svh;
    padding-top: var(--header-h);
    padding-bottom: var(--sp-5);
    box-sizing: border-box;
  }
  .is-pinned .steps-grid__head {
    grid-row: 1;
    margin-bottom: var(--sp-6);
  }
  /* the notebook keeps a margin inside the page on both sides, room for the cards waiting behind on the right */
  .is-pinned .step-visual {
    grid-row: 2;
    grid-column: 1;
    align-self: start;
    justify-self: center;
    width: calc(100% - 40px);
    margin: 0;
  }
  .is-pinned .step-visual .tile {
    height: var(--steps-card-h);
    box-sizing: border-box;
  }
  .is-pinned .step-visual .sp {
    height: 100%;
    min-height: 0;
  }
  .is-pinned .steps-spiral {
    grid-row: 2;
    grid-column: 1;
    align-self: start;
    justify-self: center;
    width: calc(100% - 40px);
    z-index: 5;
    display: flex;
    justify-content: space-between;
    height: var(--steps-card-h);
    padding: 0 var(--sp-5);
    pointer-events: none;
  }
  .is-pinned .steps-spiral__defs {
    position: absolute;
  }
  .is-pinned .steps-spiral__ring {
    flex: none;
    width: 16px;
    height: 32px;
    margin-top: -12px;
    overflow: visible;
  }
  .is-pinned .steps-spiral__ring:nth-of-type(n + 11) {
    display: none;
  }
  /* plain class selectors: the rings are copies made by <use>, which rules through an ancestor do not reach */
  .steps-spiral__hole { fill: var(--ink-300); }
  .steps-spiral__wire {
    fill: none;
    stroke: url(#coilWire);
    stroke-width: 3.4;
    stroke-linecap: round;
  }
  .steps-spiral__light { stop-color: var(--white); }
  .steps-spiral__mid { stop-color: var(--ink-100); }
  .steps-spiral__dark { stop-color: var(--ink-300); }
  /* the steps share one place under the notebook (clear of the cards waiting behind), and cross-fade there */
  .is-pinned .step {
    grid-row: 3;
    grid-column: 1;
    margin-top: calc(var(--sp-6) + var(--sp-4));
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.4s var(--ease-out), transform 0.5s var(--ease-out);
  }
  .is-pinned .step + .step {
    margin-top: calc(var(--sp-6) + var(--sp-4));
  }
  .is-pinned .step.is-active {
    opacity: 1;
    transform: none;
    transition-delay: 0.15s;
  }
  /* during the title intro the current step (its line included) waits too */
  [data-pin-steps].is-pinned.is-intro .step.is-active {
    opacity: 0;
    transform: translateY(8px);
  }
  .is-pinned .step .t-h3 {
    color: var(--ink-900);
    font-weight: var(--fw-bold);
  }
  .is-pinned .step .t-body {
    max-height: none;
    opacity: 1;
    margin-top: var(--sp-2);
  }
}

/* E. Card stream: marquee on desktop, swipe with scroll snap on mobile */

.sec-stream .container + .marquee {
  margin-top: var(--gap-text-visual);
}

.stream {
  display: flex;
  gap: var(--gap-card);
}

.stream__item {
  flex: none;
  width: 360px;
}

.stream__item--up {
  transform: translateY(calc(var(--sp-6) * -1));
}

.stream__item .media {
  aspect-ratio: 1 / 1;
}

.marquee .stream {
  padding-block: var(--sp-6);
}

/* Phones and tablets: the held section fills the screen with its words and photos in the middle; the photos are half
   the screen wide, so half a photo, one photo and half a photo show, and only the one in the middle is in colour and
   sharp (two lines mark where it stands) */
@media (max-width: 1024px) {
  .sec-stream.has-intro {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 100svh;
    padding-top: calc(var(--header-h) + var(--sp-5));
    padding-bottom: var(--sp-6);
  }
  .sec-stream .container + .marquee {
    margin-top: var(--sp-7);
  }
  .stream__item {
    width: calc(50vw - var(--gap-card) / 2);
  }
  .stream__item--up {
    transform: translateY(calc(var(--sp-4) * -1));
  }
  .sec-stream .marquee {
    -webkit-mask-image: none;
    mask-image: none;
  }
  .sec-stream .marquee::before,
  .sec-stream .marquee::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    z-index: 2;
    width: calc(25vw - var(--gap-card) / 2);
    -webkit-backdrop-filter: grayscale(1);
    backdrop-filter: grayscale(1);
    pointer-events: none;
  }
  .sec-stream .marquee::before {
    left: 0;
    border-right: 1px solid var(--ink-200);
  }
  .sec-stream .marquee::after {
    right: 0;
    border-left: 1px solid var(--ink-200);
  }
}

/* Wide screens with the section's side lines: outside the two lines the moving photos show in black and white, so
   each photo turns to colour exactly as it crosses a line into the middle; each photo is also blurred inside its own
   card by how far it is outside the lines (main.js), so the blur never spills past the card's edge */
@media (min-width: 1400px) {
  .sec-stream .marquee::before,
  .sec-stream .marquee::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    z-index: 2;
    /* one pixel over the line, so no sliver of colour shows beside it at any screen scale */
    width: max(0px, calc((100vw - var(--container)) / 2 - var(--sp-8) + 1px));
    -webkit-backdrop-filter: grayscale(1);
    backdrop-filter: grayscale(1);
    pointer-events: none;
  }
  .sec-stream .marquee::before { left: 0; }
  .sec-stream .marquee::after { right: 0; }
}

/* F. Stats */

/* No hard edge into the white section below: when the end of the band comes up the screen, the whole band turns
   white and its words dark (.is-day, set by the script); scrolling back up turns it green again */
.sec-stats {
  overflow: hidden;
}

.sec-stats::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--white);
  opacity: 0;
  transition: opacity var(--dur-bg) var(--ease-inout);
  pointer-events: none;
}

.sec-stats .t-h1,
.sec-stats .t-lead,
.sec-stats .t-label,
.sec-stats .t-num,
.sec-stats .t-small,
.sec-stats .stats {
  transition: color var(--dur-bg) var(--ease-inout), border-color var(--dur-bg) var(--ease-inout);
}

.sec-stats.is-day::after { opacity: 1; }
.sec-stats.is-day .t-h1,
.sec-stats.is-day .t-num { color: var(--ink-900); }
.sec-stats.is-day .t-lead { color: var(--ink-700); }
.sec-stats.is-day .t-small { color: var(--ink-500); }
.sec-stats.is-day .t-label { color: var(--color-accent); }
.sec-stats.is-day .stats { border-color: var(--ink-200); }

/* Title on the left, the map on the right, the numbers in one row underneath */
.stats-intro {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: var(--sp-8);
}

.stats-intro .map {
  margin-inline: auto var(--sp-8);
}

/* Numbers as a bar chart (after the full-screen motion further down toss.im): one row per number. Each bar starts at
   the left edge of the screen and grows with the scroll, one row after another, pushing its number and label along
   at its tip; the number counts up with the bar (main.js). Bars get shorter row by row. --p is the growth (0 to 1),
   1 without the script. */
.stats {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
  margin-top: var(--gap-text-visual);
}

/* Each row: the bar, and at its tip what the number is (in plain words) right above the number itself, so the
   name always travels with its bar however long or short it is. The bar lines up with the middle of the number. */
.stats {
  --stat-num: var(--fs-num);
}

.stat {
  --p: 1;
  display: flex;
  align-items: flex-end;
  gap: var(--sp-6);
}

.stat--1 { --share: 1; }
.stat--2 { --share: 0.9; }
.stat--3 { --share: 0.8; }
.stat--4 { --share: 0.7; }

.stat__bar {
  --edge: max(var(--gutter), (100vw - var(--container)) / 2);
  flex: none;
  width: calc((var(--edge) + (100% - var(--stat-text)) * var(--share)) * var(--p));
  height: var(--stat-bar-h);
  margin-left: calc(var(--edge) * -1);
  margin-bottom: calc((var(--stat-num) - var(--stat-bar-h)) / 2);
  position: relative;
  overflow: hidden;
  border-radius: 0 6px 6px 0;
  background: linear-gradient(90deg, rgba(140, 224, 181, 0.12) 0%, var(--green-300) 70%, var(--green-100) 100%);
  box-shadow: 0 0 18px rgba(140, 224, 181, 0.45);
  transition: background var(--dur-bg) var(--ease-inout);
}

/* A band of light runs along each bar now and then, each bar a little after the one above (while on screen) */
.stat__bar::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 30%;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.75) 50%, rgba(255, 255, 255, 0) 100%);
  transform: translateX(-120%);
  animation: bar-shine 3.2s var(--ease-inout) infinite paused;
}

.sec-stats.is-glowing .stat__bar::after {
  animation-play-state: running;
}

.stat--2 .stat__bar::after { animation-delay: 0.25s; }
.stat--3 .stat__bar::after { animation-delay: 0.5s; }
.stat--4 .stat__bar::after { animation-delay: 0.75s; }

@keyframes bar-shine {
  0% { transform: translateX(-120%); }
  45%, 100% { transform: translateX(420%); }
}

@media (prefers-reduced-motion: reduce) {
  .stat__bar::after {
    animation: none;
    display: none;
  }
}

.stat__text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-2);
  flex: none;
  max-width: var(--stat-text);
}

.stat__label {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--sp-2);
  margin: 0;
}

.stats .stat__label .t-label {
  font-size: var(--fs-body);
  font-weight: var(--fw-bold);
  color: var(--green-300);
  text-shadow: 0 0 12px rgba(140, 224, 181, 0.55);
}

.stats .stat__label .t-small {
  color: var(--color-on-dark-3);
}

.sec-stats.is-day .stats .stat__label .t-label { color: var(--color-accent); text-shadow: none; }

.sec-stats.is-scene .stats .stat__label .t-label {
  font-size: var(--fs-lead);
}

.stats .t-num {
  font-size: var(--stat-num);
  font-weight: var(--fw-hair);
  line-height: 1;
  white-space: nowrap;
}

/* Scene (desktop): the bars lie over the left half of the band, from the very edge of the screen, in the middle of
   its height; the title and the map alone sit in the middle until the bars push them away (main.js) */
.sec-stats.is-scene .stats {
  position: absolute;
  /* The left edge of the screen, from inside the centred page */
  left: calc(50% - 50vw);
  top: 50%;
  z-index: 1;
  width: 50vw;
  margin: 0;
  transform: translateY(-50%);
}

.sec-stats.is-scene .stat__bar {
  --edge: 0px;
  margin-left: 0;
}

.sec-stats.is-scene .stats {
  --stat-num: var(--fs-h1);
}

.sec-stats.is-scene .stats-intro > * {
  will-change: transform;
}

.sec-stats.is-day .stat__bar {
  background: linear-gradient(90deg, rgba(34, 182, 118, 0.08) 0%, var(--green-500) 100%);
  box-shadow: none;
}

@media (max-width: 1024px) {
  .stats-intro {
    grid-template-columns: 1fr;
    gap: var(--sp-7);
  }
  .stats-intro .map {
    margin-inline: auto;
  }
}

@media (max-width: 768px) {
  .stats {
    gap: var(--sp-5);
  }
  .stat {
    gap: var(--sp-4);
  }
  .stats {
    --stat-num: 30px;
  }
}

/* G. Logo strip: on the home page the title sits left of four partner strips that run the full height of the
   screen (desktop), with the logo strip below */

.sec-logos .container + .marquee {
  margin-top: var(--sp-9);
}

.partners {
  display: grid;
  grid-template-columns: 5fr 7fr;
  column-gap: var(--sp-8);
  align-items: center;
}

.partners .link-arrow {
  margin-top: var(--gap-lead-btn);
}

/* Partner strips (home, after the FEATURE columns of overwatch.nexon.com): tall strips split by thin light lines,
   each a grey photo with its number, name and a round arrow at the bottom. Pointing at a strip widens it a little,
   turns its photo to colour and fills the arrow. */
.partner-strips {
  display: flex;
  height: 100svh;
  overflow: hidden;
}

.partner-strip {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
  color: var(--color-on-dark);
  background: var(--ink-900);
  transition: flex-grow var(--dur-strip) var(--ease-out);
}

.partner-strip + .partner-strip {
  border-left: 1px solid rgba(255, 255, 255, 0.2);
}

/* The photo keeps one width, wider than any strip, centred in it: widening a strip only shows more of the photo
   instead of resizing it on every frame */
.partner-strip__photo {
  position: absolute;
  top: 0;
  left: 50%;
  width: max(100%, 460px);
  height: 100%;
  max-width: none;
  object-fit: cover;
  filter: grayscale(1) brightness(0.95) contrast(0.85);
  transform: translateX(-50%) scale(1.06);
  transition: filter var(--dur-strip) var(--ease-out), transform var(--dur-strip) var(--ease-out);
  will-change: transform;
}

.partner-strip::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(17, 25, 39, 0) 55%, rgba(17, 25, 39, 0.55) 100%);
}

/* The partner's logo in white, in the middle of the strip */
.partner-strip__logo,
.partner-col__logo {
  position: absolute;
  z-index: 1;
  left: 50%;
  top: 46%;
  width: min(72%, var(--logo-w));
  height: var(--logo-h);
  object-fit: contain;
  filter: brightness(0) invert(1) drop-shadow(0 2px 10px rgba(17, 25, 39, 0.35));
  transform: translate(-50%, -50%);
  pointer-events: none;
}

.partner-strip__body {
  position: absolute;
  z-index: 1;
  left: var(--sp-4);
  right: var(--sp-4);
  bottom: var(--sp-8);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-2);
}

/* Number under a short rule */
.partner-strip__num {
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  line-height: 1;
  color: var(--color-on-dark-2);
}

.partner-strip__num::before {
  content: "";
  display: block;
  width: 24px;
  height: 1px;
  margin-bottom: var(--sp-3);
  background: currentColor;
}

.partner-strip__name {
  font-size: var(--fs-lead);
  font-weight: var(--fw-bold);
  line-height: 1.3;
}

.partner-strip__ko {
  font-size: var(--fs-body);
  font-weight: var(--fw-semibold);
  color: var(--color-on-dark);
}

.partner-strip__arrow {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin-top: var(--sp-4);
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: var(--r-pill);
  transition: background-color var(--dur-hover) var(--ease-inout), color var(--dur-hover) var(--ease-inout), border-color var(--dur-hover) var(--ease-inout);
}

.partner-strip__arrow svg {
  width: 18px;
  height: 18px;
}

.partner-strip:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: -4px;
}

/* Phone: the row in the middle of the screen shows in colour (main.js) */
.partner-strip.is-lit .partner-strip__photo {
  filter: grayscale(0) brightness(1);
  transform: translateX(-50%) scale(1);
}

@media (hover: hover) {
  .partner-strip:hover {
    flex-grow: 1.35;
  }
  .partner-strip:hover .partner-strip__photo {
    filter: grayscale(0) brightness(1);
    transform: translateX(-50%) scale(1);
  }
  .partner-strip:hover .partner-strip__arrow {
    background: var(--white);
    border-color: var(--white);
    color: var(--ink-900);
  }
}

/* Desktop: the strips run from the top of the section to one screen down, so the section has no top padding, and
   on to the right edge of the screen (the part past the page edge is cut off by the section) */
@media (min-width: 1025px) {
  .section.sec-logos {
    padding-top: 0;
    overflow: hidden;
  }
  .partner-strips {
    margin-right: calc(max(var(--gutter), (100vw - var(--container)) / 2) * -1);
  }
  .partners {
    align-items: stretch;
  }
  .partners .section__head {
    align-self: center;
  }
}

@media (max-width: 1024px) {
  .partners {
    display: block;
  }
  .partner-strips {
    height: 70svh;
    margin-top: var(--gap-text-visual);
  }
}

/* Phone: the strips become rows */
@media (max-width: 768px) {
  .partner-strips {
    flex-direction: column;
    height: auto;
  }
  .partner-strip {
    flex: none;
    height: 132px;
  }
  .partner-strip + .partner-strip {
    border-left: 0;
    border-top: 1px solid rgba(255, 255, 255, 0.2);
  }
  .partner-strip__body {
    bottom: var(--sp-5);
  }
  .partner-strip__arrow {
    display: none;
  }
}

/* Partner columns: four tall photo columns split by thin gaps. The open one is wide and in colour; the others are
   narrow and grey. Pointing at a column opens it (main.js): it widens, its photo turns to colour and settles from a
   slight zoom, and its short description rises in. */
.partner-cols {
  display: flex;
  gap: 2px;
  height: 560px;
  border-radius: var(--r-xl);
  overflow: hidden;
}

.partner-col {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
  color: var(--color-on-dark);
  background: var(--ink-900);
  transition: flex-grow var(--dur-unveil) var(--ease-inout);
}

.partner-col.is-open {
  flex-grow: 2;
}

.partner-col__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) brightness(0.8);
  transform: scale(1.08);
  transition: filter var(--dur-unveil) var(--ease-inout), transform var(--dur-line) var(--ease-text);
}

.partner-col.is-open .partner-col__photo {
  filter: grayscale(0) brightness(1);
  transform: scale(1);
}

.partner-col::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(17, 25, 39, 0.3) 0%, rgba(17, 25, 39, 0) 28%, rgba(17, 25, 39, 0) 48%, rgba(17, 25, 39, 0.72) 100%);
}

.partner-col__num,
.partner-col__text {
  position: absolute;
  z-index: 1;
  left: var(--sp-4);
  right: var(--sp-4);
}

/* Number under a short rule, top left */
.partner-col__num {
  top: var(--sp-5);
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  line-height: 1;
  color: var(--color-on-dark-2);
}

.partner-col__num::before {
  content: "";
  display: block;
  width: 24px;
  height: 1px;
  margin-bottom: var(--sp-3);
  background: currentColor;
}

.partner-col__text {
  bottom: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.partner-col__name {
  font-size: var(--fs-body);
  font-weight: var(--fw-bold);
  line-height: 1.3;
}

.partner-col__desc {
  font-size: var(--fs-small);
  color: var(--color-on-dark-2);
  white-space: nowrap;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity var(--dur-hover) var(--ease-out), transform var(--dur-hover) var(--ease-out);
}

.partner-col.is-open .partner-col__desc {
  opacity: 1;
  transform: none;
  transition-delay: 0.25s;
}

.partner-col:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: -4px;
}

@media (max-width: 1024px) {
  .partners {
    display: block;
  }
  .partner-cols {
    height: 480px;
    margin-top: var(--gap-text-visual);
  }
}

/* Phone: the columns become rows; a tap opens a row */
@media (max-width: 768px) {
  .partner-cols {
    flex-direction: column;
    height: 600px;
    border-radius: var(--r-lg);
  }
  .partner-col.is-open {
    flex-grow: 3;
  }
  .partner-col__num {
    left: auto;
    top: var(--sp-4);
  }
  .partner-col__num::before {
    display: none;
  }
  /* The rows are short: the logo says who it is, so the name below it is left out */
  .partner-col__text {
    display: none;
  }
}

.logos {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
}

.marquee__track.logos {
  padding-right: var(--sp-8);
}

/* Partner logos in the moving strip: each logo in the same 180 x 40 box, in its own colours. The two that the
   partners publish only in white are shown in black instead, so they read on the white page. */
.logos__img {
  flex: none;
  width: var(--logo-w);
  height: var(--logo-h);
  object-fit: contain;
}

.logos__img--light {
  filter: brightness(0) opacity(0.85);
}

/* H. Call to action: centred on the home page, split (.sec-cta--split) on sub pages */

/* Notice banner (home): a square-cornered grey banner as tall as the section, centred in the space left of the
   centred call (wide screens). It rises into place with the scroll, its small notes coming in one by one
   (main.js). Below the call on narrower screens. */
.notice {
  margin: var(--sp-9) var(--gutter) 0;
  padding: var(--sp-7) var(--sp-6);
  background: var(--ink-100);
  will-change: transform;
}

.notice__label {
  font-size: var(--fs-small);
  font-weight: var(--fw-light);
  line-height: 1;
  letter-spacing: var(--ls-caption);
  color: var(--ink-500);
}

.notice__title {
  margin-top: var(--sp-3);
  font-size: var(--fs-body);
  font-weight: var(--fw-bold);
  color: var(--ink-900);
}

.notice__list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  margin-top: var(--sp-6);
}

.notice__item,
.notice__foot {
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--ink-500);
  word-break: keep-all;
}

.notice__foot {
  margin-top: var(--sp-6);
  font-weight: var(--fw-semibold);
  color: var(--ink-700);
}

/* The grey behind the banner (wide screens): a layer as big as the section, cut down to the banner's place. The script
   first sweeps it across the whole section from the right, then gathers it into the banner. */
.notice-sweep {
  display: none;
}

@media (min-width: 1200px) {
  .notice-sweep {
    display: block;
    position: absolute;
    inset: 0;
    background: var(--ink-100);
    clip-path: inset(0 calc(100% - var(--notice-space) / 2 - var(--notice-w) / 2) 0 calc(var(--notice-space) / 2 - var(--notice-w) / 2));
    will-change: clip-path;
  }
  .sec-cta > .container {
    position: relative;
    z-index: 1;
  }
  .notice {
    z-index: 1;
    background: none;
    position: absolute;
    left: calc(var(--notice-space) / 2 - var(--notice-w) / 2);
    top: 0;
    bottom: 0;
    width: var(--notice-w);
    margin: 0;
    padding: calc(var(--header-h) + var(--sp-6)) max(var(--sp-6), calc((var(--notice-w) - 232px) / 2)) var(--sp-6);
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  .notice__foot {
    margin-top: var(--sp-6);
  }
}

.sec-cta {
  overflow: hidden;
}

.sec-cta .section__head {
  max-width: 800px;
}

.sec-cta .btn-row {
  justify-content: center;
}

@media (max-width: 768px) {
  .sec-cta .btn-row {
    align-items: center;
  }
}

.sec-cta .contact-lines {
  margin-top: var(--sp-7);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
}

.sec-cta .contact-lines a {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding-block: var(--sp-2);
  color: var(--ink-700);
}

@media (hover: hover) {
  .sec-cta .contact-lines a:hover { color: var(--ink-900); }
}

/* Photo band call to action (sub pages, after the closing banners on overwatch.nexon.com): a full-width dark photo
   with the title on the left and a large phone number, a button and the mail and hours on the right. No card. */
.cta-band {
  position: relative;
  overflow: hidden;
}

.cta-band__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  will-change: transform;
}

.cta-band::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(17, 25, 39, 0.92) 0%, rgba(17, 25, 39, 0.78) 55%, rgba(17, 25, 39, 0.6) 100%);
}

.cta-band__inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: var(--sp-8);
  align-items: end;
  width: 100%;
}

.cta-band .t-lead {
  color: var(--color-on-dark-2);
}

.cta-band__actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-3);
}

.cta-band__actions .btn-row {
  margin-block: var(--sp-4) var(--sp-2);
}

.cta-band__actions .u-line,
.cta-band__actions .t-small {
  color: var(--color-on-dark-2);
}

@media (hover: hover) {
  .cta-band__actions .u-line:hover { color: var(--color-on-dark); }
}

@media (max-width: 1024px) {
  .cta-band__inner {
    grid-template-columns: 1fr;
    gap: var(--sp-7);
  }
}

.sec-cta .contact-lines svg {
  width: 18px;
  height: 18px;
}

/* I. Process */

.process {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-6);
  margin-top: var(--sp-9);
  padding-top: var(--sp-6);
}

.process__line {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--ink-100);
  border-radius: var(--r-pill);
  overflow: hidden;
}

.process__fill {
  position: absolute;
  inset: 0;
  background: var(--color-accent);
  transform-origin: left center;
  transform: scaleX(0);
}

.process__item {
  position: relative;
}

.process__item::before {
  content: "";
  position: absolute;
  left: 0;
  top: calc(var(--sp-6) * -1 - 5px);
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--white);
  border: 2px solid var(--ink-200);
  transition: background-color 0.4s var(--ease-out), border-color 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}

.process__item.is-on::before {
  background: var(--color-accent);
  border-color: var(--color-accent);
  transform: scale(1.15);
}

/* The number fills with the accent colour as the line passes (--fill, set by the script) */
.process__num {
  --fill: 0%;
  display: block;
  width: fit-content;
  font-size: var(--fs-display);
  line-height: 1;
  letter-spacing: var(--ls-display);
  font-weight: var(--fw-bold);
  color: transparent;
  background: linear-gradient(90deg, var(--color-accent) var(--fill), var(--green-200) var(--fill));
  -webkit-background-clip: text;
  background-clip: text;
  font-variant-numeric: tabular-nums;
}

.process__item .t-h3 {
  margin-top: var(--sp-4);
}

.process__item .t-body {
  margin-top: var(--sp-2);
}

@media (max-width: 1024px) {
  .process {
    grid-template-columns: 1fr;
    gap: var(--sp-7);
    max-width: var(--container-narrow);
    margin-top: var(--sp-8);
    margin-inline: auto;
    padding-top: 0;
    padding-left: var(--sp-6);
  }
  .process__line {
    top: 0;
    bottom: 0;
    left: 5px;
    right: auto;
    width: 2px;
    height: auto;
  }
  .process__fill {
    transform-origin: center top;
    transform: scaleY(0);
  }
  .process__item::before {
    left: calc(var(--sp-6) * -1);
    top: 6px;
  }
  .process__num {
    font-size: var(--fs-h1);
    background-image: linear-gradient(180deg, var(--color-accent) var(--fill), var(--green-200) var(--fill));
  }
}

/* J. Page head: first section of a sub page (after toss.im/company). A large English title over the Korean one,
   the lead under them, and on some pages a wide rounded photo. No lines. Starts at the same height on every
   sub page, left out of the one-screen centring. */

.sec-page {
  padding-top: calc(var(--header-h) + var(--page-top));
}

.section.sec-page {
  justify-content: flex-start;
  min-height: 0;
}

.page-head .t-label + * {
  margin-top: var(--gap-label-title);
}

.page-head__title {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

.page-head__en {
  font-size: var(--fs-page-en);
  line-height: 1.05;
  letter-spacing: -0.035em;
  font-weight: var(--fw-bold);
  color: var(--ink-900);
}

.page-head__ko {
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  letter-spacing: var(--ls-h3);
  font-weight: var(--fw-bold);
  color: var(--ink-700);
}

.page-head .t-lead {
  max-width: 560px;
  margin-top: var(--sp-6);
}

/* The photo lies across the full width of the screen, cut in to the page width with rounded corners; scrolling
   opens the cut to the screen edges (--open 0 to 1, main.js) */
.sec-page {
  overflow-x: clip;
}

.page-head__photo {
  --side: max(var(--gutter), (100vw - var(--container)) / 2);
  --open: 0;
  margin: var(--sp-9) calc(50% - 50vw) 0;
  clip-path: inset(0 calc(var(--side) * (1 - var(--open))) round calc(var(--r-xl) * (1 - var(--open))));
}

.page-head__photo .media {
  aspect-ratio: auto;
  height: calc((100vw - var(--side) * 2) * 9 / 21);
  border-radius: 0;
}

@media (max-width: 768px) {
  .page-head__photo {
    margin-top: var(--sp-8);
  }
  .page-head__photo .media {
    height: calc((100vw - var(--side) * 2) * 3 / 4);
  }
}

/* Sub page scenes (main.js, .has-scenes on the body). The big English title rises letter by letter out of a mask. */
.has-scenes .page-head__en .word {
  overflow: hidden;
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
  vertical-align: top;
}

/* The navy list: the item in the middle of the screen is lit, the others wait dimmed a little to the right */
.has-scenes .band__item {
  opacity: 0.22;
  transform: translateX(28px);
  transition: opacity 0.6s var(--ease-out), transform 0.8s var(--ease-out);
}

.has-scenes .band__item.is-seen {
  opacity: 0.45;
  transform: none;
}

.has-scenes .band__item.is-focus {
  opacity: 1;
  transform: none;
}

/* Services: a huge outlined number behind each row, drifting against the scroll */
/* Things that move in from beside the page (visuals, list items, cards turning over) are cut off at its edges
   rather than widening it; clip keeps sticky titles working */
.sec-detail,
.sec-band,
.sec-cards {
  overflow-x: clip;
}

.detail {
  position: relative;
  isolation: isolate;
}

.detail__num {
  position: absolute;
  z-index: -1;
  top: -0.42em;
  left: -0.04em;
  font-size: clamp(140px, 20vw, 300px);
  font-weight: var(--fw-bold);
  line-height: 1;
  letter-spacing: -0.04em;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--ink-200);
  pointer-events: none;
  user-select: none;
  will-change: transform;
}

.detail--flip .detail__num {
  left: auto;
  right: -0.04em;
}

@media (max-width: 1024px) {
  .detail__num {
    top: -0.5em;
    font-size: 120px;
  }
  .detail--flip .detail__num {
    right: auto;
    left: -0.04em;
  }
}

/* K. Info card: short facts as label and value pairs on a white rounded card, spaced apart without lines */

.info {
  display: grid;
  gap: var(--sp-5);
  padding: var(--sp-8);
  border-radius: var(--r-xl);
  background: var(--white);
}

.info__row {
  display: grid;
  grid-template-columns: 160px 1fr;
  gap: var(--sp-5);
}

.info dt {
  font-weight: var(--fw-semibold);
  color: var(--ink-900);
}

/* Phone and mail links keep their text size but get a taller touch area */
.info dd a {
  display: inline-block;
  padding-block: var(--sp-3);
  margin-block: calc(var(--sp-3) * -1);
}

@media (hover: hover) {
  .info dd a:hover { color: var(--ink-900); }
}

@media (max-width: 768px) {
  .info {
    padding: var(--sp-6);
  }
  .info__row {
    grid-template-columns: 1fr;
    gap: var(--sp-1);
  }
}

/* L. Detail rows: text and one visual side by side, sides alternate from section to section */

.detail {
  display: grid;
  grid-template-columns: 5fr 6fr;
  gap: var(--sp-9);
  align-items: center;
}

.detail--flip {
  grid-template-columns: 6fr 5fr;
}

/* Grid items may be narrower than their content, so a wide mockup never pushes the page sideways */
.detail > *,
.side > *,
.band > * {
  min-width: 0;
}

.detail--flip .detail__visual {
  order: -1;
}

.detail .section__visual {
  margin-top: 0;
}

.detail__list {
  margin-top: var(--sp-6);
  display: grid;
  gap: var(--sp-3);
}

.detail__list li {
  position: relative;
  padding-left: var(--sp-5);
}

.detail__list li::before {
  content: "";
  position: absolute;
  left: var(--sp-1);
  top: 0.7em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink-300);
}

@media (max-width: 1024px) {
  .detail,
  .detail--flip {
    grid-template-columns: 1fr;
    gap: var(--gap-text-visual);
  }
  .detail--flip .detail__visual {
    order: 0;
  }
}

/* M. Side: title on the left (staying near the top of the screen while the right side scrolls), text or a card on
   the right (after the CEO greeting on bubaum.com) */

.side {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: var(--sp-9);
  align-items: start;
}

.side__head {
  position: sticky;
  top: calc(var(--header-h) + var(--sp-8));
}

.side__body .t-body {
  margin-top: var(--sp-5);
}

.side__body .link-arrow {
  margin-top: var(--sp-6);
}

/* Three tall rounded photos in a row under the side text (after toss.im/company) */
.photo-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-4);
  margin-top: var(--sp-10);
}

.photo-row .media {
  aspect-ratio: 4 / 5;
  will-change: transform;
}

@media (max-width: 1024px) {
  .side {
    grid-template-columns: 1fr;
    gap: var(--sp-7);
  }
  .side__head {
    position: static;
  }
}

@media (max-width: 768px) {
  .photo-row {
    grid-template-columns: 1fr;
    margin-top: var(--sp-8);
  }
  .photo-row .media {
    aspect-ratio: 4 / 3;
  }
}

/* N. Logo row: the partners' logos in one row, without boxes, as soft grey silhouettes that darken on hover */

.wall {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  align-items: center;
  gap: var(--sp-6);
  margin-top: var(--sp-9);
}

.wall li {
  display: flex;
  justify-content: center;
}

.wall__img {
  width: var(--logo-w);
  max-width: 100%;
  height: var(--logo-h);
  object-fit: contain;
  filter: brightness(0);
  opacity: 0.35;
  transition: opacity var(--dur-fast) var(--ease-out);
}

@media (hover: hover) {
  .wall li:hover .wall__img { opacity: 0.8; }
}

@media (max-width: 1024px) {
  .wall {
    grid-template-columns: repeat(3, 1fr);
    row-gap: var(--sp-8);
  }
}

@media (max-width: 768px) {
  .wall {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--sp-7) var(--sp-5);
  }
}

.sec-partners .partner-cols {
  margin-top: var(--gap-text-visual);
}

/* O. Values: four short values side by side, each under a small picture of plain shapes (after bubaum.com) */

.values {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-7);
  margin-top: var(--gap-text-visual);
  text-align: center;
}

.value__pic {
  display: block;
  width: 72px;
  height: 72px;
  margin: 0 auto var(--sp-5);
}

.value__title {
  font-size: var(--fs-lead);
  line-height: var(--lh-small);
  font-weight: var(--fw-bold);
  color: var(--ink-900);
}

.value__text {
  margin-top: var(--sp-2);
  color: var(--ink-500);
  word-break: keep-all;
}

.pic-a { fill: var(--green-500); }
.pic-b { fill: var(--green-200); }
.pic-c { fill: var(--ink-200); }

.pic-line {
  fill: none;
  stroke: var(--white);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@media (max-width: 1024px) {
  .values {
    grid-template-columns: repeat(2, 1fr);
    row-gap: var(--sp-8);
  }
}

@media (max-width: 768px) {
  .values {
    grid-template-columns: 1fr;
    gap: var(--sp-8);
  }
}

/* P. Band: a navy section, its title on the left (staying in view) and a numbered list in white on the right, with
   space instead of lines between the items (after the history on bubaum.com) */

.section--ink {
  background: var(--ink-900);
  color: var(--color-on-dark);
}

.band {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: var(--sp-9);
  align-items: start;
}

.band__head {
  position: sticky;
  top: calc(var(--header-h) + var(--sp-8));
}

.section--ink .t-label { color: var(--green-400); }
.section--ink .t-h1 { color: var(--color-on-dark); }

.band__list {
  display: grid;
  gap: var(--sp-9);
}

.band__item {
  display: grid;
  grid-template-columns: var(--sp-9) 1fr;
  gap: var(--sp-4);
}

.band__num {
  padding-top: 0.45em;
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  color: var(--green-400);
  font-variant-numeric: tabular-nums;
}

.band__title {
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  letter-spacing: var(--ls-h3);
  font-weight: var(--fw-bold);
  color: var(--color-on-dark);
}

.band__text {
  margin-top: var(--sp-2);
  color: var(--color-on-dark-2);
}

@media (max-width: 1024px) {
  .band {
    grid-template-columns: 1fr;
    gap: var(--sp-8);
  }
  .band__head {
    position: static;
  }
}

@media (max-width: 768px) {
  .band__list {
    gap: var(--sp-7);
  }
  .band__item {
    grid-template-columns: var(--sp-7) 1fr;
  }
}

/* Q. Cards: numbered steps or short items as white rounded cards in one row (four, or three with .cards--3) */

.cards {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-4);
  margin-top: var(--gap-text-visual);
}

/* two cards side by side (the contact page) */
.cards--2 {
  grid-template-columns: repeat(2, 1fr);
  max-width: 820px;
}

@media (max-width: 768px) {
  .cards--2 {
    grid-template-columns: 1fr;
  }
}

.cards--3 {
  grid-template-columns: repeat(3, 1fr);
}

.card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: var(--sp-7) var(--sp-6);
  border-radius: var(--r-xl);
  background: var(--white);
}

.card__num,
.card__pic,
.value__pic {
  transform-origin: 0% 100%;
}

.value__pic {
  transform-origin: 50% 100%;
}

.card__num {
  font-size: var(--fs-h2);
  line-height: 1;
  letter-spacing: var(--ls-h2);
  font-weight: var(--fw-bold);
  color: var(--green-500);
  font-variant-numeric: tabular-nums;
}

.card__pic {
  width: 48px;
  height: 48px;
}

.card__title {
  margin-top: var(--sp-7);
  font-size: var(--fs-lead);
  line-height: var(--lh-small);
  font-weight: var(--fw-bold);
  color: var(--ink-900);
}

.card__value {
  margin-top: var(--sp-2);
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  letter-spacing: var(--ls-h3);
  font-weight: var(--fw-bold);
  color: var(--ink-900);
  word-break: break-all;
}

.card__text {
  margin-top: var(--sp-2);
  color: var(--ink-500);
  word-break: keep-all;
}

.card .btn,
.card .link-arrow {
  margin-top: auto;
}

.card__value + .btn,
.card__value + .link-arrow {
  margin-top: var(--sp-6);
}

/* Tablet: two cards a row; the contact cards, with long values, one a row */
@media (max-width: 1024px) {
  .cards {
    grid-template-columns: repeat(2, 1fr);
  }
  .cards--3 {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 768px) {
  .cards,
  .cards--3 {
    grid-template-columns: 1fr;
  }
  .card {
    padding: var(--sp-6);
  }
  .card__title {
    margin-top: var(--sp-5);
  }
}
