/* =========================================================================
   PUBBLIKA — web development studio
   Near-black ground, one typeface, single weight, all-caps headings,
   hairline rules, a lot of air. Structure is a full-service agency layout.
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. TOKENS
   ------------------------------------------------------------------------- */
:root {
  --bg:        #040404;
  --bg-2:      #0A0A0A;
  --fg:        #FFFFFF;
  --fg-70:     rgba(255, 255, 255, 0.70);
  --fg-50:     rgba(255, 255, 255, 0.50);
  --fg-35:     rgba(255, 255, 255, 0.35);
  --line:      rgba(255, 255, 255, 0.14);
  --line-2:    rgba(255, 255, 255, 0.08);

  /* the one carry-over from the brand — used sparingly, never as decoration */
  --accent:    #C4643F;

  --font:      'Space Grotesk', 'Helvetica Neue', Arial, sans-serif;

  --gut:       clamp(1.25rem, 5vw, 5rem);
  --sec-y:     clamp(5rem, 12vw, 11rem);
  --maxw:      1600px;

  --ease:      cubic-bezier(0.22, 1, 0.36, 1);

  /* Panels sit slightly transparent so the fixed gradient reads through them
     instead of being punched out in rectangles. */
  --panel:     rgba(4, 4, 4, 0.62);

  /* scroll progress, 0 → 1, written by main.js */
  --sp: 0;
}

/* -------------------------------------------------------------------------
   2. RESET
   ------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-weight: 300;
  font-size: clamp(0.95rem, 0.9rem + 0.22vw, 1.0625rem);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; padding: 0; }
button, input, textarea, select { font: inherit; color: inherit; }

::selection { background: var(--fg); color: var(--bg); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--fg); color: var(--bg); padding: 0.8rem 1.2rem;
}
.skip:focus { left: 0; }

/* Off-screen but still announced — used for the "opens in a new tab" note. */
.vh {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

/* -------------------------------------------------------------------------
   3. TYPE
   ------------------------------------------------------------------------- */
h1, h2, h3 {
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: -0.005em;
  line-height: 1.06;
}

/* The small technical label used everywhere — section numbers, captions,
   field labels. Wide tracking, never larger than 0.72rem. */
.lbl {
  font-size: 0.68rem;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--fg-50);
  display: flex;
  align-items: baseline;
  gap: 0.9rem;
  flex-wrap: wrap;
}
.lbl .num { color: var(--fg-35); }
.lbl .sep { color: var(--fg-35); }

/* -------------------------------------------------------------------------
   3b. MEDIA
   Work covers are full colour at rest — they are the loud thing on an
   otherwise monochrome page. Hover just pushes them a little further.
   ------------------------------------------------------------------------- */
.media {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: var(--bg-2);
}
.media img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  filter: none;
  transform: scale(1.01);
  transition: filter 0.6s var(--ease), transform 1.2s var(--ease);
}
.media--tall { aspect-ratio: 4 / 5; }

/* dimmed only while still below the fold, so it arrives rather than pops */
.reveal.is-armed .media img { filter: brightness(0.55) saturate(0.7); }

.proj:hover .media img {
  filter: saturate(1.18) contrast(1.05);
  transform: scale(1.05);
}

@media (prefers-reduced-motion: reduce) {
  .media img,
  .reveal.is-armed .media img { transform: none; filter: none; transition: none; }
  .proj:hover .media img { transform: none; }
  .proj__visit { transform: none; transition: opacity 0.01ms; }
}

/* -------------------------------------------------------------------------
   4. HEADER
   ------------------------------------------------------------------------- */
.hdr {
  position: fixed;
  inset: 0 0 auto;
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.4rem var(--gut);
  mix-blend-mode: difference;   /* stays legible over the hero */
  transition: background 0.4s var(--ease), padding 0.4s var(--ease);
}
/* Once content is scrolling underneath, difference blending turns the logo
   to mush against body copy — swap to a solid backdrop instead. */
.hdr.is-stuck {
  mix-blend-mode: normal;
  background: rgba(4, 4, 4, 0.88);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line-2);
  padding-block: 1rem;
}
.brand { display: inline-flex; align-items: center; gap: 0.55rem; }
.brand__mark {
  width: 28px; height: 28px;
  fill: none; stroke: var(--fg); stroke-width: 2.4;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform 0.6s var(--ease);
}
.brand:hover .brand__mark { transform: rotate(-14deg); }
.brand__word {
  font-size: 1.05rem; font-weight: 500; letter-spacing: -0.02em;
}

