  html {
    color-scheme: light;
    /* How much taller than natural the wordmark is drawn — see .brand-lockup.
       1.88 is what makes EB Garamond 800 land on the printed sign's
       width-to-height ratio (6.43 : 1 for "LA MAESTRANZA"). */
    --brand-stretch: 1.88;
  }
  body {
    background: linear-gradient(180deg, #F6EFE1 0%, #FBF6EA 55%, #F6EFE1 100%);
    font-family: 'Inter', sans-serif;
    /* Playfair Display defaults to old-style figures (digits of uneven height,
       some with descenders) — illegible in prices. Inherited by everything, this
       switches every digit to Playfair's built-in uniform lining set. */
    font-variant-numeric: lining-nums;
  }
  ::selection { background: rgba(217,164,65,.35); }
  /* Slim scrollbar */
  ::-webkit-scrollbar { width: 8px; height: 8px; }
  ::-webkit-scrollbar-track { background: #F6EFE1; }
  ::-webkit-scrollbar-thumb { background: rgba(29,92,80,.25); border-radius: 8px; }
  ::-webkit-scrollbar-thumb:hover { background: rgba(29,92,80,.45); }

  /* ── Brand lockup ────────────────────────────────────────────────────────
     The house's wordmark, rebuilt as live text: the wrought-iron lantern off
     the sign, then LA MAESTRANZA drawn the way the printed logo draws it —
     all caps in a Garamond bold, stretched to nearly twice its natural height
     (the sign is Adobe Garamond Bold; EB Garamond 800 is its web stand-in).

     One number sizes the whole mark: --brand-cap, the CAP height of the
     wordmark. Everything else is a ratio measured off the printed logo —
     font-size = cap / (0.65 cap-ratio x the stretch), lantern = 2.15 x cap,
     gap = 0.484 x cap — so an instance only sets --brand-cap (the markup does
     it with Tailwind's arbitrary properties, responsively). Those two ratios
     read 1.98 and 0.446 off the logo against the wordmark's INKED height,
     which runs 1.087x the cap once A's apex and S's curve overshoot it.

     The lantern is /img/lantern.svg (white, transparent) painted through a
     mask, so it takes the lockup's `color`: verde in the booking panel, white
     over the hero. Ornament only — it carries aria-hidden and lives OUTSIDE
     the heading, whose text the server and app.js replace wholesale. */
  .brand-lockup {
    display: flex;
    align-items: center;
    gap: calc(var(--brand-cap, 1.5rem) * .484);
  }
  .brand-word {
    display: inline-block;
    font-family: 'EB Garamond', 'Playfair Display', serif;
    font-weight: 800;
    text-transform: uppercase;
    white-space: nowrap;
    font-size: calc(var(--brand-cap, 1.5rem) / (.65 * var(--brand-stretch)));
    /* The line box reserves the stretched height and the glyphs, centred in it
       by the half-leading, grow to fill it: the stretch costs no layout. */
    line-height: var(--brand-stretch);
    transform: scaleY(var(--brand-stretch));
  }
  .brand-lantern {
    flex: none;
    height: calc(var(--brand-cap, 1.5rem) * 2.15);
    aspect-ratio: 960 / 577;
    background: currentColor;
    -webkit-mask: url('/img/lantern.svg') center / contain no-repeat;
    mask: url('/img/lantern.svg') center / contain no-repeat;
  }

  /* Glass system, reserved for fixed chrome floating over scrolling content
     (booking panel / bottom sheet, mobile sticky bar) */
  .glass {
    background: rgba(253,250,243,.8);
    backdrop-filter: blur(18px);
    -webkit-backdrop-filter: blur(18px);
    border: 1px solid rgba(29,92,80,.14);
  }
  .glass-soft {
    background: rgba(253,250,243,.55);
    border: 1px solid rgba(29,92,80,.12);
  }
  /* Solid card, static in-flow surfaces and modals (no transparency, no blur) */
  .card {
    background: #FCF8EE;
    border: 1px solid rgba(29,92,80,.14);
  }

  /* CTA: solid vermillion, no ornament — the accent color carries it */
  .cta-btn {
    background: #E13723;
  }

  /* Ironwork section dividers (index.html): fade the scroll rail out toward
     the page edges so it reads as an ornament, not an edge-to-edge stripe */
  .divider-fade {
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
    mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
  }

  /* Tile-floor section dividers (index.html): the house's real cement floor
     (tiles.png → /img/property/tiles-480.webp). The photo self-repeats every
     232px with no visible seam, so a plain repeat-x needs no processing.
     Mid-page seams wear the fresco wash; the strip above the footer runs raw.
     The strips marquee: shifting the background by exactly one seamless repeat
     and looping makes the floor drift left forever with no visible restart.
     Source is 464x212 = two repeats wide; at the rendered height (h-16 = 4rem,
     scaled by 4rem/212) one repeat is 4rem * 232/212 ~= 70px, so 6s reads as a
     slow ~12px/s drift. Retime with --tile-drift alone; the distance follows. */
  .tile-divider {
    --tile-repeat: calc(4rem * 232 / 212);
    --tile-drift: 6s;
    background-image: url('/img/property/tiles-480.webp');
    background-repeat: repeat-x;
    background-position-y: center;
    background-size: auto 100%;
    animation: tile-drift var(--tile-drift) linear infinite;
  }
  @keyframes tile-drift {
    from { background-position-x: 0; }
    to   { background-position-x: calc(var(--tile-repeat) * -1); }
  }
  /* aged fresco: drained color, lifted, translucent */
  .tile-fresco { filter: saturate(.55) contrast(.88) brightness(1.07); opacity: .75; }

  /* Gradient border cards (offers) */
  .gradient-border {
    position: relative;
    background: rgba(253,250,243,.78);
    border-radius: 1.25rem;
    z-index: 0;
  }
  .gradient-border::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1px;
    background: linear-gradient(135deg, rgba(217,164,65,.9), rgba(126,156,111,.45), rgba(160,135,104,.9));
    -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
    pointer-events: none;
  }
  .gradient-border-warm::before {
    background: linear-gradient(135deg, rgba(160,135,104,.9), rgba(29,92,80,.25), rgba(217,164,65,.7));
  }

  /* Reveal on scroll */
  .reveal {
    opacity: 0;
    transform: translateY(28px);
    transition: opacity .8s cubic-bezier(.22,.61,.36,1), transform .8s cubic-bezier(.22,.61,.36,1);
    will-change: opacity, transform;
  }
  .reveal.in-view { opacity: 1; transform: translateY(0); }
  .reveal-delay-1 { transition-delay: .12s; }
  .reveal-delay-2 { transition-delay: .24s; }
  .reveal-delay-3 { transition-delay: .36s; }
  @media (prefers-reduced-motion: reduce) {
    .reveal { opacity: 1; transform: none; transition: none; }
    .cta-btn::after { animation: none; }
    .tile-divider { animation: none; }
  }

  /* Chapter dots */
  .chapter-dot {
    width: 8px; height: 8px; border-radius: 9999px;
    background: rgba(29,92,80,.22);
    transition: background .3s, box-shadow .3s, transform .3s;
    display: block;
  }
  .chapter-dot.active {
    background: #D9A441;
    box-shadow: 0 0 0 3px rgba(217,164,65,.35);
    transform: scale(1.35);
  }

  /* Calendar, shared by the range picker and the availability view */
  .cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); }
  .cal-dow {
    text-align: center; font-size: 9px; text-transform: uppercase;
    letter-spacing: .14em; color: rgba(56,48,43,.4); padding: 6px 0 4px;
  }
  .cal-cell { padding: 2px 0; }
  .cal-day {
    position: relative; width: 100%; height: 38px;
    display: flex; align-items: center; justify-content: center;
    font-size: 13px; font-weight: 500; color: rgba(56,48,43,.75);
    border-radius: 9999px; background: transparent; border: none;
    transition: background .15s, color .15s, box-shadow .15s;
  }
  button.cal-day { cursor: pointer; }
  button.cal-day:hover:not(:disabled):not(.cal-selected) { background: rgba(217,164,65,.28); color: #38302B; }
  .cal-day:disabled, .cal-day.cal-past { color: rgba(56,48,43,.22); cursor: default; }
  .cal-day.cal-today::after {
    content: ''; position: absolute; bottom: 3px; left: 50%; transform: translateX(-50%);
    width: 4px; height: 4px; border-radius: 9999px; background: #D9A441;
  }
  .cal-day.cal-selected {
    background: #1D5C50; color: #fff; font-weight: 600;
    box-shadow: 0 8px 16px -8px rgba(29,92,80,.6);
  }
  .cal-cell.cal-in-range { background: rgba(217,164,65,.18); }
  .cal-cell.cal-range-start { background: linear-gradient(90deg, transparent 50%, rgba(217,164,65,.18) 50%); }
  .cal-cell.cal-range-end { background: linear-gradient(90deg, rgba(217,164,65,.18) 50%, transparent 50%); }
  .cal-cell.cal-range-start.cal-range-end { background: transparent; }
  .cal-day.cal-blocked {
    color: rgba(56,48,43,.28); text-decoration: line-through;
    background: rgba(160,135,104,.18);
  }
  .cal-pop {
    background: rgba(252,248,238,.96);
    backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
    border: 1px solid rgba(29,92,80,.16);
  }
  .cal-nav {
    width: 30px; height: 30px; border-radius: 9999px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    background: rgba(253,250,243,.6); border: 1px solid rgba(29,92,80,.14);
    color: #1D5C50; transition: background .2s, box-shadow .2s, opacity .2s;
  }
  .cal-nav:hover:not(:disabled) { background: #fff; box-shadow: 0 4px 14px -6px rgba(29,92,80,.5); }
  .cal-nav:disabled { opacity: .3; cursor: default; }
  .date-tile.active { border-color: rgba(225,55,35,.55); }

  /* Scroll hint bounce */
  @keyframes hintFloat {
    0%, 100% { transform: translateY(0); opacity: .7; }
    50% { transform: translateY(8px); opacity: 1; }
  }
  .scroll-hint { animation: hintFloat 2.4s ease-in-out infinite; }

  /* Bottom sheet transition (mobile) */
  #bookingPanel { transition: transform .45s cubic-bezier(.32,.72,.24,1); }
  #sheetBackdrop { transition: opacity .4s ease; }

  /* Booking panel view swap (stay view ⇄ guest details): the shared library
     (lib/booking.js swapPanelViews) drives these classes — the outgoing view
     goes absolute so the incoming one takes the flow, then drifts out fading
     while the incoming slides in from the opposite edge; going back runs the
     mirror image. */
  .view-exit { position: absolute; inset: 0; pointer-events: none; }
  .view-out-left  { animation: viewOutLeft  .38s cubic-bezier(.32,.72,.24,1) both; }
  .view-out-right { animation: viewOutRight .38s cubic-bezier(.32,.72,.24,1) both; }
  .view-in-right  { animation: viewInRight  .38s cubic-bezier(.32,.72,.24,1) both; }
  .view-in-left   { animation: viewInLeft   .38s cubic-bezier(.32,.72,.24,1) both; }
  @keyframes viewOutLeft  { to { transform: translateX(-35%); opacity: 0; } }
  @keyframes viewOutRight { to { transform: translateX(35%); opacity: 0; } }
  @keyframes viewInRight  { from { transform: translateX(100%); } }
  @keyframes viewInLeft   { from { transform: translateX(-100%); } }
  @media (prefers-reduced-motion: reduce) {
    .view-exit { display: none; }
    .view-out-left, .view-out-right, .view-in-right, .view-in-left { animation: none; }
  }

  /* Guest-details policy checkbox, in the house style (the stock native box
     looks foreign next to the glass surfaces) */
  .gd-check {
    appearance: none; -webkit-appearance: none;
    width: 22px; height: 22px; border-radius: 8px; flex-shrink: 0; margin: 0;
    background: rgba(253,250,243,.6); border: 1px solid rgba(29,92,80,.25);
    display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer; transition: background .2s, border-color .2s, box-shadow .2s;
  }
  .gd-check:checked {
    background: #1D5C50; border-color: #1D5C50;
    box-shadow: 0 4px 14px -6px rgba(29,92,80,.6);
  }
  .gd-check:checked::after {
    content: ''; width: 10px; height: 6px; margin-top: -2px;
    border: 2px solid #fff; border-top: 0; border-right: 0;
    transform: rotate(-45deg);
  }
  /* While the sheet is open the language toggle yields the top-right corner
     to the sheet's close button (app.js toggles this class) */
  #langToggle { transition: opacity .25s ease; }
  #langToggle.sheet-hidden { opacity: 0; pointer-events: none; }
  /* The shared library renders the toggle pills with utility classes from
     another site's palette (they resolve to nothing here), so this site's
     colors are applied through the aria-pressed state instead: verde pill
     for the active language, muted espresso for the rest (mirrors the
     legal pages' toggle). */
  #langToggle button { color: rgba(56,48,43,.6); }
  #langToggle button:hover { color: #1D5C50; }
  #langToggle button[aria-pressed="true"] {
    background: #1D5C50;
    color: #fff;
    box-shadow: 0 4px 14px -6px rgba(29,92,80,.6);
  }

  /* Gallery hover zoom */
  .zoom-img img { transition: transform .8s cubic-bezier(.22,.61,.36,1), opacity .6s; }
  .zoom-img:hover img { transform: scale(1.07); }

  /* Room card selected states: the pick carries the house's vermillion */
  .room-card { transition: border-color .3s, box-shadow .3s, transform .3s, background .3s; cursor: pointer; }
  .room-card:hover { transform: translateY(-4px); }
  .room-card.selected {
    border-color: rgba(225,55,35,.55) !important;
    box-shadow: 0 0 0 1px rgba(217,164,65,.5), 0 16px 32px -14px rgba(29,92,80,.3);
  }
  .room-option { transition: border-color .25s, background .25s, box-shadow .25s; cursor: pointer; }
  .room-option.selected {
    border-color: rgba(225,55,35,.5) !important;
    background: rgba(217,164,65,.15);
    box-shadow: 0 8px 18px -10px rgba(29,92,80,.35);
  }
  .room-option.selected .room-radio { border-color: #E13723; }
  .room-option.selected .room-radio::after {
    content: ''; position: absolute; inset: 3px; border-radius: 9999px; background: #E13723;
    box-shadow: none;
  }
  .room-radio { position: relative; }

  /* Unavailability markings, two deliberately different treatments:
     'booked' = tobacco, solid, muted (echoes the calendar's struck days);
     'guest limit' = verdigris, dashed (a fit problem, not a calendar problem) */
  .status-booked, .status-guests {
    align-items: center;
    margin-top: 7px; margin-right: 6px;
    padding: 3px 9px; border-radius: 9999px;
    font-size: 9px; font-weight: 600;
    text-transform: uppercase; letter-spacing: .12em;
    white-space: nowrap;
  }
  .status-booked {
    background: rgba(160,135,104,.2);
    border: 1px solid rgba(160,135,104,.55);
    color: #6B5844;
  }
  .status-guests {
    background: rgba(29,92,80,.1);
    border: 1px dashed rgba(29,92,80,.55);
    color: #1D5C50;
  }
  /* In the selector the pill sits in the price slot of a centered flex row */
  .room-option .status-booked, .room-option .status-guests { margin: 0; }
  /* On photo overlays the pills need solid backgrounds to stay legible */
  [data-card-status] .status-booked,
  [data-card-status] .status-guests { margin: 0; box-shadow: 0 4px 14px -6px rgba(56,48,43,.35); }
  [data-card-status] .status-booked { background: #EBE0C9; }
  [data-card-status] .status-guests { background: #E3EBE4; }

  /* Selector rows while unavailable (defined after .selected so they win).
     The chapter room cards deliberately get NO surface treatment, only the
     corner badge and the Select-button label communicate their state. */
  .room-option.is-booked { opacity: .6; background: rgba(160,135,104,.14); }
  .room-option.is-overcap { border-style: dashed; border-color: rgba(29,92,80,.45); }

  /* Stay verdict, the summary card is the main communicator of the result;
     it speaks plainly (no badge) and carries the reason's color language */
  #stayCard.verdict-booked {
    background: rgba(160,135,104,.16);
    border-color: rgba(160,135,104,.5);
  }
  #stayCard.verdict-booked #verdictTitle { color: #6B5844; }
  #stayCard.verdict-guests {
    background: rgba(29,92,80,.08);
    border-style: dashed;
    border-color: rgba(29,92,80,.5);
  }
  #stayCard.verdict-guests #verdictTitle { color: #1D5C50; }

  /* Click-time verify: when the fresh quote differs from the shown one, the
     hint line under the CTA becomes a real notice and the stay card flashes
     once so the changed total is impossible to miss. */
  #handoffUrl.price-notice {
    color: #8a5a17;
    font-family: 'Inter', ui-sans-serif, system-ui, sans-serif;
    font-size: 12px;
    line-height: 1.45;
  }
  @keyframes priceFlash {
    0% { background: rgba(217,164,65,.28); border-color: rgba(217,164,65,.7); }
    100% { background: transparent; }
  }
  #stayCard.price-flash { animation: priceFlash 1.4s ease-out; }

  /* Breakdown money always carries two decimals so the column aligns
     (fmtMoneyHtml); the cents and the trailing currency code are shrunk to the
     same smaller size so they don't compete with the big digits, but keep the
     SAME colour as those digits (no fade). */
  .money-cents,
  .money-cur { font-size: .65em; }

  /* Best value pulse */
  @keyframes tagGlow {
    0%, 100% { box-shadow: 0 2px 8px rgba(29,92,80,.45); }
    50% { box-shadow: 0 4px 14px rgba(29,92,80,.7); }
  }
  .best-value-tag { animation: tagGlow 3s ease-in-out infinite; }

  /* Amenity card hover glow */
  .amenity-card { transition: border-color .3s, box-shadow .3s, transform .3s; }
  .amenity-card:hover {
    border-color: rgba(126,156,111,.55);
    box-shadow: 0 12px 26px -12px rgba(29,92,80,.22);
    transform: translateY(-3px);
  }

  /* Hero slideshow */
  .hero-slide {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; opacity: 0; transition: opacity 1.4s ease;
  }
  .hero-slide.active { opacity: 1; }

  /* Hero ambient video: sits above the slides, invisible until it actually
     plays, so the slideshow is both the instant poster and the fallback.
     (No video is authored for this site yet; the hook stays wired.) */
  .hero-video {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; opacity: 0; transition: opacity 1.4s ease;
    pointer-events: none;
  }
  .hero-video.playing { opacity: 1; }

  /* Room card carousels */
  .carousel .slide {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; opacity: 0;
    transition: opacity .45s ease, transform .8s cubic-bezier(.22,.61,.36,1);
  }
  .carousel .slide.active { opacity: 1; }
  .carousel-btn {
    position: absolute; top: 50%; transform: translateY(-50%); z-index: 5;
    width: 30px; height: 30px; border-radius: 9999px;
    display: flex; align-items: center; justify-content: center;
    background: rgba(253,250,243,.8); border: 1px solid rgba(29,92,80,.18);
    color: #1D5C50; backdrop-filter: blur(6px);
    transition: background .25s, box-shadow .25s;
  }
  .carousel-btn:hover { background: #fff; box-shadow: 0 4px 14px -6px rgba(29,92,80,.5); }
  .carousel-btn.prev { left: 8px; }
  .carousel-btn.next { right: 8px; }
  .carousel-dots {
    position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%);
    display: flex; gap: 6px; z-index: 5;
  }
  .carousel-dot {
    width: 5px; height: 5px; border-radius: 9999px;
    background: rgba(255,255,255,.55); transition: background .25s, transform .25s;
  }
  .carousel-dot.active { background: #fff; transform: scale(1.3); }
  .photo-count {
    position: absolute; bottom: 8px; right: 10px; z-index: 5;
    font-size: 10px; letter-spacing: .08em; padding: 3px 8px; border-radius: 9999px;
    background: rgba(56,48,43,.5); color: #fff; backdrop-filter: blur(4px);
  }

  /* Lightbox */
  #lightbox { opacity: 0; pointer-events: none; transition: opacity .3s ease; }
  #lightbox.open { opacity: 1; pointer-events: auto; }

  /* Room details modal */
  #roomModal { opacity: 0; pointer-events: none; transition: opacity .3s ease; }
  #roomModal.open { opacity: 1; pointer-events: auto; }

  /* Amenity chips on room cards */
  .room-chip {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 10px; border-radius: 9999px;
    background: rgba(253,250,243,.55); border: 1px solid rgba(29,92,80,.12);
    font-size: 11px; color: rgba(56,48,43,.72); white-space: nowrap;
  }
  .room-chip svg { flex-shrink: 0; }

  /* Radio dot in card Select button (mirrors the panel's room options) */
  .room-card.selected .room-radio { border-color: #E13723; }
  .room-card.selected .room-radio::after {
    content: ''; position: absolute; top: 50%; left: 50%;
    width: 5px; height: 5px; transform: translate(-50%, -50%);
    border-radius: 9999px; background: #E13723;
  }

  /* Consent banner (engine-built DOM, lib/analytics.js). The ids/classes are
     the engine's contract; the look AND the placement are this site's — the
     engine's injected stylesheet is only a neutral fail-safe for a site that
     hasn't styled the banner yet, and site rules always win the cascade.
     Placement here: mobile pins it to the top (the bottom edge belongs to
     the sticky booking bar); from lg: up the booking panel is fixed to the
     left 38% (#bookingPanel), so the banner's box spans the CONTENT column
     and the engine's margin:0 auto centers it over that column. The media
     override must FOLLOW the base rule: same specificity, so source order
     decides. */
  #consentBanner {
    top: 1rem; left: 1rem; right: 1rem;
    background: #FCF8EE;
    color: #38302B;
    border: 1px solid rgba(29,92,80,.18);
    border-radius: 1.25rem;
    box-shadow: 0 24px 64px -28px rgba(56,48,43,.30);
    font-family: 'Inter', sans-serif;
  }
  @media (min-width: 1024px) {
    #consentBanner {
      top: 1.25rem;
      left: calc(38% + 1.5rem);
      right: 1.5rem;
    }
  }
  #consentBanner .consent-text { color: rgba(56,48,43,.85); }
  #consentBanner .consent-link {
    color: #1D5C50; text-underline-offset: 2px;
    text-decoration-color: rgba(29,92,80,.35);
  }
  #consentBanner .consent-link:hover { text-decoration-color: #1D5C50; }
  #consentBanner button { border-radius: 9999px; font-weight: 600; transition: all .15s ease; }
  #consentBanner .consent-decline {
    border: 1px solid rgba(56,48,43,.25); color: rgba(56,48,43,.75); background: transparent;
  }
  #consentBanner .consent-decline:hover { border-color: rgba(56,48,43,.45); color: #38302B; }
  #consentBanner .consent-accept {
    background: #1D5C50; border-color: #1D5C50; color: #fff;
    box-shadow: 0 4px 14px -6px rgba(217,164,65,.6);
  }
  #consentBanner .consent-accept:hover { background: #14332B; }
