/* ──────────────────────────────────────────────────────────────
   VUELCO — editorial creative-technology firm
   Strict monochrome · one type system · architectural rhythm.
   The hero wordmark is the nav brand: the black hero scrolls away
   in normal flow while the wordmark docks into the header, always
   ahead of the rising white edge — it never touches the white.
   ────────────────────────────────────────────────────────────── */

:root {
  /* ── Palette — strict neutral monochrome ─────────────── */
  --ink:        #0a0a0b;
  --ink-2:      #141415;
  --char:       #232325;
  --paper:      #f4f4f5;
  --paper-2:    #eaeaeb;
  --paper-3:    #e2e2e4;
  --mineral:    #6e6e74;
  --mineral-lo: #9a9aa0;

  --line:           rgba(10,10,11,0.14);
  --line-dim:       rgba(10,10,11,0.07);
  --line-light:     rgba(244,244,245,0.22);
  --line-light-dim: rgba(244,244,245,0.09);

  --on-dark:   rgba(244,244,245,0.94);
  --on-dark-2: rgba(244,244,245,0.62);
  --on-dark-3: rgba(244,244,245,0.38);

  --font-sans: "Geist", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, Menlo, monospace;

  /* ── Spacing — one margin, one vertical rhythm ───────── */
  --pad:    clamp(20px, 3vw, 48px);      /* page margin          */
  --pad-y:  clamp(96px, 13vh, 180px);    /* section padding      */
  --gut:    clamp(16px, 1.6vw, 28px);    /* grid gutter          */
  --head-gap: clamp(56px, 9vh, 110px);   /* label → content      */

  /* ── Type tiers — each size has one job ──────────────── */
  --t-display: clamp(42px, 5.2vw, 92px); /* section headlines    */
  --t-heading: clamp(22px, 2.3vw, 34px); /* capability titles    */
  --t-lede:    clamp(17px, 1.45vw, 22px);/* intros               */
  --t-body:    clamp(15px, 1.05vw, 17px);/* paragraphs           */
  --t-micro:   11px;                     /* mono labels          */

  /* hero wordmark height: full page width, aspect 5.504 — scaled by the
     same 0.97 micro-factor as the flight math below, so the scroll cue /
     tagline offsets stay in sync with the actual rendered logo height. */
  --logo-h: calc(min(calc((100vw - var(--pad) * 2) / 5.504), 42vh) * 0.97);

  --ease:     cubic-bezier(.2,.7,.2,1);
  --ease-out: cubic-bezier(.16,1,.3,1);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { overflow-x: clip; }
body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  line-height: 1.32;
  letter-spacing: -0.006em;
}
body.is-loading { overflow: hidden; height: 100vh; }
body.lenis { height: auto; }
body.lenis.lenis-smooth { scroll-behavior: auto !important; }
html.is-locked, html.is-locked body { overflow: hidden; }

/* ── Load veil — a controlled, fully-black first frame. Pure CSS on the
   initial markup (body ships class="is-loading"), so it exists from the
   very first render, above ALL fixed UI (nav 50 / lang 55 / case 60 /
   cursor 90). app.js removes .is-loading when the hero is ready and the
   veil fades away. Gated to :not(.no-js): without JS nothing could ever
   lift it, so no-JS renders the page directly. ── */
html:not(.no-js) body::after {
  content: ""; position: fixed; inset: 0;
  background: #0a0a0b; z-index: 200;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .55s var(--ease), visibility 0s linear .55s;
}
html:not(.no-js) body.is-loading::after {
  opacity: 1; visibility: visible; pointer-events: auto;
  transition: none;
}
/* hard-off (app.js adds .veil-off ~900ms after ready): the veil is
   guaranteed gone even if a throttled tab froze its fade transition */
html:not(.no-js) body.veil-off::after { display: none; }

img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

::selection { background: var(--ink); color: var(--paper); }
.intro ::selection, .contact ::selection,
.footer ::selection, .menu-overlay ::selection { background: var(--paper); color: var(--ink); }

/* ── Metadata / mono ──────────────────────────────────── */
.mono {
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: var(--t-micro);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--mineral);
}
.mono.small { font-size: 10px; }
.intro .mono, .contact .mono, .footer .mono, .menu-overlay .mono { color: var(--on-dark-2); }

.dot { display: inline-block; padding-left: 0.03em; }

/* ── Editorial serif accent — a second, refined register applied only
   to the second half of selected headlines. The geometric sans stays
   the system base; this enters purely as a contrast, never a graft. ── */
.ed {
  /* same base sans as the rest of the system — differentiated only by
     the muted grey already used in "Muchas compañías, todavía no" (no italic) */
  font-style: normal;
  color: var(--mineral-lo);
}

.intro, .contact, .footer { background: var(--ink); color: var(--paper); }

.s-label { grid-column: 1 / 5; grid-row: 1; color: var(--mineral); }

/* ════════════════════════════════════════════════════════
   NAV — the brand image IS the hero wordmark
   ════════════════════════════════════════════════════════ */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gut);
  padding: 22px calc(var(--pad) + 64px) 22px var(--pad);
  mix-blend-mode: difference;
  color: var(--paper);
  pointer-events: none;
  transition: transform .5s var(--ease);
}
.nav > * { pointer-events: auto; }
.nav.is-hidden { transform: translateY(-101%); }
.nav.is-hidden > * { pointer-events: none; }
.nav__brand {
  display: inline-flex; align-items: center; height: 18px; position: relative;
  width: calc(18px * 2075 / 377); /* reserve the docked-logo footprint so the flex row spacing is unchanged now the img is absolute */
}
.nav__brand-img {
  height: 18px; width: auto; filter: invert(1); display: block;
  /* absolute + top-left origin: JS drives every visual size (hero + docked)
     via transform: scale() from the image's natural raster resolution, so
     the browser only ever down-samples — never upscales a tiny 18px layer —
     which is what produced the soft/pixelated logo on mobile. */
  position: absolute; left: 0; top: 0;
  max-width: none; /* the global img{max-width:100%} would otherwise clamp
    the JS-set natural-resolution width to .nav__brand's tiny reserved box */
  transform-origin: 0 0; will-change: transform;
}
.nav__menu {
  display: flex; gap: 30px;
  /* centered on the header's own axis (independent of the logo/lang-switch
     asymmetric padding), without moving the logo (left) or language switch (right) */
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
}
.nav__link {
  font-size: 13px; font-weight: 400; letter-spacing: -0.004em;
  position: relative; padding: 4px 0;
  opacity: .9; transition: opacity .4s var(--ease);
}
.nav__link:hover { opacity: 1; }
.nav__link::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px;
  height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: left;
  transition: transform .5s var(--ease);
}
.nav__link:hover::after { transform: scaleX(1); }

.nav__toggle {
  display: none;
  font-family: var(--font-mono); font-size: var(--t-micro);
  letter-spacing: 0.08em; text-transform: uppercase;
  line-height: 1; /* match .lang-switch's line-box so MENÚ / EN share one visual baseline */
  padding: 6px 0;
}

/* ── Language switch — always visible, independent of header
   show/hide. Same mix-blend-mode trick as .nav gives automatic
   contrast on both the black hero and the white sections. ── */
.lang-switch {
  position: fixed; top: 22px; right: var(--pad); z-index: 55;
  font-family: var(--font-mono); font-size: 11px; font-weight: 400;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--paper);
  mix-blend-mode: difference;
  padding: 6px 2px;
  line-height: 1;
}
.lang-switch::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px;
  height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: right;
  transition: transform .5s var(--ease);
}
.lang-switch:hover::after { transform: scaleX(1); transform-origin: left; }

.nav__menu, .nav__toggle { transition: opacity .6s var(--ease) .15s; }
.nav.is-quiet .nav__menu, .nav.is-quiet .nav__toggle {
  opacity: 0; pointer-events: none; transition: opacity .35s var(--ease);
}
/* the header now ships is-quiet from the HTML (so the menu can never flash
   on first paint); without JS nothing would release it — force it back on */
html.no-js .nav.is-quiet .nav__menu,
html.no-js .nav.is-quiet .nav__toggle { opacity: 1; pointer-events: auto; }

/* ════════════════════════════════════════════════════════
   MOBILE MENU OVERLAY (below the blended nav)
   ════════════════════════════════════════════════════════ */
.menu-overlay {
  position: fixed; inset: 0; z-index: 40;
  background: var(--ink); color: var(--paper);
  padding: 0 var(--pad);
  display: grid; align-content: center;
  opacity: 0; pointer-events: none; visibility: hidden;
  transition: opacity .45s var(--ease), visibility 0s linear .45s;
}
.menu-overlay.is-open {
  opacity: 1; pointer-events: auto; visibility: visible;
  transition: opacity .45s var(--ease);
}
.menu-overlay__nav { display: grid; }
.menu-overlay__link {
  display: block;
  font-size: clamp(30px, 8.5vw, 44px); font-weight: 300; letter-spacing: -0.025em;
  padding: 16px 0;
  border-bottom: 1px solid var(--line-light-dim);
}
.menu-overlay__link:first-child { border-top: 1px solid var(--line-light-dim); }
.menu-overlay__meta {
  position: absolute; left: var(--pad); right: var(--pad); bottom: 28px;
  display: flex; justify-content: space-between; gap: 16px;
}

/* ════════════════════════════════════════════════════════
   01 · INTRO — a single fullscreen black stage in normal
   flow: it rises with the scroll while the wordmark flies
   to the header, always ahead of the white edge below.
   ════════════════════════════════════════════════════════ */
/* mobile: svh (small viewport) — this box must NOT resize when the URL bar
   collapses at scroll start. With dvh the box grew mid-gesture, the flight
   math re-measured against it and the wordmark visibly jumped before its
   rise; svh keeps every measurement identical for the whole flight.
   (Desktop: svh == vh, unchanged.) */
