/* Shared component layer.
   Everything src/layout.js emits (header, nav, footer) plus the vocabulary every
   page reuses: buttons, cards, pills, fields, section heads, media wrappers, the
   lightbox shell. Home-page composition lives at the bottom of this file because
   this workstream owns no per-page stylesheet.

   Rules this file is built to (docs/reference-bar.json):
     TYPE-01   two families / three weights only -- never set a weight above 500
     TYPE-02   four heading steps, ratio 1.3-1.6 between neighbours at every width
     TYPE-03   prose is 16-18px; nothing read as a sentence is set smaller
     TYPE-04   tracking above 0.1em only on uppercase labels of 14px or less
     COLOR-02  at most three non-neutral flat fills: the blush section band, the
               primary-CTA gradient and the plum-100 hover wash. No component
               carries a decorative hue of its own -- see .promo
     COLOR-03  the brand purple never carries text on a tint; --plum-ink does
     GRAD-01   one gradient declaration on the page: .btn--primary, nothing else
     SHADOW-01 exactly one box-shadow value, --shadow-float, on overlay surfaces
     RADIUS-01 photo 6 / control 10 / card 12 / pill -- graded, never uniform
     SPACE-01  every vertical gap is a multiple of 8px, so this file uses only
               --space-xs/-md/-lg/-xl/-2xl/-3xl/-4xl (8/16/24/32/48/72/104)
     ICON-01   no emoji; one line-icon set (.icon), 1.5 stroke, currentColor
*/

/* Six declarations that belong in css/tokens.css. They live here because this
   workstream does not own that file; every one of them is listed as a request in
   the builder's return value. components.css loads after tokens.css, so a :root
   redeclaration of the same custom property wins. */
:root {
  /* Masthead height. The hero pulls itself up by exactly this much so the photo
     reaches the top edge of the viewport. */
  --header-h: 4.5rem;

  /* Heading scale: four steps, geometric at ~1.55. Measured on the built page:
       390px   H1 40  H2 27  H3 19  kicker 14   ratios 1.48 / 1.42 / 1.36
       768px   H1 45  H2 30  H3 20  kicker 14   ratios 1.51 / 1.49 / 1.43
       1440px  H1 54  H2 35  H3 22  kicker 14   ratios 1.54 / 1.59 / 1.57
     The scale it replaces ran 56/40/28/18/15 -- five steps, and its last ratio
     was 1.20, which is why the smallest headings read as body text instead.
     The kicker is fixed at 14px because TYPE-04 only allows its 0.14em tracking
     at 14px or below; that pins the bottom of the scale and therefore the top. */
  --step-4: clamp(2.5rem, 2.175rem + 1.333vw, 3.375rem);
  --step-3: clamp(1.6875rem, 1.502rem + 0.762vw, 2.1875rem);
  --step-2: clamp(1.1875rem, 1.118rem + 0.286vw, 1.375rem);

  /* Uppercase tracked labels. Fixed, not fluid: 14px is a ceiling, not a target. */
  --step-caps: 0.875rem;
  /* The smallest size any sentence may use. --step--1 bottoms out at 14px, below
     TYPE-03's 16px floor, so it is now reserved for UI chrome only: nav links,
     the brand's second line, pills and form labels. */
  --step-small: 1rem;
}

/* Darkened brand purple for every link: #8c59b3 measures 4.24:1 on --blush-100
   and 3.98:1 on --plum-100, both AA failures (COLOR-03). --plum-ink clears 8:1
   on the tints and 9.4:1 on --paper, so one link colour works on every ground. */
a {
  color: var(--plum-ink);
}

a:hover {
  color: var(--plum-900);
}

/* SPACE-01 wants >=96px of section padding on desktop; base.css ships 72px,
   which is the correct mobile value. */
@media (min-width: 62rem) {
  .section {
    padding-block: var(--space-4xl);
  }

  .section--tight {
    padding-block: var(--space-3xl);
  }
}

