/* ═══════════════════════════════════════════════════════════════════════════
   AWQATY — Booking Flow v2
   Design system ported 1:1 from the reference mockup
   "AWQATY Booking Flow.html" / "AWQATY Booking Flow -AR-.html".

   Scope of this file so far: Screen 1 — Provider Page.
   Screens 2-4 (Select Time / Checkout / Confirmation) will be appended under
   their own banners as each page is migrated.

   Naming follows the reference exactly (.provider-card, .service-card,
   .section-head, …) so a developer familiar with the mockup finds the same
   classes here. App-only additions (cover image, empty state, profile video,
   RTL) are grouped at the end of each section and marked as such.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── DESIGN TOKENS ─────────────────────────────────────────────────────────
   Neutrals, semantic colours and the blue ramp are the reference's literal
   values, so an unbranded vendor renders pixel-identical to the mockup.
   When a vendor has branding enabled, the v2 header re-points the blue ramp
   at --brand-* (see booking/v2/layouts/header.blade.php) and every component
   follows, because no component hard-codes a blue.
   ───────────────────────────────────────────────────────────────────────── */
:root {
    --blue: #0069FF;
    --blue-dark: #0050CC;
    --blue-light: #EEF4FF;
    --blue-mid: #4D9BFF;
    --text: #1A1A2E;
    --muted: #6B7280;
    --muted-light: #9CA3AF;
    --border: #E5E7EB;
    --border-light: #F1F3F5;
    --bg: #F9FAFB;
    --card: #FFFFFF;
    --green: #12B76A;
    --green-light: #DCFCE7;
    --amber: #F59E0B;
    --amber-light: #FEF3C7;
    --red: #EF4444;
    --red-light: #FEE2E2;

    /* Branding fallbacks — overridden by the brand-theme block when a vendor
       has branding configured. Kept equal to the reference blue by default. */
    --brand-primary: #0069FF;
    --brand-secondary: #4D9BFF;
    --brand-accent: #0069FF;
    --brand-btn-radius: 9px;
    --brand-header-bg: #0069FF;
    --brand-overlay-opacity: 0.5;
}

/* ── BASE ──────────────────────────────────────────────────────────────────
   The reference resets margin/padding on `*`. Bootstrap is also loaded on
   these pages, so a blanket reset would strip its component spacing (dropdown
   menus in particular). Resetting only the elements the reference layout
   relies on produces identical rendering without fighting Bootstrap.
   ───────────────────────────────────────────────────────────────────────── */
html {
    scroll-behavior: smooth;
}

body {
    font-family: 'DM Sans', sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    min-height: 100vh;
}

html[lang="ar"] body,
[dir="rtl"] body {
    font-family: 'IBM Plex Sans Arabic', 'DM Sans', sans-serif;
}

/* Wrapped in :where() so the reset carries zero specificity. A plain
   `.bkv2 p` selector (0,2,0) outranks single-class component rules like
   `.conf-subtitle { margin: 0 auto }` (0,1,0) and silently strips their
   auto-centring and spacing. */
:where(.bkv2) :where(h1, h2, h3, p) {
    margin: 0;
}

.bkv2 button,
.bkv2 input,
.bkv2 select,
.bkv2 textarea {
    font-family: inherit;
}

/* Latin runs — emails, times, codes — kept LTR inside an RTL page.
   Taken from the AR reference, which only ships this helper in its RTL file.
   Scoped to [dir="rtl"] because `display: inline-block` makes the run an
   unbreakable box: on an LTR page it needlessly forces long emails onto their
   own line and orphans the preceding word. */
[dir="rtl"] .latin {
    font-family: 'DM Sans', sans-serif;
    direction: ltr;
    unicode-bidi: isolate;
    display: inline-block;
}

/* ── SHELL ────────────────────────────────────────────────────────────────
   Reference: .shell { max-width: 1160px; margin: 0 auto; padding: 32px 24px 64px; }
   ───────────────────────────────────────────────────────────────────────── */
.shell {
    max-width: 1160px;
    margin: 0 auto;
    padding: 32px 24px 64px;
}

/* ── COMMON: section heading with the blue accent bar ─────────────────────── */
.section-head {
    display: flex;
    align-items: center;
    gap: 10px;
    font-weight: 700;
    font-size: 17px;
    color: var(--text);
    margin-bottom: 18px;
}

.section-head::before {
    content: '';
    width: 3px;
    height: 18px;
    background: var(--blue);
    border-radius: 2px;
    flex-shrink: 0;
}

.card {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 28px;
    /* Same 16px rhythm .provider-top and .provider-card already stack on.
       Without it two cards in a row meet border-to-border, and their padding
       reads as one empty band instead of a gap between two sections. */
    margin-bottom: 16px;
}

.card:last-child {
    margin-bottom: 0;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SCREEN 1 — PROVIDER PAGE
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Top bar: language switcher (app also renders a back link here) ──────── */
.provider-top {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 12px 16px;
    margin-bottom: 16px;
    display: flex;
    align-items: center;
    gap: 12px;
}

.provider-top-label {
    font-size: 13px;
    color: var(--muted);
    font-weight: 500;
    margin: 0;
}

.lang-select {
    border: 1px solid var(--border);
    background: white;
    padding: 6px 14px;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    transition: border-color 0.15s;
}

.lang-select:hover,
.lang-select:focus,
.lang-select.show {
    border-color: var(--blue);
    background: white;
    color: var(--text);
    box-shadow: none;
}

/* Bootstrap dropdown caret replaced by the reference's chevron. */
.lang-select.dropdown-toggle::after {
    content: '';
    width: 10px;
    height: 10px;
    border: none;
    margin: 0;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10' fill='none'><path d='M2 3l3 3 3-3' stroke='%236B7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    vertical-align: middle;
}

.lang-menu.dropdown-menu {
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.08);
    padding: 6px;
    margin-top: 6px;
    min-width: 200px;
}

.lang-menu .dropdown-menu-item {
    padding: 8px 10px;
    border-radius: 7px;
    cursor: pointer;
    width: 100%;
    font-size: 13px;
    font-weight: 500;
    color: var(--text);
    transition: background 0.15s;
}

.lang-menu .dropdown-menu-item:hover {
    background: var(--bg);
}


/* ── Provider card ───────────────────────────────────────────────────────── */
.provider-card {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 56px 32px 36px;
    margin-bottom: 16px;
    text-align: center;
    position: relative;
}

.provider-avatar {
    width: 88px;
    height: 88px;
    border-radius: 22px;
    background: white;
    border: 1px solid var(--border);
    margin: 0 auto 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
    overflow: hidden;
}

.provider-avatar img {
    width: 56px;
    height: 56px;
    object-fit: contain;
}

.provider-avatar img.provider-avatar-logo {
    width: 64px;
    height: 64px;
    object-fit: contain;
    padding: 6px;
}

.provider-avatar-fallback {
    width: 100%;
    height: 100%;
    background: linear-gradient(135deg, var(--blue), var(--blue-mid));
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 38px;
    font-weight: 700;
    letter-spacing: -1.5px;
}

.provider-name {
    font-size: 28px;
    font-weight: 700;
    color: var(--text);
    letter-spacing: -0.8px;
    margin-bottom: 10px;
    line-height: 1.3;
}

.provider-tagline {
    font-size: 15px;
    color: var(--muted);
    max-width: 540px;
    margin: 0 auto 22px;
    line-height: 1.65;
}

.provider-show-more {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--blue);
    color: white;
    border: none;
    cursor: pointer;
    padding: 10px 20px;
    border-radius: 9px;
    font-size: 14px;
    font-weight: 600;
    transition: all 0.15s;
    margin-top: 4px;
}

.provider-show-more:hover {
    background: var(--blue-dark);
    color: white;
}

.provider-show-more svg {
    transition: transform 0.3s;
}

.provider-show-more.open svg {
    transform: rotate(180deg);
}

.provider-extra {
    /* Collapsed: show a short bio preview above Show More (not max-height:0,
       which parked the CTA under the avatar with no content between them). */
    max-height: 4.8em;
    overflow: hidden;
    transition: max-height 0.4s ease, margin-top 0.3s, padding-top 0.3s, border-color 0.3s;
    text-align: center;
    color: var(--muted);
    font-size: 14px;
    line-height: 1.7;
    max-width: 540px;
    margin: 0 auto 16px;
}

.provider-extra p {
    margin: 0;
}

.provider-extra.open {
    max-height: 400px;
}

.provider-socials {
    display: flex;
    justify-content: center;
    gap: 10px;
    margin-top: 24px;
    flex-wrap: wrap;
}

.social-icon {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--bg);
    color: var(--muted);
    display: flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    transition: all 0.18s;
    border: 1px solid transparent;
}

.social-icon svg {
    width: 17px;
    height: 17px;
    fill: currentColor;
    display: block;
}

.social-icon:hover {
    background: var(--blue-light);
    color: var(--blue);
    transform: translateY(-2px);
    border-color: color-mix(in srgb, var(--blue) 20%, transparent);
}

/* ── Lone social link ─────────────────────────────────────────────────────
   One chip on its own loses the repetition that makes the row legible and
   reads as a disabled dot, so a single link is rendered as a labelled pill
   instead (see partials/social-links.blade.php). The row is untouched.
   ───────────────────────────────────────────────────────────────────────── */
/* Cornered rather than centred: stacked under .provider-show-more it read as a
   second CTA competing with it. Pushed to the card's bottom inline-end corner
   it leaves the centre column to name + primary action and reads as the aside
   it is. Kept in the flow rather than absolutely positioned — an expanded bio
   is centred and full-width, and would run underneath a floating chip.
   flex-end resolves to the left corner under RTL on its own. */
.provider-socials--solo {
    justify-content: flex-end;
    margin-top: 18px;
    margin-bottom: -8px;
}

/* Sized a step below .provider-show-more on purpose: it sits directly under
   that primary button, so a same-weight pill would read as a second, competing
   CTA. Tinted rather than filled for the same reason. */
.social-pill {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 14px;
    border-radius: 100px;
    background: var(--bg);
    color: var(--muted);
    border: 1px solid var(--border);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    transition: all 0.18s;
}

.social-pill svg {
    width: 15px;
    height: 15px;
    fill: currentColor;
    display: block;
    flex-shrink: 0;
}

.social-pill:hover {
    background: var(--blue-light);
    border-color: color-mix(in srgb, var(--blue) 25%, transparent);
    color: var(--blue);
    text-decoration: none;
}

/* WhatsApp keeps its own green, but only as a tint — enough to name the
   channel without shouting over the booking flow. */
