@font-face {
  font-family: 'EfectoWow';
  src: url("design-system/fonts/EfectoWow-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

:root {
  --purple: #380757;
  --purple-accent: #45166B;
  --lima: #dce157;
  --magenta: #ec4899;
  --orange: #f97316;
  --orange-text: #c2410c; /* darker than --orange: passes WCAG AA (5.18:1) as text on white, --orange itself only hits 2.8:1 */
  --blue: #a5d8ff;
  --cloud: #F1ECF5;
  --ink: #1A1320;
  --white: #ffffff;

  --font-display: 'EfectoWow', 'Poppins', sans-serif;
  --font-body: 'DM Sans', sans-serif;
  --font-mono: 'IBM Plex Mono', monospace;

  --space-1: 8px;
  --space-2: 16px;
  --space-3: 24px;
  --space-4: 32px;
  --space-5: 40px;
  --space-6: 48px;
  /* Every full-bleed section (nav, hero, method, toggle-section, work,
     labs, footer, ...) pads itself with this one variable, so capping it
     here caps them all at once without touching each section's markup.
     The 2nd term only takes over past ~1900px-wide viewports (it's
     negative, so max() ignores it, below that) — beyond that point it
     grows so the *content* width tops out around 1600px, turning any
     extra viewport width (ultrawide "gamer" monitors, zooming out with
     Ctrl -) into visible side margin instead of stretching every
     section's content/images/text further and further apart. */
  --page-x: max(clamp(24px, 8vw, 160px), calc((100vw - 1600px) / 2));
  --space-7: 56px;

  --nav-h: 88px;

  /* Shared type scale for section-level text. Every section (#servicios,
     #labs, #trabajo, #filosofia, #metodologia, servicios.html's category/
     FAQ headings) used to hardcode its own clamp()/px value for what is
     semantically the same role — a section heading or a section's intro
     paragraph — and they'd drifted to 7 different heading sizes and 4
     different intro-paragraph sizes with no reasoning behind the
     differences. #metodologia's numbers read as correctly balanced on
     mobile, so they're the values these tokens standardize on. */
  --h2-size: clamp(26px, 3.4vw, 38px);
  --intro-size: 15px;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

section[id] { scroll-margin-top: var(--nav-h); }

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--white);
  overflow-x: hidden;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;
  margin: 0;
  line-height: 1.15;
  letter-spacing: 0.01em;
  font-kerning: none;
  font-feature-settings: "kern" 0, "liga" 0;
}

p { line-height: 1.6; }

a { text-decoration: none; color: inherit; }

.eyebrow {
  font-family: var(--font-mono);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-size: 13px;
  color: var(--lima);
  margin: 0 0 var(--space-2);
}

.eyebrow-dark { color: var(--orange-text); }

h1 em, h2 em {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-weight: 400;
  color: var(--lima);
}

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 16px 32px;
  border-radius: 999px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 16px;
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.btn:hover { transform: translateY(-2px); }
.btn-sm { padding: 10px 22px; font-size: 14px; }
.btn-primary { background: var(--lima); color: var(--purple); }
.btn-primary:hover { box-shadow: 0 8px 24px rgba(220,225,87,0.4); }
.btn-outline { background: transparent; border-color: var(--white); color: var(--white); }
.btn-outline:hover { background: rgba(255,255,255,0.1); }

/* Nav */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--page-x);
  background: transparent;
  color: var(--white);
  transition: background-color 0.3s ease;
}
.nav.is-scrolled {
  background:
    radial-gradient(circle at 75% 20%, var(--purple-accent) 0%, var(--purple) 55%),
    url("design-system/backgrounds/wow-squiggle-texture.webp");
  background-repeat: no-repeat, no-repeat;
  background-position: center, center;
  background-size: cover, cover;
}
main { padding-top: var(--nav-h); }
.logo {
  display: flex;
  align-items: center;
  gap: 10px;
}
.logo-img {
  height: 56px;
  width: auto;
  display: block;
}
.footer-logo-img {
  height: 44px;
  width: auto;
  display: block;
}
.nav-links { display: flex; align-items: center; gap: var(--space-4); }
.nav-links a:not(.btn) {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--cloud);
  transition: color 0.15s ease;
}
.nav-links a:not(.btn):hover { color: var(--lima); }

/* Services mega menu — opens on hover (":hover" + ":focus-within" so
   keyboard/tab users get it too) under the "Servicios" nav link, mirroring
   the Superside-style dropdown reference. Pure CSS, no JS needed. */
.nav-item { position: static; display: flex; align-items: center; }
.nav-item-trigger { display: inline-flex; align-items: center; gap: 4px; }
.nav-item-caret { font-size: 10px; transition: transform 0.2s ease; }
.nav-item:hover .nav-item-caret, .nav-item:focus-within .nav-item-caret { transform: rotateX(180deg); }
.nav-dropdown {
  position: fixed;
  top: var(--nav-h);
  left: 0;
  right: 0;
  z-index: 49;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5) var(--page-x);
  background:
    radial-gradient(circle at 75% 20%, var(--purple-accent) 0%, var(--purple) 55%),
    url("design-system/backgrounds/wow-squiggle-texture.webp");
  background-repeat: no-repeat, no-repeat;
  background-position: center, center;
  background-size: cover, cover;
  border-top: 1px solid rgba(255,255,255,0.1);
  box-shadow: 0 24px 48px rgba(0,0,0,0.35);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s linear 0.2s;
}
.nav-item:hover .nav-dropdown,
.nav-item:focus-within .nav-dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s linear 0s;
}
.nav-dropdown-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4) var(--space-5);
}
.nav-dropdown-col { display: flex; flex-direction: column; gap: 10px; }
.nav-dropdown-cat {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 4px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--white);
  padding-bottom: 8px;
  border-bottom: 1px solid rgba(255,255,255,0.14);
}
.nav-dropdown-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.nav-dot-lima { background: var(--lima); }
.nav-dot-blue { background: var(--blue); }
.nav-dot-magenta { background: var(--magenta); }
.nav-dot-orange { background: var(--orange); }
.nav-dot-cloud { background: var(--cloud); }
.nav-dropdown-col a,
.nav-dropdown-link {
  display: block;
  /* Shrink to fit the text (not stretched to the column's full width by the
     flex column's default align-items:stretch) — the popup's arrow is
     centered using this element's own getBoundingClientRect(), so it needs
     to end at the text, not the whole row's clickable width. */
  align-self: flex-start;
  max-width: 100%;
  padding: 0;
  border: none;
  background: none;
  text-align: left;
  font-family: var(--font-body);
  font-size: 14px;
  text-transform: none;
  letter-spacing: normal;
  color: #d9d2e0;
  cursor: pointer;
  transition: color 0.15s ease;
}
.nav-dropdown-col a:hover,
.nav-dropdown-link:hover,
.nav-dropdown-link.active { color: var(--lima); }
/* Click a service to see a short description — same white-card popup
   pattern as .hub-popup (services section), positioned relative to
   .nav-dropdown (which is itself the containing block, being
   position:fixed) instead of #hubDiagram. */
.nav-service-popup {
  position: absolute;
  z-index: 10;
  /* Vertically centered on the clicked link via translateY(-50%) (top is set
     in JS to the link's own vertical center) — the horizontal position is
     plain px set in JS (not a transform), since it flips from "right of the
     link" to "left of the link" depending on available space, and mixing
     that flip with a translateX(-50%)-style trick gets confusing fast. */
  top: 0;
  left: 0;
  transform: translateY(-50%) translateX(6px) scale(0.96);
  width: 240px;
  max-width: 70vw;
  padding: var(--space-2) var(--space-3);
  border-radius: 12px;
  background: var(--white);
  color: var(--purple);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
  text-align: left;
  box-shadow: 0 12px 28px rgba(0,0,0,0.35);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease, transform 0.15s ease;
}
.nav-service-popup.is-open { opacity: 1; transform: translateY(-50%) translateX(0) scale(1); pointer-events: auto; }
.nav-service-popup.is-flip { transform: translateY(-50%) translateX(-6px) scale(0.96); }
.nav-service-popup.is-flip.is-open { transform: translateY(-50%) translateX(0) scale(1); }
.nav-service-popup p { margin: 0; }
.nav-service-popup-arrow {
  position: absolute;
  top: 50%;
  left: -6px;
  transform: translateY(-50%) rotate(45deg);
  width: 12px;
  height: 12px;
  background: var(--white);
  border-radius: 2px;
}
/* Flipped when there isn't enough room to the right (links in the last
   column or two) — popup sits to the left of the link instead, so the
   arrow needs to move to the popup's right edge. */
.nav-service-popup.is-flip .nav-service-popup-arrow { left: auto; right: -6px; }
.nav-dropdown-cta {
  align-self: flex-start;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--lima);
  padding-top: var(--space-3);
  border-top: 1px solid rgba(255,255,255,0.14);
  width: 100%;
}
.nav-dropdown-cta:hover { color: var(--white); }
.nav-burger {
  display: none;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border: none;
  background: transparent;
  cursor: pointer;
  position: relative;
  z-index: 51;
}
/* Mobile nav — a compact floating glass panel over a blurred backdrop: a creative-studio overlay, not a fullscreen modal.
   Base display:none here (and on .nav-burger above) must stay BEFORE the @media block below: the media query's
   display:flex/block only wins the cascade if it comes after these unconditional rules — reversing the order
   previously made the mobile menu permanently unopenable at every viewport width, regardless of .is-open. */
