/* ==========================================================================
   VEQLABS — Ernesto Pila Torres
   Grayscale. Single serif family. Mobile-first. Spanish default.
   ========================================================================== */

:root{
  /* black → white, nothing in between but gray */
  --ink:        #121212;   /* near-black: text, rules, the contact band */
  --paper:      #FBFBFA;   /* near-white canvas */
  --wash:       #EFEFEE;   /* light gray panel */
  --muted:      #5A5A58;   /* secondary text on paper */
  --muted-dk:   #ABABA8;   /* secondary text on ink */
  --hair:       rgba(18,18,18,.16);
  --hair-lt:    rgba(251,251,250,.20);

  --measure:    640px;
  --gutter:     clamp(20px, 5.6vw, 34px);
  --section:    clamp(58px, 11vw, 92px);

  --ease:       cubic-bezier(.16,.84,.44,1);
  --serif:      "Source Serif 4", Georgia, "Times New Roman", Times, serif;
}

/* ---------- reset ---------- */
*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; }
body,h1,h2,p,ol,li,dl,dd,dt,figure{ margin:0; padding:0; }
ol{ list-style:none; }
img{ display:block; max-width:100%; height:auto; }
b{ font-weight:600; }

body{
  background:var(--paper);
  color:var(--ink);
  font-family:var(--serif);
  font-size:18px;
  line-height:1.66;
  font-weight:400;
  font-optical-sizing:auto;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}

/* ---------- language switching ---------- */
html[data-lang="es"] [lang="en"]{ display:none !important; }
html[data-lang="en"] [lang="es"]{ display:none !important; }

/* ---------- layout ---------- */
.wrap{
  width:100%;
  max-width:calc(var(--measure) + var(--gutter) * 2);
  margin-inline:auto;
  padding-inline:var(--gutter);
}
.band{ padding-block:var(--section); }

/* ==========================================================================
   MASTHEAD
   ========================================================================== */
.masthead{
  border-bottom:1px solid var(--ink);
  padding-block:18px;
}
.masthead-inner{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:16px;
}
.lockup{ display:flex; align-items:center; gap:13px; min-width:0; }
.mark{
  width:44px; height:44px;
  border-radius:10px;
  flex:none;
}
.wordmark{
  font-size:15px;
  font-weight:600;
  letter-spacing:.26em;
  text-transform:uppercase;
  line-height:1;
  padding-top:2px;
}

/* language toggle */
.langtoggle{ display:flex; align-items:center; gap:2px; flex:none; }
.langbtn{
  position:relative;
  appearance:none;
  background:none;
  border:0;
  font-family:var(--serif);
  font-size:15px;
  font-weight:600;
  letter-spacing:.14em;
  color:var(--muted);
  padding:11px 10px;
  min-height:44px;
  cursor:pointer;
  transition:color .26s var(--ease);
}
/* the active marker grows out of the centre instead of snapping on */
.langbtn::after{
  content:"";
  position:absolute;
  left:9px; right:9px; bottom:10px;
  height:2px;
  background:var(--ink);
  transform:scaleX(0);
  transform-origin:center;
  transition:transform .34s var(--ease);
}
.langbtn[aria-pressed="true"]{ color:var(--ink); }
.langbtn[aria-pressed="true"]::after{ transform:scaleX(1); }
.langbtn:hover{ color:var(--ink); }
.langsep{
  width:1px; height:14px;
  background:var(--hair);
  display:block;
}

/* ==========================================================================
   HERO
   ========================================================================== */
.hero{ padding-top:clamp(38px,9vw,60px); padding-bottom:clamp(46px,9vw,66px); }

/* Two true columns at every width: portrait left, ALL the hero text in its
   own column on the right. Nothing wraps underneath the photo, so the text
   keeps one consistent measure from the name down to the service area.
   The photo column is shorter than the text column; that whitespace beneath
   it is intentional and is what makes the block read as a single unit. */
