/*
 * Kept from the Blazor template: a live pair with the
 * <FocusOnNavigate Selector="h1"> in Components/Routes.razor. The landing has
 * no <h1>, but Components/Pages/Error.razor does, and on that page
 * FocusOnNavigate moves focus to it after navigation. Without this rule the
 * error heading would gain a visible focus ring it does not have today.
 */
h1:focus {
    outline: none;
}

/*
 * Anchor navigation offset for the sticky site header.
 * The header (Elementor element 33f7185b) is sticky on all devices, so anchor
 * targets must keep their top clear of it: 64px logo + 1% + 1% viewport-width
 * padding on desktop/tablet, ~70px min-height on mobile. Elementor 4.x performs
 * native (non-intercepted) anchor scrolling, so scroll-margin-top is honored.
 */
.elementor-menu-anchor,
#contacto {
    scroll-margin-top: calc(64px + 2vw + 8px);
}

@media (max-width: 767px) {
    .elementor-menu-anchor,
    #contacto {
        scroll-margin-top: 80px;
    }
}

/*
 * Language switcher flag.
 * Sprite geometry copied from wwwroot/lib/intl-tel-input/css/intlTelInput.min.css
 * (intl-tel-input 20.0.4): the sheet is not reused because it is only linked from
 * the home page, while the switcher renders in the header and footer of every page.
 * Only the two countries the site switches between are declared here.
 * .elementor-nav-menu a is already a flex container with align-items: center,
 * so the flag only needs to keep its intrinsic box.
 */
.lang-switch__flag {
    display: inline-block;
    flex: 0 0 auto;
    width: 20px;
    /* Vendor default height; each country modifier overrides it. Kept here so an
       unmapped country renders a visibly wrong flag instead of collapsing to 0px. */
    height: 15px;
    vertical-align: middle;
    background-image: url("/lib/intl-tel-input/img/flags.png");
    background-repeat: no-repeat;
    background-size: 5762px 15px;
    box-shadow: 0 0 1px 0 #888;
}

.lang-switch__flag--es {
    height: 14px;
    background-position: -1577px 0;
}

.lang-switch__flag--us {
    height: 11px;
    background-position: -5373px 0;
}

@media (min-resolution: 2x) {
    .lang-switch__flag {
        background-image: url("/lib/intl-tel-input/img/flags@2x.png");
    }
}

/*
 * BG-001 — Language switcher under forced colors.
 * Realizes the "Paso 6 y paso 10, agente de usuario en modo de colores forzados"
 * entry of DF-001 (docs/features/FT-003-localizacion/dataflows/DF-001-conmutar-a-ingles.md)
 * and DF-002 (.../DF-002-conmutar-a-espanol.md), section "Error paths".
 * In forced-colors mode Chromium and Edge discard background-image, so the sprite
 * flag of step 6 never paints. The accessible name travels in a span the vendor
 * hides by clipping, so the anchor ends up with NO visible content at all: it
 * keeps its href, stays focusable and still announces correctly, but is invisible.
 * This block reveals that accessible name as visible text, restoring the
 * information — which language the switcher offers — and not merely the presence
 * of the control.
 *
 * Scope: every selector is anchored on .lang-switch, the anchor emitted by
 * Components/Shared/LanguageSwitch.razor. That anchor is the same in the four
 * locations of step 5 (header main menu, header dropdown, footer main menu,
 * footer dropdown) and no selector here depends on a header, footer or dropdown
 * ancestor. The live DOM carries six, not four: the header container declares
 * "sticky":"top" in its data-settings (Components/Sections/SiteHeader.razor:6) and
 * Elementor Pro's sticky module (lib/elementor-pro/assets/lib/sticky/jquery.sticky.min.js)
 * clones the sticky element into a hidden spacer, duplicating the header's two
 * switchers. Being ancestor-independent, the fix reaches all four server-emitted
 * anchors and the two clones, and nothing else. .elementor-screen-only is
 * a vendor class the whole Elementor export uses; an unscoped override would
 * reveal every visually hidden text on the site under high contrast.
 *
 * Forbidden inside this block: color, background, border-color and
 * forced-color-adjust. The user agent must paint the label with the system
 * colors — that is what the terminal state of DF-001 / DF-002 under forced colors
 * requires. Also forbidden: !important; the cascade weight below is already
 * sufficient.
 *
 * Everything lives inside the @media, so outside forced colors the presentation
 * of steps 5 and 6 — sprite flag visible, label clipped, min-resolution: 2x
 * variant intact — is unchanged.
 */
@media (forced-colors: active) {
    /* The flag element keeps its 20px-wide box even with nothing to paint, and
       .elementor-nav-menu a is a flex container, so merely emptying the
       background would open an empty gap to the left of the revealed label.
       Take it out of the flow entirely. */
    .lang-switch .lang-switch__flag {
        display: none;
    }

    /* Undo the vendor clipping of .elementor-screen-only, declared in the frozen
       export at lib/elementor/assets/css/frontend.min.css (read-only) as
       height:1px; width:1px; margin:-1px; padding:0; overflow:hidden;
       position:absolute; top:-10000em; clip:rect(0,0,0,0).
       This selector wins twice over, without !important: it carries one class
       more than the vendor's single .elementor-screen-only, and app.css is linked
       after every vendor sheet in Components/App.razor. `top` needs no reset
       because static positioning makes it inert. */
    .lang-switch .elementor-screen-only {
        position: static;
        clip: auto;
        clip-path: none;
        width: auto;
        height: auto;
        overflow: visible;
        margin: 0;
        padding: 0;
        white-space: normal;
    }
}

/*
 * BL-005 (ADO #96 "Promesa Vive Galápagos", #100 "El Santuario") — open state of
 * the expandable feature boxes on touch devices.
 * Realizes step 5 of DF-003
 * (docs/features/FT-006-cajas-expandibles/dataflows/DF-003-expandir-caja-tactil.md).
 * Components/Sections/PageScripts.razor already toggles the `active` marker on
 * every .mi-card-hover when the user agent declares no pointer capability, but no
 * rule for the open state existed, so the marker appeared in the document and
 * nothing was revealed. This is that missing presentation rule; no new JavaScript
 * is involved, and PageScripts.razor is untouched.
 *
 * The rule lives here and not in the <style id="wp-custom-css"> block of
 * Components/App.razor because app.css is linked after it — the cascade is
 * therefore deterministic — and because wwwroot/css/ and wwwroot/lib/ are the
 * frozen Elementor export.
 *
 * The selector depends on no section ancestor, so it reaches the six boxes that
 * Components/Sections/PromiseSection.razor and Components/Sections/SanctuarySection.razor
 * emit (step 1 of DF-003).
 */