.social-pill--whatsapp {
    background: color-mix(in srgb, #25D366 10%, #ffffff);
    border-color: color-mix(in srgb, #25D366 28%, transparent);
    color: #128C4A;
}

.social-pill--whatsapp:hover {
    background: color-mix(in srgb, #25D366 18%, #ffffff);
    border-color: color-mix(in srgb, #25D366 45%, transparent);
    color: #0E7038;
}

/* On a dark branded hero the neutral pill would disappear; the WhatsApp tint
   is already a near-white chip, so it reads fine on dark and is left alone. */
.provider-card.is-branded .social-pill:not(.social-pill--whatsapp) {
    background: rgba(255, 255, 255, 0.14);
    border-color: rgba(255, 255, 255, 0.3);
    color: #fff;
}

.provider-card.is-branded .social-pill:not(.social-pill--whatsapp):hover {
    background: rgba(255, 255, 255, 0.26);
    border-color: rgba(255, 255, 255, 0.45);
    color: #fff;
}

.provider-card.is-branded.is-light .social-pill:not(.social-pill--whatsapp) {
    background: var(--bg);
    border-color: var(--border);
    color: var(--text);
}

.provider-card.is-branded.is-light .social-pill:not(.social-pill--whatsapp):hover {
    background: var(--blue-light);
    border-color: color-mix(in srgb, var(--blue) 35%, transparent);
    color: var(--blue);
}

.provider-meta {
    display: flex;
    justify-content: center;
    gap: 28px;
    margin-top: 24px;
    flex-wrap: wrap;
}

.provider-meta-item {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--muted);
}

.provider-meta-item svg {
    color: var(--blue);
}

/* App-only: vendor cover image / pattern. The reference has no cover, so the
   card keeps its geometry and the cover is inset as a banner; the avatar then
   overlaps it the way the app has always done. */
.provider-card.has-cover {
    padding-top: 0;
    overflow: hidden;
}

.provider-cover {
    height: 180px;
    margin: 0 -32px 0;
    background: var(--brand-header-bg);
    overflow: hidden;
}

.provider-cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.provider-card.has-cover .provider-avatar {
    margin-top: -44px;
    position: relative;
    z-index: 2;
    border-width: 3px;
    border-color: white;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}

/* App-only: branded hero. Same card geometry as .provider-card, with the
   vendor's background image/gradient and light-on-dark text. */
.provider-card.is-branded {
    border-color: transparent;
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
}

.provider-card.is-branded .provider-name {
    color: #fff;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
}

.provider-card.is-branded .provider-tagline,
.provider-card.is-branded .provider-extra {
    color: rgba(255, 255, 255, 0.9);
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

.provider-card.is-branded .social-icon {
    background: rgba(255, 255, 255, 0.14);
    color: rgba(255, 255, 255, 0.9);
}

.provider-card.is-branded .social-icon:hover {
    background: rgba(255, 255, 255, 0.26);
    color: #fff;
    border-color: rgba(255, 255, 255, 0.35);
}

/* Branded hero with the "none" background type is a plain white card, so it
   keeps the reference's own light treatment. */
.provider-card.is-branded.is-light {
    border-color: var(--border);
}

.provider-card.is-branded.is-light .provider-name {
    color: var(--text);
    text-shadow: none;
}

.provider-card.is-branded.is-light .provider-tagline,
.provider-card.is-branded.is-light .provider-extra {
    color: var(--muted);
    text-shadow: none;
}

.provider-card.is-branded.is-light .social-icon {
    background: var(--bg);
    color: var(--muted);
}

.provider-card.is-branded.is-light .social-icon:hover {
    background: var(--blue-light);
    color: var(--blue);
    border-color: color-mix(in srgb, var(--blue) 20%, transparent);
}

/* ── Services list ───────────────────────────────────────────────────────── */
.services-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.service-card {
    background: white;
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 18px;
    display: flex;
    flex-wrap: wrap;
    gap: 18px;
    cursor: pointer;
    transition: all 0.18s;
    align-items: flex-start;
    position: relative;
}

.service-card:hover {
    border-color: var(--blue);
    box-shadow: 0 8px 28px color-mix(in srgb, var(--blue) 8%, transparent);
    transform: translateY(-2px);
}

.service-img {
    width: 100px;
    height: 100px;
    border-radius: 12px;
    flex-shrink: 0;
    background: linear-gradient(135deg, #EEF4FF, #DBEAFE);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 38px;
    overflow: hidden;
    color: var(--blue);
}

.service-img img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: #F8FAFC;
    display: block;
}

.service-content {
    flex: 1;
    min-width: 0;
}

.service-top-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 6px;
}

.service-name {
    font-size: 17px;
    font-weight: 700;
    color: var(--text);
    letter-spacing: -0.3px;
    line-height: 1.3;
    /* An unusually long title combined with .service-price's flex-shrink:0
       squeezed this column down toward min-width:0, and overflow-wrap:break-word
       (set below, shared with .service-desc etc.) then had to split almost
       every word to fit the narrow result. Capping it at 2 lines keeps the
       column — and the wrap — from collapsing that far in the first place. */
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.service-price {
    font-size: 18px;
    font-weight: 700;
    color: var(--blue);
    white-space: nowrap;
    flex-shrink: 0;
}

.service-price-unit {
    font-size: 12px;
    font-weight: 500;
    color: var(--muted);
    margin-left: 2px;
}

.service-meta-row {
    display: flex;
    gap: 10px;
    align-items: center;
    margin-bottom: 10px;
    flex-wrap: wrap;
}

.service-pill {
    background: var(--bg);
    border: 1px solid var(--border);
    padding: 4px 10px;
    border-radius: 100px;
    font-size: 12px;
    font-weight: 500;
    color: var(--muted);
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

.service-pill svg,
.service-pill i {
    color: var(--blue);
}

.service-desc {
    font-size: 13px;
    color: var(--muted);
    line-height: 1.6;
    margin: 0;
    /* Body copy in the card's text column, so it follows the reading direction
       like the name and the meta chips above it — start, not centre. Works for
       Arabic without an RTL override.

       flex:1 1 100% and width:100% were here to give the description its own
       full-width row when it sat outside .service-content on the service list.
       It sits inside that column now, on every surface that uses this class, so
       both are gone: as a block child the width is already 100%, and the flex
       basis only ever applied to the one case that was misplaced. */
    text-align: start;
}

.service-desc:empty {
    display: none;
}

.service-arrow {
    color: var(--muted-light);
    flex-shrink: 0;
    margin-top: 4px;
    transition: transform 0.2s, color 0.2s;
}

.service-card:hover .service-arrow {
    color: var(--blue);
    transform: translateX(4px);
}

/* App-only: in-flight state while the service URL is being navigated to. */
.service-card-loader {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.55);
    border-radius: inherit;
    z-index: 10;
}

.service-card-spinner {
    width: 22px;
    height: 22px;
    border: 3px solid var(--blue-light);
    border-top-color: var(--blue);
    border-radius: 50%;
    animation: bkv2-spin 0.7s linear infinite;
}

@keyframes bkv2-spin {
    to {
        transform: rotate(360deg);
    }
}

/* ── Agents list ─────────────────────────────────────────────────────────
   The agent list is the services list with a person in each row, so it reuses
   .service-card wholesale; only the thumbnail becomes a round avatar.
   ───────────────────────────────────────────────────────────────────────── */
.service-img.is-avatar {
    border-radius: 50%;
}

.service-img.is-avatar img {
    border-radius: 50%;
}

/* A person in a list row is an identifier, not artwork: the 100px square that
   suits a service thumbnail becomes a dominating disc next to a name and one
   line of bio, so agent avatars run smaller. */
.agent-card .service-img.is-avatar {
    width: 64px;
    height: 64px;
    font-size: 26px;
}

/* Photo-less agent: the .provider-avatar-fallback treatment at list scale —
   the person's initial on the blue gradient, inheriting whatever shape the
   surrounding .service-img has. */
.service-img-initial {
    width: 100%;
    height: 100%;
    background: linear-gradient(135deg, var(--blue), var(--blue-mid));
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Inherited so the 72px mobile card's smaller type carries through. */
    font-size: inherit;
    font-weight: 700;
    letter-spacing: -1.5px;
    line-height: 1;
}

/* No price sits opposite the name here, so let it use the full row. */
.agent-card .service-top-row {
    display: block;
}

/* ── App-only: empty state ───────────────────────────────────────────────── */
.empty-state {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 56px 28px;
    text-align: center;
}

.empty-state img {
    width: 100px;
    height: auto;
    margin-bottom: 20px;
    opacity: 0.7;
}

.empty-state-title {
    font-size: 17px;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 6px;
}

.empty-state-sub {
    font-size: 14px;
    color: var(--muted);
}

/* ── App-only: profile video ─────────────────────────────────────────────── */
/* The player stands on its own — no card wrapper. Its internals only existed in
   booking.css, which v2 does not load, so the whole control layer rendered
   unstyled here; ported over with the blue ramp and neutrals coming from the v2
   tokens instead of hard-coded hexes. */
.custom-video-player {
    position: relative;
    width: 100%;
    margin-bottom: 16px;
    border-radius: 14px;
    overflow: hidden;
    background: #000;
    user-select: none;
    -webkit-user-select: none;
}

.custom-video-player video {
    width: 100%;
    display: block;
    cursor: pointer;
    aspect-ratio: 16 / 9;
    object-fit: contain;
    -webkit-touch-callout: none;
}

/* ── Skeleton, shown until the video reports its dimensions ──────────────── */
/* Purely decorative, and it sits above the play overlay — so it must never
   swallow the click that starts the video, even if it is still showing. */
.video-skeleton {
    position: absolute;
    inset: 0;
    z-index: 5;
    background: var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    pointer-events: none;
    transition: opacity 0.35s ease;
}

.video-skeleton::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(110deg, transparent 25%, rgba(255, 255, 255, 0.7) 50%, transparent 75%);
    background-size: 200% 100%;
    animation: videoSkeletonShimmer 1.6s linear infinite;
}

.video-skeleton.hidden {
    opacity: 0;
    pointer-events: none;
}

/* Size, colour and glyph come from the shared disc rule further down, so the
   placeholder is exactly the play button that replaces it — only faded. */
.video-skeleton-icon {
    position: relative;
    opacity: 0.3;
}

@keyframes videoSkeletonShimmer {
    0% {
        background-position: 200% 0;
    }

    100% {
        background-position: -200% 0;
    }
}

/* ── Controls ────────────────────────────────────────────────────────────── */
.video-controls {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0.4) 70%, transparent 100%);
    padding: 20px 16px 12px;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.custom-video-player:hover .video-controls,
.custom-video-player.show-controls .video-controls {
    opacity: 1;
}

.video-progress-container {
    position: relative;
    width: 100%;
    height: 6px;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 3px;
    cursor: pointer;
    margin-bottom: 12px;
}

.video-progress {
    position: relative;
    height: 100%;
    width: 0;
    background: var(--blue);
    border-radius: 3px;
    transition: width 0.1s linear;
}

.video-progress::after {
    content: '';
    position: absolute;
    right: -6px;
    top: 50%;
    transform: translateY(-50%);
    width: 12px;
    height: 12px;
    background: white;
    border-radius: 50%;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: opacity 0.2s;
}

.video-progress-container:hover .video-progress::after {
    opacity: 1;
}

.video-controls-bottom {
    display: flex;
    align-items: center;
    gap: 12px;
}

.video-control-btn {
    background: transparent;
    border: none;
    color: white;
    cursor: pointer;
    padding: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    outline: none;
    transition: transform 0.2s, opacity 0.3s;
}

.video-control-btn:hover {
    transform: scale(1.1);
    opacity: 0.8;
}

.video-control-btn svg {
    width: 24px;
    height: 24px;
    fill: currentColor;
}

.video-time {
    color: white;
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
}

.video-spacer {
    flex: 1;
}

.video-volume-container {
    display: flex;
    align-items: center;
    gap: 8px;
}

.video-volume-slider {
    position: relative;
    width: 0;
    height: 4px;
    background: rgba(255, 255, 255, 0.3);
    border-radius: 2px;
    cursor: pointer;
    overflow: hidden;
    transition: width 0.3s ease;
}

.video-volume-container:hover .video-volume-slider {
    width: 60px;
}

.video-volume-progress {
    height: 100%;
    width: 100%;
    background: white;
    border-radius: 2px;
}

/* ── Play overlay ────────────────────────────────────────────────────────
   The skeleton's placeholder icon is the same disc, so both are sized here —
   one rule, and they cannot drift apart.
   ───────────────────────────────────────────────────────────────────────── */
.video-play-overlay,
.video-skeleton-icon {
    width: 70px;
    height: 70px;
    background: var(--blue);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    /* The skeleton icon is a flex item; without this it can be squeezed below
       70px and stop matching the play button it stands in for. */
    flex-shrink: 0;
}

.video-play-overlay svg,
.video-skeleton-icon svg {
    width: 32px;
    height: 32px;
    fill: white;
}

.video-play-overlay {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.35);
    transition: opacity 0.3s, transform 0.3s, filter 0.2s;
}

.custom-video-player.paused .video-play-overlay {
    opacity: 0.92;
    pointer-events: all;
}

.video-play-overlay:hover {
    transform: translate(-50%, -50%) scale(1.1);
    filter: brightness(1.15);
    opacity: 1;
}

@media (max-width: 768px) {
    .video-controls {
        padding: 16px 12px 10px;
    }

    .video-control-btn svg {
        width: 20px;
        height: 20px;
    }

    .video-volume-container:hover .video-volume-slider {
        width: 50px;
    }

    .video-play-overlay,
    .video-skeleton-icon {
        width: 60px;
        height: 60px;
    }
}

/* ── RTL ─────────────────────────────────────────────────────────────────── */
[dir="rtl"] .service-arrow {
    transform: scaleX(-1);
}

[dir="rtl"] .service-card:hover .service-arrow {
    transform: scaleX(-1) translateX(-4px);
}

[dir="rtl"] .service-price-unit {
    margin-left: 0;
    margin-right: 2px;
}

/* ── RESPONSIVE ───────────────────────────────────────────────────────────
   The reference has a single breakpoint at 880px.
   ───────────────────────────────────────────────────────────────────────── */
@media (max-width: 880px) {
    .shell {
        padding: 20px 14px 40px;
    }

    .provider-card {
        padding: 28px 18px 22px;
    }

    .provider-card.has-cover {
        padding-top: 0;
    }

    .provider-cover {
        margin-left: -18px;
        margin-right: -18px;
    }

    /* Every component below this line was still rendering at its full
       desktop size on mobile (no override existed at all) — trimmed down
       together, in this one shared breakpoint, instead of per page. */
    .provider-avatar {
        width: 72px;
        height: 72px;
        border-radius: 18px;
        margin-bottom: 18px;
    }

    .provider-avatar img {
        width: 46px;
        height: 46px;
    }

    .provider-avatar img.provider-avatar-logo {
        width: 52px;
        height: 52px;
    }

    .provider-avatar-fallback {
        font-size: 30px;
    }

    .provider-name {
        font-size: 22px;
        margin-bottom: 8px;
    }

    .provider-tagline {
        font-size: 13.5px;
        margin-bottom: 18px;
    }

    .section-head {
        font-size: 15.5px;
        margin-bottom: 14px;
    }

    .service-card {
        padding: 14px;
        gap: 12px;
    }

    .service-img {
        width: 64px;
        height: 64px;
        font-size: 24px;
    }

    .agent-card .service-img.is-avatar {
        width: 56px;
        height: 56px;
        font-size: 22px;
    }

    .service-name {
        font-size: 15.5px;
    }

    .service-price {
        font-size: 16px;
    }

    /* Name and price sat side by side on the same row, so the name's column
       only had the sliver left after the icon and the price — the 2-line
       clamp then had so little width to work with that a long title showed
       as two or three unreadable 3-4 letter fragments ("The" / "Ex..."
       instead of anything legible. Stacking the price under the name gives
       the name the whole card width to clamp into, so the two lines it gets
       actually carry useful text. */
    .service-top-row {
        flex-direction: column;
        align-items: flex-start;
        gap: 4px;
    }

    .card {
        padding: 18px;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   SCREEN 2 — SERVICE DETAIL + TIME SELECTION
   ═══════════════════════════════════════════════════════════════════════════ */

.screen2 {
    display: grid;
    grid-template-columns: 1fr 1.3fr;
    gap: 20px;
    align-items: start;
}

/* A grid item's automatic minimum size is its min-content width, so one
   unbreakable run of characters in any card widens the whole track and the
   page picks up a horizontal scrollbar. min-width:0 lets the column shrink and
   hand the wrapping back to the text. */
.screen2 > * {
    min-width: 0;
}

/* Single-slot services hide the day/time column entirely, so the remaining
   column is centred at the left column's natural width. */
.screen2.is-single {
    grid-template-columns: minmax(0, 460px);
    justify-content: center;
}

/* …and the back button lines up with that column's left edge, rather than
   sitting far out at the edge of the full-width shell. */
.booking-datepicker-v2.is-single-slot .back-row {
    max-width: 460px;
    margin-inline: auto;
}

/* ── Selected service summary ────────────────────────────────────────────── */
.selected-service {
    background: white;
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 18px;
    display: flex;
    gap: 16px;
    align-items: center;
    margin-bottom: 16px;
}

/* Single-slot services add date/time rows under the header. The card then stacks:
   an image+name row, then full-width rows — so the thumbnail stays beside the
   service name instead of centring against a much taller column. */
.selected-service:has(.booking-info-simple) {
    display: block;
}

.selected-service-head {
    display: flex;
    gap: 16px;
    align-items: center;
}

.selected-service .service-img {
    width: 76px;
    height: 76px;
    font-size: 28px;
    border-radius: 10px;
}

.selected-service .service-img img {
    cursor: zoom-in;
}

.selected-service-info {
    flex: 1;
    min-width: 0;
}

.selected-service-name {
    font-size: 16px;
    font-weight: 700;
    margin-bottom: 6px;
    letter-spacing: -0.3px;
    color: var(--text);
    line-height: 1.35;
}

.selected-service-meta {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
}

/* ── Location options ────────────────────────────────────────────────────
   The app drives this with real <input type="radio"> elements (page JS mirrors
   the choice into #selected_location). The input stays in the DOM and keeps
   firing `change`; it is only visually replaced by the reference's own radio.
   ───────────────────────────────────────────────────────────────────────── */
.location-options {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.location-option {
    background: white;
    border: 1.5px solid var(--border);
    border-radius: 12px;
    padding: 16px;
    cursor: pointer;
    transition: all 0.15s;
    display: flex;
    gap: 14px;
    align-items: flex-start;
    position: relative;
    margin: 0;
}

.location-input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    pointer-events: none;
}

.location-option:has(.location-input:checked) {
    border-color: var(--blue);
    background: var(--blue-light);
}

.location-radio {
    width: 18px;
    height: 18px;
    border: 1.5px solid var(--border);
    border-radius: 50%;
    flex-shrink: 0;
    background: white;
    margin-top: 14px;
    position: relative;
}

.location-option:has(.location-input:checked) .location-radio {
    border-color: var(--blue);
}

.location-option:has(.location-input:checked) .location-radio::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--blue);
}

.location-input:focus-visible ~ .location-radio {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}

.location-icon {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    background: var(--blue-light);
    color: var(--blue);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    margin-top: 0;
    font-size: 20px;
}

.location-option:has(.location-input:checked) .location-icon {
    background: white;
}

.location-info {
    flex: 1;
    padding-top: 2px;
    min-width: 0;
}

.location-name {
    font-size: 14px;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 4px;
}

.location-option:has(.location-input:checked) .location-name {
    color: var(--blue);
}

.location-desc {
    font-size: 12.5px;
    color: var(--muted);
    line-height: 1.5;
    display: block;
}

/* Fixed online location (vendor did not enable the choice) — same anatomy,
   presented as a static row rather than a selectable option. */
.location-static {
    display: flex;
    gap: 14px;
    align-items: flex-start;
}

.location-badge {
    display: inline-flex;
    align-items: center;
    background: var(--blue-light);
    color: var(--blue);
    font-size: 12px;
    font-weight: 600;
    padding: 4px 12px;
    border-radius: 100px;
    margin-bottom: 8px;
}

.location-note {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-top: 12px;
    padding: 10px 12px;
    background: var(--blue-light);
    border-radius: 10px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--blue);
}