.nav-mobile-menu {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 55;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(20, 4, 34, 0.5);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.3s ease, visibility 0s linear 0.3s;
}
@media (max-width: 900px) {
  .nav-dropdown { display: none; }
  /* Burger nav now switches on at the same 900px boundary where the desktop
     mega-menu already turns off, instead of 720px. Between 721-900px the
     full set of nav-links (Servicios/Labs/Trabajo/Portafolio + lang toggle +
     CTA button) didn't fit one row and wrapped to a second line, making the
     nav render ~20px taller than --nav-h (108px vs the 88px used everywhere
     hero/section offsets are calculated) — that mismatch is the root cause
     of the hero-sub / hero-sub-secondary text scrolling in partially behind
     the opaque fixed nav on tablet widths. */
  .nav-links { gap: var(--space-2); }
  .nav-links a:not(.btn) { display: none; }
  .nav-links .btn { display: none; }
  .nav-burger { display: block; }
  .nav-mobile-menu { display: flex; }
}
.nav-burger span {
  position: absolute;
  top: 50%;
  left: 8px;
  right: 8px;
  height: 2px;
  background: var(--white);
  border-radius: 2px;
  transition: transform 0.25s ease, opacity 0.2s ease;
}
.nav-burger span:nth-child(1) { transform: translateY(-7px); }
.nav-burger span:nth-child(2) { transform: translateY(-1px); }
.nav-burger span:nth-child(3) { transform: translateY(5px); }
.nav-burger.is-open span:nth-child(1) { transform: translateY(-1px) rotate(45deg); }
.nav-burger.is-open span:nth-child(2) { opacity: 0; }
.nav-burger.is-open span:nth-child(3) { transform: translateY(-1px) rotate(-45deg); }
.nav-mobile-menu.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.3s ease, visibility 0s linear 0s;
}
.nav-mobile-panel {
  position: relative;
  width: 100%;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  background: rgba(56, 7, 87, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 22px;
  padding: var(--space-4) var(--space-3);
  box-shadow: 0 30px 70px rgba(10, 0, 20, 0.45);
  overflow: hidden;
  transform: scale(0.92) translateY(6px);
  opacity: 0;
  transition: transform 0.4s cubic-bezier(0.2, 0.85, 0.25, 1), opacity 0.3s ease;
}
.nav-mobile-menu.is-open .nav-mobile-panel { transform: scale(1) translateY(0); opacity: 1; }
.nav-mobile-top { position: relative; display: flex; align-items: center; justify-content: center; width: 100%; margin-bottom: var(--space-3); }
.nav-mobile-top .logo-img { height: 50px; }
.nav-mobile-close {
  position: absolute;
  top: -6px;
  right: 0;
  width: 38px;
  height: 38px;
  border: none;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 50%;
  cursor: pointer;
}
.nav-mobile-close span {
  position: absolute;
  top: 50%;
  left: 10px;
  right: 10px;
  height: 2px;
  background: var(--white);
  border-radius: 2px;
}
.nav-mobile-close span:nth-child(1) { transform: translateY(-1px) rotate(45deg); }
.nav-mobile-close span:nth-child(2) { transform: translateY(-1px) rotate(-45deg); }
.nav-mobile-links { display: flex; flex-direction: column; align-items: center; width: 100%; }
.nav-mobile-links a {
  position: relative;
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 12px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(30px, 9.5vw, 40px);
  line-height: 1.2;
  color: var(--white);
  padding: 8px 0;
  opacity: 0;
  transform: translateY(14px);
  transition: transform 0.4s ease, opacity 0.4s ease, color 0.15s ease;
}
.nav-mobile-links a:not(:last-child)::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 44px;
  height: 1px;
  background: rgba(255, 255, 255, 0.18);
}
.nav-mobile-links a:hover { color: var(--lima); }
.nav-mobile-link-num {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.05em;
  color: var(--lima);
}
.nav-mobile-menu.is-open .nav-mobile-links a { opacity: 1; transform: translateY(0); }
.nav-mobile-menu.is-open .nav-mobile-links a:nth-child(1) { transition-delay: 0.1s; }
.nav-mobile-menu.is-open .nav-mobile-links a:nth-child(2) { transition-delay: 0.16s; }
.nav-mobile-menu.is-open .nav-mobile-links a:nth-child(3) { transition-delay: 0.22s; }
.nav-mobile-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: var(--space-3);
  opacity: 0;
  transform: translateY(14px);
  transition: transform 0.4s ease, opacity 0.4s ease;
}
.nav-mobile-cta-arrow { transition: transform 0.2s ease; }
.nav-mobile-cta:hover .nav-mobile-cta-arrow { transform: translateX(4px); }
.nav-mobile-menu.is-open .nav-mobile-cta { opacity: 1; transform: translateY(0); transition-delay: 0.28s; }
.nav-mobile-foot {
  margin-top: var(--space-4);
  padding-top: var(--space-2);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  opacity: 0;
  transition: opacity 0.4s ease;
}
.nav-mobile-menu.is-open .nav-mobile-foot { opacity: 1; transition-delay: 0.34s; }
.nav-mobile-foot-mark { font-size: 18px; color: var(--lima); }
.nav-mobile-foot a {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--cloud);
  padding: 12px 6px;
}
.nav-mobile-foot a:hover { color: var(--lima); }

/* Hero */
.hero {
  position: relative;
  height: min(96vh, 960px);
  min-height: 640px;
  margin-top: calc(-1 * var(--nav-h));
  background:
    radial-gradient(circle at 75% 20%, var(--purple-accent) 0%, var(--purple) 55%),
    url("design-system/backgrounds/wow-squiggle-texture.webp");
  background-repeat: no-repeat, no-repeat;
  background-position: center, center;
  background-size: cover, cover;
  color: var(--white);
  padding: calc(var(--space-7) + var(--nav-h)) var(--page-x) var(--space-7);
  text-align: left;
  overflow: hidden;
}
.hero-inner {
  display: flex;
  align-items: stretch;
  gap: var(--space-5);
  width: 100%;
  height: 100%;
}
/* Basis scales with viewport (clamp, same shape as the h1 font-size
   clamp below) instead of a fixed 520px — at a fixed basis, the
   headline's own max-width (640px, needed so "que se sientan reales" /
   "that feel real" fits on its own line) exceeded the column it sat in
   once the h1's font-size grew past ~57px (roughly 1600px+ viewports),
   so on wide screens it wrapped into 3 cramped lines instead of the
   intended 2, with a big dead gap opening up before hero-media (whose
   own margin-left: auto pushes it to the far right regardless of how
   little width hero-content actually uses). */
.hero-content { position: relative; z-index: 2; flex: 0 1 clamp(520px, 40vw, 800px); min-width: 280px; align-self: center; }
.hero h1 {
  font-size: clamp(28px, 3.6vw, 68px);
  max-width: 100%;
  margin: var(--space-2) 0 var(--space-3);
}
.hero-sub {
  max-width: 480px;
  font-size: 19px;
  color: var(--cloud);
  margin-bottom: var(--space-2);
}
.hero-cta { display: flex; gap: var(--space-2); flex-wrap: wrap; }

/* Outline word */
.outline-word {
  position: absolute;
  top: var(--space-4);
  right: var(--space-5);
  left: var(--space-5);
  font-family: var(--font-display);
  font-size: clamp(40px, 7vw, 110px);
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.04em;
  font-kerning: none;
  font-feature-settings: "kern" 0, "liga" 0;
  color: transparent;
  -webkit-text-stroke: 1px currentColor;
  opacity: 0.3;
  pointer-events: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
  text-align: right;
  z-index: 0;
}
.outline-orange { color: var(--orange); }
.outline-magenta { color: var(--magenta); }
.outline-blue { color: var(--blue); }
.method, .toggle-section, .labs, .services, .work { position: relative; overflow: hidden; }
.method > *:not(.outline-word), .toggle-inner, .labs > *:not(.outline-word),
.services > *:not(.outline-word):not(.figma-cursor), .work > *:not(.outline-word) {
  position: relative;
  z-index: 1;
}
@media (max-width: 720px) {
  .outline-word { display: none; }
}

/* Toggle / switch list — pinned until every switch turns on */
.toggle-pin {
  position: relative;
  /* Capped — an uncapped vh multiplier grows the scroll-pin distance (and
     with it, the rounding error in the sticky child's stick/unstick math)
     without bound on unusual viewports, the likely cause of a reported
     gap appearing between this section and the next after zooming out. */
  height: min(190vh, 1700px);
}
.toggle-section {
  position: sticky;
  top: var(--nav-h);
  /* Capped (not just 100vh - navH) — on an unusually tall/short-ratio
     viewport, an uncapped 100vh floor stretches this section (content is
     vertically centered) into a mostly-empty box with the toggle list
     floating in a sea of dead space, same fix as .hero's min(96vh,960px). */
  min-height: min(calc(100vh - var(--nav-h)), 760px);
  display: flex;
  align-items: center;
  padding: var(--space-5) var(--page-x);
  background: var(--cloud);
  overflow: hidden;
}
.toggle-inner {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  width: 100%;
}
.toggle-copy { flex: 1 1 480px; min-width: 0; }
.toggle-section h2 {
  font-size: var(--h2-size);
  color: var(--purple);
  margin-bottom: var(--space-4);
}
.toggle-intro { font-size: var(--intro-size); line-height: 1.6; }
.toggle-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: 760px;
}

/* Icon morph animation */
.icon-morph {
  position: relative;
  flex: 0 0 200px;
  height: 200px;
  margin-right: var(--space-5);
  display: none;
}
.morph-icon {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 24px;
  opacity: 0;
  animation: morphCycle 7.5s infinite;
}
.mi-1 { animation-delay: 0s; }
.mi-2 { animation-delay: 1.5s; }
.mi-3 { animation-delay: 3s; }
.mi-4 { animation-delay: 4.5s; }
.mi-5 { animation-delay: 6s; }
@keyframes morphCycle {
  0% { opacity: 0; transform: scale(0.5) rotate(-30deg); }
  4% { opacity: 1; transform: scale(1) rotate(0deg); }
  16% { opacity: 1; transform: scale(1) rotate(0deg); }
  20% { opacity: 0; transform: scale(0.5) rotate(30deg); }
  100% { opacity: 0; }
}
@media (min-width: 901px) {
  .icon-morph { display: block; }
}
@media (prefers-reduced-motion: reduce) {
  .morph-icon { animation: none; opacity: 0; }
  .mi-1 { opacity: 1; }
}
.toggle-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  background: var(--white);
  border-radius: 999px;
  padding: 10px var(--space-3) 10px 10px;
}
.switch {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  border-radius: 999px;
  border: none;
  background: #d8d3c8;
  min-width: 64px;
  cursor: pointer;
  transition: background 0.2s ease;
}
.switch-label {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  color: var(--white);
}
.switch-knob {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--white);
  margin-left: auto;
  transition: transform 0.2s ease;
}
.switch:not(.is-on) .switch-knob { order: -1; margin-left: 0; margin-right: auto; }
.switch:not(.is-on) .switch-label { color: #6b6458; }
.toggle-on-lima .switch.is-on { background: var(--lima); }
.toggle-on-lima .switch.is-on .switch-label { color: var(--purple); }
.toggle-on-orange .switch.is-on { background: var(--orange); }
.toggle-on-magenta .switch.is-on { background: var(--magenta); }
.toggle-text { font-size: 16px; color: var(--ink); transition: opacity 0.3s ease, max-width 0.3s ease; opacity: 1; }
.toggle-text strong { display: block; margin-bottom: 2px; }
.toggle-item.text-hidden .toggle-text { opacity: 0; }

/* Method loop — see .method-loop and friends further down for the circular
   scroll-driven rocket/track (this used to be a straight left-to-right timeline). */

/* Hero media marquee */
.hero-media {
  position: relative;
  flex: 0 1 620px;
  max-width: 620px;
  min-width: 260px;
  margin-left: auto;
  display: flex;
  gap: var(--space-2);
  align-self: stretch;
  margin-top: calc(-1 * (var(--space-7) + var(--nav-h)));
  margin-bottom: calc(-1 * var(--space-7));
  height: calc(100% + var(--nav-h) + (var(--space-7) * 2));
  overflow: hidden;
  z-index: 1;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, black calc(var(--nav-h) + 70px), black 88%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, black calc(var(--nav-h) + 70px), black 88%, transparent 100%);
}
.media-col {
  display: flex;
  flex-direction: column;
  align-self: flex-start;
  gap: var(--space-2);
  flex: 1 1 0;
  animation: scrollUp 110s linear infinite;
}
.media-col-b { animation-duration: 140s; animation-direction: reverse; }
.media-col-c { animation-duration: 170s; }
.media-card {
  position: relative;
  flex: 0 0 auto;
  aspect-ratio: 2 / 3;
  width: 100%;
  border-radius: 18px;
  border: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 14px;
  color: var(--white);
  cursor: pointer;
  transition: transform 0.2s ease;
}
.media-card:hover { transform: scale(1.04); }
@media (hover: hover) {
  .media-card:hover { cursor: none; }
}
.media-col:hover { animation-play-state: paused; }
.media-card span { font-size: 22px; }
.media-photo {
  /* contain, not cover: the card's aspect-ratio can change across
     breakpoints (see the mobile override further down, which drops
     aspect-ratio to auto), so a fixed image ratio can't always match the
     box — contain guarantees the full photo is always visible instead of
     cropping it whenever ratio and box disagree. background-color is the
     letterbox fill for the space that opens up on either side. */
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  background-color: var(--purple);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.15);
}