.hdr__right { display: flex; align-items: center; gap: clamp(1rem, 2vw, 2rem); }
.hdr__cta {
  font-size: 0.68rem; letter-spacing: 0.2em; text-transform: uppercase;
  padding-bottom: 3px; border-bottom: 1px solid var(--line);
  transition: border-color 0.3s var(--ease);
}
.hdr__cta:hover { border-color: var(--fg); }

.menu-btn {
  width: 34px; height: 22px;
  background: none; border: 0; padding: 0; cursor: pointer;
  position: relative;
}
.menu-btn span {
  position: absolute; left: 0; width: 100%; height: 1px;
  background: var(--fg);
  transition: transform 0.4s var(--ease), opacity 0.25s;
}
.menu-btn span:nth-child(1) { top: 6px; }
.menu-btn span:nth-child(2) { top: 15px; }
.menu-btn[aria-expanded="true"] span:nth-child(1) { transform: translateY(4.5px) rotate(45deg); }
.menu-btn[aria-expanded="true"] span:nth-child(2) { transform: translateY(-4.5px) rotate(-45deg); }

/* -------------------------------------------------------------------------
   5. OVERLAY MENU
   ------------------------------------------------------------------------- */
.menu {
  position: fixed; inset: 0; z-index: 80;
  background: var(--bg);
  display: grid; place-items: center;
  /* visibility (not the hidden attribute) so it stays animatable while still
     leaving the tab order and the accessibility tree when closed */
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.5s var(--ease), visibility 0s linear 0.5s;
}
.menu.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.5s var(--ease), visibility 0s;
}

.menu__inner { width: min(var(--maxw), 100%); padding: 6rem var(--gut) 3rem; }
.menu__list { display: grid; gap: clamp(0.2rem, 1vw, 0.6rem); }
.menu__list a {
  display: flex; align-items: baseline; gap: 1.4rem;
  font-size: clamp(2rem, 7vw, 5rem);
  text-transform: uppercase;
  line-height: 1.1;
  transition: color 0.3s var(--ease), transform 0.5s var(--ease);
}
.menu__list i {
  font-style: normal; font-size: 0.7rem; letter-spacing: 0.2em;
  color: var(--fg-35);
}
.menu__list a:hover { color: var(--accent); transform: translateX(14px); }

.menu__meta {
  display: flex; flex-wrap: wrap; gap: clamp(2rem, 6vw, 6rem);
  margin-top: clamp(2.5rem, 6vw, 5rem);
  padding-top: 2rem; border-top: 1px solid var(--line);
  font-size: 0.9rem; color: var(--fg-70);
}
.menu__meta .lbl { margin-bottom: 0.7rem; }
.menu__soc { display: flex; gap: 1.2rem; }
.menu__meta a:hover { color: var(--fg); }

/* -------------------------------------------------------------------------
   6. HERO
   ------------------------------------------------------------------------- */
.hero {
  position: relative;
  max-width: var(--maxw); margin-inline: auto;
  padding: clamp(8rem, 16vh, 12rem) var(--gut) clamp(3rem, 6vw, 5rem);
}

/* -------------------------------------------------------------------------
   6b. THE GRADIENT
   Fixed behind the whole document, not just the hero, so the colour field
   carries through every section. Two layers per blob:
     .grad__b  — offset by scroll progress (--sp, set in JS, 0 → 1)
     .grad__b i — its own slow drift loop
   Splitting them means the scroll offset and the idle drift can both live on
   `transform` without overwriting each other.
   ------------------------------------------------------------------------- */
/* Only the sections carrying .has-grad get a colour field — the hero, the
   statement band and the contact footer. Everywhere else stays flat black,
   so the gradient reads as punctuation rather than wallpaper. */
.has-grad { position: relative; isolation: isolate; }
.has-grad > *:not(.grad) { position: relative; z-index: 1; }

.grad {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;            /* nothing here may widen the page */
}

/* A blurred, animating colour field costs the compositor every frame whether
   or not it is on screen — three of these were running at all times. JS adds
   .grad--rest to any .has-grad section further than a viewport away, which
   stops the drift and lets the browser drop the layers. The margin is a full
   viewport either side, so nothing is ever hidden while it could be seen. */
.grad--rest .grad { visibility: hidden; }
.grad--rest .grad__b i { animation-play-state: paused; }
.grad__b {
  position: absolute;
  display: block;
  width: 62vw; height: 62vw;
  min-width: 440px; min-height: 440px;
  will-change: transform;
  /* smooths the scroll offset into a drift rather than a 1:1 jump */
  transition: transform 1.1s cubic-bezier(0.22, 1, 0.36, 1);
}
.grad__b i {
  position: absolute;
  inset: 0;
  display: block;
  border-radius: 50%;
  /* Less blur than before: at 100px the fields were so diffuse that motion
     was invisible. Tighter edges make the movement legible. */
  filter: blur(76px);
  mix-blend-mode: screen;
  opacity: 0.5;
  will-change: transform;
  /* each field runs a continuous circuit rather than a slow ping-pong —
     0% and 100% match, so it loops without a visible reversal */
  animation-iteration-count: infinite;
  animation-timing-function: ease-in-out;
}

