/* Two-step booking form — stage 1 lead-capture card + stage 2 wrapper.
   Designed to embed cleanly inside a 400x650 iframe: the shell fills the
   iframe, stage 1 sits as a centred card inside that frame, stage 2 flushes
   to the iframe edges and fills the full 400x650. Content that exceeds 650
   scrolls vertically via the iframe's own scrollbar. */

html, body.ts-body {
    margin: 0;
    padding: 0;
}

.ts-body {
    background: var(--surgerly-white);
    min-height: 100vh;
    width: 100%;
    /* Centre the shell when the viewport is larger than the target 400x650
       (i.e. when the form is opened directly in a browser rather than inside
       its iframe). Inside the iframe the shell exactly fills the viewport so
       these auto margins collapse and nothing shifts. */
    display: flex;
    justify-content: center;
    align-items: stretch;
}

.ts-shell {
    width: 100%;
    max-width: 400px;
    height: 650px;
    margin: auto 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    font-family: system-ui, -apple-system, BlinkMacSystemFont, "Inter", sans-serif;
    color: var(--surgerly-black);
}

/* Cards — base (stage 1 look). Stage 2 overrides these to flush the card to
   the iframe edges. */

.ts-card {
    background: var(--surgerly-white);
    border: 1px solid color-mix(in srgb, var(--surgerly-black) 10%, var(--surgerly-white));
    border-radius: 0.5rem;
    padding: 0.85rem 0.85rem 0.95rem;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
}

/* Stage 1: matches stage 2's 400x650 dimensions. The card flex-grows to
   fill the iframe, and the form inside flex-grows again so we can use an
   auto-expanding spacer to push the consent/CTA block to the bottom —
   fields cluster at the top, the CTA sits at the bottom, and the gap
   between them grows/shrinks with the available height. */
#tsStage1 {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    margin: 0.6rem;
}

#tsStage1 .ts-form {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
}

#tsStage1 .ts-form > .ts-checkbox-row {
    margin-top: auto;
}

#tsStage1 .ts-form > .ts-checkbox-row + .ts-checkbox-row {
    margin-top: 0;
}

/* Stage 2: same card treatment as stage 1 (border / radius / shadow / gutter)
   but flex-grows to fill the iframe's 650 height. The overlay centres inside
   the card during the loading phase, and the compact form flows from the
   top once revealed. `min-height: 0` is required so the flex children below
   can respect the card's height and introduce their own scrollbar when the
   compact form's content exceeds the available space. */
.ts-card.ts-stage2 {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    margin: 0.6rem;
    /* Serve as the containing block for .ts-success-overlay. We want the
       overlay to span the full card during the loading phase (not just the
       compact-frame), so the centred content sits at the card's visual
       midpoint rather than being offset by the eyebrow above it. */
    position: relative;
}

.ts-eyebrow {
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    color: var(--surgerly-cta, var(--surgerly-primary));
    text-transform: uppercase;
    margin-bottom: 0.2rem;
    text-align: center;
}

.ts-title {
    font-size: 1.1rem;
    font-weight: 700;
    margin: 0 0 0.25rem 0;
    line-height: 1.25;
    color: var(--surgerly-black);
    text-align: center;
}

.ts-subtitle {
    font-size: 0.78rem;
    color: color-mix(in srgb, var(--surgerly-black) 55%, var(--surgerly-white));
    margin: 0 0 0.65rem 0;
    line-height: 1.35;
    text-align: center;
}

/* Stage 1 form */

.ts-form {
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
}

.ts-field-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.45rem;
}

.ts-field {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    min-width: 0;
}

.ts-field-label {
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--surgerly-black) 65%, var(--surgerly-white));
}

.ts-input,
.ts-select {
    border: 1px solid color-mix(in srgb, var(--surgerly-black) 14%, var(--surgerly-white));
    border-radius: 0.375rem;
    padding: 0.5rem 0.7rem;
    font-size: 0.85rem;
    background: var(--surgerly-white);
    color: var(--surgerly-black);
    width: 100%;
}