.location-note i {
    margin-top: 2px;
    flex-shrink: 0;
}

/* ── Timezone ────────────────────────────────────────────────────────────── */
.timezone-card {
    background: white;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 18px;
    margin-bottom: 16px;
}

.timezone-label {
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 10px;
    color: var(--text);
    display: block;
}

/* The timezone picker is the shared <x-searchable-select> component. Passing an
   :icon puts it in the component's `.ss-dd--icon` variant, which is the compact
   inline filter-pill used in dashboard toolbars (auto width, 40px tall, 13px,
   600-weight truncated label). Here it has to read as a full-width form control,
   so every pill-specific declaration is unwound back to the reference's
   .timezone-select. */
.timezone-card .ss-dd,
.timezone-card .ss-dd--icon {
    display: block;
    width: 100%;
    flex-shrink: 1;
    position: relative;
}

.timezone-card .ss-dd .ss-trigger,
.timezone-card .ss-dd--icon .ss-trigger {
    width: 100%;
    height: auto;
    background: var(--bg);
    border: 1.5px solid var(--border);
    padding: 12px 14px;
    border-radius: 10px;
    font-size: 14px;
    font-weight: 400;
    /* The reference's .timezone-select is a div inheriting body line-height;
       a <button> would default to `normal` and come out shorter. */
    line-height: 1.55;
    color: var(--text);
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 10px;
    text-align: start;
    transition: all 0.15s;
}

.timezone-card .ss-dd .ss-trigger:hover,
.timezone-card .ss-dd .ss-trigger.is-open,
.timezone-card .ss-dd--icon .ss-trigger:hover,
.timezone-card .ss-dd--icon .ss-trigger.is-open {
    border-color: var(--blue);
    color: var(--text);
}

.timezone-card .ss-trigger-icon,
.timezone-card .ss-dd--icon .ss-trigger:hover .ss-trigger-icon {
    display: inline-flex;
    color: var(--muted);
    flex-shrink: 0;
}

/* The pill variant pins the label to `flex: none; max-width: 160px; font-weight: 600`. */
.timezone-card .ss-dd .ss-trigger-label,
.timezone-card .ss-dd--icon .ss-trigger-label {
    flex: 1;
    min-width: 0;
    max-width: none;
    font-weight: 400;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.timezone-card .ss-chevron {
    color: var(--muted);
    flex-shrink: 0;
}

/* Panel matches the trigger's width instead of the pill's `max-content`. */
.timezone-card .ss-dd .ss-panel,
.timezone-card .ss-dd--icon .ss-panel {
    left: 0;
    right: 0;
    width: auto;
    min-width: 0;
    max-width: none;
}

/* ── Calendar ────────────────────────────────────────────────────────────
   The calendar markup is generated at runtime by objCalender() in
   booking/layouts/footer.blade.php, which is shared with the reschedule flow
   and must not change. These rules map its emitted class names onto the
   reference's .cal-* system one-for-one.
     .calendar-controls  → .cal-nav-row      .calendar-body       → .cal-grid
     .calendar-prev/next → .cal-nav-btn      .calendar-body > div → .cal-day-cell
     .calendar-*-label   → .cal-month        .number-item         → .avail
                                             .number-item.border-blue → .selected
   ───────────────────────────────────────────────────────────────────────── */
.calendar-card {
    background: white;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 24px;
    margin-bottom: 16px;
}

.cal-header {
    text-align: center;
    font-size: 15px;
    font-weight: 600;
    margin-bottom: 14px;
    color: var(--text);
}

.calendar-card .calendar-controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 14px;
}

.calendar-card .calendar-prev a,
.calendar-card .calendar-next a {
    width: 32px;
    height: 32px;
    border: 1px solid var(--border);
    background: white;
    border-radius: 8px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--muted);
    transition: all 0.15s;
    text-decoration: none;
}

.calendar-card .calendar-prev a:hover,
.calendar-card .calendar-next a:hover {
    border-color: var(--blue);
    color: var(--blue);
}

/* The generated markup ships a PNG arrow; replace it with the reference's
   chevron, masked so it inherits the (brandable) currentColor. */
.calendar-card .calendar-prev a img,
.calendar-card .calendar-next a img {
    display: none;
}

.calendar-card .calendar-prev a::after,
.calendar-card .calendar-next a::after {
    content: '';
    width: 14px;
    height: 14px;
    background-color: currentColor;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
}

.calendar-card .calendar-prev a::after {
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14' fill='none'><path d='M9 11L5 7l4-4' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14' fill='none'><path d='M9 11L5 7l4-4' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/></svg>");
}

.calendar-card .calendar-next a::after {
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14' fill='none'><path d='M5 3l4 4-4 4' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14' fill='none'><path d='M5 3l4 4-4 4' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/></svg>");
}

/* Flex already places previous on the right and next on the left in RTL.
   Mirror the chevrons so each one points the way that button moves. */
[dir=rtl] .calendar-card .calendar-prev a::after,
[dir=rtl] .calendar-card .calendar-next a::after {
    transform: scaleX(-1);
}

.calendar-card .calendar-year-month {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 4px;
    flex: 1;
}

.calendar-card .calendar-month-label {
    font-size: 16px;
    font-weight: 700;
    color: var(--text);
}

.calendar-card .calendar-year-label {
    font-size: 16px;
    font-weight: 600;
    color: var(--muted-light);
}

/* The generated "اليوم: …" line has no counterpart in the reference, so it is
   hidden rather than removed: plotSelectors() emits it and attachEvents() binds
   a click listener to it with no null guard, so deleting the node would throw
   and break the calendar on every page sharing that script. */
.calendar-card .calendar-today-date {
    display: none;
}

.calendar-card .calendar-body {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 4px;
}

/* RTL-only. Arabic weekday labels will not shrink below their text, so
   with the 4px gaps the day grid is wider than the card at 320px. Let the
   calendar scroll sideways instead of closing that gap. The controls are
   only as wide as the card, so the month arrows stay put while the days move. */
[dir=rtl] .calendar-card .position-relative,
[dir=rtl] .calendar-card .calendar,
[dir=rtl] .calendar-card .calendar-inner {
    min-width: 0;
    max-width: 100%;
}

[dir=rtl] .calendar-card .calendar-inner {
    overflow-x: auto;
    /* Setting overflow-x makes overflow-y auto too. The day cells scale in with a slight
       overshoot, which overflowed by 1px and flashed a scrollbar on every load. */
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
}

[dir=rtl] .calendar-card .calendar-body {
    width: max-content;
    min-width: 100%;
}

/* While the day cells scale in (the stagger ends near 0.5s) nothing may scroll, or a
   scrollbar flashes and the card changes size. Hand scrolling back once it has settled. */
@keyframes bkv2-cal-settle {
    from, 99% { overflow-x: hidden; }
    to        { overflow-x: auto; }
}

[dir=rtl] .calendar-card .calendar.fade-in .calendar-inner {
    animation: bkv2-cal-settle 0.7s linear;
}

/* Base cell — the reference's .cal-day-cell */
.calendar-card .calendar-body > div {
    aspect-ratio: 1.2;
    border-radius: 100px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    font-weight: 500;
    cursor: default;
    color: var(--muted-light);
    transition: all 0.12s;
    background: transparent;
}

/* First row is the day-name header — the reference's .cal-dow-cell */
.calendar-card .calendar-body > div:nth-child(-n + 7) {
    aspect-ratio: auto;
    text-align: center;
    font-size: 11px;
    font-weight: 700;
    color: var(--muted-light);
    padding: 6px 0;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    border-radius: 0;
}

.calendar-card .calendar-body .dateNumber {
    color: inherit;
    text-decoration: none;
    font: inherit;
    line-height: 1;
}

.calendar-card .calendar-body ul {
    display: none;
}

/* Bookable day — the reference's .cal-day-cell.avail: no fill, just darker text
   and a pointer, tinting only on hover. */
.calendar-card .calendar-body > .number-item {
    background: transparent;
    color: var(--text);
    cursor: pointer;
    font-weight: 600;
}

.calendar-card .calendar-body > .number-item:hover {
    background: var(--blue-light);
    color: var(--blue);
}

/* Selected day — the reference's .cal-day-cell.selected: solid blue fill. */
.calendar-card .calendar-body > .number-item.border-blue,
.calendar-card .calendar-body > .number-item.selected {
    background: var(--blue);
    color: white;
    font-weight: 700;
}

.calendar-card .calendar-body > .number-item.border-blue .dateNumber,
.calendar-card .calendar-body > .number-item.selected .dateNumber {
    color: white;
}

/* Off day — a day inside this month the vendor is not taking bookings on.
   This is the reference's .cal-day-cell.weekend: tinted --blue-light, inert. */
.calendar-card .calendar-body > .disable-dates {
    background: var(--blue-light);
    color: var(--blue);
    cursor: default;
    font-weight: 500;
}

.calendar-card .calendar-body > .disable-dates .dateNumber {
    color: var(--blue);
    cursor: default;
}

/* Adjacent-month padding cells — the reference's plain .cal-day-cell. */
.calendar-card .calendar-body > .prev-dates,
.calendar-card .calendar-body > .next-dates {
    background: transparent;
    color: var(--muted-light);
    cursor: default;
    font-weight: 500;
}

.calendar-card .calendar-body > .prev-dates .dateNumber,
.calendar-card .calendar-body > .next-dates .dateNumber {
    color: var(--muted-light);
    cursor: default;
}

/* ── Time slots ──────────────────────────────────────────────────────────── */
.time-card {
    background: white;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 24px;
}

.time-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 18px;
    gap: 12px;
    flex-wrap: wrap;
}

.time-title {
    font-size: 17px;
    font-weight: 700;
    color: var(--text);
    margin: 0;
}

.time-duration {
    font-size: 13px;
    color: var(--muted);
}

.time-duration strong {
    color: var(--text);
    font-weight: 700;
}

.time-card .times-container {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* .click_time is the generated anchor for one bookable slot. Laid out as a
   centred flex row so the spinner the shared handler appends on submit — and the
   selected-time tick — sit beside the label instead of wrapping under it. */
.time-card .click_time {
    background: white;
    border: 1.5px solid var(--border);
    padding: 14px;
    border-radius: 10px;
    text-align: center;
    font-size: 14px;
    font-weight: 600;
    color: var(--blue);
    cursor: pointer;
    transition: all 0.12s;
    text-decoration: none;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    position: relative;
}

/* Sized to sit with 14px text. Border thins proportionally with the diameter so
   the ring keeps its hole. The `0 auto` from the base rule is cleared — auto
   margins absorb free space in a flex row and would shove it to the edge. */
.time-card .click_time .times-loader {
    width: 15px;
    height: 15px;
    border-width: 2px;
    margin: 0;
    flex-shrink: 0;
}

/* The Continue button carries the busy state on both branches — plain booking and
   reschedule alike — so the spinner the shared handler appends inside the slot is
   a redundant second indicator. */
#timesContainer .click_time .times-loader {
    display: none;
}

.time-card .click_time:hover {
    background: var(--blue-light);
}

.time-card .click_time.border-blue,
.time-card .click_time.selected {
    background: var(--blue);
    border-color: var(--blue);
    color: white;
}

.time-card .click_time.disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Spacing comes from .click_time's flex gap. */
.selected_time {
    flex-shrink: 0;
}

.ramadan-next-day-badge {
    position: absolute;
    top: -5px;
    inset-inline-end: -8px;
    font-size: 11px;
    padding: 5px 10px;
    border-radius: 88px;
    background: var(--blue);
    color: white;
    font-weight: 600;
}

.notimeAvilabale {
    text-align: center;
    background: #FEF2F2;
    color: #B91C1C;
    border: 1px solid #FECACA;
    font-weight: 500;
    font-size: 13px;
    width: 100%;
    border-radius: 10px;
    padding: 14px;
}

/* ── Description ─────────────────────────────────────────────────────────── */
.description-card {
    margin-top: 16px;
}

.description-text {
    font-size: 14px;
    color: var(--text);
    line-height: 1.75;
    /* Vendors paste descriptions we do not control. A run of characters with no
       spaces has nowhere to break, so it renders as one very long line. Both
       properties are kept: overflow-wrap is the standard, word-break is the
       legacy alias older Safari understands. See also the min-width:0 on the
       screen2/screen3 grid items, which is what stops the column itself from
       being widened by that line. */
    overflow-wrap: break-word;
    word-break: break-word;
}

