/*
 * The agent website: the Boutique template, owner-approved 2026-09-22, which
 * replaced the 2026-09-06 page for every agency at once. Photograph-led: the
 * hero is the agency's headline beside a photograph carrying a price stamp,
 * the search card is tabbed per service, and the hotels are one feature panel
 * over a list rather than a row of equal cards.
 *
 * SERVED FROM public/, NOT BUILT FROM resources/css, and deliberately: the
 * built bundles need `npm run prod` and a committed artifact, and this repo has
 * already shipped a hand-patched bundle that the next real build silently
 * reverted. `public-pages.css` beside it is served the same way for the same
 * reason.
 *
 * IT DEFINES NO COLOUR OF ITS OWN except the THREE neutrals at the top - the
 * two unbranded fallbacks and the photo scrim - the WhatsApp green with the
 * white ink that sits on it, and the form-error red in its two themes. That
 * list is exhaustive and was counted, not remembered: comments stripped, the
 * only colour literals left in any RULE are the whites on the WhatsApp green
 * and #b91c1c / #f87171 on `.site-form-error`. Every other colour resolves
 * from the three brand tokens the white-label partial writes at :root -
 * --brand-orange, --brand-orange-rgb and --brand-navy - which ARE the
 * agency's primary_color and accent_color. That is why one stylesheet dresses
 * every agency and why there is no per-agent CSS anywhere in this feature.
 *
 * WHY --brand-navy IS SAFE AS THE DEEP FIELD (the enquiry block and the
 * footer) IN DARK MODE. The hotel feature panel's scrim is NOT on that list -
 * it is the neutral above, for the reason declared beside it. brand.css maps
 * --brand-navy to light ink under [data-bs-theme=dark], but the white-label
 * partial re-declares it at :root and is emitted AFTER brand.css - equal
 * specificity, later wins -
 * so on a copy it is the agency's accent in both themes. The fallback below is
 * what an unresolvable copy gets, and it is dark on purpose: a hero field that
 * turned pale would put white type on white.
 *
 * NO HARDCODED LIGHT SURFACE ANYWHERE. `DarkModeAtPhoneWidthTest` scans every
 * served stylesheet for one, because a light literal here is a screen that
 * stays light in dark mode and nothing in the compiled sweeps can see it.
 */

:root {
    /* The unbranded fallbacks. They mirror WhiteLabelBrand's own, and they are
       overridden by white-label/partials/brand.blade.php on any copy that
       resolves a site row. */
    --brand-orange: #f07822;
    --brand-orange-rgb: 240, 120, 34;
    --brand-navy: #16284b;

    /* The scrim under the hotel feature panel's type. NEUTRAL ON PURPOSE and
       deliberately NOT --brand-navy, which every other deep field here reads.
       This one lies over a PHOTOGRAPH and carries --site-on-deep (white) ink,
       and on a copy --brand-navy is the agency's OWN accent: a pale one would
       put white type on a pale ground, which is the 2.49:1 white-on-gold this
       project has already paid for once. A scrim exists to make type legible
       over an image whatever the agency's palette, so it is the one field on
       this page that must not follow it. Two stops, so the rule that reads
       them carries no colour of its own. */
    --site-scrim: rgba(11, 18, 36, 0.86);
    --site-scrim-clear: rgba(0, 0, 0, 0);

    /* WhatsApp is a CHANNEL, not decoration: the button carries the colour
       people recognise it by, in the muted tone the mockup uses rather than
       the neon one. It is the only colour on this page that belongs to
       neither the agency nor the neutrals. */
    --site-wa: #0b6e5f;
    --site-wa-hover: #085548;

    /* Radius scale - deliberate, not "rounded everything": media and cards are
       soft, actions are pills, inputs and tables are nearly square. */
    --site-r-card: 14px;
    --site-r-media: 12px;
    --site-r-input: 10px;

    /* 8px spacing scale. Every margin and padding below is one of these. */
    --site-s1: 8px;
    --site-s2: 16px;
    --site-s3: 24px;
    --site-s4: 32px;
    --site-s6: 48px;
    --site-s8: 64px;
    --site-s10: 80px;

    --site-container: 1200px;

    /* Ink that sits ON the deep brand field. Fixed rather than derived: the
       field is the agency's own dark accent in both themes, so the type on it
       is white in both themes too. */
    --site-on-deep: #ffffff;
    --site-on-deep-muted: rgba(255, 255, 255, 0.76);
    --site-on-deep-faint: rgba(255, 255, 255, 0.56);
    --site-on-deep-line: rgba(255, 255, 255, 0.16);
    --site-on-deep-fill: rgba(255, 255, 255, 0.08);

    /*
     * BRAND INK - the agency's primary used as TEXT rather than as a fill.
     *
     * On light it is the brand colour itself. On dark it cannot be: an agency
     * whose primary is a deep blue (which the approved design's own agency is)
     * puts #163988 text on a #121a2a card, and the kickers, the ghost buttons
     * and the "All hotels" links all but disappear. The dark value mixes the
     * agency's own colour towards white, so it stays THEIR colour and becomes
     * legible - and where `color-mix` is unsupported the declaration is simply
     * invalid and the light value survives, which is a duller button rather
     * than a broken page.
     */
    --site-brand-ink: var(--brand-orange);

    --site-tint: rgba(var(--brand-orange-rgb), 0.10);
    --site-tint-strong: rgba(var(--brand-orange-rgb), 0.16);

    /* ONE TYPEFACE, THE PORTAL'S. brand.css declares Plus Jakarta Sans on
       --bs-font-sans-serif and ships the files; the two aliases below exist so
       every rule in this sheet names a ROLE rather than a family, which is what
       TypographyIsOneFamilyTest's allowlist admits. */
    --site-font-head: var(--bs-font-sans-serif);
    --site-font-body: var(--bs-font-sans-serif);

    --site-shadow-card: 0 1px 2px rgba(16, 40, 75, 0.05), 0 12px 28px -20px rgba(16, 40, 75, 0.28);
    --site-shadow-lift: 0 20px 48px -24px rgba(16, 40, 75, 0.45);
}

[data-bs-theme="dark"] {
    /* The card shadow is the one thing that cannot survive: a shadow on a dark
       ground reads as a smudge, so cards are separated by their border alone. */
    --site-shadow-card: none;
    --site-shadow-lift: none;

    --site-brand-ink: color-mix(in srgb, var(--brand-orange) 42%, #ffffff);
    --site-tint: rgba(var(--brand-orange-rgb), 0.22);
    --site-tint-strong: rgba(var(--brand-orange-rgb), 0.32);
}

/* ---------- page ---------- */

.site {
    background: var(--brand-bg);
    color: var(--brand-text);
    font-family: var(--site-font-body);
    font-size: 16px;
    line-height: 1.62;
    -webkit-font-smoothing: antialiased;
}

.site *,
.site *::before,
.site *::after { box-sizing: border-box; }

.site h1,
.site h2,
.site h3,
.site h4 {
    margin: 0;
    font-family: var(--site-font-head);
    font-weight: 800;
    letter-spacing: -0.018em;
    color: var(--brand-text);
    text-wrap: pretty;
}

.site p { margin: 0; }
.site a { color: var(--site-brand-ink); text-decoration: none; }
.site a:hover { color: var(--site-brand-ink); text-decoration: underline; }
.site img { max-width: 100%; }

.site-inner {
    width: 100%;
    max-width: var(--site-container);
    margin: 0 auto;
    padding-left: var(--site-s3);
    padding-right: var(--site-s3);
}

.site-sec { padding: var(--site-s10) 0; }
.site-sec--tight { padding: var(--site-s8) 0; }
.site-sec--surface {
    background: var(--brand-surface);
    border-top: 1px solid var(--brand-border);
    border-bottom: 1px solid var(--brand-border);
}
.site-sec--alt { background: var(--brand-surface-2); }

.site-kicker {
    display: block;
    font-family: var(--site-font-head);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--site-brand-ink);
}