.ts-input::placeholder,
.ts-select:invalid {
    color: color-mix(in srgb, var(--surgerly-black) 35%, var(--surgerly-white));
}

.ts-input:focus,
.ts-select:focus {
    outline: none;
    border-color: var(--surgerly-primary);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--surgerly-primary) 18%, transparent);
}

/* Consent checkbox */

.ts-checkbox-row {
    display: flex;
    align-items: flex-start;
    gap: 0.45rem;
    padding: 0.1rem 0;
}

.ts-checkbox {
    margin-top: 0.15rem;
    flex-shrink: 0;
}

.ts-checkbox-label {
    font-size: 0.68rem;
    line-height: 1.4;
    color: color-mix(in srgb, var(--surgerly-black) 70%, var(--surgerly-white));
    margin: 0;
}

.ts-checkbox-label a {
    color: var(--surgerly-primary);
    text-decoration: underline;
}

/* CTA */

.ts-cta {
    display: block;
    width: 100%;
    background: var(--surgerly-cta, var(--surgerly-primary));
    color: var(--surgerly-white);
    border: none;
    border-radius: 0.375rem;
    padding: 0.7rem 1rem;
    font-size: 0.9rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    cursor: pointer;
    transition: filter 0.15s ease;
    margin-top: 0.25rem;
    position: relative;
}

.ts-cta:hover:not(:disabled) {
    filter: brightness(1.08);
}

.ts-cta:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.ts-cta-error {
    color: #dc2626;
    font-size: 0.72rem;
    text-align: center;
    min-height: 0.9rem;
    margin-top: 0.2rem;
}

/* Stage 2 frame — holds the success overlay and the compact form in the
   same space so switching between them doesn't change the card's height.
   The overlay is absolutely positioned over the compact form; the compact
   form starts faded out and fades in once backend data is loaded and the
   overlay sequence has played out. */

.ts-compact-frame {
    /* Grow to fill the stage 2 card so the compact form flows from the top
       once revealed; if its content exceeds the frame, the inner compact-wrap
       handles its own scrollbar. The overlay is absolute-positioned against
       the card (not the frame) so it can span the card's full height during
       the loading phase — that's why we don't set position: relative here. */
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.ts-success-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    text-align: center;
    padding: 0.5rem 0.75rem;
    transition: opacity 350ms ease, visibility 0s linear 350ms;
}

.ts-success-overlay.is-hiding {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}

/* Wrapper for the default success variant (tick + title + sub). Needs its
   own flex-column/align-center because the overlay only centres its direct
   children — without this the tick and title would fall back to default
   block left-alignment inside the wrapper. */
.ts-success-default {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.35rem;
}

.ts-success-icon {
    width: 2.4rem;
    height: 2.4rem;
    border-radius: 999px;
    background: #16a34a;
    color: var(--surgerly-white);
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 0 0.25rem;
}

.ts-success-title {
    font-size: 1rem;
    font-weight: 700;
    margin: 0;
    color: var(--surgerly-black);
}

.ts-success-sub {
    font-size: 0.78rem;
    color: color-mix(in srgb, var(--surgerly-black) 55%, var(--surgerly-white));
    margin: 0;
    line-height: 1.35;
    max-width: 20rem;
}

.ts-success-followup {
    font-size: 0.78rem;
    color: color-mix(in srgb, var(--surgerly-black) 55%, var(--surgerly-white));
    margin: 0.4rem 0 0;
    line-height: 1.35;
    max-width: 20rem;
}

.ts-success-loader {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.45rem;
    margin-top: 0.5rem;
}

.ts-success-loader .spinner-border {
    width: 1.15rem;
    height: 1.15rem;
    border-width: 0.14rem;
    color: color-mix(in srgb, var(--surgerly-black) 45%, var(--surgerly-white));
}

.ts-success-loader-text {
    font-size: 0.7rem;
    color: color-mix(in srgb, var(--surgerly-black) 55%, var(--surgerly-white));
    margin: 0;
    text-align: center;
    max-width: 16rem;
    line-height: 1.35;
}