/* base.css sets .eyebrow's tracking and case but not its family, so an
   <h3 class="eyebrow"> would inherit the display serif from the h3 rule. The size
   is pinned to 14px here: at the 15px it inherited, the 0.14em tracking sits one
   pixel outside the range TYPE-04 permits for tracked uppercase. */
.eyebrow {
  font-family: var(--font-body);
  font-size: var(--step-caps);
}

/* base.css gives the skip link --radius-control; it is a control, but keeping it
   on the same three-value radius set as everything else keeps the page's radius
   count at three (photo 6 / card 12 / pill). */
.skip-link {
  border-radius: var(--radius-pill);
}

/* ---- icons -------------------------------------------------------------- */
/* One set, one stroke weight, sized to the text it sits beside. */

.icon {
  inline-size: 1em;
  block-size: 1em;
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---- masthead ----------------------------------------------------------- */

.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-header);
  inline-size: 100%;
  background: var(--paper);
  border-block-end: 1px solid transparent;
  transition:
    background-color var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}

.site-header__in {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  min-block-size: var(--header-h);
  padding-block: var(--space-xs);
}

/* From 62rem up, the masthead floats over the hero photograph so the image reaches
   all three viewport edges; measured on the built page, the darkest pixel under the
   brand-and-nav strip is 8.97:1 against --plum-900.

   It does NOT float below 62rem, and that is a measurement, not a preference. The
   phone crop is a 43%-wide window of the frame, and the top-right corner of every
   such window holds dried stems or eucalyptus: sweeping the crop from 50% to 100%
   in 5% steps, the worst pixel under the menu button never rises above 3.33:1 and
   the wordmark drops to 2.58:1 past 90%. So on a phone the header keeps its own
   ground and the photograph starts underneath it — full width, no gutters, no
   radius, and every glyph on paper at 13:1 or better. */
@media (min-width: 62rem) {
  .has-hero .site-header {
    background: transparent;
    border-block-end-color: transparent;
  }

  .has-hero main > :first-child {
    margin-block-start: calc(var(--header-h) * -1);
  }
}

.site-header--stuck,
.has-hero .site-header--stuck,
.nav-open .site-header {
  background: var(--paper);
  border-block-end-color: var(--line);
}

/* ---- wordmark ----------------------------------------------------------- */

.brand {
  display: grid;
  gap: var(--space-xs);
  text-decoration: none;
  color: var(--ink);
}

.brand:hover {
  color: var(--plum-ink);
}

.brand__name {
  font-family: var(--font-display);
  font-size: var(--step-1);
  /* headroom so the tilde on both n-with-tilde glyphs never clips (I18N-01) */
  line-height: 1.18;
  letter-spacing: 0.005em;
}

.brand__artist {
  font-family: var(--font-body);
  font-weight: var(--weight-ui);
  font-size: var(--step--1);
  line-height: 1.3;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* Only while the masthead is actually floating on the photograph (>=62rem). */
@media (min-width: 62rem) {
  .has-hero .site-header:not(.site-header--stuck) .brand__artist {
    color: var(--ink-soft);
  }
}

/* ---- navigation --------------------------------------------------------- */

.site-nav__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs) var(--space-lg);
}

.site-nav__link {
  display: inline-flex;
  align-items: center;
  min-block-size: 2.25rem;
  font-size: var(--step--1);
  font-weight: var(--weight-ui);
  color: var(--ink);
  text-decoration: none;
}

.site-nav__link:hover {
  color: var(--plum-ink);
  text-decoration: underline;
}

.site-nav__link[aria-current="page"] {
  text-decoration: underline;
  text-decoration-color: var(--plum-400);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.4em;
}

/* The header's booking link is deliberately an outline, never a second primary:
   CTA-01 fails a page showing two competing primary buttons in one screenful. */