.site-h2 { font-size: 34px; line-height: 1.16; margin-top: var(--site-s1); }
.site-lead {
    font-size: 16.5px;
    line-height: 1.7;
    color: var(--brand-text-muted);
    margin-top: var(--site-s2);
    max-width: 62ch;
}

.site-head-row {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--site-s3);
    margin-bottom: var(--site-s4);
}

.site-muted { color: var(--brand-text-muted); }
/*
 * MUTED, NOT FAINT. These are the small uppercase captions over every figure
 * on the page - FROM, PER SEAT, DEPARTS - and at `--brand-text-faint` they
 * measured 2.45:1 on the light theme, well under the 4.5 a 11px label needs.
 * They are not decoration: they are what says whether PKR 588,600 is per
 * person or per seat.
 */
.site-lbl {
    display: block;
    font-family: var(--site-font-head);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--brand-text-muted);
}

/* ---------- buttons ---------- */

.site-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    min-height: 48px;
    padding: 0 24px;
    border-radius: 999px;
    border: 0;
    font-family: var(--site-font-head);
    font-size: 15px;
    font-weight: 700;
    cursor: pointer;
    text-decoration: none;
    transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease;
}
.site-btn:hover { text-decoration: none; }
/*
 * TWO CLASSES DEEP, AND THAT IS NOT A STYLE PREFERENCE. `.site a` above sets
 * the link colour and scores (0,1,1); a single-class button rule scores
 * (0,1,0) and LOSES to it - so every button that is an anchor rendered its
 * label in the brand link colour, which on the primary and WhatsApp fills is
 * the fill's own colour. The controls looked like unlabelled blobs and the
 * words were there all along.
 *
 * BUT THE SECOND CLASS IS THE BUTTON'S OWN, NEVER THE BODY'S, AND THAT IS THE
 * FIX THIS ROUND MAKES. These read `.site .site-btn--x`, which needs a
 * `body.site` ancestor - and only the LANDING page carries that class. The
 * twelve inner pages a copy serves include `page-chrome` into their own bare
 * `<body>`, so every one of these variants was INERT on them: the WhatsApp
 * pill in the header rendered with no fill at all and took its ink from
 * `brand.css`'s bare `a` rule, measuring 1.78:1 on Hafiz G's own site in dark
 * at 1440 - on the one control a customer taps - and 4.16:1 on Midjourney's in
 * light. Keyed on `.site-btn` instead the specificity is identical, (0,2,0)
 * either way, and the rule matches wherever the button does.
 *
 * THE BODY-SCOPED RULES ABOVE ARE DELIBERATELY LEFT ALONE. `.site h1`,
 * `.site p`, `.site a` and `.site *` are page-BODY styling, and `page-chrome`
 * exists precisely to leave those twelve page bodies as they were designed;
 * putting `class="site"` on them to fix a button would repaint every heading,
 * paragraph margin and link on twelve pages at once. Measured across the whole
 * chrome on both bodies, the pill and its label were the ONLY elements that
 * differed in anything a visitor can see.
 */
.site-btn.site-btn--primary { background: var(--brand-orange); color: var(--brand-on-primary, #ffffff); }
.site-btn.site-btn--primary:hover { background: var(--brand-orange); color: var(--brand-on-primary, #ffffff); filter: brightness(0.92); }
.site-btn.site-btn--wa { background: var(--site-wa); color: #ffffff; }
.site-btn.site-btn--wa:hover { background: var(--site-wa-hover); color: #ffffff; }
.site-btn.site-btn--ghost {
    background: var(--brand-surface);
    color: var(--site-brand-ink);
    border: 1.5px solid var(--brand-border);
}
.site-btn.site-btn--ghost:hover { background: var(--site-tint); color: var(--site-brand-ink); }
.site-btn--sm { min-height: 42px; padding: 0 18px; font-size: 14px; }
.site-btn--block { width: 100%; }

/* ---------- the inner service pages ---------- */

/*
 * EVERY INNER SERVICE PAGE SITS ON THE LANDING PAGE'S CANVAS NOW (owner,
 * 2026-09-23: "The background should be the same across the website", and,
 * asked which canvas, the landing's). That canvas is `.site`'s own ground
 * above - `--brand-bg` under `--brand-text` - which follows the visitor's
 * theme, where the inner pages used to paint a navy-to-gold gradient that was
 * dark in both themes. Each page's own `body` rule reads the same two tokens;
 * these two classes are the page title and its lead sentence, written in the
 * landing's own heading and lead inks rather than in the white the gradient
 * needed.
 *
 * `--brand-text` FOR THE TITLE, NOT `--brand-navy`. `brand.css` paints every
 * heading `--brand-navy`, and on a copy that property IS the agency's accent in
 * both themes - a pale accent would put a pale title on the pale canvas. The
 * landing's `.site h1` reads `--brand-text` for exactly that reason, and the
 * title here is the same ink so the two pages read as one site.
 */
.site-page-title { color: var(--brand-text); text-shadow: none; }
.site-page-lead { color: var(--brand-text-muted); }

/*
 * THE ONE "BACK TO HOME" CONTROL (`public.site.partials.back-home`): the landing's
 * ghost button, on its own line at the top-left of the page's content.
 *
 * ITS INK IS NOT THE GHOST BUTTON'S. `--site-brand-ink` is the agency's primary
 * as it comes, which on light is the fill colour used as text - Midjourney's
 * gold measured 2.49:1 as text on the white header, the figure recorded beside
 * `.site-brand-name`. That token is left alone because every landing-page link
 * reads it. This control reads `--site-brand-name-ink` instead, the SAME
 * derivation the wordmark already uses: the agency's own hue and chroma with
 * the lightness clamped to at most L 0.45 on light and at least L 0.72 on dark,
 * against the same two surfaces (`--brand-surface` is this button's fill and
 * the header's), so the floor measured there holds here. Where relative colour
 * syntax is unsupported the `@supports` block never runs and the fallback is
 * `--brand-orange-ink`, exactly as for the wordmark.
 *
 * `display: flex` WITH `width: fit-content` puts it on its own line whatever
 * follows it, without stretching it across the container. Two classes deep so
 * it is ordered after `.site-btn.site-btn--ghost` at the same specificity; the
 * hover repeats the ink because the ghost hover is one class deeper.
 */
.site-btn.site-back-home {
    display: flex;
    width: fit-content;
    margin: 0 0 var(--site-s3);
    color: var(--site-brand-name-ink, var(--brand-orange-ink));
}
.site-btn.site-back-home:hover { color: var(--site-brand-name-ink, var(--brand-orange-ink)); }
.site-btn.site-back-home .ti { font-size: 18px; line-height: 1; }

/* ---------- cards, pills, chips ---------- */

.site-card {
    background: var(--brand-surface);
    border: 1px solid var(--brand-border);
    border-radius: var(--site-r-card);
    box-shadow: var(--site-shadow-card);
}

.site-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border-radius: 999px;
    font-family: var(--site-font-head);
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    background: var(--site-tint);
    color: var(--site-brand-ink);
}
.site-pill--on-deep {
    background: var(--site-on-deep-fill);
    color: var(--site-on-deep);
}

.site-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--site-s1);
    padding: 9px 16px;
    border-radius: 999px;
    background: var(--brand-surface);
    border: 1px solid var(--brand-border);
    font-size: 14px;
    font-weight: 600;
    color: var(--brand-text);
}

.site-icobox {
    width: 52px;
    height: 52px;
    border-radius: var(--site-r-media);
    background: var(--site-tint);
    color: var(--site-brand-ink);
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
}

.site-ico { width: 24px; height: 24px; display: block; }
.site-ico--sm { width: 18px; height: 18px; }
.site-ico--lg { width: 34px; height: 34px; }

.site-price {
    white-space: nowrap;
    font-family: var(--site-font-head);
    font-size: 24px;
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--brand-text);
}
.site-price--sm { font-size: 19px; }
.site-price small {
    font-family: var(--site-font-body);
    font-size: 13px;
    font-weight: 500;
    color: var(--brand-text-muted);
}
.site-price--onreq { font-size: 19px; color: var(--brand-text-muted); }

.site-stars { display: inline-flex; gap: 2px; color: var(--site-brand-ink); }

/* ---------- top bar + header ---------- */

.site-topbar {
    background: var(--brand-navy);
    color: var(--site-on-deep-muted);
    font-size: 13.5px;
}
.site-topbar .site-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--site-s3);
    min-height: 44px;
    padding-top: 6px;
    padding-bottom: 6px;
    flex-wrap: wrap;
}
.site-topbar-item { display: inline-flex; align-items: center; gap: var(--site-s1); }
.site-topbar-item svg { color: var(--site-on-deep-faint); }
.site-topbar a { color: var(--site-on-deep-muted); }
.site-topbar a:hover { color: var(--site-on-deep); }
.site-topbar-group { display: flex; align-items: center; gap: var(--site-s3); flex-wrap: wrap; }