/*
 * Single open-state height bound, shared by the touch rule below and by the
 * :hover rule of the <style id="wp-custom-css"> block in Components/App.razor,
 * which reads this property with the previous literal as its fallback. Declared
 * once so the two bounds cannot diverge: DF-005 § Error paths records that a
 * divergence would reveal the same box at two different heights depending on the
 * device, and the hidden overflow of the base rule clips WITHOUT a scrollbar, so
 * the shorter of the two would silently truncate the text.
 *
 * Value fixed after sweeping the viewport from 320px to 1920px and measuring the
 * natural height of the text widget of all six boxes in both cultures.
 * Tallest measured: 422px — culture es, viewport 768px, box 9e25543, the third
 * box of Promesa Vive Galápagos ("Te invitamos a reconectar con la esencia...").
 * Tallest in en: 398px — viewport 768px, box 8077e33. Both cultures peak at the
 * 768px tablet width, where the three boxes are narrowest.
 * The previous literal of 400px was therefore already clipping the Spanish copy
 * of 9e25543 by one line on hover. 520px clears the worst case by 98px, which is
 * four lines at the 24px line height the boxes use.
 * Note when re-measuring: the three El Santuario boxes carry the marker only in
 * the elementor-hidden-desktop variant of SanctuarySection.razor, so they have no
 * layout above 1024px; the desktop variant of that section is a different set of
 * containers that do not collapse.
 */
.mi-card-hover {
    --mi-card-open-max-height: 520px;
}

/*
 * Open state. Exactly one marker more than the base rule
 * (.mi-card-hover .elementor-widget-text-editor) and no !important, so when
 * PageScripts.razor removes `active` the base rule takes the wheel again and the
 * box closes (DF-004 step 3 and its error path).
 * `transition` is deliberately absent: it is declared on the base rule in
 * App.razor and must animate both directions. Declaring it here would make the
 * collapse of DF-004 instantaneous (DF-003 step 6, DF-004 § Error paths).
 * The declaration set is exactly that of the :hover rule — max-height and opacity
 * and nothing else — so the same box reveals identically on both devices
 * (DF-005 § Error paths).
 */
.mi-card-hover.active .elementor-widget-text-editor {
    max-height: var(--mi-card-open-max-height);
    opacity: 1;
}
/*
 * BL-004 (ADO #84) — País de Residencia.
 * Realizes the presentation half of DF-030
 * (docs/features/FT-004-formulario-contacto/dataflows/DF-030-pais-de-residencia-establece-el-prefijo.md):
 * step 3 emits a native <select>, step 5 mounts a flag-bearing control over it.
 * The panel that control opens is DF-033 and DF-032, in the block further down.
 * The behaviour lives in Components/Sections/PageScripts.razor; nothing here
 * decides what travels in the submission.
 *
 * Everything below is anchored on the two country fields of the contact form —
 * residence and dial code — which get the SAME control: both enhanced, or both
 * native (FR-012, FR-013, DF-033 paso 2). Both paint a flag, in the rows and in
 * the trigger; the one thing that differs is the TEXT of the rows, and no rule in
 * this file decides it — each row copies its <option>, which the catalogue
 * composes with a dial code for one selector and without it for the other.
 * Nothing here is written twice for the second selector, and nothing here is
 * written per id except the one no-JavaScript rule below that cannot be: leaving
 * one of them out is how the two presentations would drift apart.
 *
 * The form exists only on the home page. That page is also the only one that links
 * wwwroot/lib/intl-tel-input/css/intlTelInput.min.css, so the sprite flag classes
 * (.iti__flag, .iti__{iso}) and the list geometry (.iti__country-list,
 * .iti__country, .iti__flag-box, .iti__country-name, .iti__highlight,
 * .iti__arrow) are already loaded and are REUSED here — none of
 * their geometry is transcribed (SOLUTION.md § Activos de bandera, § Banderas of
 * DF-030). The Conmutador de Idioma above keeps its own seven values because it
 * renders on pages where that sheet is absent; this control never does.
 *
 * The field box itself needs no rule at all: the frozen export already styles
 * .elementor-field-group .elementor-field:not(.elementor-select-wrapper) for this
 * exact form (wwwroot/css/post-2152.css, element 74d8b0e), so the <select> and
 * the toggle button inherit the same transparent background, 2px bottom border,
 * 11px radius, white text and Ubuntu face as every other field.
 */

/*
 * Native <select>s, JavaScript disabled (NFR-002).
 * The form paints white text on a dark photographic background; the option list,
 * however, is drawn by the user agent over its own light popup, where inherited
 * white would be invisible. This is the only rule the no-JavaScript path needs.
 *
 * BOTH dropdowns, and by id because that is the only handle they do not share
 * with the rest of the form: the two carry identical Elementor field classes, so
 * a class selector here would also repaint the option list of any other <select>
 * this form ever grows. They inherit the same white from the same place, so a
 * rule for one of them alone leaves the other with an unreadable list the moment
 * the enhancement does not run — which is the whole of FL-034.
 */
#form-field-field_618a0d1 option,
#form-field-field_a577223_dial option {
    color: #1f2124;
    background-color: #ffffff;
}

/*
 * Native <select>, enhancement mounted. One class for both selectors.
 * PageScripts.razor adds this class to a <select> ONLY after that selector's own
 * trigger is in the document, so a script that never runs — or that fails before
 * mounting — leaves both native dropdowns visible and fully operable. And the
 * mount is all or nothing, so this class never ends up on one of the two alone:
 * one enhanced and one raw, adjacent and over the same catalogue, is what
 * FR-012 / FR-013 forbid in binary terms.
 * display:none is deliberate and safe: a hidden form control is still submitted;
 * only `disabled` would drop it, and nothing here disables or removes the
 * element (DF-030 § Error paths, paso 5).
 */
.vg-country__native--hidden {
    display: none;
}

/*
 * The control wrapper. It is a direct child of the flex .elementor-field-group
 * and stands in for a full-width form field.
 *
 * It no longer carries the vendor's .iti--inline-dropdown modifier: the list
 * left this wrapper for the modal panel below, and that modifier exists only to
 * position .iti__dropdown-content absolutely against it and to cap
 * .iti__country-list at 185px — two declarations that would now fight the
 * panel's own measure. .iti stays for the vendor's `.iti *{box-sizing:border-box}`,
 * which the toggle's flag box relies on.
 */