/* Overlay price variant — shown instead of the tick/title/sub block when
   the stage 1 response includes a price_display payload. */

.ts-price-overlay {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15rem;
    margin: 0 0 0.15rem;
}

.ts-price-overlay-from {
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    color: color-mix(in srgb, var(--surgerly-black) 55%, var(--surgerly-white));
    text-transform: uppercase;
}

.ts-price-overlay-procedure {
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--surgerly-black);
    margin-bottom: 0.05rem;
    line-height: 1.2;
}

.ts-price-overlay-amount {
    font-size: 1.9rem;
    font-weight: 800;
    line-height: 1.1;
    color: var(--surgerly-primary);
    letter-spacing: -0.01em;
}

.ts-price-overlay-finance {
    font-size: 0.78rem;
    color: color-mix(in srgb, var(--surgerly-black) 60%, var(--surgerly-white));
    margin-top: 0.15rem;
}

.ts-price-overlay-finance a {
    color: var(--surgerly-cta, var(--surgerly-primary));
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* Price-flow hero (title + subtitle that sit between the eyebrow and the
   guide-price box). Hidden by default; the --with-price flag reveals them
   so non-price flows (booking/brochure/callback) don't render the price
   copy with no price beneath it. */

.ts-price-hero-title,
.ts-price-hero-subtitle {
    display: none;
    text-align: center;
    margin: 0;
}

.ts-card.ts-stage2--with-price .ts-price-hero-title {
    display: block;
    font-size: 1.25rem;
    font-weight: 800;
    line-height: 1.2;
    color: var(--surgerly-black);
    margin: 0.1rem 0 0.25rem;
    opacity: 0;
    transition: opacity 350ms ease;
}

.ts-card.ts-stage2--with-price .ts-price-hero-subtitle {
    display: block;
    font-size: 0.75rem;
    color: color-mix(in srgb, var(--surgerly-black) 60%, var(--surgerly-white));
    line-height: 1.4;
    margin: 0 0 0.6rem;
    opacity: 0;
    transition: opacity 350ms ease;
}

/* Tie the hero copy to the same fade-in moment as the eyebrow / compact
   form so it doesn't appear above an empty card during the loading phase. */
.ts-stage2-heading.is-visible ~ .ts-price-hero-title,
.ts-stage2-heading.is-visible ~ .ts-price-hero-subtitle {
    opacity: 1;
}

/* Guide-price box — the visual hero of the price flow. Sized up from the
   former slim strip to match marketing's design: a tall pink-tinted card
   with "YOUR GUIDE PRICE" eyebrow, a large amount, the finance line, and a
   confirm-in-consultation footer. Fades in with the eyebrow (mirrors
   .ts-stage2-heading's transition). */

.ts-price-strip {
    opacity: 0;
    transition: opacity 350ms ease;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.15rem;
    padding: 0.85rem 0.85rem 0.75rem;
    margin: 0 0 0.5rem;
    border-radius: 0.6rem;
    background: color-mix(in srgb, var(--surgerly-cta, var(--surgerly-primary)) 8%, var(--surgerly-white));
    border: 1.5px solid color-mix(in srgb, var(--surgerly-cta, var(--surgerly-primary)) 35%, var(--surgerly-white));
    text-align: center;
    line-height: 1.2;
}

.ts-price-strip.is-visible {
    opacity: 1;
}

.ts-price-strip-header {
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    color: var(--surgerly-cta, var(--surgerly-primary));
    text-transform: uppercase;
}

.ts-price-strip-amount {
    font-size: 1.7rem;
    font-weight: 800;
    color: var(--surgerly-black);
    line-height: 1.1;
    letter-spacing: -0.01em;
    margin: 0.1rem 0 0.05rem;
}

.ts-price-strip-finance {
    font-size: 0.72rem;
    color: color-mix(in srgb, var(--surgerly-black) 60%, var(--surgerly-white));
}

.ts-price-strip-finance a {
    color: var(--surgerly-cta, var(--surgerly-primary));
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* Reassurance pills beneath the guide price — two side-by-side cards with a
   strong line + supporting copy. Hidden until --with-price; fades in with
   the rest of the price hero. */

.ts-price-pills {
    display: none;
    grid-template-columns: 1fr 1fr;
    gap: 0.4rem;
    margin: 0 0 0.55rem;
    opacity: 0;
    transition: opacity 350ms ease;
}

.ts-card.ts-stage2--with-price .ts-price-pills {
    display: grid;
}

.ts-stage2-heading.is-visible ~ .ts-price-pills {
    opacity: 1;
}

.ts-price-pill {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.05rem;
    padding: 0.45rem 0.55rem;
    border: 1px solid color-mix(in srgb, var(--surgerly-cta, var(--surgerly-primary)) 25%, var(--surgerly-white));
    border-radius: 0.45rem;
    background: color-mix(in srgb, var(--surgerly-cta, var(--surgerly-primary)) 6%, var(--surgerly-white));
    text-align: center;
    line-height: 1.25;
}

.ts-price-pill strong {
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--surgerly-cta, var(--surgerly-primary));
}

.ts-price-pill span {
    font-size: 0.68rem;
    color: color-mix(in srgb, var(--surgerly-black) 60%, var(--surgerly-white));
}

/* When a price strip is populated we suppress the compact form's default
   header so the strip + pills become the top of the stage 2 card. */

.ts-card.ts-stage2--with-price .bfc-header {
    display: none;
}


/* Procedure picker loading skeleton — greys out six chip slots while the
   /procedures/ fetch is in flight, then tsRenderProcedureChips replaces
   them with the real chips. */

.ts-chip-skeleton {
    min-height: 2.9rem;
    border-radius: 0.375rem;
    background: linear-gradient(
        90deg,
        color-mix(in srgb, var(--surgerly-black) 6%, var(--surgerly-white)) 0%,
        color-mix(in srgb, var(--surgerly-black) 11%, var(--surgerly-white)) 50%,
        color-mix(in srgb, var(--surgerly-black) 6%, var(--surgerly-white)) 100%
    );
    background-size: 200% 100%;
    animation: tsChipShimmer 1.2s ease-in-out infinite;
    border: 1px solid color-mix(in srgb, var(--surgerly-black) 8%, var(--surgerly-white));
}

@keyframes tsChipShimmer {
    from { background-position: 100% 0; }
    to   { background-position: -100% 0; }
}

/* Sequential fade-in for each overlay element. Each item sets its own delay
   via --ts-fade-delay so the template stays declarative. */

.ts-fade-item {
    opacity: 0;
    animation: tsFadeInUp 380ms ease-out forwards;
    animation-delay: var(--ts-fade-delay, 0ms);
}

@keyframes tsFadeInUp {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Compact form — starts invisible, fades in when we're ready to reveal it.
   Takes the remaining vertical space inside the stage 2 card and scrolls
   internally if its content exceeds what the 650H iframe allows. The
   scrollbar lives in the card's right padding (via the negative margin +
   compensating padding trick) so it doesn't visually steal width from the
   form. Styled thin so it fits the gutter cleanly. */

.ts-compact-wrap {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    opacity: 0;
    transition: opacity 350ms ease;
    margin-right: -0.85rem;
    padding-right: 0.85rem;
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--surgerly-black) 22%, transparent) transparent;
}