.site-header {
    background: var(--brand-surface);
    border-bottom: 1px solid var(--brand-border);
}
/*
 * THE HEADER WRAPS RATHER THAN BREAKING WORDS, and that is sizing for every
 * agency rather than for the mockup's one. The approved design carries six
 * short captions beside a short brand name and fits on one row; an agency
 * that buys all seven services and is called "Hafiz G Travel & Tours" needs
 * about 730px of nav in 590px of space, and the nav then broke every caption
 * in half - "Umrah / Packages", "Ziarat & / Transport".
 *
 * `flex-wrap` plus a nav that asks for 420px means the row stays exactly as
 * approved whenever it fits and drops the nav to a full-width second row when
 * it does not, instead of shredding it. Nothing here depends on how many
 * services this agency bought or on how long its name is.
 */
.site-header .site-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--site-s2) var(--site-s3);
    min-height: 88px;
    padding-top: var(--site-s1);
    padding-bottom: var(--site-s1);
}
/*
 * THE BRAND LINK IS THE MARK AND THE NAME (owner, 2026-09-09). The tagline
 * used to sit under the name here and again as the hero's subtitle, so the
 * same sentence was read twice; `.site-brand-sub` is gone rather than hidden,
 * because a rule with no element is the next author's invitation to bring the
 * element back. See header.blade.php for the whole reasoning.
 *
 * `max-width` BOUNDS THE BLOCK, `overflow-wrap` BOUNDS THE WORD. The brand is
 * `flex: 0 0 auto`, so its base size is its content and only the max-width
 * stops a long name widening it into the nav; a single unbreakable word longer
 * than that box would still spill past it, which no agency name here does and
 * which one declaration makes impossible for the one that eventually does.
 * The nav is `flex: 1 1 420px` beside it and drops to its own row when it no
 * longer fits, so a two-line name costs header HEIGHT and never nav layout -
 * measured in Chromium at 390 and 1440 on both live kits.
 *
 * 340 RATHER THAN 320, AND WHAT THE 20px BUYS IS A LINE BEHIND A WIDE MARK.
 * The cap bounds the whole link - mark, 12px gap and name - so the wider the
 * agency's logo the less of the box is left for their name. Driven against the
 * real element at 1440 with fifteen agency-shaped names: on Hafiz G's narrow
 * 34px mark the two caps are IDENTICAL on all fifteen, and on Midjourney's
 * 148px mark 340 saves a whole line on four of them ("Al Noor Travels" 2 -> 1,
 * "Hafiz G Travel & Tours Pvt Ltd" 3 -> 2, "Karachi Air Travel Services Pvt
 * Limited" and "Al Haramain International Travel & Tours" 4 -> 3).
 *
 * SO IT CHANGES NOTHING ON THE THREE NAMES LIVE TODAY, AND THAT IS SAID RATHER
 * THAN DRESSED UP: all three wrap to two lines under either cap and the header
 * measures 89px at 1440 and 115px at 390 either way. What it changes is the
 * next agency whose logo is wide, which is the case the bound exists for. The
 * cap only binds at desktop at all - at 390 the block measures 299-311px on
 * all three kits, under both ceilings.
 */
.site-brand { display: flex; align-items: center; gap: 12px; text-decoration: none; flex: 0 0 auto; max-width: 340px; }
.site-brand:hover { text-decoration: none; }
.site-brand-mark { height: 44px; width: auto; }
/*
 * IN DARK THE HEADER IS A DEEP SURFACE TOO, SO A DARK MARK NEEDS A PLATE.
 *
 * `.site-header` is `--brand-surface`, which is white in light and near-black
 * in dark - so Midjourney's dark navy wordmark, in their own header, was the
 * footer defect one surface up: 1.41:1 for the file's own ink against that
 * field, measured off the image rather than read off the box, because the gold
 * swoosh beside it lifts any percentile taken over the whole mark.
 *
 * IT IS THE `--plate` MODIFIER AND NOT THE MARK ITSELF, and that is the fix
 * this round makes. Plating every logo trades one invisible mark for another:
 * a near-white file - the commonest way an agency ships a logo FOR dark chrome
 * - measures 1.04:1 on a white plate against 16.69:1 on the bare dark header.
 * The class is emitted only when `LogoGround` says a white ground beats the
 * field for THIS file, so a mark that needs nothing is drawn as it is.
 *
 * `content-box` SO THE PLATE GROWS AND THE ART DOES NOT. `.site *` is
 * border-box, under which the padding would eat 10px of a 44px logo and the
 * mark would shrink the moment a visitor's phone is in dark mode.
 *
 * THE GROUND IS `--site-on-deep`, WHICH IS THIS FILE'S OWN "WHITE IN BOTH
 * THEMES" TOKEN and not a literal that happens to be white. A literal here
 * would be right and would also read exactly like the pinned-light page
 * surfaces the served-stylesheet scan exists to catch; the token says what is
 * meant - the light thing that goes on a deep field - and cannot drift from
 * the ink the rest of this footer and header already take from it.
 */