.vg-country {
    display: block;
    flex-basis: 100%;
    width: 100%;
    max-width: 100%;
}

/*
 * The trigger wears the native form field's own classes, so the frozen export
 * gives it the same box as every other field of this form. What is declared
 * here is only the arrangement inside it: text to the leading edge, arrow
 * pinned to the trailing one.
 *
 * min-height is a floor, not a measure: the field box already measures more
 * than this at every width band, and the declaration is what keeps it a
 * conforming target if it ever stops (NFR-004, WCAG 2.2 SC 2.5.8).
 */
.vg-country__toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: 24px;
    text-align: start;
    cursor: pointer;
}

/* The name takes the slack so the arrow stays pinned to the trailing edge. */
.vg-country__name {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.vg-country__flag {
    flex: 0 0 auto;
}

/*
 * No country chosen yet — the trigger showing the invitation text — and the
 * "not declared" row of the list: NO flag box at all, not an empty one. A blank
 * 20x15 box beside the invitation reads as a defect, and the one row whose text
 * does not align with the rest is precisely what tells the visitor it is not a
 * country (FR-013, DF-030 § Banderas, DF-033 § Banderas y geometría).
 *
 * The restore is needed for the row and not for the trigger: `.iti__country`
 * declares display:flex with author weight on the row, and a user-agent
 * `[hidden]{display:none}` loses to any author rule. Nothing declares display
 * on the trigger's flag span, so there the user agent's own rule still holds —
 * it is stated for both so the pair cannot drift apart.
 */
.vg-country__flag[hidden],
.vg-country__option .iti__flag-box[hidden] {
    display: none;
}

/*
 * The vendor arrow hardcodes #555, which is unreadable on this form's dark
 * background. Colour only — the triangle geometry stays the vendor's.
 *
 * There is no `--up` counterpart any more: the trigger no longer unrolls a list
 * beneath itself, it opens a dialog, so the arrow has only one state.
 */
.vg-country__toggle .iti__arrow {
    flex: 0 0 auto;
    border-top-color: currentColor;
}

/* ===================================================================== *
 * The country panel, as a native modal dialog.
 * Realizes DF-033 steps 3 to 5 and step 7, and the terminal state of DF-032
 * (docs/features/FT-004-formulario-contacto/dataflows/DF-033-panel-de-pais-como-dialogo-modal.md,
 *  .../DF-032-acotar-el-catalogo-con-el-buscador.md).
 *
 * Components/Sections/ContactSection.razor serves one <dialog> per selector,
 * inert and outside the <form>; Components/Sections/PageScripts.razor fills the
 * list and opens it. What the user agent contributes once showModal() is
 * called, and this file therefore does NOT reproduce: the top layer — the panel
 * paints above the fixed site header with no z-index at play —, Escape,
 * inertness of the page behind and focus containment. Same mechanism the four
 * route maps already use further down.
 *
 * The measure is the only part written twice, by the arbitration of D1: below
 * the tablet band the panel takes the useful height edge to edge, because that
 * is where the defect is — 4.6 of 244 options on screen at 390px; above it a
 * centred dialog of bounded height, which is what a visitor arriving from a
 * <select> expects and what the reference control does on a desktop.
 * ===================================================================== */

/*
 * Tablet and desktop: a centred box. `position:fixed; inset:0; margin:auto` is
 * the user agent's own for `dialog:modal`, so the centring needs no rule — only
 * a width and a height for it to centre. The four user-agent declarations that
 * ARE wrong for this box (max-width and max-height capped at the viewport minus
 * chrome, a 1px border and 1em of padding) are undone explicitly, exactly as
 * the route-map dialogs undo them further down.
 *
 * The height is measured in dvh, not vh: `vh` is the viewport with the browser
 * chrome expanded, so on a phone the last rows land underneath it. See the note
 * on the mobile band below for the part CSS alone does not cover.
 */
dialog.vg-country-panel {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    width: min(28rem, calc(100vw - 2rem));
    height: min(32rem, calc(100dvh - 4rem));
    max-width: none;
    max-height: none;
    /* The panel's whole lateral measure, declared ONCE and here. Everything
       inside — heading, close button, search field, rows, empty state — is
       inset by this and restates none of it, so the four bands line up on both
       edges by construction instead of by four numbers agreeing. `box-sizing`
       above keeps it inside the 100% width/height the mobile rule sets, so the
       full-height panel stays full-height. */
    padding: 12px;
    border: 0;
    /* The 11px of every field of this form (post-2152.css, element 74d8b0e), so
       the panel reads as belonging to the control that opened it. */
    border-radius: 11px;
    overflow: hidden;
    background-color: #fff;
    color: #1f2124;
}

/*
 * A closed dialog is hidden by the user agent, and a user-agent declaration
 * loses to ANY author rule — here to the `display:flex` two rules up, which
 * would otherwise paint both panels unrolled over the landing. This is the same
 * failure the four route maps already had, corrected the same way and for the
 * same reason: the restore carries one attribute more than the rule it must
 * beat, so it cannot be the loser.
 */
dialog.vg-country-panel:not([open]) {
    display: none;
}

/*
 * The backdrop is painted HERE, and that is the difference with the route maps.
 * There the tint comes from the frozen post-{id}.css on the dialog itself and
 * the backdrop must stay transparent or the map sits under two dimmings; no
 * frozen sheet declares anything for this panel, so without this rule the form
 * behind would show through undimmed (DF-033 § Error paths, paso 3).
 */
dialog.vg-country-panel::backdrop {
    background-color: rgba(0, 0, 0, .55);
}

/*
 * Mobile band (NFR-003, up to 767px): the useful height, edge to edge.
 *
 * `100dvh` is the dynamic viewport — the window with the browser's retractable
 * chrome accounted for — and it is as far as CSS alone reaches. The on-screen
 * keyboard that the search field raises is a separate matter: with the default
 * `interactive-widget=resizes-visual` the layout viewport does not shrink for
 * it, so a keyboard tall enough can still cover the last rows. Changing that
 * would mean rewriting the viewport meta of Components/App.razor for the whole
 * landing, which is not this control's decision to take.
 */
@media (max-width: 767px) {
    dialog.vg-country-panel {
        inset: 0;
        width: 100%;
        height: 100dvh;
        margin: 0;
        border-radius: 0;
    }
}

/*
 * Scroll lock. Native <dialog> makes the page behind inert but leaves it
 * scrollable, so without this a wheel or a swipe drags the form away under the
 * panel and the visitor finds it somewhere else on closing. Expressed by the
 * state of the document rather than from a script, and released by the same
 * condition ceasing to hold — the same shape, and the same two declarations, as
 * the route-map rule further down.
 */
body:has(dialog.vg-country-panel[open]) {
    max-height: 100vh;
    overflow: hidden;
}

/* No lateral padding: the dialog's own is the panel's measure. Only the space
   down to the rule that separates the heading from the body is declared here. */
.vg-country-panel__header {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 0 12px;
    border-bottom: 1px solid #ccc;
}

.vg-country-panel__title {
    flex: 1 1 auto;
    margin: 0;
    font-size: 1.0625rem;
    line-height: 1.3;
}

/* 44px, well past the 24x24 floor of NFR-004 / WCAG 2.2 SC 2.5.8, because this
   is the one visible way out of the panel on a phone. */
.vg-country-panel__close {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background-color: transparent;
    color: inherit;
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
}

.vg-country-panel__close:hover,
.vg-country-panel__close:focus-visible {
    background-color: rgba(0, 0, 0, .06);
}

/*
 * The body is the flex column that makes the list the ONLY scrolling region:
 * min-height:0 is what lets it shrink below its content instead of pushing the
 * panel taller, which is what would otherwise put a second scrollbar on the
 * dialog and let the visitor drag the header instead of the list.
 */
.vg-country-panel__body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/*
 * The search field. 44px of height for the same reason as the close button: it
 * is the control the whole change exists for.
 *
 * 12px of horizontal padding: the panel's one lateral measure, declared on the
 * header, on this field, on the rows and on the empty state, so the title, the
 * term, the country names and the no-matches message all start on the same
 * vertical line and none of them touches the edge of the panel. See the note on
 * the rows for why the measure is repeated on each band instead of being put
 * once on their common parent.
 *
 * THE SELECTOR CARRIES THE DIALOG, and here it is load-bearing for FOUR of the
 * declarations below, not just the padding. `wwwroot/lib/hello-elementor/assets/css/reset.css`
 * declares
 *   input[type=text], … {border:1px solid #666; border-radius:3px; padding:.5rem 1rem; width:100%}
 * and `input[type=text]` is one class AND one attribute, so it outranks a bare
 * `.vg-country-panel__search` — cascade order does not come into it, and this
 * sheet loading later never helped. Measured before the qualifier was added:
 * padding 8px 16px, border 1px solid #666 on all four sides, radius 3px — i.e.
 * the field painted the reset's generic boxed input, and `border:0`,
 * `border-bottom`, `border-radius:0` and the padding below had never once
 * applied. Qualifying with `dialog.vg-country-panel` puts this rule at two
 * classes and an element and makes what it says true.
 */
dialog.vg-country-panel .vg-country-panel__search {
    flex: 0 0 auto;
    box-sizing: border-box;
    width: 100%;
    min-height: 44px;
    padding: 10px 12px;
    border: 0;
    border-bottom: 1px solid #ccc;
    border-radius: 0;
    background-color: #fff;
    color: inherit;
    font: inherit;
}

.vg-country-panel__search:focus-visible {
    outline: 2px solid #11547e;
    outline-offset: -2px;
}

/*
 * THE LIST DOES NOT SCROLL. This is a deliberate product decision, not an
 * oversight, and it is the whole reason the search field exists: what does not
 * fit is clipped, and the way to reach a country past the fold is to type. A
 * scrolling list of 245 rows invites dragging through them, which on a phone is
 * the worst way to answer this question and is exactly the friction FL-036 was
 * opened to remove.
 *
 * `hidden` overrides the vendor's `overflow-y:scroll` on `.iti__country-list`,
 * which would otherwise reserve a scrollbar gutter AT ALL TIMES — a dead bar
 * beside a list that cannot move. Nothing else of the vendor rule is
 * transcribed: overflow is the one thing overridden.
 *
 * KEYBOARD NAVIGATION STILL REACHES EVERY ROW, and that is not a contradiction.
 * `overflow:hidden` suppresses scrolling by user gesture, but the box stays
 * programmatically scrollable, so the `scrollTop` writes in setActive() keep
 * bringing the active option into view as the visitor arrows down. Losing that
 * would strand aria-activedescendant on a clipped row with nothing visible
 * moving, which is the NFR-004 failure this file already guards against for the
 * highlight colour. Do not "simplify" this to `clip`: `overflow:clip` makes the
 * box unscrollable by ANY means, including scrollTop, and would break it.
 *
 * THE SELECTOR CARRIES THE DIALOG ON PURPOSE, and it is not decoration.
 * `.vg-country-panel__list` alone ties with `.iti__country-list` at one class
 * each, and intlTelInput.min.css is linked from Components/Sections/PageScripts.razor
 * in the BODY while this sheet is linked from the <head> — so on a tie the
 * vendor is the later rule and wins. Qualifying with `dialog.vg-country-panel`
 * puts this rule ahead on specificity, where cascade order cannot reach it.
 */
dialog.vg-country-panel .vg-country-panel__list {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

/*
 * The empty state (DF-032 paso 8). Without it the visitor who mistypes sees a
 * blank panel and cannot tell "no matches" from "the control is broken".
 *
 * It takes the growth the list gives up. PageScripts.razor hides the <ul> in the
 * same write that reveals this message — the substitution DF-032 paso 8 asks
 * for — so the list stops claiming the column's free space and this is what
 * would otherwise be left sitting on whichever edge the leftover flexes onto.
 * Growing it instead makes it the region below the search field, and the text
 * starts at its top edge, immediately under the term that produced it (DT-033).
 */
.vg-country-panel__empty {
    flex: 1 1 auto;
    margin: 0;
    /* Block only: the lateral measure is the dialog's. The 8px matches the rows
       so the message starts where their text does. */
    padding: 16px 8px;
    color: #5a5f66;
}

/*
 * Rows. The layout, the 20px flag box and the vertical padding are the vendor's
 * `.iti__country` / `.iti__flag-box` / `.iti__country-name`, which this page
 * already loads and which the row wears by class; min-height is the 24x24 CSS px
 * floor of NFR-004 / WCAG 2.2 SC 2.5.8 — a list of 244 entries squeezed so more
 * of them fit is exactly where that gets broken.
 */
.vg-country__option {
    color: #1f2124;
    cursor: pointer;
    min-height: 24px;
}

/*
 * Rows sit flush inside the dialog's padding, so the highlight band of the
 * active row spans the panel's full measure instead of floating in a second
 * inset column. The 8px is breathing room between the band's edge and the flag,
 * not a lateral measure — that one is the dialog's and is declared once.
 *
 * `padding-inline` AND NOT `padding`, which is the whole point: the vendor's
 * `.iti__country{padding:8px 8px}` is what gives every row its 40px of height,
 * and 40px is this control's tap target — well past the 24px floor of NFR-004 /
 * WCAG 2.2 SC 2.5.8, on a list of 245 entries meant to be used with a thumb.
 * Writing the shorthand here would take the block padding with it and shrink
 * every row to its text; only the inline axis is being restated.
 *
 * The selector carries the list for the same cascade reason as the overflow rule
 * above: `.vg-country__option` alone ties with the vendor's `.iti__country`, and
 * the vendor sheet is the later one.
 */
.vg-country-panel__list .vg-country__option {
    padding-inline: 8px;
}

/*
 * A row the search term excluded (DF-032 paso 6). It stays in the document, so
 * the id aria-activedescendant points at never dangles and nothing has to be
 * rebuilt when the term is cleared — but display:none is what takes it out of
 * the keyboard walk AND out of the pointer's reach at the same time. Hiding it
 * visually alone would let a swipe land on a country the visitor cannot see.
 *
 * The restore is required, not belt-and-braces: `.iti__country{display:flex}`
 * is an author rule, and the user agent's `[hidden]{display:none}` loses to any
 * author rule. Without this the filter would hide nothing at all.
 */
.vg-country__option[hidden] {
    display: none;
}

.vg-country__option[aria-selected="true"] {
    font-weight: 600;
}

/*
 * Keyboard position (NFR-004). The vendor's rgba(0,0,0,.05) is too faint to
 * follow while arrowing through 244 entries, so the same marker class is given
 * the form's own blue at a contrast that reads without becoming a second
 * selection state.
 *
 * QUALIFIED ON THE DIALOG, AND THAT IS LOAD-BEARING. The vendor declares
 * `.iti__country.iti__highlight{background-color:rgba(0,0,0,.05)}` in
 * wwwroot/lib/intl-tel-input/css/intlTelInput.min.css, which is (0,2,0) — the
 * SAME specificity this rule would carry without the `dialog` qualifier. Ties
 * are broken by document order, and that order does NOT favour us: app.css is
 * the last sheet of the <head>, but the vendor sheet is linked from the BODY,
 * by Components/Sections/PageScripts.razor, so it loads AFTER and wins. Until
 * this qualifier existed the rule below never applied once and the keyboard
 * position painted the vendor's faint grey — the exact contrast NFR-004 exists
 * to prevent, in the one place a visitor arrows through 244 entries.
 * Same trap as the search field and the list: a rule that reads as if it were
 * in force, and is not.
 */
dialog.vg-country-panel .vg-country__option.iti__highlight {
    background-color: rgba(17, 84, 126, .16);
}

/*
 * DT-020 — keyboard position under forced colors.
 * This is the third flag-bearing surface of the site and the only one that had no
 * forced-colors treatment. Losing the sprite flag here costs nothing: the country
 * name travels in the sibling .vg-country__name span, which is real text and
 * survives. What does not survive is the rule above — the user agent discards
 * author background-color in forced-colors mode, and that background is the ONLY
 * visible indicator of where aria-activedescendant sits among the 244 entries. A
 * high-contrast user arrowing through the list would see nothing move.
 *
 * The two system colors below are the pair the user agent itself uses for a
 * selected list item, so the marker keeps painting in whatever palette the user
 * chose. Both are required: setting Highlight alone would leave the option's own
 * #1f2124 text on it, and the two are not guaranteed to contrast.
 *
 * NOT forced-color-adjust: none. The BG-001 block above forbids it for this file,
 * and the reason applies here in full — it would opt the option row out of the
 * user's contrast choices instead of expressing the marker inside them.
 *
 * No !important, but NOT for the reason this comment used to give. It claimed the
 * selector "already carries the same weight as the rule it overrides and appears
 * after it", and the second half was simply false: the vendor sheet is linked from
 * the body by PageScripts.razor and therefore loads AFTER app.css, so an equal-weight
 * selector loses the tie. The `dialog` qualifier is what wins it — here for the same
 * reason as in the base rule above, and it must not be removed from either.
 */
@media (forced-colors: active) {
    dialog.vg-country-panel .vg-country__option.iti__highlight {
        background-color: Highlight;
        color: HighlightText;
    }
}

/* ===================================================================== *
 * BL-011 — what the Elementor Pro runtime used to contribute.
 * Each block below replaces a behaviour that lived in the Pro JavaScript
 * bundles and had no CSS expression at all. wwwroot/css/ and wwwroot/lib/ are
 * the frozen export and keep loading untouched; everything the removal cost is
 * paid for here, in the only stylesheet this project owns.
 * ===================================================================== */

/*
 * Sticky site header (SiteHeader.razor:6 declares "sticky":"top").
 *
 * Pro's sticky module produced this exact rendering at runtime: it wrote
 * `position: fixed; top: 0; width: <viewport>px` inline on the header container
 * and left an absolutely positioned, visibility:hidden clone of it behind — the
 * "spacer" that BL-001 recorded as the reason the live DOM carried 6 language
 * switchers instead of the 4 the server emits. The clone contributed NOTHING to
 * layout: being absolute it never occupied flow, and <main> already began at
 * y=0 with the header overlaying it, exactly as post-35.css describes.
 *
 * So the whole of the module's visible effect is one keyword. Only the custom
 * property is overridden — frontend.min.css resolves `.e-con{position:var(--position)}`
 * — which leaves top, left, width and z-index to the frozen sheet and keeps this
 * rule to the single thing that changed. Geometry is therefore identical to the
 * pre-BL-011 live page, and the switcher count drops from 6 to the 4 of
 * DF-001 / DF-002.
 *
 * NOT `position: sticky`: a sticky element is pinned only within its parent's
 * box, and this container is the sole child of <header>, so its sticky range
 * would be zero and it would scroll away on the first pixel. Making <header>
 * itself sticky would work, but only by putting it back in flow — which would
 * push <main> down by the header's height and change the design.
 */
.elementor-35 .elementor-element.elementor-element-33f7185b {
    --position: fixed;
}

/*
 * Mobile navigation panel, stretched (SiteHeader.razor:11 declares
 * "full_width":"stretch").
 *
 * widget-nav-menu.min.css gives the open panel `position:absolute` and nothing
 * else — no offsets. Pro's `stretchElement` supplied the rest at runtime as
 * inline left/width/top. Without it the panel keeps the width of its own widget
 * box, which on a phone is the ~138px column the burger sits in.
 *
 * The two rules are one mechanism. Neutralising the widget's own
 * `position:relative` (declared by .elementor-widget in frontend.min.css) hands
 * the panel's containing block to the header container, which is the fixed,
 * full-width box above — so `left:0; right:0` spans the viewport (an absolutely
 * positioned box resolves against the PADDING box of its container, so the
 * header's 8% side padding is included, not subtracted) and `top:100%` lands it
 * on the header's lower edge without a measurement anywhere.
 *
 * Confined to the mobile breakpoint, which is the only width where the panel
 * exists: above 767px widget-nav-menu.min.css sets it to display:none.
 * The widget carries no absolutely positioned descendant of its own — the
 * underline pointers resolve against `.elementor-nav-menu a`, which that same
 * sheet declares position:relative — so nothing else moves with it.
 */
@media (max-width: 767px) {
    .elementor-widget-nav-menu.elementor-nav-menu--stretch {
        position: static;
    }

    .elementor-nav-menu--stretch .elementor-nav-menu__container.elementor-nav-menu--dropdown {
        top: 100%;
        left: 0;
        right: 0;
        width: auto;
    }
}

/*
 * The four route-map popups, as native modal dialogs.
 * Components/Sections/PagePopups.razor emits one <dialog> per map wearing the
 * id and classes Pro's popup module used to assign at runtime, so the frozen
 * wwwroot/css/post-{id}.css keeps styling them through
 * #elementor-popup-modal-{id}, .dialog-widget-content and .dialog-message —
 * overlay tint, per-breakpoint measure, black backing and glow, all unchanged.
 *
 * What is declared here is only what the runtime used to fetch and no frozen
 * sheet ever provided. lib/elementor/assets/css/conditionals/dialog.min.css was
 * demand-loaded by the AssetsLoader of the core bundle; with that bundle gone
 * nothing requests it, and its `.dialog-type-lightbox` rule — the full-viewport
 * fixed box the overlay is painted on — would silently vanish. Those four
 * declarations are reproduced below, on the element that now plays that part.
 */
dialog.elementor-popup-modal {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    /* The user agent sizes a dialog to fit its content and caps it at
       calc(100% - 6px - 2em), and draws a border and 1em of padding around it.
       All four are wrong for a full-bleed overlay and all four must be undone
       explicitly: they are user-agent declarations on the element itself, which
       no frozen rule contradicts. */
    max-width: 100%;
    max-height: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    overflow: hidden;
}

/*
 * A closed dialog is hidden by the user agent, and a user-agent declaration
 * loses to ANY author rule — including `.elementor-popup-modal.dialog-type-lightbox
 * {display:flex}` in popup.min.css, which would otherwise paint all four maps
 * stacked on the landing. This restores it with author weight, and carries one
 * class more than that rule so it cannot be the loser.
 */
dialog.elementor-popup-modal:not([open]) {
    display: none;
}

/*
 * The overlay tint is painted by the dialog itself (post-{id}.css sets the
 * background-color on #elementor-popup-modal-{id}), so the user agent's own
 * backdrop must add nothing or the map would sit under two dimmings instead of
 * the one the design specifies.
 */
dialog.elementor-popup-modal::backdrop {
    background: transparent;
}

/*
 * The popup documents are served hidden — popup.min.css declares
 * `[data-elementor-type=popup]:not(.elementor-edit-area){display:none}` and the
 * Pro module was the only thing that ever revealed one. Being open is now the
 * whole condition, and it is expressed where it is true: on the dialog.
 */
dialog[open] [data-elementor-type="popup"] {
    display: block;
}

/*
 * Scroll lock. dialog.min.js put `.dialog-prevent-scroll` on <body> for as long
 * as a popup was open; these are that class's two declarations, applied by the
 * state of the document instead of by a script. Native <dialog> makes the page
 * behind inert but leaves it scrollable, so without this the map would drift
 * away under a stray wheel or swipe.
 */
body:has(dialog.elementor-popup-modal[open]) {
    max-height: 100vh;
    overflow: hidden;
}

/*
 * BG-011 — the close control of the four route maps. DF-034 steps 2, 3 and 4,
 * and DF-035 step 4. The markup is in Components/Sections/PagePopups.razor,
 * which carries the reasoning for its SHAPE; what follows is why it sits where
 * it sits and why it measures what it measures.
 *
 * OUT OF THE FLEX FLOW, AND THAT IS THE FIRST THING THIS RULE DOES.
 * popup.min.css hangs `display:flex` off `.elementor-popup-modal.dialog-type-lightbox`,
 * so a direct child left IN flow would be one more flex item and would displace
 * the map wrapper — the defect would be fixed and the geometry of the map broken
 * in both ranges, and the fidelity sweep would then report the whole map as the
 * divergence instead of the new control (DF-034 § Error paths, step 3).
 * Absolutely positioned, the map's boxes do not move at all.
 *
 * ANCHORED TO THE WINDOW BOX, NOT TO THE MAP. The rule above already restores
 * `position:fixed; inset:0; width:100%; height:100%` on the dialog, so the
 * dialog IS the visible window and its top-right corner is always on screen,
 * whatever composition the map presents. Anchored to the image instead, at
 * 390px the vertical composition measures 390x693 inside an 844px dialog and
 * pushes the control out of the visible area — the defect reappearing exactly
 * where it was reported (DF-034 § Por qué se ancla al diálogo).
 *
 * z-index: 1, AND IT IS THE MINIMUM THAT BEATS `auto`, NOT A ROUND NUMBER
 * PICKED TO WIN. Document order alone does not settle this. The form is the
 * FIRST child of the dialog — for the focus reason recorded in
 * Components/Sections/PagePopups.razor — and the map that follows it is wrapped
 * in `div.elementor-element` boxes that the export leaves `position:relative`.
 * They are therefore POSITIONED siblings of this form, and among positioned
 * boxes that all read `z-index:auto` the painting order is the document order:
 * the map comes later, so the map paints on top. Measured over the four maps at
 * thirteen widths, that covered the control at 480 and 600 on the two vertical
 * maps and at 1180 on the two horizontal ones — the widths where the image
 * reaches the top-right corner — and left it visible everywhere else, which is
 * why a sweep of 390 and 1440 alone reported everything correct.
 *
 * Focus order and painting order are two different orders and here they must
 * run in opposite directions: the control has to be the FIRST thing focused and
 * the LAST thing painted. Its position in the document settles the first; this
 * number settles the second, and it is the case `z-index` exists for. One is
 * enough and one is the ceiling: the boxes that cover it live in the same
 * stacking context as this form and read `auto`, and 1 is the smallest integer
 * above `auto`. Nothing larger buys anything, and writing something larger
 * would be a claim about a competitor that does not exist. Nor is this the
 * z-index race the native <dialog> was chosen to end — that one is this control
 * against the REST of the page, and the top layer still settles it without a
 * number; this is the control against its own siblings INSIDE the dialog.
 *
 * The <form> is the positioned box and it hugs the button exactly, so it adds
 * no dead surface around it: every pixel of this box is the button, and none of
 * it is a press that lands on neither path.
 */
dialog.elementor-popup-modal .vg-map-close {
    position: absolute;
    z-index: 1;
    top: 8px;
    right: 8px;
    display: flex;
    margin: 0;
}

/*
 * 44x44, NOT the 24x24 floor. NFR-004 imposes 24 on any target and 44 on the
 * one visible way out of a surface that covers the page, which is what this is.
 * It is the same bar the country panel's close control already meets
 * (DF-033 § El listón del control de cierre); diverging from it would be the
 * sign that the bar was applied out of habit rather than for a reason.
 *
 * A BACKGROUND OF ITS OWN, not a contrast computed against the map. A map is an
 * image of varying tone: a colour picked to read over the sea disappears over
 * the land. The opaque disc is what makes the reading independent of where the
 * control happens to fall, and the hairline ring is what keeps its EDGE visible
 * over the pale parts of a map.
 *
 * The selector carries `dialog.elementor-popup-modal` because
 * `wwwroot/lib/hello-elementor/assets/css/reset.css` styles bare `button` and
 * `[type=submit]` — border, radius, padding and a #c36 hover — and those reach
 * one class of specificity on the pseudo-classes. Two classes and an element
 * put this rule and its states above them without a single `!important`.
 */
dialog.elementor-popup-modal .vg-map-close__button {
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background-color: #fff;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .25);
    color: #1f2124;
    font-size: 1.75rem;
    line-height: 1;
    cursor: pointer;
}

dialog.elementor-popup-modal .vg-map-close__button:hover {
    background-color: #e9e9e9;
    color: #1f2124;
}

/*
 * The focus indicator, and it is `:focus-visible` and not `:focus` on purpose.
 * With the control inside the dialog, the initial focus of the modal opening
 * lands ON IT — it is the only focusable element the dialog contains, because
 * its content is an image (DF-035 step 3). Declared for plain `:focus`, opening
 * a map with the mouse would paint a ring nobody asked for; declared for
 * keyboard focus, it appears only for whoever needs it.
 *
 * Drawn INSIDE, over the control's own background rather than against the map:
 * a ring painted on the image would be as variable as the image
 * (DF-035 § Error paths, step 4). A negative offset is what puts it there, and
 * the outline follows the border radius, so it reads as a ring inside the disc.
 */
dialog.elementor-popup-modal .vg-map-close__button:focus-visible {
    outline: 3px solid #11547e;
    outline-offset: -3px;
}

/* ===================================================================== *
 * BL-011 — what the Elementor core runtime used to contribute.
 * ===================================================================== */

/*
 * BG-010 — the two numbers of the photo carousel of El Santuario (widget
 * 068161a), one pair per Elementor breakpoint. They are declared side by side,
 * and not as three duplicated rule blocks, because the second is DERIVED from
 * the first: changing one without the other breaks the loop. Same reasoning as
 * --mi-card-open-max-height further up — declared once so the two cannot
 * diverge.
 *
 * SLIDES ACROSS. widget-image-carousel.min.css caps every slide at
 * `100% / var(--e-image-carousel-slides-to-show, 3)`, and post-17.css sets that
 * variable to 5 with no per-breakpoint variant — because the widget's
 * `data-settings` only ever declared `slides_to_show: 5`, and Elementor emits a
 * variant only for a breakpoint the editor was given a value for. The other two
 * values came from Swiper: faced with a missing per-breakpoint setting Elementor
 * does NOT inherit the desktop one, it falls back to its own defaults — 2 on
 * tablet, 1 on mobile — and Swiper wrote the result as an inline width on every
 * slide. BL-011 removed that runtime, leaving the variable as the only surviving
 * source of the measure, and it read 5 at every width: a 390px phone showed five
 * 78px photos. The ladder below is that fallback, moved out of the runtime and
 * into the sheet. Nothing here is invented, and `data-settings` is left alone —
 * it is the record of what the original design said, not a place to correct it.
 *
 * DRIFT. SanctuarySection.razor emits the eight photos twice, so the sixteen
 * slides measure `(16 / slides-across) x 100%` of the wrapper — a percentage in
 * translateX resolves against the element's own border box, and swiper.min.css
 * declares the wrapper width:100%. Travelling half of that lands the ninth slide
 * exactly where the first began, so the restart is invisible. The distance is
 * therefore `(8 / slides-across) x 100%`: 800% across one photo, 400% across
 * two, 160% across five. Change the number of photos, or a slides-across value,
 * and its neighbour on the next line changes with it.
 *
 * The 40s of the animation below does NOT change on any breakpoint, and is
 * deliberately left as a constant there rather than repeated here: it is the
 * same eight photos crossing the screen at five seconds each — `autoplay_speed:
 * 0` with `speed: 5000` — whether one of them is visible at a time or five.
 * Scaling the duration per breakpoint is the natural mistake here and would make
 * the phone and the desktop run the same strip at different speeds, which no
 * setting in the export ever asked for.
 *
 * Elementor's breakpoints: mobile up to 767px, tablet 768-1024px, desktop from
 * 1025px. Mobile is the unqualified case, so the ladder also covers a viewport
 * narrower than any query, and it overrides post-17.css by cascade order at
 * equal specificity — which is why the selector is that sheet's own, verbatim.
 */
.elementor-17 .elementor-element.elementor-element-068161a {
    --e-image-carousel-slides-to-show: 1;
    --vg-carousel-drift-distance: -800%;
}

@media (min-width: 768px) and (max-width: 1024px) {
    .elementor-17 .elementor-element.elementor-element-068161a {
        --e-image-carousel-slides-to-show: 2;
        --vg-carousel-drift-distance: -400%;
    }
}

@media (min-width: 1025px) {
    .elementor-17 .elementor-element.elementor-element-068161a {
        --e-image-carousel-slides-to-show: 5;
        --vg-carousel-drift-distance: -160%;
    }
}

/*
 * The carousel as a CSS marquee.
 *
 * Swiper drove it with navigation:none, pagination none, autoplay_speed:0 and
 * speed:5000 — one slide every five seconds, no pause, looping for ever, and
 * no API call anywhere on the page. A constant leftward drift is therefore the
 * whole of what it did, and 8 slides x 5s is where the 40s comes from — the one
 * number that is the same on every breakpoint.
 *
 * The distance is READ from the property declared above, never written here, so
 * it cannot fall out of step with the slides-across value it is derived from.
 * Custom properties are substituted at computed-value time, so the var() inside
 * @keyframes resolves against the animated element — a descendant of the widget
 * the ladder is anchored on — and picks up the breakpoint's value. Measured at
 * 390, 768 and 1440px, not assumed.
 *
 * The clipping is the frozen sheet's own — swiper.min.css declares
 * `.swiper{overflow:hidden}`, which is what used to hide the slides past the
 * visible window in the pre-init state and now hides everything outside it.
 */
.elementor-widget-image-carousel .elementor-image-carousel.swiper-wrapper {
    animation: vg-carousel-drift 40s linear infinite;
}

@keyframes vg-carousel-drift {
    from { transform: translateX(0); }
    to { transform: translateX(var(--vg-carousel-drift-distance)); }
}

/*
 * A photo the visitor is pointing at, or a slide they have tabbed into, stops
 * sliding out from under them. :focus-within is the keyboard half of the same
 * rule and is what keeps the strip usable without a pointer.
 */
.elementor-widget-image-carousel .elementor-image-carousel-wrapper:hover .elementor-image-carousel.swiper-wrapper,
.elementor-widget-image-carousel .elementor-image-carousel-wrapper:focus-within .elementor-image-carousel.swiper-wrapper {
    animation-play-state: paused;
}

/*
 * Reduced motion. Stopping the animation alone would strand every photo past
 * the visible window behind the clip — three of the eight on desktop, seven of
 * them on a phone now that the ladder above puts one across — so the strip
 * becomes scrollable instead: the same eight, reachable by wheel, swipe, or
 * keyboard, in the visitor's own time.
 * The duplicate track is dropped here: it is scaffolding for a seamless loop
 * that is no longer running, and leaving it would offer the same eight photos
 * twice.
 */
@media (prefers-reduced-motion: reduce) {
    .elementor-widget-image-carousel .elementor-image-carousel.swiper-wrapper {
        animation: none;
    }

    .elementor-widget-image-carousel .vg-carousel__clone {
        display: none;
    }

    .elementor-widget-image-carousel .elementor-image-carousel-wrapper.swiper {
        overflow-x: auto;
        overflow-y: hidden;
        scroll-snap-type: x mandatory;
    }

    .elementor-widget-image-carousel .swiper-slide {
        scroll-snap-align: start;
    }
}

/*
 * BG-009 — the three background films, and the box the frozen sheet never
 * declared.
 *
 * frontend.min.css gives `.elementor .elementor-background-video-hosted`
 * position:absolute, inset-block-start:50%, inset-inline-start:50%,
 * transform:translate(-50%,-50%) and object-fit:cover — placement, centring
 * and cropping, and NOT ONE DIMENSION. The size came from somewhere else:
 * Elementor core's BackgroundVideo handler measured the container and wrote
 * width and height INLINE on the element at runtime. BL-011 removed that
 * bundle, and with it the only source of size the element ever had.
 *
 * object-fit:cover does not stand in for it. Cover crops WITHIN the element's
 * box, and the box is precisely what went missing, so the film fell back to its
 * intrinsic 16:9 ratio scaled to the available width — its height governed by
 * the viewport while the hero's is not. Measured before this rule: 34px short
 * of an 844px-tall hero at 1440px, and 26% of that same height at 390px, where
 * the hero drew as a band of video with the rest of it empty. The failure is
 * silent in all three channels — it builds, it logs nothing, the film downloads
 * and plays — and it gets worse the narrower the window.
 *
 * The box is declared RELATIVE, and that is the whole of the fix. The removed
 * handler computed 1500.44px of width: the width needed to cover a 1440x844
 * container at 16:9. That number is true for that container at that one
 * viewport width and false at every other. A box of 100% x 100% hands the same
 * arithmetic back to `cover`, which resolves it natively at any resolution and
 * in all three width bands of NFR-003. Reproduce what the runtime DID, never
 * the number it WROTE — a literal left behind by a script that no longer runs
 * has nobody to resynchronise it. Same reasoning as the sticky header, the
 * stretched mobile panel, the four dialogs and the Santuario carousel above.
 *
 * The frozen centring stays correct on a full-size box, and this is the point
 * where a later reader will hesitate. The element is still absolutely
 * positioned with its block-start and inline-start edges at 50% of its
 * containing block, then pulled back half its own size by
 * translate(-50%,-50%). When the box matches the container, half the box IS
 * half the container: the element retreats exactly to the origin and its four
 * edges land on the container's. The centring becomes inert, not wrong — and it
 * stays, because the frozen sheet is not edited. The containing block is
 * `.elementor-background-video-container`, which the same sheet declares
 * position:absolute with inset:0, so 100% resolves to the section container in
 * both axes.
 *
 * Scope is the class, not one hero. The site serves three background films and
 * all three lost the same source of size: container 63b4eb9
 * (Components/Sections/HeroSection.razor, /media/videoportada.mp4), 1a360d6
 * (Components/Sections/PromiseSection.razor, /media/tortugabay-1.mp4) and
 * 78ecd75 (Components/Sections/CommitmentSection.razor,
 * /media/playagarrapatero_1.mp4). The two nobody reported measured worse than
 * the one that was. The selector is the frozen sheet's own, so the box is
 * declared where everything else about this element already is. No !important:
 * no frozen rule declares width or height on any background video element at
 * any specificity, and app.css is linked last in Components/App.razor.
 *
 * Realizes step 9 of DF-011
 * (docs/features/FT-001-landing-una-pagina/dataflows/DF-011-composicion-de-la-landing-espanol.md)
 * and step 7 of DF-012 (.../DF-012-composicion-de-la-landing-ingles.md).
 * See DF-011 § El vídeo que no traía su caja.
 */
.elementor .elementor-background-video-hosted {
    width: 100%;
    height: 100%;
}