.description-text ol,
.description-text ul {
    padding-left: 20px;
}

[dir="rtl"] .description-text ol,
[dir="rtl"] .description-text ul {
    padding-left: 0;
    padding-right: 20px;
}

.description-text ol li,
.description-text ul li {
    margin-bottom: 6px;
}

.description-text p {
    margin-bottom: 10px;
}

.description-text p:last-child {
    margin-bottom: 0;
}

/* "Show more" clamp. Vendors paste descriptions of any length, so the text is
   capped on every screen size, not just mobile — an unbounded one pushed the
   whole page down past the booking controls. The toggle stays hidden until the
   script measures the text and finds it actually overflows the clamp, so a
   short description shows no button at all. */
.collapsed-text {
    overflow: hidden;
    max-height: 200px;
}

.collapsed-text.expanded {
    max-height: none;
}

.description-toggle {
    display: none;
    background: none;
    border: none;
    padding: 0;
    margin-top: 12px;
    color: var(--blue);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    align-items: center;
    gap: 6px;
}

/* Added by the script only when the description is taller than its clamp. */
.description-card.is-clamped .description-toggle {
    display: inline-flex;
}

/* ── Continue button ─────────────────────────────────────────────────────── */
.continue-btn-wrap {
    margin-top: 24px;
}

.continue-btn {
    width: 100%;
    background: var(--blue);
    color: white;
    padding: 16px;
    border: none;
    border-radius: 11px;
    font-size: 15px;
    font-weight: 700;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    transition: all 0.15s;
    box-shadow: 0 4px 16px color-mix(in srgb, var(--blue) 20%, transparent);
}

.continue-btn:hover {
    background: var(--blue-dark);
    color: white;
    transform: translateY(-1px);
    box-shadow: 0 8px 24px color-mix(in srgb, var(--blue) 30%, transparent);
}

.continue-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    transform: none;
}

/* sv2BtnBusy() disables the button while submitting. Dimmed and inert so the
   state is unmistakable, and pointer-events are dropped so no hover lift or
   pointer survives to make it look clickable. */
.continue-btn.is-busy,
.continue-btn.is-busy:disabled {
    opacity: 0.7;
    cursor: not-allowed;
    pointer-events: none;
    transform: none;
    box-shadow: none;
    /* sv2BtnBusy() puts the spinner before the label, but the arrow it replaces comes
       after it. Reversing the row keeps the spinner where the arrow was, in both directions. */
    flex-direction: row-reverse;
}

.continue-btn svg {
    transition: transform 0.2s;
}

.continue-btn:hover svg {
    transform: translateX(4px);
}

[dir="rtl"] .continue-btn svg {
    transform: scaleX(-1);
}

[dir="rtl"] .continue-btn:hover svg {
    transform: scaleX(-1) translateX(-4px);
}

/* ── App-only: single-slot booking summary ───────────────────────────────
   Date and time are .bs-block rows — the same label/value/divider rhythm as the
   checkout summary — stacked full width under the service header.
   ───────────────────────────────────────────────────────────────────────── */
.booking-info-simple {
    border-top: 1px solid var(--border-light);
    margin-top: 16px;
}

/* .bs-block drops its top padding on the first row, which is right inside the
   checkout card but would collapse the gap under the rule above these. */
.booking-info-simple .bs-block:first-of-type {
    padding-top: 16px;
}

/* ── App-only: loaders ─────────────────────────────────────────────────────
   The fade matches hideLoader()'s 100ms hand-off, so the spinner is fully
   faded by the time it is removed rather than cut mid-transition. */
.loader-wrapper {
    min-height: 200px;
    opacity: 1;
    transition: opacity 0.1s ease-out;
}

.loader-wrapper.fade-out {
    opacity: 0;
}

.spinner-circle {
    width: 44px;
    height: 44px;
    border: 4px solid var(--blue-light);
    border-top-color: var(--blue);
    border-radius: 50%;
    animation: bkv2-spin 0.8s linear infinite;
}

/* ── Reveal ──────────────────────────────────────────────────────────────
   The loader hands off the moment availability lands, so the entrance has to
   carry the transition rather than a long fade. The container rises into
   place, then its cells / slots stagger in on the reference's own entrance
   easing (cubic-bezier(0.34, 1.56, 0.64, 1), used by .conf-check's confPop).
   ───────────────────────────────────────────────────────────────────────── */
.times-container,
.calendar,
#notAvailableTimes {
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.28s ease-out, transform 0.28s ease-out;
}

.times-container.fade-in,
.calendar.fade-in,
#notAvailableTimes.fade-in {
    opacity: 1;
    transform: translateY(0);
}

@keyframes bkv2-cell-in {
    from {
        opacity: 0;
        transform: scale(0.86);
    }
    to {
        opacity: 1;
        transform: scale(1);
    }
}

@keyframes bkv2-slot-in {
    from {
        opacity: 0;
        transform: translateY(6px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* `backwards` holds the start frame through the stagger delay so nothing
   flashes at full opacity before its turn. */
.calendar.fade-in .calendar-body > div {
    animation: bkv2-cell-in 0.3s cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
}

/* Row-by-row stagger. Each rule also matches every later cell, so the cascade
   order gives each seven-cell row its own delay without per-cell selectors. */
.calendar.fade-in .calendar-body > div:nth-child(n + 8)  { animation-delay: 0.035s; }
.calendar.fade-in .calendar-body > div:nth-child(n + 15) { animation-delay: 0.07s; }
.calendar.fade-in .calendar-body > div:nth-child(n + 22) { animation-delay: 0.105s; }
.calendar.fade-in .calendar-body > div:nth-child(n + 29) { animation-delay: 0.14s; }
.calendar.fade-in .calendar-body > div:nth-child(n + 36) { animation-delay: 0.175s; }
.calendar.fade-in .calendar-body > div:nth-child(n + 43) { animation-delay: 0.21s; }

.times-container.fade-in .click_time {
    animation: bkv2-slot-in 0.3s ease-out backwards;
}

.times-container.fade-in .click_time:nth-child(n + 2) { animation-delay: 0.035s; }
.times-container.fade-in .click_time:nth-child(n + 3) { animation-delay: 0.07s; }
.times-container.fade-in .click_time:nth-child(n + 4) { animation-delay: 0.105s; }
.times-container.fade-in .click_time:nth-child(n + 5) { animation-delay: 0.14s; }
.times-container.fade-in .click_time:nth-child(n + 6) { animation-delay: 0.175s; }
.times-container.fade-in .click_time:nth-child(n + 7) { animation-delay: 0.21s; }

@media (prefers-reduced-motion: reduce) {
    .times-container,
    .calendar,
    #notAvailableTimes {
        transform: none;
        transition: opacity 0.15s linear;
    }

    .calendar.fade-in .calendar-body > div,
    .times-container.fade-in .click_time {
        animation: none;
    }
}

/* Same border-ring idiom as .spinner-circle, so the page has one visual language
   for "loading". Colours derive from currentColor, so it reads correctly both on
   a selected slot (white on blue) and on a plain surface. */
.times-loader {
    width: 20px;
    height: 20px;
    border: 2.5px solid color-mix(in srgb, currentColor 28%, transparent);
    border-top-color: currentColor;
    border-radius: 50%;
    margin: 0 auto;
    animation: bkv2-spin 0.7s linear infinite;
}

/* ── App-only: alerts ────────────────────────────────────────────────────── */
.bkv2 .alert {
    border-radius: 10px;
    font-size: 13.5px;
    padding: 12px 14px;
    margin-bottom: 16px;
}

.bkv2 .alert-danger {
    background: #FEF2F2;
    border: 1px solid #FECACA;
    color: #B91C1C;
}

/* ── App-only: timezone mismatch toast ───────────────────────────────────── */
.timezone-toast {
    position: fixed;
    bottom: 24px;
    inset-inline-end: 24px;
    z-index: 60;
    width: 340px;
    max-width: calc(100vw - 32px);
    background: white;
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12);
    padding: 16px;
    flex-direction: column;
    gap: 12px;
    animation: bkv2-toast-in 0.3s ease-out;
}

@keyframes bkv2-toast-in {
    from {
        opacity: 0;
        transform: translateY(12px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.timezone-toast-header {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.timezone-toast-icon {
    width: 34px;
    height: 34px;
    border-radius: 9px;
    background: var(--blue-light);
    color: var(--blue);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.timezone-toast-content p {
    font-size: 13px;
    line-height: 1.5;
    color: var(--text);
    margin: 0;
}

.timezone-toast-close {
    background: none;
    border: none;
    padding: 0;
    color: var(--muted-light);
    cursor: pointer;
    flex-shrink: 0;
    transition: color 0.15s;
}

.timezone-toast-close:hover {
    color: var(--text);
}

.timezone-toast-action {
    width: 100%;
    background: var(--blue);
    color: white;
    border: none;
    border-radius: 9px;
    padding: 10px 16px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s;
}

.timezone-toast-action:hover {
    background: var(--blue-dark);
}

@keyframes fadeOut {
    to {
        opacity: 0;
    }
}

@keyframes slideOutRight {
    to {
        opacity: 0;
        transform: translateX(110%);
    }
}

@keyframes slideOutLeft {
    to {
        opacity: 0;
        transform: translateX(-110%);
    }
}

/* ── SCREEN 2 — RESPONSIVE ───────────────────────────────────────────────── */
@media (max-width: 880px) {
    .screen2 {
        grid-template-columns: 1fr;
    }

    .screen2.is-single {
        grid-template-columns: 1fr;
    }

    .calendar-card,
    .time-card {
        padding: 18px;
    }

    /* Each slot carried the same 14px padding as desktop, so next to the
       compact calendar grid above it (small cells, 4px gaps) it read as
       oversized — lots of empty space around a short "9:00 AM" label.
       Brought down to match that density; still comfortably tappable. */
    .time-card .click_time {
        padding: 10px;
        font-size: 13px;
        border-radius: 8px;
    }

    .time-card .times-container {
        gap: 8px;
    }

    /* Still the most prominent element on the page (primary CTA), just not
       at the same 16px/15px scale as desktop next to the now-compact slots. */
    .continue-btn {
        padding: 13px;
        font-size: 14px;
    }

    .selected-service .service-img {
        width: 64px;
        height: 64px;
    }

    /* Tighter clamp on small screens, where 200px is most of the viewport. */
    .collapsed-text {
        max-height: 140px;
    }

    .timezone-toast {
        inset-inline: 16px;
        width: auto;
        bottom: 16px;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   SCREEN 3 — CHECKOUT
   ═══════════════════════════════════════════════════════════════════════════ */

.checkout-back {
    background: white;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px 18px;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    cursor: pointer;
    margin-bottom: 16px;
    transition: all 0.15s;
    text-decoration: none;
}

.checkout-back:hover {
    border-color: var(--blue);
    color: var(--blue);
    text-decoration: none;
}

.checkout-back svg {
    transition: transform 0.15s;
}

.checkout-back:hover svg {
    transform: translateX(-3px);
}

[dir="rtl"] .checkout-back svg {
    transform: scaleX(-1);
}

[dir="rtl"] .checkout-back:hover svg {
    transform: scaleX(-1) translateX(-3px);
}

.screen3 {
    display: grid;
    grid-template-columns: 1fr 1.3fr;
    gap: 20px;
    align-items: start;
}

/* Same automatic-minimum-size guard as .screen2 above. */
.screen3 > * {
    min-width: 0;
}

/* ── Booking summary ─────────────────────────────────────────────────────── */
.booking-summary {
    background: white;
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 24px;
}

.bs-block {
    padding: 16px 0;
    border-bottom: 1px solid var(--border-light);
}

.bs-block:last-child {
    border-bottom: none;
    padding-bottom: 0;
}

.bs-block:first-of-type {
    padding-top: 0;
}

.bs-label {
    font-size: 10.5px;
    font-weight: 700;
    color: var(--muted);
    letter-spacing: 1.2px;
    text-transform: uppercase;
    margin-bottom: 6px;
}

.bs-value {
    font-size: 15px;
    font-weight: 600;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 8px;
}

.bs-value svg {
    color: var(--text);
    flex-shrink: 0;
}

.bs-meta {
    font-size: 12px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--green-light);
    color: #15803D;
    padding: 4px 10px;
    border-radius: 100px;
    margin-top: 8px;
    font-weight: 600;
}

/* Variants used by the Time and Location blocks in the reference. */
.bs-meta--blue {
    background: var(--blue-light);
    color: var(--blue);
}

.bs-meta--plain {
    background: var(--bg);
    color: var(--muted);
    border: 1px solid var(--border);
}

/* ── Form ────────────────────────────────────────────────────────────────── */
.form-section {
    background: white;
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 24px;
}

.form-field {
    margin-bottom: 16px;
}

.form-field:last-child {
    margin-bottom: 0;
}

.form-label,
.bkv2 .form-label {
    display: block;
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 6px;
}

.form-label .req {
    color: var(--red);
    margin-left: 2px;
}

.form-label .opt {
    color: var(--muted);
    font-weight: 400;
    font-size: 12px;
}

/* `.form-control` is listed alongside so the shared phone partial — which
   hardcodes Bootstrap's class — gets the identical control without forking it. */
.form-input,
.bkv2 .form-control,
.bkv2 textarea.form-control,
.bkv2 .form-select {
    width: 100%;
    background: white;
    border: 1.5px solid var(--border);
    padding: 12px 14px;
    border-radius: 10px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--text);
    transition: all 0.15s;
    font-family: inherit;
}

.form-input::placeholder,
.bkv2 .form-control::placeholder {
    color: var(--muted-light);
}

.form-input:focus,
.bkv2 .form-control:focus,
.bkv2 .form-select:focus {
    outline: none;
    border-color: var(--blue);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 10%, transparent);
}

.form-input.is-invalid,
.bkv2 .form-control.is-invalid {
    border-color: var(--red);
}

.form-input.is-invalid:focus,
.bkv2 .form-control.is-invalid:focus {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--red) 12%, transparent);
}

.bkv2 .invalid-feedback,
.bkv2 small.text-danger {
    font-size: 12px;
    color: var(--red);
    margin-top: 4px;
}

/* ── Phone field ─────────────────────────────────────────────────────────
   The country picker comes from dashboard/settings/phone.blade.php, which is
   shared with the dashboard, so it is restyled here rather than forked: its
   Bootstrap .input-group becomes the reference's .phone-input-row.
   ───────────────────────────────────────────────────────────────────────── */
.phone-input-row,
.bkv2 .form-field .input-group {
    display: flex;
    gap: 8px;
    margin-bottom: 0;
}

.phone-country,
.bkv2 .form-field .input-group > .dropdown-toggle {
    background: white !important;
    border: 1.5px solid var(--border) !important;
    /* Was 12px 14px with an 8px gap — comfortable for "+965" plus a flag and
       a caret, but wider than it needs to be next to the number field, which
       is what the user actually spends their attention typing into. */
    padding: 12px 10px;
    border-radius: 10px !important;
    font-size: 14px;
    font-weight: 600;
    color: var(--text) !important;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    min-width: auto !important;
    transition: border-color 0.15s;
}

.bkv2 .form-field .input-group > .dropdown-toggle:hover,
.bkv2 .form-field .input-group > .dropdown-toggle:focus {
    border-color: var(--blue) !important;
}

.phone-country img,
.bkv2 .form-field .input-group > .dropdown-toggle img {
    width: 20px;
    height: 15px;
    border-radius: 2px;
    object-fit: cover;
    margin: 0 !important;
}

.phone-input,
.bkv2 .form-field .input-group > input[type="tel"] {
    flex: 1;
    min-width: 0;
    border: 1.5px solid var(--border) !important;
    border-radius: 10px !important;
}

/* Digits stay in their own order, but an Arabic placeholder is a sentence.
   text-align on ::placeholder is ignored, so the input itself has to align
   it to the right, beside the country code. */
[dir="rtl"] .phone-input,
[dir="rtl"] .bkv2 .form-field .input-group > input[type="tel"],
[dir="rtl"] .bkv2 .participant-phone {
    text-align: right;
}

.bkv2 .form-field .input-group > .dropdown-menu {
    max-height: 280px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.08);
    padding: 6px;
}

.bkv2 .form-field .input-group > .dropdown-menu .dropdown-item {
    border-radius: 7px;
    font-size: 13px;
    padding: 8px 10px;
}

/* ── Order summary ───────────────────────────────────────────────────────── */
.order-summary {
    background: white;
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 24px;
}

.order-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 4px 0;
    font-size: 14px;
}

.order-row .label {
    color: var(--text);
    font-weight: 500;
}

.order-row .value {
    font-weight: 600;
    color: var(--text);
}

.order-row .value.is-discount {
    color: var(--red);
}

.order-remove {
    background: none;
    border: none;
    padding: 0;
    margin-inline-start: 8px;
    font-size: 12px;
    font-weight: 600;
    color: var(--red);
    cursor: pointer;
    text-decoration: underline;
}

.promo-row {
    display: flex;
    gap: 10px;
    margin-top: 14px;
}

.promo-input-wrap {
    flex: 1;
    /* A text input's default intrinsic min-width ignores its own width:100%
       and resists flex-shrink until this is zeroed — same issue fixed
       elsewhere this pass (.cp-close, .cust-cell, .service-name). Without
       it, .promo-btn got pushed to overlap the input at narrow widths
       instead of the input shrinking to make room, which read as its
       placeholder getting cut off mid-word. */
    min-width: 0;
    position: relative;
}

.promo-input-wrap::before {
    content: '';
    position: absolute;
    inset-inline-start: 12px;
    top: 50%;
    transform: translateY(-50%);
    width: 18px;
    height: 18px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%230069FF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='3 17 9 11 13 15 21 7'></polyline><polyline points='14 7 21 7 21 14'></polyline></svg>");
    background-size: 14px;
    background-position: center;
    background-repeat: no-repeat;
    background-color: var(--blue-light);
    border-radius: 5px;
    pointer-events: none;
    z-index: 2;
}

.promo-input,
.bkv2 .promo-input-wrap .form-control {
    width: 100%;
    min-width: 0;
    /* Without this, width:100% only sized the content box — the 52px of
       left/right padding (for the icon + breathing room) was added on top,
       so the input rendered ~52px wider than its own parent and overlapped
       .promo-btn instead of leaving it room. No global box-sizing reset
       exists on this page, so it's set here directly. */
    box-sizing: border-box;
    background: var(--bg);
    border: 1.5px solid var(--border);
    padding: 11px 14px 11px 38px;
    border-radius: 10px;
    font-size: 14px;
    color: var(--text);
}

/* The input stays dir=ltr so a typed code doesn't reverse. That pinned the
   Arabic placeholder to the left, so align it to the right and keep the icon
   in the padding on that side. The row itself follows the page direction, so
   in Arabic the apply button sits on the other side. */
[dir="rtl"] .promo-input,
[dir="rtl"] .bkv2 .promo-input-wrap .form-control {
    padding: 11px 38px 11px 14px;
    text-align: right;
}

[dir="rtl"] .promo-input-wrap::before {
    inset-inline-start: auto;
    left: auto;
    right: 12px;
}

.promo-btn {
    background: var(--blue);
    color: white;
    border: none;
    cursor: pointer;
    padding: 0 22px;
    border-radius: 10px;
    font-size: 14px;
    font-weight: 600;
    transition: all 0.15s;
    flex-shrink: 0;
    /* Row layout so sv2BtnBusy()'s spinner sits beside the label. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

.promo-btn:hover:not(:disabled) {
    background: var(--blue-dark);
    color: white;
}

.promo-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Checking the code: dimmed and inert, matching .continue-btn / .pay-btn. */
.promo-btn.is-busy,
.promo-btn.is-busy:disabled {
    opacity: 0.7;
    cursor: not-allowed;
    pointer-events: none;
}

.order-divider {
    border-top: 1px solid var(--border-light);
    margin: 14px 0;
}

.order-total {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-weight: 700;
}

.order-total .label {
    font-size: 15px;
}

.order-total .value {
    font-size: 20px;
    color: var(--blue);
}

/* ── Terms ───────────────────────────────────────────────────────────────── */
.terms-row {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 18px 0;
    padding: 14px 18px;
    background: white;
    border: 1px solid var(--border);
    border-radius: 12px;
}

.terms-checkbox {
    width: 18px;
    height: 18px;
    appearance: none;
    -webkit-appearance: none;
    border: 1.5px solid var(--border);
    border-radius: 5px;
    cursor: pointer;
    position: relative;
    flex-shrink: 0;
    background: white;
    margin: 0;
}

.terms-checkbox:checked {
    background: var(--blue);
    border-color: var(--blue);
}

.terms-checkbox:checked::after {
    content: '✓';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: white;
    font-size: 13px;
    font-weight: 700;
}

.terms-checkbox:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}

.terms-row label {
    font-size: 13.5px;
    color: var(--text);
    cursor: pointer;
    margin: 0;
}

.terms-row label a {
    color: var(--blue);
    text-decoration: underline;
    font-weight: 500;
}

/* validators.terms() flags the checkbox with .is-invalid when Proceed to Payment
   is pressed with the box unticked, and clears it again on `change`. The control
   is appearance:none, so Bootstrap's own .is-invalid styling never lands on it,
   hence the explicit rule below instead of relying on the browser default. */
.terms-checkbox.is-invalid {
    border-color: var(--red);
}

.terms-error {
    font-size: 12px;
    color: var(--red);
    margin-top: -8px;
    margin-bottom: 12px;
}

/* ── Pay button ──────────────────────────────────────────────────────────── */
.pay-btn {
    width: 100%;
    background: var(--blue);
    color: white;
    padding: 16px;
    border: none;
    border-radius: 11px;
    font-size: 16px;
    font-weight: 700;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    transition: all 0.15s;
    box-shadow: 0 4px 16px color-mix(in srgb, var(--blue) 25%, transparent);
}

.pay-btn:hover:not(:disabled) {
    background: var(--blue-dark);
    color: white;
    transform: translateY(-1px);
    box-shadow: 0 8px 24px color-mix(in srgb, var(--blue) 35%, transparent);
}

.pay-btn svg {
    transition: transform 0.2s;
}

.pay-btn:hover:not(:disabled) svg {
    transform: translateX(4px);
}

[dir="rtl"] .pay-btn svg {
    transform: scaleX(-1);
}

[dir="rtl"] .pay-btn:hover:not(:disabled) svg {
    transform: scaleX(-1) translateX(-4px);
}

.pay-btn:disabled,
.pay-btn.is-busy {
    opacity: 0.7;
    cursor: not-allowed;
    pointer-events: none;
    transform: none;
    box-shadow: none;
}

/* The questions page's Continue button has an arrow after its label too, so its spinner
   has to follow the label as well. Other .pay-btn buttons have no arrow and are left alone. */
#saveQuestions.is-busy {
    flex-direction: row-reverse;
}

