/* MPHB Availability Calendar — frontend styles */

.mphbac-root {
    --mphbac-color-available: #7BDCB5;
    --mphbac-color-booked: #FB6962;
    --mphbac-color-past: #bdc3c7;
    --mphbac-color-header: #0A50B2;
    --mphbac-color-namecol: #F8F9FA;
    --mphbac-color-namecol-alt: #F1F3F5;
    --mphbac-color-namecol-text: #111111;
    --mphbac-color-frame: #e0e0e0;
    --mphbac-color-nav-bg: #C43A3A;
    --mphbac-color-nav-text: #FFFFFF;
    --mphbac-color-nav-hover: #078732;
    --mphbac-color-legend-text: #111111;
    --mphbac-color-today-outline: #f4da62;
    --mphbac-color-text: #000000;
    --mphbac-color-bg: #fdfdfd;
    --mphbac-font-size: 14px;
    --mphbac-days: 7;
    --mphbac-cell-min: 38px;
    --mphbac-header-min: 38px;
    --mphbac-label-width: 180px;
    --mphbac-radius: 4px;
    --mphbac-gap: 2px;
    --mphbac-info-prerender-width: 720px;

    position: relative;
    box-sizing: border-box;
    width: 100%;
    color: var(--mphbac-color-text);
    background: var(--mphbac-color-bg);
    font-size: var(--mphbac-font-size);
    line-height: 1.3;
}

.mphbac-root *,
.mphbac-root *::before,
.mphbac-root *::after {
    box-sizing: inherit;
}

.mphbac-inherit-theme {
    --mphbac-color-text: var(--e-global-color-text, currentColor);
    --mphbac-color-bg: var(--e-global-color-bg, transparent);
    --mphbac-color-today-outline: var(--e-global-color-primary, #0f6dbf);
    font-family: var(--e-global-typography-text-font-family, inherit);
}

.mphbac-heading {
    margin: 0 0 0.75em;
    font-size: 1.4em;
    font-weight: 600;
    text-align: center;
}

/* Filters — centered as a group */
.mphbac-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5em 0.75em;
    align-items: flex-end;
    justify-content: center;
    margin-bottom: 0.75em;
}

.mphbac-filter {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25em;
    font-size: 0.9em;
}

.mphbac-filter-actions {
    display: flex;
    justify-content: center;
    gap: 0.5em;
}

/* Mobile: stack each filter element on its own full-width row, centered */
@media (max-width: 600px) {
    .mphbac-filters {
        flex-direction: column;
        align-items: center;
    }
    .mphbac-filter,
    .mphbac-filter-actions {
        width: 100%;
    }
    /* Cottage column collapses to just the #number on phones — the
       truncated name above it was forcing rows ~30% taller than the
       configured --mphbac-cell-min, which in turn forced every day cell
       on the same row to be taller and narrower. Guests who need to
       know "what is #22?" tap the cell → the cottage info popup opens
       with the full cottage record. Scoped with :has() so a cottage
       whose post title doesn't match the "Cottage NN:" pattern (no
       parsed number) keeps its abbrev visible — never blank cells.
       Custom-label overrides (cottage_labels repeater) emit only a
       .mphbac-label-custom span with no .mphbac-label-num sibling, so
       this selector silently doesn't match them either. */
    .mphbac-cell-label:has(.mphbac-label-num:not(:empty)) .mphbac-label-abbrev {
        display: none;
    }
    .mphbac-cell-label .mphbac-label-num {
        opacity: 1;
        font-size: 1em;
        font-weight: 600;
        font-variant-numeric: tabular-nums;
        letter-spacing: 0.02em;
    }
    /* Center the #N inside the data-row cottage cells so the column reads
       as an intentional ID column rather than a left-jammed remnant of
       the pre-v0.9.8 two-line layout. Doubled-class prefix outranks
       Bravada's (0,3,1) button reset on text-align / justify-content.
       Scoped to data rows only — the .mphbac-row-header corner cell
       (the "Cottage" string) keeps its existing left-aligned styling. */
    .mphbac-root.mphbac-root .mphbac-row:not(.mphbac-row-header) .mphbac-cell-label {
        justify-content: center;
        text-align: center;
        padding-left: 8px;
        padding-right: 8px;
    }
}

/* Class-doubled selector (.mphbac-input.mphbac-input) instead of
   .mphbac-root .mphbac-input so the rule matches both the filter-row
   inputs AND the booking popup's date inputs after v0.8.6's portal to
   document.body. Without doubling-via-no-ancestor, Bravada's Elementor
   kit reset (line-height: 1px) wins on the portaled inputs and
   collapses the date text to a thin slice. Same pattern as the
   .mphbac-sheet.mphbac-sheet centering fix from v0.8.7. */
.mphbac-input.mphbac-input {
    padding: 10px 12px;
    border: 1px solid var(--mphbac-color-frame);
    border-radius: 6px;
    background: #ffffff;
    color: #111111;
    font: inherit;
    /* !important defeats Bravada's Elementor kit, which resets every input to
       line-height:1px and would otherwise collapse these date fields. The
       Elementor "Filter Fields" typography control excludes line-height for
       this reason. */
    line-height: 1.4 !important;
    min-width: 8.5em;
    min-height: 2.4em;
    box-sizing: border-box;
    transition: border-color 0.25s ease, box-shadow 0.25s ease;
}
/* When the checkin date moves and we have to force-shift the checkout to
   stay valid, briefly highlight the checkout input so the change isn't
   silent. JS adds this class for ~1.5s. */
.mphbac-input.mphbac-input--just-changed {
    border-color: var(--mphbac-color-today-outline, #f4da62);
    box-shadow: 0 0 0 3px rgba(244, 218, 98, 0.35);
}
@media (prefers-reduced-motion: reduce) {
    .mphbac-input.mphbac-input { transition: none; }
}

.mphbac-filter-label {
    font-weight: 600;
    color: #111111;
    text-align: center;
}

/* Structural button base only. Visual styling (colors, border, radius,
   padding, typography) comes from the Elementor "Buttons" style controls,
   which render at higher specificity and override these defaults. */
.mphbac-btn {
    display: inline-block;
    padding: 0.5em 0.9em;
    border: 0;
    border-radius: var(--mphbac-radius);
    background: #0f6dbf;
    color: #ffffff;
    font: inherit;
    line-height: 1.3;
    cursor: pointer;
}

/* Legend — centered */
.mphbac-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4em 1em;
    margin-bottom: 0.5em;
    font-size: 0.85em;
    color: var(--mphbac-color-legend-text);
    justify-content: center;
}