[data-bs-theme="dark"] .site-header .site-brand-mark--plate {
    box-sizing: content-box;
    background: var(--site-on-deep);
    border-radius: 10px;
    padding: 5px 8px;
}
.site-brand-name {
    display: block;
    min-width: 0;
    overflow-wrap: anywhere;
    font-family: var(--site-font-head);
    font-size: 21px;
    font-weight: 800;
    letter-spacing: -0.02em;
    /*
     * THE AGENCY'S COLOUR AS TEXT, NOT AS A FILL. `--site-brand-ink` is the
     * primary itself on light, which is right for a colour chosen to be a
     * button and wrong for one used as 21px type: Midjourney's gold measured
     * **2.49:1** on the white header at 390 and 1440, on the one word this
     * link now exists to carry.
     *
     * `--brand-orange-ink` IS THE FALLBACK AND NOT THE ANSWER, AND THE
     * SENTENCE THAT SAID OTHERWISE WAS WRONG TWICE. It read: the token "moves
     * nothing for an agency whose primary is already dark". It is the primary
     * mixed 68% with black on light, and a fixed mix moves EVERY colour - the
     * seeded #1A3F8E goes from 9.79:1 to 13.60:1, which is a real change to an
     * agency's own wordmark, not a no-op. And a fixed mix cannot promise
     * anything: a pale primary darkened by 68% is still pale. Swept over twenty
     * primaries against the real header surfaces (#ffffff in light, #121a2a in
     * dark, both read off the rendered page), ELEVEN fail AA under it - nine on
     * the white header, #FFFFFF worst at 2.24:1, then #F7F7F5 2.38, #FFFF00
     * 2.40, #E8E8E8 2.68, #00FFFF 2.77, #7FFF00 2.85, #FFD966 2.96, #00FF00
     * 3.01, #BBDEFB 3.04 - and two on the dark one, #000000 at 3.67:1 and
     * #111111 at 4.17:1. An agency picks its primary on a form; pale is a
     * choice it is allowed to make, and so is near-black.
     *
     * SO THE INK IS DERIVED TO A LIGHTNESS THE SURFACE CAN CARRY, keeping the
     * agency's hue and chroma and moving only the one channel that decides
     * legibility: at most L 0.45 on the white header, at least L 0.72 on the
     * dark one. Over those same twenty, NONE falls below AA and the worst case
     * is 6.00:1 on light (#00FF00) and 5.06:1 on dark (#FF0000) - so it is a
     * FLOOR rather than an improvement in the average, which is the point: on
     * the seeded #1A3F8E it reads 9.79:1 rather than the mix's 13.60:1, which
     * is a truer rendering of the agency's own colour at the same legibility.
     *
     * THE FIGURES ABOVE REPLACE A SET THAT WAS MEASURED ON A SMALLER SWEEP AND
     * WRITTEN AS THOUGH IT COVERED THIS ONE. They said four failures and a
     * 6.80/6.52 worst case; both were true of an earlier fifteen-colour list
     * that did not contain the colours the sentence went on to name. A count
     * carries the population it was counted over, or it is a guess wearing a
     * decimal point.
     *
     * THE `@supports` IS LOAD-BEARING AND NOT CEREMONY: this is a CUSTOM
     * property, so a browser that cannot parse the derivation would ACCEPT the
     * token stream anyway, win the cascade and then fail at computed-value
     * time - leaving the wordmark with inherited ink rather than with the
     * fallback. The at-rule is evaluated before the declaration is parsed,
     * which is the only shape that really falls back.
     *
     * THE REST OF `--site-brand-ink` IS DELIBERATELY UNTOUCHED. Every link,
     * kicker and ghost button on the site reads it and measures the same 2.49
     * on that palette; repainting all of them is a decision about two live
     * agency websites rather than a fix to the control the owner named, and it
     * is reported with its figure instead of taken here.
     */
    color: var(--site-brand-name-ink, var(--brand-orange-ink));
    line-height: 1.15;
}
@supports (color: oklch(from red l c h)) {
    :root { --site-brand-name-ink: oklch(from var(--brand-orange) min(l, 0.45) c h); }
    /*
     * `:root[…]` RATHER THAN THE BARE ATTRIBUTE, so this beats the `:root`
     * above it on specificity rather than on source order - the white-label
     * partial is emitted inside the page and this file is not, and a rule that
     * relies on being later is one an added stylesheet can silently reverse.
     */
    :root[data-bs-theme="dark"] { --site-brand-name-ink: oklch(from var(--brand-orange) max(l, 0.72) c h); }
}

/*
 * `[hidden]` IS ONLY A UA `display:none`, AND `.site-nav` OVERRIDES IT. The
 * collapse script sets `nav.hidden = true` on a phone and the menu stayed
 * open, which is the dead-control shape with the control right beside it.
 */
.site-nav {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1 1 420px;
    gap: 18px;
    row-gap: var(--site-s1);
    flex-wrap: wrap;
}
.site-nav[hidden] { display: none; }
.site-nav a {
    font-size: 14.5px;
    font-weight: 600;
    color: var(--brand-text);
    white-space: nowrap;
}
.site-nav a:hover { color: var(--site-brand-ink); text-decoration: none; }

.site-burger { display: none; }
.site-header-actions { display: flex; align-items: center; gap: var(--site-s1); flex: 0 0 auto; }

/* ---------- hero ---------- */

/*
 * THE HERO SITS ON THE PAGE GROUND, NOT ON THE DEEP FIELD. The approved
 * template puts the headline in body ink beside a photograph; the deep colour
 * is kept for the enquiry block and the footer, where white type on it is the
 * design. So nothing here reads --site-on-deep, and the buttons are the
 * ordinary primary / WhatsApp / ghost variants.
 */
.site-hero { background: var(--brand-bg); color: var(--brand-text); }
.site-hero-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--site-s6);
    align-items: center;
    padding-top: var(--site-s6);
    padding-bottom: var(--site-s2);
}
.site-hero h1 {
    font-size: 50px;
    line-height: 1.06;
    letter-spacing: -0.03em;
    max-width: 16ch;
}
.site-hero-sub {
    font-size: 17.5px;
    line-height: 1.65;
    color: var(--brand-text-muted);
    max-width: 44ch;
    margin-top: var(--site-s2);
}
.site-hero-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: var(--site-s4); }

/*
 * THE PANEL IS A PHOTOGRAPH WITH A ROUNDED EDGE AND ONE STAMP ON IT. The
 * radius is larger than a card's on purpose - it is the one hero-sized panel
 * on the page (the spec's 16px hero panel, rounded up to the approved
 * mockup's 22px) - and the stamp is a surface-coloured plate so the figure
 * reads in body ink on either photograph, in either theme.
 */
