/* ═══════════════════════════════════════════════════════════════════════════
   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: left;
    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;
}

.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"] .provider-extra {
    text-align: right;
}

[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: 24px 16px 48px;
    }

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

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

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

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

    .service-img {
        width: 72px;
        height: 72px;
        font-size: 28px;
    }

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

    .card {
        padding: 22px;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   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>");
}

.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;
}

/* 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;
}

.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;
    }

    .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;
    padding: 12px 14px;
    border-radius: 10px !important;
    font-size: 14px;
    font-weight: 600;
    color: var(--text) !important;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    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;
}

.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;
    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%;
    background: var(--bg);
    border: 1.5px solid var(--border);
    padding: 11px 14px 11px 38px;
    border-radius: 10px;
    font-size: 14px;
    color: var(--text);
}

[dir="rtl"] .promo-input,
[dir="rtl"] .bkv2 .promo-input-wrap .form-control {
    padding: 11px 38px 11px 14px;
}

.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;
}

.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);
}

.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;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   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;
}

/* ── 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;
    }
}

/* 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: 14px;
    }
}

/* ═══════════════════════════════════════════════════════════════════════
   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;
}