.intro { position: relative; height: 100vh; height: 100svh; }
.intro__stage {
  position: relative;
  height: 100%;
  overflow: clip;
  background: var(--ink);
}

/* right-rail descriptor — sits well above the wordmark */
.intro__tag {
  position: absolute; right: var(--pad);
  bottom: calc(var(--logo-h) + 110px);
  display: grid; gap: 18px; justify-items: end; text-align: right;
  max-width: min(600px, 56vw); z-index: 3;
  opacity: 1;
  pointer-events: none;
  will-change: transform, opacity;
}
.intro__tag-label {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--on-dark-3);
}
.intro__tag-claim {
  font-weight: 400; font-size: clamp(19px, 1.9vw, 28px);
  line-height: 1.2; letter-spacing: -0.014em; color: var(--on-dark);
}
.intro__tag-sub {
  font-weight: 300; font-size: clamp(15px, 1.25vw, 18px);
  line-height: 1.55; letter-spacing: -0.006em; color: var(--on-dark-2);
  max-width: 40ch;
}

/* scroll cue — bottom-left, above the wordmark. Left edge is computed to
   match the hero wordmark's own left edge (which sits slightly inset from
   var(--pad) due to its 0.97 micro-shrink — see app.js), so the label reads
   as a fine editorial note flush with the logo, not merely page-padded. */
.intro__cue {
  position: absolute;
  left: calc(var(--pad) + (100vw - var(--pad) * 2) * 0.015);
  bottom: calc(var(--logo-h) + 80px);
  z-index: 3;
  opacity: 0; animation: fadeIn .9s var(--ease) 2.4s forwards;
  pointer-events: none;
  will-change: transform, opacity;
}
.intro__cue .mono { font-size: 9px; letter-spacing: 0.11em; color: var(--on-dark-3); }
.intro__cue-arrow { display: inline-block; animation: cueFloat 3s var(--ease) infinite; }
@keyframes cueFloat {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(3px); }
}
@keyframes fadeIn { to { opacity: 1; } }

/* ── Hero entrance — the claim cascades in (label → claim → sub) once the
   page is READY (body.is-ready = veil lifting), so the cascade can never
   play out unseen behind the load veil. Enhancement only: gated to
   motion-allowed + JS, so no-JS / reduced-motion render the hero untouched. ── */
@media (prefers-reduced-motion: no-preference) {
  html:not(.no-js) .intro__tag-label,
  html:not(.no-js) .intro__tag-claim,
  html:not(.no-js) .intro__tag-sub {
    opacity: 0; transform: translateY(15px);
  }
  html:not(.no-js) body.is-ready .intro__tag-label,
  html:not(.no-js) body.is-ready .intro__tag-claim,
  html:not(.no-js) body.is-ready .intro__tag-sub { animation: heroRise 0.9s var(--ease-out) forwards; }
  html:not(.no-js) body.is-ready .intro__tag-label { animation-delay: 1.0s; }
  html:not(.no-js) body.is-ready .intro__tag-claim { animation-delay: 1.15s; }
  html:not(.no-js) body.is-ready .intro__tag-sub   { animation-delay: 1.3s; }
}
@keyframes heroRise { to { opacity: 1; transform: translateY(0); } }

/* static wordmark — only for no-JS / reduced-motion */
.intro__wordmark-static {
  display: none;
  position: absolute; left: var(--pad); right: var(--pad);
  bottom: clamp(40px, 6vh, 64px);
  width: calc(100% - var(--pad) * 2); height: auto;
}
html.no-js .intro__wordmark-static { display: block; }
@media (prefers-reduced-motion: reduce) {
  .intro__wordmark-static { display: block; }
}

/* ════════════════════════════════════════════════════════
   Shared section scaffold
   ════════════════════════════════════════════════════════ */
.section {
  padding: var(--pad-y) var(--pad);
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--gut);
  align-content: start;
}

/* reveal primitives — visible by default; the timed entrance layer
   below (reveal.js adds html.rv + per-scope .is-rev) is pure enhancement */
.line-mask { display: block; overflow: hidden; }
.line-mask > * { display: inline-block; }
.fade-up { opacity: 1; }
.manifesto__rule { transform-origin: left; }

/* ════════════════════════════════════════════════════════
   EDITORIAL ENTRANCES — one timed grammar for the whole page.
   IntersectionObserver flips .is-rev per scope (reveal.js);
   entrances are one-shot animations so approved hover/pin
   behaviour is never touched. Order inside every section:
   label (0ms) → headline lines (120ms, staggered) → paragraphs
   and secondary blocks (260ms+, cascading). Pre-hidden states
   exist ONLY under html.rv + motion allowed — no JS or reduced
   motion renders everything visible and static.
   The pinned choreographies (Posición, Qué hacemos) are excluded:
   they own their sections' motion.
   ════════════════════════════════════════════════════════ */
:root { --rv-e: cubic-bezier(0.23, 0.62, 0.09, 0.99); }

@media (prefers-reduced-motion: no-preference) {
  /* ── pre-states (hidden until the scope reveals) ── */
  html.rv .rv-s:not(.is-rev) .s-label,
  html.rv .rv-s:not(.is-rev):not(.manifesto) .fade-up:not(.work__item):not(.case):not(.contact__form):not(.contact__meta):not(.sup-i):not(.sup-g),
  html.rv .rv-s:not(.is-rev) .contact__meta-block,
  html.rv .footer:not(.is-rev) .footer__brand,
  html.rv .footer:not(.is-rev) .footer__items span,
  html.rv .projects__grid .case:not(.is-rev),
  html.rv .contact__form:not(.is-rev) .field,
  html.rv .contact__form:not(.is-rev) .contact__submit { opacity: 0; }
  html.rv .rv-s:not(.is-rev):not(.manifesto) .line-mask > * { transform: translateY(112%); opacity: 0; }

  /* ── 1 · section labels — a technical note printing itself ── */
  html.rv .rv-s.is-rev .s-label { animation: rvUp 0.6s var(--rv-e) both; }

  /* ── 2 · big headlines — masked line reveal: each line uncovers from
     behind its own clip, rising with a soft opacity ramp. The grey second
     line follows ~160ms behind the first — a legible, unhurried cascade,
     premium easing, no bounce. Triggered later now (see reveal.js
     REVEAL_AT) so the gesture plays in full view of the reader. ── */
  html.rv .rv-s.is-rev:not(.manifesto) .line-mask > * { animation: hlLine 0.9s var(--rv-e) 0.1s both; }
  html.rv .rv-s.is-rev:not(.manifesto) .line-mask:nth-child(2) > * { animation-delay: 0.26s; }
  html.rv .rv-s.is-rev:not(.manifesto) .line-mask:nth-child(3) > * { animation-delay: 0.42s; }
  /* (the projects title now carries real line-masks in the markup and is
     covered by the headline rule above — same grammar as every titular) */

  /* ── 3 · paragraphs & secondary blocks — after the headline, cascading ── */
  html.rv .rv-s.is-rev:not(.manifesto) .fade-up:not(.work__item):not(.case):not(.contact__form):not(.contact__meta):not(.sup-i):not(.sup-g) {
    animation: rvUp 0.7s var(--rv-e) calc(0.26s + var(--rvi, 0) * 0.13s) both;
  }
  html.rv .rv-s.is-rev .contact__meta-block { animation: rvUp 0.6s var(--rv-e) calc(0.44s + var(--rvi, 0) * 0.12s) both; }

  /* ── 3b · support texts beside/below the titulars — their own in-view
     cascade (reveal.js observes each .sup-g block directly): small blocks
     rise 24px behind a soft fade, 120ms apart. Perceptible, sober. ── */
  html.rv .sup-g:not(.is-rev) .sup-i,
  html.rv .sup-i.sup-g:not(.is-rev) { opacity: 0; }
  html.rv .sup-g.is-rev .sup-i,
  html.rv .sup-i.sup-g.is-rev { animation: supIn 0.8s var(--rv-e) calc(0.06s + var(--si, 0) * 0.12s) both; }

  /* ── 4 · project cards — curated cascade, observed per card;
         pairs share a row on desktop, the right one follows ── */
  html.rv .projects__grid .case.is-rev { animation: caseReveal 0.85s var(--rv-e) calc(var(--rvc, 0) * 0.14s) both; }

  /* ── 5 · contact form — fields settle, baselines draw, button closes ── */
  html.rv .contact .field { position: relative; }
  html.rv .contact .field :is(input, select, textarea) { border-bottom-color: transparent; }
  html.rv .contact .field::before {
    content: ""; position: absolute;
    left: 0; right: 0; bottom: 0; height: 1px;
    background: var(--line-light);
    transform-origin: left;
    transition: background 0.4s var(--ease);
  }
  html.rv .contact__form:not(.is-rev) .field::before { transform: scaleX(0); }
  html.rv .contact__form.is-rev .field { animation: rvUp 0.6s var(--rv-e) calc(var(--rvi, 0) * 0.1s) both; }
  html.rv .contact__form.is-rev .field::before { animation: ruleX 0.8s var(--rv-e) calc(0.14s + var(--rvi, 0) * 0.1s) both; }
  html.rv .contact .field:hover::before        { background: rgba(244, 244, 245, 0.4); }
  html.rv .contact .field:focus-within::before { background: rgba(244, 244, 245, 0.85); }
  html.rv .contact__form.is-rev .contact__submit { animation: rvUp 0.6s var(--rv-e) 0.72s both; }

  /* ── 6 · footer — quiet close ── */
  html.rv .footer.is-rev .footer__brand { animation: rvFade 0.9s var(--rv-e) both; }
  html.rv .footer.is-rev .footer__items span { animation: rvUp 0.6s var(--rv-e) 0.18s both; }
  html.rv .footer.is-rev .footer__items span:nth-child(2) { animation-delay: 0.3s; }

  /* ── scopes already in view at load reveal with zero timing (no flash) ── */
  html.rv .rv-instant, html.rv .rv-instant *,
  html.rv .rv-instant *::before { animation-duration: 0s !important; animation-delay: 0s !important; }

  /* ── mobile: same grammar, quicker and quieter ── */
  @media (max-width: 820px) {
    html.rv .rv-s.is-rev:not(.manifesto) .line-mask > * { animation-duration: 0.66s; animation-delay: 0.07s; }
    html.rv .rv-s.is-rev:not(.manifesto) .line-mask:nth-child(2) > * { animation-delay: 0.21s; }
    html.rv .rv-s.is-rev:not(.manifesto) .line-mask:nth-child(3) > * { animation-delay: 0.34s; }
    html.rv .rv-s.is-rev:not(.manifesto) .fade-up:not(.work__item):not(.case):not(.contact__form):not(.contact__meta):not(.sup-i):not(.sup-g) {
      animation-duration: 0.55s;
      animation-delay: calc(0.16s + var(--rvi, 0) * 0.09s);
    }
    html.rv .rv-s.is-rev .contact__meta-block { animation-delay: calc(0.28s + var(--rvi, 0) * 0.1s); }
    html.rv .sup-g.is-rev .sup-i,
    html.rv .sup-i.sup-g.is-rev { animation-duration: 0.6s; animation-delay: calc(0.05s + var(--si, 0) * 0.1s); }
    html.rv .projects__grid .case.is-rev { animation-duration: 0.6s; }
  }
}
@keyframes lineUp { from { transform: translateY(108%); } to { transform: translateY(0); } }
@keyframes rvUp   { from { opacity: 0; transform: translateY(12px); } }
@keyframes rvUpLg { from { opacity: 0; transform: translateY(22px); } }
@keyframes rvFade { from { opacity: 0; } }
@keyframes ruleX  { from { transform: scaleX(0); } to { transform: scaleX(1); } }
/* headline line reveal — mask slide + short opacity ramp (used by the
   EDITORIAL ENTRANCES headline rule above) */