.grad__b--1 { top: -16%; left: -8%;
  transform: translate3d(calc(var(--sp) * 26vw), calc(var(--sp) * 34vh), 0); }
.grad__b--1 i {
  background: radial-gradient(circle, #4FD8E8 0%, rgba(79, 216, 232, 0) 66%);
  animation-name: drift-1;
  animation-duration: 14s;
}

.grad__b--2 { top: -6%; left: 36%;
  transform: translate3d(calc(var(--sp) * -32vw), calc(var(--sp) * 46vh), 0); }
.grad__b--2 i {
  background: radial-gradient(circle, #7C4EF4 0%, rgba(124, 78, 244, 0) 66%);
  animation-name: drift-2;
  animation-duration: 18s;
}

.grad__b--3 { top: 14%; left: 8%;
  transform: translate3d(calc(var(--sp) * 20vw), calc(var(--sp) * -40vh), 0); }
.grad__b--3 i {
  background: radial-gradient(circle, #3B488C 0%, rgba(59, 72, 140, 0) 68%);
  animation-name: drift-3;
  animation-duration: 16s;
}

/* the brand accent, kept in the mix so it still reads as Pubblika */
.grad__b--4 { top: -2%; left: 56%;
  transform: translate3d(calc(var(--sp) * -24vw), calc(var(--sp) * -30vh), 0); }
.grad__b--4 i {
  background: radial-gradient(circle, #C4643F 0%, rgba(196, 100, 63, 0) 64%);
  animation-name: drift-4;
  animation-duration: 21s;
  opacity: 0.42;
}

/* -------------------------------------------------------------------------
   6c. WHAT WE DO — plain list, directly under the hero statement
   ------------------------------------------------------------------------- */
.offer {
  margin-top: clamp(2.5rem, 6vw, 4.5rem);
}
.offer > .lbl { margin-bottom: 1.6rem; }
.offer__list { border-top: 1px solid var(--line); }
.offer__row {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 15rem) minmax(0, 1fr);
  gap: clamp(0.8rem, 3vw, 2.5rem);
  align-items: baseline;
  padding: clamp(1.1rem, 2.4vw, 1.6rem) 0;
  border-bottom: 1px solid var(--line);
}
.offer__no {
  font-size: 0.68rem; letter-spacing: 0.2em; color: var(--fg-35);
}
.offer__row h3 { font-size: clamp(1.2rem, 2.1vw, 1.7rem); }
.offer__row p { color: var(--fg-70); font-size: 0.95rem; max-width: 52ch; }

/* Four-point circuits. First and last frame match so each loop is seamless,
   and no two share a duration, so the fields never fall into step. */
@keyframes drift-1 {
  0%, 100% { transform: translate3d(-4vw, -6vh, 0) scale(1); }
  25%      { transform: translate3d(20vw,  8vh, 0) scale(1.35); }
  50%      { transform: translate3d(12vw, 22vh, 0) scale(1.05); }
  75%      { transform: translate3d(-10vw, 10vh, 0) scale(0.85); }
}
@keyframes drift-2 {
  0%, 100% { transform: translate3d(6vw, 4vh, 0) scale(1.1); }
  25%      { transform: translate3d(-18vw, 18vh, 0) scale(0.85); }
  50%      { transform: translate3d(-24vw, -8vh, 0) scale(1.3); }
  75%      { transform: translate3d(-4vw, -18vh, 0) scale(1); }
}
@keyframes drift-3 {
  0%, 100% { transform: translate3d(0, 8vh, 0) scale(0.9); }
  25%      { transform: translate3d(24vw, -6vh, 0) scale(1.25); }
  50%      { transform: translate3d(8vw, -22vh, 0) scale(1); }
  75%      { transform: translate3d(-14vw, -4vh, 0) scale(1.15); }
}
@keyframes drift-4 {
  0%, 100% { transform: translate3d(-2vw, 2vh, 0) scale(1.15); }
  25%      { transform: translate3d(-20vw, 16vh, 0) scale(0.9); }
  50%      { transform: translate3d(-8vw, 26vh, 0) scale(1.25); }
  75%      { transform: translate3d(14vw, 12vh, 0) scale(1); }
}

/* Motion is the decorative part — the colour field itself can stay. */
@media (prefers-reduced-motion: reduce) {
  .grad__b { transform: none; transition: none; }
  .grad__b i { animation: none; }
}
.hero__spread {
  display: flex; flex-wrap: wrap;
  font-size: clamp(0.7rem, 1.1vw, 0.85rem);
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--fg-50);
  margin-bottom: clamp(1.5rem, 4vw, 3rem);
  min-height: 1.2em;
}
.hero__spread span {
  opacity: 0; transform: translateY(6px);
  animation: rise 0.6s var(--ease) forwards;
}
.hero__spread .sp { width: 0.7em; }
@keyframes rise { to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .hero__spread span { opacity: 1; transform: none; animation: none; }
}

.hero__stmt {
  font-size: clamp(1.9rem, 5.4vw, 4.6rem);
  line-height: 1.04;
}
.hero__foot {
  display: flex; flex-wrap: wrap; gap: 1.5rem;
  justify-content: space-between; align-items: flex-end;
  margin-top: clamp(2.5rem, 6vw, 4.5rem);
  padding-bottom: clamp(2.5rem, 6vw, 4.5rem);
  border-bottom: 1px solid var(--line);
}
.hero__foot .lbl { display: block; line-height: 2; }

.arrow-link {
  display: inline-flex; align-items: center; gap: 0.8rem;
  font-size: 0.68rem; letter-spacing: 0.2em; text-transform: uppercase;
}
.arrow-link svg {
  width: 30px; height: 12px; fill: none; stroke: currentColor;
  stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round;
  transition: transform 0.4s var(--ease);
}
.arrow-link:hover svg { transform: translateX(8px); }


/* -------------------------------------------------------------------------
   7. STATEMENT BAND
   ------------------------------------------------------------------------- */
.stmt {
  max-width: var(--maxw); margin-inline: auto;
  padding: var(--sec-y) var(--gut);
}
.stmt__line {
  font-size: clamp(1.3rem, 3.4vw, 3rem);
  line-height: 1.18;
  max-width: 24ch;
  text-transform: uppercase;
}

/* -------------------------------------------------------------------------
   8. SECTION SHELL
   ------------------------------------------------------------------------- */
.sec {
  max-width: var(--maxw); margin-inline: auto;
  padding: var(--sec-y) var(--gut);
  border-top: 1px solid var(--line);
}
.sec__head { margin-bottom: clamp(2.5rem, 6vw, 4.5rem); }
.sec__head .lbl { margin-bottom: 1.6rem; }
.sec__title { font-size: clamp(1.8rem, 4.6vw, 3.8rem); }
.sec__lede {
  color: var(--fg-70); max-width: 46ch; margin-top: 1.4rem;
}

/* -------------------------------------------------------------------------
   9. FILTERS
   ------------------------------------------------------------------------- */
.filters {
  display: flex; flex-wrap: wrap; gap: 0.5rem;
  margin-bottom: clamp(1.8rem, 4vw, 3rem);
}
.chip {
  background: none; cursor: pointer;
  border: 1px solid var(--line);
  border-radius: 100px;
  padding: 0.5rem 1.05rem;
  font-size: 0.66rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--fg-50);
  transition: color 0.3s var(--ease), border-color 0.3s var(--ease),
              background 0.3s var(--ease);
}
.chip:hover { color: var(--fg); border-color: var(--fg-35); }
.chip.is-on { background: var(--fg); border-color: var(--fg); color: var(--bg); }

.grid__empty { color: var(--fg-50); font-size: 0.95rem; }

/* -------------------------------------------------------------------------
   10. WORK GRID
   ------------------------------------------------------------------------- */
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2.4vw, 2.2rem);
}
.proj { display: block; }
.proj[hidden] { display: none; }
.proj__meta { padding-top: 1rem; }
.proj__meta h3 { font-size: clamp(1rem, 1.4vw, 1.2rem); margin-bottom: 0.5rem; }