.payment-secured {
    margin-top: 16px;
    padding: 12px 16px;
    background: white;
    border: 1px solid var(--border);
    border-radius: 12px;
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 13px;
    color: var(--muted);
}

.payment-secured strong {
    color: var(--text);
    font-weight: 700;
}

.payment-secured svg {
    color: var(--green);
    flex-shrink: 0;
}

/* App-only: privacy / refund policy links. */
.policy-links {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    margin-top: 14px;
    padding: 0 4px;
}

.policy-links a {
    font-size: 12px;
    color: var(--muted);
    text-decoration: none;
    transition: color 0.15s;
}

.policy-links a:hover {
    color: var(--blue);
    text-decoration: underline;
}

/* ── App-only: group participants ────────────────────────────────────────── */
.participants-section {
    margin-top: 20px;
    padding-top: 20px;
    border-top: 1px solid var(--border-light);
}

/* Short label only takes over on mobile (see RESPONSIVE below) — desktop
   has room for the full "Total Participants". */
.participants-label-short {
    display: none;
}

.participants-counter {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px 16px;
    margin-bottom: 14px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
}

.participants-stepper {
    display: flex;
    align-items: center;
    gap: 14px;
}

.participants-stepper button {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    border: 1.5px solid var(--border);
    background: white;
    color: var(--blue);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    transition: all 0.15s;
}

.participants-stepper button:hover:not(:disabled) {
    border-color: var(--blue);
    background: var(--blue-light);
}

.participants-stepper button:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.participants-stepper .count {
    font-size: 16px;
    font-weight: 700;
    min-width: 20px;
    text-align: center;
}

.bkv2 .participant-item {
    background: white;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 16px;
    margin-bottom: 12px;
}

.bkv2 .participant-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--blue-light);
    color: var(--blue);
    margin-inline-end: 8px;
    flex-shrink: 0;
}

/* ── Participant card header ─────────────────────────────────────────────
   Composed from primitives already on the page: the .participant-badge disc
   for the number, a status pill (the reference's .bs-meta anatomy) and a ghost
   button for remove. State is driven by classes so no colour is set inline.
   ───────────────────────────────────────────────────────────────────────── */
.bkv2 .participant-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}

.bkv2 .participant-head-info {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    min-width: 0;
}

/* Same disc as .participant-badge, so the sticky bar and the card agree. */
.bkv2 .participant-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--blue-light);
    color: var(--blue);
    font-size: 12.5px;
    font-weight: 700;
    flex-shrink: 0;
    margin: 0;
}

.bkv2 .participant-title {
    font-size: 15px;
    font-weight: 700;
    color: var(--text);
    letter-spacing: -0.2px;
}

.bkv2 .participant-status-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 10px;
    border-radius: 100px;
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
}

/* Text shades are mixed down from the palette tokens rather than introduced as
   new colours — the tints alone do not carry enough contrast for label text. */
.bkv2 .participant-status-badge.is-required {
    background: var(--amber-light);
    color: color-mix(in srgb, var(--amber) 70%, var(--text));
}

.bkv2 .participant-status-badge.is-done {
    background: var(--green-light);
    color: #15803D;
}

.bkv2 .participant-status-badge.is-incomplete {
    background: color-mix(in srgb, var(--red) 10%, white);
    color: color-mix(in srgb, var(--red) 78%, var(--text));
}

.bkv2 .remove-participant-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    flex-shrink: 0;
    background: white;
    border: 1.5px solid var(--border);
    border-radius: 9px;
    color: var(--muted-light);
    font-size: 12px;
    cursor: pointer;
    opacity: 1;
    transition: all 0.15s;
}

.bkv2 .remove-participant-btn:hover {
    border-color: var(--red);
    color: var(--red);
}

/* Flagged on submit. 1px, so nothing shifts when the state changes. */
.bkv2 .participant-item.participant-incomplete {
    border-color: var(--red);
}

/* ── App-only: a participant's own phone number ───────────────────────────
   The field itself is the shared phone partial's shape (.form-field >
   .input-group), so it already picks up the phone rules above. Only what is
   particular to the participant card is styled here.
   ───────────────────────────────────────────────────────────────────────── */
.bkv2 .participant-phone-toggle {
    margin-top: 10px;
    font-size: 13px;
    font-weight: 600;
    color: var(--blue);
    text-decoration: none;
}

.bkv2 .participant-phone-toggle:hover {
    color: var(--blue-dark);
}

/* .form-field's own 16px would push the error away from the field it belongs to. */
.bkv2 .participant-phone-field {
    margin-bottom: 0;
}

/* Shown/hidden inline by showError()/clearError(), so only the look is set here. */
.bkv2 .participant-phone-error {
    margin-top: 6px;
    font-size: 12px;
    color: var(--red);
}

/* The country menu is moved to <body> while open (see PortalDropdown in
   assets/js/phone.js), which puts it outside .form-field and so out of reach
   of the `>` selectors above. These match on the menu's own class instead, so
   the open list keeps the same chrome as the main phone field's. */
.participant-country-menu {
    max-height: 280px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.08);
    padding: 6px;
}

.participant-country-menu .dropdown-item {
    border-radius: 7px;
    font-size: 13px;
    padding: 8px 10px;
}

/* ── Policy dialogs ──────────────────────────────────────────────────────
   Terms / privacy / refund render inside the dashboard's shared modal shell
   (.sv2-overlay + .sv2-modal-inner + .pm-head/.pm-body from app-utils.css),
   so no chrome is styled here — only the typography for the vendor-authored
   HTML that goes in the body, which the WYSIWYG emits without any rhythm.
   ───────────────────────────────────────────────────────────────────────── */
.policy-body {
    font-size: 14px;
    line-height: 1.7;
    color: var(--muted);
}

.policy-body h1,
.policy-body h2,
.policy-body h3,
.policy-body h4 {
    font-size: 15px;
    font-weight: 700;
    color: var(--text);
    margin: 18px 0 8px;
}