@keyframes hlLine { 0% { transform: translateY(112%); opacity: 0; } 42% { opacity: 1; } 100% { transform: translateY(0); opacity: 1; } }
/* support-block rise — used by the 3b cascade above */
@keyframes supIn { from { opacity: 0; transform: translateY(24px); } }

/* ════════════════════════════════════════════════════════
   02 · POSICIÓN
   ════════════════════════════════════════════════════════ */
.manifesto__statement {
  grid-column: 1 / 12; grid-row: 2;
  margin-top: var(--head-gap);
  font-weight: 300; font-size: var(--t-display);
  line-height: 1.04; letter-spacing: -0.035em;
}
.manifesto__statement .mute { color: var(--mineral-lo); }
.manifesto__rule {
  grid-column: 1 / 4; grid-row: 3; align-self: start;
  margin-top: clamp(44px, 7vh, 76px);
  width: clamp(64px, 8vw, 120px); height: 1px; background: var(--line);
}
.manifesto__support {
  grid-column: 8 / -1; grid-row: 3;
  margin-top: clamp(40px, 7vh, 72px);
  justify-self: end;
  font-size: var(--t-body); line-height: 1.6; color: var(--char);
  max-width: 40ch;
}

/* ════════════════════════════════════════════════════════
   03 · QUÉ HACEMOS — compact editorial table
   ════════════════════════════════════════════════════════ */
.work { padding-block: clamp(72px, 9vh, 120px); }
.work__concept {
  grid-column: 6 / -1; grid-row: 2;
  margin-top: calc(var(--head-gap) - 34px);
  justify-self: end; text-align: right;
  font-weight: 300; font-size: var(--t-display);
  letter-spacing: -0.035em; line-height: 1.04;
}
/* the concept's secondary word is greyed like the rest, but upright
   (no italic) — it is a title, not an editorial accent */
.work__concept .ed { font-style: normal; }
.work__support {
  grid-column: 1 / 5; grid-row: 2;
  margin-top: calc(var(--head-gap) + 96px);
  align-self: start;
  font-size: var(--t-body); line-height: 1.6; color: var(--char);
  max-width: 34ch;
}
.work__list {
  grid-column: 1 / -1; grid-row: 3;
  margin-top: clamp(40px, 6vh, 72px);
  list-style: none;
  border-top: 1px solid var(--line);
}
.work__item {
  display: grid;
  grid-template-columns: 64px minmax(0, 6fr) minmax(0, 5fr);
  align-items: baseline; column-gap: var(--gut);
  padding: clamp(16px, 2.4vh, 26px) 0;
  border-bottom: 1px solid var(--line);
  transition: padding-left .55s var(--ease);
}
.work__num { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.04em; color: var(--mineral); }
.work__name {
  font-weight: 300; font-size: var(--t-heading);
  letter-spacing: -0.022em; line-height: 1.08; color: var(--ink);
}
.work__desc {
  font-size: 14px; line-height: 1.55; color: var(--mineral);
  max-width: 44ch;
  transition: color .5s var(--ease);
}
.work__short { display: none; } /* mobile-only active-row summary, see Responsive + MOBILE PIN blocks */

/* ════════════════════════════════════════════════════════
   04 · ÚLTIMOS PROYECTOS — case cards with editorial mockups
   ════════════════════════════════════════════════════════ */
.projects__title {
  grid-column: 5 / -1; grid-row: 1;
  justify-self: end; text-align: right;
  font-weight: 300; font-size: var(--t-display);
  letter-spacing: -0.035em; line-height: 1;
}
.projects__grid {
  grid-column: 1 / -1; grid-row: 2;
  margin-top: clamp(64px, 10vh, 130px);
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(56px, 8vh, 96px) var(--gut);
}
.case { display: grid; gap: 14px; align-content: start; }

.case__media {
  display: block; width: 100%;
  aspect-ratio: 4 / 3;
  position: relative; overflow: clip;
  container-type: inline-size;
  text-align: left; padding: 0;
}
.case__media:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }

.case__row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
  padding-bottom: 12px; border-bottom: 1px solid var(--line);
}
.case__name { font-weight: 400; font-size: clamp(19px, 1.75vw, 27px); letter-spacing: -0.025em; line-height: 1; }
.case__year { font-size: 10px; letter-spacing: 0.06em; white-space: nowrap; }
.case__foot { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.case__cats { font-size: 10px; letter-spacing: 0; text-transform: none; line-height: 1.4; }
.case__view {
  display: inline-flex; align-items: baseline; gap: 7px;
  font-size: 10px; letter-spacing: 0.05em; color: var(--mineral-lo);
  white-space: nowrap; padding: 2px 0; position: relative;
  transition: color .4s var(--ease);
}
.case:hover .case__view,
.case__view:hover, .case__view:focus-visible { color: var(--ink); }
.case__view > span:first-child { position: relative; }
.case__view > span:first-child::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: right;
  transition: transform .45s var(--ease);
}
.case__view:hover > span:first-child::after,
.case__view:focus-visible > span:first-child::after { transform: scaleX(1); transform-origin: left; }
.case__view .case__arrow { transition: transform .45s var(--ease-out); }
.case__view:hover .case__arrow,
.case__view:focus-visible .case__arrow { transform: translate(3px, -3px); }
.case__view:focus-visible { outline: 1px solid var(--line); outline-offset: 3px; }