.mphbac-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
}

.mphbac-swatch {
    display: inline-block;
    width: 0.9em;
    height: 0.9em;
    border-radius: 2px;
    background: var(--mphbac-color-past);
}

.mphbac-swatch-available { background: var(--mphbac-color-available); }
.mphbac-swatch-booked    { background: var(--mphbac-color-booked); }
.mphbac-swatch-past      { background: var(--mphbac-color-past); }

/* Nav */
.mphbac-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5em;
    margin-bottom: 12px;
}

.mphbac-nav-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* iOS HIG / WCAG 2.5.5 AAA recommend ≥ 44px touch targets. The icon
       glyph stays font-size 16px; only the hit area grew. */
    min-width: 44px;
    min-height: 44px;
    padding: 0 4px;
    border: none;
    border-radius: 6px;
    background-color: var(--mphbac-color-nav-bg);
    color: var(--mphbac-color-nav-text);
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
    transition: background-color 0.2s ease;
}

.mphbac-nav-btn:hover,
.mphbac-nav-btn:focus-visible {
    background-color: var(--mphbac-color-nav-hover);
}

/* Back-to-today button is a text label, not an arrow icon — let it size
   to its content. Inherits all other nav-btn styling for consistency.
   `hidden` attribute controls visibility (set from JS by updateRange). */
.mphbac-nav-btn.mphbac-nav-today {
    width: auto;
    min-width: 44px;
    padding: 0 0.85em;
    font-size: 13px;
    font-weight: 600;
    text-transform: capitalize;
}

.mphbac-nav-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.mphbac-nav-range {
    font-size: 15px;
    font-weight: 600;
    color: #111111;
    text-align: center;
}

/* Grid */
.mphbac-grid-wrap {
    width: 100%;
    overflow: hidden;
    touch-action: pan-y;
    border: 1px solid var(--mphbac-color-frame);
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}

.mphbac-grid {
    display: grid;
    /* Day columns share the remaining width equally and shrink to fit, so the
       calendar never overflows its container on small screens. --mphbac-cell-min
       governs cell HEIGHT only (tap-target size), not width. */
    grid-template-columns: var(--mphbac-label-width) repeat(var(--mphbac-days), minmax(0, 1fr));
    gap: var(--mphbac-gap);
    user-select: none;
}

.mphbac-row {
    display: contents;
}

.mphbac-cell {
    display: flex;
    align-items: center;
    justify-content: center;
}
/* Cottage-row cells use --mphbac-cell-min ("Cottage row height" control).
   Header-row cells use --mphbac-header-min ("Header row height" control).
   Split in v0.10.0 — previously a single --mphbac-cell-min governed both,
   which meant editors trying to enlarge the cottage rows ended up dialing
   the header row instead (the header content was tighter, so the min-height
   bound there first). */
.mphbac-row:not(.mphbac-row-header) .mphbac-cell {
    min-height: var(--mphbac-cell-min);
}
.mphbac-row-header .mphbac-cell {
    min-height: var(--mphbac-header-min);
}

/* Cottage-name column (data rows) */
.mphbac-cell-label {
    justify-content: flex-start;
    padding: 8px 12px;
    background: var(--mphbac-color-namecol);
    border: 0;
    border-right: 2px solid var(--mphbac-color-frame);
    color: var(--mphbac-color-namecol-text);
    cursor: default;
    font: inherit;
    font-weight: 600;
    text-align: left;
    line-height: 1.2;
    gap: 0.1em;
    min-width: 0;
    overflow: hidden;
}

.mphbac-row-alt .mphbac-row-toggle {
    background: var(--mphbac-color-namecol-alt);
}

.mphbac-row-toggle {
    flex-wrap: wrap;
}

/* Only cottages with an info popup configured are clickable. */
.mphbac-row-toggle--info {
    cursor: pointer;
}
.mphbac-row-toggle--info:hover .mphbac-label-abbrev,
.mphbac-row-toggle--info:hover .mphbac-label-custom,
.mphbac-row-toggle--info:focus-visible .mphbac-label-abbrev,
.mphbac-row-toggle--info:focus-visible .mphbac-label-custom {
    text-decoration: underline;
}

/* Scoped under .mphbac-cell-label — these spans only ever live inside the
   row-label buttons. Crucially, the ROOT element carries the class
   mphbac-label-abbrev too (the Row-label-style mode flag), so a bare
   .mphbac-label-abbrev selector also styled the whole widget root:
   white-space:nowrap leaked into the legend/hint/empty-state text and the
   root's overflow:hidden clipped it. */
.mphbac-cell-label .mphbac-label-abbrev,
.mphbac-cell-label .mphbac-label-num,
.mphbac-cell-label .mphbac-label-custom {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex-basis: 100%;
}

.mphbac-label-num {
    opacity: 0.7;
    font-size: 0.85em;
    font-weight: 400;
}

/* "Number only" row-label mode (Elementor: Display → Row label style).
   When the root carries .mphbac-label-number, suppress the cottage-name
   abbrev so only the parsed #N stays. The cottage column width is
   intentionally unchanged — the user has a separate Cottage column width
   control if a narrower column is wanted. Graceful degradation: when a
   row's parsed number is empty (custom-label override or unparseable post
   title), the abbrev stays visible — never blank cells. Mirrors the v0.9.9
   mobile rules but gated on the .mphbac-label-number root class so they
   fire on every viewport. Doubled .mphbac-root prefix beats Bravada's
   (0,3,1) button reset on text-align / justify-content. */
.mphbac-root.mphbac-root.mphbac-label-number
    .mphbac-row:not(.mphbac-row-header)
    .mphbac-cell-label:has(.mphbac-label-num:not(:empty))
    .mphbac-label-abbrev {
    display: none;
}
.mphbac-root.mphbac-root.mphbac-label-number
    .mphbac-row:not(.mphbac-row-header)
    .mphbac-cell-label {
    justify-content: center;
    text-align: center;
}
.mphbac-root.mphbac-root.mphbac-label-number
    .mphbac-cell-label .mphbac-label-num {
    opacity: 1;
    font-size: 1em;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
}