.site-hero-panel {
    position: relative;
    border-radius: 22px;
    overflow: hidden;
    background: var(--brand-navy);
    min-height: 440px;
}
.site-hero-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.site-hero-stamp {
    position: absolute;
    left: var(--site-s3);
    bottom: var(--site-s3);
    /* Its own inset on BOTH sides: a seven-figure price on a 320px phone
       otherwise ran to the panel's edge and under its rounded corner. */
    max-width: calc(100% - 2 * var(--site-s3));
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 2px;
    padding: 14px 18px;
    border-radius: var(--site-r-media);
    background: var(--brand-surface);
    color: var(--brand-text);
    box-shadow: var(--site-shadow-lift);
}
/*
 * THE STAMP IS A CAROUSEL OF LINKS, ONE PER PRICED PACKAGE (owner decision
 * 2026-09-23). Inside the plate each package is a link to its own detail
 * page, and only one is shown at a time - the others carry `hidden`.
 *
 * EVERY STAMP SITS IN THE SAME GRID CELL, so the plate is as wide as the
 * WIDEST stamp and never moves as they rotate - laid out one at a time it
 * jumped 23px wider and back every four seconds. That is also why a hidden
 * stamp is `visibility: hidden` rather than `display: none`: it must keep its
 * place in the cell to size the plate. `visibility: hidden` still takes it out
 * of the accessibility tree, out of the tab order and out of hit-testing, so
 * `[hidden]` means what it says; `display: flex` on the link is restated on
 * the hidden rule because the user-agent `[hidden] { display: none }` would
 * otherwise put it back to taking no space.
 *
 * A LONG PRICE WRAPS RATHER THAN CLIPS. `.site-price` is `nowrap` everywhere
 * else; on the plate, which is capped at the panel's width minus its inset,
 * "per person" may drop to a second line on a narrow phone.
 *
 * The link keeps the label's and the price's own inks (`.site-lbl`,
 * `.site-price`): it is the plate that says "this is a stamp", and an
 * underline across a price reads as a typo rather than a link.
 */
.site-hero-stamp-link {
    grid-area: 1 / 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    border-radius: var(--site-r-input);
}
.site-hero-stamp-link[hidden] { display: flex; visibility: hidden; }
.site-hero-stamp .site-price { white-space: normal; }
/* ...as a unit: "per" on one line and "person" on the next reads as a typo. */
.site-hero-stamp .site-price small { white-space: nowrap; }
.site .site-hero-stamp-link:hover { text-decoration: none; }
.site-hero-stamp-link:focus-visible { outline: 2px solid var(--site-brand-name-ink, var(--brand-orange-ink)); outline-offset: 4px; }
@media (prefers-reduced-motion: no-preference) {
    /* On the SHOWN stamp only, so the fade re-runs each time one is revealed. */
    .site-hero-stamp-link:not([hidden]) { animation: site-hero-stamp-in 240ms ease-out; }
}
@keyframes site-hero-stamp-in {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: none; }
}
/*
 * ONE DOT PER STAMP, the current one filled in the agency's ink. The button is
 * a 24px target (WCAG 2.5.8) and the visible dot is its 8px `::before`, so a
 * row that reads as small marks is still something a thumb can hit.
 *
 * THE INK IS `--site-brand-name-ink`, NOT `--site-brand-ink`. A dot is a
 * control whose filled/hollow state IS its information, so it needs 3:1
 * against the plate (WCAG 1.4.11), and the raw primary on the white plate is
 * the 2.49:1 Midjourney's gold measured beside `.site-brand-name`. The
 * wordmark's derivation - the agency's hue with the lightness clamped for
 * the surface - is declared against `--brand-surface`, which is this plate's
 * fill too, so the floor measured there holds here.
 */
.site-hero-dots {
    grid-area: 2 / 1;
    display: flex;
    /* The first dot's mark sits a spacing step inside its 24px target; pulling
       the row back by that step lines the mark up with the label above it. */
    margin-left: calc(-1 * var(--site-s1));
}
.site-hero-dots[hidden] { display: none; }
.site-hero-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: none;
    cursor: pointer;
}
.site-hero-dot::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    border: 1.5px solid var(--site-brand-name-ink, var(--brand-orange-ink));
}
.site-hero-dot[aria-current="true"]::before { background: var(--site-brand-name-ink, var(--brand-orange-ink)); }
.site-hero-dot:focus-visible { outline: 2px solid var(--site-brand-name-ink, var(--brand-orange-ink)); outline-offset: 0; }

/* ---------- search card ---------- */

.site-search { position: relative; z-index: 2; margin-top: var(--site-s4); }
.site-search-card {
    padding: 0;
    border-radius: 18px;
    box-shadow: var(--site-shadow-lift);
    overflow: visible;
}

/*
 * TABS, ONE PER SERVICE THE AGENCY SELLS. The strip and the panes are the
 * portal landing card's shape under this surface's class names; the active
 * tab wears the brand tint so it reads as a control and not as a heading.
 * Only the active pane is displayed, and the toggle is four lines of script
 * in the partial - no library, nothing fetched.
 */
.site-search-tabs {
    display: flex;
    gap: 4px;
    padding: var(--site-s1);
    border-bottom: 1px solid var(--brand-border);
    overflow-x: auto;
    scrollbar-width: none;
}
.site-search-tab {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 14px;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--brand-text-muted);
    font-family: var(--site-font-head);
    font-size: 14px;
    font-weight: 700;
    white-space: nowrap;
    cursor: pointer;
}
.site-search-tab:hover { color: var(--brand-text); background: var(--brand-surface-2); }
.site-search-tab.is-active { background: var(--site-tint); color: var(--site-brand-ink); }
.site-search-tab:focus-visible { outline: 2px solid var(--brand-orange); outline-offset: 2px; }
.site-search-pane { display: none; padding: var(--site-s3); }
.site-search-pane.is-active { display: block; }
.site-search-simple {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--site-s2);
    flex-wrap: wrap;
}
.site-search-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--site-s2);
    margin-bottom: var(--site-s2);
    flex-wrap: wrap;
}
.site-search-note { font-size: 13.5px; color: var(--brand-text-muted); }
.site-search-grid {
    display: grid;
    grid-template-columns: 1.2fr 1.2fr 1fr 1fr 0.9fr auto;
    gap: 12px;
    align-items: stretch;
}

/*
 * A GRID ITEM DEFAULTS TO `min-width: auto`, SO IT CANNOT SHRINK BELOW ITS
 * CONTENT - and a native `<input type="date">` has an intrinsic width wider
 * than a 390px column. Without this the search card pushed the whole page 6px
 * wider than the viewport and the document scrolled sideways, which on a phone
 * is the first thing anybody notices.
 */
.site-search-grid > * { min-width: 0; }
.site-field input,
.site-field select { min-width: 0; }
.site-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 10px 14px;
    border-radius: var(--site-r-input);
    background: var(--brand-surface-2);
    border: 1px solid var(--brand-border);
}
.site-field input,
.site-field select {
    border: 0;
    background: transparent;
    color: var(--brand-text);
    font-family: var(--site-font-body);
    font-size: 15.5px;
    font-weight: 600;
    padding: 0;
    width: 100%;
    min-height: 24px;
}
.site-field input:focus,
.site-field select:focus { outline: none; }