.policy-body > :first-child {
    margin-top: 0;
}

.policy-body p {
    margin-bottom: 12px;
}

.policy-body ul,
.policy-body ol {
    padding-inline-start: 20px;
    margin-bottom: 12px;
}

.policy-body li {
    margin-bottom: 6px;
}

.policy-body a {
    color: var(--blue);
}

/* ── SCREEN 3 — RESPONSIVE ───────────────────────────────────────────────── */
@media (max-width: 880px) {
    .screen3 {
        grid-template-columns: 1fr;
    }

    .booking-summary,
    .form-section,
    .order-summary {
        padding: 20px;
    }

    /* Light trim to sit closer to .form-input's already-compact 12px/14px
       scale, same spirit as the other screens' passes. .question-option's
       own mobile padding is set further down, in the questions-specific
       RESPONSIVE block — a rule here would've been silently overridden by
       it anyway, since that one comes later in the cascade. */
    .bkv2 .question-field {
        padding: 13px 0;
    }

    /* The label and the stepper were each sized for desktop's wider row, so
       together they no longer fit on one line at mobile widths. Trimmed the
       stepper (the buttons were larger than they need to be) and swapped to
       the short "Participants" label — the count sitting right next to it
       already does the job "Total" was spelling out, and truncating the
       full label with an ellipsis (tried first) read as broken rather than
       intentional for a short, essential bit of UI chrome. */
    .participants-counter {
        padding: 11px 14px;
        gap: 8px;
    }

    .participants-counter > span {
        min-width: 0;
    }

    .participants-label-full {
        display: none;
    }

    .participants-label-short {
        display: inline;
    }

    .participants-stepper {
        gap: 10px;
    }

    .participants-stepper button {
        width: 28px;
        height: 28px;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   SCREEN 4 — CONFIRMATION
   ═══════════════════════════════════════════════════════════════════════════ */

.conf-hero {
    background: white;
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 48px 32px 36px;
    text-align: center;
    margin-bottom: 16px;
    position: relative;
    overflow: hidden;
}

/* Fills 0 → 100% like a progress bar completing. Width is animated rather than
   scaleX so the gradient stays put and the bar reads as a reveal instead of a
   stretch; it is one short animation on a single element, so the layout cost is
   irrelevant. Logical inset means it fills from the right in Arabic without a
   second rule.

   The animation is gated behind .is-progress, which the page adds on load: run
   from first paint it would start while the browser is still blocked on this
   page's render-blocking scripts and could finish before the hero is ever
   visible, which looks like a bar that was simply always full. */
.conf-hero::before {
    content: '';
    position: absolute;
    top: 0;
    inset-inline-start: 0;
    inset-inline-end: auto;
    width: 100%;
    height: 6px;
    background: linear-gradient(90deg, var(--green), #34D399, var(--green));
}

.conf-hero.is-progress::before {
    animation: confProgress var(--conf-fill, 1.1s) cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes confProgress {
    from { width: 0; }
    to   { width: 100%; }
}

.conf-check {
    width: 76px;
    height: 76px;
    background: var(--green-light);
    border-radius: 50%;
    margin: 0 auto 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
}

@keyframes confPop {
    0% { transform: scale(0); }
    100% { transform: scale(1); }
}

.conf-check::before {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background: var(--green-light);
    opacity: 0.5;
    animation: confRipple 2s ease-out infinite;
}

@keyframes confRipple {
    0% { transform: scale(1); opacity: 0.5; }
    100% { transform: scale(1.5); opacity: 0; }
}

.conf-check svg {
    width: 36px;
    height: 36px;
    color: var(--green);
    position: relative;
    z-index: 1;
}

/* ── Hero intro choreography ──────────────────────────────────────────────
   One timeline, one trigger. Everything below is gated on .is-progress — the
   class the page adds on load — so the bar, the badge and the icon all start
   from the same instant instead of the badge running at first paint and the
   bar running a second later, which is what made them look unrelated.

   t=0      bar starts filling
   t=0.35   badge pops                     (0.45s) → 0.80s
   t=0.75   tick draws                     (0.35s) ┐ lands on 1.10s, the exact
   t=0.60   cross stroke 1                 (0.25s) │ frame the bar reaches
   t=0.85   cross stroke 2                 (0.25s) ┘ 100%.

   The icon is deliberately held back rather than popping at t=0: the bar is the
   thing that "completes", so the badge appears while it is filling and the last
   stroke finishes with it. Every delay is derived from --conf-fill, so changing
   that one value re-times the whole sequence and it still lands together.
   ───────────────────────────────────────────────────────────────────────── */
.conf-hero {
    --conf-fill: 1.1s;
}

.conf-hero.is-progress .conf-check,
.conf-hero.is-progress .conf-x {
    animation: confPop 0.45s cubic-bezier(0.34, 1.56, 0.64, 1)
               calc(var(--conf-fill) - 0.75s) both;
}

/* Both shapes carry pathLength="1", so one dash length works for either
   regardless of their real geometry: hide the stroke by offsetting a full
   dash, then animate the offset back to 0. */
.conf-check svg polyline,
.conf-x svg line {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
}

.conf-hero.is-progress .conf-check svg polyline {
    animation: confDraw 0.35s cubic-bezier(0.65, 0, 0.35, 1)
               calc(var(--conf-fill) - 0.35s) forwards;
}

/* Two strokes rather than a fade: the second starts as the first ends, and
   lands with the bar. */
.conf-hero.is-progress .conf-x svg line {
    animation: confDraw 0.25s cubic-bezier(0.65, 0, 0.35, 1)
               calc(var(--conf-fill) - 0.5s) forwards;
}

.conf-hero.is-progress .conf-x svg line:last-of-type {
    animation-delay: calc(var(--conf-fill) - 0.25s);
}

@keyframes confDraw {
    to { stroke-dashoffset: 0; }
}

.conf-title {
    font-size: 32px;
    font-weight: 700;
    color: var(--text);
    letter-spacing: -1px;
    margin-bottom: 10px;
    line-height: 1.2;
}

.conf-subtitle {
    font-size: 15px;
    color: var(--muted);
    max-width: 460px;
    /* No trailing margin: the reference's hero ends on this paragraph. */
    margin: 0 auto;
    line-height: 1.6;
    text-wrap: pretty;
    overflow-wrap: break-word;
}

.conf-subtitle strong {
    color: var(--text);
}

.conf-ref {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--bg);
    border: 1px solid var(--border);
    padding: 8px 16px;
    border-radius: 100px;
    font-size: 13px;
    color: var(--muted);
    font-weight: 500;
}

.conf-ref strong {
    color: var(--text);
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    letter-spacing: 0.5px;
    /* Reference codes are Latin/numeric — keep them LTR inside an RTL page. */
    direction: ltr;
    unicode-bidi: isolate;
}

.conf-ref-copy {
    border: none;
    background: none;
    cursor: pointer;
    color: var(--blue);
    font-weight: 700;
    font-size: 12px;
    padding-inline-start: 8px;
    border-inline-start: 1px solid var(--border);
}

.conf-ref-copy:hover {
    text-decoration: underline;
}

.conf-body {
    display: grid;
    grid-template-columns: 1.2fr 1fr;
    gap: 16px;
}

.conf-body-right {
    display: flex;
    flex-direction: column;
    justify-content: start;
}

/* ── Booking details ─────────────────────────────────────────────────────── */
.conf-details {
    background: white;
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 24px;
}

.conf-detail-row {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 14px 0;
    border-bottom: 1px solid var(--border-light);
}

.conf-detail-row:last-child {
    border-bottom: none;
    padding-bottom: 0;
}

.conf-detail-row:first-of-type {
    padding-top: 0;
}

.conf-detail-icon {
    width: 36px;
    height: 36px;
    background: var(--blue-light);
    color: var(--blue);
    border-radius: 9px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.conf-detail-icon--green {
    background: var(--green-light);
    color: var(--green);
}

.conf-detail-info {
    flex: 1;
    min-width: 0;
}

.conf-detail-label {
    font-size: 11.5px;
    font-weight: 700;
    color: var(--muted);
    letter-spacing: 0.2px;
    text-transform: none;
    margin-bottom: 3px;
}

.conf-detail-value {
    font-size: 15px;
    font-weight: 600;
    color: var(--text);
}

.conf-detail-sub {
    font-size: 13px;
    color: var(--muted);
    margin-top: 2px;
}

/* ── Actions / payment column ────────────────────────────────────────────── */
.conf-actions {
    background: white;
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 24px;
}

.conf-actions-head {
    font-size: 15px;
    font-weight: 700;
    margin-bottom: 14px;
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--text);
}

.conf-actions-head::before {
    content: '';
    width: 3px;
    height: 16px;
    background: var(--blue);
    border-radius: 2px;
    flex-shrink: 0;
}

/* Paid / free status chips inside the payment card. */
.conf-status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px;
    border-radius: 100px;
    font-size: 12px;
    font-weight: 700;
}

.conf-status--paid {
    background: var(--green-light);
    color: #15803D;
}

.conf-status--free {
    background: var(--green-light);
    color: #15803D;
}

.conf-status--discount {
    background: var(--amber-light);
    color: #92400E;
}

.conf-strike {
    text-decoration: line-through;
    color: var(--muted);
    font-weight: 500;
}

.conf-saved {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--green);
    margin-top: 10px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
}

/* ── Email note ──────────────────────────────────────────────────────────── */
.conf-email-note {
    background: var(--blue-light);
    border: 1px solid #BFDBFE;
    border-radius: 12px;
    padding: 14px 18px;
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
}

.conf-email-note-icon {
    width: 36px;
    height: 36px;
    background: white;
    border-radius: 9px;
    color: var(--blue);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.conf-email-note-text {
    font-size: 13px;
    color: var(--text);
    line-height: 1.5;
}

.conf-email-note-text strong {
    color: var(--blue);
}

/* ── Secondary action ────────────────────────────────────────────────────── */
.conf-cta {
    text-align: center;
    margin-top: 24px;
}

.conf-back-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: white;
    color: var(--blue);
    border: 1.5px solid var(--border);
    cursor: pointer;
    padding: 12px 24px;
    border-radius: 11px;
    font-size: 14px;
    font-weight: 600;
    transition: all 0.15s;
    text-decoration: none;
}

.conf-back-btn:hover {
    border-color: var(--blue);
    background: var(--blue-light);
    color: var(--blue);
    text-decoration: none;
}

/* The icon comes first in the markup; in Arabic it has to follow the text, so it sits on the left. */
[dir="rtl"] .conf-back-btn {
    flex-direction: row-reverse;
}

/* ── Brand footer ────────────────────────────────────────────────────────── */
.brand-footer {
    text-align: center;
    margin-top: 40px;
    font-size: 12px;
    color: var(--muted);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

.brand-footer img {
    height: 18px;
    opacity: 0.7;
}

/* ── SCREEN 4 — RESPONSIVE ───────────────────────────────────────────────── */
@media (max-width: 880px) {
    .conf-body {
        grid-template-columns: 1fr;
    }

    .conf-title {
        font-size: 24px;
    }

    .conf-hero {
        padding: 36px 22px 28px;
    }

    .conf-details,
    .conf-actions {
        padding: 20px;
    }

    /* Same oversizing as .continue-btn had — 16px/16px desktop scale next to
       .form-input's already-compact 12px/14px. */
    .pay-btn {
        padding: 13px;
        font-size: 14px;
    }
}

/* The confirmation hero's three effects — the progress bar, the badge pop and
   the icon draw-in — are the page's completion feedback and were specified as
   always-on, so they are deliberately not suppressed under reduced motion. The
   only thing dropped here is the badge's endlessly repeating ripple, which is
   decorative and, unlike the others, never stops. */
@media (prefers-reduced-motion: reduce) {
    .conf-check::before {
        animation: none;
        opacity: 0;
    }
}

/* ── Save the appointment: calendar rows ─────────────────────────────────── */
.conf-cal-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.conf-cal-row {
    display: flex;
    align-items: center;
    gap: 14px;
    background: white;
    border: 1.5px solid var(--border);
    border-radius: 12px;
    padding: 12px 14px;
    cursor: pointer;
    text-decoration: none;
    color: var(--text);
    transition: all 0.18s;
}

.conf-cal-row:hover {
    border-color: var(--blue);
    background: var(--blue-light);
    transform: translateX(2px);
    text-decoration: none;
    color: var(--text);
}

.conf-cal-row-icon-simple {
    width: 40px;
    height: 40px;
    border-radius: 10px;
    background: var(--blue-light);
    color: var(--blue);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.conf-cal-row:hover .conf-cal-row-icon-simple {
    background: white;
}

.conf-cal-row-info {
    flex: 1;
    min-width: 0;
}

.conf-cal-row-name {
    font-size: 14px;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 2px;
}

.conf-cal-row-sub {
    font-size: 12px;
    color: var(--muted);
}

.conf-cal-row-arrow {
    color: var(--muted-light);
    flex-shrink: 0;
    transition: color 0.18s;
}

.conf-cal-row:hover .conf-cal-row-arrow {
    color: var(--blue);
}

[dir="rtl"] .conf-cal-row:hover {
    transform: translateX(-2px);
}

[dir="rtl"] .conf-cal-row-arrow {
    transform: scaleX(-1);
}

/* ═══════════════════════════════════════════════════════════════════════════
   SCREEN 4b — PAYMENT FAILED
   The declined page is the confirmation screen in a red key: it reuses every
   confirmation primitive (.conf-hero, .conf-details, .conf-actions, …) and
   only swaps the colour of the hero rule, the badge and the note bar, so the
   two pages stay one design with one set of spacing rules.
   ═══════════════════════════════════════════════════════════════════════════ */
.conf-hero--error::before {
    background: linear-gradient(90deg, var(--red), #F87171, var(--red));
}

/* The confirmation subtitle interpolates a provider name, date and email, so it
   is always long and wraps naturally. This one is a single fixed sentence: give
   it room to sit on one line on desktop, and balance the wrap below that so it
   never breaks into a long line plus a stranded word. */
.conf-hero--error .conf-subtitle {
    max-width: 62ch;
    text-wrap: balance;
}

/* Same circle as .conf-check, minus the "success" ripple — a failure should
   not pulse for attention. */
.conf-x {
    width: 76px;
    height: 76px;
    background: var(--red-light, #FEE2E2);
    border-radius: 50%;
    margin: 0 auto 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    animation: confPop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.conf-x svg {
    width: 36px;
    height: 36px;
    color: var(--red);
}


/* ── Dead-end state card ─────────────────────────────────────────────────
   For pages that end the journey rather than advance it (service unavailable).
   Deliberately not built on .conf-hero: that hero is full-bleed, carries a
   progress rule and a pop/draw sequence, and all of it is meaningless here —
   nothing completed and nothing failed. This is a single card sized to its own
   content, sitting high on an otherwise empty page.
   ───────────────────────────────────────────────────────────────────────── */
.state-card {
    max-width: 520px;
    margin: 8px auto 0;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 48px 32px 44px;
    text-align: center;
    box-shadow: 0 1px 3px rgba(16, 24, 40, 0.04);
}

/* The old page led with a large circular illustration; this keeps that weight,
   drawn in the v2 line style instead of a flat silhouette. currentColor drives
   every stroke, so the whole drawing tints from one declaration. */
.state-art {
    width: 132px;
    height: 132px;
    margin: 0 auto 22px;
    color: var(--muted-light);
}

.state-art svg {
    width: 100%;
    height: 100%;
    display: block;
}

/* ── Entrance ─────────────────────────────────────────────────────────────
   The same fill-and-draw pairing the confirmation hero uses, in this card's own
   blue: the bar sweeps 0 → 100% while the illustration draws itself, and the
   last stroke lands on the frame the bar completes. Card and copy are static —
   only the bar and the drawing move.

   t=0     bar fills                        (--conf-fill)
   t=0.10  disc scales up                   (0.40s)
   t=0.25  calendar draws itself            (0.50s)
   t=0.55  cross stroke 1                   (0.27s)
   t=0.83  cross stroke 2                   (0.27s) → lands with the bar at 1.10s
   ───────────────────────────────────────────────────────────────────────── */
.state-card {
    --conf-fill: 1.1s;
    position: relative;
    overflow: hidden;
}

.state-card::before {
    content: '';
    position: absolute;
    top: 0;
    inset-inline-start: 0;
    inset-inline-end: auto;
    width: 100%;
    height: 5px;
    background: linear-gradient(90deg, var(--blue), var(--blue-mid), var(--blue));
}

.state-card.is-in::before {
    animation: confProgress var(--conf-fill) cubic-bezier(0.22, 1, 0.36, 1) both;
}

.state-art-bg {
    transform-origin: 60px 60px;
    transform: scale(0.8);
    opacity: 0;
}

.state-card.is-in .state-art-bg {
    animation: stateDisc 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) 0.1s both;
}

@keyframes stateDisc {
    to { transform: scale(1); opacity: 1; }
}

.state-art-draw,
.state-art-x {
    stroke-dasharray: 1;
    stroke-dashoffset: 1;
}

.state-card.is-in .state-art-draw {
    animation: confDraw 0.5s cubic-bezier(0.65, 0, 0.35, 1) 0.25s forwards;
}

.state-card.is-in .state-art-x {
    animation: confDraw 0.27s cubic-bezier(0.65, 0, 0.35, 1)
               calc(var(--conf-fill) - 0.55s) forwards;
}

.state-card.is-in .state-art-x + .state-art-x {
    animation-delay: calc(var(--conf-fill) - 0.27s);
}

/* The service's own name, above the heading — it is context, not the headline. */
.state-eyebrow {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: var(--muted-light);
    margin-bottom: 8px;
    overflow-wrap: break-word;
}

.state-title {
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.5px;
    color: var(--text);
    margin-bottom: 10px;
    line-height: 1.25;
}

.state-text {
    font-size: 14.5px;
    line-height: 1.65;
    color: var(--muted);
    text-wrap: pretty;
    max-width: 46ch;
    margin: 0 auto;
}

/* Actions under a dead-end card. Side by side while they fit, stacked below —
   the buttons are the same ones the confirmation column uses, so they arrive
   full-width and are constrained back here rather than restyled. */
.state-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
    margin-top: 26px;
}

.state-actions .conf-primary-btn,
.state-actions .conf-back-btn {
    width: auto;
    min-width: 190px;
    margin-top: 0;
}

@media (max-width: 620px) {
    .state-card {
        padding: 36px 22px 32px;
    }

    .state-art {
        width: 104px;
        height: 104px;
    }

    .state-actions .conf-primary-btn,
    .state-actions .conf-back-btn {
        width: 100%;
    }
}

.conf-detail-icon--red {
    background: var(--red-light, #FEE2E2);
    color: var(--red);
}

.conf-status--declined {
    background: var(--red-light, #FEE2E2);
    color: #B91C1C;
}

/* Amber sibling of .conf-email-note for the "not confirmed yet" advisory. */
.conf-email-note--warn {
    background: var(--amber-light);
    border-color: #FDE68A;
}

.conf-email-note--warn .conf-email-note-icon {
    color: #B45309;
}

/* Primary action inside the actions card — the .pay-btn treatment at the
   smaller scale the confirmation column uses. */
.conf-primary-btn {
    width: 100%;
    background: var(--blue);
    color: white;
    border: none;
    border-radius: 11px;
    padding: 14px 20px;
    font-size: 15px;
    font-weight: 700;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    text-decoration: none;
    transition: all 0.15s;
    box-shadow: 0 4px 16px color-mix(in srgb, var(--blue) 25%, transparent);
}

.conf-primary-btn:hover {
    background: var(--blue-dark);
    color: white;
    text-decoration: none;
    transform: translateY(-1px);
    box-shadow: 0 8px 24px color-mix(in srgb, var(--blue) 35%, transparent);
}

.conf-secondary-btn {
    width: 100%;
    margin-top: 10px;
    justify-content: center;
}

/* Numbered "what to do next" list under the retry button. */
.conf-hints {
    list-style: none;
    margin: 16px 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.conf-hints li {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 13px;
    color: var(--muted);
    line-height: 1.5;
}

.conf-hints li::before {
    content: '';
    width: 6px;
    height: 6px;
    margin-top: 7px;
    border-radius: 50%;
    background: var(--muted-light);
    flex-shrink: 0;
}

/* ═══════════════════════════════════════════════════════════════════════════
   QUESTIONS STEP
   No screen in the reference mockup covers this page, so nothing here is a new
   design: every value is lifted from an existing reference primitive.

     question block  → .bs-block   (divided rows inside one card)
     question label  → .form-label (+ .req marker)
     question index  → .bs-meta--blue pill
     text answers    → .form-input
     radio/checkbox  → .location-option row and its drawn radio
     dropdown        → <x-searchable-select>, as on the datepicker
     submit          → .pay-btn

   The file upload has no reference counterpart at all; the compromises made for
   it are noted inline. Everything is scoped to .bkv2 so the identically-named
   classes in the v1 stylesheet are untouched — and the participant questions on
   the v2 checkout page, which use the same class names, pick these up for free.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Question block — the reference's .bs-block divider rhythm ────────────── */
.bkv2 .question-field {
    padding: 16px 0;
    border-bottom: 1px solid var(--border-light);
}

.bkv2 .question-field:first-of-type {
    padding-top: 0;
}

.bkv2 .question-field:last-of-type {
    border-bottom: none;
    padding-bottom: 0;
}

/* ── Question label ──────────────────────────────────────────────────────── */
.bkv2 .question-label {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 10px;
}

.bkv2 .question-text {
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    line-height: 1.55;
}

/* Same pill as .bs-meta--blue, sized down to sit beside a 14px label. */
.bkv2 .question-index {
    flex-shrink: 0;
    background: var(--blue-light);
    color: var(--blue);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.5px;
    padding: 2px 9px;
    border-radius: 100px;
    line-height: 1.6;
}

/* ── Choice options — the .location-option row, minus the icon tile ──────── */
.bkv2 .question-options {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.bkv2 .question-option {
    background: white;
    border: 1.5px solid var(--border);
    border-radius: 12px;
    padding: 14px 16px;
    cursor: pointer;
    transition: all 0.15s;
    display: flex;
    gap: 14px;
    align-items: center;
    position: relative;
    margin: 0;
}

.bkv2 .question-option:hover {
    border-color: var(--blue);
}

/* The real input stays in the DOM — it keeps the field name, the element id and
   the `change` events the page JS listens for — and is only visually replaced,
   exactly as .location-input does on the datepicker. */
.bkv2 .question-input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    margin: 0;
    pointer-events: none;
}

.bkv2 .question-option:has(.question-input:checked) {
    border-color: var(--blue);
    background: var(--blue-light);
}

.bkv2 .question-radio,
.bkv2 .question-check {
    width: 18px;
    height: 18px;
    border: 1.5px solid var(--border);
    flex-shrink: 0;
    background: white;
    position: relative;
    transition: border-color 0.15s;
}

.bkv2 .question-radio {
    border-radius: 50%;
}

.bkv2 .question-check {
    border-radius: 5px;
}

.bkv2 .question-option:has(.question-input:checked) .question-radio,
.bkv2 .question-option:has(.question-input:checked) .question-check {
    border-color: var(--blue);
}

.bkv2 .question-option:has(.question-input:checked) .question-radio::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--blue);
}

/* Same tick mark the reference draws on .terms-checkbox. */
.bkv2 .question-option:has(.question-input:checked) .question-check {
    background: var(--blue);
}

.bkv2 .question-option:has(.question-input:checked) .question-check::after {
    content: '✓';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: white;
    font-size: 12px;
    font-weight: 700;
}

.bkv2 .question-input:focus-visible ~ .question-radio,
.bkv2 .question-input:focus-visible ~ .question-check {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}

.bkv2 .question-option-label {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    line-height: 1.5;
}

.bkv2 .question-option:has(.question-input:checked) .question-option-label {
    color: var(--blue);
}

/* ── "Other option" ──────────────────────────────────────────────────────── */
.bkv2 .other-opt-block {
    margin-top: 10px;
}

.bkv2 .other-opt-input-wrap {
    margin-top: 10px;
    padding-inline-start: 32px;
}

/* ── File upload ─────────────────────────────────────────────────────────
   No reference primitive exists for a drop zone. Composed from the option row
   (1.5px border, 12px radius, blue hover) and the 44px blue icon tile used by
   .location-icon, rather than inventing a dashed-border style. Centring follows
   .empty-state.
   ───────────────────────────────────────────────────────────────────────── */
.bkv2 .image-upload-card {
    background: white;
    border: 1.5px solid var(--border);
    border-radius: 12px;
    cursor: pointer;
    transition: all 0.15s;
    overflow: hidden;
}

.bkv2 .image-upload-card:hover {
    border-color: var(--blue);
    background: var(--blue-light);
}

.bkv2 .upload-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    width: 100%;
    padding: 22px 16px;
    margin: 0;
    cursor: pointer;
}

.bkv2 .upload-icon {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    background: var(--blue-light);
    color: var(--blue);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 17px;
    margin-bottom: 12px;
    transition: background 0.15s;
}

.bkv2 .image-upload-card:hover .upload-icon {
    background: white;
}

.bkv2 .upload-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 4px;
}

.bkv2 .upload-hint {
    font-size: 12.5px;
    color: var(--muted);
    line-height: 1.5;
}

.bkv2 .file-input {
    display: none;
}

/* ── File preview ────────────────────────────────────────────────────────── */
.bkv2 .file-preview-container {
    display: none;
    background: white;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 18px;
    margin-top: 12px;
}

.bkv2 .file-preview-container.active {
    display: block;
}

/* attachFileUpload.js fades the panel out before emptying it. Card motion:
   0.18s, 2px translate. */
.bkv2 .file-preview-container.fade-out {
    animation: bkv2FadeOutDown 0.18s ease forwards;
}

@keyframes bkv2FadeOutDown {
    from {
        opacity: 1;
        transform: translateY(0);
    }

    to {
        opacity: 0;
        transform: translateY(2px);
    }
}

.bkv2 .preview-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    margin-bottom: 14px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border-light);
}

/* Micro-label, as used for .bs-label. */
.bkv2 .preview-title {
    font-size: 11px;
    font-weight: 700;
    color: var(--muted);
    letter-spacing: 1.2px;
    text-transform: uppercase;
}

/* Ghost button recoloured for a destructive action — the reference has no
   destructive button of its own. */
.bkv2 .remove-btn {
    background: white;
    border: 1.5px solid var(--border);
    border-radius: 10px;
    color: var(--red);
    padding: 8px 14px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    transition: border-color 0.15s;
}

.bkv2 .remove-btn:hover {
    border-color: var(--red);
}

.bkv2 .preview-content {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.bkv2 .preview-image {
    max-width: 100%;
    max-height: 400px;
    object-fit: contain;
    border-radius: 10px;
    border: 1px solid var(--border);
}

.bkv2 .file-info {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 14px;
}

.bkv2 .file-info-row {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* 36px icon tile. Kept in the file-type colour the upload JS assigns, so a PDF
   still reads as a PDF at a glance. */
.bkv2 .file-icon {
    width: 36px;
    height: 36px;
    border-radius: 9px;
    background: white;
    border: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    flex-shrink: 0;
}

.bkv2 .file-icon.pdf {
    color: var(--red);
}

.bkv2 .file-icon.image {
    color: var(--blue);
}

.bkv2 .file-details {
    flex: 1;
    min-width: 0;
}

.bkv2 .file-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    word-break: break-all;
}

.bkv2 .file-meta {
    font-size: 12px;
    color: var(--muted);
    margin-top: 4px;
}

.bkv2 .file-type-badge {
    display: inline-flex;
    align-items: center;
    background: var(--blue-light);
    color: var(--blue);
    padding: 2px 10px;
    border-radius: 100px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
}

/* ── Errors ──────────────────────────────────────────────────────────────
   Red counterpart of the reference's blue .location-note callout. The upload JS
   toggles `.active`; the per-question validation message is a separate element
   that stays in flow and hides itself while empty.
   ───────────────────────────────────────────────────────────────────────── */
.bkv2 .error-message {
    display: none;
    margin-top: 10px;
    padding: 12px 14px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--red) 8%, white);
    border: 1px solid color-mix(in srgb, var(--red) 35%, white);
    color: var(--red);
    font-size: 13px;
    font-weight: 500;
}