/* Top row — day-of-week + date headers, and the corner "Property" cell */
.mphbac-cell-day {
    flex-direction: column;
    background: var(--mphbac-color-header);
    color: #ffffff;
    padding: 6px 2px;
    line-height: 1.3;
    text-transform: capitalize;
}
.mphbac-d-dow { font-size: 9px; font-weight: 400; opacity: 0.8; }
.mphbac-d-num { font-size: 13px; font-weight: 700; }

/* Day-of-week abbreviation length — toggled per device by the
   "Day-of-week format" responsive control via the custom properties. */
.mphbac-d-dow-long  { display: var(--mphbac-dow-long, inline); }
.mphbac-d-dow-short { display: var(--mphbac-dow-short, none); }

.mphbac-cell-day.is-today {
    box-shadow: inset 0 -3px 0 0 var(--mphbac-color-today-outline);
    font-weight: 700;
}

/* Weekend (Sat/Sun) treatment. Header cells use a dedicated background
   color set by the "Weekend background color" Elementor control, falling
   back to the weekday header color when not set — so out-of-the-box the
   header reads as a single solid bar, and editors who want a different
   weekend hue can dial it in. Body cells keep a barely-there overlay
   that helps weekenders spot Fri-Sun runs without competing with the
   available/booked colors. */
.mphbac-cell-day.is-weekend {
    background-color: var(--mphbac-color-header-weekend, var(--mphbac-color-header));
}
.mphbac-cell-status.is-weekend {
    background-image: linear-gradient(rgba(0, 0, 0, 0.035), rgba(0, 0, 0, 0.035));
}

/* Month-boundary divider — when the visible window crosses a month
   boundary (e.g. Jul 31 → Aug 1), a thin vertical line on the left edge
   of the first cell of the new month gives orienting structure to long
   grids. */
.mphbac-cell-day.is-month-start,
.mphbac-cell-status.is-month-start {
    border-left: 1px solid var(--mphbac-color-frame);
}

.mphbac-row-header .mphbac-cell-label {
    background: var(--mphbac-color-header);
    color: #ffffff;
    font-size: 12px;
    font-weight: 700;
    text-transform: capitalize;
    cursor: default;
    border-right-color: rgba(255, 255, 255, 0.15);
}