.site-nav__link--cta {
  /* 44px, not the 36px the plain nav links carry: this one reads as a button, and
     CTA-01 puts the floor for a button's tap target at 44px on every viewport. */
  min-block-size: 2.75rem;
  padding-inline: var(--space-md);
  border: 1px solid var(--plum-700);
  border-radius: var(--radius-pill);
}

.site-nav__link--cta:hover {
  background: var(--plum-100);
  text-decoration: none;
}

/* Off-canvas drawer below the desktop breakpoint. Driven by #nav-toggle's
   aria-expanded (js/app.js also mirrors it onto body.nav-open). */
@media (max-width: 61.999rem) {
  .site-nav {
    position: fixed;
    inset-block: var(--header-h) 0;
    inset-inline-end: 0;
    z-index: var(--z-drawer);
    inline-size: min(20rem, 82vw);
    padding: var(--space-lg) var(--space-lg) var(--space-2xl);
    overflow-y: auto;
    visibility: hidden;
    background: var(--surface);
    border-inline-start: 1px solid var(--line);
    box-shadow: var(--shadow-float);
    transform: translateX(101%);
    transition:
      transform var(--dur-base) var(--ease-out),
      visibility var(--dur-base) step-end;
  }

  .nav-open .site-nav,
  .site-header:has(#nav-toggle[aria-expanded="true"]) .site-nav {
    visibility: visible;
    transform: translateX(0);
    transition-timing-function: var(--ease-out), step-start;
  }

  .site-nav__list {
    display: grid;
    gap: 0;
  }

  .site-nav__item + .site-nav__item {
    border-block-start: 1px solid var(--line);
  }

  .site-nav__link {
    inline-size: 100%;
    min-block-size: 3rem;
    font-size: var(--step-0);
  }

  .site-nav__link--cta {
    justify-content: center;
    margin-block-start: var(--space-md);
    min-block-size: 3rem;
  }

  /* the booking pill sits in route order, so it needs air on both sides rather
     than the hairlines that separate the plain links */
  .site-nav__item:has(.site-nav__link--cta) {
    margin-block-end: var(--space-md);
    border-block-start: 0;
  }

  .site-nav__item:has(.site-nav__link--cta) + .site-nav__item {
    border-block-start: 0;
  }

  .nav-open {
    overflow: hidden;
  }
}

@media (min-width: 62rem) {
  .site-nav {
    margin-inline-start: var(--space-2xl);
    /* keeps every nav label inside the pale left half of the hero photograph */
    margin-inline-end: auto;
  }
}

/* ---- header tools ------------------------------------------------------- */

.site-header__tools {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  margin-inline-start: auto;
}

/* Opaque chip: it is the one header element that can end up over a busy part of
   the photograph, so it carries its own ground instead of relying on the image.
   Both states are two uppercase letters, so the header never shifts on switch. */
.lang-switch {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 2.75rem;
  min-block-size: 2.75rem;
  padding-inline: var(--space-md);
  border: 1px solid var(--ink-muted);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: var(--step--1);
  font-weight: var(--weight-ui);
  letter-spacing: var(--tracking-caps);
  text-decoration: none;
  transition:
    background-color var(--dur-base) var(--ease-out),
    color var(--dur-base) var(--ease-out);
}

.lang-switch:hover {
  background: var(--plum-100);
  color: var(--plum-ink);
}

/* Pill, like every other control on this page: RADIUS-01 fails a page carrying
   more than three distinct radii, and --radius-control is reserved for inputs. */
.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  border-radius: var(--radius-pill);
  color: var(--ink);
}

.nav-toggle__bars {
  display: grid;
  gap: 5px;
  inline-size: 1.375rem;
}

