/* ── Hero ──────────────────────────────────────────────────────────────────
   One uncropped photograph, the copy resting on its lower left.

   Three deliberate departures from the Framer file, all in the type:

     · the title was set in a second display face, Clash Grotesk, while the
       rest of the page is Inter. It is Inter here, so the hero sounds like
       the site it opens;

     · it was indented 40px past the column — the title started at 72px and
       the paragraph under it at 32px, which read as a mistake rather than as
       an offset. One column now, one left edge, every line on it;

     · and the block sits on noticeably more air, top and bottom, so the
       photograph has somewhere to breathe behind it.
   ────────────────────────────────────────────────────────────────────────── */

/* ── The pin ───────────────────────────────────────────────────────────────
   The hero holds its place while the story slides up over it, and is let go
   the moment the pair has passed. position: sticky bounded by .opening does
   the whole thing: the hero sticks for exactly the length of the two sections
   and releases on its own, with no measurement to go stale and nothing to
   recalculate on a resize.

   .opening must not clip, or the sticky child has nothing to stick inside.
   ────────────────────────────────────────────────────────────────────────── */

.opening {
  position: relative;
  overflow: visible;
}

.hero {
  position: sticky;
  top: 0;
  /* Under the story, which carries its own ground and its own rounded lip. */
  z-index: 0;
  display: flex;
  align-items: flex-end;
  height: 100svh;
  padding-top: var(--nav-h);
  overflow: hidden;
  background: var(--hero-ground);
  isolation: isolate;
}

/* What the hero does while it is being covered: it settles back a little and
   the light goes out of it, so the story arrives over something receding
   rather than over a still photograph. js/hero.js scrubs these two. */
.hero__stage {
  position: absolute;
  inset: 0;
  z-index: -3;
  transform-origin: 50% 40%;
  will-change: transform, filter;
}

/* ── The photograph ────────────────────────────────────────────────────── */

.hero__bg {
  position: absolute;
  inset: 0;
  z-index: 1;
  /* The image inside this is deliberately larger than the frame — see the
     inset on .hero__bg-img — so the drift has somewhere to go. Without a clip
     here, that overhang simply hung outside the scrim, which is measured at
     inset: 0 on the stage. Scaling the stage down as the story covers it made
     the overhang plain: a 2% margin of raw, undimmed photograph around a
     dimmed one. The frame clips it now, and the scrim covers the frame
     exactly. */
  overflow: hidden;
}

.hero__bg-img {
  position: absolute;
  inset: -2% -2% -6%;
  /* A portrait photograph in a landscape frame: on a wide screen only a band
     of it shows, so the band is held on his face and folded arms (70% down)
     and he stays in the middle, clear of the copy in the lower left. */
  background: url("../assets/hero-quirofano.webp") 55% 70% / cover no-repeat;
  /* No starting offset. The lean existed to counter a sideways mask that is
     no longer there; on its own it was just a lurch. */
  will-change: transform;
}

/* On a phone the frame is taller than the photograph is, so all of it shows
   and his face lands exactly where the heading starts. Enlarged by a third and
   held to its bottom edge, the picture rides up: the face clears the copy and
   only the sign above the door is lost. */
@media (max-width: 47.99rem) {
  .hero__bg-img {
    background-size: auto 132%;
    background-position: 58% 100%;
  }
}

/* The scrim. Three layers, because the type sits in three different places
   and one gradient cannot serve all of them.

   Measured off the rendered page before this existed: the label above the
   title read 2.37:1 and the navbar's wordmark 3.89:1, both against the pale
   painting behind them. The paragraph lower down was already at 12.5:1 — the
   old scrim only did its job at the very bottom of the frame.

   So: a band under the bar, a diagonal that follows the copy into the lower
   left, and the original rise from the bottom. The diagonal is what keeps the
   photograph open — it darkens the corner the words are in and leaves his
   face and the wood on the right alone, which a stronger flat scrim would
   have flattened. */