.ts-compact-wrap::-webkit-scrollbar {
    width: 6px;
}

.ts-compact-wrap::-webkit-scrollbar-track {
    background: transparent;
}

.ts-compact-wrap::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--surgerly-black) 22%, transparent);
    border-radius: 3px;
}

.ts-compact-wrap::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--surgerly-black) 35%, transparent);
}

.ts-compact-wrap.is-visible {
    opacity: 1;
}

/* STEP 2 eyebrow is hidden until the compact form fades in, so the overlay
   is the only thing on screen during the loading phase. */

.ts-stage2-heading {
    opacity: 0;
    transition: opacity 350ms ease;
}

.ts-stage2-heading.is-visible {
    opacity: 1;
}

/* Neutralise the compact form's own centring since it's now nested inside
   the stage 2 card. */

.ts-stage2 .ts-compact-wrap .bfc-shell {
    max-width: none;
    margin: 0;
    padding: 0.25rem 0 0;
    /* Neutralise the compact form's panel styling — it's already sitting
       inside the stage 2 card, so a second border/background would produce
       a double-card effect. */
    background: transparent;
    border: none;
    box-shadow: none;
    border-radius: 0;
    /* Drop the standalone-shell's min-height — stage 2's outer card owns
       the panel sizing here, so the inner shell should hug its content. */
    min-height: 0;
}