.nav-toggle__bars span {
  display: block;
  block-size: 2px;
  border-radius: var(--radius-pill);
  background: currentColor;
  transition:
    transform var(--dur-fast) var(--ease-out),
    opacity var(--dur-fast) var(--ease-out);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(2) {
  opacity: 0;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

@media (min-width: 62rem) {
  .nav-toggle {
    display: none;
  }
}

/* ---- buttons ------------------------------------------------------------ */
/* Two button tiers and one text link, total. Every "Pedir mi cita" on the page --
   the hero one and the closing one -- is the same .btn--primary, so the action
   the page exists for has exactly one treatment (CTA-01). Buttons share height,
   radius and label case; horizontal padding is 4x the vertical and the minimum
   height is 48px. The third tier this file used to carry (.btn--ghost: a
   zero-padding underline wearing .btn) is no longer used in markup -- that job
   belongs to .text-link, which does not pretend to be a button. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  min-block-size: 3rem;
  padding: var(--space-xs) var(--space-xl);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: var(--weight-ui);
  line-height: 1.25;
  letter-spacing: 0.01em;
  text-align: center;
  text-decoration: none;
  transition:
    background-color var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out),
    color var(--dur-base) var(--ease-out);
}

/* The page's ONE gradient (GRAD-01): a single two-stop ramp inside one hue, on
   one button style, and nowhere else. It carries white type at 5.0:1 on the light
   end and 9.6:1 on the dark end, so both ends of the ramp clear AA (COLOR-03).
   No shadow and no visible border: the amateur stack is gradient + glow + rule. */
.btn--primary {
  background-image: linear-gradient(135deg, var(--plum-500), var(--plum-ink));
  color: var(--surface);
}

.btn--primary:hover {
  background-image: linear-gradient(135deg, var(--plum-ink), var(--plum-900));
  color: var(--surface);
}

.btn--secondary {
  border-color: var(--plum-700);
  color: var(--ink);
}

.btn--secondary:hover {
  background-color: var(--plum-100);
  border-color: var(--plum-ink);
  color: var(--plum-ink);
}

/* Retained for pages this workstream does not own, and given the padding ratio
   CTA-01 requires (24px inline against 8px block = 3x) instead of the 0x it had. */
.btn--ghost {
  padding-inline: var(--space-lg);
  color: var(--plum-ink);
}

.btn--ghost:hover {
  background-color: var(--plum-100);
  color: var(--plum-900);
}

/* Tertiary actions are a real underlined text link, not a third button tier.
   The block padding buys a 40px pointer target without inflating the type. */
.text-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding-block: var(--space-xs);
  color: var(--plum-ink);
  font-weight: var(--weight-ui);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
}

.text-link:hover {
  color: var(--plum-900);
  text-decoration-thickness: 2px;
}

.btn--block {
  inline-size: 100%;
}

.btn[aria-disabled="true"],
.btn:disabled {
  opacity: 0.55;
  pointer-events: none;
}

/* ---- surfaces ----------------------------------------------------------- */
/* Cards use a hairline, not elevation: SHADOW-01 allows one shadow value on the
   whole page and it is spent on the overlay surfaces. */

.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  padding: var(--space-lg);
  border: var(--border-hair);
  border-radius: var(--radius-card);
  background: var(--surface);
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  min-block-size: 1.75rem;
  padding: var(--space-xs) var(--space-md);
  border: var(--border-hair);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: var(--step--1);
  font-weight: var(--weight-ui);
  line-height: 1.3;
}

.pill--accent {
  border-color: var(--plum-300);
  color: var(--plum-ink);
}

.pill--muted {
  color: var(--ink-muted);
}

/* ---- section head ------------------------------------------------------- */

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-md) var(--space-lg);
  margin-block-end: var(--space-2xl);
}

.section-head__text {
  display: grid;
  gap: var(--space-xs);
  max-inline-size: var(--measure);
}

.section-head__sub {
  color: var(--ink-muted);
  max-inline-size: var(--measure);
}

/* ---- media -------------------------------------------------------------- */
/* The box reserves its ratio before the bytes arrive, which is what holds CLS at
   zero; every <img> also ships width and height attributes. */

.media {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: var(--ratio, 1);
  border-radius: var(--radius-photo);
  background: var(--surface-sunken);
}