.mphbac-cell-status {
    background: var(--mphbac-color-booked);
    border-radius: var(--mphbac-radius);
    position: relative;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.mphbac-cell-status.is-available { background: var(--mphbac-color-available); }
.mphbac-cell-status.is-booked    { background: var(--mphbac-color-booked); }
.mphbac-cell-status.is-past      { background: var(--mphbac-color-past); }

.mphbac-hide-past .mphbac-cell-status.is-past {
    visibility: hidden;
}

/* Hover tooltip on each calendar cell (available / booked / past) */
.mphbac-cell-tip {
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    background: #2c3e50;
    color: #ffffff;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 11px;
    line-height: 1.2;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.15s ease;
    z-index: 20;
}
.mphbac-cell-status:hover .mphbac-cell-tip,
.mphbac-cell-status:focus-visible .mphbac-cell-tip {
    opacity: 1;
}

/* Empty state */
.mphbac-empty {
    margin-top: 0.75em;
    padding: 1em;
    border: 1px dashed currentColor;
    border-radius: var(--mphbac-radius);
    text-align: center;
}

.mphbac-empty[hidden] {
    display: none;
}

/* Soft hint banner shown when the visible window starts with one or more
   all-booked days. Lives inside .mphbac-grid-wrap above the grid, so it
   shares the aria-live region and gets read by screen readers when it
   appears. */
.mphbac-availability-hint {
    margin-bottom: 0.5em;
    padding: 0.55em 0.85em;
    background: rgba(244, 218, 98, 0.18);
    border-left: 3px solid var(--mphbac-color-today-outline, #f4da62);
    border-radius: var(--mphbac-radius, 4px);
    font-size: 0.92em;
    color: var(--mphbac-color-text, #111);
    transition: opacity 0.15s ease, transform 0.15s ease;
}
/* Initial state for the fade-in. JS appends the hint with this class,
   then on the next frame swaps in --shown which transitions to opaque. */
.mphbac-availability-hint.mphbac-hint--enter {
    opacity: 0;
    transform: translateY(-4px);
}
.mphbac-availability-hint.mphbac-hint--shown {
    opacity: 1;
    transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
    .mphbac-availability-hint {
        transition: none;
    }
    .mphbac-availability-hint.mphbac-hint--enter {
        opacity: 1;
        transform: none;
    }
}

/* Available cells stay tappable (booking popup). Brief active-state scale
   gives tactile feedback when a visitor taps — felt on mobile, ignored on
   resting state so the grid still reads as a data table. */
.mphbac-popup-enabled .mphbac-cell-status.is-available.is-clickable {
    cursor: pointer;
    transition: transform 100ms ease;
}
.mphbac-popup-enabled .mphbac-cell-status.is-available.is-clickable:active {
    transform: scale(0.94);
}
@media (prefers-reduced-motion: reduce) {
    .mphbac-popup-enabled .mphbac-cell-status.is-available.is-clickable {
        transition: none;
    }
    .mphbac-popup-enabled .mphbac-cell-status.is-available.is-clickable:active {
        transform: none;
    }
}

/* Book Now sheet + Cottage Info sheet share these styles */
.mphbac-sheet-overlay,
.mphbac-info-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    opacity: 0;
    transition: opacity 0.2s ease;
    z-index: 1000;
}
.mphbac-sheet-overlay.is-open,
.mphbac-info-overlay.is-open { opacity: 1; }

/* The [hidden] attribute is the source of truth for popup visibility.
   These elements have `display: flex` set further down for their
   internal layout, which silently overrides the browser-default
   `[hidden] { display: none }`. On most pages the closed-state
   `transform: translateY(100%)` masks that by pushing the popup
   off-screen — but a transformed Elementor ancestor can break the
   containing block for the transform and leave the popup visible at
   page bottom. !important keeps `hidden` authoritative regardless. */
.mphbac-sheet[hidden],
.mphbac-info-sheet[hidden],
.mphbac-sheet-overlay[hidden],
.mphbac-info-overlay[hidden] {
    display: none !important;
}

/* Hidden source for the cottage info popup. Rendered with real width
   offscreen (not display:none) so Elementor's image-carousel handler
   initializes Swiper + lightbox click binding correctly at page-load.
   On open, widget.js moves the node into the popup body and removes
   [hidden]; on close, restoreMovedContent() puts [hidden] back and
   this rule re-engages. */
.mphbac-info-content[hidden] {
    position: fixed !important;
    top: 0 !important;
    left: 0 !important;
    transform: translateY(-200vh);
    width: var(--mphbac-info-prerender-width, 720px);
    max-width: 100vw;
    opacity: 0;
    pointer-events: none;
    user-select: none;
    z-index: -1;
    overflow: hidden;
}

.mphbac-sheet,
.mphbac-info-sheet {
    position: fixed;
    z-index: 1001;
    /* border-box so width:100% / 100vw includes the popup's own padding —
       otherwise the popup overflows the viewport by 2 × horizontal padding
       and the right side of the content gets clipped off-screen. */
    box-sizing: border-box;
    background: #fff;
    color: #000;
    box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.2);
    transition: transform 0.25s ease, opacity 0.2s ease;
    /* Mobile: full-width bottom sheet that never causes horizontal scroll */
    left: 0;
    right: 0;
    /* `bottom: 0` puts the popup's bottom edge at the viewport's vh-bottom,
       which on iOS Safari is BEHIND the floating bottom toolbar — the
       toolbar overlays the viewport, so the bottom ~80px of the popup
       (background + content + padding) is clipped underneath it. The
       env(safe-area-inset-bottom) value, available when the document's
       viewport meta carries `viewport-fit=cover` (which boot() ensures —
       see widget.js), reports the height of that safe-area inset; pinning
       the popup there lifts it above the toolbar. Falls back to 0 on
       browsers without env() support (no harm — they had the bug before
       too, and likely don't have an overlaying toolbar). */
    bottom: env(safe-area-inset-bottom, 0px);
    width: 100%;
    border-radius: 16px 16px 0 0;
    transform: translateY(100%);
    /* Sizing fallback chain: every browser sees one of these. svh is the
       "small viewport height" unit — excludes browser chrome AND the
       on-screen keyboard, so the popup never extends behind the iOS
       keyboard. Older Safari that doesn't support svh falls back to dvh
       (still excludes browser chrome but not OSK), then vh (excludes
       neither). Order matters — last declaration the browser understands
       wins. */
    max-height: 90vh;
    max-height: 90dvh;
    max-height: 90svh;
    overflow-x: hidden;
    overflow-y: auto;
    padding: 1em 1.25em 1.5em;
}
.mphbac-info-sheet {
    /* Flex column so the sticky close button can align to flex-end (top-right)
       and stay pinned at the top while the body content scrolls. */
    display: flex;
    flex-direction: column;
    /* Hide the NATIVE scrollbar on every engine — we draw our own custom
       always-visible one below (.mphbac-info-scrollbar). This is the whole
       reason the previous "always-visible scrollbar" attempt failed: iOS
       Safari auto-hides native overlay scrollbars and ignores the styling
       hooks, so a native bar can't be forced to stay visible there. */
    scrollbar-width: none;          /* Firefox */
    -ms-overflow-style: none;       /* old Edge */
}
.mphbac-info-sheet::-webkit-scrollbar {
    width: 0;
    height: 0;
    display: none;                  /* WebKit / Blink */
}

/* Custom always-visible scrollbar. The sheet itself is the scroll container;
   this element is a sticky, zero-height flex child pinned to the top-right so
   it rides along in view as the body scrolls. widget.js sizes the track and
   thumb from scrollHeight/clientHeight and moves the thumb from scrollTop, so
   it behaves identically on iOS, Android, and desktop. Indicator-only
   (pointer-events:none) — touch/wheel scrolling is unchanged; it shows how
   much content there is and how far down you are. Hidden by JS when the
   content fits without scrolling. */
.mphbac-info-scrollbar {
    position: sticky;
    top: 0;
    align-self: flex-end;
    order: -1;                      /* keep it visually first / at the top */
    flex: 0 0 auto;
    width: 5px;
    height: 0;                      /* consumes no vertical space in the column */
    margin-right: -0.55em;          /* sit in the sheet's right padding gutter */
    z-index: 11;
    pointer-events: none;
}
.mphbac-info-scrollbar[hidden] {
    display: none;
}
.mphbac-info-scrollbar-track {
    position: absolute;
    top: 0;
    right: 0;
    width: 5px;
    border-radius: 3px;
    background: rgba(0, 0, 0, 0.08);
    /* height set inline by widget.js */
}
.mphbac-info-scrollbar-thumb {
    position: absolute;
    top: 0;
    right: 0;
    width: 5px;
    min-height: 28px;
    border-radius: 3px;
    background: rgba(15, 109, 191, 0.55);
    /* height + translateY set inline by widget.js */
}
.mphbac-info-close--floating {
    position: sticky;
    top: 0;
    align-self: flex-end;
    /* Above any popup-internal stacking (Elementor image-carousel slides
       and pagination dots create their own stacking contexts that beat the
       old z-index: 2). 10 sits the X above all known popup content while
       staying well below site-level overlays. */
    z-index: 10;
    width: 2.1em;
    height: 2.1em;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Frosted pill — translucent fill + backdrop blur so the X reads
       cleanly against any color/image/text that scrolls underneath.
       Earlier solid #888 disappeared into gray photos. */
    background: rgba(60, 60, 60, 0.45);
    backdrop-filter: blur(10px) saturate(140%);
    -webkit-backdrop-filter: blur(10px) saturate(140%);
    color: rgba(255, 255, 255, 0.96);
    border-radius: 50%;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
    /* Reserve no extra vertical space — visually overlap the header below. */
    margin-bottom: -2.1em;
    margin-right: -0.25em;
}
.mphbac-info-close--floating:focus-visible {
    outline: 2px solid var(--mphbac-color-today-outline, #f4da62);
    outline-offset: 2px;
}
/* Older browsers without backdrop-filter: bump opacity so the pill stays
   readable instead of falling back to the translucent rgba which would be
   nearly invisible against a light background. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .mphbac-info-close--floating {
        background: rgba(40, 40, 40, 0.92);
    }
}
.mphbac-sheet-header--info {
    /* Stack the title and the "View Cottage Page" button vertically —
       the base .mphbac-sheet-header is a space-between row, which would
       put the button off to the right of the title. */
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5em;
}
.mphbac-sheet-header--info .mphbac-sheet-title {
    /* The X is no longer a flex sibling; leave room so the title never
       collides with the floating button. */
    padding-right: 2.2em;
}
/* "View Cottage Page" button. Baked default look = filled blue rounded pill.
   The doubled class (0,2,0) is deliberate: the info sheet is portaled to
   <body> when the popup opens, so {{WRAPPER}}-scoped Elementor controls and
   Bravada's theme <a> rules would otherwise decide the look. The doubled
   class both survives the portal and outranks the theme. The dedicated
   "Cottage Page Button" Elementor section (also global + doubled) layers
   overrides on top of these. Icon is a real, editable element (Elementor
   ICONS control) — no more CSS ::after arrow. */
.mphbac-info-view-link.mphbac-info-view-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
    align-self: flex-start;
    background: #0f6dbf;
    color: #ffffff;
    border: 0;
    border-radius: 999px;
    padding: 0.5em 1.1em;
    font: inherit;
    line-height: 1.3;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease;
}
.mphbac-info-view-link.mphbac-info-view-link:hover,
.mphbac-info-view-link.mphbac-info-view-link:focus-visible {
    background: #0a4f8c;
    color: #ffffff;
}
.mphbac-info-view-link[hidden] {
    display: none;
}
.mphbac-view-icon {
    display: inline-flex;
    align-items: center;
    line-height: 0;
}
.mphbac-view-icon svg {
    width: 1em;
    height: 1em;
    fill: currentColor;
}
.mphbac-sheet.is-open,
.mphbac-info-sheet.is-open {
    transform: translateY(0);
}
/* While the user is swipe-dragging, suspend the transition so the sheet
   tracks the finger 1:1; touchend either snaps back (transition restored)
   or closes (CSS transition takes care of slide-out). */
