/* ===========================================================================
   KOREE: brand gradient system
   ---------------------------------------------------------------------------
   The identity is the six-stop gradient from the Koree logo (koreeGradNav):

     #2e9bf0 0% · #7c5cf7 22% · #b95bc4 45% · #e56a6a 65% · #fb7134 82% · #fdb44b 100%

   Used with restraint: the logo mark, the highlighted phrase of the hero
   headline, the primary CTA, the selected work tab, the phase timeline, and
   as the SOURCE of one accent per section, pulled from different stops so the
   page reads as one spectrum. Not on every card, border and heading.

   CONTRAST, measured, not assumed. Worst case across #ffffff / #f8faff /
   #fcf8f4. Every raw stop fails as small text, and every raw stop fails
   white-on-fill, so:

     stop        as text          white on it     ink (#0f172a) on it
     #2e9bf0     2.81  FAIL       2.97  FAIL      6.13  PASS
     #7c5cf7     4.20  large only 4.44  FAIL      -
     #b95bc4     3.71  large only 3.92  FAIL      -
     #e56a6a     3.01  large only 3.18  FAIL      -
     #fb7134     2.64  FAIL       2.79  FAIL      -
     #fdb44b     1.68  FAIL       1.78  FAIL     10.04  PASS

   ### TWO KNOWN AA EXCEPTIONS, BY CLIENT DECISION #########################
   These are NOT oversights and they are NOT to be "fixed" silently. The
   client asked for the light blue and the light band, was shown the numbers,
   and chose them anyway. Both are white small text needing 4.5:

     .btn-primary label on --blue-cta #0093d4        3.43   (needs 4.5)
     .stat-label on the band, 4 labels               3.33 to 3.64

   Everything else on the page passes. If they are ever to be brought up to
   AA, there are exactly two levers per case and no others:
     a) make the text LARGE (>=18.66px at weight 700), which drops the bar to
        3.0 and both then pass as they are; or
     b) darken the colour: #007cb3 for the button (4.63), and
        #0076ab / #893dff / #d43100 for the band (4.95 to 5.03).
   Both were built and both were rejected as too dark or too heavy. Do not
   re-derive this; it has been round-tripped several times.
   ########################################################################

   Consequences, deliberate:
   - Buttons are NOT the gradient. They are solid --blue-cta #0093d4, the same
     sky as the stats band, with a white label. See the exception block above.
   - The selected work tab still carries the FULL gradient, and there the label
     is NEAR-BLACK, never white: 6.13 at the blue end. A white label directly
     on an unmodified stop is a real failure and must not be reinstated.
   - The HERO and the STATS BAND do not use this six-stop gradient at all.
     They use the reference build's three-stop sky/violet/coral sweep
     (--band-gradient, --hero-text-gradient), restored from 440a62d. This
     gradient ends in amber #fdb44b, where white is 1.78; the three-stop sweep
     ends at coral, which is far kinder to white type.
   - There is NO dark overlay anywhere on the band any more. Veiling a gradient
     with black is what greys it out: it drops luminance by mixing every hue
     with grey, so the colour dies before the text becomes legible. The band
     stops are instead taken deeper AND fully saturated, which lowers luminance
     while RAISING chroma. Same trick applies anywhere else this comes up.
   - Anything painted over a gradient or a blurred glow CANNOT be checked by
     reading computed styles: the ancestor has no backgroundColor, so a naive
     audit falls through to white and reports a confident pass. The hero and
     the band are measured from RENDERED PIXELS. See both blocks.
   - Small text uses per-stop ink variants (--ink-*), each >= 4.70 worst case.
   - The .text-gradient headline is large display type, so its bar is 3.0; its
     stops are darkened just enough to clear it (worst 3.21).
   - Raw stops are for fills, glows, grid and borders only.

   Note the audit blind spot: background-clip:text makes the computed colour
   `transparent`, so an automated colour audit silently SKIPS .text-gradient
   and anything else painted that way. Those are measured by hand.

   TYPE  Raleway 300-800 display · Inter 300-700 body · IBM Plex Mono for
         numbers, eyebrows, tags and the technology ticker.
   ========================================================================= */