.media > picture {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

.media img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.media--square {
  --ratio: 1;
}

.media--portrait {
  --ratio: 3 / 4;
}

.media--wide {
  --ratio: 16 / 9;
}

.media--flush {
  border-radius: 0;
}

/* ---- form field --------------------------------------------------------- */

.field {
  display: grid;
  gap: var(--space-xs);
}

.field__label {
  font-size: var(--step--1);
  font-weight: var(--weight-ui);
  color: var(--ink-soft);
}

.field__optional {
  color: var(--ink-muted);
  font-weight: var(--weight-body);
}

.field__hint {
  font-size: var(--step-small);
  color: var(--ink-muted);
}

.field input,
.field select,
.field textarea,
.input {
  inline-size: 100%;
  min-block-size: 3rem;
  padding: var(--space-xs) var(--space-md);
  border: 1px solid var(--ink-muted);
  border-radius: var(--radius-control);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--step-0);
}

.field textarea {
  min-block-size: 7rem;
  resize: vertical;
}

.field input::placeholder,
.field textarea::placeholder {
  color: var(--ink-muted);
}

.field [aria-invalid="true"] {
  border-color: var(--danger-600);
}

.field__error {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  font-size: var(--step-small);
  color: var(--danger-600);
}

.field--check {
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--space-md);
}

.field--check input {
  inline-size: 1.375rem;
  block-size: 1.375rem;
  min-block-size: 0;
  padding: 0;
  accent-color: var(--plum-ink);
}

/* ---- notices ------------------------------------------------------------ */

.notice {
  padding: var(--space-md) var(--space-lg);
  border: var(--border-hair);
  border-radius: var(--radius-card);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: var(--step-small);
}

.notice--warn {
  border-color: var(--warn-600);
}

.notice--error {
  border-color: var(--danger-600);
  color: var(--danger-600);
}

.notice--ok {
  border-color: var(--ok-600);
}

/* ---- lightbox shell ----------------------------------------------------- */
/* Structure and paint only; the gallery workstream owns focus trap, Esc and
   arrow-key behaviour. Hidden until it carries [open] or the is-open flag. */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: var(--z-lightbox);
  display: none;
  place-items: center;
  padding: var(--space-lg);
  border: 0;
  background: color-mix(in srgb, var(--plum-900) 92%, transparent);
}

.lightbox[open],
.lightbox.is-open {
  display: grid;
}

.lightbox__panel {
  position: relative;
  display: grid;
  gap: var(--space-md);
  justify-items: center;
  max-inline-size: min(64rem, 100%);
}

.lightbox__img {
  max-block-size: min(72svh, 46rem);
  inline-size: auto;
  border-radius: var(--radius-photo);
  object-fit: contain;
  box-shadow: var(--shadow-float);
}

.lightbox__caption {
  max-inline-size: var(--measure);
  color: var(--paper);
  font-size: var(--step-small);
  text-align: center;
}

.lightbox__close,
.lightbox__prev,
.lightbox__next {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 3rem;
  block-size: 3rem;
  border: 1px solid var(--plum-300);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink);
}

.lightbox__close:hover,
.lightbox__prev:hover,
.lightbox__next:hover {
  background: var(--plum-100);
}

.lightbox__close {
  position: absolute;
  inset-block-start: calc(var(--space-lg) * -1);
  inset-inline-end: 0;
}