.hero-grid{
  display:grid;
  grid-template-columns:clamp(96px, 29vw, 132px) 1fr;
  gap:16px;
  align-items:start;
}

/* The photo is never cropped. It keeps its native 4:5 proportions at every
   size, and the text beside it is sized to come as close as possible to the
   same height rather than the photo being reshaped to match the text. */
.portrait{
  width:100%;
  border-radius:10px;
  overflow:hidden;      /* clips the load scale-in */
  background:var(--wash);
}
.portrait img{ width:100%; height:auto; }

h1{
  font-size:clamp(24px, 6.4vw, 29px);
  font-weight:600;
  line-height:1.1;
  letter-spacing:-.012em;
  text-wrap:balance;
}

/* Held flat at 17px on phones rather than scaling up. Against a name at
   24-29px that keeps a clear step in the hierarchy, and it stops the text
   block from outweighing the photo beside it. 17px is the floor for this
   audience, so it does not go lower. */
.lead{
  font-size:17px;
  line-height:1.5;
  margin-top:12px;
  text-wrap:pretty;
}

/* Sits below the photo/text block at full width rather than inside the text
   column. Keeping it in the column pushed the text well past the bottom of an
   uncropped photo; out here it reads as a caption on the whole block. */
.area{
  font-size:16px;
  line-height:1.5;
  color:var(--muted);
  margin-top:16px;
}

/* ---------- actions ---------- */
.actions{
  display:flex;
  flex-direction:column;
  gap:12px;
  margin-top:30px;
}
.btn{
  position:relative;
  overflow:hidden;
  display:flex;
  align-items:center;
  justify-content:center;
  min-height:58px;
  padding:14px 22px;
  border-radius:4px;
  font-family:var(--serif);
  font-size:18px;
  font-weight:600;
  text-decoration:none;
  text-align:center;
  border:1.5px solid transparent;
  transition:color .3s var(--ease), border-color .3s var(--ease), transform .12s var(--ease);
  -webkit-tap-highlight-color:transparent;
  touch-action:manipulation;
}
/* the wipe that fills an outline button on hover */
.btn::before{
  content:"";
  position:absolute;
  inset:0;
  transform:scaleY(0);
  transform-origin:bottom center;
  transition:transform .4s var(--ease);
}
.btn > span{ position:relative; }
.btn:active{ transform:scale(.985); }