.hero__stage::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  /* Two layers, not three.

     The diagonal that used to run across the middle was there to darken the
     corner the copy sits in — but it read as a grey wash laid over the left
     half of the photograph, which is the first thing anyone sees. The rise
     from the floor already covers the copy; the band at the top already
     covers the bar. The middle of the picture is now just the picture.

     The ink is deliberately warm and deliberately the same in both editions.
     The blue fork had this at rgba(8, 12, 30) — a navy — which tinted the
     whole photograph to match the palette. A palette should not colour a
     photograph of a person. */
  background:
    /* the bar's own ground */
    linear-gradient(to bottom,
      rgba(20, 18, 14, 0.50) 0%,
      rgba(20, 18, 14, 0.24) 11%,
      rgba(20, 18, 14, 0) 20%),
    /* and the rise from the floor, under the copy */
    linear-gradient(to top,
      rgba(20, 18, 14, 0.78) 0%,
      rgba(20, 18, 14, 0.56) 26%,
      rgba(20, 18, 14, 0.14) 58%,
      rgba(20, 18, 14, 0) 100%);
  pointer-events: none;
}

/* ── The column ────────────────────────────────────────────────────────── */

.hero__inner {
  position: relative;
  width: var(--measure);
  margin-inline: auto;
  /* The extra air the hero was asked for: the copy clears the bottom of the
     frame by a good deal more than it did, and the gutter is the page's. */
  padding: clamp(5rem, 12vh, 9rem) var(--gutter) clamp(4.5rem, 11vh, 8rem);
}

.hero__copy {
  max-width: 46rem;
  /* One left edge for the whole block. The title, the label above it, the
     paragraph and the action all start here — nothing is indented past
     anything else. */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
}

.hero__mask {
  display: block;
  overflow: hidden;
  /* Descenders below, and room on the right for the last glyph: the page is
     set on negative tracking, which is subtracted after the final character
     too, so a box sized to its own text is narrower than the ink in it. */
  padding: 0 0.12em 0.2em 0;
  margin: 0 -0.12em -0.2em 0;
}

.hero__eyebrow {
  margin: 0 0 clamp(1.1rem, 2.4vw, 1.6rem);
  font-size: var(--fs-meta);
  font-weight: 600;   /* the heaviest Inter loaded — 700 would fall back to this anyway */
  letter-spacing: normal;
  text-transform: uppercase;
  color: var(--cream);
  transform: translate3d(0, 110%, 0);
}

.hero__title {
  /* var(--sans): the page's own face, not a second display one. */
  margin: 0 0 clamp(1.25rem, 2.6vw, 1.85rem);
  font-family: var(--sans);
  font-size: var(--fs-display);
  font-weight: 500;
  line-height: 1.02;
  letter-spacing: var(--track-hero);
  color: var(--white);
}

.hero__tline {
  display: block;
  overflow: hidden;
  padding: 0 0.12em 0.2em 0;
  margin: 0 -0.12em -0.2em 0;
}

.hero__tin {
  display: block;
  transform: translate3d(0, 110%, 0);
  will-change: transform;
}

/* ── The title, letter by letter ───────────────────────────────────────────
   The Framer file animates its title one character at a time: the word sits
   in a mask of overflow: hidden, each letter is its own block starting 100px
   below the line, and they come up in sequence on a spring. js/hero.js cuts
   the letters; these are the boxes they come up through.

   Once cut, .hero__tin stops carrying the movement — the letters do — so it
   gives its own offset up, or the line would arrive perfectly into a box
   that is still a full line-height down. */
.hero__title[data-split] .hero__tin { transform: none; }

.hero__ch {
  display: inline-block;
  transform: translate3d(0, 100%, 0);
  opacity: 0;
  will-change: transform, opacity;
}

/* A space between words is not a letter and must not be collapsed by the
   inline-block boxes on either side of it. */
.hero__sp { display: inline-block; white-space: pre; }

/* ── The word that changes ─────────────────────────────────────────────────
   A vertical word swap, run letter by letter: the title holds "Vuelve a" and
   the last word sits in a fixed window, leaving through the top on a timer
   while the next one rises into its place. Each letter goes a beat after the
   one before it, so the change travels across the word rather than the whole
   word moving at once.

   The window is sized by the words themselves. Every word in the set is in
   the markup, invisible, all sharing one grid cell — so the box is as wide as
   the longest and exactly one line tall, with no measuring in script and
   nothing to re-measure when the webfont lands or the viewport changes. Its
   own overflow is the mask the words pass through.
   ────────────────────────────────────────────────────────────────────────── */