/* Live projects are anchors, so the whole card is one hit area. Two
   affordances, because one of them only works with a mouse:
     .proj__url    always visible, under the caption
     .proj__visit  a badge that rises out of the cover on hover
   Both point at the same href — the card itself. */
a.proj { cursor: pointer; }
a.proj:focus-visible { outline-offset: 6px; }

.proj__url {
  display: inline-flex;
  align-items: baseline;
  gap: 0.45rem;
  margin-top: 0.15rem;
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  color: var(--fg-35);
  transition: color 0.35s var(--ease);
}
.proj__url::after { content: "\2197"; font-size: 0.78rem; line-height: 1; }
a.proj:hover .proj__url,
a.proj:focus-visible .proj__url { color: var(--accent); }

/* Pinned to literal ink rather than tokens: this sits on a screenshot,
   which can be any colour, so it has to carry its own contrast. */
.proj__visit {
  position: absolute;
  left: 1rem;
  bottom: 1rem;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.62rem 1rem;
  font-size: 0.62rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #fff;
  background: rgba(8, 7, 10, 0.8);
  border: 1px solid rgba(255, 255, 255, 0.45);
  opacity: 0;
  transform: translateY(9px);
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease),
              background-color 0.4s var(--ease), color 0.4s var(--ease);
}
.proj__visit::after { content: "\2197"; }
a.proj:hover .proj__visit,
a.proj:focus-visible .proj__visit { opacity: 1; transform: none; }
a.proj:hover .proj__visit { background: #fff; border-color: rgba(8, 7, 10, 0.22); color: #08070A; }

/* No hover on touch — show it outright rather than hiding the affordance. */
@media (hover: none) {
  .proj__visit { opacity: 1; transform: none; }
  a.proj:hover .proj__visit { background: rgba(8, 7, 10, 0.72); border-color: rgba(255, 255, 255, 0.45); color: #fff; }
}

/* -------------------------------------------------------------------------
   10b. LIGHT SECTION
   A full-bleed paper block between two gradient sections — the one place the
   page inverts. It works by redefining the colour tokens inside the section
   rather than restating every rule, so everything below inherits the flip.
   ------------------------------------------------------------------------- */
/* One token set, two light regions: the services section and the proof block.
   `--bg` is flipped too, so every "invert on hover" rule that paints
   `var(--fg)` behind `var(--bg)` text still reads correctly on paper. */
.sec--light,
.light-block {
  --fg:      #08070A;
  --fg-70:   rgba(8, 7, 10, 0.72);
  --fg-50:   rgba(8, 7, 10, 0.52);
  --fg-35:   rgba(8, 7, 10, 0.34);
  --line:    rgba(8, 7, 10, 0.16);
  --line-2:  rgba(8, 7, 10, 0.08);
  --paper:   #F4F3EF;
  --panel:   #F4F3EF;
  --bg:      #F4F3EF;

  background: var(--paper);
  color: var(--fg);
}

.sec--light {
  max-width: none;
  padding-inline: 0;
  border-top: none;
}

/* the colour change is the divider — no hairline needed at the top edge */
.light-block > *:first-child { border-top: none; }
.sec--light .sec__inner {
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gut);
}

/* Service illustrations. Strokes are `currentColor`, so when a row inverts on
   hover the whole drawing flips with the text. The accent stays clay in both
   states — it is the one fixed note in each scene. */
.svc__art {
  width: 100%;
  max-width: 210px;
  height: auto;
  justify-self: end;
  align-self: center;
}
.svc__art .ln {
  fill: none;
  stroke: currentColor;
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.svc__art .bar {
  fill: none;
  stroke: currentColor;
  stroke-width: 9;
  stroke-linecap: round;
}
.svc__art .ground { opacity: 0.3; }
.svc__art .hi { fill: var(--accent); stroke: none; }
.svc__art .hi-ln {
  fill: none;
  stroke: var(--accent);
  stroke-width: 7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The section number becomes the graphic element — set at display size in
   the left column instead of a 0.68rem caption. */
.sec--light .svc__no {
  font-size: clamp(2.2rem, 4.4vw, 3.6rem);
  font-weight: 300;
  letter-spacing: -0.03em;
  line-height: 0.9;
  color: var(--fg-35);
  padding-top: 0;
  transition: color 0.45s var(--ease);
}

.sec--light .svc__row {
  position: relative;
  transition: color 0.45s var(--ease);
  /* wider first column than the dark sections — the numerals are display size
     now. `auto` lets it size to the number instead of clipping it. */
  grid-template-columns:
    minmax(6.5rem, auto) minmax(0, 1fr) minmax(0, 1.2fr) minmax(140px, 210px);
}
/* These carry .sec--light specificity, so they must be restated per
   breakpoint — otherwise they outrank the plain .svc__row media rules. */
@media (max-width: 1080px) {
  .sec--light .svc__row { grid-template-columns: minmax(5rem, auto) 1fr; }
  /* illustration drops under the copy rather than squeezing the text */
  .sec--light .svc__art { grid-column: 2; justify-self: start; margin-top: 1.4rem; }
}
@media (max-width: 620px) {
  .sec--light .svc__row { grid-template-columns: 1fr; }
  .sec--light .svc__no { font-size: 2rem; }
  .sec--light .svc__art { grid-column: 1; max-width: 190px; }
}
/* the ink wipe — inset negatively so it bleeds past the text column */
.sec--light .svc__row::before {
  content: '';
  position: absolute;
  inset: 0 clamp(-1.5rem, -2vw, -0.75rem);
  /* explicit ink, not var(--bg) — inside .sec--light that token is paper */
  background: #08070A;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.55s var(--ease);
  z-index: 0;
}
.sec--light .svc__row > * { position: relative; z-index: 1; }

/* Hovering flips the tokens back to the dark set, so the heading, body,
   number and tag borders all invert together. */
.sec--light .svc__row:hover {
  --fg:     #FFFFFF;
  --fg-70:  rgba(255, 255, 255, 0.72);
  --fg-50:  rgba(255, 255, 255, 0.52);
  --fg-35:  rgba(255, 255, 255, 0.38);
  --line:   rgba(255, 255, 255, 0.28);
  color: var(--fg);
}
.sec--light .svc__row:hover::before { transform: scaleX(1); }
.sec--light .svc__row:hover .svc__no { color: var(--accent); }

.sec--light .svc__row:hover { background: none; }   /* the wipe handles it */

@media (prefers-reduced-motion: reduce) {
  .sec--light .svc__row::before { transition: none; }
}

/* -------------------------------------------------------------------------
   11. SERVICES
   ------------------------------------------------------------------------- */
.svc { border-top: 1px solid var(--line); }
.svc__row {
  display: grid;
  grid-template-columns: 7rem minmax(0, 1.1fr) minmax(0, 1.4fr);
  gap: clamp(1rem, 3vw, 3rem);
  padding: clamp(1.8rem, 4vw, 3rem) 0;
  border-bottom: 1px solid var(--line);
  align-items: start;
  transition: background 0.4s var(--ease);
}
.svc__row:hover { background: var(--bg-2); }
.svc__no {
  font-size: 0.68rem; letter-spacing: 0.2em; color: var(--fg-35);
  padding-top: 0.5rem;
}
.svc__row h3 { font-size: clamp(1.3rem, 2.4vw, 2rem); }
.svc__row p { color: var(--fg-70); max-width: 52ch; }
.svc__tags {
  grid-column: 3; display: flex; flex-wrap: wrap; gap: 0.45rem;
  margin-top: 1.1rem;
}
.svc__tags li {
  font-size: 0.62rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--fg-50);
  border: 1px solid var(--line); border-radius: 100px;
  padding: 0.32rem 0.75rem;
}

/* -------------------------------------------------------------------------
   12. STUDIO
   ------------------------------------------------------------------------- */
.about {
  display: grid; grid-template-columns: 1.15fr 0.85fr;
  gap: clamp(2rem, 6vw, 6rem); align-items: start;
}
.about__copy p { color: var(--fg-70); max-width: 56ch; }
.about__copy p + p { margin-top: 1rem; }
.ticks { margin-top: 1.8rem; display: grid; gap: 0.7rem; }
.ticks li {
  position: relative; padding-left: 1.8rem;
  font-size: 0.92rem;
}
.ticks li::before {
  content: ''; position: absolute; left: 0; top: 0.55em;
  width: 12px; height: 1px; background: var(--accent);
}

.stats { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line); }
.stats > div { background: var(--panel); padding: clamp(1.2rem, 2.5vw, 2rem); }
.stats dt {
  font-size: clamp(1.8rem, 3.4vw, 2.8rem); font-weight: 400;
  letter-spacing: -0.02em;
}
.stats dd {
  font-size: 0.66rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--fg-50); margin-top: 0.5rem;
}