/* Hero mosaic: the "taller" door as a custom cursor (see the door-cursor IIFE in index.html).
   It's position:fixed and never sits inside a card's layout or DOM, so it can't cover the
   image or interfere with the card's own click. Only ever created on hover-capable devices. */
.door-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 999;
  pointer-events: none;
}
.door-cursor-inner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.7) translateY(6px);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.door-cursor.is-visible .door-cursor-inner { opacity: 1; transform: translate(-50%, -50%) scale(1) translateY(0); }
.door-cursor-frame {
  position: relative;
  width: 78px;
  height: 92px;
  flex: 0 0 auto;
  border-radius: 39px 39px 8px 8px;
  background: var(--purple);
  padding: 5px;
  box-shadow: 0 10px 22px rgba(10, 2, 18, 0.45);
}
.door-cursor-leaf {
  position: absolute;
  inset: 5px;
  border-radius: 34px 34px 5px 5px;
  background:
    repeating-linear-gradient(90deg, rgba(56,7,87,0.1) 0 1.5px, transparent 1.5px 14px),
    linear-gradient(160deg, var(--lima), #c3c93a);
  box-shadow: inset 0 0 0 2px rgba(56,7,87,0.5);
  transform-origin: left center;
  transform: rotateY(8deg);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 10px;
  gap: 4px;
}
.door-cursor-handle {
  position: absolute;
  right: 6px;
  top: 50%;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #5b1a86, var(--purple) 70%);
  transform: translateY(-50%);
}
.door-cursor-mark-ring {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1.5px solid rgba(56,7,87,0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
.door-cursor-mark-ring img { width: 9px; height: 9px; opacity: 0.85; }
.door-cursor-label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 10px;
  line-height: 1.15;
  color: var(--purple);
  text-align: center;
  text-transform: uppercase;
}
.door-cursor-arrow { display: block; font-size: 10px; font-weight: 400; text-transform: none; }
.door-cursor-spark {
  position: absolute;
  color: var(--lima);
  font-size: 12px;
  opacity: 0.85;
}
.door-cursor-spark-1 { top: -2px; left: 2px; }
.door-cursor-spark-2 { top: 14px; right: -4px; }

@keyframes scrollUp {
  from { transform: translateY(0); }
  to { transform: translateY(-50%); }
}

@media (max-width: 900px) {
  .hero { height: auto; }
  .hero-inner { flex-direction: column; height: auto; align-items: center; }
  .hero-content { text-align: center; max-width: 560px; flex: 0 1 auto; }
  .hero h1, .hero-sub { margin-left: auto; margin-right: auto; }
  .hero-cta { justify-content: center; }
  .hero-media {
    width: calc(100% + (2 * var(--page-x)));
    max-width: none;
    flex-basis: auto;
    flex-direction: column;
    height: auto;
    gap: var(--space-2);
    margin-top: 0;
    margin-bottom: 0;
    margin-left: calc(-1 * var(--page-x));
    align-self: auto;
    overflow: hidden;
    -webkit-mask-image: none;
    mask-image: none;
  }
  .media-col {
    flex: 0 0 auto;
    flex-direction: row;
    align-self: stretch;
    width: max-content;
    height: 150px;
    gap: var(--space-2);
    animation: heroRowLeft 32s linear infinite !important;
  }
  .media-col-b { animation: heroRowRight 32s linear infinite !important; }
  .media-col-c { display: none; }
  /* aspect-ratio 2/3 matches these photos' real ratio almost exactly, so the
     card's width now derives from the row's fixed height instead of being a
     separate guess (112px) that didn't match — that mismatch was letterboxing
     every card in this row. */
  .hero-media .media-card { flex: 0 0 auto; width: auto; height: 100%; aspect-ratio: 2 / 3; }
  @keyframes heroRowLeft { from { transform: translateX(0); } to { transform: translateX(-50%); } }
  @keyframes heroRowRight { from { transform: translateX(-50%); } to { transform: translateX(0); } }
}
@media (prefers-reduced-motion: reduce) {
  .media-col { animation: none; }
  .work-door.is-open .work-door-frame { animation: none; }
}

/* Services */
.services {
  padding: var(--space-7) var(--page-x);
  background: var(--white);
  position: relative;
  isolation: isolate;
  cursor: none;
}
.services a, .services button { cursor: none; }
.figma-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 2147483647;
  display: flex;
  align-items: flex-start;
  gap: 4px;
  pointer-events: none;
  opacity: 0;
  transform: translate(-2px, -2px);
  will-change: transform;
}
.figma-cursor.is-visible { opacity: 1; }
/* Swap arrow → hand over clickable elements, same Figma-collaborator look
   (lima fill, purple stroke, "Tú" tag) either way — just the icon shape. */
.cursor-hand { display: none; }
.figma-cursor.is-pointer .cursor-arrow { display: none; }
.figma-cursor.is-pointer .cursor-hand { display: block; }
.figma-cursor-label {
  margin-top: 14px;
  padding: 2px 8px;
  border-radius: 6px;
  background: var(--lima);
  color: var(--purple);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}
@media (max-width: 900px) {
  .services { cursor: auto; }
  .services a, .services button { cursor: pointer; }
  .figma-cursor { display: none; }
}
.services h2 {
  font-size: var(--h2-size);
  color: var(--purple);
  margin-top: var(--space-6);
  margin-bottom: var(--space-2);
  max-width: 480px;
}
/* Labs — hover-expand panels */
.labs {
  padding: calc(var(--nav-h) + var(--space-4)) 0 0;
  background: var(--purple);
}
.labs-intro-row {
  padding: 0 var(--page-x);
  margin-bottom: var(--space-5);
}
@media (min-width: 900px) {
  .labs-intro-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-6);
    align-items: end;
  }
  .labs-intro { margin-top: 0; max-width: none; }
}
.labs .eyebrow {
  padding: 0;
}
.labs h2 {
  color: var(--white);
  font-size: var(--h2-size);
  margin-bottom: 0;
  max-width: 560px;
}
.labs-intro {
  padding: 0;
  color: rgba(255,255,255,0.82);
  font-size: var(--intro-size);
  line-height: 1.6;
  max-width: 640px;
  margin: var(--space-3) 0 0;
}
.labs-panels {
  display: flex;
  gap: 0;
  width: 100%;
  height: 520px;
  border-radius: 0;
  overflow: hidden;
  margin-top: var(--space-4);
}
.labs-panel {
  position: relative;
  flex: 1;
  cursor: pointer;
  transition: flex 0.4s ease;
  display: flex;
  align-items: flex-end;
  padding: var(--space-4);
  overflow: hidden;
}
.labs-panels:hover .labs-panel { flex: 1; }
.labs-panels .labs-panel:hover { flex: 3.2; }
.labs-panel-insight { background: linear-gradient(160deg, #5aa9f7, #3B82F6); }
.labs-panel-brand { background: linear-gradient(160deg, #c084fc, #A855F7); }
.labs-bg-icon {
  position: absolute;
  right: -10%;
  bottom: -10%;
  width: 70%;
  height: auto;
  opacity: 0;
  filter: brightness(0) invert(1);
  transition: opacity 0.4s ease, transform 0.4s ease;
  transform: scale(0.85);
  pointer-events: none;
}
.labs-panel:hover .labs-bg-icon { opacity: 0.16; transform: scale(1); }
.labs-label {
  position: absolute;
  bottom: var(--space-4);
  left: var(--space-4);
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 18px;
  color: rgba(255,255,255,0.85);
  white-space: nowrap;
  transition: opacity 0.25s ease;
}
.labs-label-icon { width: 16px; height: 16px; filter: brightness(0) invert(1); }
.labs-panel:hover .labs-label { opacity: 0; }
.labs-content {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.3s ease 0.1s, transform 0.3s ease 0.1s;
  color: var(--white);
  max-width: 420px;
}
.labs-panel:hover .labs-content { opacity: 1; transform: translateY(0); }
.labs-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border: none;
  border-radius: 999px;
  background: rgba(255,255,255,0.2);
  color: var(--white);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: var(--space-2);
  cursor: pointer;
  transition: background 0.15s ease;
}
.labs-tag:hover { background: rgba(255,255,255,0.32); }
.labs-tag-icon { width: 12px; height: 12px; filter: brightness(0) invert(1); }
.labs-toggle { display: none; }
.labs-content h3 { font-size: 22px; margin-bottom: var(--space-1); }
.labs-content p { margin: 0; font-size: 14px; opacity: 0.9; }
@media (max-width: 900px) {
  /* Accordion: collapsed color bars, tap to expand one at a time (matches the reference) */
  .labs-panels { flex-direction: column; height: auto; }
  .labs-panel {
    flex: none !important;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--page-x);
    cursor: pointer;
  }
  .labs-label {
    position: static;
    writing-mode: horizontal-tb;
    transform: none;
    margin-bottom: 0;
    font-size: 17px;
    opacity: 1;
    order: 0;
  }
  .labs-panel:hover .labs-label { opacity: 1; }
  /* The lab name already shows in .labs-label above — the tag pill repeating it here is redundant on mobile */
  .labs-tag { display: none; }
  .labs-toggle {
    display: block;
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 1.5px solid rgba(255,255,255,0.6);
    background: transparent;
    position: relative;
    cursor: pointer;
    order: 1;
  }
  .labs-toggle span, .labs-toggle span::before {
    content: '';
    position: absolute;
    top: 50%; left: 50%;
    width: 14px; height: 2px;
    background: var(--white);
    transform: translate(-50%, -50%);
    transition: transform 0.25s ease;
  }
  .labs-toggle span::before { transform: translate(-50%, -50%) rotate(90deg); }
  .labs-panel.is-open .labs-toggle span::before { transform: translate(-50%, -50%) rotate(0deg); }
  .labs-content {
    order: 2;
    flex-basis: 100%;
    max-width: none;
    position: static;
    max-height: 0;
    opacity: 0;
    transform: none;
    overflow: hidden;
    transition: max-height 0.35s ease, opacity 0.3s ease, margin-top 0.35s ease;
  }
  .labs-panel.is-open .labs-content { max-height: 1000px; opacity: 1; margin-top: var(--space-2); }
  .labs-bg-icon { opacity: 0.14; }
  .labs-panel.is-open .labs-bg-icon { opacity: 0.18; transform: scale(1); }
}

/* Hub diagram */
.hub-diagram {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-7);
  min-height: 420px;
}
.hub-arrows {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
}
.hub-col {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  max-width: 380px;
}
.hub-col-left {
  /* Each .hub-row is capped at 3 pills and is its own flex container, so a row's
     pills size to their own text width independently of other rows (a shared grid
     column would force one width down the whole column — see git history) while
     still hard-capping the row at 3, which plain flex-wrap can't guarantee. */
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  max-width: 700px;
}
/* nowrap: a .hub-row must never break onto a second line — if it doesn't fit in
   700px, that's a row to rebalance in the HTML, not something to auto-wrap (an
   auto-wrap would visually orphan a pill onto its own line, which reads exactly
   like the standalone "…y mucho más" row and defeats the point of grouping). */
.hub-row { display: flex; flex-wrap: nowrap; justify-content: flex-end; gap: 10px; }
.hub-col-left .hub-pill { padding: 7px 13px; }
.hub-col-right { flex-direction: column; align-items: flex-start; max-width: 220px; }
.hub-pill {
  display: inline-flex;
  align-items: center;
  padding: 10px 18px;
  border-radius: 999px;
  border: 2px solid transparent;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  white-space: nowrap;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.hub-pill:hover { transform: translateY(-2px) scale(1.05); box-shadow: 0 8px 18px rgba(56,7,87,0.18); }
.hub-pill.active { border-color: var(--purple); box-shadow: 0 8px 18px rgba(56,7,87,0.25); }
/* Match the two remaining Labs' actual panel colors (.labs-panel-brand / .labs-panel-insight)
   so a service's pill color tells you which Lab it belongs to at a glance. */
.hub-lab-brand { background: #A855F7; color: var(--white); }
.hub-lab-insight { background: #3B82F6; color: var(--white); }
.hub-center {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  width: 100px;
  height: 100px;
  border-radius: 26px;
  background: var(--purple);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  cursor: pointer;
  box-shadow: 0 20px 40px rgba(56,7,87,0.25);
}
.hub-w {
  width: 38%;
  height: auto;
  clip-path: inset(0 100% 0 0);
  transition: opacity 0.3s ease;
}
.hub-w.is-typed { animation: typeW 1s steps(20) forwards; }
@keyframes typeW { to { clip-path: inset(0 0 0 0); } }
.hub-full-logo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 14px;
  object-fit: contain;
  opacity: 0;
  transform: scale(0.7);
  transition: opacity 0.3s ease, transform 0.3s ease;
  pointer-events: none;
}
.hub-center:hover .hub-w, .hub-center.is-open .hub-w { opacity: 0; }
.hub-center:hover .hub-full-logo, .hub-center.is-open .hub-full-logo { opacity: 1; transform: scale(1); }
.hub-center-wrap {
  /* position+z-index needed so this (and the CTA link inside it) paints above
     .hub-arrows — that SVG is position:absolute with z-index:0, and per CSS
     stacking rules a positioned element always paints above a non-positioned
     one regardless of DOM order, so without this the invisible SVG silently
     ate every click meant for the link underneath it. */
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}
.hub-popup {
  position: absolute;
  z-index: 10;
  transform: translateX(-50%) translateY(4px) scale(0.96);
  width: 240px;
  max-width: 70vw;
  padding: var(--space-2) var(--space-3);
  border-radius: 12px;
  background: var(--white);
  color: var(--purple);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
  text-align: left;
  box-shadow: 0 12px 28px rgba(56,7,87,0.28);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease, transform 0.15s ease;
}
.hub-popup.is-open { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); pointer-events: auto; }
.hub-popup p { margin: 0; }
.hub-popup-arrow {
  position: absolute;
  top: -6px;
  left: 50%;
  transform: translateX(-50%) rotate(45deg);
  width: 12px;
  height: 12px;
  background: var(--white);
  border-radius: 2px;
}

@media (max-width: 900px) {
  .hub-diagram { flex-direction: column; align-items: center; min-height: 0; }
  .hub-col-right {
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    max-width: 100%;
    row-gap: 8px;
  }
  /* Flatten the desktop row grouping (each .hub-row was its own wrap
     container, capped at 3-4 pills) into one shared flex-wrap pool so the
     browser can pack pills across former row boundaries instead of being
     forced to break exactly where the desktop grouping did — that forced
     breaking was stranding single pills alone on their own line whenever a
     3-pill group didn't quite fit 3-across at 375px. Lab color already
     shows which pills belong together, so losing the strict grouping here
     costs nothing visually. */
  .hub-col-left { display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: center; max-width: 100%; gap: 8px; }
  .hub-row { display: contents; }
  .hub-center { margin: var(--space-5) 0; }
  .hub-pill { padding: 11px 16px; font-size: 14px; }
}

/* Method — pinned while the rocket flies, so you can't scroll past mid-flight */
.method-pin {
  position: relative;
  /* Capped for the same reason as .toggle-pin above. */
  height: min(260vh, 2400px);
}
.method {
  position: sticky;
  top: var(--nav-h);
  /* Capped for the same reason as .toggle-section below — an uncapped
     100vh - navH stretches this (content is justify-content: center)
     into a mostly-empty box on tall/unusual-ratio viewports. */
  height: min(calc(100vh - var(--nav-h)), 800px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--space-6) var(--page-x) var(--space-7);
  background: var(--purple);
  color: var(--white);
  overflow: hidden;
  /* Forces its own GPU compositor layer. Without this, a sticky element whose
     children get their inline transform/left/top rewritten every scroll frame
     (the rocket + progress ring here) can occasionally leave a stale painted
     frame behind during fast scrolling — reads as a "ghost" duplicate of the
     circle until the next full repaint catches up. */
  transform: translateZ(0);
  will-change: transform;
}
@media (max-width: 720px) {
  .toggle-pin { height: auto; }
  .toggle-section { position: relative; top: auto; height: auto; min-height: 0; display: block; }
  .toggle-inner { flex-direction: column; }
}
/* Method's mobile-fallback cutoff is wider than most (1300px, not 720px) because
   the circular loop needs real room to breathe — see .method-loop below. Below
   this it drops the scroll-pin/circle entirely for the plain stacked-cards view,
   rather than trying to squeeze a circle into a cramped tablet width. */
@media (max-width: 1299px) {
  .method-pin { height: auto; }
  .method { position: relative; top: auto; height: auto; display: block; }
}

.method h2 {
  font-size: var(--h2-size);
  max-width: 460px;
  margin-bottom: var(--space-3);
}
.method-intro {
  color: #c9c0d1;
  font-size: var(--intro-size);
  line-height: 1.6;
  max-width: 460px;
  margin: 0;
}
.method-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
@media (min-width: 1300px) {
  /* Text stays left; the loop sits to the right, not centered on the page — and
     everything here is sized to fit within one sticky viewport (.method's own
     height) with no vertical overflow, since .method clips overflow rather than
     letting the pinned section scroll internally. */
  .method-body {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-6);
  }
  .method-header { flex: 0 1 340px; }
  /* margin-right reserves room for the ms-2 card, which pokes out well past the
     ring's own right edge (anchored at the ring, then pushed further out by its
     own width + gap). Computed with calc() off the same --loop-w/--card-w custom
     properties the ring and cards use below (both vw-based clamps), so the
     reserved space always exactly matches the actual protrusion at any viewport
     width instead of a fixed px guess that only worked at one width. */
  .method-loop {
    flex: 0 0 auto;
    margin-left: auto;
    margin-right: calc(var(--card-w) + var(--card-push) - 0.14 * var(--loop-w));
    /* Clears the fixed "PROCESO" watermark (.outline-word, absolutely
       positioned at the top of .method, independent of this flow — it can't
       move). The ms-1 card is pushed further up above the ring than any
       other card (see .method-step.ms-1 below), so on short/wide viewports
       it was the one colliding with the watermark's letters. Scales with vw
       so it keeps enough clearance at wider widths, where the watermark's
       clamp() font-size is also larger. */
    margin-top: clamp(24px, 4vw, 80px);
  }
}
/* Method loop — mobile-first: plain stacked cards, no circle (simplest, safest
   on small screens). At 721px+ it becomes a real circle: the 4 cards move to
   absolute compass positions (top/right/bottom/left) around an SVG ring, and
   the rocket + progress arc fly around it in sync with scroll (JS sets the
   rocket's left/top/rotation and the progress circle's stroke-dashoffset every
   tick — see updateScrollScrubs in the script at the bottom of this file). */
.method-loop {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.method-loop-svg, .loop-dot, .method-rocket { display: none; }
.method-step {
  position: relative;
  padding: var(--space-4) var(--space-3) var(--space-3);
  border-radius: 20px;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.1);
  opacity: 0;
  transition: opacity 0.6s ease, transform 0.6s ease;
  transform: translateY(20px);
}
.method-step.in-view { opacity: 1; transform: translateY(0); }
.method-num {
  display: block;
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--lima);
  margin-bottom: var(--space-2);
}
.method-step h3 { font-size: 19px; margin-bottom: var(--space-1); }
.method-step p { margin: 0; color: #c9c0d1; font-size: 15px; }

@media (min-width: 1300px) {
  .method-loop {
    display: block;
    /* --loop-w/--card-w/--card-push drive the ring, the cards, AND the
       margin-right buffer above off the same numbers, so shrinking/growing the
       ring, or making the cards wider/narrower, automatically keeps everything
       fitting — no more re-tuning three separate hardcoded values by hand.
       Ring made smaller than before (was 420-520px) specifically to leave more
       room for wider cards within the same available width. */
    --loop-w: clamp(260px, 16vw, 300px);
    --card-w: clamp(220px, 18vw, 340px);
    --card-push: 24px;
    width: var(--loop-w);
    aspect-ratio: 1;
  }
  .method-loop-svg {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
  }
  .method-loop-track { fill: none; stroke: rgba(255,255,255,0.15); stroke-width: 1.5; }
  .method-loop-progress {
    fill: none;
    stroke: var(--lima);
    stroke-width: 2;
    stroke-linecap: round;
    /* circumference of r=32 circle (2 * PI * 32 ≈ 201.06), fully hidden at rest —
       JS dials stroke-dashoffset down from this as scroll progress advances. */
    stroke-dasharray: 201.06;
    stroke-dashoffset: 201.06;
    transform-origin: 50% 50%;
    transform: rotate(-90deg);
  }
  .loop-dot {
    display: block;
    position: absolute;
    width: 12px;
    height: 12px;
    margin: -6px;
    border-radius: 50%;
    background: rgba(220,225,87,0.25);
    transition: background 0.3s ease, transform 0.3s ease;
    z-index: 1;
  }
  .loop-dot.lit { background: var(--lima); transform: scale(1.3); }
  .loop-dot-1 { top: 18%; left: 50%; }
  .loop-dot-2 { top: 50%; left: 82%; }
  .loop-dot-3 { top: 82%; left: 50%; }
  .loop-dot-4 { top: 50%; left: 18%; }
  .method-rocket {
    display: block;
    position: absolute;
    top: 50%;
    left: 50%;
    font-size: 22px;
    line-height: 1;
    margin: -12px;
    opacity: 0;
    z-index: 2;
    transition: opacity 0.3s ease;
    /* left/top set inline by JS each scroll tick to fly it around the ring —
       CSS can't do the trig needed to move something around a circle via a
       single custom prop. Rotation is NOT set by JS: the glyph always keeps
       this fixed "sideways" heading (doesn't turn to face its direction of
       travel) as it orbits. */
    transform: translate(-50%, -50%) rotate(-45deg);
  }
  .method.in-view .method-rocket { opacity: 1; }
  .method-step {
    position: absolute;
    width: var(--card-w);
    padding: var(--space-3) var(--space-3) var(--space-2);
    opacity: 0;
    transform: none;
  }
  .method-step .method-num { font-size: 11px; margin-bottom: 4px; }
  .method-step h3 { font-size: 16px; margin-bottom: 3px; }
  .method-step p { font-size: 12px; line-height: 1.4; }
  .method-step.in-view { opacity: 1; }
  /* Anchored at the ring's dot positions (18%/50%/82%, matching .loop-dot below),
     then pushed fully outside the ring by the card's own size + a gap — not
     anchored to the container's 0%/50%/100% edges, which put the card right on
     top of the ring itself since the card is much taller than the ring's margin. */
  .method-step.ms-1 { top: 14%; left: 50%; transform: translate(-50%, calc(-100% - var(--card-push))); text-align: center; }
  .method-step.ms-2 { top: 50%; left: 86%; transform: translate(var(--card-push), -50%); }
  .method-step.ms-3 { top: 86%; left: 50%; transform: translate(-50%, var(--card-push)); text-align: center; }
  .method-step.ms-4 { top: 50%; left: 14%; transform: translate(calc(-100% - var(--card-push)), -50%); text-align: right; }
}

/* Work — horizontal scroll gallery */
.work {
  padding: var(--space-7) var(--page-x);
  background: var(--cloud);
}
.work h2 {
  font-size: var(--h2-size);
  color: var(--purple);
  margin-bottom: var(--space-2);
  max-width: 640px;
}
.work-gallery { display: flex; flex-direction: column; }
.work-visible {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}
.work-hidden {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  margin-top: 0;
  transition: max-height 0.6s ease, opacity 0.4s ease, margin-top 0.5s ease;
}
/* Desktop: a fixed single row of exactly 5 cards (4 projects + the door as the 3rd
   item) via CSS Grid — never wraps to a second line. The revealed "taller" content
   below is a normal-flow grid too, so opening it just grows the page's height. */
@media (min-width: 901px) {
  .work-visible {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    align-items: end;
  }
  /* Same 5 columns as .work-visible above — was 3, which made the (wider) columns
     produce visibly bigger photo cards than the row above once cards started
     sizing to each photo's own ratio instead of a shared fixed box. */
  .work-hidden {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
  .work-visible .work-item,
  .work-hidden .work-item { width: 100%; }
  /* Match the door's height to the photo cards in its row (which set the row's
     height via their own aspect-ratio) instead of the door's own width-driven
     clamp() — width then follows from the door art's fixed aspect-ratio. */
  .work-visible .work-door { width: auto; height: 100%; }
  .work-door { margin: 0 auto; }
}
/* Was capped at 900px, which clipped the bottom row/cards once there were enough
   items to need it (14 cards: ~5 rows at 3-col desktop, single stacked column on
   mobile) — bumped well past any realistic content height so nothing gets cut off,
   at any breakpoint or item count, instead of guessing a tight pixel value. */
.work-hidden.is-open {
  max-height: 6000px;
  opacity: 1;
  margin-top: var(--space-3);
}
/* Cards wait behind the door, then rise into place one after another once it opens */
.work-hidden .work-item {
  opacity: 0;
  transform: translateY(18px) scale(0.97);
  transition: opacity 0.45s ease, transform 0.45s ease;
}
.work-hidden.is-open .work-item { opacity: 1; transform: translateY(0) scale(1); }
.work-hidden.is-open .work-item:nth-child(1) { transition-delay: 0.05s; }
.work-hidden.is-open .work-item:nth-child(2) { transition-delay: 0.1s; }
.work-hidden.is-open .work-item:nth-child(3) { transition-delay: 0.15s; }
.work-hidden.is-open .work-item:nth-child(4) { transition-delay: 0.2s; }
.work-hidden.is-open .work-item:nth-child(5) { transition-delay: 0.25s; }
.work-hidden.is-open .work-item:nth-child(6) { transition-delay: 0.3s; }
.work-hidden.is-open .work-item:nth-child(7) { transition-delay: 0.35s; }
.work-hidden.is-open .work-item:nth-child(8) { transition-delay: 0.4s; }
.work-hidden.is-open .work-item:nth-child(9) { transition-delay: 0.45s; }
.work-hidden.is-open .work-item:nth-child(10) { transition-delay: 0.5s; }
.work-hidden.is-open .work-item:nth-child(11) { transition-delay: 0.55s; }
.work-hidden.is-open .work-item:nth-child(12) { transition-delay: 0.6s; }
.work-item {
  flex: 0 0 auto;
  width: 320px;
  border-radius: 18px;
  border: none;
  padding: 0;
  overflow: hidden;
  cursor: pointer;
  background: var(--white);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.work-item:hover { transform: translateY(-4px); }
.work-item.is-highlighted { box-shadow: 0 0 0 3px var(--lima); transform: translateY(-4px); }
/* No fixed height and no object-fit games: the card's own height comes from
   the image's intrinsic aspect ratio, so the box always matches the photo
   instead of the photo being fitted (and letterboxed) into a fixed box. */
.work-item img { width: 100%; height: auto; display: block; }

/* "Abrir el taller" door — click reveals the rest of the gallery from behind it.
   Real 3D: the leaf rotates on a fixed left-edge hinge (transform-origin), no
   translateX slide — the dark starry glow behind it is what reads as "the void",
   revealed as the rotating leaf sweeps away from covering it. */
/* Fluid at every viewport size — width scales continuously with the viewport (clamped
   between a usable minimum and the original desktop size) instead of jumping between
   fixed px values at breakpoints. aspect-ratio keeps the height in lockstep. Every
   child below is sized in cqw (% of this element's own width, via container-type)
   rather than fixed px, so the whole door — frame, leaf, hinge, logo, label, sparks —
   scales together as one proportional unit at any size, not just at 720px/901px. */
.work-door {
  position: relative;
  flex: 0 0 auto;
  container-type: inline-size;
  /* Was clamp(150px, 40vw, 232px) — 40vw blew past the 232px cap on almost any
     viewport wider than ~580px, so the door looked frozen at its max size across
     the entire desktop/tablet range and only actually shrank on small phones.
     This formula instead scales continuously from ~667px down to ~1683px viewport
     (i.e. through the whole realistic desktop/tablet range), not just at the very
     bottom of the scale. */
  width: clamp(110px, 12vw + 30px, 232px);
  aspect-ratio: 232 / 260;
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  perspective: 1500px;
}
.work-door-frame {
  position: relative;
  width: 90.5cqw;
  height: 107.76cqw;
  border-radius: 45.26cqw 45.26cqw 6.03cqw 6.03cqw;
  background: var(--purple);
  padding: 3.45cqw;
  box-shadow: 0 18px 34px rgba(56,7,87,0.32);
  transition: transform 0.2s ease, box-shadow 0.6s ease;
  /* Without this, the leaf's rotateY/translateZ below gets flattened into 2D by the
     browser before the parent's perspective ever sees it — the leaf just looked like
     it was sliding sideways instead of swinging out in 3D. */
  transform-style: preserve-3d;
}
.work-door:hover .work-door-frame { transform: translateY(-3px); }
/* Nudges the closed door every few seconds so it reads as clickable without
   being distracting — pauses on hover/open so it never fights the other
   transforms on this element. */
.work-door:not(.is-open) .work-door-frame {
  animation: workDoorWiggle 2s ease-in-out infinite;
}
.work-door:hover .work-door-frame,
.work-door:focus-visible .work-door-frame { animation-play-state: paused; }
@keyframes workDoorWiggle {
  0%, 30%, 100% { transform: rotate(0deg); }
  5% { transform: rotate(-3deg); }
  10% { transform: rotate(3deg); }
  15% { transform: rotate(-2deg); }
  20% { transform: rotate(2deg); }
  25% { transform: rotate(0deg); }
}
/* Majestic glow once open: a warm lima bloom breathing outward from the frame,
   on top of the existing drop shadow (not replacing it). */
.work-door.is-open .work-door-frame {
  animation: workDoorGlowPulse 2.6s ease-in-out 0.15s infinite;
}
@keyframes workDoorGlowPulse {
  0%, 100% {
    box-shadow:
      0 18px 34px rgba(56,7,87,0.32),
      0 0 5cqw 1.3cqw rgba(220,225,87,0.5),
      0 0 12cqw 3.5cqw rgba(220,225,87,0.22);
  }
  50% {
    box-shadow:
      0 18px 34px rgba(56,7,87,0.32),
      0 0 7cqw 2cqw rgba(220,225,87,0.75),
      0 0 16cqw 5cqw rgba(220,225,87,0.32);
  }
}
.work-door-glow {
  position: absolute;
  inset: 3.45cqw;
  border-radius: 41.81cqw 41.81cqw 3.45cqw 3.45cqw;
  /* A visible bright rim down the middle plus a lighter void tone (vs. the near-black
     used before) so the opening reads clearly against the purple frame instead of
     blending into it — the previous version was too close in value to the frame color
     to notice the leaf had rotated away at all. */
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.12);
  background:
    radial-gradient(2px 2px at 30% 20%, #fff 0, transparent 60%),
    radial-gradient(1.5px 1.5px at 55% 35%, #fff 0, transparent 60%),
    radial-gradient(2px 2px at 40% 55%, #fff 0, transparent 60%),
    radial-gradient(1.5px 1.5px at 65% 65%, #fff 0, transparent 60%),
    radial-gradient(1.5px 1.5px at 25% 70%, #fff 0, transparent 60%),
    radial-gradient(circle at 50% 60%, rgba(220,225,87,0.55), transparent 60%),
    radial-gradient(circle at 50% 25%, #4a1470, #150428 85%);
  transition: filter 0.6s ease;
}
/* The void itself glows brighter too once open, not just the outer frame bloom. */
.work-door.is-open .work-door-glow { filter: brightness(1.35) saturate(1.2); }
/* Hinge hardware fixed to the frame's right inner edge — the point the leaf actually
   pivots around (matches transform-origin below). Hidden while closed since the leaf
   sits right on top of it; fades in once open. */
.work-door-hinge {
  position: absolute;
  right: 1.29cqw;
  top: 50%;
  z-index: 2;
  width: 3.45cqw;
  height: 3.45cqw;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #5b1a86, #2a0640 70%);
  box-shadow: 0 1px 2px rgba(0,0,0,0.5);
  transform: translateY(-50%);
  opacity: 0;
  transition: opacity 0.3s ease 0.15s;
}
.work-door.is-open .work-door-hinge { opacity: 1; }
.work-door-leaf {
  position: absolute;
  inset: 3.45cqw;
  border-radius: 41.81cqw 41.81cqw 3.45cqw 3.45cqw;
  background:
    repeating-linear-gradient(90deg, rgba(56,7,87,0.1) 0 2px, transparent 2px 34px),
    linear-gradient(160deg, var(--lima), #c3c93a);
  box-shadow: inset 0 0 0 4px rgba(56,7,87,0.55);
  transform-origin: right center;
  transform: rotateY(0deg) translateZ(0);
  transition: transform 0.55s cubic-bezier(0.22, 0.8, 0.3, 1), box-shadow 0.55s ease;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 14.66cqw;
  gap: 6.03cqw;
}
/* Hinge is the right edge (transform-origin above), and it stays put — no translateZ
   here (that shifts the whole box, pivot included, before rotating). rotateY alone
   rotates purely around transform-origin, so the right edge stays pinned to the frame
   while the free (left) edge swings toward the viewer and back toward the hinge,
   revealing the arch void on the left. POSITIVE rotateY is what brings that edge
   forward with the origin on the right — negative sends it away from the viewer
   instead. */
.work-door:hover .work-door-leaf { transform: rotateY(18deg); }
.work-door.is-open .work-door-leaf {
  transform: rotateY(38deg);
  box-shadow: inset 0 0 0 4px rgba(56,7,87,0.55), -10px 14px 26px rgba(10,2,18,0.45);
}
.work-door-handle {
  position: absolute;
  left: 7.76cqw;
  top: 50%;
  width: 6.47cqw;
  height: 6.47cqw;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #5b1a86, var(--purple) 70%);
  box-shadow: 0 2px 3px rgba(0,0,0,0.35);
  transform: translateY(-50%);
}
.work-door-mark-ring {
  width: 17.24cqw;
  height: 17.24cqw;
  border-radius: 50%;
  border: 2px solid rgba(56,7,87,0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
.work-door-mark {
  width: 8.62cqw;
  height: 8.62cqw;
  opacity: 0.85;
  pointer-events: none;
}
.work-door-spark {
  position: absolute;
  color: var(--lima);
  font-size: 6.9cqw;
  opacity: 0.75;
  transition: opacity 0.3s ease, transform 0.3s ease;
  transform: scale(0.85);
}
.work-door-spark-1 { top: 1.72cqw; left: 0.86cqw; }
.work-door-spark-2 { top: 11.21cqw; right: -1.72cqw; }
.work-door-spark-3 { bottom: 14.66cqw; left: -3.45cqw; }
.work-door:hover .work-door-spark,
.work-door.is-open .work-door-spark { opacity: 1; transform: scale(1.15); }
.work-door-label {
  font-family: var(--font-display);
  font-weight: 700;
  /* Floor keeps the label legible on the smallest doors instead of shrinking forever. */
  font-size: clamp(12px, 8.62cqw, 20px);
  line-height: 1.2;
  color: var(--purple);
  text-align: center;
  text-transform: uppercase;
}
.work-door-label-close { display: none; }
.work-door.is-open .work-door-label-open { display: none; }
.work-door.is-open .work-door-label-close { display: block; }
.work-door-arrow {
  display: block;
  margin-top: 1.72cqw;
  font-size: 0.9em;
  font-weight: 400;
  text-transform: none;
}

.work-item-name {
  font-family: var(--font-display);
  font-size: 22px;
}
.work-item-tag {
  font-size: 12px;
  line-height: 1.4;
  opacity: 0.9;
}

/* Brands whose only asset is their logo (no project photo/mockup) but that
   DO have a real case study behind them (desc/work/capabilities). The logo
   sits on a white badge (guarantees contrast regardless
   of the logo's own colors) over a brand-colored gradient, instead of
   object-fit:cover-ing a small logo file, which would crop/distort it. */
.work-item-logo {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3);
  aspect-ratio: 3 / 2;
  color: var(--white);
  text-align: center;
  cursor: pointer;
}
.work-item-logo-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px 20px;
  border-radius: 12px;
  background: var(--white);
}
.work-item-logo-badge img { height: 30px; width: auto; max-width: 130px; object-fit: contain; display: block; }
.work-item-logo .work-item-name { font-size: 18px; }
.work-item-logo .work-item-tag { opacity: 0.85; }
.work-item-clinicacerebro { background: linear-gradient(160deg, #0f172a, #0ea5e9); }
.work-item-carlosravelo { background: linear-gradient(160deg, #1c1917, #a16207); }
.work-item-caminosdelavida { background: linear-gradient(160deg, #052e16, #22c55e); }
.work-item-lamarquessa { background: linear-gradient(160deg, #500724, #ec4899); }
.work-item-serninos { background: linear-gradient(160deg, #1e3a8a, #3b82f6); }
.work-item-walkmate { background: linear-gradient(160deg, #0e2f3d, #2fbad6); }

.work-brands-marquee {
  margin-top: var(--space-6);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, black 4%, black 96%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0%, black 4%, black 96%, transparent 100%);
}
.work-brands-track {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  width: max-content;
  /* Never pauses — logos aren't clickable/inspectable anymore, so there's no
     reason to stop the scroll on hover like some other marquees on the site
     do. */
  animation: scrollLeftWorkBrands 34s linear infinite;
}
@keyframes scrollLeftWorkBrands {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* Was max-width: 720px, leaving a 721-900px gap where neither this nor the
   min-width:901px grid rule applied — cards fell back to the base 320px
   width in a plain flex-wrap, so shrinking the window into that gap made
   cards look bigger, not smaller. 900px closes the gap exactly at the grid's
   own breakpoint. */
@media (max-width: 900px) {
  .work-item { width: 240px; }
  .work-visible, .work-hidden { justify-content: center; }
  /* .work-door is fluid via clamp()/cqw now — no fixed-size override needed here. */
}

/* Case-study modal */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background: rgba(10,7,13,0.9);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.2s ease, visibility 0s linear 0.2s;
}
.lightbox.is-open { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity 0.2s ease, visibility 0s linear 0s; }
.lightbox-inner {
  position: relative;
  width: min(1100px, 100%);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  background: var(--ink);
  border-radius: 20px;
  /* Was a single overflow:hidden — fine when the fixed-height collage
     (2 rows, never shrinks) plus the caption always fit under 90vh, but a
     project with multiple capability groups (see .lightbox-lab-group)
     makes the caption taller, and the total can exceed 90vh. Hidden
     silently cropped whatever didn't fit (e.g. the tail end of the Work
     text) instead of showing it — auto on the y-axis lets it scroll
     instead; x stays hidden so the rounded corners still clip normally. */
  overflow-x: hidden;
  overflow-y: auto;
}
/* Automatic Editorial Horizontal Collage System — generic, reusable, no
   per-project knowledge. Given any set of images it builds an asymmetric
   2-row strip sized from each image's own aspect ratio (ProjectCollage.render
   in the script at the bottom of this file does the measuring/placement;
   this just defines the grid + row-height/gap tokens it reads). Exactly 2
   rows always (grid-template-rows), columns grow as needed (grid-auto-flow:
   column dense lets the browser's own packer fill 1-row gaps with the next
   fitting item instead of us hand-placing anything), and overflow-x:auto
   instead of ever shrinking images to fit. */
.project-collage-wrap {
  position: relative;
  /* Must match .project-collage's own flex:0 0 auto exactly — the collage
     inside is a fixed, non-shrinking 2-row height (see .project-collage).
     This wrap used to be allowed to shrink (flex:1 1 auto), which let a
     tall caption squeeze it smaller than its non-shrinking child, and the
     child then visually overflowed past the wrap's own bottom edge,
     overlapping/covering the top of the caption panel below it. */
  flex: 0 0 auto;
  display: flex;
}
.project-collage {
  --pc-row-h: 150px;
  --pc-gap: 16px;
  --pc-radius: 14px;
  /* Grid used to reserve exactly 2 rows via grid-template-rows, which
     the flex parent (.project-collage-wrap) always deferred to. Flex has
     no equivalent auto-height-from-rows mechanism, so without an explicit
     height here the flex parent could allocate less than 2 rows' worth
     (e.g. squeezed by the caption panel below), and overflow-y:hidden
     silently cropped the second row instead of showing it — height +
     flex-shrink:0 pins it to exactly 2 rows tall, same as the grid did. */
  /* 2 rows + the gap between them + the container's own top/bottom
     padding (box-sizing: border-box means padding eats into `height`,
     not added on top of it — without the extra +2×gap here the content
     area came up 32px short and the second row got clipped again). */
  height: calc(var(--pc-row-h) * 2 + var(--pc-gap) * 3);
  flex: 0 0 auto;
  min-width: 0;
  /* Was CSS Grid (grid-auto-flow: column dense) with grid-auto-columns:
     max-content — but a grid column's track width is the MAX of every
     item dense-packed into it, so a narrow item sharing a column with a
     wide one (e.g. a wide wordmark logo above a narrower photo) rendered
     inside a too-wide track, leaving a visible empty gap of background
     to its side. Flex row of manually-built .pc-col column wrappers
     (each sized to its own 1-2 items only, see ProjectCollage.render's
     column-grouping pass) has no shared track, so no such gap is
     possible. */
  display: flex;
  gap: var(--pc-gap);
  overflow-x: auto;
  overflow-y: hidden;
  background: var(--ink);
  padding: var(--pc-gap);
  /* Scrollbar hidden — hovering near an edge auto-scrolls that direction
     (see the mousemove handler in index.html), and the pc-nav arrow buttons
     are the click-driven option, so there's no visible scrollbar track.
     Still a native scroll container underneath (touch/trackpad scroll and
     keyboard still work), just undecorated. */
  scrollbar-width: none;
}
.project-collage::-webkit-scrollbar { display: none; }
/* Shown for the brief moment between clicking a project and its images
   finishing their fetch — without this the previous project's collage just
   sits there frozen while the next one loads, which reads as the UI being
   stuck rather than switching. */
.project-collage.is-loading::after {
  content: '';
  grid-row: 1 / -1;
  grid-column: 1;
  width: 40px;
  align-self: center;
  aspect-ratio: 1;
  border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, 0.25);
  border-top-color: #fff;
  animation: pc-spin 0.8s linear infinite;
}
@keyframes pc-spin { to { transform: rotate(360deg); } }
/* Column wrapper built in JS — holds either one .pc-span2 item alone or
   two regular items stacked. Sized to its own content only (flex, not a
   shared grid track), so it can never be forced wider than what's
   actually inside it. */
.pc-col {
  display: flex;
  flex-direction: column;
  flex: none;
  gap: var(--pc-gap);
}
.pc-item {
  flex: none;
  border-radius: var(--pc-radius);
  overflow: hidden;
  background: #000;
}
/* Never crop — width is set inline per-image (computed from its real aspect
   ratio at the row height above), height simply fills its row(s). No
   object-fit:cover anywhere; the box IS the image's own proportions. */
.pc-item img { display: block; height: 100%; width: 100%; border-radius: inherit; }
/* Slow, subtle Ken Burns drift on real photos only — a static grid of
   thumbnails reads as inert, this keeps the collage feeling alive without
   being distracting. Excluded on logo/type tiles (below), where a zooming
   mark would just look like it's cropping in and out. */
.pc-item:not(.pc-item-logo) img {
  animation: pcKenBurns 16s ease-in-out infinite alternate;
}
.pc-item:nth-child(3n+1) img { animation-delay: -2s; }
.pc-item:nth-child(3n+2) img { animation-delay: -7s; }
.pc-item:nth-child(3n+3) img { animation-delay: -12s; }
@keyframes pcKenBurns {
  from { transform: scale(1); }
  to { transform: scale(1.08); }
}
@media (prefers-reduced-motion: reduce) {
  .pc-item img { animation: none; }
}
/* Logo/icon marks: a padded card instead of an edge-to-edge photo crop, so
   the mark has breathing room and reads clearly against its own transparent
   canvas — matches how logos are presented everywhere else on the site. */
.pc-item-logo {
  background: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 14%;
  box-sizing: border-box;
}
.pc-item-logo img { width: 100%; height: 100%; object-fit: contain; animation: none; }
/* Kinetic type specimen (replaces the old static "Aa123" screenshot): the
   same two brand colors as the original swatch, now animated — the split
   drifts side to side and each line breathes at its own pace so it doesn't
   look like a frozen product shot. */
.pc-item-type {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--pc-c1) 50%, var(--pc-c2) 50%);
  background-size: 220% 220%;
  animation: pcTypeSlide 6s ease-in-out infinite;
  overflow: hidden;
}
/* Alternates horizontal, vertical, and diagonal sweeps — each phase holds
   briefly at its endpoint so the three read as distinct moves, not one
   continuous blur. */
/* Both lines stack in the same spot and take turns being visible — "Aa",
   then "123", then back — instead of sitting side by side at once. */
.pc-type-line {
  position: absolute;
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--white);
  line-height: 1;
  font-size: calc(var(--pc-row-h, 190px) * 0.3);
  text-shadow: 0 2px 12px rgba(0,0,0,0.25);
  opacity: 0;
  animation: pcTypeCycle 4s ease-in-out infinite;
}
.pc-type-line:last-child { animation-delay: -2s; }
@keyframes pcTypeSlide {
  0%, 5%   { background-position: 0% 50%; }    /* start: left-mid */
  28%, 33% { background-position: 100% 50%; }  /* horizontal (y constant) */
  56%, 61% { background-position: 100% 0%; }   /* vertical (x constant) */
  84%, 89% { background-position: 0% 100%; }   /* diagonal (both change) */
  100%     { background-position: 0% 50%; }    /* back to start */
}
@keyframes pcTypeCycle {
  0%, 4% { opacity: 0; transform: scale(0.85); }
  12%, 38% { opacity: 1; transform: scale(1); }
  46%, 100% { opacity: 0; transform: scale(0.85); }
}
@media (prefers-reduced-motion: reduce) {
  .pc-item-type, .pc-type-line { animation: none; }
}
/* Pattern card: the brand's own seamless print pattern, tiled and
   scrolling sideways forever — upright the whole time (no rotation, so
   it stays recognizable as the actual pattern, not a blur of noise)
   with the loop distance set to exactly one tile width so there's
   never a visible seam or jump. */
.pc-item-pattern {
  position: relative;
  overflow: hidden;
}
.pc-pattern-scroll {
  position: absolute;
  top: 0;
  /* Buffer tile sits on the left now (not the right) so there's always
     off-screen pattern ready to enter from the left edge as it scrolls
     rightward. */
  left: calc(-1 * var(--pattern-tile-w, 40px));
  width: calc(100% + var(--pattern-tile-w, 40px));
  height: 100%;
  background-repeat: repeat;
  animation: pcPatternScroll 14s linear infinite;
}
@keyframes pcPatternScroll {
  from { transform: translateX(0); }
  to { transform: translateX(var(--pattern-tile-w, 40px)); }
}
@media (prefers-reduced-motion: reduce) {
  .pc-pattern-scroll { animation: none; }
}
/* Tagline card: the project's own hand-designed tagline graphic
   (design-system/portfolio/<slug>/tagline.png), 3 copies visible at once
   with generous spacing between them, looping sideways forever — same
   duplicated-track, translateX(-50%) technique as the pattern/palette
   tiles, just with a group of 3 (not 1) as the repeat unit. Each image's
   own spacing margin is set inline per-piece in JS (scaled off the
   collage's --pc-gap), not fixed here. */
.pc-item-tagline-img {
  position: relative;
  overflow: hidden;
}
.pc-tagline-scroll {
  position: absolute;
  /* Nudged down from the card's top edge so the art doesn't butt right
     up against it — free to run past the bottom edge instead, hidden by
     this card's own overflow: hidden. */
  top: 8%;
  left: 0;
  display: flex;
  flex-direction: row;
  align-items: stretch;
  height: 100%;
  animation: pcTaglineScroll 18s linear infinite;
}
/* Two classes so this beats the generic ".pc-item img { width: 100% }"
   rule (higher specificity than a class+element selector) — without it
   the image stretched to fill the flex item's auto width instead of
   keeping its own aspect ratio. */
.pc-tagline-scroll .pc-tagline-scroll-img {
  flex: 0 0 auto;
  height: 100%;
  width: auto;
  display: block;
}
@keyframes pcTaglineScroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .pc-tagline-scroll { animation: none; }
}
/* Several small vertical strips side by side in one card, each an endless
   scrolling loop (same duplicated-track technique as the hero marquee) at
   its own speed/direction — not one single wide column. */
.pc-item-palette {
  position: relative;
  height: 100%;
  display: flex;
  gap: 14px;
}
.pc-palette-col {
  flex: 0.85 1 0;
  height: 100%;
  overflow: hidden;
  position: relative;
}
/* Middle column wider than the two flanking it — since each chip is sized
   off its own column's width, a wider column also means bigger chips,
   giving the offset/staggered look instead of three equal strips. */
.pc-palette-col:nth-child(2) { flex: 1.6 1 0; }
.pc-palette-track {
  height: 200%;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 14px;
  animation: scrollUp 16s linear infinite;
}
/* Height comes from the card (a fixed share of the track), not from the
   column's own width — so side and middle chips are equally tall rectangles,
   just narrower or wider, instead of the thin side columns also going short. */
.pc-palette-chip {
  flex: 0 0 36%;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;
  gap: 0.3em;
  /* Horizontal padding is a fixed amount (off the card's own row height),
     not a % of each column's width — otherwise the narrower flanking
     columns would sit closer to their edge than the wider middle one. */
  padding: 8% calc(var(--pc-row-h, 190px) * 0.05);
  box-sizing: border-box;
  overflow: hidden;
  text-align: left;
  border-radius: calc(var(--pc-radius, 14px) * 0.5);
}
/* Flanking columns: label at the top instead of the bottom, and allowed to
   spill past the chip's own (narrow) edges instead of being clipped — only
   the middle column's text has to stay strictly inside its chip. */
.pc-palette-chip-top {
  justify-content: flex-start;
  padding-top: 16%;
  overflow: visible;
}
.pc-palette-chip-top .pc-swatch-title {
  max-width: none;
  white-space: nowrap;
  font-size: calc(var(--pc-row-h, 190px) * 0.06);
}
@media (prefers-reduced-motion: reduce) {
  .pc-palette-track { animation: none; }
}
/* Large color name, then the same name again in small caps, then the hex —
   same hierarchy as a paint-chip label. */
.pc-swatch-title {
  font-family: var(--font-display);
  font-size: calc(var(--pc-row-h, 190px) * 0.09);
  font-weight: 600;
  line-height: 1.05;
  max-width: 100%;
  word-break: normal;
  overflow-wrap: normal;
}
/* Middle column's chip is the only one that must never overflow or crop a
   word — smaller type so its (possibly multi-word) name always wraps
   cleanly at a space and fits within the chip's own bounds. */
.pc-palette-chip:not(.pc-palette-chip-top) .pc-swatch-title {
  font-size: calc(var(--pc-row-h, 190px) * 0.06);
  line-height: 1.15;
}
.pc-swatch-hex {
  font-family: var(--font-mono, monospace);
  font-size: calc(var(--pc-row-h, 190px) * 0.045);
  font-weight: 500;
  letter-spacing: 0.02em;
  opacity: 0.75;
}
.pc-nav {
  position: absolute;
  top: 50%;
  z-index: 3;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: none;
  background: var(--lima);
  color: var(--purple);
  font-size: 18px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 6px 16px rgba(0,0,0,0.35);
  opacity: 0.95;
  transition: opacity 0.15s ease, transform 0.15s ease;
}
.pc-nav:hover { opacity: 1; transform: translateY(-50%) scale(1.06); }
.pc-nav-prev { left: 16px; transform: translateY(-50%); }
.pc-nav-prev:hover { transform: translateY(-50%) scale(1.06); }
.pc-nav-next { right: 16px; transform: translateY(-50%); }
.pc-nav-next:hover { transform: translateY(-50%) scale(1.06); }
/* Hidden entirely once there's nowhere left to scroll that direction —
   JS toggles this via .is-hidden rather than unmounting the buttons. */
.pc-nav.is-hidden { display: none; }
@media (max-width: 720px) {
  .pc-nav { width: 38px; height: 38px; font-size: 15px; }
  .pc-nav-prev { left: 8px; }
  .pc-nav-next { right: 8px; }
}
@media (max-width: 720px) {
  .project-collage { --pc-row-h: 130px; --pc-gap: 10px; --pc-radius: 10px; }
}
.lightbox-caption {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: 1.2fr 1fr 1fr;
  align-items: start;
  gap: var(--space-5);
  padding: var(--space-4) var(--space-5);
  background: var(--purple);
  color: var(--white);
}
.lightbox-caption-col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  min-width: 0;
}
.lightbox-caption-main { display: flex; flex-direction: column; gap: 4px; }
.lightbox-caption h3 {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-weight: 400;
  font-size: 26px;
  margin: 0 0 4px;
}
.lightbox-category {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #a89fb3;
}
.lightbox-desc {
  margin: 0;
  color: #cfc7d6;
  font-size: 15px;
}
.lightbox-label {
  margin: 0 0 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--lima);
}
.lightbox-work {
  margin: 0;
  color: #cfc7d6;
  font-size: 14px;
  line-height: 1.5;
}
.lightbox-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
/* Spacing between stacked lab-groups already comes from the parent
   .lightbox-caption-col's own `gap` — no extra margin needed here. */
.lightbox-tag {
  padding: 6px 14px;
  border-radius: 999px;
  border: none;
  background: rgba(255,255,255,0.16);
  color: var(--white);
  font-size: 12px;
  white-space: nowrap;
}
.lightbox-close {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  z-index: 2;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: none;
  background: var(--white);
  color: var(--purple);
  font-size: 16px;
  cursor: pointer;
  box-shadow: 0 4px 12px rgba(0,0,0,0.35);
}

@media (max-width: 640px) {
  .lightbox-caption { grid-template-columns: 1fr; }
}

/* Project form modal */
.project-modal {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background: rgba(26,19,32,0.82);
  backdrop-filter: blur(4px);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.25s ease, visibility 0s linear 0.25s;
}
.project-modal.is-open { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity 0.25s ease, visibility 0s linear 0s; }
.project-modal-inner {
  position: relative;
  width: min(640px, 100%);
  max-height: 88vh;
  overflow-y: auto;
  background: var(--cloud);
  border-radius: 20px;
  padding: var(--space-6) var(--space-5);
  transform: translateY(16px) scale(0.98);
  transition: transform 0.25s ease;
}
.project-modal.is-open .project-modal-inner { transform: translateY(0) scale(1); }
.project-modal-close {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid rgba(56,7,87,0.25);
  background: var(--white);
  color: var(--purple);
  font-size: 16px;
  cursor: pointer;
}
.project-modal-title {
  font-family: var(--font-display);
  font-size: clamp(24px, 4vw, 32px);
  color: var(--ink);
  text-align: center;
  margin: 0 0 var(--space-5);
}
.project-modal-title em {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-weight: 400;
  color: var(--purple);
}
.project-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3) var(--space-3);
}
.project-field-full { grid-column: 1 / -1; }
.project-field { display: flex; flex-direction: column; gap: 6px; }
.project-field label {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: #6b6478;
}
.project-field input,
.project-field select,
.project-field textarea {
  font-family: var(--font-body);
  font-size: 15px;
  padding: 12px 16px;
  border-radius: 999px;
  border: 1.5px solid rgba(56,7,87,0.25);
  background: var(--white);
  color: var(--ink);
}
.project-field textarea {
  border-radius: 18px;
  resize: vertical;
  font-family: var(--font-body);
}
.project-field input:focus,
.project-field select:focus,
.project-field textarea:focus {
  outline: none;
  border-color: var(--purple);
}
.project-submit {
  grid-column: 1 / -1;
  justify-self: end;
  margin-top: var(--space-2);
}
.project-form-thanks {
  display: none;
  text-align: center;
  padding: var(--space-5) 0;
  font-size: 18px;
  color: var(--purple);
}
.project-form-thanks.is-visible { display: block; }

/* Honeypot: visually hidden and unreachable by keyboard/screen readers, but present in the DOM
   (never display:none — some bots skip fields that are display:none and fill everything else). */
.project-field-hp {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.project-field.has-error input,
.project-field.has-error select,
.project-field.has-error textarea {
  border-color: #c0392b;
}
.project-field-error {
  display: none;
  font-family: var(--font-body);
  font-size: 12px;
  color: #c0392b;
}
.project-field.has-error .project-field-error { display: block; }

.project-form-error {
  display: none;
  grid-column: 1 / -1;
  font-family: var(--font-body);
  font-size: 14px;
  color: #c0392b;
  text-align: center;
  margin: 0;
}
.project-form-error.is-visible { display: block; }

.project-submit[disabled] { opacity: 0.65; cursor: not-allowed; }

@media (max-width: 560px) {
  .project-form { grid-template-columns: 1fr; }
  .project-submit { justify-self: stretch; }
}

.client-logo {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 110px;
  height: 40px;
  background: transparent;
  border: none;
  padding: 0;
  opacity: 0.75;
  filter: grayscale(1);
  transition: opacity 0.2s ease, filter 0.2s ease;
}
.client-logo:hover, .client-logo.is-highlighted { opacity: 1; filter: grayscale(0); }
.client-logo img {
  height: 100%;
  width: auto;
  max-width: 100%;
  object-fit: contain;
}

/* Contact */
.contact {
  position: relative;
  min-height: clamp(480px, 60vh, 640px);
  padding: var(--space-4) var(--page-x) var(--space-7);
  background: var(--cloud);
  text-align: center;
  overflow: hidden;
}
.closer-line {
  position: relative;
  z-index: 2;
  font-family: var(--font-display);
  font-size: clamp(30px, 6vw, 54px);
  color: var(--purple);
  margin: 0 0 var(--space-2);
  line-height: 1.2;
  letter-spacing: 0.01em;
  font-kerning: none;
  font-feature-settings: "kern" 0, "liga" 0;
}
.closer-line em {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-weight: 400;
  color: var(--magenta);
}
.contact .essence-lead { position: relative; z-index: 2; margin: 0 auto var(--space-4); color: #4a3f52; }
.contact-links {
  position: relative;
  z-index: 2;
  display: flex;
  gap: var(--space-2);
  justify-content: center;
  flex-wrap: wrap;
}
.contact-pill {
  padding: 14px 26px;
  border-radius: 999px;
  background: var(--white);
  border: 2px solid var(--purple);
  color: var(--purple);
  font-weight: 700;
  font-size: 15px;
  transition: background 0.15s ease, color 0.15s ease;
}
.contact-pill:hover { background: var(--purple); color: var(--white); }
.contact-pill-primary { background: var(--purple); color: var(--white); }
.contact-pill-primary:hover { background: var(--lima); color: var(--purple); border-color: var(--lima); }

/* Falling icons playground — integrated into the contact section itself, not a separate box */
.icon-playground {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.falling-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: auto;
  touch-action: none;
  cursor: grab;
}
.falling-canvas:active { cursor: grabbing; }

/* Footer */
.footer {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--space-6) var(--page-x) var(--space-3);
  background: var(--purple);
  color: var(--cloud);
  font-size: 13px;
  gap: var(--space-2);
  text-align: center;
}
.footer-logo {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--white);
}
.footer-quote {
  font-family: 'Playfair Display', serif;
  font-style: italic;
  font-size: clamp(16px, 2.4vw, 22px);
  color: var(--lima);
  max-width: 560px;
  margin: var(--space-2) 0;
}
.footer-socials {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
  justify-content: center;
}
.footer-socials a {
  display: inline-flex;
  align-items: center;
  padding: 12px 4px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--cloud);
  transition: color 0.15s ease;
}
.footer-socials a:hover { color: var(--lima); }

@media (max-width: 720px) {
  /* More generous, editorial-feeling hero on mobile: bigger top gap under
     the nav, more room between eyebrow/h1/sub before the CTA, and a single
     dominant full-width primary pill with the secondary action demoted to
     a plain text link underneath instead of a second competing button —
     matches the reference the client pointed to (one confident CTA, not
     two pills fighting for attention). */
  .hero { padding: calc(var(--space-7) + var(--nav-h)) var(--page-x) 72px; }
  /* Reference headline dominates the screen (~85% of line width, tight
     leading) — our clamp's mobile floor (28px, sized for a much wider
     two-line desktop layout) reads as timid at 375-430px by comparison. */
  .hero h1 { font-size: clamp(36px, 11vw, 50px); line-height: 1.08; }
  .hero-sub { margin-bottom: var(--space-4); }
  .hero-cta { flex-direction: column; align-items: center; gap: var(--space-3); }
  .hero-cta .btn-primary { width: 100%; max-width: 400px; padding: 18px 24px; font-size: 16px; }
  .hero-cta .btn-outline {
    flex: 0 0 auto;
    width: auto;
    padding: 4px 8px;
    border: none;
    background: none;
    font-size: 14px;
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 3px;
  }
  .hero-cta .btn-outline:hover { background: none; opacity: 0.8; }
  .services, .contact, .work { padding: var(--space-6) var(--page-x); }
  .labs { padding: var(--space-6) 0 0; }
  /* give the falling-icons playground more room to actually play with on a phone screen */
  .contact { min-height: clamp(560px, 78vh, 760px); }
}

/* ------------------------------------------------------------------
   Servicios page (servicios.html) — standalone SEO landing, shares the
   nav/footer/contact/project-modal styles above but needs its own
   hero/category-grid/FAQ treatment. Prefixed .svc- so it can't collide
   with any existing selector (this stylesheet is shared with index.html).
   ------------------------------------------------------------------ */
.svc-hero {
  padding: calc(var(--nav-h) + var(--space-6)) var(--page-x) var(--space-5);
  text-align: center;
  max-width: 900px;
  margin: 0 auto;
}
.svc-hero h1 {
  font-family: var(--font-display);
  font-size: clamp(32px, 5.5vw, 56px);
  color: var(--purple);
  line-height: 1.15;
  margin: var(--space-2) 0 var(--space-2);
}
.svc-hero-sub {
  font-size: clamp(16px, 2vw, 19px);
  color: var(--ink);
  opacity: 0.75;
  max-width: 620px;
  margin: 0 auto var(--space-4);
  line-height: 1.6;
}
.svc-hero .hero-cta { justify-content: center; }

.svc-jump {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2) var(--space-3);
  padding: 0 var(--page-x) var(--space-5);
  max-width: 1100px;
  margin: 0 auto;
}
.svc-jump a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ink);
  padding: 8px 14px;
  border: 1px solid rgba(26,19,32,0.15);
  border-radius: 999px;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.svc-jump a:hover { border-color: var(--purple); transform: translateY(-1px); }
.svc-jump-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
}

.svc-category {
  padding: var(--space-6) var(--page-x);
  border-top: 1px solid rgba(26,19,32,0.08);
}
.svc-cat-head {
  max-width: 720px;
  margin: 0 auto var(--space-4);
  text-align: center;
}
.svc-cat-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--purple);
  margin: 0 0 var(--space-2);
}
.svc-cat-head h2 {
  font-family: var(--font-display);
  font-size: var(--h2-size);
  color: var(--purple);
  margin: 0 0 var(--space-2);
}
.svc-cat-head p {
  font-size: var(--intro-size);
  line-height: 1.6;
  color: var(--ink);
  opacity: 0.75;
  margin: 0;
}
.svc-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space-2);
  max-width: 1100px;
  margin: 0 auto;
}
.svc-card {
  padding: var(--space-3);
  border-radius: 14px;
  background: var(--cloud);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.svc-card:hover { transform: translateY(-2px); box-shadow: 0 12px 28px rgba(26,19,32,0.1); }
.svc-card h3 {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 16px;
  color: var(--purple);
  margin: 0 0 6px;
}
.svc-card p {
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  opacity: 0.75;
  margin: 0;
}

.svc-faq {
  padding: var(--space-6) var(--page-x);
  max-width: 780px;
  margin: 0 auto;
  text-align: center;
}
.svc-faq h2 {
  font-family: var(--font-display);
  font-size: var(--h2-size);
  color: var(--purple);
  margin: var(--space-2) 0 var(--space-4);
}
.svc-faq-list { text-align: left; }
.svc-faq-item {
  border-bottom: 1px solid rgba(26,19,32,0.12);
}
.svc-faq-q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-2) 4px;
  background: none;
  border: none;
  text-align: left;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 16px;
  color: var(--ink);
  cursor: pointer;
}
.svc-faq-icon {
  flex: none;
  font-size: 20px;
  color: var(--purple);
  transition: transform 0.2s ease;
}
.svc-faq-item.is-open .svc-faq-icon { transform: rotate(45deg); }
.svc-faq-a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.25s ease;
}
.svc-faq-item.is-open .svc-faq-a { grid-template-rows: 1fr; }
.svc-faq-a p {
  overflow: hidden;
  margin: 0 0 var(--space-2);
  padding: 0 4px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--ink);
  opacity: 0.75;
}
.svc-faq-a > p { min-height: 0; }
.svc-faq-a { overflow: hidden; }