.lightbox__nav {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.lightbox-open {
  overflow: hidden;
}

/* ---- footer ------------------------------------------------------------- */

.site-footer {
  background: var(--plum-900);
  color: var(--paper);
}

.site-footer__in {
  display: grid;
  gap: var(--space-xl);
  padding-block: var(--space-3xl) var(--space-xl);
}

@media (min-width: 48rem) {
  .site-footer__in {
    grid-template-columns: 1.5fr 1fr 1fr;
    gap: var(--space-2xl);
  }

  .site-footer__legal {
    grid-column: 1 / -1;
  }
}

.site-footer__name {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.18;
}

.site-footer__tagline {
  margin-block-start: var(--space-xs);
  max-inline-size: 30ch;
  color: var(--plum-300);
  font-size: var(--step-small);
}

.site-footer__nav ul,
.site-footer__contact {
  display: grid;
  gap: var(--space-xs);
}

/* inline-flex with a 24px min height: WCAG 2.2 SC 2.5.8 wants a 24x24 target,
   and a bare 16px link in a list is only 22px tall. */
.site-footer a {
  display: inline-flex;
  align-items: center;
  min-block-size: 1.5rem;
  color: var(--paper);
  font-size: var(--step-small);
  text-decoration: none;
}

.site-footer a:hover {
  color: var(--paper);
  text-decoration: underline;
}

.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-xs) var(--space-lg);
  padding-block-start: var(--space-lg);
  border-block-start: 1px solid color-mix(in srgb, var(--plum-300) 34%, transparent);
  color: var(--plum-300);
  font-size: var(--step-small);
}

/* =========================================================================
   HOME PAGE
   ========================================================================= */

/* ---- hero --------------------------------------------------------------- */

/* Two heroes, art-directed, sharing one file.
   Below 62rem the photograph is a full-bleed band and the copy sits under it on
   paper. That is not a stylistic preference: the flat-lay is 2.36:1 and every
   subject in it -- both bottles, the gypsophila, the rings, the ribbon roll --
   lives in the right third of the frame. Dropped behind copy in a 390x677 box,
   object-fit: cover keeps a 165px-wide slice of the middle and throws all of it
   away, leaving a pink-to-lavender field indistinguishable from the CSS gradient
   GRAD-01 exists to forbid. The band crops right instead, so a phone gets the
   photograph the desktop gets. From 62rem up the frame is wide enough to hold
   the copy on its empty left half, so the photograph goes back behind the text.
   A portrait-cut source would beat the phone crop; it is requested in the return
   value, and home.js says where the <source media> for it goes. */
.hero {
  position: relative;
  display: grid;
  /* start, not center: a centred block re-centres itself when the web fonts swap
     in, and that one reflow was worth 0.021 of CLS on its own. */
  align-content: start;
  isolation: isolate;
  background: var(--paper);
}

.hero__media {
  display: block;
  /* 336px at a 390x844 phone: the source paints 792 CSS px wide inside it, which
     is the 205vw entry in the img's sizes attribute. Sized so the band, the
     headline, the lede and both buttons all land above the fold on that phone. */
  block-size: min(44svh, 21rem);
}

.hero__media img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  /* right-anchored: at 390 the visible window is source x 0.53-0.96, which holds
     both bottles, both sprays of gypsophila, the rings and the ribbon */
  object-position: 92% 50%;
}

.hero__body {
  /* the text column never crosses into the busy right third of the photograph */
  max-inline-size: 36rem;
  padding-block: var(--space-xl) var(--space-3xl);
}

@media (min-width: 62rem) {
  /* Comfortably taller than the copy it holds, so the section below it does not
     move when the web fonts swap in and the headline re-wraps. */
  .hero {
    min-block-size: min(44rem, 86svh);
    background: var(--surface-sunken);
  }

  .hero__media {
    position: absolute;
    inset: 0;
    z-index: -1;
    block-size: auto;
  }

  /* Measured on the built page at 1440x900: the darkest pixel behind the headline
     box is 12.48:1 against --plum-900, behind the lede 10.75:1, under the trust
     row 8.99:1. Aiming further right picks up the ribbon and the dried stems,
     which drop to 1.8:1. */
  .hero__media img {
    object-position: 50% 50%;
  }

  .hero__body {
    padding-block: calc(var(--header-h) + var(--space-3xl)) var(--space-3xl);
  }
}

.hero__eyebrow {
  color: var(--ink);
}

.hero__title {
  margin-block-start: var(--space-md);
}

