

::selection { background: var(--signal); color: #fff; }

.grain {
  opacity: .028;
  mix-blend-mode: soft-light;
}

.cursor__dot {
  background: var(--signal-hot);
  box-shadow: 0 0 8px rgba(99, 216, 255, .88), 0 0 22px rgba(59, 134, 255, .4);
}

.cursor__ring {
  background: radial-gradient(circle at 35% 30%, rgba(99, 216, 255, .12), transparent 65%);
  box-shadow: inset 0 0 0 1px rgba(99, 216, 255, .4), 0 5px 20px rgba(0, 0, 0, .35);
}

:focus-visible {
  outline-color: var(--signal-hot);
  outline-offset: 5px;
}

.human-kicker,
.section-index,
.contact__kicker {
  font-family: var(--font-mono);
  font-size: clamp(8.5px, .67vw, 11px);
  font-weight: 500;
  letter-spacing: .22em;
  line-height: 1.5;
  text-transform: uppercase;
  color: var(--signal-hot);
}

.human-kicker { margin-bottom: clamp(22px, 3.2vh, 40px); }
.human-kicker i { margin-inline: .55em; font-style: normal; opacity: .48; }
/* One item, one line. The dots are what group these three into a sentence, so
   a break inside one of them is a break in the wrong place, and the item's
   own hyphen is a break opportunity as much as its spaces are. The line's only
   break points are the `wbr` after each dot (see index.html). */
.human-kicker span { white-space: nowrap; }

.cta--signal {
  color: #02050c;
  border-color: var(--signal);
  background: var(--signal);
  box-shadow: 0 14px 50px -22px rgba(59, 134, 255, .78);
}

.cta--signal::before { background: rgba(255, 255, 255, .18); }

.cta--signal:hover,
.cta--signal:focus-visible {
  color: #02050c;
  border-color: var(--signal-hot);
  background: var(--signal-hot);
  box-shadow: 0 18px 56px -20px rgba(99, 216, 255, .72);
}

.text-link {
  position: relative;
  padding-block: 9px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: rgba(210, 230, 255, .84);
}

.text-link::after {
  content: '';
  position: absolute;
  right: 0;
  bottom: 3px;
  left: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(.22);
  transform-origin: left;
  transition: transform .45s var(--ease-out), color .35s ease;
}

.text-link:hover::after,
.text-link:focus-visible::after { transform: scaleX(1); }

/* ─── static editorial sections ─────────────────────────────────────── */

.static-section {
  z-index: 5;
  min-height: auto;
  overflow: hidden;
  padding: clamp(110px, 13vw, 210px) var(--gutter);
  background: var(--ink);
}

.static-section__inner {
  width: min(100%, var(--content));
  margin-inline: auto;
}

/* The eyebrow belongs to its heading. Both reference frames set the section
   label a caption's distance above the display line (reference2: ~30px over a
   56px cap); at clamp(65px, 8vw, 126px) it floated a quarter-screen clear of
   everything and read as an orphan: and every anchored arrival spent that
   whole band showing nothing. The section still breathes through its own top
   padding; the label now annotates the heading instead of hovering over it. */
.section-index { margin-bottom: clamp(20px, 2.4vw, 36px); }

/* The editorial half's section heading. It is the same lit-metal face as
   `.section-heading` in foundation.css and deliberately not the same setting:
   the diorama sections are fitted tight and condensed against reference2,
   while the editorial ones are set open and allowed to fill their column.
   One face, one case, one fill, two tempos. */
.studio-heading {
  font-family: var(--font-display);
  font-size: clamp(4rem, 8.2vw, 9.5rem);
  font-weight: 400;
  line-height: .82;
  letter-spacing: -.02em;
  text-transform: uppercase;
  text-wrap: balance;
  background: linear-gradient(177deg,
    #ffffff 2%, #eef4f7 20%, #b9c6cd 48%, #8894a0 68%, #b3c2ce 92%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.capabilities,
.studio {
  color: var(--bone);
  background: var(--ink-2);
}

.capabilities .section-index,
.studio .section-index { color: var(--signal-hot); }

/* ─── studio / contact / footer ─────────────────────────────────────── */

/* The statement is one column, and the right of the section is the mark's.
   It used to be two: the heading left, the paragraph right, aligned to its
   foot: which put the paragraph squarely on top of the mark it was meant to
   leave room for: measured at 1440, the copy sat over the ring at 22%
   brightness and read as a caption on a picture. The paragraph sits under
   its heading now, both held to the left of the mark's pocket. */
.studio__statement {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(30px, 3.4vw, 52px);
  max-width: min(100%, 60vw, 960px);
}

.studio__statement em { color: var(--signal-hot); font-style: normal; }
.studio__statement > p { max-width: 46ch; font-size: clamp(15px, 1.18vw, 19px); line-height: 1.72; color: rgba(202, 224, 255, .72); }

.studio__principles {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  margin-top: clamp(90px, 12vw, 180px);
  border-top: 1px solid var(--paper-line);
}

/* The three principles are the section's statements, not captions: set at
   reading size with the index above them, rather than 13px of type floating
   in a 150px cell of black.

   The rule between them belongs to the COLUMN, not to the sentence. It used to
   be a `border-right` on a box capped at `max-width: 26ch`, which draws the
   line at the end of the text rather than on the grid line: measured at 1440,
   three 440px columns starting at x=59, 500 and 940, and three rules at 319,
   760 and 1200: each one 180px short of the boundary it was supposed to be
   drawing, so a divided row read as three ragged marks at arbitrary places.
   The paragraph fills its cell now and the measure is held by the gutter on
   its right instead of by shrinking the box away from the line. `--lead` is
   subtracted as well, so all three columns are set to the same 26 characters
   whether or not they carry the indent. */
.studio__principles p {
  --lead: 0px;
  min-height: 128px;
  padding: 25px max(26px, calc(100% - var(--lead) - 26ch)) 20px var(--lead);
  border-right: 1px solid var(--paper-line);
  font-size: clamp(15px, 1.15vw, 18px);
  line-height: 1.5;
  color: var(--bone);
  text-wrap: balance;
}
.studio__principles p + p { --lead: 26px; }
.studio__principles p:last-child { border-right: 0; }
.studio__principles span { display: block; margin-bottom: 26px; font-family: var(--font-mono); font-size: 10px; letter-spacing: .18em; color: var(--signal-hot); }
.contact__kicker { color: rgba(202, 224, 255, .66); }

.contact__title {
  margin-top: clamp(24px, 3vw, 42px);
  font-family: var(--font-display);
  font-size: clamp(5.5rem, 13.5vw, 15rem);
  font-weight: 400;
  /* .7 was fitted on a single line. Two lines of Bebas at 15rem overlap at
     that leading: the second line's cap height crosses the first's baseline. */
  line-height: .78;
  letter-spacing: -.05em;
  text-transform: uppercase;
}

.contact__copy { margin-top: clamp(40px, 5vw, 76px); font-size: clamp(16px, 1.3vw, 21px); }

/* The closing action bar. The rules the row lives by: the address is the
   studio's one address and stays readable at rest, the button is the primary
   control and is the only full-strength signal element in this viewport, and
   the two hairlines that bracket them warm together on hover so the row reads
   as a single surface rather than as two unrelated links stacked on a line. */
.contact__action {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: clamp(18px, 2.4vw, 34px);
  margin-top: clamp(36px, 4vw, 60px);
  padding: clamp(18px, 1.9vw, 26px) 0;
  border-top: 1px solid rgba(122, 173, 255, .38);
  border-bottom: 1px solid rgba(122, 173, 255, .38);
  transition: border-color .5s var(--ease-out);
}

.contact__action:hover,
.contact__action:focus-within { border-color: rgba(99, 216, 255, .58); }

/* The studio's one address, and a link. The vertical padding is what makes it
   a target as well as a line: set solid it was 23px tall on a phone, under the
   24px a finger is entitled to, and it is the control a reader reaches for when
   they would rather write the mail themselves than fill the brief in. The row
   it sits in centres its items, so the padding costs the composition nothing. */
.contact__email {
  padding-block: 5px;
  font-family: var(--font-mono);
  font-size: clamp(13px, 1.35vw, 20px);
  letter-spacing: .06em;
  color: var(--text-1);
  border-bottom: 1px solid transparent;
  transition: color .4s var(--ease-out), border-color .4s var(--ease-out);
}

.contact__email:hover,
.contact__email:focus-visible { color: var(--signal-hot); border-color: var(--signal-hot); }

.contact__action .cta { margin-top: 0; flex: none; }

.footer {
  position: relative;
  z-index: 5;
  padding: 72px var(--gutter) max(34px, env(safe-area-inset-bottom));
  background: var(--ink);
  border-top: 1px solid var(--hair-soft);
}

.footer__inner {
  width: min(100%, var(--content));
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;
  gap: 34px;
}

/* The header's own logo, at the height the header wears it over content. */
.footer__mark { display: block; width: fit-content; }
.footer__mark img { display: block; height: 44px; width: auto; }
.footer__slogan { margin-top: .9em; font-size: 10px; color: rgba(176, 204, 246, .70); }
/* Wraps: five items at this tracking are wider than a phone, and a row that
   cannot wrap is cut off at the edge: measured at 390px, where the last
   item ran under the window's right edge and the document grew six pixels
   wider than the screen. */
/* The row gap is 2px rather than 12 because the links carry the other ten as
   their own padding: at 10.5px of mono a footer link is a 16px-tall target,
   under the 24px a finger is entitled to, and five of them wrapped onto two
   rows on a phone. The padding grows the hit area without moving the type,
   the pitch between wrapped rows is the 28px it always was. */
.footer__nav { display: flex; flex-wrap: wrap; gap: 2px 30px; font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .15em; text-transform: uppercase; }
.footer__nav a { display: inline-block; padding-block: 5px; transition: color .35s var(--ease-out); }
.footer__nav a:hover, .footer__nav a:focus-visible { color: var(--signal-hot); }
/* The colophon line. It is set to the RIGHT edge of the footer, so its type has
   to be set right as well: at 1440 the sentence is 404px against a 404px track
   and wraps, and left-set inside a right-placed box that put "reserved." alone
   under the start of the line: a ragged edge on the side the eye is reading
   from. Set right, and balanced so the break lands mid-sentence rather than
   leaving one word to hold a line by itself. */
.footer__legal { justify-self: end; text-align: right; text-wrap: balance; font-family: var(--font-mono); font-size: 10px; color: rgba(186, 212, 248, .74); }

@media (max-width: 900px), (max-height: 639px), (max-aspect-ratio: 1/1) {

  .human-kicker { margin-bottom: 22px; }

  .static-section {
    display: block;
    min-height: auto;
    padding: clamp(88px, 21vw, 140px) var(--gutter);
  }

  .section-index { margin-bottom: 24px; }
  .studio-heading { font-size: clamp(3.65rem, 16vw, 7rem); }

  .studio__statement { max-width: none; gap: 36px; }

  .studio__principles { grid-template-columns: 1fr; }
  .studio__principles p,
  .studio__principles p + p { min-height: auto; padding: 24px 0; border-right: 0; border-bottom: 1px solid var(--paper-line); }
  .studio__principles span { margin-bottom: 18px; }
  .contact__title { font-size: clamp(6rem, 29vw, 12rem); }
  /* Narrow: the address sits above its button rather than beside it, and the
     button goes full width so the last control on the page is also the widest
     touch target on it. */
  .contact__action { flex-direction: column; align-items: stretch; gap: 20px; }
  .contact__email { font-size: clamp(12px, 3.6vw, 15px); justify-self: start; width: fit-content; }
  .contact__action .cta { justify-content: space-between; width: 100%; }

  .footer__inner { grid-template-columns: 1fr auto; }
  .footer__nav { grid-row: 2; justify-self: start; }
  .footer__legal { grid-row: 2; }
}

@media (max-width: 520px) {
  .studio-heading { font-size: clamp(3.2rem, 15vw, 5.5rem); }
  .footer__inner { display: flex; flex-direction: column; align-items: flex-start; }
  .footer__nav { gap: 2px 22px; }
  /* One column, everything set from the left: a right-set line has no right
     edge to be set to once the grid is a stack. */
  .footer__legal { justify-self: start; text-align: left; }
}

/* ============================================================
   THE HERO MARK: the artifact discovered by light
   ============================================================
   The studio's mark standing at the back of the opening chapter, where the
   Spline robot used to. `styles/swarm.css` owns where it sits in the stack;
   this owns how it is lit.

   It is the same mechanic the STUDIO section runs on (styles/editorial.css,
   "the artifact is discovered by light") and deliberately the same one, not a
   second invention: near-black at rest, brought up by proximity, and read
   across by a travelling window that follows the pointer. Three layers, and
   the reason there are three is that the middle one is what makes the reveal
   feel spatial rather than like a fade,

     .hero-mark__img    the mark at rest, edges dissolved into the dark
     .hero-mark::before a cold pool under it, so it is lit from somewhere
     .hero-mark::after  the same mark at FULL strength, seen through a circle
                        of light that tracks the pointer

   `--prox`, `--px` and `--py` are written by scripts/studio/attention.js onto
   this element, so `--px`/`--py` are the pointer's position in the mark's own
   box and the window lands exactly under the cursor. The studio section
   registers its whole section instead, which is looser and is fine there
   because the mark is the only thing on that side of it.

   At rest this runs to 0.20 rather than the studio's 0.22: the hero already
   carries the particle field, the wave and the copy, and the mark is the
   quietest of the four until someone reaches for it. */
.hero-mark__img,
.hero-mark__light,
.hero-mark::before,
.hero-mark::after {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  /* The object in the room. The mark's box is carried by the journey
     (styles/swarm.css: its offset, its scale, and the transition that lifts
     it into place at boot) and that rule is not touched; the TURN is on the
     four layers inside the box, identically, so the pool, the light, the
     image and the travelling window turn as one object under one lens.

     Two angles, added. The scroll's, `--mrot`, written by scripts/process/
     journey.js as sin(π · travel), so the V shows its side as the camera
     passes it and squares up again as it settles, leaving the flare exactly
     where the orbit is born from: turns its right-hand stroke away and its
     top away, which is how an object passed on its left and rising above
     the eye turns. The hand's: `--px`/`--py` are the pointer's place in the
     mark's own box (scripts/studio/attention.js), so the object leans a few
     degrees toward the hand, weighted by how near the hand is; on a coarse
     pointer neither is ever written and both terms are the identity. A
     single lens for all four, so the perspective is one perspective. Never
     transitioned: the values are per frame, and the attention field already
     damps the hand. */
  transform: perspective(1400px)
             rotateY(calc(var(--mrot, 0) * 14deg + (var(--px, 0.5) - 0.5) * (2.2deg + var(--prox, 0) * 3.4deg)))
             rotateX(calc(var(--mrot, 0) * 6deg + (0.5 - var(--py, 0.5)) * (1.6deg + var(--prox, 0) * 2.4deg)));
  transform-origin: 50% 50%;
  backface-visibility: hidden;
}

.hero-mark__img {
  max-width: none;
  margin: 0;
  object-fit: contain;
  opacity: calc(0.20 + var(--prox, 0) * 0.38);
  transition: opacity 620ms var(--ease-ui);
  /* The same radial dissolve the studio's mark wears, so the image has no
     edge of its own and ends in the dark rather than in a rectangle.

     Its centre travels. `--mark-p` is how far the V is along its journey into
     the process section (scripts/process/journey.js, 0 at rest), and as it
     rises the window of light moves toward the upper right with it, so the
     lower point of the V dissolves into the dark first while the upper arc
     and the bright right-hand stroke keep their light. The mark is not
     redrawn or cropped; only where it ends in the page moves. */
  mask-image: radial-gradient(70% 70% at calc(50% + var(--mark-p, 0) * 9%) calc(50% - var(--mark-p, 0) * 8%),
    #000 18%, rgba(0, 0, 0, 0.5) 52%, transparent 82%);
  -webkit-mask-image: radial-gradient(70% 70% at calc(50% + var(--mark-p, 0) * 9%) calc(50% - var(--mark-p, 0) * 8%),
    #000 18%, rgba(0, 0, 0, 0.5) 52%, transparent 82%);
}

/* The pool. Cyan, low, and under the mark rather than on it, the mark is lit
   from somewhere, and this is the somewhere. */
.hero-mark::before {
  content: "";
  background: radial-gradient(46% 46% at 50% 66%, rgba(0, 170, 210, 0.10), transparent 68%);
  opacity: calc(0.24 + var(--prox, 0) * 0.42);
  transition: opacity 620ms var(--ease-ui);
}

/* The light. What the mark throws into the air around it, a wide cold halo
   about the ring, on the page's blue, and a bloom at the flare on its cyan,
   under the image and over the pool, so the object is lit in a VOLUME rather
   than standing on a lit ground. Both fall off the way light does: a bright
   core, a long tail, and nothing at the edge, so the plate has no edge for
   the eye to find. It rises with the pointer on the same number the pool
   does, a touch steeper, so reaching for the mark is reaching into its
   light; and it is never brighter than the stroke it comes from. The flare's
   place restates FLARE in scripts/process/orbit.js and the halo's restates
   HALO, which tests/process.mjs holds to the artwork. */
.hero-mark__light {
  background:
    radial-gradient(11% 11% at 70.6% 27.5%,
      rgba(120, 232, 255, 0.34) 0%, rgba(80, 210, 250, 0.16) 30%,
      rgba(40, 170, 230, 0.05) 62%, transparent 100%),
    radial-gradient(44% 44% at 50% 50.6%,
      rgba(60, 150, 235, 0.17) 0%, rgba(50, 130, 220, 0.09) 34%,
      rgba(34, 96, 180, 0.035) 64%, transparent 100%);
  opacity: calc(0.42 + var(--prox, 0) * 0.5);
  transition: opacity 620ms var(--ease-ui);
}

/* The travelling window. A second copy of the mark at full strength, masked to
   a circle of light under the pointer. `background-image` is named here rather
   than injected by script the way the studio's is: this one is on the first
   screen, the file is already being fetched for the <img> above it, and the
   browser serves the second reference from cache. */
.hero-mark::after {
  content: "";
  background-image: image-set(url("/assets/logo-mark.png") 1x, url("/assets/logo-mark-2x.png") 2x);
  background-image: -webkit-image-set(url("/assets/logo-mark.png") 1x, url("/assets/logo-mark-2x.png") 2x);
  /* The WebP encodings, last, so a browser that understands `type()` takes
     them and one that does not keeps the PNG set above. Same two densities,
     same rule about which one a display fetches (tools/brand/webp.mjs). */
  background-image: image-set(url("/assets/logo-mark.webp") type("image/webp") 1x, url("/assets/logo-mark-2x.webp") type("image/webp") 2x);
  background-position: center;
  background-size: contain;
  background-repeat: no-repeat;
  mask-image: radial-gradient(
    circle 210px at calc(var(--px, 0.5) * 100%) calc(var(--py, 0.5) * 100%),
    #000 0%, rgba(0, 0, 0, 0.55) 35%, transparent 72%
  );
  -webkit-mask-image: radial-gradient(
    circle 210px at calc(var(--px, 0.5) * 100%) calc(var(--py, 0.5) * 100%),
    #000 0%, rgba(0, 0, 0, 0.55) 35%, transparent 72%
  );
  opacity: var(--prox, 0);
  transition: opacity 520ms var(--ease-ui);
}

/* No pointer, no proximity. On touch there is nothing to carry the light, so
   the artifact would sit at its resting fifth for the whole visit; it is given
   its lit value outright and the travelling window is dropped. The studio
   section makes the same trade for the same reason. */
@media (hover: none), (pointer: coarse) {
  .hero-mark__img { opacity: 0.52; }
  .hero-mark::before { opacity: 0.5; }
  .hero-mark__light { opacity: 0.62; }
  .hero-mark::after { display: none; }
}

/* ---------- The receipt under the hero's controls ---------- */
/* One number and one sentence. The claim above it, AI-directed products,
   built end to end: is a claim about pace as much as about scope, and a claim
   about pace that carries no number is the kind of thing every studio says.
   Set quiet and small: it is evidence under the controls, not a second
   headline competing with the first. */
.hero-receipt {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-top: clamp(22px, 2.6vh, 34px);
  max-width: 46ch;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-2);
  text-wrap: pretty;
}
.hero-receipt__n {
  flex: none;
  font-family: var(--font-display);
  font-size: clamp(30px, 3vw, 44px);
  line-height: 0.9;
  color: var(--cyan-l3);
  text-shadow: 0 0 18px var(--cyan-l3-glow);
}
@media (max-width: 767px) {
  .hero-receipt { font-size: 13px; gap: 11px; }
}