.bkv2 .error-message.active {
    display: block;
}

.bkv2 .question-error {
    margin-top: 8px;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--red);
}

.bkv2 .question-error:empty {
    display: none;
}

/* ── Date answers ────────────────────────────────────────────────────────
   bootstrap-datepicker, as used across the dashboard. The widget is appended to
   <body>, so it cannot be scoped under .bkv2 — booking-v2.css only loads on the
   booking pages, and it is loaded after the plugin's own stylesheet.
   ───────────────────────────────────────────────────────────────────────── */
.bkv2 .question-datepicker {
    cursor: pointer;
    background: white;
}

.datepicker.datepicker-dropdown {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.08);
    font-family: inherit;
    font-size: 13px;
    z-index: 1060;
}

.datepicker.datepicker-dropdown:after,
.datepicker.datepicker-dropdown:before {
    display: none;
}

.datepicker table tr td,
.datepicker table tr th {
    border-radius: 8px;
    width: 32px;
    height: 32px;
    color: var(--text);
}

.datepicker .datepicker-switch,
.datepicker .prev,
.datepicker .next {
    font-weight: 700;
    color: var(--text);
}

.datepicker table tr th.dow {
    font-size: 11px;
    font-weight: 700;
    color: var(--muted-light);
    letter-spacing: 0.5px;
}