/*
 * A NATIVE DATE INPUT IGNORES `width: 100%` ON WEBKIT UNLESS IT IS TOLD TO
 * STOP BEING A NATIVE DATE INPUT. `min-width: 0` above is half the fix and was
 * already here: it lets the GRID ITEM shrink. The other half is the CONTROL,
 * which on iOS Safari carries an intrinsic width of its own and lays its
 * shadow parts out inside it - so at this breakpoint, where Depart and Return
 * share a `1fr 1fr` row about 118px wide (measured in Chromium at 390px), the
 * control renders wider than its column and spills past the card's right edge.
 * That is what the owner photographed on 2026-09-08.
 *
 * CHROMIUM NEVER SHOWED IT, so this is the standard WebKit rule set rather
 * than something reproduced locally: `appearance: none` drops the intrinsic
 * sizing, `display: block` stops the control being laid out inline, and
 * `box-sizing: border-box` keeps its padding inside the 100%. Measured in
 * Chromium at 390px and 1440px before and after: no input's right edge moves.
 */
.site-field input[type="date"] {
    display: block;
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    -webkit-appearance: none;
    appearance: none;
}

/* The field owns its own autocomplete list, so any number of cards can sit on
   one page - nothing here is keyed on an id. */
.site-field { position: relative; }

.site-search-options {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 30;
    margin: 0;
    padding: 4px;
    list-style: none;
    max-height: 240px;
    overflow-y: auto;
    background: var(--brand-surface);
    border: 1px solid var(--brand-border);
    border-radius: var(--site-r-input);
    box-shadow: var(--site-shadow-lift);
}

.site-search-options li {
    padding: 8px 10px;
    border-radius: 8px;
    color: var(--brand-text);
    font-family: var(--site-font-body);
    font-size: 14.5px;
    cursor: pointer;
}

.site-search-options li:hover { background: var(--brand-surface-2); }

/* A refusal the visitor can read, spanning the row whatever the column count. */
.site-search-refusal {
    grid-column: 1 / -1;
    margin: 0;
    color: var(--brand-danger-ink);
    font-family: var(--site-font-body);
    font-size: 14.5px;
}
.site-field:focus-within {
    border-color: var(--brand-orange);
    box-shadow: 0 0 0 3px var(--site-tint);
}
.site-search-grid .site-btn { min-height: 100%; border-radius: var(--site-r-input); }

/* ---------- trust strip ---------- */

.site-trust { padding: var(--site-s4) 0 0; }
.site-trust .site-inner {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    justify-content: flex-start;
}

/* ---------- grids ---------- */

.site-grid { display: grid; gap: var(--site-s3); }
.site-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.site-grid--visa { grid-template-columns: 0.9fr repeat(3, minmax(0, 1fr)); }

/* ---------- hotels: one feature panel over a list ---------- */

.site-hotels {
    display: grid;
    grid-template-columns: 1.3fr 1fr;
    gap: var(--site-s3);
    align-items: stretch;
}
.site-hotels--one { grid-template-columns: 1fr; }
.site-hotel-feature {
    position: relative;
    display: block;
    min-height: 380px;
    border-radius: var(--site-r-card);
    overflow: hidden;
    background: var(--brand-navy);
    color: var(--site-on-deep);
    text-decoration: none;
}
.site-hotel-feature:hover { text-decoration: none; color: var(--site-on-deep); }
.site-hotel-feature-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
/*
 * THE SCRIM IS WHAT MAKES THE TYPE DECIDABLE. White ink over an unknown
 * photograph is white on whatever the picture happens to be; a darkening
 * band under the text gives it a ground the figure can be read against
 * whatever the agency uploads. It is a plain vertical fade to the deep
 * colour, the same device the 2026-09-06 hero used, not decoration.
 */