/* Pin the compact form's header (title + subtitle) to the top of the
   scroll region so it stays visible while the form sections below scroll.
   The original <hr> divider is folded into the sticky header as a
   border-bottom, so the whole top block is a single visual unit that
   never scrolls out of view. */

.ts-card.ts-stage2 .bfc-header {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--surgerly-white);
    border-bottom: 1px solid var(--bfc-line);
    padding-bottom: 0.5rem;
    margin-bottom: 0.65rem !important;
}

.ts-card.ts-stage2 .bfc-divider {
    display: none;
}

/* Two-step iframe modals. Every .bfc-modal (the procedure picker on stage 1,
   plus the procedure / option / location / availability amend modals on
   stage 2) fills the 400x650 iframe exactly — they read as a full-screen
   takeover rather than a small popover dropped into a tiny iframe. The
   modal body handles internal scrolling; nested overflow on lists inside
   is neutralised to avoid double scrollbars. */

/* Make the modal itself a flex container when shown so the 650-tall dialog
   sits centred vertically inside taller viewports (e.g. direct-browser
   previews). Inside the 400x650 iframe the dialog fills exactly, so the
   centring is a no-op. */
body.ts-body .modal.bfc-modal.show {
    display: flex !important;
    align-items: center;
    justify-content: center;
}

body.ts-body .bfc-modal .modal-dialog {
    width: 100%;
    max-width: 400px;
    height: 650px;
    /* Bootstrap's .modal-dialog-centered applies min-height: calc(100% - …)
       to stretch the dialog to the full modal height — on a direct-browser
       test that's way bigger than 650 and beats our `height: 650px`. Reset
       it so the explicit height wins. */
    min-height: 0;
    max-height: 100vh;
    margin: 0;
    align-items: stretch;
}

body.ts-body .bfc-modal .modal-content {
    flex: 1 1 auto;
    max-height: 100%;
    display: flex;
    flex-direction: column;
}

body.ts-body .bfc-modal .modal-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--surgerly-black) 22%, transparent) transparent;
}

body.ts-body .bfc-modal .modal-body::-webkit-scrollbar {
    width: 6px;
}

body.ts-body .bfc-modal .modal-body::-webkit-scrollbar-track {
    background: transparent;
}

body.ts-body .bfc-modal .modal-body::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--surgerly-black) 22%, transparent);
    border-radius: 3px;
}

body.ts-body .bfc-modal .modal-body::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--surgerly-black) 35%, transparent);
}

body.ts-body .bfc-modal .modal-body .bfc-list {
    max-height: none;
    overflow-y: visible;
}

/* Availability modal specifically — the compact CSS caps its modal-body at
   75vh and relies on content-driven height, which leaves a big empty gap
   below the specialist list inside the 650-tall iframe modal. Override so
   the shell/grid/results chain flex-fills the full height instead. */

body.ts-body .bfc-availability-modal .modal-body {
    max-height: none;
    display: flex;
    flex-direction: column;
}

body.ts-body .bfc-availability-modal .availability-shell {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

body.ts-body .bfc-availability-modal .availability-grid {
    flex: 1 1 auto;
    min-height: 0;
    grid-template-rows: auto 1fr;
}

body.ts-body .bfc-availability-modal .availability-results {
    min-height: 0;
    display: flex;
    flex-direction: column;
}

body.ts-body .bfc-availability-modal .specialist-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* Modal backdrop is made transparent by booking_form_compact.css, which is
   loaded on this page too — no need to re-declare it here. */