.swap {
  position: relative;
  display: inline-grid;
  overflow: hidden;
  /* Descender room, so a "g" is not clipped by the window it lives in. */
  padding-block: 0.12em;
  vertical-align: baseline;
}

.swap__size,
.swap__word {
  grid-area: 1 / 1;
  white-space: nowrap;
}

/* Present for layout, never seen. */
.swap__size { visibility: hidden; }

/* The letters. Each is its own box so it can travel a beat after the one
   before it; the word itself no longer moves. */
.swap__ch {
  display: inline-block;
  will-change: transform;
}

/* This line's mask is the swap window's own, and the window needs the room
   its padding gives it — so the line box must not clip it a second time. */
.hero__tline--swap {
  overflow: visible;
  padding-bottom: 0;
  margin-bottom: 0;
}

.hero__lede {
  max-width: 34rem;
  margin: 0 0 clamp(1.9rem, 4vw, 2.75rem);
  font-size: clamp(1rem, 1.45vw, 1.25rem);
  line-height: 1.5;
  letter-spacing: var(--track-body);
  color: var(--cream);
  opacity: 0;
  transform: translate3d(0, 1rem, 0);
}

.hero__actions {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.4vw, 1.75rem);
  flex-wrap: wrap;
}

/* ── The opinions ──────────────────────────────────────────────────────────
   Five stars and a count, under the call to action. It is a link, not a
   rating control: nothing on this page collects a score, it points at the
   register that already holds 107 of them.

   White rather than the gold a rating widget would reach for — the hero is
   type and photograph and nothing else, and the label beside the stars says
   plainly what they are.
   ────────────────────────────────────────────────────────────────────────── */

.hero__stars {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem clamp(0.7rem, 1.6vw, 1rem);
  flex-wrap: wrap;
  margin-top: clamp(1.4rem, 3vw, 2rem);
  text-decoration: none;
}

.hero__stars-row { display: inline-flex; gap: 0.3rem; }

.hero__star {
  width: 1.375rem;
  height: 1.375rem;
  flex: none;
  fill: var(--white);
  /* They sit on a photograph, so they carry their own edge. */
  filter: drop-shadow(0 2px 6px rgba(20, 18, 14, 0.45));
  will-change: transform;
}

.hero__stars-txt {
  font-size: var(--fs-meta);
  font-weight: 500;
  letter-spacing: var(--track-body);
  color: rgba(255, 255, 255, 0.82);
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.3);
  text-underline-offset: 0.2em;
  transition: text-decoration-color 240ms var(--ease);
}

.hero__stars:hover .hero__stars-txt { text-decoration-color: rgba(255, 255, 255, 0.85); }

/* ── Where he practises ────────────────────────────────────────────────────
   Two towns, under the stars. Shown on a phone only, where the paragraph that
   used to carry this is hidden — "can I reach him" is the question directly
   behind "can he help me", and the hero had stopped answering it.
   ────────────────────────────────────────────────────────────────────────── */

.hero__where {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin: clamp(1rem, 2.4vw, 1.4rem) 0 0;
  font-size: var(--fs-meta);
  font-weight: 600;          /* the heaviest Inter loaded — it has to be found at a glance */
  letter-spacing: var(--track-body);
  color: #fff;
}

.hero__where svg { width: 1rem; height: 1rem; flex: none; }

.dr-badge--hero { display: none; }   /* off at every width — the stars below already point at Doctoralia */

/* ── The licence numbers ───────────────────────────────────────────────────
   Against the right edge of the frame, reading down. Two facts a stranger can
   check against the SEP register — out of the copy's column, where they had
   been sitting between the call to action and everything below it.

   Absolute, so they hold the right edge whatever length the heading runs to;
   the column itself is left alone. Below 64rem there is no right edge to
   speak of and they go back into the flow.
   ────────────────────────────────────────────────────────────────────────── */

.hero__creds {
  position: absolute;
  right: var(--gutter);
  bottom: clamp(4.5rem, 11vh, 8rem);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
  gap: clamp(0.9rem, 2vw, 1.4rem);
  margin: 0;
}

.hero__cred dt {
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.72);
}