.mphbac-sheet.is-dragging,
.mphbac-info-sheet.is-dragging {
    transition: none;
}

@media (min-width: 601px) {
    .mphbac-sheet,
    .mphbac-info-sheet {
        left: 50%;
        right: auto;
        bottom: auto;
        top: 50%;
        transform: translate(-50%, calc(-50% + 20px));
        opacity: 0;
        width: min(440px, 92vw);
        max-height: 80vh;
        border-radius: 12px;
    }
    /* Cottage-info popup gets its own configurable width — defaults to 800px
       but can be tuned via the "Info popup max width" Elementor control to
       comfortably display image galleries / multi-column widgets. */
    .mphbac-info-sheet {
        /* Default 1200px raised in v0.8.5 (was 800px in v0.8.4). 96vw cap
           gives the popup more horizontal room on wide monitors while still
           leaving a sliver of frame around it. */
        width: min(var(--mphbac-info-max-width, 1200px), 96vw);
    }
    .mphbac-sheet.is-open,
    .mphbac-info-sheet.is-open {
        opacity: 1;
        transform: translate(-50%, -50%);
    }
}

/* "Full viewport width" mode — used when the popup should look as close as
   possible to a real page render (e.g. the MotoPress accommodation source).
   Combined selector reaches (0,2,0) specificity so it overrides the desktop
   centered-modal rules above. The popup's top edge is anchored to the
   --mphbac-info-sheet-top CSS variable (set by JS to the widget's current
   getBoundingClientRect().top on each open), so the popup appears to grow
   out of the top of the calendar widget rather than covering the page
   header area above it. Slides up from the bottom on every viewport.
   Symmetric --mphbac-info-side gutters keep it from running edge-to-edge
   (which on some Elementor pages would clip behind a transformed ancestor
   and hide the close button). JS portals the sheet + overlay to
   document.body on open so the ancestor containing block can't constrain
   the popup at all. */
.mphbac-info-sheet.mphbac-info-sheet--full {
    left: var(--mphbac-info-side, 12px);
    right: var(--mphbac-info-side, 12px);
    /* max() with env(safe-area-inset-top) keeps the popup's title row
       below the iPhone notch / Dynamic Island / status bar when the
       widget is near the top of the page. Falls back to 0 on devices
       without a safe-area inset (every non-notched device). */
    top: max(var(--mphbac-info-sheet-top, 0px), env(safe-area-inset-top, 0px));
    bottom: 0;
    width: auto;
    max-width: none;
    max-height: none;
    border-radius: 16px 16px 0 0;
    transform: translateY(100%);
    opacity: 1;
    overscroll-behavior: contain;
}
.mphbac-info-sheet.mphbac-info-sheet--full.is-open {
    transform: translateY(0);
    opacity: 1;
}
@media (min-width: 601px) {
    /* Re-assert the full-viewport positioning at desktop sizes so the
       (0,1,0) media-query rules above don't centered-modal it. Wider
       gutters than mobile so the popup reads as a panel, not a bleed. */
    .mphbac-info-sheet.mphbac-info-sheet--full {
        --mphbac-info-side: 32px;
        left: var(--mphbac-info-side);
        right: var(--mphbac-info-side);
        top: max(var(--mphbac-info-sheet-top, 0px), env(safe-area-inset-top, 0px));
        bottom: 0;
        width: auto;
        max-width: none;
        max-height: none;
        transform: translateY(100%);
    }
    .mphbac-info-sheet.mphbac-info-sheet--full.is-open {
        transform: translateY(0);
    }
}

/* Lock body scroll while the info popup is open so touch-scroll gestures
   land on the popup's own overflow-y: auto instead of chaining into the
   page. Without this, mobile users can't reach the bottom of a popup that
   is taller than the viewport — the page scrolls behind the popup until
   the page hits its bottom, then nothing scrolls. */
html.mphbac-info-open,
body.mphbac-info-open {
    overflow: hidden;
}

/* Booking popup centers to the visible viewport on every breakpoint
   (desktop / tablet / mobile). Replaces the v0.7.1 widget-top anchor:
   on tall pages the visitor sometimes had to scroll to find the popup,
   and the auto-scroll fallback was unreliable on mobile. position:fixed
   + portal-to-body (openSheet() moves the node to document.body) makes
   the center coordinates literal viewport center. Subtle 20px slide-up
   on open via the closed-state translateY offset.

   Selector uses the class-doubled trick (.mphbac-sheet.mphbac-sheet)
   rather than .mphbac-root .mphbac-sheet — once the sheet is portaled
   to document.body, the .mphbac-root ancestor is gone, so descendant
   selectors fail to match. Class-doubling reaches (0,2,0) specificity
   without depending on any parent. Mirror of the .mphbac-info-sheet
   --full pattern. */