/* -------------------------------------------------------------------------
   13. QUOTES
   ------------------------------------------------------------------------- */
.quotes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--line); }
.quote {
  background: var(--panel);
  padding: clamp(1.5rem, 3vw, 2.5rem);
  display: flex; flex-direction: column; gap: 1.4rem;
}
.quote p { font-size: clamp(1rem, 1.5vw, 1.25rem); line-height: 1.4; }
.quote footer {
  margin-top: auto;
  font-size: 0.66rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--fg-50);
}

/* -------------------------------------------------------------------------
   14. PRESS
   ------------------------------------------------------------------------- */
.press {
  max-width: var(--maxw); margin-inline: auto;
  padding: clamp(2.5rem, 5vw, 4rem) var(--gut);
  border-top: 1px solid var(--line);
  display: flex; flex-wrap: wrap; align-items: center;
  gap: clamp(1.5rem, 4vw, 4rem);
}
.press__row {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: clamp(1.5rem, 4vw, 3.5rem);
}
.press__row li {
  font-size: clamp(0.95rem, 1.6vw, 1.35rem);
  text-transform: uppercase; letter-spacing: -0.01em;
  color: var(--fg-35);
  transition: color 0.3s var(--ease);
}
.press__row li:hover { color: var(--fg); }

/* -------------------------------------------------------------------------
   15. CLIENTS
   ------------------------------------------------------------------------- */
