:root {
    --navy: #0e2239;
    --gold: #d4af37;
    --ink: #183047;
    --muted: #667583;
    --warm: #f8f5ef;
    --white: #fff;
    --line: #dfe3e2;
    --serif: Georgia, "Times New Roman", serif;
    --sans: Inter, ui-sans-serif, system-ui, sans-serif;

    /* P2.71 customer typography calibration — three shared tokens, so the
       same semantic role is corrected once rather than through dozens of
       isolated overrides.

       Measured first (Georgia width probe at 40px, "Handgloves"):
         weight 300/400/500 -> 209.2px   (all resolve to Georgia REGULAR)
         weight 600/700/800 -> 242.8px   (all resolve to Georgia BOLD)
       So the serif headings already render Regular at their declared 500,
       and the perceived heaviness was never the serif's weight. It came
       from the sans layer: every eyebrow/metadata label sat at 800
       (ExtraBold) in uppercase with wide tracking, so 10-12px gold and
       navy micro-type was optically louder than the property identity and
       the photography it sits beside.

       --weight-eyebrow  quiets that whole class to a confident-but-calm
                         650 (the codebase's own existing "confident, not
                         bold" sans step, already used by .differentiators
                         span / .stepper-value / .transfer-select-price).
       --tracking-eyebrow normalises uppercase tracking that ranged from
                         .08em to .19em; .1em stays legible in caps without
                         shouting.
       --lh-display      loosens display headings from 1.05, which read as
                         dense on a sturdy screen serif. Weight is what
                         changes here, not size. */
    --weight-eyebrow: 650;
    --tracking-eyebrow: .1em;
    --lh-display: 1.14;

    /* Search-results premium refinement — a small spacing scale for the
       result-card component this package touches. Deliberately scoped
       to this component, not a file-wide spacing-token migration (the
       rest of catalogue.css keeps its established literal rem/clamp()
       convention, documented as-is elsewhere in this file); introduced
       here so the card's own internal rhythm is deliberate and
       consistent rather than isolated one-off margins. */
    --space-3xs: .25rem;
    --space-2xs: .4rem;
    --space-xs: .6rem;
    --space-sm: .85rem;
    --space-md: 1.15rem;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* P2.70B — every existing "X img" / "X > img" sizing rule below
   (.card-media img, .hero-media > img, .gallery-tile img, .room-media
   img, .media-dialog-stage img, .highlight-card img) was written for a
   bare <img>. responsive-media.blade.php wraps a WebP-capable image in
   a <picture> instead; `display: contents` makes the <picture> generate
   no box of its own, so its child <img> is styled exactly as if the
   <picture> wrapper wasn't there at all — no per-component rule below
   needed to change. Excluded whenever [hidden] is also present (a
   carousel slide toggle, e.g. Room Explorer's own [data-room-slide]) so
   this rule never fights the standard [hidden] -> display:none behavior
   with a competing author-stylesheet display value. */
picture:not([hidden]) { display: contents; }
body { margin: 0; color: var(--ink); background: #fff; font-family: var(--sans); line-height: 1.55; }
/* P2.48E — standard visually-hidden-but-announced utility, mirroring
   catalogue-booking.css's own identical rule (that stylesheet isn't
   loaded on this page, so it's defined once here too rather than
   pulling in an unrelated file). */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.skip { position: fixed; left: 1rem; top: 0; transform: translateY(calc(-100% - 1px)); max-width: calc(100% - 2rem); z-index: 99; background: var(--navy); color: #fff; padding: .8rem 1rem; overflow-wrap: anywhere; }
.skip:focus { top: 1rem; transform: none; outline: 3px solid var(--gold); outline-offset: 2px; }
.site-header { min-height: 74px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem 1.2rem; padding: .5rem clamp(1.2rem, 5vw, 5rem); border-bottom: 1px solid #eef0ef; background: rgba(255, 255, 255, .96); }
.site-header a { color: var(--navy); text-decoration: none; }
.brand { font-family: var(--serif); font-size: 1.65rem; font-weight: 700; }
.site-header span { color: var(--muted); font-size: .85rem; }
/* P2.52 §G — the customer navigation itself: on every page but the one
   it targets, links to Search and to the existing (previously
   undiscoverable) /recover-booking route. A plain flex+gap group, not
   a second `justify-content` participant, so `.site-header` keeps its
   simple two-child space-between layout regardless of how many links
   this holds on a given page. */
.site-nav { display: flex; flex-wrap: wrap; align-items: center; min-width: 0; max-width: 100%; gap: .5rem clamp(1rem, 2.5vw, 1.75rem); font-size: .85rem; font-weight: 550; }
.site-nav a { display: inline-flex; align-items: center; min-height: 44px; max-width: 100%; overflow-wrap: anywhere; }
/* POST-CUTOVER-3 — "Sign in" is a restrained utility action, not a
   CTA: same weight as its siblings, set apart only by a thin pill
   outline (never filled/coloured) so it reads as a quieter, secondary
   affordance than the informational links beside it. Its own smaller
   gap keeps it visually anchored to the border rather than floating
   in the middle of the nav's wider inter-link spacing. */
.site-nav-signin { display: inline-flex; align-items: center; padding: .35rem .85rem; border: 1px solid var(--line); border-radius: 999px; color: var(--navy); }
@media (max-width: 430px) {
    .site-nav { gap: .7rem; font-size: .78rem; }
    .site-nav-signin { padding: .3rem .7rem; }
}
@media (max-width: 360px) {
    /* Comfortable margin rather than a hairline fit: at the very
       narrowest supported width, retain the existing type sizes while
       allowing links to wrap when enlarged text requires another row. */
    .brand { font-size: 1.4rem; }
    .site-header { padding: 0 .85rem; }
    .site-nav { gap: .6rem; font-size: .72rem; }
    .site-nav-signin { padding: .28rem .6rem; }
}

/* Homepage "Book with clarity" — a quiet cream closing band after the
   results (search.blade.php, public.home only). Same horizontal padding
   and 1000px column as the property grid; no cards, icons or borders. */
.book-clarity { background: var(--warm); padding: clamp(2.2rem, 5vw, 3.6rem) clamp(1.2rem, 7vw, 7rem); }
.book-clarity h2 { margin: 0; font-family: var(--sans); font-size: clamp(1.12rem, .98rem + .7vw, 1.55rem); font-weight: 550; color: var(--ink); }
.book-clarity-intro { max-width: 64ch; margin: .55rem 0 0; color: var(--muted); font-size: .95rem; }
.book-clarity-points { display: grid; gap: 1.15rem; margin: 1.5rem 0 0; padding: 0; list-style: none; }
.book-clarity-points h3 { margin: 0; font-family: var(--sans); font-size: .95rem; font-weight: 600; color: var(--navy); }
.book-clarity-points p { margin: .3rem 0 0; color: var(--muted); font-size: .9rem; }
.book-clarity-points a, .book-clarity-points a:visited { color: var(--navy); text-decoration: underline; text-underline-offset: 2px; overflow-wrap: anywhere; }
@media (max-width: 600px) { .book-clarity { padding: 2.4rem 1rem; } }
@media (min-width: 601px) { .book-clarity-inner { max-width: 1000px; margin-inline: auto; } }
@media (min-width: 901px) { .book-clarity-points { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2.25rem; } }

/* P2.52 §I — a small, honest closing shell (see partials/site-footer)
   so the journey never just stops mid-page. Deliberately plain: no
   multi-column link farm, matching the header's own restraint. */
.site-footer { border-top: 1px solid var(--line); margin-top: clamp(2rem, 5vw, 4rem); padding: clamp(1.6rem, 4vw, 2.4rem) clamp(1.2rem, 5vw, 5rem); }
.site-footer-inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .6rem 1.5rem; color: var(--muted); font-size: .82rem; }
.site-footer-brand { font-family: var(--serif); font-weight: 700; color: var(--navy); }
.site-footer-support a, .site-footer-support a:visited { color: var(--muted); text-decoration: underline; text-underline-offset: 2px; }
.site-footer-copyright { color: var(--muted); flex-basis: 100%; order: 5; }
.site-footer-legal { display: flex; flex-wrap: wrap; gap: .4rem 1rem; }
.site-footer-legal a, .site-footer-legal a:visited { color: var(--muted); text-decoration: underline; text-underline-offset: 2px; }
.eyebrow { font-size: .72rem; font-weight: var(--weight-eyebrow); letter-spacing: var(--tracking-eyebrow); color: #8c741f; }
h1, h2, h3 { font-family: var(--serif); color: var(--navy); line-height: var(--lh-display); margin: .25em 0; }

/* P2.52 — top/bottom padding tightened again (was clamp(2.25rem,5vw,
   4.75rem) / clamp(1.6rem,3.5vw,3rem)): the owner's typography/density
   review found the hero block, even with P2.51B's already-reduced H1,
   still consumed too much vertical space before the search instrument
   and — combined with the results header below — pushed all inventory
   below the fold on a standard desktop viewport. */
.search-hero { background: var(--warm); padding: clamp(1.75rem, 3.5vw, 3rem) clamp(1.2rem, 7vw, 7rem) clamp(1.2rem, 2.5vw, 1.9rem); }
/* P2.51B §H reduced this once already; P2.52 narrows it further (was
   clamp(1.75rem, 3vw, 2.75rem) / max-width 640px) per the owner's
   explicit target range (~40-48px desktop) and instruction that
   functional OTA surfaces should not read as a magazine headline — a
   narrowly-scoped reduction, still this selector only. */
/* P2.52 — ONE fluid curve for the full 320-1440px+ range (anchored at
   320px≈28px and 1440px≈44px, the owner's own desktop target), not a
   base rule plus two separate breakpoint overrides. The previous
   three-rule version (this rule plus two @media overrides below)
   produced a real, visible backward jump in size right at the 900px
   boundary once the base value changed — found live while checking
   intermediate widths, not merely the named breakpoints. A single
   clamp() cannot jump. */
.search-hero h1 { overflow-wrap: anywhere; font-size: clamp(1.75rem, 1.46rem + 1.43vw, 2.75rem); max-width: 580px; font-weight: 500; line-height: 1.1; letter-spacing: -.01em; text-wrap: balance; }
/* Customer search UX refinement (§2) — same grid/column-ratio structure
   as before (this is a refinement, not a rebuild), softened toward a
   "clean premium OTA control" rather than a dense form box:
   - divider colour lightened from #d8d9d5 to var(--line) (the same
     hairline colour every other border on this page already uses, so
     the bar's own dividers stop reading as a slightly different,
     heavier grey than its surroundings);
   - corner radius nudged 14px -> 16px, matching the popovers/panels
     this same bar opens (.search-popover/.destination-suggest already
     use 16px) so the whole interactive family shares one radius;
   - shadow softened slightly (heavier alpha read as a harder-edged
     box than the rest of the page's restrained shadow language). */
.search-form { margin-top: 2rem; display: grid; grid-template-columns: minmax(0, 2fr) repeat(3, minmax(0, 1fr)) auto; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 16px; overflow: hidden; box-shadow: 0 16px 40px #0e22390e; }
/* Horizontal padding widened .1rem and label weight/tracking eased
   (650->600, .1em->.08em) — a small, legible label still reads clearly
   in caps without the previous slightly shouty density; colour set to
   var(--muted) to match the enhanced-state field label exactly (the
   plain/no-JS label previously had no colour rule of its own and fell
   back to the page's dark body ink, which is why it read heavier than
   the JS-enhanced Dates/Guests labels sitting right beside it). */
.search-form label { min-width: 0; padding: .75rem 1.15rem .7rem; background: #fff; font-size: .66rem; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.search-form input { display: block; width: 100%; min-width: 0; border: 0; margin-top: .3rem; padding: .2rem 0; color: var(--ink); font: inherit; font-size: .95rem; background: transparent; }
/* Destination only (input[name="destination"] exists on no other
   .search-form — the property page's stay-picker-form has no
   destination field at all, so Dates/Guests and that shared form are
   both untouched): the segment already sits inside the larger bar, so
   the browser's own bright rectangular outline around just the inner
   input reads as congested. Treat the whole segment as active instead —
   the same idea as .booking-amend-option:has(input:checked)'s own
   active-state background swap — and keep a restrained, translucent-gold
   ring (matching every other quiet focus state on this page, e.g.
   .search-form button:focus-visible) on the input itself for keyboard
   users, never removing focus visibility. Background/outline never
   affect layout, so focus/blur introduces no shift. */
.search-form label:has(input[name="destination"]:focus) { background: var(--warm); }
.search-form input[name="destination"]:focus { outline: none; }
.search-form input[name="destination"]:focus-visible { outline: 2px solid #d4af3780; outline-offset: 2px; }
.search-form button, .button { min-width: 0; max-width: 100%; white-space: normal; overflow-wrap: anywhere; border: 0; background: var(--navy); color: #fff; padding: 1rem 1.75rem; font-weight: 750; text-decoration: none; cursor: pointer; }
.search-form button:hover, .search-form button:focus-visible, .button:hover, .button:focus-visible { outline: 3px solid #d4af3780; outline-offset: -3px; }

/* Destination cell: the label (unchanged) plus, when aAura is enabled, its microphone entry point
   inside the field's right edge. The button is a sibling of the label, not a child, so it never
   becomes part of the input's accessible name or of the label's click target. */
.destination-cell { position: relative; min-width: 0; display: flex; background: #fff; }
.destination-cell > label { flex: 1; }
/* The existing focus ring is drawn on the input, whose box runs under the Ask aAura control. In this cell
   the same translucent-gold ring is drawn around the whole segment instead (still shown for keyboard and
   pointer focus, never removed), so it frames the field with the control inside it. */
.destination-cell:has(.aura-field-mic) input[name="destination"]:focus-visible { outline: none; }
.destination-cell:has(.aura-field-mic) > label:has(input[name="destination"]:focus-visible) { box-shadow: inset 0 0 0 2px #d4af3780; }
.destination-cell:has(.aura-field-mic) input[name="destination"] { padding-right: 8.6rem; }
.search-form button.aura-field-mic {
    position: absolute; top: 50%; right: .7rem; transform: translateY(-50%);
    display: inline-flex; align-items: center; justify-content: center; gap: .45rem;
    height: 2.25rem; min-height: 0; padding: 0 .8rem 0 .95rem; border-radius: 999px;
    border: 1px solid #d4af3799; background: transparent; color: var(--gold, #d4af37);
    font-size: .8rem; font-weight: 600; letter-spacing: .02em; text-transform: none; white-space: nowrap;
    transition: background-color .15s ease, color .15s ease;
}
.aura-field-mic-label { color: var(--navy); }
.search-form button.aura-field-mic:hover { background: var(--navy); color: var(--gold, #d4af37); outline: none; }
.search-form button.aura-field-mic:hover .aura-field-mic-label { color: #fff; }
.search-form button.aura-field-mic:focus-visible { outline: 2px solid var(--gold, #d4af37); outline-offset: 2px; }
.search-form button.aura-field-mic[aria-expanded="true"] { background: var(--navy); }
.search-form button.aura-field-mic[aria-expanded="true"] .aura-field-mic-label { color: #fff; }
@media (max-width: 760px) {
    /* A comfortable (44px) touch target on phones and tablets. */
    .search-form button.aura-field-mic { height: 2.75rem; right: .55rem; }
    .destination-cell:has(.aura-field-mic) input[name="destination"] { padding-right: 8.4rem; }
}
@media (max-width: 359px) {
    /* Very narrow screens: the microphone alone, to protect the destination input. */
    .aura-field-mic-label { display: none; }
    .search-form button.aura-field-mic { width: 2.75rem; padding: 0; }
    .destination-cell:has(.aura-field-mic) input[name="destination"] { padding-right: 3.2rem; }
}

.results, .rooms-section, .review-section { padding: clamp(3rem, 7vw, 7rem) clamp(1.2rem, 7vw, 7rem); }
/* P2.51B §H — the search-results section specifically (never
   rooms-section/review-section, whose own rhythm is unrelated to the
   benchmarked "hero-to-first-results" gap) sits directly below the
   search instrument; narrowing just its own top padding keeps related
   decisions (search → results) visually closer, matching the tighter
   rhythm observed across every competitor studied. */
/* P2.52 — narrowed again (was clamp(2rem, 4vw, 3.5rem)) alongside the
   results-header changes below it, so the property grid is reachable
   without scrolling on a standard desktop viewport. */
.results { padding-top: clamp(1.3rem, 2.5vw, 2.2rem); }
/* P2.53 final visual gate — .rooms-section is markup-exclusive to the
   customer property page (grep-verified: never shared with search
   results or any other template), so unlike the P2.51B-era comment
   above (written before Highlights existed), narrowing ITS OWN top
   padding here cannot touch review-section's unrelated rhythm. With
   "Why stay here" now sitting directly above Room Explorer, the full
   7vw/7rem padding read as a second unexplained gap stacked on top of
   Highlights' own bottom spacing, pushing Room Explorer's heading and
   intro copy down before any room card could appear. Matches
   .results' own precedent exactly. */
/* Property-page final premium refinement — global section rhythm: each
   major section owns its OWN top gap only (bottom set to 0), the same
   pattern .highlights already used deliberately. No section's gap is
   ever the sum of one section's bottom plus the next section's top. */
.rooms-section { padding-top: clamp(1.3rem, 2.5vw, 2.2rem); padding-bottom: 0; }
.section-title { display: flex; justify-content: space-between; align-items: end; margin-bottom: 1.1rem; }
.rooms-section h2, .review-section h2 { font-size: clamp(1.5rem, 2.6vw, 2.35rem); font-weight: 500; letter-spacing: -.01em; }
/* P2.52 — split out of the shared `.section-title h2, .rooms-section
   h2, .review-section h2` rule above (which stays serif/2.35rem
   exactly as it was — it still governs Room Explorer's own heading,
   explicitly protected, and the review section's). `.section-title h2`
   is markup-exclusive to the search-results count
   (search.blade.php's "N properties") and nothing else: a functional
   navigation/wayfinding number, not a content heading, so it now takes
   the sans-serif hierarchy instead of the serif one — smaller and
   lighter, so it reads as information rather than a second hero
   statement stacked under the first. */
/* P2.69 typography audit — 700 (full bold) gave this functional count
   heading more visual weight than the property/room titles it sits above,
   an inverted hierarchy. 650 matches this codebase's own established sans
   "confident but not bold" token (.differentiators span, .stepper-value,
   .transfer-select-price all already use it). */
.section-title h2 { font-family: var(--sans); font-size: clamp(1.19rem, .96rem + 1.16vw, 2rem); font-weight: 550; color: var(--ink); }
.section-title > p, .section-intro { color: var(--muted); }
/* Customer search UX refinement (§4) — the dynamic search-state/count
   line under the results heading (`section-context`, a child of the
   left-hand `<div>`, not the right-side `<p>` the two rules above
   already style). Deliberately smaller/lighter than the heading it
   sits directly beneath: it is confirmation of what was searched, not
   a second statement competing with the heading above it. */
.section-context { margin: .3rem 0 0; color: var(--muted); font-size: .92rem; }
/* P2.69 — mobile-first default is a single column; the 601px+ rule below
   sets the 2-column landscape card layout, and the 1280px+ rule further
   below densifies to 3 columns on wide desktop. (A `repeat(3, ...)`
   default lived here previously, but the unconditional 601px+ override
   further down the cascade always won over it at every width ≥601px —
   dead code that never actually rendered; removed rather than kept as
   misleading intent.) */
.property-grid { container: discovery / inline-size; display: grid; grid-template-columns: minmax(0, 1fr); align-items: start; gap: clamp(1.1rem, 2vw, 2rem); }
.property-card { min-width: 0; border: 1px solid var(--line); border-radius: 20px; overflow: hidden; background: #fff; }
/* P2.51C §E — .card-media is an <a>; without this, the browser's
   default link underline/blue paints through every descendant
   (including the "aA" / "Photography coming soon" fallback), which
   read as a broken/unstyled prototype link rather than the intended
   navy placeholder mark. */
/* Owner correction, review round 2 — checked against real production
   media (Niva Kurumba/Season Paradise/Niva Veleassaru hero derivatives,
   all genuinely 960x640 = 3:2): ImageProcessor::resize() only ever
   scales proportionally, it never crops, so 3:2 here is each master
   photo's own native ratio, not a pipeline artefact. The former 16:10
   (1.6) box was measurably wider than the real 3:2 (1.5) image, forcing
   an avoidable extra object-fit:cover crop on every card photo beyond
   whatever the source composition already needs — 3:2 removes that. */
.card-media { display: block; aspect-ratio: 3 / 2; overflow: hidden; color: inherit; text-decoration: none; }
.card-media:hover, .card-media:focus { color: inherit; text-decoration: none; }
.card-media img, .hero-media > img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s; }
.property-card:hover .card-media img { transform: scale(1.025); }
.media-fallback { height: 100%; min-height: 260px; background: linear-gradient(145deg, #e9e5dc, #f8f5ef); display: grid; place-content: center; text-align: center; color: var(--navy); }
.media-fallback span { font-family: var(--serif); font-size: 4rem; }
.media-fallback small { letter-spacing: .12em; text-transform: uppercase; }
.card-body { padding: 1.2rem min(1.35rem, 21.6px) 1.3rem; }
/* P2.52 — was font-size: 1.6rem with the browser's implicit h3 bold
   (700): at that size/weight the serif title outweighed the price
   (1.12rem) by a wide margin, competing with the property photograph
   above it and undersELLING price/commercial value relative to
   identity. Kept comfortably inside the owner's 22-28px target range
   and still serif (property identity is one of the strategic uses the
   brief names) — only weight and size trimmed, and margin tightened to
   match. */
/* P2.52 — a single fluid clamp (≈19px at 320px → 24px at 1280px+)
   rather than a base size plus a separate mobile-breakpoint override,
   so card titles scale continuously with viewport width instead of
   stepping between two fixed values at 600px. */
/* P2.69 final micro-correction — 600 still rendered visually heavy: `--serif`
   (Georgia/Times New Roman) ships only two real faces, Regular(400) and
   Bold(700); browsers resolve any font-weight without an exact face to the
   NEAREST one, and 600 is numerically closer to 700 than 400, so it was
   rendering identically to bold. 500 is the lightest value that reliably
   resolves to the font's actual Regular face across engines — a real
   optical change, not just a smaller number. */
.card-body h3 { margin: 0 0 var(--space-2xs); font-size: clamp(1.19rem, 1.08rem + .52vw, 1.5rem); font-weight: 500; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.card-body a { color: inherit; text-decoration: none; }
/* Owner final-polish — replaces the old "AE · HOTEL" uppercase eyebrow
   (a decorative property-type label, never itself a comparison fact).
   The name now leads the column outright, so its location line reads
   as calm, sentence-case secondary text immediately beneath it — never
   another competing uppercase micro-label. */
.card-location { margin: 0 0 var(--space-xs); font-size: .82rem; color: var(--muted); }
/* Search-card Google credential (owner-approved, 2026-09) — the exact
   same .reputation-credential/.reputation-credential-rating/
   .reputation-credential-attribution markup and reputation-credential.js
   behaviour the property-page hero already ships, just resized/spaced to
   sit quietly in a comparison card: secondary supporting information,
   never competing with the property name or the "Check availability"
   CTA. No new classes, no new script, no new fetch logic. */
.card-body .reputation-credential { margin: 0 0 var(--space-xs); font-size: .78rem; }
.summary { margin: 0; color: var(--muted); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* One compact, authoritative arrival-accessibility fact — never a large
   block, never competing with rating/price/CTA. */
.arrival-line { margin: 0 0 var(--space-xs); font-size: .78rem; color: var(--muted); }
/* P2.69 — `.card-rail` replaces the former `.card-foot`: on mobile it is
   still a simple row beneath the body (verified-stay score, price, then a
   full-width CTA); from 901px it becomes the card's third zone. */
.card-rail { min-width: 0; padding: 0 min(1.35rem, 21.6px) 1.3rem; display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: var(--space-sm) 1rem; font-size: .8rem; color: var(--muted); }
/* Owner mobile-commercial-hierarchy V2 — the commercial group is
   left-aligned by default (mobile's own reading axis: property, location,
   description and the room block above it are all left-aligned; the price
   block must not suddenly shift to the opposite edge). Tablet/desktop
   restore right/left alignment appropriate to their own row layouts inside
   their own media queries below, unchanged from before. The small gap
   gives the three stacked lines (amount, guest basis, tax line) a
   deliberate, visible micro-rhythm instead of an accidental zero-gap
   collision — still clearly tighter than the spacing outside this group
   (room block above, CTA below). */
.price { text-align: left; display: grid; gap: var(--space-3xs); }
/* P2.52 — raised from 1.12rem to sit closer to Room Explorer's own
   established price scale (.room-price strong, 1.3rem) instead of
   reading as secondary metadata beneath a heavier title. */
.price strong { color: var(--navy); font-size: 1.28rem; font-weight: 700; }
/* Owner final-polish — "total" folds in beside the figure at a lighter
   weight/size instead of living on its own small legal-looking line. */
.price-suffix { font-family: var(--sans); font-size: .78rem; font-weight: 400; color: var(--muted); }
.quiet-state { text-align: left; }
/* Today's Stay Rate — the label is the same quiet eyebrow voice as the page ("THE INDIAN OCEAN…"), above the price; the
   transfer disclosure is one muted line under "Tax included". No badge, no urgency, no new colour. */
.price-eyebrow { font-family: var(--sans); font-size: .68rem; font-weight: var(--weight-eyebrow); letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: #8c741f; }
.price-transfer { color: var(--muted); }
/* Expired-dates notice: plain, readable, never a modal; sits directly above the results it explains. */
.date-notice { margin: 0 auto var(--space-sm, 1rem); max-width: 72rem; padding: .85rem 1rem; border-left: 3px solid var(--gold); background: #faf6e8; color: var(--ink); font-family: var(--sans); font-size: .95rem; line-height: 1.45; }


/* P2.69 — the room actually being quoted, surfaced on the comparison row.
   Sans throughout: this is commercial comparison information, not
   identity. Kept to one name plus a short fact row so the card answers
   "which room, for how many, on what terms" without becoming a spec
   table — aAlabu answers the full version in Room Explorer. */
.card-room { margin: var(--space-sm) 0 0; padding: var(--space-xs) .75rem; border-radius: 10px; background: var(--warm); }
.card-room-name { margin: 0; font-family: var(--sans); font-size: .84rem; font-weight: 650; color: var(--ink); }
.card-room-facts { display: flex; flex-wrap: wrap; gap: .25rem .5rem; margin: .2rem 0 0; font-size: .76rem; color: var(--muted); }
.card-room-facts span:not(:last-child)::after { content: "·"; margin-left: .5rem; color: #b9b3a4; }
.price span, .price small, .card-room-name, .card-room-facts { font-family: var(--sans); }
.more { display: table; margin: 3rem auto 0; border: 1px solid var(--navy); border-radius: 99px; padding: .8rem 1.5rem; color: var(--navy); text-decoration: none; }
.empty { padding: 3rem; background: var(--warm); border-radius: 18px; }

.property-hero { padding: clamp(1.75rem, 5vw, 4.5rem) clamp(1.2rem, 5vw, 5rem); display: grid; grid-template-columns: minmax(0, .95fr) minmax(420px, 1.05fr); align-items: center; gap: clamp(2rem, 4vw, 4rem); background: var(--warm); }
.property-hero > *, .hero-copy { min-width: 0; }
/* P2.51B §H — reduced from clamp(2.5rem, 4.2vw, 3.9rem): the property
   name must read as clear, premium identity without visually
   overpowering stay selection, Room Explorer, price or the booking CTA
   below it — narrowly scoped to this selector only. */
.hero-copy h1 { max-width: 100%; font-size: clamp(1.9rem, 3vw, 2.9rem); font-weight: 500; line-height: 1.08; letter-spacing: -.02em; overflow-wrap: break-word; hyphens: auto; text-wrap: balance; }
.location { font-size: .78rem; letter-spacing: var(--tracking-eyebrow); font-weight: var(--weight-eyebrow); text-transform: uppercase; }
/* P2.53 §7 — Brand sits inline with location (same restrained label
   treatment, not a second heading); Group is deliberately a separate,
   quieter line below — secondary information, never mechanically next
   to the property name. */
.brand-name { color: var(--navy); }
.brand-group { margin: .2rem 0 0; font-size: .72rem; letter-spacing: normal; text-transform: none; font-weight: 500; color: var(--muted); }
.lead { font-family: var(--serif); font-size: clamp(1.2rem, 2vw, 1.65rem); color: var(--muted); max-width: 600px; }
/* Property-page final premium refinement — narrowed from a 6-line clamp:
   the hero should introduce the property, not consume excessive
   vertical space before Room Explorer. "Read more" (JS-measured, never
   a server-side truncation) now appears somewhat more often, which is
   the intended trade — the full description is always one click away,
   never lost. */
.lead.is-collapsed { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.lead-toggle { display: block; margin: .4rem 0 0; padding: 0; border: 0; background: none; color: var(--navy); font: inherit; font-size: .85rem; font-weight: 650; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.lead-toggle[hidden] { display: none; }
.lead-toggle:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; }
/* One compact, authoritative arrival-accessibility fact — never a large
   block, never competing with the price/CTA below it. Same treatment
   family as search cards' .arrival-line. */
.hero-transfer { margin: var(--space-xs) 0 0; font-size: .85rem; color: var(--muted); }
.button { display: inline-block; border-radius: 99px; margin-top: 1.3rem; }
/* P2.51C §E — the arch/dome radius here (was 180px 180px 24px 24px)
   read as boutique-hospitality/editorial rather than a calm modern OTA,
   and was the one surface in the whole journey not sharing the
   property-card/room-card 20px rounded-rect language. Normalized to
   match. */
/* P2.53 final visual gate — was aspect-ratio 1.1 (near-square): P2.52's
   own pass fixed this element's SHAPE (arch -> rounded-rect) but never
   checked its PROPORTIONS, which stayed the one image on the entire
   site not sharing the 16/10 ratio every card/highlight/room image
   already uses. At a realistic 1440x900 laptop viewport this alone
   measured 591px tall — 66% of the viewport — pushing the first
   room's Select button to 2.3x viewport height before any scroll.
   16/10 matches every other image site-wide (family resemblance) and
   is the single largest contributor to reaching Room Explorer sooner. */
.hero-media { position: relative; min-width: 0; aspect-ratio: 16 / 10; border-radius: 20px; overflow: hidden; }

/* P2.53 §D — compact, real "why stay here" content (catalog_property_
   highlights); deliberately lighter-weight than .amenities below it —
   this is a handful of cards, not a dense fact list, and must not add
   vertical ceremony before Room Explorer. auto-fit means 1/2/3 cards
   read as intentional regardless of how many highlights a property
   actually has. */
/* P2.71 surgical correction — Room Explorer/.highlights/.amenities/
   .getting-there previously ran as four consecutive sections with no
   background of their own (all inheriting the plain white body), the
   longest unbroken plane on the page. Tinting this one section reuses
   the exact white-card-on-warm treatment already proven elsewhere on
   this same page (.review-section/.review-grid article) rather than
   inventing a new pattern — .highlight-card's own white background is
   unchanged. */
.highlights { padding: clamp(2rem, 4vw, 3rem) clamp(1.2rem, 7vw, 7rem) 0; background: var(--warm); }
.highlights h2 { font-size: clamp(1.3rem, 2vw, 1.75rem); font-weight: 500; letter-spacing: -.01em; margin: 0 0 1.1rem; }
.highlights-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.1rem; }
.highlight-card { min-width: 0; border: 1px solid var(--line); border-radius: 16px; overflow: hidden; background: #fff; }
.highlight-card img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; display: block; }
.highlight-body { padding: 1rem 1.15rem 1.2rem; }
.highlight-category { margin: 0 0 .3rem; font-size: .68rem; font-weight: var(--weight-eyebrow); letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: #8c741f; }
/* P2.71 surgical correction — 600 has no real Georgia face and was
   resolving to the same Bold glyphs as 700, reading heavier than this
   card's own parent (.highlights h2, 500) sitting directly above it.
   500 resolves to Georgia's actual Regular face, matching the same fix
   already applied to the sibling .card-body h3/.room-content h3 (see
   their own P2.69 comments above). */
.highlight-body h3 { margin: 0 0 .4rem; font-size: 1.15rem; font-weight: 500; overflow-wrap: anywhere; }
/* Property-page final premium refinement — visual conciseness only
   (never a content rewrite): each reason reads as a few useful lines,
   never a mini paragraph competing with the others for attention.
   Raised from a 2-line clamp (V2 correction) — 2 lines cut off several
   real authored summaries mid-thought; 3 comfortably fits a complete
   sentence for most of this property's authored highlights while
   staying clearly more compact than the original unclamped text.
   Admin-authored text is untouched; this only clamps how much of it is
   shown at a glance. */
.highlight-body p:last-child { margin: 0; color: var(--muted); font-size: .88rem; line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }

/* aAlabu Takes — deliberately NOT styled like a review card
   (.review-grid article: bordered box, big score, guest byline) or a
   highlight card (photo, category chip): a thin left accent rule and
   plain text is the whole treatment, so its restraint itself signals
   "this is a brief aAlabu note," never a guest testimonial.
   Owner visual-QA correction — stacked vertically (never a two-column
   testimonial-like row: that read as a pair of review cards, exactly
   what this must not resemble) and capped to a readable measure rather
   than spanning the full content width, matching how a pull-quote or
   editorial aside is set in print, not a data grid. Extra top padding
   (vs. .highlights' clamp(2rem,4vw,3rem)) gives it its own clear
   breathing room after Room Explorer rather than reading as one
   continuous block with whatever precedes it. */
/* Good to know before you stay — compact disclosure rows of verified, unambiguous facts. */
.before-you-stay { padding: clamp(2.75rem, 5vw, 4.25rem) clamp(1.2rem, 7vw, 7rem) 0; background: #fff; }
.before-you-stay-card { max-width: 640px; padding: 1.5rem 1.75rem; border: 1px solid #e6e1d4; border-radius: 14px; background: #fffdf8; }
.before-you-stay-title { margin: 0 0 .9rem; font-size: 1.25rem; font-weight: 600; color: var(--ink); }
.gtk-groups { display: flex; flex-direction: column; }
.gtk-group { border-top: 1px solid #efe9d9; }
.gtk-group:first-child { border-top: 0; }
/* Plain and expandable rows share one box, so titles, summaries and wrapping are identical. The chevron sits on the
   title line (absolutely positioned) and never narrows the summary text. */
.gtk-group > summary, .gtk-group--static { display: block; padding: .8rem 0; }
.gtk-group > summary { position: relative; cursor: pointer; list-style: none; }
.gtk-group > summary::-webkit-details-marker { display: none; }
.gtk-group > summary::after { content: "›"; position: absolute; right: .25rem; top: .8rem; color: var(--muted); font-size: 1.1rem; line-height: 1.2; transition: transform .15s ease; }
.gtk-group[open] > summary::after { transform: rotate(90deg); }
.gtk-group > summary:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; border-radius: 4px; }
.gtk-title { display: block; margin: 0; color: var(--muted); font-size: .72rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
.gtk-summary { display: block; margin: .2rem 0 0; color: var(--ink); font-size: .98rem; line-height: 1.5; overflow-wrap: anywhere; }
.gtk-details { margin: 0 0 .8rem; padding: 0 0 0 1rem; color: var(--ink); font-size: .93rem; line-height: 1.55; }
.gtk-details li { margin: .25rem 0; overflow-wrap: anywhere; }
@media (max-width: 640px) { .before-you-stay-card { padding: 1.25rem 1.25rem; } .gtk-summary { font-size: .95rem; } }
/* Desktop: the card spans the same content width as the sections around it (the section's own side padding), and
   the disclosure rows flow in DOM order across two columns, equal width so a missing group never changes the hierarchy.
   Rows align to the top so opening one never stretches or moves its neighbour. Below 900px nothing changes. */
@media (min-width: 900px) {
  .before-you-stay-card { max-width: none; padding: 1.75rem 2.25rem 1.5rem; }
  .gtk-groups { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: clamp(2.5rem, 5vw, 4.5rem); align-items: start; }
  .gtk-group:nth-child(2) { border-top: 0; }
}

.aalabu-takes { padding: clamp(2.75rem, 5vw, 4.25rem) clamp(1.2rem, 7vw, 7rem) 0; background: #fff; }
.aalabu-takes .eyebrow { margin: 0 0 1rem; }
.aalabu-takes-list { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.25rem; max-width: 640px; }
.aalabu-takes-list--pair { max-width: 880px; }
.aalabu-take { margin: 0; padding-left: 1rem; border-left: 2px solid #d9c48a; color: var(--ink); }
.aalabu-take-label { margin: 0 0 .25rem; color: var(--muted); font-size: .72rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; font-style: normal; }
.aalabu-take-body { margin: 0; font-size: .95rem; line-height: 1.6; font-style: italic; overflow-wrap: anywhere; }
@media (min-width: 720px) { .aalabu-takes-list--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.75rem; } }
@media (min-width: 900px) { .aalabu-takes-list--pair { max-width: none; gap: clamp(2.5rem, 5vw, 4.5rem); } }

/* P2.53 §G/§H — the strongest 2-4 room-comparison facts (view/
   beachfront/private pool/etc.), styled distinctly from the plain
   grey .chips (generic amenities) below so they read as the higher-
   priority signal the brief calls for — a warm gold tint rather than
   a new colour, staying inside the existing accent family. */
.differentiators { display: flex; flex-wrap: wrap; gap: .4rem; margin: .6rem 0 0; }
.differentiators span { border: 1px solid #d9c48a; background: var(--warm); color: #7a5f14; border-radius: 99px; padding: .3rem .7rem; font-size: .74rem; font-weight: 650; }

/* Property-page final premium refinement — top normalized to the same
   value .highlights already uses (one consistent "major section gap"
   figure across the page instead of a one-off 3.5rem), bottom set to 0
   so this section never compounds with review-section's own top gap
   below it (same top-owns-the-gap rule as .rooms-section/.highlights). */
.amenities { padding: clamp(2rem, 4vw, 3rem) clamp(1.2rem, 7vw, 7rem) 0; display: grid; grid-template-columns: .8fr 1fr; gap: 2rem; background: #fff; }
/* P2.53 final visual gate — .amenities has 3 direct grid children
   (eyebrow, h2, the chips div) across a 2-column grid with no explicit
   placement, so default row-major auto-flow put the eyebrow and h2
   side-by-side on row 1 (splitting the intended "eyebrow above
   heading" pairing used by every other section) and left the chips
   div alone on row 2 — an empty column-2 rectangle roughly half the
   section's height, not a deliberate composition. Explicit placement
   restores the eyebrow+heading stack in column 1 and lets the chips
   list occupy column 2 for the section's full height, matching the
   left-label/right-content composition the .8fr/1fr split was
   clearly authored for. The @media(max-width:900px) override below
   switches to display:block, where these placements simply don't
   apply and DOM order (eyebrow, h2, div) already stacks correctly. */
.amenities p.eyebrow { grid-column: 1; grid-row: 1; }
.amenities h2 { grid-column: 1; grid-row: 2; font-size: clamp(1.5rem, 2.6vw, 2.35rem); font-weight: 500; letter-spacing: -.01em; }
.amenities > div { grid-column: 2; grid-row: 1 / span 2; align-self: center; display: grid; grid-template-columns: repeat(2, 1fr); gap: .8rem 1.5rem; align-content: center; }
.amenities span { border-bottom: 1px solid var(--line); padding: .6rem 0; }

/* P2.73 — the property-level commercial transfer selector. A single
   restrained, calm card (never the same large section-title treatment
   as .rooms-section — a decision aid, not a competing primary section),
   sitting between the stay-picker form and Room Explorer. Mirrors
   .transfer-summary's own established "plain class sets display: flex
   unconditionally, so [hidden] (0,1,1) must stay more specific than the
   bare class (0,1,0) to actually collapse to zero visual space" fix. */
.transfer-selector {
    margin: 1.4rem clamp(1.2rem, 7vw, 7rem) 0; padding: 1.2rem 1.4rem;
    background: var(--warm); border: 1px solid var(--line); border-radius: 16px;
    display: flex; flex-direction: column; gap: .5rem;
}
.transfer-selector[hidden] { display: none; }
.transfer-selector .eyebrow { margin: 0; }
.transfer-selector h2 { margin: 0; font-size: clamp(1.05rem, 1.6vw, 1.3rem); font-weight: 500; }
.transfer-select-intro { margin: 0; color: var(--muted); font-size: .85rem; }
.transfer-select-blocked { margin: 0; color: #8c3a1f; font-size: .88rem; line-height: 1.5; }

.transfer-select-list { list-style: none; margin: .3rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .5rem; }
/* CLOSE-4D.2 — the optional property-arranged transfer picker offered
   at Review Total/checkout (never before Room Explorer) is a single-
   click "Add transfer" per row, never a radiogroup + separate confirm
   step (adding an optional ancillary needs no deliberate confirmation
   the way a mandatory decision once did) — so this is the row's own
   layout directly, not a wrapping <label>/<input radio>. */
.transfer-select-option {
    display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .7rem;
    border: 1px solid var(--line); border-radius: 12px; background: #fff; padding: .75rem .9rem;
}
.transfer-select-option.is-disabled { opacity: .6; }
.transfer-select-option .transfer-select-confirm-button { flex: 0 0 auto; padding: .5rem 1rem; min-height: 38px; }
.transfer-select-option-body { display: flex; flex-direction: column; gap: .15rem; }
.transfer-select-option-name { font-weight: 650; color: var(--ink); font-size: .92rem; }
.transfer-select-price { color: var(--navy); font-weight: 650; font-size: .85rem; }
/* P2.72/P2.73 — a lighter weight than the price itself so the amount
   stays the visual lead, while still reading as a distinct commercial fact. */
.transfer-select-payable-note { font-weight: 500; color: var(--muted); }
.transfer-select-note { font-size: .74rem; color: var(--muted); }
.transfer-select-note-ineligible { color: #8c3a1f; }

.transfer-select-confirm-button {
    align-self: flex-start; border: 0; border-radius: 10px; background: var(--navy); color: #fff;
    padding: .7rem 1.3rem; font-weight: 650; font-size: .86rem; cursor: pointer; min-height: 44px;
}
.transfer-select-confirm-button:disabled { opacity: .5; cursor: not-allowed; }
.transfer-select-confirm-button:not(:disabled):hover, .transfer-select-confirm-button:not(:disabled):focus-visible { outline: 3px solid #d4af3780; outline-offset: -3px; }

.transfer-select-confirmed { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; font-size: .88rem; color: var(--ink); }
.transfer-select-change {
    border: 1px solid var(--line); background: #fff; border-radius: 8px; padding: .3rem .7rem;
    font-size: .78rem; font-weight: 650; color: var(--navy); cursor: pointer; min-height: 32px;
}
.transfer-select-change:hover, .transfer-select-change:focus-visible { outline: 3px solid #d4af3780; outline-offset: -2px; }

/* CLOSE-4D.2 — the optional transfer picker's own container inside
   `.checkout-summary`, visually subordinate to the accommodation price
   above it (smaller eyebrow, no card/border of its own — the picker's
   OWN option rows already carry their own border via
   .transfer-select-option). */
.checkout-transfer-picker { margin-top: .6rem; }
.checkout-transfer-picker[hidden] { display: none; }
.checkout-transfer-picker .eyebrow { margin: 0 0 .3rem; }
.transfer-select-picker-body { margin-top: .6rem; display: flex; flex-direction: column; gap: .5rem; }
.transfer-select-picker-body[hidden] { display: none; }

.room-scroll-hint { display: none; color: var(--muted); font-size: .83rem; font-weight: 600; }
/* Property-page final premium refinement V2 — the previous rigid
   3-column grid left large accidental empty space whenever a property
   had fewer than 3 currently visible/bookable rooms (a single card
   stranded on the far left, or an awkward empty third column). `repeat
   (auto-fit, minmax(300px, 360px))` sizes each card to its own natural
   ~300-360px width regardless of how many exist, and `justify-content:
   center` centers whatever fits as one balanced group instead of
   pinning it to the start — 1 room reads as an intentional single-card
   composition, 2 as a balanced pair, 3+ wraps into the same comparison
   grid as before. No JS, no per-property logic, no fixed heights. Only
   takes effect ≥1100px — the <1099px horizontal-scroll rule further
   below already handles 1/2/3+ rooms gracefully on its own. */
.room-scroller { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 360px)); justify-content: center; align-items: stretch; gap: 1.4rem; max-width: 100%; padding: 1rem 1px 2rem; }
/* Property-page final visual correction — exactly one room category
   gets a modestly wider premium card (≥1100px only — below that,
   .room-scroller is the horizontal-scroll carousel, which already
   presents a single room as one naturally-sized card). Photography
   scales with the card automatically via .room-card > img's existing
   width:100%/aspect-ratio rule — no separate image rule needed. */
@media (min-width: 1100px) {
    .room-scroller--single { grid-template-columns: minmax(300px, 440px); }
}
.room-card { min-width: 0; height: 100%; display: flex; flex-direction: column; border: 1px solid var(--line); background: #fff; color: var(--ink); border-radius: 20px; overflow: hidden; box-shadow: 0 10px 26px #0e223912; }
.room-card > img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; flex: 0 0 auto; }
.room-fallback { min-height: 230px; display: grid; place-items: center; padding: 1rem; background: linear-gradient(145deg, #e9e5dc, #f8f5ef); color: var(--navy); text-align: center; }
.room-content { min-width: 0; padding: 1.3rem; flex: 1; display: flex; flex-direction: column; }
/* Property-page final visual correction — two things previously
   compounded into one large gap: (1) `margin-top: auto` pinned this
   block to the bottom of the (equal-height, per .room-scroller's
   align-items:stretch) card, stretching by however much shorter this
   room's content was than its tallest row sibling; (2) this wrapper's
   OWN `padding-top: .9rem` stacked on top of `.room-price`'s/
   `.room-unavailable`'s already-present `margin-top: 1rem; padding-top:
   .9rem; border-top` — a redundant second gap before the same visual
   separator line. Both removed: the wrapper itself now carries no
   spacing of its own, and .room-price/.room-unavailable's existing
   rule is the single, deliberate source of the gap — natural
   information density over perfectly equal card bottoms (owner
   correction); no fixed/min-heights, no spacer elements. */
.room-commercial { margin-top: 0; }
/* P2.69 typography audit — no font-weight was set here, so this fell
   through to the browser's default bold (~700) for h3: heavier than the
   Property title's own explicit 500 one level up. 600 matches the
   secondary-serif-heading weight already used for .card-body h3 (search
   result name) and .highlight-body h3, giving Room Explorer's room name a
   calmer, but still prominent, sibling to those. */
/* P2.69 final micro-correction — 600 still read as visually bold: Georgia
   has no real 600 face, so the browser was resolving it to the same Bold
   glyphs as 700. 500 resolves to the font's actual Regular face, the
   lightest weight that is a genuine optical change rather than a numeric
   one — see .card-body h3's comment above for the full explanation. */
.room-content h3 { margin: 0 0 .55rem; color: var(--navy); font-weight: 500; font-size: clamp(1.4rem, 1.8vw, 1.7rem); letter-spacing: -.01em; line-height: 1.16; overflow-wrap: anywhere; }
.room-content > p { margin: 0; color: var(--muted); line-height: 1.5; overflow-wrap: anywhere; }
/* Property-page final premium refinement V2 — replaces the previous
   3-row Space/Sleeps/Beds spec table with one compact, economical fact
   line ("74 m² · Sleeps 2 · 1 king bed"). Still real, materially useful
   decision facts (kept, per owner correction) — just not three bordered
   table rows. Wraps naturally at narrow widths (flex-wrap, not a rigid
   grid), so it stays comfortably readable at 320/390px without a
   separate breakpoint override. */
.room-facts { margin: .6rem 0 0; color: var(--ink); font-size: .82rem; line-height: 1.5; overflow-wrap: anywhere; }
.chips { display: flex; flex-wrap: wrap; gap: .38rem; }
.chips span { border: 1px solid var(--line); background: var(--warm); color: var(--ink); border-radius: 99px; padding: .27rem .6rem; font-size: .72rem; }
/* Property-page final premium refinement — Room Explorer is a
   comparison surface, not an amenity inventory: generic room amenities
   (Minibar, Air Conditioning, Bathtub...) sit behind a collapsed native
   <details> so they never compete with the always-visible
   differentiators above, while remaining fully available on demand —
   same disclosure mechanic as .rate-options below, deliberately quieter
   (smaller, muted) since amenities are lower comparison value than rate
   alternatives. */
.room-amenities { margin: .5rem 0 0; }
.room-amenities summary { cursor: pointer; list-style: none; display: flex; align-items: center; gap: .25rem; min-height: 32px; color: var(--muted); font-weight: 600; font-size: .76rem; }
.room-amenities summary::-webkit-details-marker { display: none; }
.room-amenities summary::after { content: '›'; display: inline-block; transform: rotate(90deg); transition: transform .15s ease; font-size: .9rem; }
.room-amenities[open] summary::after { transform: rotate(270deg); }
.room-amenities summary:focus-visible { outline: 3px solid var(--navy); outline-offset: 3px; border-radius: 4px; }
.room-amenities .chips { margin-top: .5rem; }

/* Room Explorer card refinement (Phase A) — decision facts lead the card.
   Scoped as `.room-content > …` because the older `.room-content > p` rule
   (muted colour, zero margin) is more specific than a bare class and was
   silently flattening the facts line into body text. */
.room-content > .room-facts { margin: 0; color: var(--navy); font-size: .9rem; font-weight: 600; line-height: 1.45; }
.room-content > .room-summary { margin: .7rem 0 0; color: var(--muted); font-size: .9rem; line-height: 1.5; }
/* Clamp applied by catalogue-gallery.js only when the text overflows three
   lines; without JS the full summary shows. */
.room-content > .room-summary.is-clamped { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.room-summary-toggle { align-self: flex-start; margin: .25rem 0 0; padding: .2rem 0; border: 0; background: none; color: var(--navy); font: inherit; font-size: .78rem; font-weight: 650; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.room-summary-toggle:focus-visible { outline: 3px solid var(--navy); outline-offset: 3px; border-radius: 4px; }
/* Distinctive features support the facts line rather than out-shout it. */
.room-content .differentiators { margin-top: .7rem; }
.room-content .differentiators span { background: transparent; border-color: #e3d6ad; color: #6b5718; font-weight: 600; }
/* Guest combinations: the icon stays beside its text when the line wraps. */
.room-content .room-occupancy { flex-wrap: nowrap; align-items: flex-start; }
.room-content .room-occupancy .room-occupancy-icon { margin-top: .15rem; }
/* The empty status line no longer reserves space under the button; it
   still appears (aria-live) when there is something to say. */
.room-select-status:empty { min-height: 0; margin: 0; }

/* P2.31 — the property page's own compact dates/guests form, sharing
   .search-form's field/button styling but with its own column count
   (no destination field) and no extra top margin since it sits directly
   under the Room Explorer intro rather than a hero. */
.stay-picker-form.search-form { grid-template-columns: repeat(3, 1fr) auto; margin: 1.25rem 0 2rem; }

.room-price { margin-top: 1rem; padding-top: .9rem; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: .25rem; }
.room-price strong { font-size: 1.3rem; color: var(--navy); }
/* Property-page final visual correction — this is booking-decision
   information (nights, meal inclusion, cancellation terms), not fine
   print: raised from .78rem/default line-height so it stays clearly
   readable at 320/390px without visually competing with the price
   above it (still noticeably smaller, still var(--muted)). */
.room-price span { font-size: .85rem; line-height: 1.45; color: var(--muted); }

/* P2.48E §C — restrained strike-through + concise benefit label,
   suppressed entirely (see accommodation-price.blade.php) unless a
   Promotion actually moved the displayed price. Reused identically by
   both the primary .room-price block and each .rate-option-action row —
   sized by its ancestor's own existing `strong`/`span` rules, never a
   separate size system. */
.price-original { font-size: .78rem; color: var(--muted); }
.price-original s { text-decoration-thickness: 1.5px; }
.promotion-badge { display: inline-block; margin-top: .15rem; font-size: .72rem; font-weight: 700; color: #8a711d; }
.room-select {
    display: block; width: 100%; margin-top: .8rem; border: 0; border-radius: 99px; padding: .75rem 1rem;
    background: var(--navy); color: #fff; font-weight: 750; font-size: .88rem; cursor: pointer;
}
.room-select:hover:not(:disabled) { background: #17334e; }
.room-select:disabled { opacity: .6; cursor: not-allowed; }
.room-select-status { min-height: 1rem; margin: .5rem 0 0; font-size: .76rem; color: var(--muted); }
.room-select-status[data-kind="error"] { color: #9c3b2c; font-weight: 650; }
.room-select-status[data-kind="success"] { color: #3f7d4a; }
.room-unavailable { margin-top: 1rem; padding-top: .9rem; border-top: 1px solid var(--line); font-size: .82rem; color: var(--muted); }
.room-unavailable-note { margin-top: .35rem; font-size: .82rem; color: var(--muted); }

/* P2.32 — RatePlan choice: the recommended offer stays the primary CTA
   above (unchanged markup/styling); when a room has more than one
   currently sellable RatePlan, a restrained <details> disclosure below
   it exposes the rest without turning the card into a dense rate table. */
.room-price-eyebrow { margin: 0 0 .15rem; font-size: .66rem; font-weight: var(--weight-eyebrow); text-transform: uppercase; letter-spacing: var(--tracking-eyebrow); color: #8a711d; }

.rate-options { margin-top: .9rem; }
.rate-options summary {
    cursor: pointer; list-style: none; display: flex; align-items: center; gap: .3rem; min-height: 44px;
    color: var(--navy); font-weight: 650; font-size: .82rem;
}
.rate-options summary::-webkit-details-marker { display: none; }
.rate-options summary::after { content: '›'; display: inline-block; transform: rotate(90deg); transition: transform .15s ease; font-size: 1rem; }
.rate-options[open] summary::after { transform: rotate(270deg); }
.rate-options summary:focus-visible { outline: 3px solid var(--navy); outline-offset: 3px; border-radius: 4px; }

.rate-option-list { list-style: none; margin: .7rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .7rem; }
.rate-option { display: flex; justify-content: space-between; align-items: flex-end; gap: .8rem; padding-top: .7rem; border-top: 1px solid var(--line); }
.rate-option-info { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.rate-option-info strong { color: var(--navy); font-size: .88rem; }
.rate-option-info span { font-size: .74rem; color: var(--muted); overflow-wrap: anywhere; }
.rate-option-action { display: flex; flex-direction: column; align-items: flex-end; gap: .35rem; flex: 0 0 auto; }
.rate-option-action > strong { font-size: .92rem; color: var(--navy); }
.rate-option-select {
    display: inline-flex; align-items: center; justify-content: center; min-height: 44px;
    border: 1px solid var(--navy); border-radius: 99px; background: transparent; color: var(--navy);
    padding: 0 .9rem; font-weight: 650; font-size: .78rem; cursor: pointer; white-space: nowrap;
}
.rate-option-select:hover:not(:disabled) { background: var(--navy); color: #fff; }
.rate-option-select:disabled { opacity: .6; cursor: not-allowed; }
.rate-option .room-select-status { text-align: right; }

/* P2.37D.5 — "What's included" disclosure. A native <details>/<summary>
   control: keyboard-operable (Tab + Enter/Space), touch-operable, no
   hover dependency — matches .rate-options' own established pattern. */
.meal-plan-disclosure { margin: .5rem 0; }
.meal-plan-disclosure summary {
    cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: .3rem; min-height: 44px;
    color: var(--navy); font-weight: 650; font-size: .78rem; text-decoration: underline; text-underline-offset: 2px;
}
.meal-plan-disclosure summary::-webkit-details-marker { display: none; }
.meal-plan-disclosure summary:focus-visible { outline: 3px solid var(--navy); outline-offset: 3px; border-radius: 4px; }
.meal-plan-disclosure-body { margin-top: .4rem; padding: .7rem .8rem; border-radius: 10px; background: var(--warm); font-size: .78rem; color: var(--muted); }
.meal-plan-summary { margin: 0 0 .4rem; color: var(--navy); font-weight: 600; }
.meal-plan-facts { list-style: none; margin: 0 0 .4rem; padding: 0; display: flex; flex-direction: column; gap: .25rem; }
.meal-plan-fact { overflow-wrap: anywhere; }
.meal-plan-fact--not_included { text-decoration: line-through; opacity: .75; }
.meal-plan-description, .meal-plan-conditions { margin: .4rem 0 0; }

/* Property-page final premium refinement — .review-section previously
   relied entirely on the shared `.results, .rooms-section,
   .review-section` rule for its own padding (up to clamp(3rem,7vw,7rem)
   on every side), which stacked directly on top of .amenities' own
   fixed 3.5rem bottom above it — the single largest compounded gap on
   the page. Normalized to the same major-section-gap figure used
   everywhere else on this page (.highlights/.amenities), applied only
   here so .results (search results) is completely unaffected. */
.review-section { padding: clamp(2rem, 4vw, 3rem) clamp(1.2rem, 7vw, 7rem); background: var(--warm); }
/* P2.53 final visual gate — the empty-reviews state ("A new story on
   aAlabu." + one line of body copy) has no grid or averages list to
   fill the section's width, so at large-desktop widths (1440px+) it
   read as an unexplained sparse gap of empty right-hand space rather
   than a deliberate composition. Direct-child selector only: never
   touches review-grid's own nested article paragraphs or the
   populated review-averages layout, both unrelated and unaudited
   here. Matches the existing .search-hero h1 max-width precedent. */
.review-section > h2, .review-section > p { max-width: 640px; }
/* P2.69 §G — compact aligned category summary. Two columns from the
   narrowest supported width up (six stacked label/value pairs was the
   "long vertical list before the actual reviews" the brief called out),
   sans-serif throughout because these are comparison metrics, not
   editorial content. */
.review-averages { display: grid; grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: .7rem 1.4rem; margin: 1.2rem 0 0; font-family: var(--sans); }
.review-averages > div { min-width: 0; }
.review-averages dt { font-size: .78rem; color: var(--ink); }
.review-averages dd { margin: .12rem 0 0; display: grid; grid-template-columns: 1fr auto; align-items: center; gap: .5rem; }
.review-average-value { grid-column: 2; grid-row: 1; font-size: .82rem; font-weight: 700; color: var(--navy); }
.review-average-bar { grid-column: 1; grid-row: 1; height: 4px; border-radius: 99px; background: #e2ded2; }
.review-average-bar::before { content: ""; display: block; width: var(--fill, 0%); height: 100%; border-radius: inherit; background: var(--gold); }

/* align-items: start — review cards size to their own content. Stretched
   to a common height, a two-line review next to a fifteen-line one left a
   large empty card, which read as missing content rather than a short
   review. */
.review-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; align-items: start; }
.review-grid article { min-width: 0; background: #fff; border-radius: 16px; padding: 1.4rem; }
.review-grid article > strong { color: #8a711d; font-size: 1.4rem; }
/* P2.69 typography audit — review titles had no dedicated rule, so they
   fell through to the same browser bold-h3 default as the two rules above,
   visually competing with the score directly beside them. Calmer weight +
   a size closer to body text, still serif so it reads as a small heading
   rather than another paragraph. */
/* P2.69 final micro-correction — same Georgia-has-no-600-face issue as
   .card-body h3 / .room-content h3 above; 500 is the lightest weight that
   resolves to the real Regular face instead of silently matching Bold. */
.review-grid article h3 { margin: .3rem 0 .5rem; font-size: 1.05rem; font-weight: 500; }
/* P2.69 final micro-correction — compact reading state for long reviews.
   `.is-collapsed` uses the same -webkit-line-clamp technique already used
   above for .card-body h3 (search-result name truncation); ~7 lines was
   the requested visual target. The toggle button is revealed by JS only
   when a given review's real content actually overflows that clamp, so a
   short review (e.g. a title-only entry) never grows an empty control. */
.review-body p { margin: 0; }
.review-body.is-collapsed { display: -webkit-box; -webkit-line-clamp: 7; -webkit-box-orient: vertical; overflow: hidden; }
.review-toggle { display: block; margin: .6rem 0 .7rem; padding: 0; border: 0; background: none; color: var(--navy); font: inherit; font-size: .85rem; font-weight: 650; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
/* P2.69 review-toggle verification fix — `display: block` above is
   author-origin CSS, which always wins over the UA stylesheet's own
   `[hidden] { display: none }` rule regardless of selector specificity.
   Without this, a review the JS correctly decided did NOT need expanding
   (so left the button's `hidden` attribute untouched) still rendered as a
   visible, non-functional "Read more" — a real defect found during live
   verification, distinct from the earlier byline-spacing fix. This
   restores the native hidden-attribute behaviour for this one element. */
.review-toggle[hidden] { display: none; }
.review-toggle:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; }
.review-grid blockquote { margin: 1rem 0 0; padding: 1rem; border-left: 2px solid var(--gold); background: var(--warm); font-size: .85rem; }
.review-grid blockquote b { display: block; }
.large { min-height: 100%; }

/* P2.43A §N — a subtle SECONDARY signal, deliberately small and quiet:
   never the same visual weight as the aAlabu score above it, never
   implying a combined rating. Empty (no layout) until the client script
   populates it on demand. */
/* Deliberately NOT hidden via `:empty` — a display:none element has no
   layout box, so IntersectionObserver could never detect it entering
   the viewport and the on-demand fetch would never trigger. The
   client script instead sets `display:none` explicitly (via
   `[data-visible="false"]`) only once a fetch has resolved to nothing
   worth showing. */
.external-reputation { margin-top: 1.5rem; padding-top: 1.5rem; border-top: 1px solid var(--line); max-width: 22rem; min-height: 1.2rem; }
.external-reputation[data-visible="false"] { display: none; }
.external-reputation__eyebrow { font-size: .68rem; font-weight: var(--weight-eyebrow); letter-spacing: var(--tracking-eyebrow); color: var(--muted); text-transform: uppercase; margin: 0 0 .3rem; }
.external-reputation__score { font-size: 1.1rem; margin: 0; color: var(--ink); }
.external-reputation__score strong { font-size: 1.35rem; }
.external-reputation__count { display: inline-block; margin-left: .5rem; color: var(--muted); font-size: .85rem; }
.external-reputation__link { display: block; margin-top: .3rem; font-size: .85rem; color: var(--navy); }
.external-reputation__attribution { margin: .4rem 0 0; font-size: .72rem; color: var(--muted); }
.external-reputation__hint { font-size: .8rem; color: var(--muted); margin: 0; }

@media (max-width: 1099px) {
    .room-scroll-hint { display: block; margin: 1.25rem 0 .1rem; }
    /* Property-page final visual correction — the previous `62%`
       exposed roughly 200px+ of the next card at tablet widths (a
       percentage of a wide track), reading as sliced/broken rather than
       an intentional small peek. `calc(100% - 36px)` reserves a
       CONSTANT ~36px — this rule's own 1.4rem (22.4px) gap plus a
       genuinely small ~14px peek — regardless of viewport width,
       instead of a percentage that scales unpredictably. */
    /* Reachability: a centred track that overflows pushes its first
       cards past the scroll start, where no scrolling can reach them.
       `safe center` still centres rooms that fit but falls back to the
       start edge as soon as they overflow; browsers without `safe`
       (Safari < 17.6) keep the preceding `start`, so every room stays
       reachable everywhere. */
    .room-scroller { justify-content: start; justify-content: safe center; grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(300px, calc(100% - 36px)); overflow-x: auto; overflow-y: visible; scroll-snap-type: inline mandatory; scroll-padding-inline: 1px; overscroll-behavior-inline: contain; scrollbar-color: var(--gold) #e8e5de; }
    .room-card { scroll-snap-align: start; }
}

@media (max-width: 900px) {
    .search-hero { padding-top: clamp(2.1rem, 6vw, 3.4rem); }
    /* P2.52 — font-size override removed here: the base rule's single
       fluid clamp now covers this range too, avoiding the discontinuity
       a second breakpoint-specific clamp previously introduced. */
    .search-form { grid-template-columns: 1fr 1fr; }
    .search-form label:first-child, .search-form .destination-cell { grid-column: 1 / -1; }
    .search-form button { min-height: 56px; }
    .stay-picker-form.search-form { grid-template-columns: 1fr 1fr; }
    .property-hero { grid-template-columns: minmax(0, 1fr); padding-top: 2.3rem; }
    .hero-copy h1 { font-size: clamp(1.9rem, 5vw, 2.6rem); }
    /* Photography-first on mobile/tablet: the image is decorative relative
       to the copy (a photo, not sequential content), so reordering it
       visually ahead of the text via `order` — without touching DOM/reading
       order — is the low-risk option per the brief's own preference for
       CSS-only presentation changes over structural duplication. */
    /* P2.53 final acceptance verification — was aspect-ratio 1.25 (0.8x
       width tall). At this breakpoint hero-copy and hero-media STACK
       (via `order: -1` above) instead of sitting side by side, so a
       taller ratio here is backwards: it adds height at exactly the
       widths where the image and text already cost vertical space
       twice over. Measured live at 900px width/900px viewport: the
       hero section alone was 989px tall — taller than the entire
       viewport, before any other content. Matches the exact defect
       class already fixed in the base desktop rule above (C3); this
       override was flagged then as unaudited and is fixed now with
       the same 16/10 ratio for consistency with every image site-wide. */
    .hero-media { order: -1; aspect-ratio: 16 / 10; border-radius: 20px; }
    .review-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 600px) {
    .site-header { min-height: 64px; padding: .5rem 1.1rem; }
    .site-header span { display: none; }
    /* POST-CUTOVER-3 — every non-search page's "Explore stays" link is
       pure duplication of the brand mark immediately to its left once
       space is this tight (both go to /search); dropping it here is
       what keeps "Find my booking" + "Sign in" from wrapping onto
       their own lines at narrow widths, matching the search page's
       own span already disappearing at this exact breakpoint. */
    .site-nav-explore { display: none; }
    .search-hero { padding: 2.1rem 1rem 1.35rem; }
    /* P2.52 — only line-height tightens here now (a legitimate small-
       size refinement); font-size is governed entirely by the base
       rule's single fluid clamp, so no second breakpoint-specific size
       jump is introduced at this boundary either. */
    .search-hero h1 { line-height: 1.08; }
    .search-form { margin-top: 1.55rem; grid-template-columns: 1fr; }
    .search-form label:first-child, .search-form .destination-cell { grid-column: auto; }
    .stay-picker-form.search-form { grid-template-columns: 1fr; }
    .results, .rooms-section, .review-section { padding: 3.4rem 1rem; }
    /* P2.52 — .results' own top padding narrowed to match the desktop
       change, same reasoning: reach inventory sooner. */
    .results { padding-top: 1.8rem; }
    /* Property-page final premium refinement — .rooms-section's own
       desktop top narrowing (line ~172) was never mirrored at this
       breakpoint: the shorthand above resets it back to the full
       3.4rem top, a real inconsistency (mobile ends up with a LARGER
       hero-to-Room-Explorer gap than desktop), not a deliberate mobile
       choice. Re-narrowed here to match .results' own value exactly
       (same hero-adjacent reasoning); bottom re-stated at 0 since the
       shorthand above re-sets all four sides. */
    .rooms-section { padding-top: 1.8rem; padding-bottom: 0; }
    .section-title { display: block; margin-bottom: 1.2rem; }
    .property-grid { grid-template-columns: minmax(0, 1fr); gap: 1rem; }
    /* A single-column mobile card has room to wrap naturally without
       creating uneven neighbouring-card heights, so the desktop/tablet
       two-line clamp is lifted here — a genuine layout change, not a
       font-size one; size itself now comes from the base rule's single
       fluid clamp (see above), not a second fixed value here. */
    .card-body h3 { -webkit-line-clamp: unset; display: block; overflow: visible; }
    .card-rail { align-items: start; }
    .card-rail .card-cta { flex: 1 1 100%; }
    .property-hero { padding: 2rem 1rem 1rem; gap: 1.5rem; }
    .hero-copy h1 { font-size: clamp(1.7rem, 8vw, 2.2rem); line-height: 1.06; }
    .lead { font-size: 1.1rem; }
    /* P2.53 final acceptance verification — was aspect-ratio 1/1.08
       (near-square, taller than the tablet override even). Same
       stacked-layout reasoning as the 900px breakpoint above: fixed to
       16/10 for consistency and to stop compounding height at the
       narrowest widths, where hero+copy already stack vertically. */
    .hero-media { aspect-ratio: 16 / 10; border-radius: 18px; }
    .amenities { padding: 2.5rem 1rem 0; display: block; }
    .amenities > div { gap: .2rem 1rem; }
    /* Property-page final visual correction — same constant-peek
       reasoning as the <1099px rule above: this band's own smaller
       .8rem (12.8px) gap plus a genuinely small ~11px peek, regardless
       of viewport (320 and 390 both get the same small peek, never a
       viewport-scaling percentage). */
    .room-scroller { grid-auto-columns: minmax(270px, calc(100% - 24px)); gap: .8rem; }
    .room-fallback { min-height: 210px; }
    .room-content { padding: 1.15rem; }
    .room-content h3 { font-size: 1.4rem; }
    .rate-option { flex-direction: column; align-items: stretch; gap: .5rem; }
    .rate-option-action { align-items: stretch; }
    .rate-option-action > strong { text-align: right; }
    .review-grid { grid-template-columns: minmax(0, 1fr); }
    .empty { padding: 2rem 1.2rem; }
}

/* P2.69 final commercial hierarchy: Room Explorer now sits immediately
   after the opening in actual DOM order (moved in property.blade.php,
   not CSS-reordered) — a flex/order reflow here would visually move
   Room Explorer up while leaving it later in the keyboard/screen-reader
   tab order, behind Highlights/Amenities/Getting There. Real DOM order
   keeps visual order and reading/tab order identical. */

.hero-native-reputation { max-width: 320px; margin: .8rem 0 0; padding: .7rem .8rem; border: 1px solid #d9ddd9; border-radius: 11px; background: #fff; display: flex; flex-direction: column; justify-content: center; }
.hero-native-reputation > span { display: block; margin: 0 0 .2rem; color: var(--navy); font-size: .61rem; font-weight: var(--weight-eyebrow); letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; }
.hero-native-reputation strong { color: var(--navy); font-size: 1rem; }
.hero-native-reputation small { color: var(--muted); font-size: .7rem; }

/* Google reputation credential — a single compact, inline line under
   the property name/location, reading like a normal property
   credential ("★ 4.7 · 2,340 reviews · Google Maps") — never a bordered
   card. Explicit-intent (owner-approved reversal, 2026-09): the SAME
   class renders twice, on two different elements —
   `<button class="reputation-credential">` ("View Google rating &
   reviews", reset below to read as plain text with only a subtle
   affordance) before the click, then reputation-credential.js replaces
   it with `<p class="reputation-credential">` carrying the loaded
   result once the click's fetch resolves. Nothing here fetches on
   render or scroll. */
.reputation-credential { margin: .6rem 0 0; display: flex; align-items: center; flex-wrap: wrap; gap: .5rem; font-size: .85rem; min-height: 1px; }
/* The pre-click button state only — reset to plain inline text so it
   reads as an understated invitation, not a boxed UI button, matching
   the compact credential it becomes once loaded. */
button.reputation-credential { border: 0; padding: 0; background: none; font: inherit; color: var(--navy); font-weight: 650; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; border-radius: 2px; }
button.reputation-credential:hover, button.reputation-credential:focus-visible { outline: 3px solid #d4af3780; outline-offset: 2px; }
button.reputation-credential:disabled { color: var(--muted); text-decoration: none; cursor: default; }
/* The primary trust credential — rating/review count. Clickable
   (underlined) only when a reviews_uri was returned; otherwise plain
   text of identical weight, never a fabricated or substituted link. */
.reputation-credential-rating { display: inline-flex; align-items: center; gap: .3rem; font-weight: 650; color: var(--navy); text-decoration: none; }
.reputation-credential-rating[href] { text-decoration: underline; text-underline-offset: 2px; }
/* Required Google Maps attribution — own element, visually
   distinguished from aAlabu's own content, exact unmodified text per
   Google's current attribution requirements. Official policy is silent
   on whether attribution may be a link, so this doubles as the "View
   on map" destination (maps_uri) when available — a plain, non-
   underlined span when it isn't — without ever becoming a third action
   alongside the rating/reviews link: text, color, size, and position
   stay identical either way, only the href changes. */
.reputation-credential-attribution { color: var(--muted); font-size: .68rem; text-decoration: none; }
.reputation-credential-attribution[href] { text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }

@media (min-width: 901px) {
    .search-hero { padding-top: 1.65rem; }
    .search-hero h1 { font-size: clamp(1.7rem, 2.3vw, 2.25rem); max-width: 500px; }
    .search-form { margin-top: 1.35rem; }
    .property-hero { min-height: 520px; padding-block: 2rem; grid-template-columns: minmax(320px, .68fr) minmax(560px, 1.32fr); gap: clamp(2rem, 3vw, 3.25rem); }
    .property-gallery-preview { min-height: 430px; }
    .highlights { padding-top: clamp(2.5rem, 4vw, 3.5rem); border-top: 1px solid var(--line); }
    .review-section { padding-block: clamp(2rem, 4vw, 3rem); display: grid; grid-template-columns: minmax(220px, .72fr) minmax(0, 2fr); column-gap: clamp(2rem, 4vw, 4rem); align-items: start; }
    .review-section > * { grid-column: 1; }
    .review-section > .review-grid { grid-column: 2; grid-row: 1 / span 8; }
    .review-section > .review-count-note { grid-column: 2; }
    /* The desktop review layout puts the summary in a narrow left rail
       beside the review cards, so two fixed columns rather than auto-fit. */
    .review-averages { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 1rem; }
}

/* P2.69 final benchmark correction — landscape comparison rows.
   Measured against the live customer sites: Booking 815px row / 240px
   media, Agoda ~820/275, Expedia ~755/250, Trip ~865/235. The results
   column is therefore capped rather than stretched to the full 1440
   canvas — a 1240px-wide row would strand the price rail a long scan
   away from the photograph, and an uncapped column is also what made a
   single result look accidental. A capped column means one result and
   twenty results are composed identically and deliberately. */
@media (min-width: 601px) {
    /* Centred, not stretched: the section heading is capped to the same
       measure so the column reads as a deliberate composition rather than
       content stranded against the left edge of a wide canvas. */
    .property-grid, .results > .section-title { gap: 1.15rem; max-width: 1000px; margin-inline: auto; }
    .property-card { display: grid; grid-template-columns: minmax(210px, 290px) minmax(0, 1fr); }
    .card-media { height: 100%; min-height: 230px; aspect-ratio: auto; }
    .card-media img { height: 100%; }
    .media-fallback { min-height: 100%; }
    .card-body { padding: 1.15rem 1.25rem; display: flex; flex-direction: column; }
    /* No truncation of property identity on a comparison row: none of the
       four OTA comparison surfaces truncate a property name (Booking wraps
       to six lines rather than clip). The 2-line clamp stays on the narrow
       mobile card, where uneven card heights would otherwise show. */
    .card-body h3 { display: block; -webkit-line-clamp: none; overflow: visible; font-size: clamp(1.14rem, 1.3vw, 1.34rem); }
    /* 601-900px: two zones, with the commercial rail as a full-width
       footer beneath both — a rail confined to the text column alone left
       an empty band under the photograph. */
    .card-rail { grid-column: 1 / -1; border-top: 1px solid var(--line); margin: 0 1.25rem; padding: .9rem 0 1.1rem; display: flex; align-items: end; justify-content: space-between; gap: 1rem; }
    /* Tablet's horizontal footer row keeps its own established
       right-aligned price/quiet-state (opposite the identity column) —
       this pass is mobile-driven and does not change tablet's row
       composition, only restores what the mobile-only left-align base
       rule no longer provides here. */
    .card-rail .price, .card-rail .quiet-state { margin-left: auto; text-align: right; max-width: 180px; }
    .card-cta { margin: 0; flex: 0 0 auto; }
}

@media (min-width: 901px) {
    /* Three zones: media | identity | commercial rail. Scanning a column
       of rows, names line up on one vertical axis and prices on another —
       the mechanism that actually makes an OTA list comparable. Owner
       final-polish — widened 180-200px to 200-220px so "View rooms and
       rates →" always has comfortable breathing room; the width comes
       from the middle identity column, not the 320px photograph. The
       rail's own vertical border was also softened away (see below): the
       card should read as one unified property card, not three stacked
       cells. */
    .property-card { grid-template-columns: 320px minmax(0, 1fr) minmax(12.5rem, 13.75rem); }
    /* Owner final-polish, "card unity" — the rail's commercial content
       (whatever it is for this card's state: price+CTA, quiet-state+CTA,
       or CTA alone) is centered as one group rather than pinned
       top/bottom, since the rail no longer carries a reputation badge to
       anchor a top edge (moved into the identity column). This also
       removes the previous state-specific `margin-top:auto` CTA hack —
       one rule now handles every state's vertical rhythm. */
    .card-rail { grid-column: 3; grid-row: 1; margin: 0; padding: var(--space-md) 1.2rem; border-top: 0; border-left: 1px solid #eceeed; flex-direction: column; align-items: stretch; justify-content: center; gap: .7rem; }
    .card-media, .card-body { grid-row: 1; }
    .card-rail .price, .card-rail .quiet-state { margin-left: 0; text-align: left; max-width: none; }
    .card-cta { width: 100%; }
}

/* Reflow by the card list's available measure in em, so enlarged text
   moves the commercial rail below the photograph and identity together.
   The established 100% wide-desktop arrangement remains unchanged. */
@media (min-width: 901px) {
    @container discovery (width < 55em) {
        .property-card { grid-template-columns: minmax(210px, 320px) minmax(0, 1fr); }
        .card-rail { grid-column: 1 / -1; grid-row: 2; margin: 0 1.25rem; padding: .9rem 0 1.1rem; border-left: 0; border-top: 1px solid var(--line); flex-direction: row; flex-wrap: wrap; align-items: center; gap: 1rem; }
        .card-rail .price, .card-rail .quiet-state { flex: 1 1 12rem; }
        .card-rail .card-cta { width: auto; flex: 1 1 12rem; }
    }
}

@media (max-width: 600px) {
    .reputation-credential { margin-top: .5rem; }
    .hero-native-reputation { margin-top: .65rem; padding: .65rem; }
    .property-hero { padding-bottom: 1.35rem; }
    .rooms-section { padding-top: 2.4rem; }
    .highlights { padding-top: 2.5rem; border-top: 1px solid var(--line); }
}

/* P2.69 customer discovery and property foundation. */
.property-card { box-shadow: 0 14px 36px #0e22390d; }
.card-body { display: flex; flex-direction: column; }
/* Owner final-polish — the mandatory-charge line is comfortably
   readable secondary metadata, not microscopic legal fine print
   (raised from .68rem); still visually subordinate to the price
   itself (1.28rem strong) and the nights/adults line (.8rem). */
.price small { color: var(--muted); font-size: .76rem; }
.card-cta { min-width: 0; max-width: 100%; margin-top: 1rem; min-height: 46px; padding: .7rem min(.9rem, 14.4px); border-radius: 10px; background: var(--navy); color: #fff !important; text-decoration: none; display: flex; align-items: center; justify-content: center; gap: .5rem; white-space: normal; text-align: center; font-family: var(--sans); font-weight: 700; font-size: .83rem; }
.card-cta-label { min-width: 0; overflow-wrap: anywhere; }
.card-cta-arrow { flex: 0 0 auto; }
.card-cta:focus-visible, .gallery-link:focus-visible, .gallery-tile:focus-visible, .media-dialog button:focus-visible, .room-media button:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; }

.property-hero { align-items: stretch; grid-template-columns: minmax(300px, .72fr) minmax(520px, 1.28fr); }
.hero-copy { align-self: center; }
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .8rem; margin-top: 1.3rem; }
.hero-actions .button { margin-top: 0; }
.gallery-link { border: 1px solid var(--navy); background: #fff; color: var(--navy); border-radius: 99px; min-height: 46px; padding: .7rem 1rem; font: inherit; font-size: .84rem; font-weight: var(--weight-eyebrow); cursor: pointer; }
/* Property hero photo trigger: the former text-only "View all N photos" pill, now
   a compact stack of real thumbnails + the count. Same button, same height. */
.gallery-thumbs { display: inline-flex; align-items: center; gap: .5rem; padding: .3rem .85rem .3rem .35rem; border-color: var(--line); box-shadow: 0 1px 2px #0e223914; transition: border-color .2s ease, box-shadow .2s ease; }
.gallery-thumbs:hover { border-color: var(--navy); box-shadow: 0 3px 10px #0e22391f; }
.gallery-thumbs-stack { display: inline-flex; flex: none; }
.gallery-thumb { position: relative; display: block; box-sizing: border-box; width: 30px; height: 30px; flex: none; overflow: hidden; border: 2px solid #fff; border-radius: 9px; background: #e9e5dc; box-shadow: 0 1px 3px #0e22393d; transition: transform .2s ease; }
.gallery-thumb + .gallery-thumb { margin-left: -11px; }
.gallery-thumb:nth-child(1) { z-index: 3; }
.gallery-thumb:nth-child(2) { z-index: 2; }
.gallery-thumb:nth-child(3) { z-index: 1; }
/* Hover fans the stack with a transform: it must never change the control's width, or a tight hero row would reflow and flicker. */
.gallery-thumbs:hover .gallery-thumb:nth-child(2) { transform: translateX(2px); }
.gallery-thumbs:hover .gallery-thumb:nth-child(3) { transform: translateX(4px); }
.gallery-thumb img, .gallery-thumb picture { display: block; width: 100%; height: 100%; }
.gallery-thumb img { object-fit: cover; }
.gallery-thumb img[hidden] { display: none; }
.gallery-thumbs-label { white-space: nowrap; }
.gallery-thumbs-lead { display: none; }
/* From 601px the pill must never be wider than the original text button, so it stays on the
   same row as "See rooms and prices" wherever that button fitted (mobile keeps the roomier spacing). */
@media (min-width: 601px) {
    .gallery-thumbs { gap: .35rem; padding-right: .55rem; padding-left: .3rem; }
    .gallery-thumb + .gallery-thumb { margin-left: -12px; }
}
@media (prefers-reduced-motion: reduce) { .gallery-thumbs, .gallery-thumb { transition: none; } }
.property-gallery-preview { position: relative; min-width: 0; display: grid; grid-template-columns: 2fr 1fr; grid-template-rows: 1fr 1fr; gap: .45rem; min-height: 390px; border-radius: 18px; overflow: hidden; background: #e9e5dc; }
.gallery-tile { border: 0; padding: 0; overflow: hidden; cursor: pointer; background: #e9e5dc; }
.gallery-tile--1 { grid-row: 1 / span 2; }
.property-gallery-preview--single { display: block; }
.property-gallery-preview--single .gallery-tile { width: 100%; height: 100%; display: block; }
.gallery-tile img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .25s ease; }
.gallery-tile:hover img { transform: scale(1.02); }
.gallery-count { position: absolute; right: .8rem; bottom: .8rem; background: #fff; color: var(--ink); border-radius: 99px; padding: .45rem .75rem; font-size: .76rem; font-weight: var(--weight-eyebrow); box-shadow: 0 4px 16px #0e223929; }

.media-dialog { width: min(1100px, calc(100% - 2rem)); height: min(800px, calc(100% - 2rem)); max-width: none; max-height: none; padding: 0; border: 0; border-radius: 18px; background: #081a2d; color: #fff; }
.media-dialog::backdrop { background: #071523d9; }
.media-dialog-shell { position: relative; height: 100%; display: grid; grid-template-rows: auto 1fr auto; }
.media-dialog-header { display: flex; align-items: center; justify-content: space-between; padding: .9rem 1.1rem; }
.media-dialog-header h2 { margin: 0; color: #fff; font-family: var(--sans); font-size: 1rem; }
.media-dialog-header button { width: 42px; height: 42px; border: 1px solid #ffffff66; border-radius: 50%; background: transparent; color: #fff; font-size: 1.4rem; cursor: pointer; }
.media-dialog-stage { position: relative; min-height: 0; display: grid; place-items: center; overflow: hidden; }
.media-dialog-stage figure { margin: 0; width: 100%; height: 100%; display: grid; grid-template-rows: 1fr auto; min-height: 0; }
.media-dialog-stage figure[hidden] { display: none; }
.media-dialog-stage img { width: 100%; height: 100%; min-height: 0; object-fit: contain; }
.media-dialog-stage figcaption { padding: .6rem 4.5rem 0; text-align: center; font-size: .8rem; color: #dce4eb; }
.gallery-nav { position: absolute; top: 50%; transform: translateY(-50%); width: 46px; height: 46px; border: 1px solid #ffffff55; border-radius: 50%; background: #071523b8; color: #fff; font-size: 1.8rem; cursor: pointer; }
.gallery-nav--prev { left: 1rem; }
.gallery-nav--next { right: 1rem; }
.gallery-position { margin: 0; padding: .8rem; text-align: center; color: #dce4eb; font-size: .8rem; }

/* Reputation UX correction — the permanent desktop ~75/25 side-panel
   grid and the mobile floating pill/bottom-sheet this dialog used to
   carry are removed. Photography is full width here again, on every
   breakpoint (.media-dialog-shell has no reputation-driven variant any
   more). The owner-approved FUTURE contract for a guest-review-excerpt
   drawer — see media-gallery-dialog.blade.php's own docblock — should
   slot in as a new trigger in .media-dialog-header and a drawer
   appended inside .media-dialog-shell without needing this comment's
   block back. */

.external-reputation--card { margin: .85rem 0 0; padding: .75rem 0 0; border-top: 1px solid var(--line); max-width: none; min-height: 1rem; }
.external-reputation--card .external-reputation__eyebrow { color: var(--navy); }
.external-reputation--card .external-reputation__score { display: inline; }
.external-reputation--card .external-reputation__link, .external-reputation--card .external-reputation__attribution { display: none; }
.review-count-note { margin: 1rem 0 0; color: var(--muted); font-size: .82rem; }

.getting-there { margin: 2rem clamp(1.2rem, 7vw, 7rem) 0; padding: 1.15rem 1.3rem; border: 1px solid var(--line); border-radius: 14px; display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; }
/* P2.71 surgical correction — no font-weight was declared here, so this
   fell through to the browser's default bold (~700) for h2, the one
   section heading on this page never given the explicit 500 every
   sibling heading already has (.rooms-section h2, .amenities h2,
   .transfer-selector h2, .highlights h2). */
.getting-there h2 { margin: .1rem 0 0; font-family: var(--sans); font-size: 1rem; font-weight: 500; }
.getting-there p:last-child { margin: 0; max-width: 540px; color: var(--muted); font-size: .84rem; }

.room-media { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: #e9e5dc; }
.room-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.room-media img[hidden] { display: none; }
.room-media button { position: absolute; top: 50%; transform: translateY(-50%); width: 36px; height: 36px; border: 0; border-radius: 50%; background: #fff; color: var(--navy); font-size: 1.25rem; cursor: pointer; box-shadow: 0 3px 12px #0e22392e; }
/* Touch target: the visible control stays a 36px circle, but an invisible
   4px halo (a pseudo-element of the button itself, so every tap on it is
   the button's own) makes the effective target 44 x 44 CSS px. The halo
   cannot reach a sibling control: the nearest pair, Expand and Next, stay
   at least 12px apart even on the narrowest card. */
.room-media button::after { content: ""; position: absolute; inset: -4px; }
.room-media [data-room-prev] { left: .6rem; }
.room-media [data-room-next] { right: .6rem; }
.room-media > span { position: absolute; right: .6rem; bottom: .6rem; padding: .3rem .55rem; background: #fff; border-radius: 99px; font-size: .7rem; }
/* Scoped under .room-media so it outranks `.room-media button` above;
   unscoped, Expand inherited top:50% and sat exactly on top of Next. */
.room-media .room-media-expand { top: .6rem; right: .6rem; left: auto; transform: none; font-size: 1rem; }

@media (max-width: 900px) {
    .property-hero { grid-template-columns: 1fr; }
    .property-gallery-preview { order: -1; min-height: 0; aspect-ratio: 16 / 9; }
}

@media (max-width: 600px) {
    .property-gallery-preview { grid-template-columns: 1fr; grid-template-rows: 1fr; aspect-ratio: 4 / 3; border-radius: 14px; }
    .gallery-tile { display: none; }
    .gallery-tile--1 { display: block; grid-row: auto; }
    .gallery-count { right: .55rem; bottom: .55rem; }
    .hero-actions { align-items: stretch; }
    .hero-actions .button, .gallery-link { flex: 1 1 100%; text-align: center; }
    .gallery-thumbs { justify-content: center; }
    .gallery-thumbs-lead { display: inline; }
    .getting-there { margin: 1.5rem 1rem 0; display: block; }
    .getting-there p:last-child { margin-top: .5rem; }
    .card-rail { align-items: end; }
    .media-dialog { width: 100%; height: 100%; border-radius: 0; }
    .media-dialog-stage figcaption { padding-inline: 3.5rem; }
}

/* =====================================================================
   P2.51B — search instrument: custom date-range/guest controls,
   progressive-enhancement trigger fields, desktop popovers and the
   shared mobile search sheet. `.search-form`'s own base rules (grid,
   borders, radius, shadow) are untouched and still apply — this section
   only adds the enhanced-state field styling and the popover/sheet
   layer, so a no-JS visit still renders the original, fully-functional
   native form exactly as before.
   ===================================================================== */

.search-form-enhanced { grid-template-columns: minmax(0, 2fr) minmax(0, 1.3fr) minmax(0, 1.1fr) auto; }
.stay-picker-form.search-form-enhanced { grid-template-columns: 1.3fr 1.1fr auto; }

.search-field { min-width: 0; background: #fff; display: flex; flex-direction: column; }
.search-trigger-field { padding: 0; }
/* Matches the refined `.search-form label`'s own top/side padding and
   eased weight/tracking exactly, so the Destination cell and the
   JS-enhanced Dates/Guests cells beside it share one visual rhythm
   instead of the label sitting fractionally higher/heavier than its
   trigger-button neighbours. */
.search-field-label { padding: .75rem 1.15rem 0; font-size: .66rem; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
/* `.search-form button` (the existing navy CTA style, shared with the
   real submit button) matches any <button> inside the form, including
   these trigger buttons — `.search-form button.search-trigger` matches
   the exact same elements at strictly higher specificity, so this
   reliably wins regardless of stylesheet order. */
.search-form button.search-trigger {
    flex: 1; min-width: 0; border: 0; background: transparent; text-align: left; cursor: pointer;
    padding: .2rem 1.15rem .75rem; font: inherit; font-weight: 400; color: var(--ink); display: flex; flex-direction: column; gap: .05rem;
}
.search-trigger strong { max-width: 100%; font-weight: 650; font-size: .95rem; white-space: normal; overflow-wrap: anywhere; }
.search-trigger span { color: var(--muted); font-size: .78rem; }
.search-form button.search-trigger:hover, .search-form button.search-trigger:focus-visible { background: var(--warm); outline: none; }
.search-form button.search-trigger:focus-visible { box-shadow: inset 0 0 0 3px #d4af3780; }

/* One truthful, restrained reassurance line near the search action —
   P2.51B §G. Deliberately plain text, not a badge/icon row: "one
   truthful signal is better than three generic badges." */
.search-trust { margin: .85rem 0 0; color: var(--muted); font-size: .82rem; }

/* P2.51C §C — destination-discovery typeahead. `.destination-suggest`
   (desktop) is body-appended and positioned in JS from the input's own
   bounding rect, same convention as `.search-popover` below and for the
   same reason (never a descendant of `.search-form`).
   `.destination-suggest-inline` (the mobile sheet's own destination
   input) instead sits in normal document flow directly under that
   input — see mountDestinationAutocomplete's comment in
   search-controls.js for why a floating panel doesn't work inside an
   open <dialog>. */
/* Customer search UX refinement (§3) — `max-width: 600px` is a CSS
   safety belt matching the JS-computed width cap in
   mountDestinationAutocomplete's own `position()` (search-controls.js);
   the actual width for a given open panel is still set inline from
   there (it depends on the input's own rect and the live viewport
   width, neither of which pure CSS can express), this just guarantees
   the panel can never render wider than the target even if that
   computation is ever skipped. `.destination-suggest-inline` (mobile)
   is explicitly excluded via the width:100% override below it — mobile
   already fills its natural container width in normal document flow
   and must never be constrained to this desktop cap. Radius matched to
   `.search-form`'s own 16px (see that rule's comment) so the whole
   interactive family — bar, calendar/guest popovers, this panel —
   reads as one consistent rounded-corner language. */
.destination-suggest {
    position: absolute; z-index: 40; background: #fff; border: 1px solid var(--line);
    border-radius: 16px; box-shadow: 0 20px 50px #0e223924; padding: .5rem;
    max-height: 340px; overflow-y: auto; max-width: 600px;
}
.destination-suggest-inline { position: static; width: 100%; box-shadow: none; margin-top: .5rem; max-height: none; max-width: none; }
.destination-suggest-status { margin: 0; padding: .7rem .85rem; color: var(--muted); font-size: .85rem; }
.destination-suggest-option {
    display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; width: 100%;
    border: 0; background: transparent; border-radius: 10px; padding: .7rem .85rem;
    font: inherit; font-size: .9rem; color: var(--ink); text-align: left; cursor: pointer;
}
.destination-suggest-option:hover, .destination-suggest-option.is-active { background: var(--warm); }
.destination-suggest-label { font-weight: 600; }
.destination-suggest-sub { flex: 0 0 auto; color: var(--muted); font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; }

/* Appended directly to <body> and positioned in JS from the trigger's
   own bounding rect (search-controls.js) — deliberately never a
   descendant of `.search-form`, so none of that form's own button/input
   styling (meant only for the real destination field and submit button)
   can ever apply here. */
.search-popover {
    max-width: calc(100vw - 16px);
    position: absolute; z-index: 40; background: #fff; border: 1px solid var(--line);
    border-radius: 16px; box-shadow: 0 20px 50px #0e223924; padding: 1.1rem; min-width: 320px;
}
.search-popover-guests { min-width: 300px; }
.search-popover-footer { display: flex; align-items: center; justify-content: space-between; margin-top: .9rem; padding-top: .9rem; border-top: 1px solid var(--line); }
.search-popover-footer-end { justify-content: flex-end; }
.search-popover-link { border: 0; background: transparent; color: var(--ink); font: inherit; font-size: .85rem; font-weight: 650; text-decoration: underline; cursor: pointer; padding: .4rem .2rem; }
.search-popover-done {
    border: 0; background: var(--navy); color: #fff; font: inherit; font-weight: 700; font-size: .85rem;
    padding: .6rem 1.2rem; border-radius: 99px; cursor: pointer;
}
.search-popover-done:focus-visible, .search-popover-link:focus-visible { outline: 3px solid #d4af3780; outline-offset: 1px; }

/* ---- Calendar ---- */
/* Customer search UX refinement — the persistent "Your stay" context
   line kept visible inside the calendar panel while dates are being
   chosen (§1). Compact by design: this is a status readout, not a
   second hero — one small eyebrow line plus one confident value line,
   set apart from the calendar grid below it by a hairline rule rather
   than a card/box treatment. */
.cal-selection-summary { padding-bottom: .75rem; margin-bottom: .85rem; border-bottom: 1px solid var(--line); }
.cal-selection-label { margin: 0 0 .15rem; font-size: .66rem; font-weight: var(--weight-eyebrow); letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--muted); }
.cal-selection-value { margin: 0; font-size: 1rem; font-weight: 650; color: var(--navy); }
.cal-months { display: flex; gap: 1.5rem; }
.cal-month-panel { min-width: 0; flex: 1; }
.cal-header { display: flex; align-items: center; justify-content: space-between; gap: .25rem; margin-bottom: .5rem; }
.cal-month { min-width: 0; overflow-wrap: anywhere; text-align: center; margin: 0; font-family: var(--sans); font-weight: 650; font-size: .88rem; color: var(--navy); }
.cal-nav {
    flex: 0 0 auto; width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--line); background: #fff;
    color: var(--navy); font-size: 1rem; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.cal-nav:hover { background: var(--warm); }
.cal-nav:focus-visible { outline: 3px solid #d4af3780; outline-offset: 1px; }
.cal-grid { border-collapse: collapse; table-layout: fixed; width: 100%; }
.cal-grid th { overflow-wrap: anywhere; font-size: .66rem; font-weight: 700; color: var(--muted); padding: .3rem 0; }
.cal-grid td { padding: 1px; text-align: center; }
.cal-day {
    width: 100%; min-height: 34px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--ink);
    font: inherit; font-size: .82rem; line-height: 1.2; cursor: pointer;
}
.cal-day:hover:not(:disabled) { background: var(--warm); }
.cal-day:focus-visible { outline: 3px solid #d4af3780; outline-offset: 1px; }
.cal-day:disabled { color: #c7ccd2; cursor: default; }
.cal-day.is-in-range { background: var(--warm); border-radius: 0; }
.cal-day.is-selected { background: var(--navy); color: #fff; }
.cal-day.is-range-start { border-radius: 50% 0 0 50%; }
.cal-day.is-range-end { border-radius: 0 50% 50% 0; }
.cal-day.is-selected.is-range-start, .cal-day.is-selected.is-range-end { border-radius: 50%; }

/* ---- Guest stepper ---- */
.stepper-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .4rem .7rem; padding: .6rem 0; border-bottom: 1px solid var(--line); }
.stepper-row:last-child { border-bottom: 0; }
.stepper-label p { margin: 0; font-size: .9rem; color: var(--ink); }
.stepper-hint { color: var(--muted); font-size: .78rem; }
.stepper-controls { flex: 0 0 auto; display: flex; align-items: center; gap: .7rem; }
.stepper-btn {
    width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--line); background: #fff;
    color: var(--navy); font-size: 1.05rem; line-height: 1; cursor: pointer;
}
.stepper-btn:hover:not(:disabled) { border-color: var(--navy); }
.stepper-btn:focus-visible { outline: 3px solid #d4af3780; outline-offset: 1px; }
.stepper-btn:disabled { color: #c7ccd2; border-color: var(--line); cursor: default; }
.stepper-value { min-width: 1.4rem; text-align: center; font-weight: 650; }

/* ---- Mobile search sheet ---- */
.search-sheet { border: 0; padding: 0; margin: 0; width: min(480px, 100vw); max-width: 100vw; height: 100%; max-height: 100vh; border-radius: 0; }
.search-sheet::backdrop { background: rgba(14, 34, 57, .45); }
.search-sheet-inner { display: flex; flex-direction: column; height: 100%; }
.search-sheet-header { display: flex; align-items: center; justify-content: space-between; gap: .5rem; padding: 1.1rem 1.2rem; border-bottom: 1px solid var(--line); }
.search-sheet-header h2 { min-width: 0; margin: 0; font-size: 1.2rem; overflow-wrap: anywhere; }
.search-sheet-close { flex: 0 0 auto; width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--line); background: #fff; font-size: 1.2rem; line-height: 1; cursor: pointer; }
.search-sheet-close:focus-visible { outline: 3px solid #d4af3780; outline-offset: 1px; }
.search-sheet-body { min-height: 0; min-width: 0; flex: 1; overflow-y: auto; padding: .5rem 1.2rem 1.2rem; }
.sheet-section { border-bottom: 1px solid var(--line); }
.sheet-section-header { width: 100%; border: 0; background: transparent; text-align: left; padding: 1rem 0; cursor: pointer; display: flex; flex-direction: column; gap: .15rem; font: inherit; }
.sheet-section-label { font-size: .68rem; font-weight: var(--weight-eyebrow); letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--muted); }
.sheet-section-summary { font-size: 1rem; font-weight: 600; color: var(--navy); }
.sheet-section-header:focus-visible { outline: 3px solid #d4af3780; outline-offset: 2px; }
.sheet-section.is-active .sheet-section-header { cursor: default; }
.sheet-section-body { padding: 0 0 1.1rem; }
.sheet-destination-label { display: block; font-size: .68rem; font-weight: var(--weight-eyebrow); letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--muted); }
.sheet-destination-input {
    display: block; width: 100%; margin-top: .5rem; border: 1px solid var(--line); border-radius: 10px;
    padding: .75rem .9rem; font: inherit; font-size: 1rem; color: var(--ink);
}
.sheet-destination-input:focus-visible { outline: 3px solid var(--navy); outline-offset: 1px; }
.search-sheet .cal-months { flex-direction: column; }
.search-sheet .cal-month-panel-second { display: none; }
.search-sheet .cal-day { width: 100%; aspect-ratio: 1; }
.search-sheet-footer { padding: 1rem 1.2rem; border-top: 1px solid var(--line); }
/* Deliberately self-contained (never reuses `.checkout-primary`, which
   lives in catalogue-checkout.css — a stylesheet this search sheet must
   never depend on, since the search page itself never loads it). */
.search-sheet-search {
    width: 100%; min-height: 50px; border-radius: 99px; border: 0;
    background: var(--navy); color: #fff; font: inherit; font-weight: 700; font-size: .95rem; cursor: pointer;
}
.search-sheet-search:hover { background: #17334e; }
.search-sheet-search:focus-visible { outline: 3px solid #d4af3780; outline-offset: 2px; }

@media (max-width: 900px) {
    .search-popover { min-width: 280px; }
    .cal-months { gap: 1rem; }
}

@media (max-width: 600px) {
    .search-form-enhanced { grid-template-columns: 1fr; }
    .stay-picker-form.search-form-enhanced { grid-template-columns: 1fr; }
    /* Below the breakpoint search-controls.js itself treats as "mobile"
       (opens the shared sheet instead of a floating popover), the
       trigger fields still render inline so the page never shows a
       popover that would have nowhere sensible to anchor. */
    .cal-months { flex-direction: column; }
    .cal-month-panel-second { display: none; }
}

/* CLOSE-4B.2 — the four static legal pages (/terms, /privacy, /cookies,
   /cancellation-policy). Reuses the same tokens/typography as the rest
   of the customer site (var(--navy)/var(--muted)/var(--line)/var(--serif)
   /var(--sans)) rather than a competing design system — deliberately
   plain: a readable content column, a restrained metadata line, no
   editorial hero, no cards around paragraphs, no gold accents. */
.legal-page-header { padding: clamp(2rem, 5vw, 3.5rem) clamp(1.2rem, 5vw, 5rem) 0; max-width: 720px; margin: 0 auto; }
.legal-page-header h1 { font-size: clamp(1.6rem, 1.3rem + 1.2vw, 2.35rem); font-weight: 500; letter-spacing: -.01em; margin: 0 0 .5rem; }
.legal-meta { color: var(--muted); font-size: .84rem; margin: 0; }
.legal-content { max-width: 720px; margin: 0 auto; padding: 1.5rem clamp(1.2rem, 5vw, 5rem) clamp(2.5rem, 6vw, 4rem); font-size: .96rem; line-height: 1.7; }
.legal-content h2 { font-family: var(--sans); font-size: 1.1rem; font-weight: 650; color: var(--navy); margin: 2.1rem 0 .6rem; }
.legal-content h2:first-child { margin-top: 0; }
.legal-content p { margin: 0 0 1rem; }
.legal-content ul, .legal-content ol { margin: 0 0 1rem; padding-left: 1.3rem; }
.legal-content li { margin: 0 0 .4rem; }
.legal-content a { color: var(--navy); text-decoration: underline; text-underline-offset: 2px; }
.legal-content a:hover { color: var(--gold); }
.legal-page-nav { max-width: 720px; margin: 0 auto; padding: 0 clamp(1.2rem, 5vw, 5rem); display: flex; flex-wrap: wrap; gap: .4rem 1rem; font-size: .84rem; }
.legal-page-nav a { color: var(--muted); text-decoration: underline; text-underline-offset: 2px; }
.legal-page-nav a[aria-current="page"] { color: var(--navy); font-weight: 650; text-decoration: none; }

/* Compact "Company details" disclosure — satisfies SI 2015/17's
   website-disclosure requirement (registered office address included)
   without permanently enlarging the footer. A native <details> element:
   no JS, keyboard-operable, and announced correctly by screen readers
   without any custom ARIA. */
.company-details { max-width: 720px; margin: 2rem auto 0; padding: 0 clamp(1.2rem, 5vw, 5rem); }
.company-details summary { cursor: pointer; color: var(--muted); font-size: .84rem; text-decoration: underline; text-underline-offset: 2px; }
.company-details-body { margin: .6rem 0 0; color: var(--muted); font-size: .84rem; line-height: 1.6; }

/* The existing shared Home/search template's explicit Google credential. */
.property-name-reputation { display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem .65rem; min-width: 0; }
.property-name-reputation h3 { flex: 1 1 13rem; min-width: 0; }
.property-name-reputation .reputation-credential { flex: 0 1 auto; }
.reputation-credential { display: inline-flex; flex-wrap: wrap; align-items: center; gap: .15rem .55rem; max-width: 100%; font-size: .8rem; line-height: 1.4; }
button.reputation-credential, .reputation-credential a, .reputation-refresh { min-height: 44px; }
button.reputation-credential { padding: .2rem .45rem; border-radius: 8px; border: 1px solid var(--line); background: #fff; color: var(--navy); text-align: left; }
.reputation-credential span[aria-hidden] { color: #9a7738; }
.reputation-credential a { display: inline-flex; align-items: center; overflow-wrap: anywhere; }
.reputation-credential .reputation-credential-attribution { font-size: 12px; color: #5e5e5e; font-weight: 400; white-space: nowrap; }
.reputation-refresh { min-width: 44px; border: 0; border-radius: 8px; color: var(--navy); background: transparent; font: inherit; cursor: pointer; }
.reputation-refresh:focus-visible, .reputation-credential:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.reputation-credential .reputation-credential-rating { align-items: baseline; gap: .1rem; }
.reputation-credential-rating span[aria-hidden] { flex-shrink: 0; }

/* Explicit Google credential: one quiet group, with focus only on activation. */
.reputation-credential { margin: 0; gap: .1rem .5rem; min-width: 0; }
button.reputation-credential { border: 0; background: transparent; padding: .2rem 0; text-decoration: none; font-size: .8rem; font-weight: 500; }
.reputation-credential a { text-decoration: none; overflow-wrap: normal; word-break: normal; }
.reputation-credential a:hover { text-decoration: underline; text-underline-offset: .2em; }
.reputation-credential-rating { flex-wrap: wrap; column-gap: .35rem; }
.reputation-score { white-space: nowrap; }
.reputation-count { white-space: normal; }
.reputation-count { font-weight: 400; color: var(--muted); }
.reputation-actions { display: inline-flex; flex-wrap: wrap; align-items: center; gap: .15rem .5rem; }
.reputation-refresh { padding: 0; }
button.reputation-credential:hover { outline: none; }
.reputation-credential a:focus-visible, button.reputation-credential:focus-visible, .reputation-refresh:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; border-radius: 4px; }
.property-card .card-rail { min-width: 0; flex-wrap: wrap; }
.property-card .card-cta { min-width: 0; max-width: 100%; box-sizing: border-box; white-space: normal; flex-shrink: 1; text-align: center; overflow-wrap: normal; word-break: normal; }
.property-card .card-cta > span { flex: 0 0 auto; }

.property-card .card-cta { display: block; }
.property-card .card-cta > span { display: inline-block; margin-inline-start: .35em; }
/* Reflow the commercial rail when enlarged text needs more inline space. */
.property-grid { container-type: inline-size; }
@media (min-width: 901px) {
    @container (max-width: 45rem) {
        .property-card { grid-template-columns: minmax(0, .8fr) minmax(0, 1fr); }
        .property-card .card-rail { grid-column: 1 / -1; grid-row: 2; border-left: 0; border-top: 1px solid var(--line); }
    }
}
.reputation-credential .reputation-credential-rating[href], .reputation-credential .reputation-credential-attribution[href] { text-decoration: none; }
.reputation-credential .reputation-credential-rating[href]:hover, .reputation-credential .reputation-credential-attribution[href]:hover { text-decoration: underline; }

/* Passive numeric presenter; no provider retrieval or caching behavior. */
.google-numeric-rating { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 .4rem; min-width: 0; margin: .15rem 0 .4rem; font-size: .8rem; line-height: 1.5; }
.google-numeric-rating__value { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: .2rem .35rem; min-height: 44px; max-width: 100%; padding: .3rem 0; color: var(--navy); text-decoration: none; }
.google-numeric-rating__score { white-space: nowrap; font-weight: 650; }
.google-numeric-rating__score [aria-hidden] { color: #9a7738; }
.google-numeric-rating__count { color: var(--muted); font-weight: 400; word-break: normal; }
.google-numeric-rating__source { white-space: nowrap; color: #5e5e5e; font-family: var(--sans); font-weight: 400; font-size: 12px; }
.google-numeric-rating__value:focus-visible { outline: none; box-shadow: 0 3px 0 var(--navy); border-radius: 0; }
.google-numeric-rating__value:hover { text-decoration: none; color: #274965; }
@media (forced-colors: active) { .google-numeric-rating__value:focus-visible { outline: 2px solid Highlight; outline-offset: 2px; box-shadow: none; } }

/* Shared card photography: fixed geometry, deferred slides and quiet controls.
   Layered Gallery — the main photograph stays full-width. A card with several
   photographs shows a small cropped preview of the NEXT photograph in a corner
   (top right by default, draggable to any corner; one quiet layer behind it when
   a third exists); the preview is the "next" control. No permanent arrow buttons.
   Slides move with transform only, driven by catalogue-gallery.js. */
.property-card-gallery { --pv: clamp(64px, 26cqw, 96px); position: relative; container-type: inline-size; background: #eeeae4; touch-action: pan-y pinch-zoom; }
.card-photo { display: block; position: absolute; inset: 0; overflow: hidden; background: #eeeae4; color: inherit; }
.card-photo > [data-card-photo], .card-photo > .media-fallback { position: absolute; inset: 0; }
.card-photo > [data-card-photo][hidden] { display: none; }
.card-photo img { display: block; }
.card-peek { position: absolute; z-index: 2; top: 10px; right: 10px; width: var(--pv); aspect-ratio: 4 / 3; overflow: hidden; border: 1.5px solid #ffffffd1; border-radius: 10px; background: #ddd6ca; box-shadow: 0 2px 8px #10243b38; pointer-events: none; opacity: 0; visibility: hidden; transition: transform .2s ease-out, opacity .2s ease-out; }
/* Revealed by JS only after the preview image has loaded: never an empty frame. */
.card-peek.is-ready { opacity: 1; visibility: visible; }
.card-peek img { display: block; width: 100%; height: 100%; object-fit: cover; }
.card-peek--2 { display: none; z-index: 1; top: 16px; right: 16px; box-shadow: 0 1px 4px #10243b24; }
.card-peek--2.is-ready { opacity: .85; }
/* The layer waits for the preview in front of it; the control is inert until then. */
.property-card-gallery:not(.has-preview) .card-peek--2 { opacity: 0; visibility: hidden; }
.property-card-gallery:not(.has-preview) .card-gallery-next { pointer-events: none; }
.card-peek--2 img { filter: brightness(.88) saturate(.9); }
.property-card-gallery--deep .card-peek--2 { display: block; }
/* Preview corner: data-corner on the card (default tr). The counter, status and
   focus pills move away from the preview so they never overlap it. */
.property-card-gallery[data-corner="br"] .card-peek--1, .property-card-gallery[data-corner="bl"] .card-peek--1 { top: auto; bottom: 10px; }
.property-card-gallery[data-corner="br"] .card-peek--2, .property-card-gallery[data-corner="bl"] .card-peek--2 { top: auto; bottom: 16px; }
.property-card-gallery[data-corner="br"] .card-gallery-next, .property-card-gallery[data-corner="bl"] .card-gallery-next { top: auto; bottom: 4px; }
.property-card-gallery[data-corner="bl"] .card-peek--1, .property-card-gallery[data-corner="tl"] .card-peek--1 { right: auto; left: 10px; }
.property-card-gallery[data-corner="bl"] .card-peek--2, .property-card-gallery[data-corner="tl"] .card-peek--2 { right: auto; left: 16px; }
.property-card-gallery[data-corner="bl"] .card-gallery-next, .property-card-gallery[data-corner="tl"] .card-gallery-next { right: auto; left: 4px; }
.property-card-gallery[data-corner="br"] .card-gallery-position { right: auto; left: 10px; }
.property-card-gallery[data-corner="br"] .card-gallery-status:not(:empty), .property-card-gallery[data-corner="bl"] .card-gallery-status:not(:empty) { bottom: auto; top: 10px; }
.property-card-gallery.is-dragging-preview .card-peek--1 { box-shadow: 0 6px 16px #10243b59; }
.property-card-gallery.is-swiping .card-photo { cursor: grabbing; }
.property-card:hover .card-media .card-peek img { transform: none; }
.property-card-gallery:has(.card-gallery-next:hover) .card-peek--1 { transform: scale(1.05); }
.card-peek.is-shift img { animation: card-peek-shift .26s ease-out; }
.card-peek[hidden], .card-peek img[hidden] { display: none; }
/* No usable further photograph: the preview, its control and the counter go away. */
.property-card-gallery.is-single .card-peek, .property-card-gallery.is-single .card-gallery-next, .property-card-gallery.is-single .card-gallery-prev, .property-card-gallery.is-single .card-gallery-move, .property-card-gallery.is-single .card-gallery-position { display: none; }
.property-card-gallery button { margin: 0; padding: 0; border: 0; font: inherit; cursor: pointer; }
/* The corner preview is the "next photograph" control: a transparent touch
   target (never under 44px) that covers only the preview and its layer. */
.card-gallery-next { position: absolute; z-index: 3; top: 4px; right: 4px; width: calc(var(--pv) + 20px); height: calc(var(--pv) * .75 + 26px); border-radius: 12px; background: transparent; touch-action: none; cursor: grab; }
.property-card-gallery.is-dragging-preview .card-gallery-next { cursor: grabbing; }
/* "Previous" has no visible control; it is a real button for keyboard and
   screen-reader users and appears only while it has focus. */
.card-gallery-prev { position: absolute; z-index: 4; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.card-gallery-prev:focus-visible, .card-gallery-move:focus-visible { width: auto; height: auto; overflow: visible; clip-path: none; left: 10px; bottom: 10px; padding: 7px 13px; border-radius: 99px; background: #10243bf2; color: #fff; font: 600 13px/1.2 sans-serif; }
/* "Move preview" is the keyboard / assistive-technology alternative to dragging
   the preview; it too appears only while focused, clear of the preview itself. */
.card-gallery-move { position: absolute; z-index: 4; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.card-gallery-move:focus-visible { left: 50%; transform: translateX(-50%); }
.property-card-gallery[data-corner="bl"] .card-gallery-prev:focus-visible, .property-card-gallery[data-corner="br"] .card-gallery-prev:focus-visible,
.property-card-gallery[data-corner="bl"] .card-gallery-move:focus-visible, .property-card-gallery[data-corner="br"] .card-gallery-move:focus-visible { bottom: auto; top: 10px; }
.property-card-gallery [hidden] { display: none; }
/* Keep the genuine fallback inside the photo box, with a counter-safe footer.
   The decorative brand mark scales with the image, not customer text size. */
.property-card-gallery .media-fallback { min-height: 0; display: flex; align-items: center; justify-content: center; padding: 16px 10px 56px; }
.card-fallback-copy { min-width: 0; max-width: 100%; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.media-fallback .card-fallback-mark { font-size: 32px; font-size: min(4rem, 12cqw); line-height: 1; }
.card-fallback-copy small { max-width: 100%; line-height: 1.25; overflow-wrap: anywhere; }
.card-gallery-position { position: absolute; z-index: 3; bottom: 10px; right: 10px; padding: 2px 9px; border-radius: 99px; background: #10243bb8; -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); color: #fff; font: 600 12px/1.5 sans-serif; font-variant-numeric: tabular-nums; pointer-events: none; }
.card-gallery-status:not(:empty) { position: absolute; z-index: 3; left: 10px; bottom: 10px; max-width: calc(100% - 86px); padding: 5px 8px; border-radius: 8px; background: #f7f4efed; color: #10243b; font: 12px/1.4 sans-serif; }
.card-gallery-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* A live loading/error message replaces the redundant "coming soon" caption. */
.property-card-gallery.has-card-fallback:has(.card-gallery-status:not(:empty)) .card-fallback-copy small { display: none; }
.property-card-gallery :focus-visible { outline: 3px solid #b78b43; outline-offset: -3px; }
@keyframes card-peek-shift { from { opacity: .35; transform: scale(1.12); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
    .property-card-gallery img { transition: none; }
    .card-peek, .card-photo > [data-card-photo] { transition: none !important; }
    .card-peek img { animation: none !important; }
}
@media (forced-colors: active) { .card-peek { border-color: CanvasText; } }

/* Verified card journey facts: secondary copy, never a price or booking badge. */
.card-transfer { display: flex; align-items: flex-start; gap: .4rem; margin: 0 0 var(--space-xs); color: var(--muted); font-size: .8rem; line-height: 1.45; }
.card-location + .card-transfer { margin-top: -.15rem; }
.card-transfer-icon { flex: 0 0 14px; width: 14px; height: 14px; margin-top: .18em; stroke: var(--gold); stroke-width: 1.5; }
.card-transfer-copy { min-width: 0; overflow-wrap: anywhere; }

/* Native guest reputation: passive, shared discovery-card identity. */
.card-identity { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: .6rem; row-gap: .2rem; margin-bottom: var(--space-2xs); }
.card-body .card-identity h3 { overflow-wrap: normal; flex: 1 1 12rem; min-width: 0; margin: 0; display: block; -webkit-line-clamp: unset; overflow: visible; }
.card-guest-rating { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: .25rem; max-width: 100%; min-width: 0; color: var(--ink); font-family: var(--sans); font-size: .78rem; font-weight: 400; line-height: 1.45; }
.card-guest-score { white-space: nowrap; }
.card-guest-star { color: #947020; }
.card-guest-source { min-width: 0; color: var(--muted); overflow-wrap: anywhere; }

/* Verified journeys: compact mobile disclosure, unchanged desktop context. */
.card-transfer-compact, .card-transfer-details { display: none; }
@media (max-width: 600px) {
    .card-transfer { align-items: center; }
    .card-transfer-desktop { display: none; }
    .card-transfer-compact { display: block; }
    .card-transfer-details { display: block; flex: 0 0 auto; }
    .card-transfer-details summary { display: flex; align-items: center; justify-content: center; width: 44px; height: 44px; cursor: pointer; color: var(--navy); list-style: none; font-size: 1rem; }
    .card-transfer-details summary::-webkit-details-marker { display: none; }
    .card-transfer-details :focus-visible { outline: 3px solid var(--gold); outline-offset: -3px; }
    .card-transfer-panel { position: fixed; z-index: 60; inset: auto 12px 12px; margin: 0; width: calc(100% - 24px); max-width: none; max-height: 70vh; overflow-y: auto; padding: min(1rem, 20px); border: 1px solid var(--line); border-radius: 16px; box-shadow: 0 12px 50px #10243b30; background: var(--paper, #fff); color: var(--ink); font-size: .85rem; overflow-wrap: anywhere; }
    .card-transfer-panel-heading { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
    .card-transfer-panel-heading h4 { margin: 0; font-size: 1rem; }
    .card-transfer-panel-heading button { flex: 0 0 auto; width: 44px; height: 44px; border: 0; border-radius: 50%; background: var(--warm); color: var(--navy); font-size: 1.2rem; cursor: pointer; }
    .card-transfer-panel p { margin: .2em 0; line-height: 1.35; }
    .card-transfer-panel .card-transfer-access { margin: .25em 0 .6em; color: var(--muted); }
    .card-transfer-panel ul { list-style: none; padding: 0; margin: 0; }
    .card-transfer-panel li { line-height: 1.35; }
    .card-transfer-panel li + li { margin-top: .6em; padding-top: .6em; border-top: 1px solid var(--line); }
}

.card-transfer-panel::backdrop { background: #10243b40; }

/* Explicit property-detail retrieval uses the existing premium numeric presenter. */
.google-detail-rating { min-width: 0; max-width: 100%; }
.google-detail-rating__button { min-height: 44px; max-width: 100%; padding: .3rem 0; border: 0; background: transparent; color: var(--navy); font: inherit; font-size: .8rem; text-align: left; white-space: normal; cursor: pointer; }
.google-detail-rating__button:focus-visible { outline: 2px solid var(--navy); outline-offset: 3px; }
.google-detail-rating__button:disabled { cursor: wait; }
.google-detail-rating__status { margin: .2rem 0; color: var(--muted); font-size: .8rem; line-height: 1.5; }
.google-detail-rating .google-numeric-rating__source[href] { display: inline-flex; align-items: center; min-height: 44px; text-decoration: none; }
.google-detail-rating .google-numeric-rating__source[href]:focus-visible { outline: 2px solid var(--navy); outline-offset: 3px; }

/* Refinement 4 — compact hotel-confirmed guest combinations ("2 Adults · 2+1 · 3 Adults"). `position: relative` anchors the
   visually-hidden spoken text to its own card; unanchored, it sat at the room carousel's off-screen x offset and widened the page. */
.room-occupancy, .card-room-occupancy { position: relative; display: flex; align-items: center; flex-wrap: wrap; gap: .35rem; margin: .35rem 0 0; font-family: var(--sans); color: var(--ink); line-height: 1.4; }
.room-occupancy { font-size: .82rem; }
.card-room-occupancy { font-size: .76rem; color: #5a6876; } /* --muted is 4.35:1 on the card background; this is 5.25:1 */
.room-occupancy-icon { flex: none; opacity: .75; }
.room-occupancy small, .card-room-occupancy small { color: #5a6876; font-size: .7rem; margin-left: .2rem; }

/* ==========================================================================
   Room Explorer comparison (Phase B) — optional, additive. Everything here
   is scoped to .room-compare / .compare-* and is inert until
   catalogue-compare.js adds .has-room-compare, so a page without JavaScript
   renders exactly as before. No per-property rules: every property and room
   uses these same components.
   ========================================================================== */
.room-compare { display: none; margin-top: .4rem; }
.has-room-compare .room-compare { display: block; }
.room-compare-toggle { position: relative; display: inline-flex; align-items: center; gap: .55rem; min-height: 44px; padding: 0 .25rem; color: var(--navy); font-size: .84rem; font-weight: 650; cursor: pointer; }
.room-compare-toggle input { width: 1.1rem; height: 1.1rem; margin: 0; accent-color: var(--navy); cursor: pointer; }
.room-compare-toggle:has(input:disabled) { opacity: .5; cursor: not-allowed; }
.room-compare-toggle:has(input:disabled) input { cursor: not-allowed; }
.room-compare-toggle:has(input:focus-visible) { outline: 3px solid var(--gold); outline-offset: 2px; border-radius: 8px; }

.compare-tray { position: fixed; left: 0; right: 0; bottom: var(--aalabu-consent-banner-space, 0px); z-index: 900; padding: .65rem 1rem calc(.65rem + env(safe-area-inset-bottom)); background: #fff; border-top: 1px solid var(--line); box-shadow: 0 -10px 30px #0e223918; }
.compare-tray[hidden] { display: none; }
body.has-compare-tray { padding-bottom: calc(var(--aalabu-consent-banner-space, 0px) + 6.5rem); }
.compare-tray-inner { max-width: 1100px; margin: 0 auto; display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .9rem; }
.compare-tray-list { display: flex; flex-wrap: wrap; gap: .4rem; flex: 1 1 260px; min-width: 0; margin: 0; padding: 0; list-style: none; }
.compare-chip { display: inline-flex; align-items: center; max-width: 100%; border: 1px solid var(--line); border-radius: 99px; background: #faf9f6; font-size: .8rem; font-weight: 650; color: var(--navy); }
.compare-chip-name { padding: .35rem .2rem .35rem .8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 12rem; }
.compare-chip-remove { position: relative; width: 32px; height: 32px; margin-right: 2px; border: 0; border-radius: 50%; background: transparent; color: var(--navy); font-size: 1.1rem; line-height: 1; cursor: pointer; }
.compare-chip-remove::after { content: ""; position: absolute; inset: -6px; }
.compare-tray-hint { flex: 1 1 100%; margin: 0; font-size: .78rem; color: var(--muted); }
.compare-tray-hint:empty { display: none; }
.compare-tray-actions { display: flex; align-items: center; gap: .6rem; margin-left: auto; }
.compare-open { min-height: 44px; padding: 0 1.2rem; border: 0; border-radius: 99px; background: var(--navy); color: #fff; font-weight: 750; font-size: .88rem; cursor: pointer; }
.compare-open:disabled { opacity: .45; cursor: not-allowed; }
.compare-clear { min-height: 44px; padding: 0 .5rem; border: 0; background: none; color: var(--navy); font-size: .82rem; font-weight: 650; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.compare-tray button:focus-visible, .compare-dialog button:focus-visible, .compare-dialog input:focus-visible, .compare-scroll:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; }

.compare-dialog { width: min(1100px, calc(100% - 2rem)); max-width: none; max-height: min(900px, calc(100dvh - 2rem)); padding: 0; border: 0; border-radius: 20px; background: #fff; color: var(--ink); overflow: hidden; }
.compare-dialog[open] { display: flex; flex-direction: column; }
.compare-dialog::backdrop { background: #071523d9; }
body:has(.compare-dialog[open]) { overflow: hidden; }
.compare-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; padding: 1.1rem 1.25rem .5rem; }
.compare-head h2 { margin: 0; font-family: var(--serif); font-size: 1.5rem; color: var(--navy); }
.compare-stay { margin: .2rem 0 0; font-size: .84rem; color: var(--muted); }
.compare-close { flex: none; width: 44px; height: 44px; border: 1px solid var(--line); border-radius: 50%; background: #fff; color: var(--navy); font-size: 1.5rem; line-height: 1; cursor: pointer; }
.compare-notices, .compare-tools, .compare-foot { position: sticky; left: 0; }
.compare-notice { margin: .4rem 0 0; padding: .65rem .85rem; border-radius: 12px; font-size: .84rem; line-height: 1.45; }
.compare-notice.is-warn { background: #fbf6e6; border: 1px solid #e3d6ad; color: #5b4a10; }
.compare-notice.is-ok { background: #f2f6f4; border: 1px solid #d5e0db; color: #2c4a3c; }
.compare-tools { padding: .5rem 0; }
.compare-diff-toggle { display: inline-flex; align-items: center; gap: .55rem; min-height: 44px; font-size: .86rem; font-weight: 650; color: var(--navy); cursor: pointer; }
.compare-diff-toggle input { width: 1.1rem; height: 1.1rem; margin: 0; accent-color: var(--navy); }
/* No scroll snapping here: snapping pulled keyboard-focused controls in the last column back out of
   view. scroll-padding-top keeps a focused control clear of the pinned room-name row. */
.compare-scroll { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 0 1.25rem 1rem; scroll-padding-top: 5rem; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.compare-table { --label-w: 8rem; --col-min: 15rem; min-width: calc(var(--label-w) + var(--cols, 2) * var(--col-min)); }
.compare-row { position: relative; display: grid; grid-template-columns: var(--label-w) repeat(var(--cols, 2), minmax(var(--col-min), 1fr)); }
.compare-row > * { min-width: 0; padding: .8rem .85rem; border-top: 1px solid var(--line); }
.compare-row--photos > * { border-top: 0; padding-bottom: .2rem; }
.compare-row--head { position: sticky; top: 0; z-index: 2; background: #fff; }
.compare-row--head > * { border-top: 0; background: #fff; padding-top: .3rem; padding-bottom: .3rem; box-shadow: 0 1px 0 var(--line); }
.compare-label { font-size: .74rem; font-weight: 750; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.compare-cap { display: none; margin-bottom: .3rem; font-size: .68rem; font-weight: 750; letter-spacing: .06em; text-transform: uppercase; color: #4f5d6b; }
.compare-cell { position: relative; font-size: .9rem; line-height: 1.5; }
.compare-cell.is-diff { background: #fbf6e6; box-shadow: inset 3px 0 0 var(--gold); }
.compare-photo { overflow: hidden; border-radius: 12px; height: clamp(110px, 13vw, 170px); background: #e9e5dc; }
.compare-photo picture { display: block; height: 100%; }
.compare-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.compare-name { margin: 0; font-family: var(--serif); font-size: 1.15rem; font-weight: 400; color: var(--navy); }
.compare-remove { min-height: 44px; margin: -.2rem 0 0 -.25rem; padding: 0 .25rem; border: 0; background: none; color: var(--muted); font-size: .78rem; font-weight: 650; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.compare-price { display: flex; flex-direction: column; gap: .15rem; }
.compare-price strong { font-size: 1.3rem; color: var(--navy); }
.compare-nights { margin: .1rem 0 .5rem; font-size: .8rem; color: var(--muted); }
.compare-term { margin: .25rem 0 0; padding: .15rem .35rem; border-radius: 6px; font-size: .84rem; }
.compare-term.is-diff { background: #fbf6e6; box-shadow: inset 3px 0 0 var(--gold); }
.compare-term-name { font-weight: 700; color: var(--navy); }
.compare-select { margin-top: .9rem; }
.compare-more { min-height: 44px; margin-top: .2rem; padding: 0; border: 0; background: none; color: var(--navy); font-size: .8rem; font-weight: 650; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.compare-unavailable, .compare-missing { margin: 0; color: #4f5d6b; font-size: .86rem; }
.compare-chips { display: flex; flex-wrap: wrap; gap: .35rem; margin: 0; padding: 0; list-style: none; }
.compare-chip-item { padding: .25rem .6rem; border: 1px solid var(--line); border-radius: 99px; font-size: .78rem; }
.compare-chip-item.is-diff { border-color: #e3d6ad; background: #fbf6e6; color: #6b5718; font-weight: 650; }
.compare-foot { margin: .5rem 0 0; padding: .8rem 0 calc(.4rem + env(safe-area-inset-bottom)); border-top: 1px solid var(--line); font-size: .76rem; color: var(--muted); }

@media (min-width: 701px) and (max-width: 1000px) {
    .compare-table { --label-w: 6rem; --col-min: 12rem; }
}

@media (max-width: 700px) {
    .compare-dialog { inset: auto 0 0 0; width: 100%; max-height: 94dvh; margin: 0; border-radius: 20px 20px 0 0; }
    .compare-head { padding: 1rem 1rem .4rem; }
    .compare-head h2 { font-size: 1.3rem; }
    .compare-scroll { padding: 0 1rem .8rem; }
    .compare-table { --label-w: 0px; --col-min: 10.5rem; }
    .compare-row { grid-template-columns: repeat(var(--cols, 2), minmax(var(--col-min), 1fr)); }
    .compare-label { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
    .compare-cap { display: block; }
    .compare-row--head .compare-cap { display: none; }
    .compare-photo { height: 96px; }
    .compare-name { font-size: 1rem; }
    .compare-row > * { padding: .7rem .6rem; }
    .compare-tray-actions { width: 100%; justify-content: space-between; }
    .compare-open { flex: 1; }
    body.has-compare-tray { padding-bottom: calc(var(--aalabu-consent-banner-space, 0px) + 9rem); }
}