.btn-primary{ background:var(--ink); color:var(--paper); border-color:var(--ink); }
.btn-primary::before{ background:#000; }
.btn-primary:hover::before{ transform:scaleY(1); }

.btn-secondary{ background:transparent; color:var(--ink); border-color:var(--ink); }
.btn-secondary::before{ background:var(--ink); }
.btn-secondary:hover{ color:var(--paper); }
.btn-secondary:hover::before{ transform:scaleY(1); }

.btn-ghost{ background:transparent; color:var(--paper); border-color:rgba(251,251,250,.55); }
.btn-ghost::before{ background:var(--paper); }
.btn-ghost:hover{ color:var(--ink); border-color:var(--paper); }
.btn-ghost:hover::before{ transform:scaleY(1); }

/* ==========================================================================
   SECTION FURNITURE
   ========================================================================== */
.rule{
  position:relative;
  padding-top:15px;
  margin-bottom:26px;
}
.rule::before{
  content:"";
  position:absolute;
  top:0; left:0; right:0;
  height:1px;
  background:var(--ink);
  transform-origin:left center;
}
.bars{
  width:22px; height:15px;
  display:block;
  fill:var(--ink);
}
.bars-light{ fill:var(--muted-dk); margin-bottom:22px; }

.eyebrow{
  font-size:13px;
  font-weight:600;
  letter-spacing:.28em;
  color:var(--muted);
  margin-bottom:10px;
}
.eyebrow-light{ color:var(--muted-dk); }

h2{
  font-size:clamp(27px, 6.6vw, 33px);
  font-weight:600;
  line-height:1.18;
  letter-spacing:-.01em;
  margin-bottom:30px;
  text-wrap:balance;
}

/* ==========================================================================
   02 · STEPS
   ========================================================================== */
.steps{ counter-reset:step; }
.steps li{
  counter-increment:step;
  display:grid;
  grid-template-columns:40px 1fr;
  gap:0 16px;
  padding-block:22px;
  border-top:1px solid var(--hair);
}
.steps li:last-child{ border-bottom:1px solid var(--hair); }
.steps li::before{
  content:counter(step,decimal-leading-zero);
  font-size:15px;
  font-weight:600;
  letter-spacing:.06em;
  color:var(--muted);
  font-variant-numeric:tabular-nums lining-nums;
  padding-top:6px;
}
.steps p{ grid-column:2; }

/* ==========================================================================
   03 · PRICE
   ========================================================================== */
.pricecard{
  border:1.5px solid var(--ink);
  background:var(--paper);
  box-shadow:6px 6px 0 var(--ink);
  margin-bottom:34px;
}
.price{
  padding:26px 24px 24px;
  display:flex;
  flex-wrap:wrap;
  align-items:baseline;
  gap:2px 14px;
}
.figure{
  font-size:clamp(54px, 14.5vw, 70px);
  font-weight:700;
  line-height:.92;
  letter-spacing:-.028em;
  font-variant-numeric:tabular-nums lining-nums;
}
.terms{
  font-size:17px;
  line-height:1.35;
  color:var(--muted);
}
.guarantee{
  border-top:1.5px solid var(--ink);
  background:var(--wash);
  padding:22px 24px 24px;
}
.guarantee p{ font-size:17.5px; line-height:1.58; }
.refund{
  font-size:1.34em;
  font-weight:700;
  letter-spacing:-.015em;
  font-variant-numeric:tabular-nums lining-nums;
  white-space:nowrap;
  box-shadow:inset 0 -2px 0 var(--ink);
}

.notes p{
  padding-block:18px;
  border-top:1px solid var(--hair);
  color:var(--muted);
  font-size:17.5px;
}
/* the last ES and EN paragraphs are the final two children; exactly one is
   ever visible, so both carry the closing rule */
.notes p:nth-last-child(1),
.notes p:nth-last-child(2){ border-bottom:1px solid var(--hair); }

/* ==========================================================================
   04 · WHO I AM
   ========================================================================== */
.band-wash{
  background:var(--wash);
  border-top:1px solid var(--ink);
  border-bottom:1px solid var(--ink);
}
.band-wash h2{ margin-bottom:26px; }

.confession p{ margin-top:20px; font-size:18px; }
/* children 1 and 2 are the ES/EN opening statements; whichever shows is first */
.confession > p:nth-child(1),
.confession > p:nth-child(2){ margin-top:0; }

.confession .statement{
  font-size:clamp(20px, 4.9vw, 23px);
  line-height:1.48;
  text-wrap:pretty;
}
.confession .closer{
  margin-top:30px;
  padding-top:22px;
  border-top:1.5px solid var(--ink);
  font-size:clamp(19px, 4.6vw, 21px);
  font-weight:600;
  line-height:1.42;
}

/* ==========================================================================
   05 · CONTACT (full-bleed ink)
   ========================================================================== */
.band-ink{
  background:var(--ink);
  color:var(--paper);
}
.band-ink h2{ color:var(--paper); }

.contact{ margin-bottom:30px; }
.contact-row{
  padding-block:18px;
  border-top:1px solid var(--hair-lt);
}
.contact-row:last-child{ border-bottom:1px solid var(--hair-lt); }
.contact dt{
  font-size:13px;
  font-weight:600;
  letter-spacing:.22em;
  text-transform:uppercase;
  color:var(--muted-dk);
  margin-bottom:7px;
}
.contact dd a{
  position:relative;
  font-size:clamp(21px, 5.4vw, 25px);
  font-weight:600;
  letter-spacing:-.01em;
  color:var(--paper);
  text-decoration:none;
  border-bottom:1.5px solid var(--muted-dk);
  padding-bottom:2px;
  display:inline-block;
  word-break:break-word;
}
/* a brighter rule sweeps across the muted one on hover */
.contact dd a::after{
  content:"";
  position:absolute;
  left:0; right:0; bottom:-1.5px;
  height:1.5px;
  background:var(--paper);
  transform:scaleX(0);
  transform-origin:left center;
  transition:transform .45s var(--ease);
}
.contact dd a:hover::after{ transform:scaleX(1); }

/* LinkedIn is corroboration, not one of the two actions, so it sits a step
   quieter than the phone and email above it. Sized to fit the full path on a
   375px screen without wrapping, since a visible, complete URL is the whole
   point of putting it on a page like this. */
.contact-row.is-social dd a{
  font-size:clamp(16px, 3.8vw, 18px);
  letter-spacing:0;
}

.invite{
  color:var(--muted-dk);
  font-size:17.5px;
  margin-bottom:28px;
  max-width:52ch;
}

.band-ink .actions{ margin-top:0; }

.colophon{
  margin-top:44px;
  padding-top:20px;
  border-top:1px solid var(--hair-lt);
  font-size:12.5px;
  font-weight:600;
  letter-spacing:.22em;
  text-transform:uppercase;
  color:var(--muted-dk);
}

/* ==========================================================================
   FOCUS
   ========================================================================== */
:focus-visible{
  outline:3px solid var(--ink);
  outline-offset:3px;
}
.band-ink :focus-visible{ outline-color:var(--paper); }

/* ==========================================================================
   MOTION

   Two systems, both fail-safe:

   1. Hero load-in — pure CSS animation, always plays, needs no JS.
   2. Section reveals — only armed when main.js adds .js-anim to <html>,
      which it does only if IntersectionObserver exists and the visitor
      has not asked for reduced motion. Without that class every rule
      below is inert and the page renders fully visible.

   Only opacity, transform and clip-path are animated, so the compositor
   handles all of it and nothing triggers layout.
   ========================================================================== */

/* ---------- 1 · hero load-in ---------- */
.reveal{
  opacity:0;
  animation:rise .72s var(--ease) forwards;
  animation-delay:var(--d,0ms);
}
@keyframes rise{
  from{ opacity:0; transform:translate3d(0,16px,0); }
  to  { opacity:1; transform:none; }
}

/* The portrait frame fades while the photo inside eases out of a slight
   push-in, clipped by the rounded corners. Ends at exactly scale 1 so the
   final render stays sharp. */
.portrait.reveal{ animation-name:fade; animation-duration:.9s; }
@keyframes fade{ from{ opacity:0; } to{ opacity:1; } }

.portrait.reveal img{
  animation:settle 1.15s var(--ease) both;
  animation-delay:var(--d,0ms);
}
@keyframes settle{
  from{ transform:scale(1.06); }
  to  { transform:none; }
}

/* ---------- 2 · section reveals ---------- */
html.js-anim .r{
  opacity:0;
  transform:translate3d(0,14px,0);
  transition:opacity .72s var(--ease) var(--d,0ms),
             transform .72s var(--ease) var(--d,0ms);
}
html.js-anim .band.in .r{ opacity:1; transform:none; }

/* section hairline draws left to right */
html.js-anim .rule::before{
  transform:scaleX(0);
  transition:transform .9s var(--ease);
}
html.js-anim .band.in .rule::before{ transform:scaleX(1); }

/* the three logo bars stagger in behind it */
html.js-anim .bars path{
  opacity:0;
  transform:translateX(-5px);
  transition:opacity .5s var(--ease), transform .5s var(--ease);
}
html.js-anim .band.in .bars path{ opacity:1; transform:none; }
html.js-anim .band.in .bars path:nth-child(1){ transition-delay:240ms; }
html.js-anim .band.in .bars path:nth-child(2){ transition-delay:310ms; }
html.js-anim .band.in .bars path:nth-child(3){ transition-delay:380ms; }

/* the price card's offset slab slides out from under the card */
html.js-anim .pricecard{
  box-shadow:0 0 0 var(--ink);
  transition:box-shadow .75s var(--ease) .18s,
             opacity .72s var(--ease) var(--d,0ms),
             transform .72s var(--ease) var(--d,0ms);
}
html.js-anim .band.in .pricecard{ box-shadow:6px 6px 0 var(--ink); }

/* $750 wipes upward from its own baseline */
html.js-anim .figure{
  clip-path:inset(100% 0 0 0);
  transition:clip-path .85s var(--ease) .3s;
}
html.js-anim .band.in .figure{ clip-path:inset(0 0 0 0); }

/* ---------- 3 · language swap ---------- */
/* main.js fades <main> down, flips the language while it is invisible, then
   fades it back. Exit is roughly half the entry duration so the switch feels
   responsive rather than sluggish. Both states are inert without .js-anim,
   in which case the swap is instant. */
html.js-anim .swap{
  opacity:1;
  transform:none;
  transition:opacity .34s var(--ease), transform .34s var(--ease);
}
html.js-anim.swapping .swap{
  opacity:0;
  transform:translate3d(0,5px,0);
  transition:opacity .17s var(--ease), transform .17s var(--ease);
}

/* ---------- opt out ---------- */
@media (prefers-reduced-motion:reduce){
  .reveal{ animation:none; opacity:1; transform:none; }
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-delay:0ms !important;
    transition-duration:.001ms !important;
    transition-delay:0ms !important;
  }
}