/* Logo wall. Hairline cells and one consistent optical size hold the set
   together; each mark keeps its own brand colours. Any logo supplied as a
   reversed (white) version needs a positive variant, or it vanishes on the
   paper ground — see assets/clients/README.md. */
.logos {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--line);
}
.logo {
  background: var(--panel);
  display: grid;
  place-items: center;
  padding: clamp(1.6rem, 3.5vw, 2.8rem) clamp(1rem, 2vw, 1.8rem);
  min-height: clamp(110px, 12vw, 160px);
  transition: background 0.35s var(--ease);
}
.logo img {
  max-width: 100%;
  max-height: clamp(38px, 4.5vw, 56px);
  width: auto;
  height: auto;
  object-fit: contain;
  /* Logos keep their own colours. They sit slightly held back so the wall
     reads as one band rather than four competing marks, and come to full
     strength on hover. */
  opacity: 0.82;
  transition: opacity 0.35s var(--ease);
}
.logo:hover img { opacity: 1; }

/* Portrait / stacked lockups (Nateel) would render tiny under a single height
   cap — a 0.67 ratio mark at 56px tall is only 37px wide, dwarfed by the
   horizontal logos beside it. Logo walls normalise by optical area, not by
   height, so tall marks get their own ceiling. */
.logo--tall img { max-height: clamp(64px, 7vw, 92px); }