.hero__cred dd {
  margin: 0.2rem 0 0;
  font-size: var(--fs-ui);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--track-body);
  color: var(--white);
}

.hero__scroll {
  position: relative;
  color: var(--cream);
  font-size: var(--fs-ui);
  font-weight: 500;
  letter-spacing: var(--track-body);
  text-decoration: none;
}
.hero__scroll::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -0.35em;
  height: 1px;
  background: currentColor;
  transform-origin: 0 50%;
  transition: transform 0.35s var(--ease);
}
.hero__scroll:hover::after { transform: scaleX(0.3); }

/* Without JS nothing ever opens the masks, so nothing may start closed. The
   photograph is not among them any more — it is simply painted. */
.no-js .hero__bg-img { transform: none; }
.no-js .hero__eyebrow,
.no-js .hero__tin    { transform: none; }
.no-js .hero__ch     { transform: none; opacity: 1; }
.no-js .hero__lede,
.no-js .hero__actions,
.no-js .hero__creds,
.no-js .hero__stars { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .hero__bg-img { transform: none; }
  .hero__eyebrow,
  .hero__tin    { transform: none; }
  .hero__ch     { transform: none; opacity: 1; }
  .hero__lede,
  .hero__actions,
  .hero__creds,
  .hero__stars { opacity: 1; transform: none; }
  .hero__star { transform: none; opacity: 1; }
}

@media (max-width: 63.99rem) {
  .hero__creds {
    position: static;
    align-items: flex-start;
    text-align: left;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0.5rem clamp(1.5rem, 3.5vw, 2.75rem);
    margin-top: clamp(1.5rem, 3vw, 2.25rem);
  }
}

/* ── Short viewports ───────────────────────────────────────────────────────
   The pin needs the hero to be exactly one viewport tall, and a hero that is
   exactly one viewport tall clips its own copy when the viewport is a
   landscape phone. Below that height the hero gives the pin up and grows
   instead — the story then simply follows it, which is the same page without
   the transition rather than a broken one.
   ────────────────────────────────────────────────────────────────────────── */

@media (max-height: 33rem) {
  .hero {
    position: relative;
    height: auto;
    min-height: 100svh;
  }
}

/* Same reasoning for anyone who asked for less motion: no pin, no recede. */
@media (prefers-reduced-motion: reduce) {
  .hero {
    position: relative;
    height: auto;
    min-height: 100svh;
  }
  .about { border-top-left-radius: 0; border-top-right-radius: 0; }
}

/* ── Mobile ────────────────────────────────────────────────────────────────
   Three things go, and what is left is the whole of the offer: who he is,
   what he does, the one button, and two licence numbers.

   "Conóceme" scrolls to a section that is the next thing down the page
   anyway — on a phone it is a link to the swipe you were about to make. The
   paragraph and the Doctoralia row are both good, and both cost a screen's
   worth of a viewport where the heading and the button have to land together
   or neither is read.

   They are hidden, not removed: js/hero.js still tweens them, which costs
   nothing on an element that is not being laid out, and the markup stays one
   document across both widths.
   ────────────────────────────────────────────────────────────────────────── */

@media (max-width: 47.99rem) {
  .hero__lede,
  .hero__scroll { display: none; }

  /* The two calls to action stack, and both come down a tenth — two pills at
     hero size own more of a small screen than the heading above them does.

     They are also made the same width. Their heights already matched to a
     tenth of a pixel — 1rem of padding around a 1.6rem lockup is the same box
     as 1rem around a 1.0625rem line — but one carries a word mark and the
     other carries three words, so at their natural widths they read as two
     different sizes sitting on top of each other. Equal width, contents
     centred, capped so they do not stretch into bars on a small tablet. */
  .hero__actions {
    flex-direction: column;
    align-items: stretch;
    gap: 0.6rem;
  }

  .hero__actions > * {
    width: 100%;
    max-width: 20rem;
    justify-content: center;
  }

  .hero__actions .wa--lg {
    padding: calc(1rem * 0.9) calc(1.75rem * 0.9);
    font-size: calc(var(--fs-body) * 0.9);
  }

  /* The licence numbers move to the record in Sobre mí — see css/about.css. */
  .hero__creds { display: none; }
}