.datepicker .datepicker-switch:hover,
.datepicker .prev:hover,
.datepicker .next:hover {
    background: var(--blue-light);
    color: var(--blue);
}

.datepicker table tr td.old,
.datepicker table tr td.new {
    color: var(--muted-light);
}

/* The plugin's stock theme paints the "today" cell with an amber gradient and
   re-asserts it on :hover / :focus / :active / .disabled, each at a higher
   specificity than a plain `td.today` rule. Prefixing with .datepicker-dropdown
   (always present on an attached widget) outranks all of them, so the whole day
   grid can be restated in the design system's blue without any !important.
   background-image / border-color / text-shadow are reset explicitly because
   the theme sets a gradient, a border tint and a text shadow. */
.datepicker.datepicker-dropdown table tr td.day:hover,
.datepicker.datepicker-dropdown table tr td.day.focused {
    background: var(--blue-light);
    background-image: none;
    border-color: transparent;
    color: var(--blue);
    text-shadow: none;
}

.datepicker.datepicker-dropdown table tr td.day.today,
.datepicker.datepicker-dropdown table tr td.day.today:hover,
.datepicker.datepicker-dropdown table tr td.day.today:focus,
.datepicker.datepicker-dropdown table tr td.day.today:active,
.datepicker.datepicker-dropdown table tr td.day.today.focused,
.datepicker.datepicker-dropdown table tr td.day.today.disabled,
.datepicker.datepicker-dropdown table tr td.day.today.disabled:hover {
    background: var(--blue-light);
    background-image: none;
    border-color: transparent;
    color: var(--blue);
    font-weight: 700;
    text-shadow: none;
}

/* Selected day — including when the selection is today. */
.datepicker.datepicker-dropdown table tr td.day.active,
.datepicker.datepicker-dropdown table tr td.day.active:hover,
.datepicker.datepicker-dropdown table tr td.day.active:focus,
.datepicker.datepicker-dropdown table tr td.day.active:active,
.datepicker.datepicker-dropdown table tr td.day.active.focused,
.datepicker.datepicker-dropdown table tr td.day.today.active,
.datepicker.datepicker-dropdown table tr td.day.today.active:hover {
    background: var(--blue);
    background-image: none;
    border-color: transparent;
    color: white;
    font-weight: 700;
    text-shadow: none;
}

.datepicker tfoot tr th {
    border-radius: 8px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--blue);
}

.datepicker tfoot tr th:hover {
    background: var(--blue-light);
}

/* ── Phone answers ───────────────────────────────────────────────────────
   The shared country picker renders its own label; the question already has
   one, so the partial's is hidden rather than the partial being forked.
   ───────────────────────────────────────────────────────────────────────── */
.bkv2 .question-phone {
    margin-bottom: 0;
}

.bkv2 .question-phone > .form-label {
    display: none;
}

/* ── Submit ──────────────────────────────────────────────────────────────── */
.bkv2 .questions-cta-wrap {
    margin-top: 16px;
}

/* ── RESPONSIVE ──────────────────────────────────────────────────────────── */
@media (max-width: 880px) {
    .bkv2 .question-option {
        padding: 11px 14px;
    }

    /* Title and button were fighting over the same row width inside the
       narrow question column, so each wrapped independently (FILE / PREVIEW
       on two lines, Remove / File on two more) instead of either comfortably
       fitting. Dropping the button's label and keeping just the icon frees
       up enough room that both sit on one row again, label-free though the
       icon still needs a spoken name — aria-label carries it. */
    .bkv2 .remove-btn {
        padding: 8px;
    }

    .bkv2 .remove-btn-label {
        display: none;
    }
}

/* ═══════════════════════════════════════════════════════════════════════
   FULLY BOOKED + WAITLIST
   Service-list card treatment and the panel that replaces the calendar on
   the detail screen when every spot is taken.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Service list: a full service recedes but stays clickable ── */
.service-card.fully-booked {
    cursor: pointer;
    background: var(--bg);
    border-color: var(--border);
}

.service-card.fully-booked .service-img {
    opacity: 0.55;
    filter: grayscale(0.4);
}

.service-card.fully-booked .service-name {
    color: var(--muted);
}

.service-card.fully-booked .service-price,
.service-card.fully-booked .service-desc {
    color: var(--muted-light);
}

.service-full-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: #FEF2F2;
    color: var(--red);
    border: 1px solid #FECACA;
    padding: 4px 10px;
    border-radius: 100px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.2px;
}

.service-full-badge svg {
    flex-shrink: 0;
}

/* ── Detail screen: the panel that stands in for the calendar ── */
.fb-panel {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 40px 28px;
    text-align: center;
}

.fb-icon {
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background: #FEF2F2;
    color: var(--red);
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto 18px;
}

.fb-icon.is-success {
    background: var(--green-light);
    color: var(--green);
}

.fb-title {
    font-size: 19px;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 8px;
}

.fb-sub {
    font-size: 13.5px;
    color: var(--muted);
    line-height: 1.6;
    max-width: 340px;
    margin: 0 auto 22px;
}

.fb-spots {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--muted);
    font-size: 12.5px;
    font-weight: 600;
    padding: 6px 12px;
    border-radius: 100px;
    margin-bottom: 22px;
}

/* The panel is centred, but the form inside reads as a normal form. */
.fb-form {
    max-width: 320px;
    margin: 0 auto;
    text-align: left;
}

[dir="rtl"] .fb-form {
    text-align: right;
}

.fb-form .form-field {
    margin-bottom: 14px;
}

.fb-form .form-input.is-invalid {
    border-color: var(--red);
}

.fb-notify-preview {
    max-width: 320px;
    margin: 0 auto 18px;
    background: var(--blue-light);
    color: var(--blue-dark);
    border-radius: 10px;
    padding: 10px 14px;
    font-size: 12.5px;
    line-height: 1.5;
    text-align: left;
    display: none;
}

[dir="rtl"] .fb-notify-preview {
    text-align: right;
}

.fb-notify-preview strong {
    font-weight: 700;
}

.fb-error {
    max-width: 320px;
    margin: 0 auto;
    color: var(--red);
    font-size: 12.5px;
    line-height: 1.5;
    text-align: left;
}

[dir="rtl"] .fb-error {
    text-align: right;
}

.fb-error:empty {
    display: none;
}

.fb-actions {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-width: 280px;
    margin: 22px auto 0;
}

.fb-waitlist-btn {
    width: 100%;
    background: var(--blue);
    color: #fff;
    border: none;
    padding: 13px;
    border-radius: 10px;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.15s;
}

.fb-waitlist-btn:hover:not(:disabled) {
    background: var(--blue-dark);
}

.fb-waitlist-btn:disabled {
    opacity: 0.65;
    cursor: default;
}

.fb-back-btn {
    display: block;
    width: 100%;
    background: var(--card);
    color: var(--text);
    border: 1.5px solid var(--border);
    padding: 12px;
    border-radius: 10px;
    font-size: 13.5px;
    font-weight: 600;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: all 0.15s;
}

.fb-back-btn:hover {
    background: var(--bg);
    color: var(--text);
}

@media (max-width: 880px) {
    .fb-panel {
        padding: 32px 20px;
    }
}

/* Waitlist form fields reuse the checkout step's markup, so they inherit the
   shared .form-field / .form-input / phone-partial rules above. These only
   re-anchor the inline errors, which would otherwise centre with the panel. */
.fb-form .text-danger,
.fb-form small[id$="phoneError"],
.fb-form .invalid-feedback {
    display: block;
    text-align: left;
    font-size: 12px;
    line-height: 1.45;
    margin-top: 5px;
}

[dir="rtl"] .fb-form .text-danger,
[dir="rtl"] .fb-form small[id$="phoneError"],
[dir="rtl"] .fb-form .invalid-feedback {
    text-align: right;
}

/* The country picker sits beside the number, so flag the number itself. */
.fb-form .input-group > input[type="tel"].is-invalid {
    border-color: var(--red) !important;
}

.fb-form .invalid-feedback {
    margin-left: 0;
    margin-right: 0;
}

/* ══════════════════════════════════════════════════════════════════════════
   PACKAGES
   Ported from the v1 `.booking-package-v2 .pkg-*` rules onto the v2 tokens and
   components. The package list on the home page and the package summary on the
   checkout step reuse .service-card / .booking-summary verbatim, so only the
   pieces those two do not already provide live here.
   ══════════════════════════════════════════════════════════════════════════ */

/* Package thumbnail. .service-img supplies the box, gradient and centring; this
   only nudges the icon's weight so a package reads as a package next to a
   service photo. */
.service-img.package-img {
    color: var(--blue-dark);
}

/* ── Package summary (left column of the package page) ───────────────────── */
.pkg-price {
    font-size: 22px;
    font-weight: 800;
    color: var(--blue);
}

.pkg-price-unit {
    font-size: 13px;
    font-weight: 700;
    color: var(--muted);
}

/* Second and later lines inside one .bs-block — the scheduled date and time
   under a service name on the package checkout. Lighter than .bs-value so the
   service name stays the anchor of the block. */
.bs-value--sub {
    font-size: 13.5px;
    font-weight: 500;
    color: var(--muted);
    margin-top: 6px;
}

.bs-value--sub svg {
    color: var(--muted-light);
}

/* ── Progress ────────────────────────────────────────────────────────────── */
.pkg-progress-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 12px;
    font-weight: 600;
    color: var(--muted);
    margin-bottom: 8px;
}

.pkg-progress-bar {
    height: 6px;
    border-radius: 100px;
    background: var(--border-light);
    overflow: hidden;
}

.pkg-progress-fill {
    height: 100%;
    border-radius: 100px;
    background: var(--blue);
    transition: width 0.3s ease;
}

/* ── Step list (right column of the package page) ────────────────────────── */
.pkg-hint {
    font-size: 13px;
    color: var(--muted);
    margin: -4px 0 16px;
}

.pkg-hint--center {
    text-align: center;
    margin: 12px 0 0;
}

.pkg-step-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.pkg-step {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--card);
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
}

.pkg-step:hover {
    border-color: var(--blue);
    box-shadow: 0 4px 14px rgba(0, 105, 255, 0.08);
    transform: translateY(-1px);
    color: inherit;
}

.pkg-step.is-done {
    border-color: var(--green);
    background: linear-gradient(0deg, var(--green-light) 0%, var(--card) 60%);
}

/* Step index, or a check once the slot is chosen. */
.pkg-step-num {
    width: 30px;
    height: 30px;
    flex-shrink: 0;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 700;
    background: var(--blue-light);
    color: var(--blue);
}

.pkg-step.is-done .pkg-step-num {
    background: var(--green);
    color: #FFFFFF;
}

.pkg-step-body {
    flex: 1;
    min-width: 0;
}

.pkg-step-top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.pkg-step-name {
    font-size: 15px;
    font-weight: 700;
    color: var(--text);
    min-width: 0;
}

.pkg-step-badge {
    flex-shrink: 0;
    font-size: 11px;
    font-weight: 700;
    padding: 3px 10px;
    border-radius: 100px;
    background: var(--bg);
    color: var(--muted);
    border: 1px solid var(--border);
}

.pkg-step-badge.is-done {
    background: var(--green-light);
    color: #15803D;
    border-color: transparent;
}

.pkg-step-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: 8px;
}

.pkg-step-when {
    background: var(--blue-light);
    color: var(--blue);
    border-color: transparent;
}

/* The continue control on the package page is a link, not a <button>, because
   it navigates. .pay-btn assumes a button, so undo what a link brings. */
a.pay-btn {
    text-decoration: none;
    box-sizing: border-box;
}

a.pay-btn:hover {
    text-decoration: none;
}

@media (max-width: 900px) {
    .pkg-step {
        padding: 14px;
    }

    .pkg-step-top {
        flex-direction: column;
        gap: 6px;
    }

    .pkg-step-badge {
        align-self: flex-start;
    }
}

/* ── RTL ─────────────────────────────────────────────────────────────────── */
[dir="rtl"] .pkg-step .service-arrow {
    transform: scaleX(-1);
}

[dir="rtl"] .pkg-step:hover .service-arrow {
    transform: scaleX(-1) translateX(-3px);
}

/* ── Vendor-typed text: wrapping ────────────────────────────────────────────
   Every surface below renders free text a vendor or customer typed, and none
   of it is under our control. A run of characters with no spaces
   ("asdasdasd…", a pasted URL, a long slug) has nowhere to break, so it
   renders as one line, pushes past its card and drags a horizontal scrollbar
   onto the whole page.

   Both properties are kept, matching .description-text above: overflow-wrap is
   the standard, word-break is the legacy alias older Safari understands.
   break-word rather than anywhere, so ordinary prose still breaks at spaces
   and only an unbreakable run is split.

   Deliberately not listed: anything already truncated with white-space:nowrap
   + text-overflow:ellipsis, which cannot overflow in the first place. */
.service-name,
.service-desc,
.selected-service-name,
.pkg-step-name,
.bs-value,
.conf-detail-value,
.fb-sub {
    overflow-wrap: break-word;
    word-break: break-word;
    /* A grid/flex child's min-content width is its longest unbreakable run, so
       without this the track itself is widened and the wrap never gets a
       chance to apply. */
    min-width: 0;
}

/* The video-camera glyph points sideways, so it mirrors with the page like the arrows do:
   in Arabic the lens faces the text it labels. */
[dir="rtl"] .icon-video {
    transform: scaleX(-1);
}