.mphbac-sheet.mphbac-sheet {
    left: 50%;
    right: auto;
    top: 50%;
    bottom: auto;
    width: min(440px, calc(100vw - 24px));
    max-height: min(80vh, 80dvh);
    border-radius: 12px;
    transform: translate(-50%, -50%) translateY(20px);
    opacity: 0;
}
.mphbac-sheet.mphbac-sheet.is-open {
    transform: translate(-50%, -50%);
    opacity: 1;
}

/* Cottage info popup adopts the Book Now popup's centered-modal feel on
   every viewport (v0.8.9): 12px gutters on mobile, 32px on tablet/desktop,
   12px radius all corners, body scrolls internally. Class-doubled selector
   for two reasons — (a) it wins over the (0,1,0) bottom-sheet base rule,
   (b) it keeps applying after openInfo() portals the sheet to
   document.body where the .mphbac-root ancestor is no longer present. */
.mphbac-info-sheet.mphbac-info-sheet {
    left: 50%;
    right: auto;
    top: 50%;
    bottom: auto;
    width: min(440px, calc(100vw - 24px));
    max-height: min(85vh, 85dvh);
    border-radius: 12px;
    transform: translate(-50%, -50%) translateY(20px);
    opacity: 0;
}
.mphbac-info-sheet.mphbac-info-sheet.is-open {
    transform: translate(-50%, -50%);
    opacity: 1;
}
/* Tablet: 32px gutter floor, up to 720px. */
@media (min-width: 601px) {
    .mphbac-info-sheet.mphbac-info-sheet {
        width: min(720px, calc(100vw - 64px));
    }
}
/* Desktop: respects the Elementor "Info popup max width" responsive control
   (falls back to 900px — down from 1200px in v0.8.5 — so the carousel and
   accordion have room without dominating the screen). */
@media (min-width: 1025px) {
    .mphbac-info-sheet.mphbac-info-sheet {
        width: min(var(--mphbac-info-max-width, 900px), calc(100vw - 64px));
    }
}

/* Defensive rules for arbitrary Elementor / Angie-snippet content cloned
   into the popup. Without these, an image set to width:1200px in a
   template would force the popup to scroll horizontally. */
.mphbac-info-body img,
.mphbac-info-body video,
.mphbac-info-body iframe {
    max-width: 100%;
    height: auto;
    display: block;
}
.mphbac-info-body .elementor-button,
.mphbac-info-body button,
.mphbac-info-body [class*="-btn"] {
    /* Keep call-to-action labels (e.g. "Choose Plan") on a single line. */
    white-space: nowrap;
}

.mphbac-sheet-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 0.5em;
    margin-bottom: 0.85em;
    padding-bottom: 0.7em;
    border-bottom: 1px solid var(--mphbac-color-frame);
}
/* Popup titles (cottage info + Book Now). These were <h3> until 0.15.0 and
   were switched to <div> because they ship empty in the HTML — JS fills them
   when a popup opens — which trips "empty heading" accessibility checks.

   The theme styled those h3s, so the tag change had to be made invisible.
   Measured on the live site with a popup OPEN (the only state that renders;
   closed popups are display:none) by diffing the real h3 against a div of
   this class in the same position:
       font-size   h3 25px   vs  div 20.7px   <- the only real difference
       line-height h3 45px   vs  div 39.3px   <- follows from font-size:
                                                 45/25 == 39.3/21.85 == 1.8,
                                                 an inherited unitless ratio
       margins     identical (the theme's h3 margin rule is scoped to an
                   ancestor the popup leaves behind when it is portaled to
                   <body> on open)
   So pinning font-size alone reproduces the previous rendering exactly, and
   line-height resolves to 45px on its own. Do not "restore" the old 1.15em
   here — that was never what rendered; the theme's h3 rule overrode it.
   The Elementor "Popup Titles" section layers on top of this (doubled-class
   selector, so it wins) for anyone who wants to restyle these. */
.mphbac-sheet-title {
    margin: 0;
    font-size: 25px;
    font-weight: 700;
    color: var(--mphbac-color-header);
    flex: 1;
    min-width: 0;
    overflow-wrap: anywhere;
    word-break: break-word;
}
/* Cottage info popup title link — inherits the typography from
   .mphbac-sheet-title (color, weight, size); just adds a subtle
   underline cue and a hover state. */
.mphbac-sheet-title-link {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 1px;
}
.mphbac-sheet-title-link:hover,
.mphbac-sheet-title-link:focus-visible {
    text-decoration-thickness: 2px;
}

/* Cottage info popup body */
.mphbac-info-body {
    overflow-wrap: anywhere;
    /* Hard-contain the popup width. min-width:0 lets flex/grid children
       shrink below their declared min-content; max-width:100% prevents
       any nested widget from pushing the body wider than its slot. */
    max-width: 100%;
    min-width: 0;
}
.mphbac-info-body :first-child { margin-top: 0; }
.mphbac-info-body :last-child  { margin-bottom: 0; }

/* Defensive containment for embedded Elementor widgets (pricing tables,
   image carousels, multi-column containers). Their server-rendered
   markup carries width/min-width assumptions from the page context
   where they were authored — which can leak out past the popup edge,
   especially in full-viewport mode where the popup is wider and
   100vw-anchored elements scale up. !important is justified because
   we own the popup's width contract. */
.mphbac-info-body,
.mphbac-info-body > *,
.mphbac-info-body .elementor-section,
.mphbac-info-body .elementor-container,
.mphbac-info-body .elementor-row,
.mphbac-info-body .elementor-column,
.mphbac-info-body .elementor-column-wrap,
.mphbac-info-body .elementor-widget,
.mphbac-info-body .elementor-widget-wrap,
.mphbac-info-body .elementor-widget-container,
.mphbac-info-body table,
.mphbac-info-body figure {
    max-width: 100% !important;
    box-sizing: border-box;
}
.mphbac-info-body .elementor-widget-price-table,
.mphbac-info-body .elementor-widget-table,
.mphbac-info-body .elementor-widget-image-carousel,
.mphbac-info-body .elementor-widget-image-gallery {
    overflow: hidden;
}
/* Keep slider nav arrows (Stratum Advanced Slider, Elementor carousels — any
   standard Swiper) visible on EVERY viewport inside the popup. The slider
   initializes while the popup content is display:none (0 width), so Swiper
   computes a broken nav state and the prev/"back" arrow vanishes ~1s after
   each slide settles. Forcing visibility here — and showing the disabled
   endpoint arrow dimmed rather than gone — keeps the back button present
   (it was already clickable while invisible). Viewport-agnostic and
   opacity/visibility-only, so it composes with the mobile chevron-redraw
   block below without double-drawing. */