:root{
  /* raw brand stops: decorative only, never small text */
  --g1:#2e9bf0; --g2:#7c5cf7; --g3:#b95bc4; --g4:#e56a6a; --g5:#fb7134; --g6:#fdb44b;
  --brand-gradient:linear-gradient(100deg,var(--g1) 0%,var(--g2) 22%,var(--g3) 45%,var(--g4) 65%,var(--g5) 82%,var(--g6) 100%);
  /* darkened for large display text (bar 3.0, worst 3.21) */
  --text-gradient:linear-gradient(100deg,#2a90df 0%,#7c5cf7 22%,#b95bc4 45%,#de6666 65%,#e1652e 82%,#b68136 100%);

  /* the six inks as a gradient, safe as SMALL text on white (4.97 to 5.10).
     Used for the selected work tab's lettering. */
  --ink-gradient:linear-gradient(100deg,#2274b4 0%,#7355e5 22%,#a04faa 45%,#b25252 65%,#b45125 82%,#90662a 100%);

  /* per-stop inks, safe for small text (>= 4.70 worst case) */
  --ink-blue:#2274b4; --ink-violet:#7355e5; --ink-magenta:#a04faa;
  --ink-red:#b25252;  --ink-orange:#b45125; --ink-amber:#90662a;

  /* solid CTA blue: the band's sky hue (199, 100%) taken to the lightest step
     that carries WHITE small text, 4.63. The band's own #0093d4 is 3.43 and
     only worked while button labels were 19.2px bold. */
  --blue-cta:#0093d4; --blue-cta-dark:#0084c0;

  /* Reference-build (440a62d) hues, restored for the hero and the stats band.
     --coral is a BORDER and a dot, never small text; --coral-ink is its
     text-safe form (4.53 on the hero wash, where the raw coral is 2.44). */
  --coral:#ff6a3d; --coral-ink:#a4361e; --violet-ref:#7c3aed;
  --sky-ref:#0ea5e9; --violet-deep:#6d28d9;
  /* Band stops: the SAME three hues, taken deeper and fully saturated instead
     of being covered by a black veil. Mixing with black is what greys a colour
     out; dropping lightness while pushing chroma up keeps it vivid. */
  --band-sky:#0093d4; --band-violet:#9d5eff; --band-coral:#ff470f;
  --band-gradient:linear-gradient(110deg,var(--band-sky) 0%,var(--band-violet) 55%,var(--band-coral) 100%);
  /* the same three stops darkened just enough for LARGE display text (bar 3.0) */
  --hero-text-gradient:linear-gradient(120deg,#0a7cae 0%,#7c3aed 55%,#e35a24 100%);
  /* lightest grey that clears 4.5 on the hero wash; the reference used
     #94a3b8, which measures 2.20 there */
  --text-quiet:#465468;

  --bg-white:#ffffff; --bg-light:#f8faff; --bg-cream:#fcf8f4;
  --bg-dark:#0d1528;  --bg-deepest:#060c1a;

  --text-main:#0f172a; --text-body:#475569; --text-muted:#5B6577;
  --text-inv:#e2e8f0;  --text-inv-dim:#a8b3c4;

  --border:#e2e8f0; --border-strong:#cbd5e1; --border-dark:rgba(255,255,255,.10);

  --display:'Raleway',system-ui,sans-serif;
  --sans:'Inter',system-ui,-apple-system,sans-serif;
  --mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace;

  --wrap:75rem; --gut:clamp(1.25rem,4vw,3rem); --sec-y:clamp(4rem,8vw,7rem);
  --r:14px; --r-lg:20px;
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}

body{
  margin:0;background:var(--bg-white);color:var(--text-body);
  font-family:var(--sans);font-size:clamp(1rem,.96rem + .2vw,1.0625rem);
  line-height:1.7;-webkit-font-smoothing:antialiased;overflow-x:hidden;
}
img{max-width:100%;height:auto;display:block}
h1,h2,h3,h4,h5{margin:0;line-height:1.12;font-family:var(--display);font-weight:700;color:var(--text-main)}
p{margin:0 0 1.15em}
p:last-child{margin-bottom:0}
a{color:inherit}
:focus-visible{outline:2px solid var(--ink-blue);outline-offset:3px;border-radius:4px}
:focus:not(:focus-visible){outline:none}

.skip{
  position:absolute;left:var(--gut);top:-4rem;z-index:200;
  background:var(--text-main);color:#fff;font-weight:600;
  padding:.7rem 1.1rem;font-family:var(--mono);font-size:.8rem;
  text-decoration:none;transition:top .15s;border-radius:8px;
}
.skip:focus{top:.75rem}

.wrap{width:100%;max-width:var(--wrap);margin-inline:auto;padding-inline:var(--gut)}
.wrap.narrow{max-width:58rem}
section[id],[id="top"]{scroll-margin-top:5.5rem}

/* The gradient as text. Large display only: see header. */
.text-gradient{
  background:var(--text-gradient);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}
/* In the hero it is the reference build's three-stop sky/violet/coral sweep,
   not the six-stop logo gradient. */
.hero-title .text-gradient{background:var(--hero-text-gradient);-webkit-background-clip:text;background-clip:text}
@supports not ((background-clip:text) or (-webkit-background-clip:text)){
  .text-gradient{color:var(--ink-violet);-webkit-text-fill-color:currentColor}
}

.h-display{font-weight:800;letter-spacing:-.025em;line-height:1.06;font-size:clamp(2rem,1.35rem + 2.9vw,3.4rem);max-width:22ch;margin:0 0 1.3rem}
.lede{font-size:clamp(1.05rem,1rem + .35vw,1.2rem);color:var(--text-body);max-width:60ch}
.sec p:not([class]){max-width:70ch}

/* Section eyebrow. The leading dash is now a drawn rule: same visual weight,
   no em dash in the text. The rule carries the brand gradient, so the numbered
   sequence reads as part of the identity rather than as punctuation. */
.eyebrow{
  font-family:var(--mono);font-size:.75rem;font-weight:500;
  letter-spacing:.18em;text-transform:uppercase;color:var(--ink-blue);
  margin:0 0 1.5rem;display:flex;align-items:center;gap:.6ch;flex-wrap:wrap;
}
.eyebrow::before{
  content:'';flex:0 0 auto;width:1.9rem;height:2px;border-radius:2px;
  background:var(--brand-gradient);margin-right:.3ch;
}
.eyebrow .eb-n{color:var(--ink-orange)}
h2.eyebrow{font-family:var(--mono);font-weight:500;line-height:1.6}

/* ── Buttons ─────────────────────────────────────────────────────────────── */
/* Labels are small text (0.95rem, weight 500), so the bar is 4.5, and white on
   --blue-cta #0093d4 measures 3.43. That is a known, accepted exception: see
   the exception block at the top of this file. The compliant alternatives are
   #007cb3 at this size (4.63), or keeping #0093d4 and setting the label to
   1.2rem/700, which makes it large text and drops the bar to 3.0. */
.btn{
  display:inline-flex;align-items:center;gap:.7ch;
  font-family:var(--sans);font-size:.95rem;font-weight:500;
  padding:.7rem 1.35rem;text-decoration:none;line-height:1.3;white-space:nowrap;
  border:1px solid transparent;border-radius:10px;min-height:44px;
  transition:transform .18s,box-shadow .18s,border-color .18s,color .18s,background .18s;
}
.btn-primary{background:var(--blue-cta);color:#fff;border:0}
.btn-primary:hover{background:var(--blue-cta-dark);box-shadow:0 10px 28px rgba(0,147,212,.34)}
/* Reference build: translucent white, not solid, so the hero wash reads through */
.btn-ghost{border-color:var(--border);color:var(--text-main);background:rgba(255,255,255,.5)}
/* --ink-blue, not --blue-cta: this label sits on white and #0093d4 is 3.43 there. */
.btn-ghost:hover{border-color:var(--blue-cta);color:var(--ink-blue);background:#fff}
/* Estado "trabajando". El boton de enviar se deshabilita nada mas pulsarlo,
   pero hasta ahora no CAMBIABA: seguia azul vivo e identico, asi que el unico
   indicio de que algo estaba pasando era una linea gris de 0.78rem debajo. El
   envio real tarda unos 0.6 s, y 0.6 s sin respuesta visible al clic se
   perciben como mucho mas de lo que son.
   Gris pizarra en vez de azul rebajado en opacidad: rebajar la opacidad del
   azul deja el texto blanco por debajo de 3.0. Asi, blanco sobre #64748b son
   4.76, que cumple AA aunque un control deshabilitado este exento.
   cursor:progress y no not-allowed: no esta prohibido, esta ocupado. */
.btn[disabled],.btn:disabled{
  background:#64748b;color:#fff;box-shadow:none;cursor:progress;
  /* La transicion general del boton es de .18s. Aqui no vale: durante 180 ms
     de una espera de 600 el boton seguiria pareciendo pulsable, justo en el
     momento en que hay que confirmar que el clic se registro. Acuse de recibo
     inmediato, con lo justo para que no sea un corte seco. */
  transition:background .06s;
}
.btn[disabled]:hover{background:#64748b;box-shadow:none;transform:none}
/* These two re-declare font-size and therefore own their own button's size. */
.btn-lg{padding:.85rem 1.6rem;font-size:1rem}
.actions,.hero-actions{display:flex;flex-wrap:wrap;gap:.85rem;margin:2.2rem 0 0}
@media (prefers-reduced-motion:no-preference){.btn:hover{transform:translateY(-2px)}}

/* ── Header ──────────────────────────────────────────────────────────────── */
/* Transparent at the top of the page, solid once you scroll, as in the
   reference build. It has to be `fixed`, not `sticky`: a sticky header still
   occupies a row in the flow, so a transparent one would show the page
   background above the hero instead of the hero wash showing through it.
   Because it is out of flow, .hero carries the top padding that clears it.

   JS adds .is-scrolled past 40px, and also while the mobile menu is open, so
   the open panel never hangs off a transparent bar. With JS off the header
   stays transparent, which is why every item in it is measured against the
   hero wash, not against white. */
.site-head{
  position:fixed;top:0;left:0;right:0;z-index:100;
  background:transparent;border-bottom:1px solid transparent;
  transition:background .4s,box-shadow .4s,border-color .4s,backdrop-filter .4s;
}
.site-head.is-scrolled{
  background:rgba(255,255,255,.85);
  -webkit-backdrop-filter:blur(16px) saturate(140%);
  backdrop-filter:blur(16px) saturate(140%);
  box-shadow:0 4px 24px rgba(15,23,42,.06);
  border-bottom-color:var(--border);
}
@media (prefers-reduced-motion:reduce){.site-head{transition:none}}
.head-in{display:flex;align-items:center;gap:1.5rem;min-height:74px}
/* Lockup: the mark is 32px and the two text lines are set to line-height 1 with
   a fixed 4px gap, so the text block measures ~31px. Mark and text block are
   therefore the same height and their top and bottom edges align, instead of
   each drifting on its own leading. Change one, re-check the other. */
.brand{display:flex;align-items:center;gap:.68rem;text-decoration:none;flex:0 0 auto}
.brand-mark{width:32px;height:32px;flex:0 0 auto}
.brand-mark svg{width:100%;height:100%;display:block;overflow:visible}
.logo-text{display:flex;flex-direction:column;justify-content:center;gap:4px}
.brand-name{font-family:var(--display);font-weight:800;letter-spacing:.14em;font-size:1.06rem;line-height:1;color:var(--text-main)}
/* --text-quiet, not --text-muted. With the header transparent at the top of
   the page this sub-line sits on the hero's peach corner, not on white:
   #5B6577 measured 4.46 there and just missed. */
.logo-sub{font-family:var(--mono);font-weight:400;font-size:.62rem;letter-spacing:.15em;line-height:1;color:var(--text-quiet);text-transform:uppercase;margin:0}
.nav{display:flex;gap:1.7rem;margin-left:auto}
.nav a{font-size:.93rem;text-decoration:none;color:var(--text-body);padding:.4rem 0;border-bottom:1px solid transparent;transition:color .15s,border-color .15s}
.nav a:hover{color:var(--ink-blue);border-bottom-color:var(--ink-blue)}
.head-end{display:flex;align-items:center;gap:1rem;margin-left:auto}
.nav+.head-end{margin-left:0}
.lang{display:flex;align-items:center;gap:.35rem;font-family:var(--mono);font-size:.78rem}
.lang button{background:none;border:0;padding:0 .3rem;cursor:pointer;font:inherit;color:var(--text-muted);min-height:44px;min-width:2.25rem;display:inline-flex;align-items:center;justify-content:center;transition:color .15s}
.lang button:hover{color:var(--text-main)}
.lang button.is-on{color:var(--ink-blue);text-decoration:underline;text-decoration-color:var(--ink-blue);text-decoration-thickness:1px;text-underline-offset:5px}
.lang span{color:var(--text-muted)}
.head-cta{padding:.55rem 1.05rem;font-size:.85rem}
.burger{display:none;background:none;border:0;cursor:pointer;padding:.6rem;width:44px;height:44px}
.burger span{display:block;height:1.5px;width:20px;background:var(--text-main);margin:4px auto}

/* ── Hero ────────────────────────────────────────────────────────────────────
   Ported from the reference build (440a62d), value for value: the warm-to-cool
   wash, the masked grid, the coral and violet glows with the float animation,
   the coral badge, the muted uppercase tagline, and the technology pills.

   Four colours in here failed AA as authored and are the ONLY things changed.
   Each is the lightest step of the SAME hue that clears the bar, so the look
   holds and the measurement is honest:

     what                     authored   corrected
     tagline / trust label    #94a3b8    #465468
     badge label              #d8492a    #a4361e
     headline gradient, sky   #0ea5e9    #0a7cae   (large display, bar 3.0)
     headline gradient, coral #ff6a3d    #e35a24   (large display, bar 3.0)

   The violet stop #7c3aed is untouched.

   These numbers come from RENDERED PIXELS, not from the three stops of the
   wash. That distinction cost a round: the two .hero-glow blobs sit ON TOP of
   the wash, so the real background under the badge and the tagline is a
   coral-tinted (241,210,201) and a violet-tinted (217,196,229), both darker
   than any base stop. Solving against the base stops said 4.53; the rendered
   pixels said 3.72 and 3.27. Same story as the stats band.

   To re-check after any change to the wash, the glows or these colours:
     /tmp-style plate: hide every .hero descendant except .hero-bg, screenshot,
     then for each text box take the worst background pixel inside it. Gradient
     text needs the opaque-glyph trick: render over white and over black, and
     only pixels identical in both renders are 100% coverage. Antialiased edges
     always measure low and must be excluded or the result is meaningless. */
.hero{
  position:relative;overflow:hidden;
  background:linear-gradient(165deg,#fdfbf7 0%,#eef4ff 52%,#ffe9e2 100%);
  /* Top padding clears the fixed header, which is out of flow (~74px) and
     would otherwise sit on the badge. Bottom padding leaves room for the
     scroll cue, absolutely positioned at the foot of the hero. */
  padding:clamp(7.5rem,11vw,9.5rem) 0 clamp(6rem,10vw,8.5rem);
}
.hero-bg{position:absolute;inset:0;pointer-events:none;overflow:hidden}
.hero-grid-pattern{
  position:absolute;inset:0;
  background-image:
    linear-gradient(rgba(15,23,42,.04) 1px, transparent 1px),
    linear-gradient(90deg,rgba(15,23,42,.04) 1px, transparent 1px);
  background-size:56px 56px;
  -webkit-mask-image:radial-gradient(ellipse 80% 80% at 50% 50%,#000 20%,transparent 100%);
  mask-image:radial-gradient(ellipse 80% 80% at 50% 50%,#000 20%,transparent 100%);
}
.hero-glow{position:absolute;border-radius:50%;filter:blur(70px);animation:float 8s ease-in-out infinite}
.hero-glow-1{width:560px;height:560px;top:-120px;left:-80px;background:rgba(255,106,61,.22)}
.hero-glow-2{width:520px;height:520px;bottom:-80px;right:-60px;background:rgba(124,58,237,.18);animation-delay:-4s}
@keyframes float{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-30px) scale(1.05)}}
@media (prefers-reduced-motion:reduce){.hero-glow{animation:none}}
.hero-content{position:relative;z-index:1}

.hero-badge{
  display:inline-flex;align-items:center;gap:8px;
  background:rgba(255,255,255,.7);border:1px solid var(--coral);
  color:var(--coral-ink);
  font-size:.8rem;font-weight:600;letter-spacing:.02em;
  padding:6px 14px;border-radius:100px;margin:0 0 28px;
  box-shadow:0 4px 16px rgba(255,106,61,.15);
}
.badge-pulse{width:7px;height:7px;border-radius:50%;background:var(--coral);flex:0 0 auto;animation:pulse 2s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.7)}}
@media (prefers-reduced-motion:reduce){.badge-pulse{animation:none}}

.hero-title{font-weight:700;letter-spacing:-.025em;line-height:1.15;font-size:clamp(2.4rem,5.5vw,4.2rem);color:var(--text-main);max-width:820px;margin:0 0 24px}
.hero-tagline{font-family:var(--display);font-size:clamp(1rem,2vw,1.25rem);font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--text-quiet);margin:14px 0 22px}
.hero-subtitle{font-family:var(--sans);font-size:1.1rem;line-height:1.7;color:var(--text-body);max-width:560px;margin:0 0 1rem}
.hero-actions{display:flex;gap:14px;flex-wrap:wrap;margin:36px 0 0}


.scroll-cue{position:absolute;left:50%;bottom:1.2rem;transform:translateX(-50%);z-index:1}
/* The original cue, restored from 440a62d: the line draws itself downward from
   its own top edge and fades, rather than a dot travelling down a track. */
.scroll-line{
  width:2px;height:48px;margin:0 auto;
  background:linear-gradient(to bottom,transparent,var(--g5));
  animation:scrollDrop 2s ease-in-out infinite;
}
@keyframes scrollDrop{
  0%  {opacity:0;transform:scaleY(0);transform-origin:top}
  50% {opacity:1}
  100%{opacity:0;transform:scaleY(1);transform-origin:top}
}
@media (prefers-reduced-motion:reduce){.scroll-line{animation:none;opacity:.8}}

/* ── Technology ticker (kept: the client likes it) ───────────────────────────
   position/z-index load-bearing: .hero-bg is absolutely positioned, and
   positioned elements paint over static in-flow content. */
.ticker{position:relative;z-index:1;overflow:hidden;padding:.95rem 0;border-block:1px solid var(--border);background:#fff}
.ticker-track{display:flex;width:max-content;animation:slide 70s linear infinite}
.ticker-set{font-family:var(--mono);font-size:.78rem;color:var(--text-muted);white-space:nowrap;padding-right:1rem}
@keyframes slide{to{transform:translateX(-50%)}}
@media (prefers-reduced-motion:reduce){.ticker-track{animation:none;width:100%;overflow-x:auto}.ticker-set:last-child{display:none}}

/* ── Stats bar ───────────────────────────────────────────────────────────── */
/* Full-bleed band, ported from the reference build (440a62d).

   NO dark overlay. There used to be one, and it is what made this band look
   muddy: a flat black veil lowers luminance by mixing every hue with grey, so
   the colour dies before the text becomes legible.

   Instead the three stops themselves are taken deeper AND fully saturated.
   Same hues, same sweep, more chroma, less lightness:

     stop     reference     band       hue  saturation
     sky      #0ea5e9       #0093d4    199  89%  -> 100%
     violet   #6d28d9       #9d5eff    263  70%  -> 100%
     coral    #ff6a3d       #ff470f     14  100%

   TWO TEXT COLOURS IN HERE, ON PURPOSE.

     figures (.stat-value/.stat-unit)  #ffffff  large text, bar 3.0, worst 3.32
     lettering (.stat-label)           #0b1220  small text, bar 4.5, worst 4.58

   That split is what keeps the band this light. White as SMALL text measures
   3.43 at worst and fails; making it legal would mean either darkening the
   band again (rejected) or setting every label at 19.2px bold so it counts as
   large text (also rejected, the client wants the lettering small). Ink at
   #0f172a on these three stops measures sky 5.21, violet 4.66, coral 5.24.

   So: if a label ever goes back to white, it must also go back to 19.2px bold,
   or the band has to be darkened. Measured per element, glyph pixels only.

   Verified by scanning every rendered pixel of the band, because the grid
   texture lightens it and the 110deg angle puts the extreme in a corner rather
   than on a stop. Arithmetic on the stops alone is optimistic by ~0.4.

   Text must be PURE white. The reference dimmed labels to 82%, which lands
   around 2.4 on the coral end and fails outright. If you change a stop, re-run
   the pixel scan; do not re-derive it from the table above. */
.stats-bar{position:relative;z-index:1;background:var(--band-gradient);padding:56px 0;overflow:hidden}
.stats-bar::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background-image:linear-gradient(rgba(255,255,255,.06) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(255,255,255,.06) 1px,transparent 1px);
  background-size:48px 48px;
}
/* align-items:start, not center. The label under each figure runs to a
   different number of lines (one for "Years", two plus a note for the platform
   figure), and centring each cell independently puts every number at a
   different height. Aligning to the top puts all four figures on one baseline,
   which is the whole point of a band like this. */
.stats-grid{position:relative;z-index:1;display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(1.75rem,4vw,2rem);align-items:start;text-align:center}
@media (min-width:60rem){.stats-grid{grid-template-columns:1fr auto 1fr auto 1fr auto 1fr;gap:clamp(1.25rem,2.5vw,2rem)}}
.stat-divider{display:none}
@media (min-width:60rem){.stat-divider{display:block;width:1px;height:60px;align-self:center;background:rgba(255,255,255,.32)}}
.stat-item{min-width:0;padding:16px 24px}
/* inline-block keeps the value and its unit on one line ("50M+", not "50" with
   the suffix wrapping onto the label). */
.stat-value,.stat-unit{display:inline-block;font-family:var(--display);font-weight:700;line-height:1;color:#fff}
.stat-value{font-size:clamp(2rem,4vw,2.8rem)}
.stat-unit{font-size:clamp(1.5rem,3vw,2.2rem)}
/* Same lettering as the section eyebrows ("01 / Criterion"): IBM Plex Mono,
   uppercase, wide tracking. White, like the figures above it. Being small
   white text is what pins the band's stops: see the block comment above. */
.stat-label{
  display:block;font-family:var(--mono);font-size:.75rem;font-weight:500;
  letter-spacing:.18em;text-transform:uppercase;color:#fff;
  line-height:1.6;max-width:200px;margin:12px auto 0;
}

/* ── Sections ────────────────────────────────────────────────────────────── */
.sec{padding:var(--sec-y) 0}
.sec+.sec{border-top:1px solid var(--border)}
.sec-note{font-family:var(--mono);font-size:.8rem;color:var(--text-muted);margin:-.5rem 0 2.5rem}
.sub-h{font-family:var(--mono);font-size:.74rem;font-weight:500;letter-spacing:.16em;text-transform:uppercase;color:var(--text-muted);margin:clamp(2.75rem,5vw,4rem) 0 1.5rem;padding-bottom:.7rem;border-bottom:1px solid var(--border)}
.pull{font-family:var(--display);font-size:clamp(1.3rem,1.1rem + 1vw,1.8rem);font-weight:700;letter-spacing:-.02em;line-height:1.3;color:var(--text-main);border-left:3px solid transparent;border-image:var(--brand-gradient) 1;padding-left:1.5rem;margin-top:2.4rem;max-width:36ch}

/* ── Bento grid ──────────────────────────────────────────────────────────── */
.bento-grid{display:grid;grid-template-columns:1fr;gap:1.15rem;margin-top:2.5rem}
@media (min-width:46rem){.bento-grid{grid-template-columns:repeat(2,1fr)}}
@media (min-width:64rem){
  /* 3 columns, 3 rows, every cell filled and no card the same size as its
     neighbour:   [ large  large ][ 2 ]
                  [ 3 ][ medium  medium ]
                  [ wide   wide   wide  ]
     An earlier version spanned the featured card two rows, which left a large
     void inside it and two empty cells in row 3. */
  /* [ featured, full width ] / [ 3 ][ 3 ][ 3 ] / [ in every engagement ]
     The three remaining service cards share one row, so no cell is left empty
     and none of them is arbitrarily wider than its neighbours. */
  .bento-grid{grid-template-columns:repeat(3,1fr)}
  .card-large{grid-column:span 3}
  .card-medium{grid-column:span 1}
  .card-wide{grid-column:span 3}
}
.bento-card{
  position:relative;display:flex;flex-direction:column;
  background:#fff;border:1px solid var(--border);border-radius:var(--r-lg);
  padding:clamp(1.5rem,3vw,2.15rem);overflow:hidden;
  transition:border-color .2s,transform .2s,box-shadow .2s;
}
/* Each card takes one stop of the gradient, in order, so the grid reads as one
   spectrum left to right and top to bottom. Card 1 is the featured card and
   carries the WHOLE gradient (.card-accent), so the numbered steps start at
   card 2. --accent-raw is the 3px rule and the icon tint; --accent is the ink
   version, used anywhere the colour becomes text or a border.

     1  Applied AI                      full gradient
     2  Analytics platforms             g1  blue
     3  Quantitative engineering        g2  violet
     4  Product & cloud architecture    g3  magenta
     5  In every engagement             g5  orange, closing the sweep */
.bento-card{--accent:var(--ink-blue);--accent-raw:var(--g1)}
.bento-card:nth-of-type(2){--accent:var(--ink-blue);--accent-raw:var(--g1)}
.bento-card:nth-of-type(3){--accent:var(--ink-violet);--accent-raw:var(--g2)}
.bento-card:nth-of-type(4){--accent:var(--ink-magenta);--accent-raw:var(--g3)}
.bento-card:nth-of-type(5){--accent:var(--ink-orange);--accent-raw:var(--g5)}
.bento-card::before{content:'';position:absolute;left:0;right:0;top:0;height:3px;background:var(--accent-raw);opacity:.9}
.card-accent::before{background:var(--brand-gradient)}
.bento-card:hover{border-color:var(--accent);box-shadow:0 16px 38px rgba(15,23,42,.09)}
@media (prefers-reduced-motion:no-preference){.bento-card:hover{transform:translateY(-4px)}}
.card-icon{width:52px;height:52px;border-radius:13px;display:grid;place-items:center;color:var(--accent);background:color-mix(in srgb,var(--accent-raw) 12%,#fff);margin-bottom:1.25rem;flex:0 0 auto}
.card-accent .card-icon{background:var(--brand-gradient);color:var(--text-main)}
.bento-card h3{font-size:1.2rem;margin-bottom:.8rem;letter-spacing:-.015em}
.card-large h3{font-size:clamp(1.35rem,1.1rem + .9vw,1.85rem)}

/* Featured-card interior, declared HERE and not up in the grid media query.
   `.bento-card{display:flex}` is defined further down the file than that block
   was, and a media query adds no specificity, so `display:grid` was being
   silently overridden back to flex while grid-template-columns still applied.
   The rule has to sit after .bento-card. Same trap as .btn-lg re-declaring
   font-size: in this file, source order decides. */
@media (min-width:64rem){
  /* The featured card is full width, so it gets a two-column interior: icon
     and title on the left, description and tags on the right. Without this its
     text runs across the left half and the right half sits empty, which reads
     as a layout bug rather than as emphasis.
     Children in source order: .card-icon, h3, p, .card-tags, .card-arrow. */
  .card-large{
    display:grid;
    grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
    column-gap:clamp(2rem,4vw,4rem);
    align-content:start;
  }
  .card-large .card-icon{grid-column:1;grid-row:1;margin-bottom:1.1rem}
  .card-large h3{grid-column:1;grid-row:2;align-self:start;margin:0}
  .card-large p{grid-column:2;grid-row:1 / span 2;margin:0}
  .card-large .card-tags{grid-column:2;grid-row:3;margin-top:1.4rem}
  .card-large .card-arrow{grid-column:2;grid-row:1;justify-self:end;align-self:start}
}
.bento-card p:not([class]){color:var(--text-body);font-size:.95rem}
.card-tags{display:flex;flex-wrap:wrap;gap:.45rem;margin-top:auto;padding-top:1.3rem}
.card-tags span{font-family:var(--mono);font-size:.68rem;color:var(--text-muted);background:var(--bg-light);border:1px solid var(--border);border-radius:999px;padding:.32rem .7rem;white-space:nowrap}
.card-arrow{position:absolute;right:1.25rem;top:1.25rem;color:var(--accent);opacity:.4;transition:opacity .2s,transform .2s}
.bento-card:hover .card-arrow{opacity:1}
@media (prefers-reduced-motion:no-preference){.bento-card:hover .card-arrow{transform:translate(3px,-3px)}}
.card-horizontal{display:grid;gap:1.5rem;grid-template-columns:1fr}
@media (min-width:56rem){.card-horizontal{grid-template-columns:1.6fr 1fr;align-items:center}}
.card-horizontal-left{display:flex;gap:1.25rem;align-items:flex-start}
.card-horizontal-left .card-icon{margin-bottom:0}
.card-horizontal-right .card-tags{padding-top:0;margin-top:0}

/* ── WORK: tabbed slider ──────────────────────────────────────────────────
   No auto-advance by design: the sister site rotates every 6s and most cases
   are never seen. Every client stays visible in the strip. */
.tabs{display:flex;gap:.5rem;flex-wrap:wrap;margin:0 0 1.75rem;padding:0 0 .75rem;border-bottom:1px solid var(--border)}
.tab{
  font-family:var(--sans);font-size:.88rem;font-weight:600;color:var(--text-body);
  background:#fff;border:1px solid var(--border);border-radius:999px;
  padding:.55rem 1.1rem;min-height:44px;cursor:pointer;
  /* the selected state swaps to a 2px border; padding there is reduced by the
     same 1px so the pill does not change size and the strip does not jump */
  display:inline-flex;align-items:center;gap:.5ch;white-space:nowrap;
  transition:color .16s,border-color .16s,background .16s;
}
.tab:hover{border-color:var(--ink-blue);color:var(--ink-blue)}
/* Selected tab: the gradient is the BORDER and the LETTERS, never a fill.

   The border uses the two-layer background trick: a flat white layer clipped
   to the padding box sits on top of the gradient layer clipped to the border
   box, so the gradient shows only in the 2px border ring. That means the
   button's own `background` is spoken for, which is why the gradient lettering
   has to live on the inner <span> rather than on the button.

   The letters use --ink-gradient, NOT --brand-gradient. Tab labels are small
   text and need 4.5 on white; the raw brand stops run 1.68 to 4.20 there and
   would fail outright. The ink stops measure 4.97 to 5.10. */
.tab[aria-selected="true"]{
  border:2px solid transparent;font-weight:700;
  padding:calc(.55rem - 1px) calc(1.1rem - 1px);
  background-image:linear-gradient(#fff,#fff),var(--brand-gradient);
  background-origin:border-box;
  background-clip:padding-box,border-box;
}
.tab[aria-selected="true"] > span{
  background:var(--ink-gradient);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}
@supports not ((background-clip:text) or (-webkit-background-clip:text)){
  .tab[aria-selected="true"] > span{color:var(--ink-violet);-webkit-text-fill-color:currentColor}
}
/* No opacity here. It is real visible text, and fading it to 85% over white
   drops the ink stops under 4.5. Colour does the job instead. */
.tab-more{font-family:var(--mono);font-size:.68rem;font-weight:500;color:var(--text-muted)}
@media (max-width:46rem){
  .tabs{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:thin;-webkit-overflow-scrolling:touch;
    -webkit-mask-image:linear-gradient(to right,#000 88%,transparent);
    mask-image:linear-gradient(to right,#000 88%,transparent)}
  .tab{flex:0 0 auto}
}
.panels{min-height:34rem}
@media (min-width:60rem){.panels{min-height:30rem}}
.panel[hidden]{display:none}
@media (prefers-reduced-motion:no-preference){
  .panel:not([hidden]){animation:panelIn .28s cubic-bezier(.2,.7,.3,1)}
  @keyframes panelIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
}

.case{margin:0;max-width:74ch}
.case-head{margin-bottom:1.6rem}
.case h3{font-size:clamp(1.7rem,1.35rem + 1.4vw,2.3rem);font-weight:800;letter-spacing:-.025em}
.case-kind{font-family:var(--mono);font-size:.75rem;color:var(--text-muted);margin:.6rem 0 0}
.case-lede{font-size:1.05rem;color:var(--text-body);margin-bottom:1.7rem}
.case-sub{font-family:var(--mono);font-size:.72rem;font-weight:500;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-blue);margin:1.8rem 0 .85rem}
.case-list{margin:0 0 1.15em;padding:0;list-style:none}
.case-list li{margin-bottom:.6rem;color:var(--text-body);padding-left:1.25rem;position:relative}
.case-list li::before{content:'';position:absolute;left:0;top:.7em;width:6px;height:6px;border-radius:50%;background:var(--g1)}
.case p:not([class]){color:var(--text-body)}
.disclaimer{font-family:var(--mono);font-size:.76rem;line-height:1.7;color:var(--text-muted);border-top:1px solid var(--border);padding-top:1.1rem;margin-top:1.8rem}

/* Reconciliation line: the most visually striking block in the panel.
   A statement, not a chart: two qualitative endpoints are not chart data. */
/* The reconciliation line is the FIRST block in every case panel, above the
   client name. It opens with the transformation, then says whose it is.

   ONE horizontal row: [BEFORE / value] arrow [AFTER / value]. Each label sits
   ABOVE its own value, not beside it, and the two groups sit side by side.

   Three things keep it from breaking mid-pair, and all three are load-bearing:
     - flex-wrap:nowrap on .recon, so the arrow can never be pushed to a line
       of its own. That is the failure this rule exists to prevent.
     - each .recon-side is its own inline group (label and value side by side)
       with white-space:nowrap, so a side is atomic: it moves as one or not at
       all.
     - min-width:auto, NOT 0, on the sides. min-width:0 lets a flex item shrink
       below its content and the nowrap text then spills; leaving it at auto
       means the sides simply hold their width.
   Below 45rem the whole row stacks and the arrow turns to point down.

   WHY 45rem. Measured, not chosen. Stacking each label over its value is what
   made this number movable: with label beside value the widest pair needed
   738px of content and the row could not fit until an 820px viewport. Stacked,
   each side is only as wide as the LONGER of its label and its value, so the
   requirement drops to 640px and the row fits from 700px.
     680px -> 18px short   700px -> fits   45rem (720px) is the setting,
   with slack for Spanish, which runs longer, and for font-loading shifts.
   If you lengthen a pair, re-run the fit check across all seven in both
   languages. */
.recon{
  display:flex;align-items:center;flex-wrap:nowrap;
  border-radius:var(--r-lg);overflow:hidden;
  margin-bottom:1.9rem;position:relative;
  background:linear-gradient(#fff,#fff) padding-box,var(--brand-gradient) border-box;
  border:2px solid transparent;
}
.recon-side{
  flex:1 1 auto;display:flex;flex-direction:column;align-items:flex-start;gap:.4rem;
  padding:1.05rem 1.4rem;white-space:nowrap;
}
.recon-l{font-family:var(--mono);font-size:.67rem;font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--text-muted);margin:0;flex:0 0 auto}
.recon-v{font-family:var(--mono);font-size:clamp(.95rem,.88rem + .3vw,1.1rem);font-weight:600;margin:0;line-height:1.4;max-width:none;white-space:nowrap}
.recon-v.is-before{color:var(--ink-red)}
.recon-v.is-after{
  background:var(--text-gradient);-webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}
@supports not ((background-clip:text) or (-webkit-background-clip:text)){
  .recon-v.is-after{color:var(--ink-violet);-webkit-text-fill-color:currentColor}
}
.recon-arrow{
  flex:0 0 auto;
  display:flex;align-items:center;max-width:none;padding:0 .5rem;margin:0;
  font-size:1.15rem;font-weight:700;
  background:var(--brand-gradient);-webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}
@supports not ((background-clip:text) or (-webkit-background-clip:text)){
  .recon-arrow{color:var(--ink-violet);-webkit-text-fill-color:currentColor}
}

/* Stacked mode. The arrow rotates to point down and becomes the divider
   between the two groups, so a value is never left without its arrow. */
@media (max-width:44.99rem){
  .recon{flex-direction:column;align-items:stretch}
  .recon-side{white-space:normal;justify-content:flex-start}
  .recon-v{white-space:normal}
  .recon-arrow{
    border-block:1px solid var(--border);padding:.55rem 1.4rem;
    justify-content:flex-start;font-size:0;
  }
  .recon-arrow::before{content:'↓';font-size:1.15rem}
}

/* ── How we work ─────────────────────────────────────────────────────────── */
/* Three short lines, not cards. Only the last one loses its rule, so the block
   reads as a list of statements rather than as three boxes. */
.measures{margin:0;padding:0;list-style:none;display:grid;gap:0}
.measures li{display:flex;gap:1rem;align-items:flex-start;padding:1rem 0;border-bottom:1px solid var(--border);color:var(--text-body);max-width:80ch;font-size:.98rem;line-height:1.65}
.measures li:last-child{border-bottom:0;padding-bottom:0}
/* Icon left of the text, not above: at this section's width the block stays
   one line of reading per point, which is the whole reason it is a list and
   not a feature grid. Same drawing language as the bento cards: 24x24,
   stroked, 1.5, no fills. Each takes one stop of the gradient. */
.me-icon{flex:0 0 auto;width:38px;height:38px;border-radius:10px;display:grid;place-items:center;color:var(--me-accent);background:color-mix(in srgb,var(--me-raw) 12%,#fff)}
.measures li:nth-child(1){--me-accent:var(--ink-blue);--me-raw:var(--g1)}
.measures li:nth-child(2){--me-accent:var(--ink-violet);--me-raw:var(--g2)}
.measures li:nth-child(3){--me-accent:var(--ink-orange);--me-raw:var(--g5)}
.me-text{min-width:0}
.measures strong{color:var(--text-main);font-weight:700}

/* Phase timeline */
.phases{list-style:none;margin:2.25rem 0 0;padding:0;display:grid;gap:0;position:relative}
@media (min-width:64rem){
  .phases{grid-template-columns:repeat(4,1fr);gap:1.15rem}
  /* the connecting rule, carrying the gradient from Discovery to Operate */
  .phases::before{content:'';position:absolute;left:0;right:0;top:26px;height:2px;background:var(--brand-gradient);border-radius:2px}
}
.phase{position:relative;padding:0 0 1.75rem}
@media (min-width:64rem){.phase{padding:0}}
.ph-dot{width:54px;height:54px;border-radius:50%;display:grid;place-items:center;position:relative;z-index:1;background:#fff;border:2px solid transparent;background-image:linear-gradient(#fff,#fff),var(--brand-gradient);background-origin:border-box;background-clip:padding-box,border-box;margin-bottom:1.1rem}
.ph-n{font-family:var(--mono);font-size:.9rem;font-weight:600;color:var(--ph-accent,var(--ink-blue));margin:0}
.phase:nth-child(1){--ph-accent:var(--ink-blue)}
.phase:nth-child(2){--ph-accent:var(--ink-violet)}
.phase:nth-child(3){--ph-accent:var(--ink-magenta)}
.phase:nth-child(4){--ph-accent:var(--ink-orange)}
.phase h4{font-size:1.08rem;margin-bottom:.4rem;letter-spacing:-.01em}
/* The pill tint is 6%, not 10%. The --ink-* accents are sized to clear 4.5 on
   WHITE (>= 4.70) and a tinted pill eats into that: at 10% all four dropped to
   4.35-4.43 and failed. Measured: 8% -> 4.48 FAIL, 6% -> 4.61, 5% -> 4.65. */
.ph-when{display:inline-block;font-family:var(--mono);font-size:.72rem;font-weight:600;font-variant-numeric:tabular-nums;color:var(--ph-accent);background:color-mix(in srgb,currentColor 6%,#fff);border-radius:999px;padding:.28rem .7rem;margin:0 0 .85rem}
/* :not([class]) is load-bearing. .ph-when is a <p>, so a bare `.phase p` is
   (0,1,1) and silently beats `.ph-when` at (0,1,0): the four week pills all
   rendered body grey and --ph-accent never reached them, which also flattened
   the color-mix pill background, since that is built from currentColor. */
.phase p:not([class]){font-size:.92rem;color:var(--text-body);max-width:none}
@media (max-width:63.99rem){
  .phase::after{content:'';position:absolute;left:26px;top:54px;bottom:.5rem;width:2px;background:var(--border)}
  .phase:last-child::after{display:none}
}

/* ── Bands ───────────────────────────────────────────────────────────────── */
/* "Where we come from" is a SUPPORTING band under the team cards, not a
   section competing with them. Smaller type, tighter padding, narrower
   measure. It carries provenance; the cards carry the people. If it ever
   starts looking like a section again, this is the block that drifted. */
.band{background:var(--bg-dark);color:var(--text-inv);padding:clamp(2.5rem,4.5vw,3.5rem) 0}
.band h2,.band h3{color:#fff}
.band .wrap{max-width:62rem}
/* CONDENSED, not shrunk. An earlier pass took the type to 0.92rem and dimmed
   it; that made it quiet rather than concise, which was not the point. The
   size is back to body copy and the COPY is what got shorter. */
.band-h{font-family:var(--mono);font-size:.86rem;font-weight:500;letter-spacing:.16em;text-transform:uppercase;color:#8ec9f5;margin:0 0 1.1rem}
.band-p{font-size:1.02rem;line-height:1.7;color:var(--text-inv);max-width:78ch;margin:0}

/* ── Team ────────────────────────────────────────────────────────────────── */
.people{display:grid;gap:clamp(1.75rem,4vw,2.5rem);grid-template-columns:1fr;margin-top:3rem}
/* En tres columnas, cada tarjeta se alinea FILA A FILA con las otras dos.
   El problema que resuelve: los cargos no ocupan las mismas lineas. A 704px,
   el de Guillermo ("Head of Data Science · ML, Riesgo y Modelizacion
   Cuantitativa") ocupa cuatro y el de Roberto dos, asi que las tres biografias
   arrancaban a tres alturas distintas y la seccion se leia descuadrada.
   Con subgrid las seis filas (foto, nombre, cargo, bio, tags, enlace) son las
   MISMAS para las tres tarjetas y la mas alta manda. Se prefiere a un
   min-height por tramo de ancho porque no hay numeros magicos que revisar cada
   vez que alguien cambie un cargo.
   La tarjeta de Jorge solo tiene cinco hijos, sin enlace de LinkedIn: la sexta
   fila queda vacia, que es exactamente lo que se quiere.
   OJO con el gap: el de .people es de la rejilla PADRE y, al declarar aqui sus
   seis filas, se colaria entre todas ellas y reventaria el interior de la
   tarjeta. Por eso el hueco vertical se anula y solo se conserva el de columna,
   que es el unico que separa tarjetas cuando van en una sola fila. */
@media (min-width:44rem){
  .people{
    grid-template-columns:repeat(3,1fr);
    grid-template-rows:repeat(6,auto);
    row-gap:0;column-gap:clamp(1.75rem,4vw,2.5rem);
  }
  .person{display:grid;grid-row:span 6;grid-template-rows:subgrid;row-gap:0;align-content:start}
}
/* Photo slot. Until real photographs exist this renders a gradient monogram,
   honest and on-brand. No stock, no generated faces: these are three real,
   named people next to real employers. */
/* El interruptor. Por defecto NO se ven: si alguien anade una <img> y olvida
   poner data-photos="on", el resultado es el monograma de siempre y no una
   tarjeta a medias. Falla hacia el estado bueno. */
/* Retratos SIN FONDO: los tres son recortes sobre transparencia, asi que se
   apoyan directamente en el blanco de la tarjeta.
   Sin borde: un recuadro de 1px alrededor de una imagen transparente dibuja una
   caja vacia con una cabeza flotando dentro.
   Sin filtro y sin hover: sale la foto y ya, y no cambia al pasar el raton.
   object-fit:contain y no cover: con cover, un recorte cuya silueta no llegue a
   los bordes se ampliaria para rellenar y descuadraria el tamano de cabeza que
   se ha igualado a mano. Aqui no hay fondo que rellenar. */
.person-photo{display:none;width:100%;aspect-ratio:1;object-fit:contain;border-radius:var(--r-lg);margin-bottom:1.4rem}
.people[data-photos="on"] .person-photo{display:block}
.people[data-photos="on"] .monogram{display:none}
.monogram{
  width:100%;aspect-ratio:1;border-radius:var(--r-lg);margin-bottom:1.4rem;
  display:grid;place-items:center;background:var(--brand-gradient);
  font-family:var(--display);font-weight:800;font-size:clamp(2.5rem,5vw,3.6rem);
  letter-spacing:.06em;color:var(--text-main);
}
.person h3{font-size:1.2rem}
.person-role{font-family:var(--mono);font-size:.76rem;color:var(--ink-violet);margin:.4rem 0 1rem}
.person p:not([class]){color:var(--text-body)}
.person p{font-size:.93rem}
.tags{font-family:var(--mono);font-size:.73rem;line-height:1.8;color:var(--text-muted);margin-top:1.3rem}
/* Quiet secondary link under the tags. With no photographs, this is the
   verifiability that matters: a buyer checking the Bankinter or Sabadell
   credential clicks through and sees it. */
/* Icon only, no label. That makes min-WIDTH matter as much as min-height: with
   the word gone the link was 14px wide, well under the site's 44px tap target,
   so the box is squared off and the margin above pulled in to compensate.
   The hover state has to move to the box as well, since there is no longer a
   text run to underline. */
.person-link{margin:.35rem 0 0}
.person-link a{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:44px;min-height:44px;margin-left:-10px;
  color:var(--ink-blue);text-decoration:none;border-radius:10px;
  transition:background .18s,color .18s;
}
.person-link a:hover{background:color-mix(in srgb,var(--g1) 12%,#fff);color:var(--blue-cta-dark)}
.person-link svg{flex:0 0 auto}

/* ── Contact ─────────────────────────────────────────────────────────────── */
/* The two columns share a top AND a bottom edge while they sit side by side.

   `align-items:start` used to size each column to its own content, so the form
   hung below the shorter trust panel. The fix is structural, not a margin
   nudge: from 60rem up the row stretches both cells to the same height, and
   the SHORTER column distributes its own contents to fill it (see .trust).
   Below 60rem the columns stack, so stretching is meaningless and it goes back
   to start; a stretched panel in a single column would just grow for nothing. */
.contact-grid{display:grid;gap:clamp(2rem,5vw,4rem);grid-template-columns:1fr;margin-top:3rem;align-items:start}
@media (min-width:60rem){
  .contact-grid{grid-template-columns:minmax(0,1.5fr) minmax(0,1fr);align-items:stretch}
  /* Rows: [name|email] [message] [send]. The MIDDLE row takes 1fr, so any
     slack between the two columns is absorbed by the textarea and the Send
     row stays pinned to the bottom. That is what makes the button's bottom
     edge, not just the form box's, sit level with the panel. Using
     align-content:start instead would park the slack under the button. */
  .form{grid-template-rows:auto 1fr auto}
  .form .field-wide textarea{flex:1 1 auto}
}
.form{display:grid;gap:1.4rem;grid-template-columns:1fr}
@media (min-width:38rem){.form{grid-template-columns:repeat(2,1fr)}}
.field{display:flex;flex-direction:column;gap:.5rem;min-width:0}
.field-wide{grid-column:1 / -1}
.field label{font-family:var(--mono);font-size:.74rem;letter-spacing:.06em;color:var(--text-muted)}
/* The asterisk marks required fields, so the one OPTIONAL field has to opt
   out of it, or the form says both 'optional' and '*' on the same label.
   .lbl-opt sits on the <label> itself because the marker has to be excluded
   from the parent, and a plain selector cannot look at a child. */
.field label:not(.lbl-opt)::after{content:' *';color:var(--ink-orange)}
/* Honeypot. Not display:none: some bots skip hidden inputs, and some browsers
   skip validating them. Pushed off-screen instead, with aria-hidden and
   tabindex -1 on the markup so no real visitor or screen reader can reach it. */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
/* Consent row. The checkbox gets a 24px box and the whole label is the target,
   so the tap area is the line, not the tick. */
.field label .opt{font-family:var(--mono);font-size:.72rem;letter-spacing:.04em;color:var(--text-muted);text-transform:none;font-weight:400}
.field input,.field select,.field textarea{font-family:var(--sans);font-size:1rem;color:var(--text-main);background:#fff;border:1px solid var(--border-strong);border-radius:10px;padding:.8rem .9rem;width:100%;min-height:44px;transition:border-color .15s,box-shadow .15s}
.field select{appearance:none;background-image:linear-gradient(45deg,transparent 50%,var(--text-muted) 50%),linear-gradient(135deg,var(--text-muted) 50%,transparent 50%);background-position:calc(100% - 18px) 1.25rem,calc(100% - 13px) 1.25rem;background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:2.5rem}
.field textarea{resize:vertical;line-height:1.6}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--ink-blue);box-shadow:0 0 0 3px rgba(34,116,180,.13)}

/* Consent row. Declared AFTER the generic .field input rule and with an
   attribute selector on purpose. `.field input{width:100%;padding:.8rem}` is
   (0,1,1) and sits below this block in source order, so a plain `.consent
   input` at the same specificity loses and the checkbox renders as a full
   width text box that shoves the label out of the form. `input[type=...]`
   is (0,2,1) and settles it. Same for the label, which would otherwise
   inherit the uppercase mono field-label styling. */
.consent{display:flex;align-items:flex-start;gap:.7rem;margin:0}
.consent input[type="checkbox"]{
  flex:0 0 auto;width:20px;height:20px;min-height:0;min-width:0;
  margin:.2rem 0 0;padding:0;border-radius:4px;accent-color:var(--blue-cta);
}
.consent label.lbl-opt{
  font-family:var(--sans);font-size:.92rem;font-weight:400;letter-spacing:0;
  text-transform:none;color:var(--text-body);line-height:1.6;cursor:pointer;max-width:52ch;
}
.consent a{color:var(--ink-blue)}
#e-consent{margin-top:.5rem}
.field[data-invalid] input,.field[data-invalid] select,.field[data-invalid] textarea{border-color:var(--ink-red)}
.err{font-family:var(--mono);font-size:.73rem;color:var(--ink-red);margin:0}
/* :empty is load-bearing for the column alignment. Until the form is
   submitted this paragraph has no text, and its 1rem top margin would still
   push the form's bottom edge a rem below the Send button. */
.form-status{font-family:var(--mono);font-size:.78rem;color:var(--text-muted);margin:1rem 0 0}
.form-status:empty{display:none}
/* En vuelo. Sin esto heredaba --text-muted, el mismo gris que un pie de campo:
   el mensaje que mas hay que ver era el mas apagado de los tres. 4.97 sobre
   blanco, y un color distinto del verde de exito y del rojo de error. */
.form-status[data-state="sending"]{color:var(--ink-blue)}
.form-status[data-state="ok"]{color:#0f766e}
.form-status[data-state="err"]{color:var(--ink-red)}
.trust{background:var(--bg-light);border:1px solid var(--border);border-radius:var(--r-lg);padding:clamp(1.5rem,3vw,2rem)}
@media (min-width:60rem){
  /* The panel is the shorter column, so it fills the row height: the list
     spreads its three items over whatever space is left and the contact block
     is pinned to the bottom, level with the foot of the Send button. */
  .trust{display:flex;flex-direction:column}
  .trust-list{flex:1 1 auto;display:flex;flex-direction:column;justify-content:space-between}
  .trust-meta{margin-top:auto;padding-top:1.5rem}
}
.trust-list{list-style:none;margin:0;padding:0}
.trust-list li{padding:.9rem 0;border-bottom:1px solid var(--border);font-size:.92rem;color:var(--text-body);display:flex;gap:.8rem}
.trust-list li:last-child{border-bottom:0}
.trust-list li::before{content:'✓';color:var(--ink-blue);font-family:var(--mono);flex:0 0 auto}
.trust-meta{font-family:var(--mono);font-size:.82rem;line-height:1.9;margin:1.5rem 0 0;color:var(--text-muted)}
.trust-meta a{color:var(--ink-blue)}

/* ── Footer ──────────────────────────────────────────────────────────────── */
.site-foot{background:var(--bg-dark);color:var(--text-inv);padding:clamp(3.25rem,6vw,4.5rem) 0 0}
.foot-in{display:grid;gap:2.5rem;grid-template-columns:1fr;padding-bottom:3rem}
@media (min-width:38rem){.foot-in{grid-template-columns:repeat(2,1fr)}}
@media (min-width:60rem){.foot-in{grid-template-columns:1.4fr 1fr 1fr 1fr}}
.foot-brand .brand-name,.foot-brand .logo-sub{color:#fff}
.foot-brand .logo-sub{color:var(--text-inv-dim)}
.foot-brand .kicker{font-family:var(--mono);font-size:.72rem;letter-spacing:.2em;text-transform:uppercase;color:#8ec9f5;margin:.9rem 0 0}
.foot-col{display:flex;flex-direction:column;gap:.7rem;align-items:flex-start}
.foot-h{font-family:var(--mono);font-size:.7rem;font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--text-inv-dim);margin:0 0 .3rem}
.foot-col a{font-size:.9rem;text-decoration:none;color:var(--text-inv);transition:color .15s}
.foot-col a:hover{color:#8ec9f5}
.foot-base{display:flex;flex-wrap:wrap;gap:1rem;justify-content:space-between;border-top:1px solid var(--border-dark);padding-block:1.5rem}
.foot-base p{font-family:var(--mono);font-size:.76rem;color:var(--text-inv-dim);margin:0}
.foot-base a{color:var(--text-inv-dim)}
.foot-base a:hover{color:#8ec9f5}

/* ── Reveal ──────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion:no-preference){
  .reveal{opacity:0;transform:translateY(18px);transition:opacity .6s cubic-bezier(.2,.7,.3,1),transform .6s cubic-bezier(.2,.7,.3,1)}
  .reveal.is-in{opacity:1;transform:none}
  .stats-grid .stat-item{opacity:0;transform:translateY(14px)}
  .stats-bar.is-in .stat-item{animation:statIn .55s cubic-bezier(.2,.7,.3,1) forwards;animation-delay:calc(var(--i) * 90ms)}
  @keyframes statIn{to{opacity:1;transform:none}}
}

@media (max-width:52rem){
  .burger{display:block}
  .head-cta{display:none}
  .nav{display:none;position:absolute;left:0;right:0;top:100%;flex-direction:column;gap:0;background:#fff;border-bottom:1px solid var(--border);padding:.5rem var(--gut) 1.2rem}
  .nav.is-open{display:flex}
  .nav a{padding:.9rem 0;border-bottom:1px solid var(--border)}
  .nav a:hover{border-bottom-color:var(--border)}
  .head-end{margin-left:auto}
  .logo-sub{display:none}
}

@media (max-width:34.99rem){
  .hero-actions .btn{width:100%;justify-content:center}
  .panels{min-height:0}
  .scroll-cue{display:none}
}

@media print{
  .reveal{opacity:1 !important;transform:none !important}
  .stats-grid .stat-item{opacity:1 !important;transform:none !important;animation:none !important}
  .panel[hidden]{display:block !important}
  .tabs,.site-head,.ticker,.burger,.lang,.skip,.form,.hero-bg,.scroll-cue{display:none}
  body{background:#fff;color:#000;font-size:11pt}
  .band,.site-foot{background:#fff;color:#000}
  .band h2,.band h3,.band-h,.band-p,.foot-h,.foot-base p{color:#333}
  .text-gradient,.stat-value,.stat-unit,.recon-v.is-after,.recon-arrow{
    -webkit-text-fill-color:#0f172a;color:#0f172a;background:none}
  /* The band prints white-on-white otherwise: browsers drop the gradient and
     the overlay, and every label in there is #fff. */
  .stats-bar{background:#fff;border-block:1px solid #ccc}
  .stats-bar::after{display:none}
  .stat-label{color:#333}
  .stat-divider{background:#ccc}
  .eyebrow::before{background:#0f172a}
  .panels{min-height:0}
  .sec{page-break-inside:avoid}
}


/* ── Legal pages ──────────────────────────────────────────────────────────
   Deliberately plainer than the marketing pages: one column, no gradients in
   the body, no motion. These are documents, and they have to stay readable
   when someone prints them or reads them on a phone in a hurry. The chrome
   (header, logo, language switch) is shared so they do not feel bolted on. */
.legal-page{background:var(--bg-white)}
/* The header is fixed on the main page and reveals the hero through it; here
   there is no hero, so it renders in its scrolled state from the start. */
.legal-page .site-head{position:sticky}
.legal-back{font-family:var(--mono);font-size:.78rem;color:var(--ink-blue);text-decoration:none;display:inline-flex;align-items:center;min-height:44px}
.legal-back:hover{text-decoration:underline}
@media (max-width:34.99rem){.legal-back{display:none}}

.legal{padding:clamp(2.5rem,6vw,4.5rem) 0 clamp(3.5rem,7vw,5.5rem)}
.legal h1{font-size:clamp(1.9rem,1.5rem + 1.8vw,2.8rem);letter-spacing:-.02em;margin-bottom:2.25rem}
.legal h2{font-size:1.12rem;letter-spacing:-.01em;margin:2.5rem 0 .85rem;padding-top:1.5rem;border-top:1px solid var(--border)}
.legal h2:first-of-type{border-top:0;padding-top:0;margin-top:0}
.legal p{color:var(--text-body);max-width:72ch;line-height:1.75}
.legal a{color:var(--ink-blue)}

.legal-list{margin:0 0 1.15em;padding-left:1.35rem;color:var(--text-body);max-width:72ch;line-height:1.75}
.legal-list li{margin-bottom:.5rem}

/* The identification block. dt/dd rather than a table: it is a set of labelled
   facts, and it has to collapse to one column on a phone without a scrollbar. */
.legal-id{display:grid;grid-template-columns:1fr;gap:.15rem .35rem;margin:0 0 1.5rem;max-width:72ch}
@media (min-width:38rem){.legal-id{grid-template-columns:11rem 1fr;gap:.6rem 1.5rem}}
.legal-id dt{font-family:var(--mono);font-size:.75rem;letter-spacing:.06em;text-transform:uppercase;color:var(--text-muted);padding-top:.15rem}
.legal-id dd{margin:0 0 .9rem;color:var(--text-main)}
@media (min-width:38rem){.legal-id dd{margin-bottom:0}}

/* Unfilled placeholders are made LOUD on purpose. A legal notice published
   with [BRACKETS] in it is worse than no legal notice, so they must be
   impossible to miss in review. Delete this class when the value goes in. */
.legal-todo{
  background:#fff4ed;border:2px dashed var(--ink-orange);border-radius:8px;
  padding:.7rem .9rem;color:var(--ink-orange) !important;font-family:var(--mono);
  font-size:.82rem;line-height:1.6;
}
.legal-updated{font-family:var(--mono);font-size:.8rem;color:var(--text-muted);margin-top:3rem;padding-top:1.5rem;border-top:1px solid var(--border)}

.legal-foot{border-top:1px solid var(--border);padding:2rem 0;background:var(--bg-light)}
.legal-foot-in{display:flex;flex-wrap:wrap;gap:1rem;justify-content:space-between;align-items:center}
.legal-foot p{font-family:var(--mono);font-size:.76rem;color:var(--text-muted);margin:0}
.legal-foot nav{display:flex;flex-wrap:wrap;gap:1.25rem}
.legal-foot a{font-family:var(--mono);font-size:.76rem;color:var(--ink-blue);text-decoration:none}
.legal-foot a:hover{text-decoration:underline}

@media print{
  .legal-page .site-head,.legal-foot nav{display:none}
  .legal h2{page-break-after:avoid}
  .legal-todo{border:2px solid #000;background:#fff;color:#000 !important}
}