.site-hotel-feature-scrim {
    position: absolute;
    inset: auto 0 0 0;
    height: 62%;
    background: linear-gradient(180deg, var(--site-scrim-clear) 0%, var(--site-scrim) 100%);
}
.site-hotel-feature-text {
    position: absolute;
    left: var(--site-s3);
    right: var(--site-s3);
    bottom: var(--site-s3);
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.site-lbl--on-deep { color: var(--site-on-deep-muted); }
.site-hotel-feature .site-hotel-name {
    font-family: var(--site-font-head);
    font-size: 26px;
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--site-on-deep);
}
.site-hotel-meta { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.site-stars--on-deep { color: var(--site-on-deep); }
.site-price--on-deep { color: var(--site-on-deep); }
.site-price--on-deep small { color: var(--site-on-deep-muted); }

.site-hotel-list { display: grid; gap: 12px; align-content: start; }
.site-hotel-row {
    display: grid;
    grid-template-columns: 92px 1fr auto;
    gap: var(--site-s2);
    align-items: center;
    padding: 12px;
    background: var(--brand-surface);
    border: 1px solid var(--brand-border);
    border-radius: var(--site-r-card);
    box-shadow: var(--site-shadow-card);
    color: var(--brand-text);
    text-decoration: none;
}
.site-hotel-row:hover { text-decoration: none; color: var(--brand-text); border-color: var(--brand-orange); }
.site-hotel-row-photo {
    width: 92px;
    height: 70px;
    border-radius: 9px;
    object-fit: cover;
    display: block;
    background: var(--brand-surface-2);
}
.site-hotel-row-text { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.site-hotel-row .site-hotel-name {
    font-family: var(--site-font-head);
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -0.01em;
}
.site-hotel-row-sub { font-size: 13.5px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.site-hotel-row-price { text-align: right; flex: none; }

/* ---------- media panels on cards ---------- */

.site-media {
    display: block;
    width: 100%;
    height: 190px;
    object-fit: cover;
    background: var(--brand-surface-2);
}

.site-cardbody { padding: var(--site-s3); }
.site-cardfoot .site-btn { flex: none; }
/*
 * THE FOOT WRAPS, BECAUSE THE PRICE AND THE BUTTON BOTH REFUSE TO SHRINK.
 *
 * `flex: none` above is right - a squeezed "Details" is not a control - and
 * the price block's `min-width` is `auto`, so its floor is its longest token.
 * Two unshrinkable items in a `nowrap` row means the row simply OVERFLOWS,
 * and it did: measured on a copy's landing page at 1440-wide steps, the
 * Details button hung outside its own card by 60px at 960, 46 at 1000, 38 at
 * 1024, 13 at 1100 and 2 at 768, and the page itself scrolled sideways by 26,
 * 12 and 4px at the three middle widths. The card's border is drawn where the
 * card ends, so the control sat past it.
 *
 * THE PAGE OVERFLOW WAS THE SMALLER HALF, AND CHASING IT ALONE WOULD HAVE
 * FIXED THREE WIDTHS OF FIVE. `documentElement.scrollWidth` only moves when
 * the spill survives the grid and the section; the button escapes its card at
 * 768 and 1100 with no document scroll at all. Measure the element against its
 * own container, not the page against the viewport.
 *
 * AND WRAPPING IS THE DESIGN'S OWN ANSWER TO "THIS ROW DOES NOT FIT" - the
 * media query below already stacks this foot and stretches the button under
 * 767px. `flex-wrap: wrap` applies that same layout at exactly the widths
 * where the row cannot hold, and leaves it side by side where it can: after
 * this, side by side at 900 (two-column grid, wide card), 1280 and 1440,
 * stacked from 768 to 1150, and mixed at 1200 where three of four cards do not
 * fit and the fourth does.
 *
 * `min-width: 0` ON THE CHILDREN WAS THE OTHER CANDIDATE AND IS WORSE. It also
 * clears the overflow, by letting the price block shrink below its content -
 * measured at 208px of text in a 123px box on eight blocks per page, so the
 * fare is clipped rather than misplaced. A wrong price is worse than a
 * stacked button.
 */
.site-cardfoot {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--site-s2);
    margin-top: var(--site-s2);
    padding-top: var(--site-s2);
    border-top: 1px solid var(--brand-border);
}

/* ---------- about ---------- */

.site-about {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--site-s8);
    align-items: center;
}
.site-about-panel {
    position: relative;
    border-radius: var(--site-r-card);
    overflow: hidden;
    background: var(--brand-navy);
    min-height: 380px;
}
.site-about-panel img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.site-about p + p { margin-top: var(--site-s2); }
.site-about-actions { display: flex; gap: 12px; margin-top: var(--site-s4); flex-wrap: wrap; }

/* ---------- enquiry ---------- */

.site-enquiry { background: var(--brand-navy); color: var(--site-on-deep); }
.site-enquiry .site-inner {
    display: grid;
    grid-template-columns: 0.85fr 1.15fr;
    gap: var(--site-s8);
    align-items: center;
}
.site-enquiry h2 { color: var(--site-on-deep); font-size: 34px; }
.site-enquiry .site-kicker { color: var(--site-on-deep-faint); }
.site-enquiry-lead { color: var(--site-on-deep-muted); font-size: 16.5px; line-height: 1.7; margin-top: var(--site-s2); max-width: 46ch; }
.site-contact-list { display: flex; flex-direction: column; gap: 14px; margin-top: var(--site-s4); }
.site-contact-list li { display: flex; align-items: center; gap: 12px; font-size: 16px; color: var(--site-on-deep); }
.site-contact-list svg { color: var(--site-on-deep-faint); flex: none; }
.site-contact-list a { color: var(--site-on-deep); }

.site-form-card { padding: var(--site-s4); border-radius: 18px; }
.site-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--site-s2) var(--site-s3); }
.site-form-full { grid-column: 1 / -1; }
.site-form-field { display: flex; flex-direction: column; gap: 6px; }
.site-form-field > label {
    font-family: var(--site-font-head);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--brand-text-muted);
}
.site-form-field input,
.site-form-field textarea {
    width: 100%;
    min-height: 48px;
    border-radius: var(--site-r-input);
    background: var(--brand-surface-2);
    border: 1px solid var(--brand-border);
    color: var(--brand-text);
    font-family: var(--site-font-body);
    font-size: 15px;
    padding: 12px 14px;
}
.site-form-field textarea { min-height: 122px; resize: vertical; }
.site-form-field input:focus,
.site-form-field textarea:focus {
    outline: none;
    border-color: var(--brand-orange);
    box-shadow: 0 0 0 3px var(--site-tint);
}
.site-form-error { font-size: 13px; color: #b91c1c; }
[data-bs-theme="dark"] .site-form-error { color: #f87171; }
.site-form-field input[aria-invalid="true"],
.site-form-field textarea[aria-invalid="true"] { border-color: #b91c1c; }
.site-form-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--site-s3);
    margin-top: var(--site-s3);
    flex-wrap: wrap;
}
.site-form-note { font-size: 12.5px; color: var(--brand-text-muted); line-height: 1.5; max-width: 40ch; }
.site-thanks {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--site-s2);
}
.site-thanks h3 { font-size: 22px; }

/* ---------- whatsapp band ---------- */

.site-wa-band { background: var(--site-wa); color: #ffffff; }
.site-wa-band .site-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--site-s4);
    padding-top: var(--site-s4);
    padding-bottom: var(--site-s4);
    flex-wrap: wrap;
}
.site-wa-title {
    font-family: var(--site-font-head);
    font-size: 21px;
    font-weight: 800;
    color: #ffffff;
}
.site-wa-sub { font-size: 15px; color: rgba(255, 255, 255, 0.82); margin-top: 2px; }
.site-wa-band .site-btn {
    background: var(--site-on-deep);
    color: var(--site-wa);
    min-height: 50px;
}
.site-wa-band .site-btn:hover { background: var(--site-on-deep); color: var(--site-wa); filter: brightness(0.95); }

/* ---------- footer ---------- */

.site-footer {
    background: var(--brand-navy);
    color: var(--site-on-deep-muted);
    padding-top: var(--site-s8);
}
.site-footer a { color: var(--site-on-deep-muted); }
.site-footer a:hover { color: var(--site-on-deep); text-decoration: none; }
.site-footer-cols {
    display: grid;
    grid-template-columns: 1.6fr 1fr 1fr 1.2fr;
    gap: var(--site-s6);
    padding-bottom: var(--site-s6);
}
.site-footer-h {
    font-family: var(--site-font-head);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--site-on-deep);
}
.site-footer-list { display: flex; flex-direction: column; gap: 11px; margin-top: var(--site-s2); font-size: 14.5px; }
/* WRAPS RATHER THAN SQUEEZES. A banner-shaped logo and a long agency name in
   one narrow footer column would otherwise share ~350px between them; wrapping
   costs nothing when they fit and is the difference between a two-line name
   and a four-line one when they do not. */