/* ── art canvases ─────────────────────────────────────── */
.art { position: absolute; inset: 0; display: block; background: var(--paper-2); }
.art__wire, .art__real {
  position: absolute; inset: 0; display: block;
  transition: opacity .6s var(--ease);
}
.art__real { opacity: 0; }
.case__media:hover .art__real, .case__media:focus-visible .art__real { opacity: 1; }
.case__media:hover .art__wire, .case__media:focus-visible .art__wire { opacity: 0; }
@media (hover: none) {
  /* touch: show the real piece, skip the wire state */
  .art__wire { display: none; }
  .art__real { opacity: 1; }
}
.art__real--tash { background: var(--ink-2); }
.art__real--simp { background: #101114; }
.art__real--sia  { background: var(--paper-3); }
.art__real--q    { background: #e9e6df; }
.art__inner {
  position: absolute; inset: 0; display: block;
  transition: transform .9s var(--ease-out);
}
.case__media:hover .art__inner { transform: scale(1.03); }

/* zero-specificity default so layout classes (.trow, .mk-nav…) always win */
:where(.art) :where(span, i) { display: block; }

/* window object */
.ui {
  background: var(--paper); color: var(--ink);
  border: 1px solid rgba(10,10,11,0.16);
}
.art__real--tash .ui, .art__real--simp .ui {
  border-color: rgba(244,244,245,0.14);
  box-shadow: 0 30px 70px -42px rgba(0,0,0,0.7);
}
.ui__bar {
  display: flex; align-items: center; gap: 2.2cqw;
  padding: 1.8cqw 2.6cqw;
  border-bottom: 1px solid var(--line-dim);
}
.ui__dots { display: flex; gap: 1cqw; }
.ui__dots i { width: 1.1cqw; height: 1.1cqw; border-radius: 50%; background: rgba(10,10,11,0.22); }
.ui__url {
  font-family: var(--font-mono); font-size: 1.6cqw;
  letter-spacing: 0.04em; color: var(--mineral);
}

/* mockup vocabulary */
.mk-nav {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 2.4cqw 3cqw;
}
.mk-brand { font-weight: 500; font-size: 2.4cqw; letter-spacing: -0.01em; }
.mk-brand--sp { letter-spacing: 0.14em; font-size: 2cqw; }
.mk-links { display: flex; gap: 2.4cqw; }
.mk-links i { font-style: normal; font-size: 1.7cqw; color: var(--mineral); }

.tone { background: #d8d8db; position: relative; overflow: hidden; }
.tone--hero { margin: 0 3cqw; height: 20cqw; }
.tone::before, .tone::after { content: ""; position: absolute; bottom: 0; }
.tone--arch::before  { left: 8%;  width: 34%; height: 72%; background: #c2c2c7; }
.tone--arch::after   { right: 12%; width: 26%; height: 50%; background: #adadb3; }
.tone--arch2::before { left: 14%; width: 44%; height: 56%; background: #bcbcc1; }
.tone--arch2::after  { right: 8%;  width: 20%; height: 78%; background: #c8c8cc; }

.mk-h {
  padding: 2.6cqw 3cqw 0;
  font-weight: 400; font-size: 2.5cqw; line-height: 1.3;
  letter-spacing: -0.012em; max-width: 82%;
}
.mk-stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 2cqw;
  padding: 2.8cqw 3cqw 3.2cqw;
}
.mk-stats > span { display: grid; gap: 0.7cqw; border-top: 1px solid var(--line-dim); padding-top: 1.6cqw; }
.mk-stats b { font-weight: 400; font-size: 2.9cqw; letter-spacing: -0.02em; }
.mk-stats i {
  font-style: normal; font-family: var(--font-mono); font-size: 1.35cqw;
  letter-spacing: 0.07em; text-transform: uppercase; color: var(--mineral);
}

.gl { height: 1.1cqw; background: rgba(10,10,11,0.13); }
.gl--num { width: 5cqw; }

/* app frame: rail + main */
.mk-app { display: grid; grid-template-columns: 23cqw 1fr; }
.mk-rail {
  display: grid; align-content: start; gap: 2cqw;
  padding: 2.8cqw 2.6cqw;
  border-right: 1px solid var(--line-dim);
}
.mk-rail i { font-style: normal; font-family: var(--font-mono); font-size: 1.6cqw; letter-spacing: 0.05em; color: var(--mineral-lo); }
.mk-rail i.on { color: var(--ink); }
.mk-logo { font-weight: 500; font-size: 2cqw; letter-spacing: -0.01em; margin-bottom: 1.6cqw; }
.mk-main { padding: 2.8cqw; }
.mk-apphead {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 2.6cqw; gap: 2cqw;
}
.mk-apptitle { font-weight: 400; font-size: 2.2cqw; letter-spacing: -0.015em; }
.mk-btn {
  font-family: var(--font-mono); font-size: 1.4cqw; letter-spacing: 0.06em;
  text-transform: uppercase; border: 1px solid var(--ink);
  padding: 1cqw 1.9cqw; white-space: nowrap;
}

/* data table */
.trow {
  display: grid; grid-template-columns: 2.2fr 1.3fr 0.7fr auto;
  gap: 2.2cqw; align-items: center;
  padding: 2cqw 0; border-top: 1px solid var(--line-dim);
}
.trow--head { padding: 0 0 1.6cqw; border-top: 0; }
.trow--head i {
  font-style: normal; font-family: var(--font-mono); font-size: 1.35cqw;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--mineral-lo);
}
.chip {
  justify-self: end;
  font-family: var(--font-mono); font-size: 1.35cqw; letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.7cqw 1.5cqw; border: 1px solid rgba(10,10,11,0.32);
  white-space: nowrap;
}
.chip--fill { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.chip--dim { color: var(--mineral-lo); border-color: var(--line); }

/* investment row */
.inv {
  display: grid; grid-template-columns: 15cqw 1fr; gap: 2.6cqw;
  align-items: center;
  padding: 2.4cqw 3cqw; border-top: 1px solid var(--line-dim);
}
.inv .tone { height: 10cqw; }
.inv__body { display: grid; gap: 1.8cqw; }
.inv__fields { display: flex; gap: 3.4cqw; }
.inv__fields > span { display: grid; gap: 0.7cqw; }
.inv__fields i {
  font-style: normal; font-family: var(--font-mono); font-size: 1.25cqw;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--mineral-lo);
}
.inv__fields b { font-weight: 400; font-size: 1.8cqw; letter-spacing: -0.01em; }
.inv__fields .gl--num { margin-top: 0.4cqw; }

/* comparison cards */
.opt-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2cqw; }
.opt {
  border: 1px solid var(--line-dim);
  padding: 2.2cqw; display: grid; gap: 1.7cqw; align-content: start;
}
.opt--hot { border-color: var(--ink); }
.opt__k {
  font-family: var(--font-mono); font-size: 1.5cqw; letter-spacing: 0.06em;
  color: var(--mineral); margin-bottom: 0.6cqw;
}
.opt .chip { justify-self: start; margin-top: 1cqw; }

/* ── base (wire) canvases: one editorial composition per project ─ */
.art__wire--ink    { background: var(--ink-2); }
.art__wire--char   { background: var(--char); }
.art__wire--paper  { background: var(--paper-2); }
.art__wire--paper2 { background: var(--paper-3); }
.art__wire--ink .ui, .art__wire--char .ui {
  border-color: rgba(244,244,245,0.14);
  box-shadow: 0 30px 70px -42px rgba(0,0,0,0.7);
}
.ui--tash { position: absolute; left: 9cqw; top: 50%; transform: translateY(-50%); width: 62cqw; }
.sheet--tash { position: absolute; right: 8cqw; bottom: 9cqw; width: 30cqw; }
.ui--sia { position: absolute; left: 9cqw; top: 50%; transform: translateY(-50%); width: 82cqw; }
.ui--simp { position: absolute; right: 8cqw; top: 50%; transform: translateY(-50%); width: 58cqw; }
.ui--quicio { position: absolute; left: 8cqw; top: 50%; transform: translateY(-50%); width: 84cqw; }

/* small paper sheet (publication fragment) */
.sheet {
  background: var(--paper); border: 1px solid rgba(244,244,245,0.14);
  box-shadow: 0 26px 60px -38px rgba(0,0,0,0.7);
  padding: 3cqw 3cqw 2.4cqw;
}
.sheet .gl { margin: 1.5cqw 0; }
.sheet__tag {
  font-family: var(--font-mono); font-size: 1.5cqw; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--mineral); margin-bottom: 2.4cqw;
}
.sheet__foot {
  font-family: var(--font-mono); font-size: 1.35cqw; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--mineral-lo);
  border-top: 1px solid var(--line-dim); padding-top: 1.8cqw; margin-top: 2.6cqw;
}

/* brand plate (identity lockup) */
.plate {
  position: absolute; left: 9cqw; top: 50%; transform: translateY(-50%);
  width: 33cqw; z-index: 2;
  background: var(--ink); color: var(--paper);
  padding: 4cqw 3.6cqw;
  display: grid; gap: 2.4cqw; align-content: start;
  box-shadow: 0 26px 60px -36px rgba(10,10,11,0.5);
}
.plate__word { font-weight: 400; font-size: 3cqw; letter-spacing: 0.16em; }
.plate__rule { width: 5cqw; height: 1px; background: rgba(244,244,245,0.4); }
.plate__tag { font-weight: 300; font-size: 1.9cqw; line-height: 1.45; color: var(--on-dark-2); }
.plate__meta {
  font-family: var(--font-mono); font-size: 1.35cqw; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--on-dark-3); margin-top: 2.4cqw;
}

/* ── real layer: shared window ───────────────────── */
.ui--full { position: absolute; left: 8cqw; top: 50%; transform: translateY(-50%); width: 84cqw; }
.art__real .ui { box-shadow: 0 26px 60px -40px rgba(10,10,11,0.45); }
.ui--site-dark { background: #1a1a1e; color: #ececee; border-color: rgba(244,244,245,0.12); }
.ui--site-dark .ui__bar { border-bottom-color: rgba(244,244,245,0.10); }
.ui--site-dark .ui__dots i { background: rgba(244,244,245,0.25); }
.ui--site-dark .ui__url { color: rgba(244,244,245,0.45); }

/* real layer: the actual project capture inside the window */
.shot { display: block; }
.shot img { display: block; width: 100%; height: auto; }

/* ════════════════════════════════════════════════════════
   05 · CLIENTES Y COLABORADORES — slow typographic marquee
   ════════════════════════════════════════════════════════ */
.clients { border-top: 1px solid var(--line); padding-block: clamp(80px, 11vh, 140px); }
.clients__title {
  grid-column: 1 / 9; grid-row: 2;
  margin-top: clamp(96px, 14vh, 180px); /* controlled upper void — the titular now sits settled on the left, no longer hung far to the lower-right */
  justify-self: start; text-align: left;
  font-weight: 300; font-size: var(--t-display);
  letter-spacing: -0.035em; line-height: 1.02;
}
.clients__support {
  grid-column: 1 / -1; grid-row: 3; /* directly beneath the titular, reads as its support line */
  margin-top: clamp(28px, 3.6vh, 46px); /* generous but controlled titular → support separation */
  font-size: var(--t-body); line-height: 1.6; color: var(--char);
  text-align: left; max-width: none; /* the two-line composition is an intentional <br>; full measure keeps the long first line on one clean line, both lines flush-left on the same axis */
}
.clients__marquee {
  grid-column: 1 / -1; grid-row: 4;
  margin-top: clamp(64px, 9.5vh, 112px);
  overflow: clip;
  border-top: 1px solid var(--line-dim); border-bottom: 1px solid var(--line-dim);
  padding: clamp(32px, 5vh, 54px) 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.clients__track {
  display: flex; width: max-content;
  animation: marquee 44s linear infinite;
}
.clients__marquee:hover .clients__track,
.clients__marquee:focus-within .clients__track { animation-play-state: paused; }
.clients__set {
  flex: none;
  display: flex; align-items: center;
  gap: clamp(110px, 16vw, 480px);
  padding-right: clamp(110px, 16vw, 480px);
}
@keyframes marquee { to { transform: translateX(-50%); } }
/* logos: grayscale by default, colour + pause on hover */
.client { display: inline-flex; align-items: center; flex: none; opacity: 0.8; transition: opacity .45s var(--ease); }
.client img { width: auto; filter: grayscale(1); transition: filter .45s var(--ease); }
.client:hover, .client:focus-visible { opacity: 1; }
.client:hover img, .client:focus-visible img { filter: none; }
.client:focus-visible { outline: 1px solid var(--ink); outline-offset: 8px; }
.client--tash img       { height: 26px; }
.client--simplifika img { height: 52px; }
.client--infozara img   { height: 34px; }
.client--quicio img     { height: 38px; }
.client--arquia img     { height: 72px; }
.client--unizar img     { height: 46px; }

/* ── red de relaciones — the section's right-side piece. An ecosystem:
   a cream core, primary trunks, lighter secondary branches, subgroups
   with air between them. All nodes present from the start; connections
   generate in sequence as the section is scrolled (motion.js drives the
   drawing via inline dasharray; each node confirms — full ink — when
   the network reaches it). Spans the void between the titular and the
   right edge (cols 6–12, rows 1–3): svg absolutely fitted. ── */
.clients__map {
  grid-column: 6 / -1; grid-row: 1 / 4; /* the ecosystem spans the whole mid-right void, in tension with the titular */
  position: relative; min-height: 0;
  pointer-events: none;
}
.clients__map svg { position: absolute; inset: 0; width: 100%; height: 100%; }

.cn-link { fill: none; stroke: rgba(10,10,11,0.30); stroke-width: 1; stroke-dasharray: 5 7; }
.cn-link--2 { stroke: rgba(10,10,11,0.18); stroke-dasharray: 3.5 6.5; } /* secondary branches — lighter, finer rhythm */
/* nodos materiales — the skyline's cream/stone, as soft physical spheres:
   core + majors in cream, mid nodes in stone, minor marks as quiet dots */
.cn-node { fill: url(#cnSphLo); }
.cn-node--lo { fill: var(--mineral-lo); }
.cn-node--xl { fill: url(#cnSph); }
.cn-hub  { fill: url(#cnSph); }
.cn-grow { transform-box: fill-box; transform-origin: 50% 50%; } /* motion.js scales these subtly with the scroll */

@media (prefers-reduced-motion: no-preference) {
  /* scroll drive — motion.js arms .cn-live and draws each connection
     via inline dasharray; nodes are present from the start (dimmed)
     and confirm to full ink (.is-on) when the network reaches them.
     Without JS or with reduced motion none of this applies: the
     network renders complete and still. */
  .cn-live .cn-mk { opacity: 0.5; transition: opacity 0.6s var(--ease-out); }
  .cn-live .cn-mk.is-on { opacity: 1; }
}

/* ════════════════════════════════════════════════════════
   06 · ESTUDIO
   ════════════════════════════════════════════════════════ */
.about { background: var(--paper-2); }
.about__title {
  grid-column: 1 / 8; grid-row: 2;
  margin-top: calc(var(--head-gap) - 26px); /* set higher — intentional tension vs. the body below */
  font-weight: 300; font-size: var(--t-display);
  letter-spacing: -0.035em; line-height: 1.02; max-width: 12ch;
}
.about__body {
  grid-column: 8 / -1; grid-row: 2;
  margin-top: calc(var(--head-gap) + 54px); /* set lower — deliberately off the title's axis */
  align-self: start;
  display: grid; gap: 20px; max-width: 42ch;
}
.about__body p { font-size: var(--t-body); line-height: 1.6; color: var(--char); }
.about__body p:first-child { color: var(--ink); }

/* ════════════════════════════════════════════════════════
   07 · TU PARTNER — mirrored about layout: long text left,
   big titular right, same editorial language
   ════════════════════════════════════════════════════════ */
.partner { background: var(--paper); border-top: 1px solid var(--line); }
.partner__body {
  grid-column: 1 / 7; grid-row: 2;
  margin-top: calc(var(--head-gap) + 54px); /* set lower — deliberate tension vs. the titular */
  display: grid; gap: 20px; max-width: 48ch;
}
.partner__body p { font-size: var(--t-body); line-height: 1.6; color: var(--char); }
.partner__body p:first-child { color: var(--ink); }
.partner__title {
  grid-column: 7 / -1; grid-row: 2;
  margin-top: calc(var(--head-gap) - 26px); /* set higher */
  justify-self: end; text-align: right;
  font-weight: 300; font-size: var(--t-display);
  letter-spacing: -0.035em; line-height: 1.05; max-width: 14ch;
}

/* ════════════════════════════════════════════════════════
   07 · CONTACTO — headline + form, black close
   ════════════════════════════════════════════════════════ */
.contact { row-gap: 0; }
.contact__title {
  grid-column: 1 / -1; grid-row: 2;
  margin-top: clamp(48px, 7vh, 80px);
  font-weight: 300; font-size: var(--t-display);
  letter-spacing: -0.04em; line-height: 1.03;
}
.contact__intro {
  grid-column: 1 / 6; grid-row: 3;
  margin-top: clamp(48px, 8vh, 90px);
  display: grid; align-content: start; gap: clamp(40px, 6vh, 64px);
}
.contact__lede-group { display: grid; gap: 10px; max-width: 34ch; }
.contact__lede {
  font-size: 14px; line-height: 1.6; letter-spacing: -0.004em;
  color: var(--on-dark-2); max-width: 34ch;
}
.contact__meta { display: grid; gap: 28px; }
.contact__meta-block { display: grid; gap: 10px; border-top: 1px solid var(--line-light-dim); padding-top: 16px; }
.contact__meta-block .mono { color: var(--on-dark-3); }
.contact__meta-block p { font-size: 14px; line-height: 1.6; color: var(--on-dark-2); }
.contact__meta-block a { transition: color .3s var(--ease); }
.contact__meta-block a:hover { color: var(--paper); }

.contact__form {
  grid-column: 7 / -1; grid-row: 3;
  margin-top: clamp(48px, 8vh, 90px);
  display: grid; gap: clamp(22px, 3.2vh, 30px);
  align-content: start;
}
.field { display: grid; gap: 10px; }
.field label { color: var(--on-dark-3); font-size: 10px; letter-spacing: 0.09em; }
.field input,
.field select,
.field textarea {
  appearance: none; -webkit-appearance: none;
  background: transparent; border: 0; border-radius: 0;
  border-bottom: 1px solid var(--line-light);
  color: var(--paper); caret-color: var(--paper);
  font-family: var(--font-sans); font-weight: 300; font-size: 16px;
  letter-spacing: -0.006em;
  padding: 6px 0 14px;
  transition: border-color .4s var(--ease);
}
.field input:focus,
.field select:focus,
.field textarea:focus { outline: none; border-bottom-color: rgba(244,244,245,0.85); }
.field input:hover,
.field select:hover,
.field textarea:hover { border-bottom-color: rgba(244,244,245,0.4); }
.field textarea { resize: vertical; min-height: 84px; line-height: 1.5; }
.field select { color: var(--on-dark-3); cursor: pointer; padding-right: 24px; }
.field select.has-value { color: var(--paper); }
.field select option { color: var(--ink); background: var(--paper); }
.field--select { position: relative; }
.field--select::after {
  content: ""; position: absolute; right: 4px; bottom: 24px;
  width: 7px; height: 7px;
  border-right: 1px solid var(--on-dark-2); border-bottom: 1px solid var(--on-dark-2);
  transform: rotate(45deg); pointer-events: none;
}

.contact__submit {
  justify-self: start; margin-top: 6px;
  display: inline-flex; align-items: center; gap: 14px;
  background: var(--paper); color: var(--ink);
  padding: 16px 30px;
  font-size: 14px; font-weight: 400; letter-spacing: -0.005em;
  transition: transform .35s var(--ease);
}
.contact__submit:hover { transform: translateY(-1px); }
.contact__submit:active { transform: translateY(0); }
.contact__submit .sarr { transition: transform .35s var(--ease); }
.contact__submit:hover .sarr { transform: translateX(4px); }

.contact__form-note { min-height: 1em; color: var(--on-dark-3); }

/* ════════════════════════════════════════════════════════
   FOOTER — compact, no metadata noise
   ════════════════════════════════════════════════════════ */
.footer { padding: 0 var(--pad) 26px; }
.footer__inner {
  border-top: 1px solid var(--line-light-dim);
  padding-top: 22px;
  display: flex; align-items: center;
  gap: clamp(24px, 3vw, 48px);
}
.footer__brand { display: inline-flex; align-items: center; flex: none; }
.footer__brand img { height: 12px; width: auto; }
.footer__items { flex: none; display: flex; gap: clamp(20px, 3vw, 44px); flex-wrap: wrap; justify-content: flex-end; }
.footer__items span {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: 0.05em; text-transform: uppercase; color: var(--on-dark-2);
}
.footer__legal {
  flex: 0 0 auto; min-width: 0; margin-left: auto;
  display: flex; gap: clamp(18px, 2.4vw, 34px); flex-wrap: wrap;
  justify-content: flex-end;
}
.footer__legal a {
  font-family: var(--font-mono); font-size: 10px;
  letter-spacing: 0.05em; text-transform: uppercase; color: var(--on-dark-3);
  transition: color .3s var(--ease);
}
.footer__legal a:hover { color: var(--paper); }

/* ════════════════════════════════════════════════════════
   CASE PANEL — editorial side panel per project
   ════════════════════════════════════════════════════════ */
.case-layer {
  position: fixed; inset: 0; z-index: 60;
  visibility: hidden;
  transition: visibility 0s linear .65s;
}
.case-layer.is-open { visibility: visible; transition: none; }
.case-layer__scrim {
  position: absolute; inset: 0;
  background: rgba(10,10,11,0.55);
  opacity: 0; transition: opacity .55s var(--ease);
  cursor: pointer;
}
.case-layer.is-open .case-layer__scrim { opacity: 1; }
.case-panel {
  position: absolute; top: 0; right: 0; bottom: 0;
  width: min(560px, 100%);
  background: var(--paper); color: var(--ink);
  display: flex; flex-direction: column;
  transform: translateX(103%);
  transition: transform .65s var(--ease-out);
}
.case-layer.is-open .case-panel { transform: translateX(0); }

.case-panel__top {
  display: flex; justify-content: space-between; align-items: center; gap: 16px;
  padding: 20px clamp(24px, 4vw, 40px);
  border-bottom: 1px solid var(--line);
  flex: none;
}
.case-panel__close { letter-spacing: 0.08em; padding: 6px 0; transition: color .3s var(--ease); }
.case-panel__close:hover { color: var(--ink); }

.case-panel__scroll {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
  padding: clamp(28px, 5vh, 44px) clamp(24px, 4vw, 40px) clamp(36px, 6vh, 56px);
}
.doc { display: grid; gap: 24px; align-content: start; }
.doc[hidden] { display: none; }
.doc__title { font-weight: 300; font-size: clamp(36px, 4vw, 54px); letter-spacing: -0.03em; line-height: 1; }
.doc__cats { font-size: 10px; }
.doc__block { display: grid; gap: 10px; }
.doc__block .mono { color: var(--mineral-lo); }
.doc__context { font-size: 15px; line-height: 1.6; color: var(--char); max-width: 46ch; }

/* case-study visual: clean, un-decorated video — the project itself, not a mockup */
.doc__video {
  overflow: hidden;
  margin-top: 4px;
}
.doc__preview-video { display: block; width: 100%; height: auto; max-height: 56vh; object-fit: cover; background: var(--ink-2); }
.doc__rebrand { margin-top: 4px; }
.doc__rebrand img { display: block; width: 100%; height: auto; border: 1px solid var(--line); }
.doc__scope { display: grid; gap: 6px; margin-top: 4px; }
.doc__scope ul { list-style: none; }
.doc__scope li {
  display: flex; gap: 14px; align-items: baseline;
  padding: 11px 0; border-top: 1px solid var(--line-dim);
  font-size: 14px; color: var(--char);
}
.doc__scope li:last-child { border-bottom: 1px solid var(--line-dim); }
.doc__scope li i {
  font-style: normal; font-family: var(--font-mono); font-size: 10px;
  color: var(--mineral-lo); letter-spacing: 0.04em;
}

.doc__actions { display: flex; justify-content: center; align-items: stretch; gap: 14px; flex-wrap: wrap; margin-top: 8px; }
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 13px 22px; font-size: 13px; letter-spacing: -0.004em;
  border: 1px solid var(--ink);
  transition: background .35s var(--ease), color .35s var(--ease);
}
.btn .mono { font-size: 10px; color: inherit; }
.btn--line:hover { background: var(--ink); color: var(--paper); }
.btn--fill { background: var(--ink); color: var(--paper); }
.btn--fill:hover { background: var(--char); }

/* ════════════════════════════════════════════════════════
   Cursor — restrained
   ════════════════════════════════════════════════════════ */
.cursor {
  position: fixed; top: 0; left: 0; width: 5px; height: 5px; border-radius: 50%;
  background: var(--ink); pointer-events: none; z-index: 90;
  transform: translate(-50%, -50%);
  transition: width .55s var(--ease-out), height .55s var(--ease-out), background .5s var(--ease), border-color .5s var(--ease);
  mix-blend-mode: difference; display: none;
}
@media (pointer: fine) { .cursor { display: block; } }
.cursor.is-link {
  width: 64px; height: 64px;
  background: rgba(244,244,245,0.08);
  border: 1px solid rgba(244,244,245,0.28);
  backdrop-filter: blur(5px); mix-blend-mode: normal;
}

@media (prefers-reduced-motion: reduce) {
  body::after { transition: none !important; }
  .line-mask > *, .fade-up, .sup-i, .manifesto__rule { animation: none !important; transform: none !important; opacity: 1 !important; }
  .intro__cue-arrow { animation: none !important; }
  .intro__tag, .intro__cue { animation: none !important; opacity: 1 !important; }
  .art__inner, .art__wire, .art__real, .case-panel, .case-layer__scrim { transition: none !important; }
  /* marquee → static roster */
  .clients__marquee { -webkit-mask-image: none; mask-image: none; }
  .clients__track { animation: none !important; width: 100%; }
  .clients__set { flex-wrap: wrap; gap: 28px 56px; padding-right: 0; }
  .clients__set:not(:first-child) { display: none; }
}

/* ════════════════════════════════════════════════════════
   Responsive
   ════════════════════════════════════════════════════════ */
@media (max-width: 820px) {
  .nav { padding-right: calc(var(--pad) + 52px); }
  .nav__menu { display: none; }
  .nav__toggle {
    display: block;
    /* centered in the free space between logo and language switch — the
       left offset is computed in JS from the real rendered boxes (see
       centerToggle in app.js); this is just the positioning/fallback base. */
    position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%);
  }

  .intro__tag { max-width: min(360px, 88vw); bottom: calc(var(--logo-h) + 140px); }
  .intro__cue { bottom: calc(var(--logo-h) + 84px); }

  .s-label { grid-column: 1 / -1; }
  .manifesto__statement { grid-column: 1 / -1; }
  .manifesto__rule { display: none; }
  .manifesto__support { grid-column: 1 / -1; justify-self: start; max-width: 44ch; }

  .work__concept { grid-column: 1 / -1; grid-row: 2; justify-self: start; text-align: left; margin-top: clamp(28px, 5vh, 52px); }
  .work__support { grid-column: 1 / -1; grid-row: 3; margin-top: clamp(18px, 3vh, 30px); max-width: 46ch; }
  .work__list { grid-row: 4; margin-top: clamp(30px, 5vh, 52px); }
  .work__item { grid-template-columns: 44px 1fr; row-gap: 6px; }
  .work__num { grid-row: 1; }
  .work__name { grid-column: 2; }
  .work__desc { display: none; } /* mobile: short summary only, see .work__short below */
  .work__short {
    display: block; grid-column: 2; max-width: 46ch;
    font-size: 14px; line-height: 1.5; color: var(--mineral);
    margin-top: 4px;
  }
  /* mobile scan mode (see motion.js): the row nearest the viewport center
     reads at full intensity, the rest sit dimmed — no accordion, no layout
     shift, only opacity hands the focus from row to row.
     !important is required here: .work-armed .work__item.is-set already
     sets opacity:1 at higher specificity (3 classes vs. 2), which would
     otherwise always win and leave every row at full intensity regardless
     of scroll position — the actual bug reported. */
  .work--scan .work__item {
    opacity: 0.3 !important;
    transition: opacity 0.45s var(--ease-out), transform 0.6s var(--ease-out), background-color 0.3s var(--ease) !important;
  }
  .work--scan .work__item.is-focus { opacity: 1 !important; background-color: rgba(10, 10, 11, 0.026); }
  /* entrance: each row rises into place the first time it crosses into the
     lower viewport (motion.js latches is-in per row in applyScan) — the
     list cascades in with the scroll instead of appearing all at once */
  .work--scan .work__item:not(.is-in) { opacity: 0 !important; transform: translateY(22px); }

  .work { padding-bottom: clamp(40px, 6vh, 72px); } /* mobile: tighter rhythm into Proyectos now the pin is gone */
  .projects { padding-top: clamp(40px, 6vh, 72px); }
  .projects__title { grid-column: 1 / -1; grid-row: 2; justify-self: start; text-align: left; margin-top: 16px; }
  .projects__grid { grid-row: 3; margin-top: clamp(48px, 8vh, 80px); }

  .clients__title { grid-column: 1 / -1; grid-row: 2; justify-self: start; text-align: left; margin-top: clamp(24px, 4vh, 40px); }
  .clients__support { grid-column: 1 / -1; grid-row: 3; align-self: auto; margin-bottom: 0; margin-top: clamp(18px, 3vh, 30px); max-width: 46ch; }
  .clients__support br { display: none; } /* mobile wraps naturally within the narrow measure — the desktop-only intentional break is dropped */
  .clients__marquee { grid-row: 4; margin-top: clamp(32px, 6vh, 56px); padding: 26px 0; }
  .clients { padding-top: clamp(32px, 5vh, 56px); }
  .clients__track { animation-duration: 28s; }
  /* móvil: misma idea, reducida — the constellation sits as a quiet
     right-aligned band between the support line and the logos; nodes
     and strokes are bumped so the half-scale render keeps its weight */
  .clients__map {
    display: block;
    grid-column: 1 / -1; grid-row: 4;
    position: relative;
    height: clamp(190px, 30vh, 250px);
    margin-top: clamp(36px, 6vh, 52px);
  }
  .cn-node:not(.cn-node--xl):not(.cn-node--lo) { r: 4.5; }
  .cn-node--lo { r: 3; }
  /* principales (hub y xl): conservan su r de atributo — la jerarquía se mantiene también en móvil */
  .cn-link { stroke-width: 2; }
  .clients__marquee { grid-row: 5; }

  .about__title, .about__body { grid-column: 1 / -1; }
  .about__title { grid-row: 2; }
  .about__body { grid-row: 3; margin-top: clamp(28px, 5vh, 48px); align-self: start; }

  .partner__title, .partner__body { grid-column: 1 / -1; }
  .partner__title { grid-row: 2; justify-self: start; text-align: left; }
  .partner__body { grid-row: 3; margin-top: clamp(28px, 5vh, 48px); }

  /* mobile order: headline → texto → formulario → email/redes */
  .contact__title { margin-top: clamp(44px, 7vh, 72px); }
  .contact__intro { display: contents; }
  .contact__lede-group { grid-column: 1 / -1; grid-row: 3; margin-top: clamp(32px, 5vh, 48px); }
  .contact__form { grid-column: 1 / -1; grid-row: 4; margin-top: clamp(44px, 7vh, 64px); }
  .contact__meta { grid-column: 1 / -1; grid-row: 5; margin-top: clamp(48px, 8vh, 72px); }

  /* mobile close: metadata first, then one last full-width "vuelco." as a
     final brand gesture */
  .footer__inner { display: flex; flex-direction: column; align-items: stretch; gap: 26px; }
  .footer__items { order: 1; flex: none; flex-direction: column; gap: 8px; justify-content: flex-start; }
  .footer__legal { order: 2; flex: none; justify-content: flex-start; margin-left: 0; }
  .footer__brand { order: 3; flex: none; }
  .footer__brand img { width: 100%; height: auto; }
}

@media (max-width: 640px) {
  .projects__grid { grid-template-columns: 1fr; gap: clamp(44px, 7vh, 72px); }
  .case__media { aspect-ratio: 5 / 4; }
  .case__foot { flex-direction: column; gap: 6px; }
  .case__view { display: none; }
  .client--tash img       { height: 20px; }
  .client--simplifika img { height: 42px; }
  .client--infozara img   { height: 26px; }
  .client--quicio img     { height: 30px; }
  .client--arquia img     { height: 56px; }
  .client--unizar img     { height: 34px; }
}

/* ════════════════════════════════════════════════════════
   MOTION LAYER — giro / encaje / sistema
   Additive interaction choreography. Everything is gated by
   prefers-reduced-motion, JS arming classes, or @supports, so
   the base design renders untouched without it.
   ════════════════════════════════════════════════════════ */
:root { --ease-swift: cubic-bezier(.76, 0, .24, 1); }

/* ── Hero: the wordmark is discovered by a horizontal mask.
   Black, a beat of silence, then VUELCO. — the dot lands last. ── */
@media screen and (prefers-reduced-motion: no-preference) {
  html:not(.no-js) .nav__brand-img { clip-path: inset(0 100% 0 0); }
  /* the discovery starts only once the page is ready (veil lifting) —
     never half-played, unseen, behind the load veil */
  html:not(.no-js) body.is-ready .nav__brand-img { animation: brandReveal 1.35s var(--ease-swift) .45s forwards; }
}
@keyframes brandReveal { to { clip-path: inset(0 0 0 0); } }

/* ── Posición: pinned scrub ─────────────────────────────── */
.m-pin { position: relative; }
.m-pin.is-armed { height: 260vh; }
.m-pin.is-armed .manifesto {
  position: sticky; top: 0;
  height: 100vh; box-sizing: border-box;
  overflow: clip;
  align-content: center;
  padding-block: clamp(48px, 8vh, 96px);
}
.m-pin.is-armed .manifesto__statement { margin-top: clamp(30px, 6vh, 60px); }
.m-pin.is-armed .manifesto__rule      { margin-top: clamp(30px, 5vh, 54px); }
.m-pin.is-armed .manifesto__support   { margin-top: clamp(26px, 5vh, 50px); }

/* the pin owns this section's choreography — release the generic
   view()-timeline reveals so the two systems never fight */
.m-pin.is-armed .line-mask > * { animation: none !important; transform: none !important; }
.m-pin.is-armed .fade-up,
.m-pin.is-armed .manifesto__rule { animation: none !important; }

/* the statement is written by the scroll */
.manifesto.is-armed .manifesto__statement :is(.mw, .dot) {
  color: rgba(10, 10, 11, 0.15);
  transition: color .5s var(--ease);
}
.manifesto.is-armed .manifesto__statement :is(.mw, .dot).on { color: var(--ink); }
.manifesto.is-armed .manifesto__statement .mute :is(.mw, .dot).on { color: var(--mineral-lo); }

/* rule + support settle once the statement is written */
.manifesto.is-armed .manifesto__support {
  opacity: 0; transform: translateY(16px);
  transition: opacity .8s var(--ease-out), transform .8s var(--ease-out);
}
.manifesto.is-armed .manifesto__rule {
  transform: scaleX(0);
  transition: transform .9s var(--ease-out) .05s;
}
.manifesto.is-armed.is-support-on .manifesto__support { opacity: 1; transform: none; }
.manifesto.is-armed.is-support-on .manifesto__rule    { transform: scaleX(1); }

/* ── skyline urbano abstracto: una composición de volúmenes que se
   EXTRUYEN del suelo con el scroll — tres niveles (base, trama media,
   principales) y vacíos deliberados. Dirección aprobada ("Prueba —
   Skyline urbano"). Mismo lenguaje material crema/gris. Sustituye a los
   tres prismas. Se conduce por data-seg (motion.js). ── */
.manifesto__prisms {
  --u: clamp(26px, 2.7vw, 40px);
  display: grid;
  grid-column: 7 / -1; grid-row: 2;
  justify-self: end; align-self: start;
  width: 100%;
  margin-top: clamp(20px, 5vh, 60px);
  justify-items: center;
}
.prism-scene {
  position: relative;
  width: calc(var(--u) * 8.6);
  height: calc(var(--u) * 6.2);
  perspective: 1600px;
  perspective-origin: 50% 30%;
  transform-style: preserve-3d;
  pointer-events: none;
}
/* one shared, rotated ground plane: every prism sits on it with real
   depth (translateZ) — the whole city lives on the same floor */
.prism-world {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transform: rotateX(-16deg) rotateY(-24deg);
  transform-origin: 50% 74%;
}
.prism {
  position: absolute; bottom: 0;
  transform-style: preserve-3d;
  transform-origin: 50% 100%;
  will-change: transform;
  visibility: visible;
  --pd: calc(var(--u) * 0.85);
  /* base (no-JS / unarmed / reduced-motion) fallback: fully built,
     settled city on the ground plane — JS overrides inline while the
     pinned scrub is live */
  transform: translateZ(calc(var(--u) * var(--z, 0))) scaleY(1);
}
/* PRINCIPALES: la torre dominante (p1), su contrapunto (p2), una tercera menor (p3) */
.prism--p1 { --z: -2.1;  left: calc(var(--u) * 3.00); width: calc(var(--u) * 1.10); height: calc(var(--u) * 5.40); }
.prism--p2 { --z: -1.1;  left: calc(var(--u) * 6.30); width: calc(var(--u) * 0.90); height: calc(var(--u) * 3.80); }
.prism--p3 { --z: -2.1;  left: calc(var(--u) * 0.90); width: calc(var(--u) * 0.80); height: calc(var(--u) * 2.90); }
/* TRAMA MEDIA — cinco piezas */
.prism--m1 { --z: -1.1;  left: calc(var(--u) * 2.20); width: calc(var(--u) * 0.80); height: calc(var(--u) * 1.90); }
.prism--m2 { --z: -0.1;  left: calc(var(--u) * 4.60); width: calc(var(--u) * 0.75); height: calc(var(--u) * 1.60); }
.prism--m3 { --z: -2.1;  left: calc(var(--u) * 5.60); width: calc(var(--u) * 0.70); height: calc(var(--u) * 2.10); }
.prism--m4 { --z: -1.1;  left: calc(var(--u) * 8.00); width: calc(var(--u) * 0.85); height: calc(var(--u) * 1.50); }
.prism--m5 { --z: -0.1;  left: calc(var(--u) * 0.20); width: calc(var(--u) * 0.90); height: calc(var(--u) * 1.30); }
/* BASE BAJA — losas y zócalos, con huecos entre grupos */
.prism--l1 { --z: 0.85;  left: 0;                     width: calc(var(--u) * 1.40); height: calc(var(--u) * 0.50); }
.prism--l2 { --z: 0.85;  left: calc(var(--u) * 2.10); width: calc(var(--u) * 0.90); height: calc(var(--u) * 0.75); }
.prism--l3 { --z: -0.1;  left: calc(var(--u) * 2.00); width: calc(var(--u) * 1.00); height: calc(var(--u) * 0.90); }
.prism--l4 { --z: 0.85;  left: calc(var(--u) * 3.60); width: calc(var(--u) * 1.60); height: calc(var(--u) * 0.40); }
.prism--l5 { --z: -0.1;  left: calc(var(--u) * 6.20); width: calc(var(--u) * 1.10); height: calc(var(--u) * 0.80); }
.prism--l6 { --z: 0.85;  left: calc(var(--u) * 6.00); width: calc(var(--u) * 0.90); height: calc(var(--u) * 0.60); }
.prism--l7 { --z: -1.1;  left: calc(var(--u) * 4.40); width: calc(var(--u) * 0.90); height: calc(var(--u) * 1.00); }
.prism--l8 { --z: 0.85;  left: calc(var(--u) * 8.30); width: calc(var(--u) * 1.00); height: calc(var(--u) * 0.55); }
/* SUELTOS — outliers en los extremos, a destiempo */
.prism--o1 { --z: -1.1;  left: calc(var(--u) * -1.35); width: calc(var(--u) * 0.70); height: calc(var(--u) * 1.05); }
.prism--o2 { --z: 0.85;  left: calc(var(--u) * -0.80); width: calc(var(--u) * 0.55); height: calc(var(--u) * 0.40); }
.prism--o3 { --z: -0.1;  left: calc(var(--u) * 9.40);  width: calc(var(--u) * 0.65); height: calc(var(--u) * 1.40); }
/* materialidad plana y editorial — tintas casi uniformes, sin brillos;
   las hileras traseras (rw-b / rw-r) aclaran hacia el papel (perspectiva
   atmosférica). Mismo lenguaje crema/gris que la web. */
.pf { position: absolute; display: block; }
.pf-f { inset: 0; background: #dfdcd6; }
.pf-s {
  top: 0; left: 100%; width: var(--pd); height: 100%;
  transform-origin: left center; transform: rotateY(90deg);
  background: #c8c5bf;
}
.pf-t {
  left: 0; top: calc(var(--pd) * -1); width: 100%; height: var(--pd);
  transform-origin: center bottom; transform: rotateX(90deg);
  background: #d7d4ce;
}
.rw-b .pf-f { background: #e3e0da; }
.rw-b .pf-s { background: #cfccc6; }
.rw-b .pf-t { background: #dcd9d3; }
.rw-r .pf-f { background: #e8e6e1; }
.rw-r .pf-s { background: #d6d3cd; }
.rw-r .pf-t { background: #e1dfda; }
@media (max-width: 820px) {
  .manifesto__prisms {
    grid-column: 1 / -1; grid-row: 4;
    justify-self: center; align-self: start;
    margin-top: clamp(24px, 4vh, 40px);
    --u: clamp(22px, 6.5vw, 34px);
  }
}

/* ── Qué hacemos: cascade in → one active service at a time → settle ── */
.work-armed .work__item {
  animation: none !important;
  opacity: 0;
  transform: translateY(26px);
  align-items: center;
  border-bottom-color: var(--line-dim);
  transition:
    opacity .5s var(--ease-out),
    transform .8s var(--ease-out),
    border-color .7s var(--ease-out),
    filter .5s var(--ease-out),
    background-color .5s var(--ease),
    padding-left .55s var(--ease);
}
.work-armed .work__item .work__name { color: var(--mineral-lo); transition: color .5s var(--ease-out); }
/* entered, waiting: visible but clearly secondary */
.work-armed .work__item.is-in { opacity: .38; transform: translateY(0); }
/* the single active service */
.work-armed .work__item.is-on {
  opacity: 1; transform: translateY(0);
  background-color: rgba(10, 10, 11, 0.026);
  border-bottom-color: var(--line);
}
.work-armed .work__item.is-on .work__name { color: var(--ink); }
/* released (or latched on mobile): settled and readable */
.work-armed .work__item.is-set {
  opacity: 1; transform: translateY(0);
  background-color: transparent;
  border-bottom-color: var(--line);
}
.work-armed .work__item.is-set .work__name { color: var(--ink); }

/* desktop pinned: sharpen the active capability, defocus the rest — a
   directed reading, one service in clear focus at a time (mobile scan
   mode never sets .w-pin.is-armed, so it is untouched) */
.w-pin.is-armed .work__item.is-in  { opacity: 0.28; filter: blur(0.6px); }
.w-pin.is-armed .work__item.is-on  { opacity: 1;   filter: none; padding-left: 16px; }
.w-pin.is-armed .work__item.is-on .work__num  { color: var(--ink); }
.w-pin.is-armed .work__item.is-on .work__desc { color: var(--char); }
.w-pin.is-armed .work__item.is-set { opacity: 1;   filter: none; }

/* pinned mode: the section holds while the scroll switches the
   system on, service by service — then releases */
.w-pin { position: relative; }
.w-pin.is-armed { height: 300vh; }
.w-pin.is-armed .work {
  position: sticky; top: 0;
  height: 100vh; box-sizing: border-box;
  overflow: clip;
  /* anchored from the top (not centered) so the active row's height
     change only pushes the content BELOW it — rows above stay put,
     avoiding the whole-block "jump" a recentering align-content:center
     would otherwise cause when work__short reveals. */
  align-content: start;
  padding-block: clamp(36px, 6vh, 80px);
}
.w-pin.is-armed .work__concept { margin-top: clamp(2px, 0.8vh, 12px); }
.w-pin.is-armed .work__support { margin-top: clamp(96px, 16vh, 168px); }
.w-pin.is-armed .work__list { margin-top: clamp(18px, 3.5vh, 46px); }
.w-pin.is-armed .work__item { padding-block: clamp(12px, 2vh, 24px); }
/* the pin owns the ROWS' choreography (is-in / is-on / is-set); the concept
   headline and the support paragraph both keep their global in-view
   entrances (headline mask / .sup-g cascade) as the section rises in —
   only the rows' own reveal is JS-driven here. */
/* work items always run their own JS-driven reveal (is-in/is-on/is-set),
   even when unpinned on mobile — neutralize the generic view-timeline
   fade-up here too, or its own scroll-progress opacity fights the classes
   above and rows near the fold get stuck invisible. */
.work-armed .work__item.fade-up { animation: none !important; }

/* ── Scan de escritorio (min-width:821px): sin pin, scroll natural. El
   servicio cuyo centro queda más cerca del centro del viewport gana
   presencia (opacidad plena + tinte sutil); el resto se atenúan. El
   layout no cambia (nombre + descripción visibles). Las reglas usan
   !important porque .work-armed .is-in/.is-set fijan la opacidad y
   ganarían por especificidad. Móvil conserva su bloque (max-width:820px). ── */
@media (min-width: 821px) {
  .work--scan .work__item {
    opacity: 0.32 !important;
    transform: translateY(0);
    filter: none;
    background-color: transparent;
    border-bottom-color: var(--line);
  }
  .work--scan .work__item:not(.is-in) { opacity: 0 !important; transform: translateY(24px); }
  .work--scan .work__item.is-focus {
    opacity: 1 !important;
    background-color: rgba(10, 10, 11, 0.026);
  }
  .work--scan .work__item.is-focus .work__desc { color: var(--char); }
}

/* ── Proyectos: cards enter by mask (keyframes used by the entrance
   layer above — see EDITORIAL ENTRANCES) ────────────────── */
@keyframes caseReveal {
  from { opacity: 0; transform: translateY(30px); clip-path: inset(4% 0 14% 0); }
  to   { opacity: 1; transform: translateY(0);    clip-path: inset(0 0 0 0); }
}

/* ════════════════════════════════════════════════════════
   MOBILE PIN — Posici\u00f3n / Qu\u00e9 hacemos keep the same pinned
   freeze-then-scrub interaction on small screens (placed last
   so it wins over the unscoped .w-pin/.m-pin rules above).
   ════════════════════════════════════════════════════════ */
@media (max-width: 820px) {
  .m-pin.is-armed .manifesto { padding-block: clamp(32px, 6vh, 64px); }
  .m-pin.is-armed .manifesto__statement { margin-top: clamp(20px, 4vh, 40px); }
  .m-pin.is-armed .manifesto__support { margin-top: clamp(18px, 3.5vh, 36px); }
}

/* ════════════════════════════════════════════════════════
   INTERACTION POLISH — final microinteraction pass.
   Hover / focus / open states only; transform + opacity + colour,
   nothing layout-affecting. Motion is gated by reduced-motion; the
   focus-visible states are always on (accessibility).
   ════════════════════════════════════════════════════════ */

/* ── Proyectos: the whole card is one target — hovering the mockup
   also arms the "Ver caso ↗" so the affordance reads as a unit ── */
.case:hover .case__view > span:first-child::after { transform: scaleX(1); transform-origin: left; }
.case:hover .case__view .case__arrow { transform: translate(3px, -3px); }

/* ── Clientes: hovering the row brings one logo forward and lets the
   rest recede — alive, never a hard spotlight ── */
.clients__marquee:hover .client,
.clients__marquee:focus-within .client { opacity: 0.5; }
.clients__marquee .client:hover,
.clients__marquee .client:focus-visible { opacity: 1; }

/* ── Botones de modal: a touch of lift, consistent with "Enviar consulta" ── */
.btn { transition: background .35s var(--ease), color .35s var(--ease), transform .35s var(--ease); }
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

/* ── Formulario: the label brightens as its field takes focus — tactile ── */
.field label { transition: color .35s var(--ease); }
.field:focus-within label { color: var(--on-dark); }
.field--select:focus-within::after { border-color: var(--on-dark); }
.contact__submit:focus-visible .sarr { transform: translateX(4px); }

/* ── Focus-visible — one restrained, on-brand keyboard vocabulary ── */
.nav__link:focus-visible::after { transform: scaleX(1); }
.lang-switch:focus-visible::after { transform: scaleX(1); transform-origin: left; }
.nav__link:focus-visible, .lang-switch:focus-visible { outline: none; }
.footer__legal a:focus-visible,
.footer__brand:focus-visible,
.menu-overlay__link:focus-visible,
.case-panel__close:focus-visible,
.contact__meta-block a:focus-visible,
.btn:focus-visible {
  outline: 1px solid currentColor; outline-offset: 4px;
}
.contact__submit:focus-visible { outline: 2px solid rgba(244, 244, 245, 0.7); outline-offset: 3px; }

@media (prefers-reduced-motion: no-preference) {
  /* ── Ficha de proyecto: the panel content settles in behind the
     sliding panel — a composed entrance, not a generic popup. Replays
     on every open because the <article> un-hides. ── */
  html.rv .case-layer.is-open .doc:not([hidden]) > * { animation: docIn 0.62s var(--ease-out) both; }
  html.rv .case-layer.is-open .doc:not([hidden]) > *:nth-child(1) { animation-delay: 0.14s; }
  html.rv .case-layer.is-open .doc:not([hidden]) > *:nth-child(2) { animation-delay: 0.20s; }
  html.rv .case-layer.is-open .doc:not([hidden]) > *:nth-child(3) { animation-delay: 0.26s; }
  html.rv .case-layer.is-open .doc:not([hidden]) > *:nth-child(4) { animation-delay: 0.32s; }
  html.rv .case-layer.is-open .doc:not([hidden]) > *:nth-child(5) { animation-delay: 0.38s; }
  html.rv .case-layer.is-open .doc:not([hidden]) > *:nth-child(6) { animation-delay: 0.44s; }
  html.rv .case-layer.is-open .doc:not([hidden]) > *:nth-child(n+7) { animation-delay: 0.50s; }
}
@keyframes docIn { from { opacity: 0; transform: translateY(14px); } }