/* Shown by main.js when a logo file is missing, so the wall degrades to a
   typographic wordmark instead of a broken-image icon. */
.logo__name {
  font-size: clamp(1rem, 1.5vw, 1.25rem);
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--fg-70);
  text-align: center;
  transition: color 0.35s var(--ease);
}
.logo:hover .logo__name { color: var(--fg); }

/* -------------------------------------------------------------------------
   16. JOURNAL
   ------------------------------------------------------------------------- */
.posts { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1.5rem, 3vw, 3rem); }
.post { border-top: 1px solid var(--line); padding-top: 1.4rem; }
.post .media { margin-bottom: 1.4rem; }
.post h3 { font-size: clamp(1.1rem, 1.7vw, 1.4rem); margin: 1rem 0 0.8rem; }
.post h3 a { transition: color 0.3s var(--ease); }
.post h3 a:hover { color: var(--accent); }
.post p:last-child { color: var(--fg-70); font-size: 0.92rem; }

/* -------------------------------------------------------------------------
   17. FOOTER / CONTACT
   ------------------------------------------------------------------------- */
.foot {
  max-width: var(--maxw); margin-inline: auto;
  padding: var(--sec-y) var(--gut) 2rem;
  border-top: 1px solid var(--line);
}
.foot__cta .lbl { margin-bottom: 1.6rem; }
.foot__big { font-size: clamp(2.4rem, 8vw, 7rem); line-height: 0.98; }
.foot__lede {
  color: var(--fg-70); max-width: 52ch;
  margin-top: 1.6rem;
}

.form { margin: clamp(2.5rem, 6vw, 4.5rem) 0; }
.form__grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1rem, 2vw, 1.8rem); }
.field { display: flex; flex-direction: column; gap: 0.6rem; }
.field--full { grid-column: 1 / -1; }
.field input, .field textarea, .field select {
  background: transparent;
  border: 0; border-bottom: 1px solid var(--line);
  padding: 0.7rem 0;
  font-size: 1rem; font-weight: 300;
  resize: vertical;
  transition: border-color 0.3s var(--ease);
  border-radius: 0;
}
.field select { appearance: none; cursor: pointer; }
.field select option { background: var(--bg-2); color: var(--fg); }
.field input::placeholder, .field textarea::placeholder { color: var(--fg-35); }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--fg);
}
.field.is-bad input, .field.is-bad textarea, .field.is-bad select { border-color: var(--accent); }

.btn {
  margin-top: 2.2rem;
  background: none; cursor: pointer;
  border: 1px solid var(--fg);
  border-radius: 100px;
  padding: 1rem 2.2rem;
  font-size: 0.68rem; letter-spacing: 0.2em; text-transform: uppercase;
  transition: background 0.35s var(--ease), color 0.35s var(--ease);
}
.btn:hover { background: var(--fg); color: var(--bg); }
.form__note { margin-top: 1.2rem; font-size: 0.88rem; color: var(--fg-70); min-height: 1.3em; }
.form__note.is-bad { color: var(--accent); }