.svc-contact {
  padding: var(--space-6) var(--page-x) var(--space-7);
  background: var(--cloud);
  text-align: center;
}

@media (max-width: 720px) {
  .svc-jump { display: none; }
  .svc-category { padding: var(--space-5) var(--page-x); }
  .svc-hero { padding: calc(var(--space-5) + var(--nav-h)) var(--page-x) var(--space-4); }
  .svc-faq { padding: var(--space-5) var(--page-x); }
  .svc-contact { padding: var(--space-5) var(--page-x) var(--space-6); }
}

/* ------------------------------------------------------------------
   Portafolio page (portafolio.html) — reuses .svc-hero/.svc-contact
   (shared with servicios.html) and .work-item (shared with index.html's
   #trabajo section) for the cards themselves; only the grid container
   that lays all of them out at once (no door-reveal, unlike the home
   page's condensed teaser) is page-specific.
   ------------------------------------------------------------------ */
.pf-grid-section {
  padding: 0 var(--page-x) var(--space-7);
}
.pf-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--space-3);
  max-width: 1400px;
  margin: 0 auto;
}
.pf-grid .work-item { width: 100%; }

@media (max-width: 720px) {
  .pf-grid-section { padding: 0 var(--page-x) var(--space-6); }
  .pf-grid { grid-template-columns: 1fr; gap: var(--space-2); }
}