.mphbac-info-body .swiper-button-prev,
.mphbac-info-body .swiper-button-next,
.mphbac-info-body .elementor-swiper-button-prev,
.mphbac-info-body .elementor-swiper-button-next {
    opacity: 1 !important;
    visibility: visible !important;
}
.mphbac-info-body .swiper-button-disabled,
.mphbac-info-body .swiper-button-lock {
    opacity: 0.4 !important;
    visibility: visible !important;
    display: flex !important;
    pointer-events: auto !important;
}
/* Mobile cottage-info carousel arrows: v0.8.13 forced original
   icon visible (didn't hold). v0.8.14 drew a ::before chevron
   (rendered in the corner). v0.8.15 switched to background-image
   chevron — the RIGHT arrow renders perfectly and stays visible,
   but the LEFT button itself disappears 0.3s after each slide
   settles. v0.8.15 dropped `display`, so any rule that sets
   `display: none` on the prev button (Elementor's mobile-hide
   rule, Bravada's reset, or Swiper's `.swiper-button-disabled`
   state) wins. v0.8.16: force `display: flex !important` so the
   button stays in the layout regardless, and add Elementor's
   long-form `-previous` class to the selector list as a defensive
   measure in case the deployed Elementor version uses that. */
@media (max-width: 600px) {
    .mphbac-info-body .elementor-swiper-button,
    .mphbac-info-body .elementor-swiper-button-prev,
    .mphbac-info-body .elementor-swiper-button-previous,
    .mphbac-info-body .elementor-swiper-button-next,
    .mphbac-info-body .swiper-button-prev,
    .mphbac-info-body .swiper-button-next {
        display: flex !important;
        align-items: center !important;
        justify-content: center !important;
        opacity: 1 !important;
        visibility: visible !important;
        pointer-events: auto !important;
        z-index: 20 !important;
        width: 36px !important;
        height: 36px !important;
        background-color: rgba(0, 0, 0, 0.5) !important;
        border-radius: 50% !important;
        background-repeat: no-repeat !important;
        background-position: center center !important;
        background-size: 16px 16px !important;
    }
    /* Defeat Swiper's `.swiper-button-disabled` state hiding too —
       if the carousel hits a non-loop endpoint we still want the
       arrow visible (dimmed at most), not gone. */
    .mphbac-info-body .swiper-button-disabled,
    .mphbac-info-body .swiper-button-lock {
        display: flex !important;
        opacity: 1 !important;
        visibility: visible !important;
    }
    /* Hide the original Elementor icon (svg, i, icon-font span, and
       its ::before / ::after pseudos if any) so they don't compete
       with the background-image chevron. */
    .mphbac-info-body .elementor-swiper-button > *,
    .mphbac-info-body .swiper-button-prev > *,
    .mphbac-info-body .swiper-button-next > * {
        opacity: 0 !important;
        visibility: hidden !important;
    }
    .mphbac-info-body .elementor-swiper-button::before,
    .mphbac-info-body .elementor-swiper-button::after,
    .mphbac-info-body .swiper-button-prev::before,
    .mphbac-info-body .swiper-button-prev::after,
    .mphbac-info-body .swiper-button-next::before,
    .mphbac-info-body .swiper-button-next::after {
        content: none !important;
        display: none !important;
    }
    /* Inline-SVG chevrons. URL-encoded (# → %23) so they're safe
       inline in CSS without needing url-escape gymnastics. */
    .mphbac-info-body .elementor-swiper-button-prev,
    .mphbac-info-body .elementor-swiper-button-previous,
    .mphbac-info-body .swiper-button-prev {
        background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><polyline points='15 18 9 12 15 6'/></svg>") !important;
    }
    .mphbac-info-body .elementor-swiper-button-next,
    .mphbac-info-body .swiper-button-next {
        background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><polyline points='9 18 15 12 9 6'/></svg>") !important;
    }
}
.mphbac-sheet-close {
    background: transparent;
    border: 0;
    font-size: 1.6em;
    line-height: 1;
    padding: 0 0.3em;
    cursor: pointer;
    color: #888888;
    transition: color 0.15s ease;
}
.mphbac-sheet-close:hover,
.mphbac-sheet-close:focus-visible {
    color: var(--mphbac-color-nav-bg);
}

/* Universal focus ring for buttons + inputs that don't already define one.
   Keyboard users need a visible indicator of where focus is. Uses a 2px
   outline + 2px offset so it doesn't clip against rounded button edges. */
.mphbac-root.mphbac-root .mphbac-btn:focus-visible,
.mphbac-root.mphbac-root .mphbac-input:focus-visible,
.mphbac-root.mphbac-root .mphbac-row-toggle:focus-visible {
    outline: 2px solid var(--mphbac-color-today-outline, #f4da62);
    outline-offset: 2px;
}

/* Check-in and check-out fields sit side-by-side on every viewport.
   flex-wrap: wrap is the safety net on viewports too narrow for two date
   inputs (~< 320px) — fields gracefully stack instead of overflowing.
   The error message lives in the same flex container; flex-basis: 100%
   pushes it to a new row below the date pair, full width. */
.mphbac-sheet-body {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    column-gap: 0.75em;
    row-gap: 0.75em;
    margin-bottom: 1em;
}
.mphbac-sheet-field {
    display: flex;
    flex-direction: column;
    flex: 1 1 calc(50% - 0.5em);
    min-width: 0;
    gap: 0.3em;
    font-size: 0.95em;
}
.mphbac-sheet-field > span {
    font-weight: 600;
    color: #111111;
}
.mphbac-sheet-error {
    flex-basis: 100%;
    margin: 0;
    padding: 0.5em 0.7em;
    background: rgba(196, 58, 58, 0.12);
    color: var(--mphbac-color-nav-bg);
    border-radius: var(--mphbac-radius);
    font-size: 0.9em;
}
.mphbac-sheet-error[hidden] { display: none; }

.mphbac-sheet-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5em;
    position: sticky;
    bottom: 0;
    background: inherit;
    padding-top: 0.5em;
}
.mphbac-btn-primary[disabled] {
    opacity: 0.6;
    cursor: not-allowed;
}