/* ==========================================================================
   BREAKPOINTS
   ========================================================================== */

/* wider phones: side-by-side buttons */
@media (min-width:460px){
  .actions{ flex-direction:row; }
  .actions .btn{ flex:1 1 0; }
}

/* Tablet and up: editorial two-column hero.
   560px rather than 640 so the grid takes over before the width band where
   the floated layout would strand a single line again. */
@media (min-width:560px){
  body{ font-size:18.5px; }

  /* same two columns, just wider; native 4:5 portrait, no stretching */
  .hero-grid{
    grid-template-columns:196px 1fr;
    gap:32px;
    align-items:start;
  }
  .portrait{ max-height:none; border-radius:12px; }
  .portrait img{ height:auto; object-fit:fill; }
  h1{
    margin-top:-6px;
    font-size:clamp(40px, 5.6vw, 54px);
  }
  .lead{ font-size:clamp(19px, 4.4vw, 21px); margin-top:18px; }
  .area{ font-size:17px; margin-top:14px; }

  .mark{ width:48px; height:48px; border-radius:11px; }

  /* deeper offset on desktop; the .js-anim selector is more specific than a
     bare .pricecard rule, so the animated end state must be restated here */
  .pricecard,
  html.js-anim .band.in .pricecard{ box-shadow:9px 9px 0 var(--ink); }
  .price{ padding:32px 30px 28px; }
  .guarantee{ padding:26px 30px 30px; }

  .steps li{ grid-template-columns:54px 1fr; padding-block:24px; }

  .contact{
    display:grid;
    grid-template-columns:1fr 1fr;
    gap:0 30px;
  }
  /* side by side, so every row needs its own closing rule */
  .contact-row{ border-bottom:1px solid var(--hair-lt); }
  /* phone and email pair off; LinkedIn spans beneath them rather than being
     stranded alone in the left column */
  .contact-row.is-social{ grid-column:1 / -1; }
}

/* desktop: paper grain, invisible on phones */
@media (min-width:760px){
  body::after{
    content:"";
    position:fixed;
    inset:0;
    z-index:9;
    pointer-events:none;
    opacity:.035;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
  }
}