.foot__cols {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(1.5rem, 3vw, 3rem);
  padding: clamp(2.5rem, 5vw, 4rem) 0;
  border-top: 1px solid var(--line);
}
.foot__cols .lbl { margin-bottom: 1.2rem; }
.foot__cols ul { display: grid; gap: 0.6rem; font-size: 0.92rem; color: var(--fg-70); }
.foot__cols a:hover { color: var(--fg); }

.foot__bar {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.6rem;
  padding-top: 1.8rem; border-top: 1px solid var(--line);
  font-size: 0.66rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--fg-35);
}

/* -------------------------------------------------------------------------
   17b. WHATSAPP
   Same vocabulary as the rest of the chrome: a hairline pill that inverts
   to solid white on hover, like .btn and .chip.
   ------------------------------------------------------------------------- */
.wa {
  position: fixed;
  right: clamp(1rem, 3vw, 2.25rem);
  bottom: clamp(1rem, 3vw, 2.25rem);
  z-index: 70;                    /* under the overlay menu (80) */
  width: 56px; height: 56px;
  display: grid; place-items: center;
  border: 1px solid var(--fg);
  border-radius: 50%;
  background: rgba(4, 4, 4, 0.82);
  color: var(--fg);
  transition: background 0.35s var(--ease), color 0.35s var(--ease),
              transform 0.35s var(--ease);
}
.wa svg { width: 24px; height: 24px; fill: currentColor; }
.wa:hover, .wa:focus-visible {
  background: #FFFFFF;
  color: #040404;
  transform: translateY(-3px);
}

/* Over a paper section a white ring is invisible and the button reads as a
   floating dark blob. JS toggles this when the button sits over one. */
.wa--paper {
  border-color: rgba(8, 7, 10, 0.28);
  background: rgba(244, 243, 239, 0.9);
  color: #08070A;
}
.wa--paper:hover, .wa--paper:focus-visible {
  background: #08070A;
  color: #F4F3EF;
  border-color: #08070A;
}

@media (max-width: 620px) {
  .wa { width: 50px; height: 50px; }
  .wa svg { width: 21px; height: 21px; }
}
@media (prefers-reduced-motion: reduce) {
  .wa { transition: background 0.2s linear, color 0.2s linear; }
  .wa:hover, .wa:focus-visible { transform: none; }
}

/* -------------------------------------------------------------------------
   18. REVEAL
   ------------------------------------------------------------------------- */
/* Visible by DEFAULT. JS arms (hides) only what starts below the fold and
   disarms it on the way in. If the script never runs, never finishes, or the
   scroll handler dies, the page is still fully readable — the opposite
   default silently eats the whole site. */
.reveal { transition: opacity 0.8s var(--ease), transform 0.8s var(--ease); }
.reveal.is-armed { opacity: 0; transform: translateY(18px); }

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal.is-armed { opacity: 1; transform: none; transition: none; }
}

/* placeholder highlighter — add ?ph to the URL */
body.show-ph .ph {
  outline: 1px solid var(--accent);
  background: rgba(196, 100, 63, 0.14);
}

/* -------------------------------------------------------------------------
   19. RESPONSIVE
   ------------------------------------------------------------------------- */
@media (max-width: 1080px) {
  .grid, .posts, .quotes { grid-template-columns: repeat(2, 1fr); }
  .logos { grid-template-columns: repeat(3, 1fr); }
  .svc__row { grid-template-columns: 5rem 1fr; }
  /* the description and tags both belong in the wide column — without this
     the paragraph wraps into the 5rem number column, one word per line */
  .svc__row p,
  .svc__tags { grid-column: 2; }
  .foot__cols { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 760px) {
  .about { grid-template-columns: 1fr; }
  .logos { grid-template-columns: repeat(2, 1fr); }
  .form__grid { grid-template-columns: 1fr; }
  .hdr { padding-block: 1.1rem; }
}

@media (max-width: 620px) {
  .grid, .posts, .quotes { grid-template-columns: 1fr; }
  .svc__row { grid-template-columns: 1fr; gap: 0.8rem; }
  .svc__no { padding-top: 0; }
  /* the row is one column here, so the paragraph has to come back out of
     column 2 — left pinned, it forces an implicit second track */
  .svc__row p,
  .svc__tags { grid-column: 1; }
  .stats { grid-template-columns: 1fr 1fr; }
  .hero__foot { align-items: flex-start; flex-direction: column; }
  .press { flex-direction: column; align-items: flex-start; gap: 1.2rem; }
}