/* Loading state — the grid is rendered client-side */
.mphbac-root.is-loading .mphbac-grid {
    opacity: 0.5;
    pointer-events: none;
}
/* While a fetch is in-flight, breathe the grid opacity slightly so the
   visitor sees motion ("something's happening") instead of a frozen dim
   state. The skeleton placeholder gets its own shimmer (see below); this
   animates the post-first-paint reload state. */
@media (prefers-reduced-motion: no-preference) {
    .mphbac-root.is-loading .mphbac-grid {
        animation: mphbac-loading-pulse 1.4s ease-in-out infinite;
    }
}
@keyframes mphbac-loading-pulse {
    0%, 100% { opacity: 0.5; }
    50%      { opacity: 0.75; }
}

/* Skeleton — first-paint placeholder that mirrors the cottage rows so the
   visitor sees structure immediately instead of a blank box or "Loading…"
   text. Disappears when renderGrid() replaces .mphbac-grid-wrap contents. */
.mphbac-root .mphbac-skeleton {
    display: flex;
    flex-direction: column;
    /* Match the real grid's --mphbac-gap var (set by the cell-gap control)
       so the skeleton-to-grid swap doesn't shift width/height. No outer
       padding for the same reason — the real grid has none. */
    gap: var(--mphbac-gap, 2px);
}
.mphbac-root .mphbac-skeleton-row {
    display: grid;
    grid-template-columns: var(--mphbac-label-width, 180px) 1fr;
    gap: var(--mphbac-gap, 2px);
    min-height: var(--mphbac-cell-min, 42px);
    background: var(--mphbac-color-namecol, #F8F9FA);
    border-radius: var(--mphbac-cell-radius, 0);
}
.mphbac-root .mphbac-skeleton-row-alt {
    background: var(--mphbac-color-namecol-alt, #F1F3F5);
}
/* Header stripe — same color/height as the rendered grid's top row, so the
   skeleton-to-grid swap doesn't introduce a vertical shift. No shimmer
   inside (the band is itself the placeholder). */
.mphbac-root .mphbac-skeleton-row--header {
    background: var(--mphbac-color-header, #0A50B2);
}
.mphbac-root .mphbac-skeleton-name,
.mphbac-root .mphbac-skeleton-cells {
    display: block;
    background: linear-gradient(
        90deg,
        rgba(0, 0, 0, 0.045) 0%,
        rgba(0, 0, 0, 0.085) 50%,
        rgba(0, 0, 0, 0.045) 100%
    );
    background-size: 200% 100%;
    border-radius: var(--mphbac-cell-radius, 4px);
}
.mphbac-root .mphbac-skeleton-name { margin: 6px; }
.mphbac-root .mphbac-skeleton-cells { margin: 6px; }
@media (prefers-reduced-motion: no-preference) {
    .mphbac-root .mphbac-skeleton-name,
    .mphbac-root .mphbac-skeleton-cells {
        animation: mphbac-skeleton-pulse 1.4s ease-in-out infinite;
    }
}
@keyframes mphbac-skeleton-pulse {
    0%   { background-position: 100% 0; }
    100% { background-position: -100% 0; }
}

/* Screen-reader-only utility (used by the loading status announcement). */
.mphbac-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* View Transitions — when the browser supports document.startViewTransition()
   the popup-open and the form-POST to checkout are wrapped in a transition,
   producing a smooth fade-morph on Chrome 111+/Safari 18+. Older browsers
   see today's CSS transitions and behave identically. */
::view-transition-old(root),
::view-transition-new(root) {
    animation-duration: 0.25s;
    animation-timing-function: ease;
}
@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*),
    ::view-transition-old(*),
    ::view-transition-new(*) {
        animation: none !important;
    }
}

/* Minimal jQuery UI Datepicker fallback (only loaded if browser lacks input[type=date]) */
.ui-datepicker {
    background: #fff;
    color: #000;
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 0.5em;
    font-size: 13px;
    box-shadow: 0 2px 12px rgba(0,0,0,0.15);
    display: none;
}
.ui-datepicker-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.4em; }
.ui-datepicker-prev, .ui-datepicker-next { cursor: pointer; padding: 0.2em 0.5em; }
.ui-datepicker-title { font-weight: 600; }
.ui-datepicker table { border-collapse: collapse; width: 100%; }
.ui-datepicker th, .ui-datepicker td { padding: 0.2em; text-align: center; }
.ui-datepicker td a { display: block; padding: 0.25em; color: inherit; text-decoration: none; border-radius: 3px; }
.ui-datepicker td a:hover { background: #0f6dbf; color: #fff; }
.ui-datepicker .ui-state-active { background: #0f6dbf; color: #fff; border-radius: 3px; }

/* Print stylesheet — a property manager firing Cmd-P should get a clean
   availability snapshot, not the interactive filters / nav / popups.
   Hides everything except the heading, the date range, the grid, and the
   legend; forces the status colors to render even when browsers strip
   backgrounds for print. */
@media print {
    body * { visibility: hidden; }
    .mphbac-root,
    .mphbac-root * { visibility: visible; }
    .mphbac-root {
        position: static;
        font-size: 11px;
        color: #000;
        background: #fff;
    }
    .mphbac-root .mphbac-filters,
    .mphbac-root .mphbac-nav-btn,
    .mphbac-root .mphbac-info-content,
    .mphbac-root .mphbac-info-overlay,
    .mphbac-root .mphbac-info-sheet,
    .mphbac-root .mphbac-sheet-overlay,
    .mphbac-root .mphbac-sheet,
    .mphbac-root .mphbac-skeleton,
    .mphbac-root .mphbac-empty,
    .mphbac-root .mphbac-btn,
    .mphbac-root .mphbac-availability-hint { display: none !important; }
    .mphbac-root .mphbac-nav { justify-content: center; }
    .mphbac-root .mphbac-cell-status,
    .mphbac-root .mphbac-cell-status.is-available,
    .mphbac-root .mphbac-cell-status.is-booked,
    .mphbac-root .mphbac-cell-status.is-past {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
    .mphbac-root .mphbac-cell-tip { display: none; }
    .mphbac-root .mphbac-row-toggle { background: transparent !important; box-shadow: none !important; }
}