.hero__lede {
  margin-block-start: var(--space-md);
  max-inline-size: 34ch;
  color: var(--ink);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  margin-block-start: var(--space-xl);
}

.hero__actions .btn {
  flex: 1 1 12rem;
}

.hero__trust {
  display: grid;
  gap: var(--space-xs);
  margin-block-start: var(--space-2xl);
  padding-block-start: var(--space-md);
  border-block-start: 1px solid color-mix(in srgb, var(--plum-900) 28%, transparent);
}

.hero__trust li {
  color: var(--ink);
  font-size: var(--step-small);
  font-weight: var(--weight-ui);
  line-height: 1.35;
}

/* One row of natural-width items rather than three equal columns: fixed columns
   made "Spanish and English spoken" wrap to two lines in English while its
   row-mates stayed on one, which is exactly the diff I18N-01 looks for. */
@media (min-width: 48rem) {
  .hero__trust {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs) var(--space-lg);
  }

  .hero__trust li + li {
    padding-inline-start: var(--space-lg);
    border-inline-start: 1px solid color-mix(in srgb, var(--plum-900) 28%, transparent);
  }
}

/* ---- about -------------------------------------------------------------- */

.about {
  display: grid;
  gap: var(--space-xl);
  align-items: center;
}

@media (min-width: 48rem) {
  .about {
    /* asymmetric on purpose: ALIGN-01 fails a page that stacks and centres
       every single section */
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    gap: var(--space-3xl);
  }
}

.about__text {
  display: grid;
  gap: var(--space-md);
  max-inline-size: 54ch;
}

/* A Jost "0" is wider than the face's average lowercase, so a ch cap over-counts:
   the 54ch column above measured 76 characters on its longest line, outside the
   60-75 TYPE-03 asks for. 47ch measures 66-68 characters at 18px. */
.about__body {
  max-inline-size: 47ch;
  color: var(--ink-soft);
}

/* 5:4, top-anchored, against a 3:4 source: the frame keeps the brush, the hand
   and the window light and drops the bottom quarter of the plate. */
.about__media {
  --ratio: 5 / 4;

  inline-size: 100%;
  max-inline-size: 34rem;
  justify-self: end;
}

.about__media img {
  object-position: 50% 0;
}

/* ---- featured gallery --------------------------------------------------- */

.tile-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-lg) var(--space-xs);
}

@media (min-width: 48rem) {
  .tile-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-md);
  }
}

/* Captioned, because these six plates are an index of finished work rather than
   six frames from one sitting: naming each set is what makes the row read as a
   catalogue instead of as a contact sheet that cannot hold its white balance.
   See the builder's return value -- the set still needs one grade pass. */
.tile__link {
  display: grid;
  gap: var(--space-xs);
  text-decoration: none;
  transition: opacity var(--dur-base) var(--ease-out);
}

.tile__link:hover {
  opacity: 0.88;
}

.tile__link:hover .tile__caption {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.tile__caption {
  color: var(--ink-soft);
  font-size: var(--step-small);
  line-height: 1.35;
}

/* ---- services menu ------------------------------------------------------ */

.menu-layout {
  display: grid;
  gap: var(--space-2xl);
}

/* the grid gap already separates the head from the list */
.menu-layout .section-head {
  margin-block-end: 0;
}

@media (min-width: 62rem) {
  .menu-layout {
    grid-template-columns: 19rem minmax(0, 1fr);
    gap: var(--space-4xl);
    align-items: start;
  }

  .menu-layout .section-head {
    display: grid;
    align-content: start;
    justify-items: start;
  }
}

.menu {
  display: grid;
  border-block-start: 1px solid var(--line-strong);
}

.menu__row {
  display: grid;
  gap: var(--space-xs);
  padding-block: var(--space-md);
  border-block-end: 1px solid var(--line-strong);
}

.menu__head {
  display: flex;
  align-items: baseline;
  gap: var(--space-md);
}

/* Body face at 17-18px, never the display serif and never larger than the price
   (MENU-01): this block has to read as a printed menu, not as a card grid. */
.menu__name {
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: var(--weight-ui);
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--ink);
}