.site-footer-brand { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
/*
 * THE FOOTER MARK: BOUNDS ALWAYS, GROUND ONLY WHEN THE FILE NEEDS ONE.
 *
 * The footer is the agency's own accent - deep in BOTH themes, by the token
 * block's own design - and an uploaded logo is one file whose colours this
 * code never learns by reading a row. Midjourney's is a dark navy wordmark
 * with a gold mark, so on their own footer it rendered as the gold alone.
 *
 * A LIGHT PLATE IS NOT ENTAILED, WHICH IS WHAT THE FIRST VERSION OF THIS
 * COMMENT GOT WRONG. It argued that the same file is drawn in the site HEADER
 * on a white surface, so any usable logo is legible on white. The header
 * surface is `--brand-surface`: white in light and NEAR-BLACK in dark. A mark
 * an agency drew for dark chrome is perfectly legible there and 1.04:1 on this
 * plate - so plating unconditionally makes a near-white logo disappear, which
 * is worse than the low-contrast case it fixes, because a dark mark on a deep
 * field at least still shows its shape.
 *
 * SO `--plate` IS A SEPARATE RULE AND THE BLADE DECIDES. `LogoGround` compares
 * a white ground against the field itself for the ink in that file; the
 * alternative treatments are still rejected for the same reason as before -
 * `filter: invert()` repaints a company's mark into colours it does not own,
 * and a `brightness` lift turns a mid-tone brand into a wash.
 *
 * THE BOUNDS ARE UNCONDITIONAL, BECAUSE THEY ARE NOT PART OF THE DECISION.
 * Midjourney's logo is 411x122 and Hafiz G's is 640x818 - a banner and a stamp
 * - so a height cap alone makes the first 216px wide and eats the column, and a
 * width cap alone makes the second a strip four pixels tall. `object-fit:
 * contain` inside a box bounded on both axes is what fits either without
 * cropping either, and an unplated mark needs that exactly as much as a plated
 * one does.
 */
.site-footer-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
}
.site-footer-mark--plate {
    background: var(--site-on-deep);
    border-radius: 12px;
    padding: 8px 12px;
}
.site-footer-mark img {
    display: block;
    height: auto;
    width: auto;
    max-height: 48px;
    max-width: 168px;
    object-fit: contain;
}
.site-footer-brand-name { font-family: var(--site-font-head); font-size: 18px; font-weight: 800; color: var(--site-on-deep); }
.site-footer-blurb { font-size: 14.5px; line-height: 1.7; margin-top: var(--site-s2); max-width: 42ch; }
.site-social { display: flex; gap: 10px; margin-top: var(--site-s3); }
.site-social a {
    width: 42px;
    height: 42px;
    border-radius: 999px;
    background: var(--site-on-deep-fill);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--site-on-deep-muted);
}
.site-social a:hover { background: var(--site-on-deep-line); color: var(--site-on-deep); }
.site-social a.is-wa { background: var(--site-wa); color: #ffffff; }
.site-footer-legal {
    border-top: 1px solid var(--site-on-deep-line);
    padding: var(--site-s3) 0 var(--site-s4);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--site-s3);
    font-size: 13px;
    color: var(--site-on-deep-faint);
    flex-wrap: wrap;
}

/* ---------- inner pages wearing the site chrome ---------- */

.site-page-head { padding: var(--site-s6) 0 var(--site-s3); }
.site-page-head h1 { font-size: 34px; }

/* ---------- responsive ---------- */

@media (max-width: 1100px) {
    .site-grid--visa { grid-template-columns: 1fr 1fr; }
    .site-search-grid { grid-template-columns: 1fr 1fr 1fr; }
    .site-search-grid .site-btn { grid-column: 1 / -1; min-height: 50px; }
}

@media (max-width: 900px) {
    .site-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .site-about,
    .site-enquiry .site-inner { grid-template-columns: 1fr; gap: var(--site-s4); }
    .site-footer-cols { grid-template-columns: 1fr 1fr; gap: var(--site-s4); }
    .site-hero-grid { grid-template-columns: 1fr; gap: var(--site-s4); }
    .site-hero h1 { font-size: 42px; }
    .site-hero-panel { min-height: 340px; }
    .site-hotels { grid-template-columns: 1fr; }
    .site-hotel-feature { min-height: 300px; }
}

@media (max-width: 767px) {
    .site-inner { padding-left: var(--site-s2); padding-right: var(--site-s2); }
    .site-sec { padding: var(--site-s6) 0; }
    .site-sec--tight { padding: var(--site-s4) 0; }
    .site-h2 { font-size: 26px; }
    /* THE UTILITY BAR IS DESKTOP FURNITURE. On a 390px frame the address, the
       hours and the email stack into three rows above the logo and push the
       whole page down; all three are in the footer, and the approved phone
       design has no utility bar at all. */
    .site-topbar { display: none; }

    /* The pill keeps its mark and drops the number: at this width the digits
       are half the header. The number is still one tap away in the footer and
       in the enquiry block. */
    .site-header-actions .site-btn--wa { padding: 0; width: 46px; min-height: 46px; }
    .site-btn-label { display: none; }
    .site-header .site-inner { min-height: 68px; }
    .site-brand-mark { height: 36px; }
    .site-brand-name { font-size: 16px; }
    /* THE PLATE SCALES WITH THE REST OF THE PHONE CHROME, and that is the
       whole reason - the header mark drops 44px to 36px three lines above for
       the same one. It is NOT about running out of column: measured, the
       footer collapses to a SINGLE 342px track at this width, so the desktop
       bound would have fitted. A comment naming a mechanism it does not have
       is worse than none, and this one said the opposite until it was
       measured. */
    .site-footer-mark--plate { padding: 6px 9px; border-radius: 10px; }
    .site-footer-mark img { max-height: 40px; max-width: 130px; }

    .site-burger {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 46px;
        height: 46px;
        border-radius: 999px;
        background: var(--site-tint);
        color: var(--site-brand-ink);
        border: 0;
        cursor: pointer;
    }
    .site-nav {
        order: 3;
        width: 100%;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        padding-bottom: var(--site-s1);
    }
    .site-nav a {
        padding: 12px 4px;
        border-top: 1px solid var(--brand-border);
    }
    .site-header .site-inner { flex-wrap: wrap; }
    

    .site-hero-grid { padding-top: var(--site-s4); gap: var(--site-s3); }
    .site-hero h1 { font-size: 33px; max-width: none; }
    .site-hero-sub { font-size: 15.5px; }
    .site-hero-actions .site-btn { flex: 1 1 100%; }
    .site-hero-panel { min-height: 260px; border-radius: var(--site-r-card); }
    .site-hero-stamp { left: var(--site-s2); bottom: var(--site-s2); max-width: calc(100% - 2 * var(--site-s2)); padding: 10px 14px; }

    .site-search { margin-top: var(--site-s3); }
    .site-search-pane { padding: var(--site-s2); }
    .site-search-grid { grid-template-columns: 1fr 1fr; }
    /* NAMED, NEVER COUNTED. These were `:nth-child(1)`, `(2)` and `(5)`, which
       made the layout depend on the child order of the grid - so adding a
       hidden input or moving a field silently re-assigned which ones span the
       row. The three that need the full width say so on themselves. */
    .site-search-grid > .site-field--wide { grid-column: 1 / -1; }

    .site-trust { padding: var(--site-s3) 0 0; }
    .site-trust .site-inner { justify-content: flex-start; }
    .site-chip { font-size: 13px; padding: 8px 14px; }

    .site-grid--3,
    .site-grid--visa { grid-template-columns: 1fr; }
    .site-head-row { flex-direction: column; align-items: flex-start; gap: var(--site-s2); }

    .site-hotel-feature { min-height: 260px; }
    .site-hotel-feature .site-hotel-name { font-size: 22px; }
    .site-hotel-row { grid-template-columns: 76px 1fr; }
    .site-hotel-row-photo { width: 76px; height: 60px; }
    .site-hotel-row-price { grid-column: 2; text-align: left; }

    .site-cardfoot { flex-direction: column; align-items: stretch; gap: var(--site-s2); }
    .site-cardfoot .site-btn { width: 100%; }

    .site-form-grid { grid-template-columns: 1fr; }
    .site-form-card { padding: var(--site-s3); }
    .site-form-foot { flex-direction: column; align-items: stretch; }
    .site-form-foot .site-btn { width: 100%; }

    .site-enquiry h2 { font-size: 26px; }
    .site-wa-band .site-inner { flex-direction: column; align-items: flex-start; gap: var(--site-s2); }
    .site-wa-band .site-btn { width: 100%; }
    .site-footer-cols { grid-template-columns: 1fr; }
    .site-about-panel { min-height: 220px; }
}