.menu__leader {
  flex: 1 1 auto;
  min-inline-size: var(--space-lg);
  border-block-end: 1px dotted var(--line-strong);
  translate: 0 -0.25em;
}

.menu__price {
  flex: 0 0 auto;
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: var(--weight-ui);
  color: var(--ink);
  white-space: nowrap;
}

.menu__from {
  color: var(--ink-muted);
  font-size: var(--step-small);
  font-weight: var(--weight-body);
}

.menu__foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
}

.menu__blurb {
  max-inline-size: 46ch;
  color: var(--ink-muted);
  font-size: var(--step-small);
  line-height: 1.5;
}

.menu__meta {
  flex: 0 0 auto;
  color: var(--ink-muted);
  font-size: var(--step-small);
  text-align: end;
  white-space: nowrap;
}

/* Same measure as a row's blurb rather than the full width of the price column:
   at 776px this line ran past the ~750px ceiling TYPE-03 puts on a text box. */
.menu__note {
  margin-block-start: var(--space-md);
  max-inline-size: 46ch;
  color: var(--ink-muted);
  font-size: var(--step-small);
}

/* ---- offers ------------------------------------------------------------- */
/* One card style. The per-offer tone this grid used to read from the data gave
   each card its own edge hue -- a success green, a warning amber, a blush and a
   plum -- which put four more non-neutral values on the page against COLOR-02's
   cap of three, and borrowed two semantic status colours as decoration. The
   offers are told apart by their words, not by a colour key nothing explains. */

.promo-grid {
  display: grid;
  /* one height per row in both locales: Spanish copy runs ~20% longer than
     English and without this the ES grid stepped 171/171 then 142/142 (I18N-01) */
  grid-auto-rows: 1fr;
  gap: var(--space-md);
}

@media (min-width: 48rem) {
  .promo-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-lg);
  }
}

.promo {
  padding: var(--space-xl);
  border-color: color-mix(in oklab, var(--plum-300) 72%, var(--line));
}

.promo__title {
  font-family: var(--font-body);
  font-size: var(--step-2);
  font-weight: var(--weight-ui);
  line-height: 1.25;
  letter-spacing: 0;
  color: var(--ink);
}

.promo__body {
  max-inline-size: 46ch;
  color: var(--ink-soft);
}

/* ---- closing booking band ---------------------------------------------- */

/* The band used to carry a CONTACTO column listing WhatsApp, a phone number, an
   email and an Instagram handle -- all four of which the footer repeats twenty
   pixels below it, which put the same phone number on the page four times. The
   footer keeps contact; the band keeps the ask and the opening hours. */
.booking {
  display: grid;
  gap: var(--space-2xl);
}

@media (min-width: 48rem) {
  .booking {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    gap: var(--space-4xl);
    align-items: start;
  }
}

.booking__cta {
  display: grid;
  justify-items: start;
  gap: var(--space-md);
  max-inline-size: 32rem;
}

.booking__cta .lede {
  color: var(--ink-soft);
}

.booking__cta .btn {
  margin-block-start: var(--space-xs);
}

.booking__hours h3 {
  margin-block-end: var(--space-md);
}

.data-list {
  display: grid;
}

.data-list__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
  padding-block: var(--space-xs);
  font-size: var(--step-small);
}

.data-list__row + .data-list__row {
  border-block-start: 1px solid color-mix(in srgb, var(--plum-300) 55%, transparent);
}

.data-list dt {
  color: var(--ink-soft);
  font-weight: var(--weight-ui);
}

.data-list dd {
  color: var(--ink-soft);
  text-align: end;
}

.data-list dd a {
  display: inline-flex;
  align-items: center;
  min-block-size: 1.5rem;
}

.data-list--closed dd {
  color: var(--ink-muted);
}
