/*
VARS LOADED FROM SITE THEME BASED ON PHP SELECTION
*/

    html {
        touch-action: manipulation;
    }

/* General Styles */
    body {
        color: var(--font-color);
        background-color: var(--bg-color);
        background-size: cover;
        background-attachment: fixed; 
        background-position: top center;
        height: 100%;   
        font-family: var(--body-font) !important;
        transition: all 0.3s ease;
    }

    .txt-green {
        color: var(--font-green);
    }

    .txt-orange {
        color: var(--accent-light-orange) !important;
    }

    .txt-blue {
        color: var(--font-blue);
    }

    .txt-white {
        color: var(--font-white);
    }

    .txt-left {
        text-align: left;
    }

    .txt-center {
            text-align: center;
    }

    .txt-right {
        text-align: right;
    }
        
    /* Theme Styles */
    .mode-dark {
        background-color: var(--bg-dark-color);
        color: var(--font-dark-color);
    }

    .mode-light {
        background-color: var(--bg-light-color);
        color: var(--font-light-color);
    }

    .disable-animations {
        transition: none !important;
        animation: none !important;
    }

    .disable-animations * {
        transition: none !important;
        animation: none !important;
    }
        
    h1, h2, h3, h4, h5, h6 {
        color: var(--heading-color);
        font-family: var(--heading-font) !important;
    }

    .mode-light h1, .mode-light h2, .mode-light h3, .mode-light h4, .mode-light h5, .mode-light h6 {
        color: var(--heading-light-color);
        font-weight: 500;
    }

    .mode-dark h1, .mode-dark h2, .mode-dark h3, .mode-dark h4, .mode-dark h5, .mode-dark h6 {
        color: var(--heading-dark-color);
        font-weight: 500;
    }


    /* Fluid type: the old fixed px is each clamp()'s floor, so phones render
       what they always did while wider screens grow into the ceiling. */
    h1 {
        font-size: clamp(24px, 20.5px + 1vw, 32px) !important;
        font-weight: 600;
    }

    h2 {
        font-size: clamp(24px, 20.5px + 1vw, 32px) !important;
        font-weight: 400;
    }

    h3 {
        font-size: clamp(22px, 19px + .8vw, 28px) !important;
        font-weight: 300;
    }

    h4 {
        font-size: clamp(20px, 17.5px + .7vw, 25px) !important;
        font-weight: 300;
    }

    h5 {
        font-size: clamp(16px, 14.5px + .45vw, 19px) !important;
        font-weight: 300;
    }

    h6 {
        font-size: clamp(16px, 14.5px + .45vw, 19px) !important;
        font-weight: 100;
    }

    .fs-12 {
        font-size: 10px !important;
    }
        
    .fw-100{
        font-weight: 100 !important;
    }
    .fw-200{
        font-weight: 200 !important;
    }
    .fw-300{
        font-weight: 300 !important;
    }
    .fw-400{
        font-weight: 400 !important;
    }
    .fw-500{
        font-weight: 500 !important;
    }
    .fw-600{
        font-weight: 600 !important;
    }
    .fw-700{
        font-weight: 700 !important;
    }
    .fw-800{
        font-weight: 800 !important;
    }
        
    p {
      color: var(--font-color);
      font-size: 16px;
      transition: all 0.3 ease;
      font-family: var(--body-font) !important;
    }

    .mode-dark p {
        color: var(--font-dark-color);
    }

    .mode-light p {
        color: var(--font-light-color);
    }

    .social {
        color: var(--icon-color);
        transition: all 0.3 ease;
    }

    .mode-light .social {
        color: var(--icon-light-color);
        transition: all 0.3 ease;
    }    

    .mode-dark .social {
        color: var(--icon-dark-color);
        transition: all 0.3 ease;
    }

    .social:hover {
        color: var(--accent-orange);
        transition: all 0.3 ease;
    }

    .mode-light .social:hover {
        color: var(--accent-orange);
        transition: all 0.3 ease;
    }    

    .mode-dark .social:hover {
        color: var(--accent-dark-orange);
        transition: all 0.3 ease;
    }

    
    .icon {
        color: var(--icon-color);
    }

    .mode-light .icon {
        color: var(--icon-light-color);
    }    

    .mode-dark .icon {
        color: var(--icon-dark-color);
    }
        
    /* Custom Container */
    .location-container {
        background-color: rgba(255, 255, 255, 1);
        transition: background-color 0.3s ease, box-shadow 0.3s ease;
    }

    .mode-dark .location-container {
        background-color: rgba(11, 11, 11, 1);
    }

    /* Storefront background image: when a studio has a cascaded background
       (body.has-storefront-bg, set by the layout), the full-bleed container
       goes transparent so the photographer's background shows edge-to-edge.
       White surfaces then come only from the floating cards (#bookingCard,
       .location-card) and the revealed packages section (.main-area). Studios
       with no background image keep the opaque container above (no regression). */
    body.has-storefront-bg .location-container,
    body.has-storefront-bg.mode-dark .location-container {
        background-color: transparent;
    }

    /* Custom Card */
    .location-card {
        border: none;
        max-width: 655px;
        height: 456px;
        border-radius: 15px;
        margin: 24px auto;
        background-color: var(--bg-color);
        color: var(--font-color);
        transition: background-color 0.3s ease, box-shadow 0.3s ease;
    }

    .mode-light .location-card {
        background-color: var(--bg-color);
        color: var(--font-color);
    }
        
    .mode-dark .location-card {
        background-color: var(--bg-dark-color);
        color: var(--font-dark-color);
    }

    @media (max-width: 992px) {
        .location-card {
            height: 100%;
        }
    }

    .themeImage {
        max-height: 50px;
    }

    /* Accessibility Styles */
    .large-cursor {
        cursor: zoom-in;
    }

    /* Buttons and Icons */
    .menu-button {
        font-size: 24px;
        cursor: pointer;
    }

    .menu-icon {
        margin-left: -2px;
        border-radius: 50%;
        width: 40px;
        height: 40px;
        font-size: 24px;
        color: var(--icon-color);
        background-color: var(--bg-color);
        display: flex;
        justify-content: center;
        align-items: center;
        border: none;
        cursor: pointer;
    }

    .light-mode .menu-icon {
        color: var(--icon-light-color);
    }

    .dark-mode .menu-icon {
        color: var(--icon-dark-color);
    }
        
    /* Active Styles */
    .active {
        display: block;
    }

    .shadow {
        box-shadow: 0px 0px 24px var(--soft-shadow);
    }

    /* Accessibility Button */
    .accessibility-btn {
        position: fixed;
        left: 2vw;
        bottom: 2vh;
        font-size: 36px;
        line-height: 48px;
        background-color: var(--accessibility-blue);
        color: var(--font-dark-color);
        width: 48px;
        height: 48px;
        border-radius: 50%;
        border: none;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        z-index: 3000;
        transition: all 0.3s ease-in;
        box-shadow: 0px 0px 24px var(--soft-shadow);
    }
    
    .accessibility-btn.bottom {
        width: 24px;
        height: 24px;
        line-height: 24px;
        font-size: 20px;
        left: 20px;
        bottom: 11px;
        background-color: var(--bg-dark-color);
    }    

    @media (max-width: 761px) {
        .accessibility-btn.bottom {
            left: -40px;
            bottom: -40px;
        }
    }
        
    .mode-dark .accessibility-btn {
        background-color: var(--bg-light-color);
        color: var(--accessibility-blue);
    }
        
    .accessibility-menu-btn {
        border-color: var(--accessibility-blue);
        color: var(--accessibility-blue);
        padding: 10px 6px;
        line-height: 1.2;
    }

    .accessibility-menu-btn:hover,
    .accessibility-menu-btn:focus {
        background-color: var(--accessibility-blue);
        border-color: var(--accessibility-blue);
        color: #fff;
    }

    .accessibility-menu-btn.active {
        background-color: var(--accessibility-blue);
        border-color: var(--accessibility-blue);
        color: #fff;
    }

    .mode-dark .accessibility-menu-btn {
        border-color: var(--bg-light-color);
        color: var(--bg-light-color);
    }

    .mode-dark .accessibility-menu-btn:hover,
    .mode-dark .accessibility-menu-btn:focus,
    .mode-dark .accessibility-menu-btn.active {
        background-color: var(--bg-light-color);
        color: var(--accessibility-blue);
    }

    .accessibility-menu {
        position: fixed;
        opacity: 0;
        color: var(--accessibility-blue);
        border-radius: 25px;
        border: 5px solid var(--accessibility-blue);
        bottom: 2vh;
        left: 2vw;
        height: 0px;
        width: 0px;
        background-color: var(--bg-color);
        padding: 20px;
        overflow-y: auto;
        z-index: 2000;
        box-shadow: 0px 0px 200px var(--soft-shadow);
        transition: all 0.3s ease;
    }
    
    .accessibility-menu.bottom{
        bottom: 12px; 
        left: 21px; 
    }
        
    .mode-dark .accessibility-menu {
        color: var(--font-dark-color);
        border: 5px solid var(--bg-light-color);
        background-color: var(--accessibility-blue);
    }
        
    .mode-dark .accessibility-menu .btn {
        color: var(--font-dark-color);
        border-color: var(--bg-light-color);
        background-color: var(--accessibility-blue);
    }
        
    .mode-dark .accessibility-menu .btn:hover {
        background-color: var(--font-blue);
    }

    .accessibility-menu h2 {
        color: var(--accessibility-blue);
    }
    
    .mode-dark .accessibility-menu h2 {
        color: var(--heading-dark-color);
    }

    .accessibility-menu.active {
        opacity: 1;
        height: auto;
        max-height: 85vh;
        width: min(425px, 96vw);
        max-width: calc(100vw - 4vw);
    }
        
        
    /* Language */
        
    /* language Button */
    .language-btn {
        position: fixed;
        right: 20px;
        top: 20px;
        font-size: 28px;
        line-height: 28px;
        background-color: var(--accessibility-blue);
        color: var(--font-dark-color);
        width: 32px;
        height: 32px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        z-index: 3000;
        transition: all 0.3s ease-in;
        box-shadow: 0px 0px 24px var(--soft-shadow);
    }
    
    .language-btn.bottom {
        width: 24px;
        height: 24px;
        line-height: 24px;
        font-size: 20px;
        right: 11px;
        top: 11px;
        background-color: var(--bg-dark-color);
    }

    @media (max-width: 761px) {
        .language-btn.bottom {
            right: -40px;
            top: -40px;
        }
    }
    
    .mode-dark .language-btn {
        background-color: var(--bg-light-color);
        color: var(--accessibility-blue);
    }
        
    .language-menu-btn .active {
        background-color: var(--bg-light-color);
        color: var(--accessibility-blue);
    }
        
    .mode-dark .language-menu-btn .active {
        background-color: var(--bg-light-color);
        color: var(--accessibility-blue);
    }

    .language-menu {
        position: fixed;
        opacity: 0;
        color: var(--accessibility-blue);
        border-radius: 25px;
        border: 5px solid var(--accessibility-blue);
        right: 20px;
        top: 20px; 
        width: 0px;
        height: 0px; 
        background-color: var(--bg-color);
        padding: 20px;
        overflow-y: auto;
        z-index: 2000;
        box-shadow: 0px 0px 200px var(--soft-shadow);
        transition: all 0.3s ease;
    }

    .language-menu.bottom {
        right: 11px;
        top: 11px;
    }
        
    .language-menu.active {
        opacity: 1;
        right: 20px;
        height: 475px; 
        width: 225px; 
    }        
        
    .mode-dark .language-menu {
        color: var(--font-dark-color);
        border: 5px solid var(--bg-light-color);
        background-color: var(--accessibility-blue);
    }
        
    .mode-dark .language-menu .btn {
        color: var(--font-dark-color);
        border-color: var(--bg-light-color);
        background-color: var(--accessibility-blue);
    }
        
    .mode-dark .language-menu .btn:hover {
        background-color: var(--font-blue);
    }

    .language-menu h2 {
        color: var(--accessibility-blue);
    }
    
    .mode-dark .language-menu h2 {
        color: var(--heading-dark-color);
    }

    .sidebar{
        background-color: var(--bg-light-color);
    }

    .mode-dark .sidebar {
        background-color: var(--bg-dark-color);
    }

    /* SIDEBAR */
    a.sidebar-link  {
        text-decoration: none;
        cursor: pointer;
        color: var(--font-light-color);
        font-size: 32px;
        font-weight: 100;
        line-height: 48px;
        transition: all 0.3s ease-in-out;
    }

    .mode-dark a.sidebar-link  {
        color: var(--font-dark-color);
        transition: all 0.3s ease-in-out;
    }

    a.sidebar-link:hover  {
        color: var(--accent-orange);
    }

    .mode-dark a.sidebar-link:hover  {
        color: var(--accent-dark-orange);
    }

     a.sidebar-link-sm  {
        text-decoration: none;
        cursor: pointer;
        color: var(--bg-dark-secondary);
        font-size: 18px;
        font-weight: 600;
        line-height: 24px;
        transition: all 0.3s ease-in-out;
    }

    .mode-dark a.sidebar-link-sm  {
        color: var(--bg-light-secondary);
        transition: all 0.3s ease-in-out;
    }

    a.sidebar-link-sm:hover  {
        color: var(--accent-orange);
    }

    .mode-dark a.sidebar-link-sm:hover  {
        color: var(--accent-orange);
    }

       
    /* MINI CART */
        
    /* Accessibility Button */
    .cart-menu {
        position: fixed;
        pointer-events: none;
        opacity: 0;
        color: var(--accessibility-blue);
        border-radius: 25px 0px 0px 25px;
        top: 0px; 
        right: -400px; 
        height: 100%; 
        width: 40%; 
        background-color: var(--bg-color);
        padding: 20px;
        overflow-y: auto;
        z-index: 5000;
        box-shadow: 0px 0px 200px rgba(0, 0, 0, 0.5);
        transition: all 0.3s ease;
    }

    @media (max-width: 761px) {
        .cart-menu {
            height: 100%; 
            width: 90%; 
        }
    }
        
    .cart-menu.active {
        pointer-events: auto;
        opacity: 1;
        top: 0px; 
        right: 0px; 
    }
        
        
    .mode-dark .cart-menu {
        color: var(--font-dark-color);
        border: 5px solid var(--bg-dark-secondary);
        background-color: var(--bg-dark-secondary);
    }
        
    .cart-menu h2 {
        color: var(--heading-light-color);
    }
    
    .mode-dark .cart-menu h2 {
        color: var(--heading-dark-color);
    }

        

    /* Reset and Skip Link */
    .skip-link {
        position: absolute;
        color: rgba(250, 249, 246, 1);
        z-index: 1000;
    }

    .skip-link {
        top: -50px;
        left: 0;
        padding: 10px;
        text-decoration: none;
    }

    .skip-link:focus {
        top: 0;
    }

    .reset-btn {
        margin-top: 1rem;
        background-color: rgba(220, 53, 69, 1);
        color: rgba(250, 249, 246, 1);
        width: 100%;
        text-align: center;
        padding: 0.5rem;
        cursor: pointer;
    }

    .reset-btn:hover {
        background-color: rgba(200, 35, 51, 1);
    }

    img {
        filter: brightness(100%);
        transition: all 0.3s ease;
    }

    .mode-dark img {
        filter: brightness(100%);
    }

    .bannerImage{
        max-width: 95vw;
        max-height: 150px;
        padding-top: 25px;
        padding-bottom: 25px;
    }

    .heroImage {
        max-width: 100%;
        max-height: 425px;
        border-radius: 9px;
        border: 10px solid var(--heading-light-color);
        transition: all 0.3s ease;
    }

    .mode-dark .heroImage {
        border: 10px solid var(--heading-dark-color);
    }

    .circle {
        background-color: var(--heading-light-color);
        width: 50px;
        height: 50px;
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-items: center;
        animation: bounceAndPulse 1.5s infinite ease-in-out;
    }

    .fa-chevron-down {
        font-size: 20px;
        color: rgba(255, 255, 255, 1); 
    }

    .mode-dark .circle {
        background-color: var(--heading-dark-color);
    }

    .mode-dark .fa-chevron-down {
        color: rgba(6, 5, 80, 1);
    }

    @keyframes bounce {
        0% {
            transform: translateY(0);
        }
        100% {
            transform: translateY(10px);
        }
    }

    @keyframes bounceAndPulse {
        0%, 100% {
            transform: translateY(0) scale(1);
            box-shadow: 0px 15px 20px rgba(0, 0, 0, 0.5); 
        }
        50% {
            transform: translateY(10px) scale(1.1);
            box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.3); 
        }
    }

    @keyframes pulse {
        0% {
            transform: scale(1);
        }
        50% {
            transform: scale(1.1);
        }
        100% {
            transform: scale(1);
        }
    }

    .gallery-counts div {
        display: inline-block;
        min-width: 44%;
        padding: 5px;
        border-radius: 25px;
    }

    .gallery-counts {
        display: flex;
        justify-content: space-between;
    }

    .flex-column {
        flex-direction: column;
        align-items: center;
    }

    @media (max-width: 992px) {
        .gallery-counts div {
            display: block;
            margin-bottom: 10px;
        }
    }

    .prepaid {
        opacity: 0.6;
        background-color: var(--prepaid-background-color);
        border: 2px solid var(--prepaid-border-color);
        transition: all 0.3s ease;
    }

    .prepaid p {
        color: var(--prepaid-font-color);
        opacity: 1;
        font-weight: 500;
        transition: all 0.3s ease;
    }
        
    .prepaid i {
        color: var(--prepaid-icon-color);
        transition: all 0.3s ease;
    }

    .rounded {
        border-radius: 25px !important;
    }

    .border-none {
        border: 0px solid #fff !important;
    }

    .menu-cart {
        background-color: var(--cart-grey);
        border-radius: 25px;
        display: flex;
        align-items: baseline;
        padding: 0px 10px 0px 10px;
        justify-content: space-between;
        transition: all 0.3s ease;
    }


    .mode-dark .menu-cart {
        background-color: var(--cart-dark-grey);
    }

    .circle-total {
        position: relative;
        left: -24px;
        top: -10px;
        height: 20px;
        width: 20px;
        border-radius: 50%;
        line-height: 20px;
        text-align: center;
        font-size: 10px;
        transform: scale(1);
    }

    /* ⚠ NO height/width HERE. This rule squats on Bootstrap's `.badge`, and a
     * 20x20 box is a CART COUNTER, not a badge — it crushed every text badge in
     * the app (the offer pill, "Sold Out", "Variation") into a 20px square that
     * clipped its own label. The fixed-circle counters have their own classes:
     * `.badge-sm` / `.badge-lg` below, and `.circle-total` above. */
    .badge {
        line-height: 10px;
        font-size: 10px;
        text-align: center;
        transform: scale(1);
        transition: all 0.3s ease-in-out;
        z-index: 2;
    }

    .badge-sm {
        height: 18px;
        width: 18px;
        line-height: 18px;
        font-size: 8px;
        text-align: center;
        transform: scale(1);
        transition: all 0.3s ease-in-out;
        z-index: 2;
    }

    .badge-lg {
        height: 30px;
        width: 30px;
        line-height: 30px;
        font-size: 20px;
        text-align: center;
        transform: scale(1);
        transition: all 0.3s ease-in-out;
        z-index: 2;
    }

    .bdg-green {
        background-color: var(--prepaid-font-color);
        border-color: var(--prepaid-font-color);
        transition: all 0.3s ease-in-out;
    }
    
    .bdg-dark {
        background-color: var(--bg-dark-secondary);
        border-color: var(--bg-dark-secondary);
        box-shadow: 0 0 0 0 var(--bg-dark-secondary);
    }

    .bdg-orange {
        background-color: var(--accent-light-orange);
        border-color: var(--accent-light-orange);
        transition: all 0.3s ease-in-out;
    }

    .bdg-light-pulse {
        background-color: var(--bg-light-color);
        border-color: var(--bg-light-color);
        animation: pulse 2.3s infinite;
        transition: all 0.3s ease-in-out;
    }

    .bdg-light-pulse:nth-child(odd) {
      animation: pulse 2.3s infinite; 
    }

    .bdg-light-pulse:nth-child(even) {
      animation: pulse 1.6s infinite;
    }

    .bdg-light-pulse:nth-child(1) {
      animation: pulse 2.1s infinite; 
    }

    .bdg-light-pulse:nth-child(4) {
      animation: pulse 1.9s infinite; 
    }

    .bdg-light-pulse:nth-child(6) {
      animation: pulse 2.4s infinite; 
    }

    .bdg-green-pulse {
        background-color: var(--prepaid-font-color);
        border-color: var(--prepaid-font-color);
        box-shadow: 0 0 0 0 var(--prepaid-font-color);
        animation: pulseGreen 1.9s infinite;
        transition: all 0.3s ease-in-out;
    }
    
    .bdg-dark-pulse {
        background-color: var(--bg-dark-secondary);
        border-color: var(--bg-dark-secondary);
        box-shadow: 0 0 0 0 var(--bg-dark-secondary);
    }

    .bdg-orange-pulse {
        background-color: var(--accent-light-orange);
        border-color: var(--accent-light-orange);
        box-shadow: 0 0 0 0 var(--accent-light-orange);
        animation: pulseOrange 1.7s infinite;
        transition: all 0.3s ease-in-out;
    }

    .circle-green {
        color: rgba(255, 255, 255, 1);
        background-color: rgba(44, 182, 167, 1);
        box-shadow: 0 0 0 0 rgba(44, 182, 167, 1);
        animation: pulseGreen 1.9s infinite;
        transition: all 0.3s ease-in-out;
    }

    .circle-orange {
        color: rgba(255, 255, 255, 1);
        background-color: var(--accent-dark-orange);
        box-shadow: 0 0 0 0 var(--accent-dark-orange);
        animation: pulseOrange 1.7s infinite;
        transition: all 0.3s ease-in-out;
    }

    .mode-dark .circle-green {
        color: rgba(255, 255, 255, 1);
        background-color: rgba(44, 182, 167, 0.8);
        box-shadow: 0 0 0 0 rgba(44, 182, 167, 0.8);
        animation: pulseGreen 1.9s infinite;
    }

    .mode-dark .circle-orange {
        color: rgba(255, 255, 255, 1);
        background-color: rgba(238, 81, 58, 0.8);
        box-shadow: 0 0 0 0 rgba(238, 81, 58, 0.8);
        animation: pulseOrange 1.7s infinite;
    }

    .mode-dark .prepaid {
        opacity: 1;
    }

    .mode-dark .prepaid p {
        opacity: 1;
    }

    .container-fluid {
        margin-left: 0;
        margin-right: 0;
        padding-left: 0;
        padding-right: 0;
    }

    .row {
        margin-left: 0;
        margin-right: 0;
        padding-left: 0;
        padding-right: 0;
    }

    .secondary-menu {
        background-color: var(--bg-color);
        color: rgba(6, 5, 80, 1);
        transition: all 0.3s ease;
    }

    .mode-dark .secondary-menu {
    background-color: rgba(42, 42, 42, 1);
    color: rgba(255, 255, 255, 1);
    }

    .mode-dark .modal-content {
    background-color: rgba(42, 42, 42, 1);
    border: 3px solid var(--accent-orange);
    color: rgba(255, 255, 255, 1);
    box-shadow: 0px 0px 44px var(--soft-shadow);
    }

    .mode-light .secondary-menu {
        background-color: var(--bg-light-color);
        color: rgba(6, 5, 80, 1);
        transition: all 0.3s ease;
    }
    @keyframes pulse {
        0% {
            transform: scale(0.95);
            box-shadow: 0 0 0 0 rgba(244, 244, 244, 0.7);
        }

        70% {
            transform: scale(1);
            box-shadow: 0 0 0 9px rgba(244, 244, 244, 0);
        }

        100% {
            transform: scale(0.95);
            box-shadow: 0 0 0 0 rgba(244, 244, 244, 0);
        }
    }

    @keyframes pulseOrange {
        0% {
            transform: scale(0.95);
            box-shadow: 0 0 0 0 rgba(238, 81, 58, 0.7);
        }

        70% {
            transform: scale(1);
            box-shadow: 0 0 0 10px rgba(238, 81, 58, 0);
        }

        100% {
            transform: scale(0.95);
            box-shadow: 0 0 0 0 rgba(238, 81, 58, 0);
        }
    }

    @keyframes pulseGreen {
        0% {
            transform: scale(0.95);
            box-shadow: 0 0 0 0 rgba(44, 182, 167, 0.7);
        }

        70% {
            transform: scale(1);
            box-shadow: 0 0 0 10px rgba(238, 81, 58, 0);
        }

        100% {
            transform: scale(0.95);
            box-shadow: 0 0 0 0 rgba(238, 81, 58, 0);
        }
    } 

    @keyframes flashingAnimation {
        0% {
            opacity: 1;
        }
        100% {
            opacity: 0.5;
        }
    }

    .category-item {
        transition: all 0.3s ease;
    }

    .category-item .btn {
        border-color: var(--accent-orange);
        color: var(--accent-orange);
        transition: all 0.3s ease;
    }

    .category-item .btn:hover {
        background-color: var(--accent-orange);
        color: var(--font-dark-color);
    }

    .category-item.active .btn {
        background-color: var(--accent-orange);
        color: var(--font-dark-color);
        font-weight: 800;
    }

    .category-card h5{
        color: var(--heading-color);
        padding-top: 5px;
        cursor: pointer;
        transition: all 0.3s ease-in-out;
    }

    .category-card:hover h5{
        color: var(--accent-dark-orange);
        transition: all 0.3s ease-in-out;
    }

    .mode-dark .category-item.active h5 {
        color: var(--heading-dark-color);
    }

    .mode-dark .category-card:hover h5{
        color: var(--heading-dark-color);
        transition: all 0.3s ease-in-out;
    }
    
    .mode-dark .category-card h5{
        color: var(--accent-dark-orange);
        transition: all 0.3s ease-in-out;
    }

    #products {
        top: 62px;
        padding-top: 15px;
        transition: all 0.3s ease;
    }

    #products.highlight {
        }

    .mode-dark #products {
        transition: all 0.3s ease;
    }

    .mode-dark #products.highlight {
    }

    #products-container {
        height: 0px;
        opacity: 0;
        pointer-events: none;
        transition: all 0.5s ease;
    }

    .mode-dark #products-container {
    }

    #products-container.show {
        height: 100%;
        pointer-events: auto;
        opacity: 1;
    }

    #products-container .card {
        margin-top: 15px;
        border: 2px solid var(--bg-light-color);
        transition: all 0.3s ease-in-out;
    }

    .mode-dark #products-container .card {
        background-color: var(--cart-dark-grey);
    }

    #products-container .card:hover {
        border-color: var(--accent-orange);
        box-shadow: 0px 0px 22px var(--soft-shadow);
    }

    .mode-dark #products-container .card:hover {
        border-color: var(--accent-orange);
        box-shadow: 0px 0px 22px var(--soft-shadow);
    }

    #products-container .card.h-100.product.selected {
        transition: all 0.3s ease;
        border-color: var(--accent-orange);
        background-color: var(--bg-light-secondary);
        box-shadow: 0px 0px 11px var(--accent-orange), 0px 0px 44px var(--soft-shadow);
        transform: scale(1.01);
    }

    .mode-dark #products-container .card.h-100.product.selected {
        border-color: var(--accent-dark-orange);
        background-color: var(--bg-dark-secondary);
        box-shadow: 0px 0px 66px var(--soft-shadow);
        transform: scale(1.02);
    }

    .product-image {
        border-radius: 10px;
    }

    .product-img {
        max-width: 75px;
        max-height: 75px;
        transition: all 0.3 ease;
    }

    .product-img:hover {
        transform: scale(1.1);
    }

    .spin-out {
        transform: rotate(360deg);
    }

    .gallery-item {
        position: relative;
    }

    .overlay {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: rgba(255, 255, 255, 0.75);
        justify-content: center;
        align-items: center;
        pointer-events: none;
        display: flex;
        z-index: 1;
        opacity: 0;
        visibility: visible;
        transition: opacity 0.2s ease-in-out, visibility 0s linear 0.3s;
    }

    .overlay.active {
        opacity: 1; 
        visibility: visible; 
        transition: opacity 0.2s ease-in-out, visibility 0s linear; 
    }

    .overlay-content {
        text-align: center;
        color: white;
    }

    .prepaid-footer {
        position: fixed;
        bottom: -100%;
        left: 0px;
        background-color: var(--prepaid-background-color);
        color: var(--prepaid-font-color);
        border-radius: 25px 25px 0px 0px;
        padding: 10px;
        transition: all 0.3s ease;
    }

    .fixed-bottom {
        bottom: 0;
        left: 0;
    }

    /* Define the style for the underline */
.fancy-underline {
    position: relative;
    display: inline-block;
    text-decoration: none;
    color: inherit;
}

/* Create the pseudo-element for the underline */
.fancy-underline::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: 0;
    width: 0%;
    height: 2px;
    background-color: var(--accent-orange); /* Change this to your preferred underline color */
    transition: width 0.3s ease;
}

/* Define the hover effect */
.fancy-underline:hover::after {
    width: 98%;
}

/* Optional: Adjustments for links */
.fancy-underline:hover {
    color: inherit;
}

#carousel {
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
}

.carousel {
    height: 70vh;
    border: 20px solid var(--heading-light-color);
    background-color: var(--heading-light-color);
    border-radius: 25px;
}

.carousel-item {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 70vh;
}

.carousel-item img {
    max-height: 65vh;
    width: auto;
    max-width: 100%;
    height: auto;
    object-fit: contain;
    opacity: 0%;
}

.cimage {
    animation: slideshow 5s infinite ease-in-out; 
}

@keyframes slideshow {
    0% {
        opacity: 0%;
    }
    25% {
        opacity: 100%;
    }
    75% {
        opacity: 100%;
    }
    100% {
        opacity: 0%;
    }
}



#activeProduct .card {
    border: 3px solid var(--accent-color);
    text-align: left !important;
}

.mode-dark #activeProduct .card {
    border: 3px solid var(--accent-dark-orange);
    background-color: var(--cart-dark-grey);
    color: var(--heading-dark-color);
}

#activeProduct .card .btn {
    position: absolute;
    background-color: var(--accent-orange);
    border: 3px solid var(--bg-light-color);
    color: var(--font-dark-color);
    bottom: -20px;
    left: 25%;
    right: 25%;
    margin: 0 auto;
    transition: all 0.3 ease;
}

#activeProduct .card .btn:hover {
    background-color: var(--bg-light-color);
    border: 2px solid var(--accent-orange);
    color: var(--accent-orange);

}

.btn {
    border-radius: 20px;
    cursor: pointer;
    padding: 10px;
    font-weight: 800;
}

.btn-danger {
    cursor: pointer;
    background-color: var(--accent-orange);
    border-color: var(--accent-orange);
}

.btn-danger:hover {
    border-color: var(--accent-orange);
    color: var(--accent-orange);
    background-color: var(--bg-light-color);
}

.btn-outline-danger {
    cursor: pointer;
    background-color: var(--bg-light-color);
    border: 2px solid var(--accent-orange);
    color: var(--accent-orange);
}

.btn-outline-danger:hover {
    background-color: var(--accent-orange);
    border: 2px solid var(--bg-light-color);
    color: var(--bg-light-color);
}

/* Solid brand button — the SECONDARY CTA rail. The studio accent stays the
   primary action (.btn-danger above); this is the calmer "go somewhere" button,
   and it was the last stock-Bootstrap blue left on the booking flow.

   Ink is --bg-light-color rather than a fixed white on purpose: every palette
   defines --heading-color to be legible ON --bg-light-color, so the reverse
   pairing inherits that same contrast — including the gold-on-charcoal themes,
   where white ink on the heading colour would fail outright. */
.btn-primary {
    background-color: var(--heading-color);
    border-color: var(--heading-color);
    color: var(--bg-light-color);
}

.btn-primary:hover,
.btn-primary:focus-visible {
    background-color: var(--bg-light-color);
    border-color: var(--heading-color);
    color: var(--heading-color);
}

.btn-outline-primary {
    background-color: var(--bg-light-color);
    border: 1px solid var(--heading-light-color);
    color: var(--heading-light-color);
    margin-bottom: 2px;
}

/* Waitlist button — the LAST stock-Bootstrap colour on the flow, and on this
   platform .btn-warning has exactly one meaning: all six call sites are
   "Join Waitlist", the affordance a customer gets when a service or a whole
   location has nothing left to book.

   FIXED amber, not a palette token, for the same reason the alert accents and
   .bk-tone--* are fixed: this button says "the thing you wanted is gone, here
   is the other path". A studio must not be able to repaint that into its own
   Book-button colour, where it would read as the primary action, or into
   something invisible. It reuses --bk-alert-warning (declared on :root further
   down, with the rest of the semantic accents) so there is one amber on the
   platform rather than two that nearly match.

   ⚠ It does NOT invert on hover the way .btn-danger / .btn-primary do. Those
   swap to a --bg-light-color background, and eight of the 24 palettes define
   that as a near-black — which would put this amber text at roughly 3.7:1.
   Staying solid and deepening keeps white ink on amber at 5:1 on every palette,
   because both colours are fixed. Bootstrap's own default here is worse still:
   #ffc107 with BLACK ink, which is the yellow that was screaming. */
.btn-warning {
    background-color: var(--bk-alert-warning);
    border-color: var(--bk-alert-warning);
    color: #fff;
}

.btn-warning:hover,
.btn-warning:focus-visible {
    background-color: #994608;
    border-color: #994608;
    color: #fff;
}

@supports (color: color-mix(in srgb, red, blue)) {
    .btn-warning:hover,
    .btn-warning:focus-visible {
        background-color: color-mix(in srgb, var(--bk-alert-warning) 85%, #000);
        border-color: color-mix(in srgb, var(--bk-alert-warning) 85%, #000);
    }
}

.btn-outline-primary:hover {
    background-color: var(--bg-light-color);
    border: 1px solid var(--accent-orange);
    color: var(--accent-orange);
}

.btn-square {
    width: 51px; 
    height: 52px;
    border-radius: 10px;
    transition: all 0.3 ease-in-out;
}

.btn-square.active {
    border: 2px solid var(--accent-orange);
    color: var(--accent-orange);
}

.donation-added {
    background-color: var(--accent-orange);
    color: var(--font-dark-color);
    border-radius: 10px;
}

.toast {
    pointer-events: none;
    margin-top: 15px;
    box-shadow: 0px 0px 44px var(--soft-shadow);
}

.mode-dark .toast-header {
    background-color: #000 !important;
    color: var(--accent-orange) !important;
}

.mode-dark .toast {
    background-color: #111 !important;
}

img.logo {
    max-height: 75px;
    width: auto;
    transition: all 0.3s ease;
}

.live img.logo {
    max-height: 75px;
}

.secondary-menu img.logo {
    max-height: 75px;
}

.secondary-menu .live img.logo {
        max-height: 50px;   
    }

@media (max-width: 761px) {
    .secondary-menu img.logo {
        max-height: 50px;
    }
    
    .secondary-menu .live img.logo {
        max-height: 40px;   
    }
}

.secondary-menu img.logo {
    max-height: 50px;
}

.donation-logo{
    max-height: 75px;
}

.donation-text{
    font-weight: 500;
    font-size: 14px;
    color: var(--heading-light-color);
}

.mode-dark .donation-text{
    color: var(--heading-dark-color);
}

.donation-link{
    font-weight: 100;
    font-size: 12px;
    text-decoration: none;
    color: var(--prepaid-font-color);
}

.footer-text {
    font-weight: 100;
    font-size: 12px;
}

.footer-text a {
    font-weight: 200;
    font-size: 12px;
    text-decoration: none;
    color: var(--accent-light-orange);
}

.footer-text a:hover {
    font-weight: 300;
    text-decoration: none;
    color: var(--accent-dark-orange);
}

.remove-from-cart{
    height: 30px;
    line-height: 16px;
    width: 32px;
    font-size: 32px;
    padding: 0px;
    border-radius: 50%;
    border: 0px solid #f5f5f5;
}

.checkout-label {
    font-size: 14px;
    font-weight: light;
    color: var(--heading-color);
    font-family: var(--heading-font) !important;
}

/* Why a paste into a re-type field did nothing. checkout.js writes the wording
   in and clears it again on the next keystroke, so the element is EMPTY for the
   whole of a normal checkout — it collapses rather than reserving a gap under
   every confirm field. Tokenised, so it reads in light and dark alike. */
.checkout-paste-hint {
    font-size: 12px;
    color: var(--font-color);
    opacity: 0.75;
}

.checkout-paste-hint:empty {
    display: none;
}


/* STYLE FOR SHOPPING CART */
.callout {
    border-left: 4px solid var(--prepaid-border-color);
    background-color: var(--prepaid-background-color);
    color: var(--prepaid-border-color);
    border-bottom-right-radius: 5px;
    border-top-right-radius: 5px;
}

.callout .checkout-label {
    color: var(--prepaid-border-color);
}

.callout i {
    color: var(--prepaid-border-color);
}

/* ============================================================
   EXPERIENCE CARDS — service selection on location page
   and featured services on home page
   ============================================================ */

.experience-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 200px;
    background: rgba(255, 255, 255, 0.08);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 12px;
    padding: 16px 12px 14px;
    color: var(--font-color);
    transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
    cursor: pointer;
}

.experience-card:hover {
    transform: translateY(-5px);
    background: rgba(255, 255, 255, 0.13);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
    color: var(--font-color);
}

.experience-card:active {
    transform: translateY(-6px) scale(1.02);
}

.experience-img {
    width: 100%;
    height: 130px;
    object-fit: cover;
    border-radius: 8px;
    display: block;
}

.experience-img-placeholder {
    width: 100%;
    height: 130px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.06);
    color: rgba(255, 255, 255, 0.35);
}

.experience-label {
    font-size: 0.88rem;
    font-weight: 600;
    font-family: var(--heading-font);
    color: var(--font-color);
    line-height: 1.35;
    word-break: break-word;
}

/* ============================================================
   LOCATIONS PAGE — search bar, map, distance badges
   ============================================================ */

.loc-search-input {
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.18);
    color: var(--font-color);
    border-radius: 8px;
    padding: 0.5rem 0.9rem;
    font-size: 0.95rem;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.loc-search-input::placeholder {
    color: rgba(255, 255, 255, 0.4);
}

.loc-search-input:focus {
    outline: none;
    border-color: var(--heading-color);
    box-shadow: 0 0 0 3px rgba(255, 69, 0, 0.15);
    background: rgba(255, 255, 255, 0.11);
    color: var(--font-color);
}

.loc-map {
    width: 100%;
    height: 420px;
    border-radius: 10px;
    overflow: hidden;
}

.loc-distance {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--heading-color);
    opacity: 0.9;
}

/* ============================================================
   HOME PAGE — banner, CTA cards, info card
   ============================================================ */

.home-banner-wrap {
    width: 100%;
    overflow: hidden;
    max-height: 320px;
}

.home-banner-img {
    width: 100%;
    height: auto;
    display: block;
    object-fit: cover;
    max-height: 320px;
}

.home-cta-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 2rem 1.5rem;
    background: rgba(255, 255, 255, 0.08);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 14px;
    color: var(--font-color);
    transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
}

.home-cta-card:hover {
    transform: translateY(-4px);
    background: rgba(255, 255, 255, 0.13);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
    color: var(--font-color);
}

.home-cta-card:active {
    transform: translateY(-5px) scale(1.01);
}

.home-cta-icon {
    font-size: 2.2rem;
    color: var(--heading-color);
    margin-bottom: 0.75rem;
    line-height: 1;
}

.home-cta-title {
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--font-color);
    margin-bottom: 0.4rem;
    line-height: 1.25;
}

.home-cta-sub {
    font-size: 0.85rem;
    color: var(--font-color);
    opacity: 0.65;
    line-height: 1.5;
}

.home-info-card {
    background: rgba(255, 255, 255, 0.07);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 10px;
    padding: 1.25rem 1.5rem;
}

/* ============================================================
   RESPONSIVE ADJUSTMENTS
   ============================================================ */

@media (max-width: 575.98px) {
    .experience-card {
        width: 155px;
        padding: 12px 10px 11px;
    }

    .experience-img,
    .experience-img-placeholder {
        height: 105px;
    }

    .home-cta-card {
        padding: 1.5rem 1.25rem;
    }

    .home-cta-icon {
        font-size: 1.8rem;
    }

    .loc-map {
        height: 300px;
    }
}

/* ============================================================
   BOOKING FLOW — restored from pre-b1 + new b1-style additions
   ============================================================ */

/* ---- Buttons ---- */

.btn-book {
    background-color: var(--accent-orange);
    color: #fff;
    border: none;
    border-radius: 8px;
    padding: 10px 24px;
    font-weight: 600;
    white-space: nowrap;
    transition: background-color 0.2s ease, transform 0.1s ease;
}

.btn-book:hover {
    background-color: var(--accent-green);
    color: #fff;
    transform: translateY(-1px);
}

.btn-book:active {
    transform: translateY(0);
}

.btn-outline-book {
    background: transparent;
    color: var(--accent-orange);
    border: 2px solid var(--accent-orange);
    border-radius: 8px;
    padding: 8px 22px;
    font-weight: 600;
    transition: background-color 0.2s ease, color 0.2s ease;
}

.btn-outline-book:hover {
    background-color: var(--accent-orange);
    color: #fff;
}

.btn-outline-themed {
    border: 2px solid var(--accent-orange);
    color: var(--accent-orange);
    background: transparent;
    border-radius: 8px;
    padding: 8px 20px;
    font-weight: 500;
    transition: all 0.2s ease;
}

.btn-outline-themed:hover {
    background-color: var(--accent-orange);
    color: #fff;
}

/* ---- Step Indicator ---- */

.booking-steps {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 16px 0;
    font-size: 14px;
    opacity: 0.8;
}

.booking-steps .step {
    display: flex;
    align-items: center;
    gap: 6px;
}

.booking-steps .step.active {
    font-weight: 600;
    opacity: 1;
    color: var(--accent-orange);
}

.booking-steps .step.completed {
    opacity: 0.6;
}

.booking-steps .step-divider {
    width: 20px;
    height: 1px;
    background-color: currentColor;
    opacity: 0.4;
}

/* ---- Calendar Grid ---- */

.cal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 0 14px;
}

.cal-nav {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    border: 1px solid rgba(128, 128, 128, 0.25);
    background: var(--bg-color);
    color: var(--font-color);
    cursor: pointer;
    transition: all 0.15s ease;
}

.cal-nav:hover {
    border-color: var(--accent-orange);
    color: var(--accent-orange);
    transform: translateY(-1px);
}

.cal-month {
    font-weight: 700;
    letter-spacing: 0.2px;
    color: var(--heading-color);
}

.cal-grid {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 8px;
}

.cal-dow span {
    text-align: center;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    color: var(--font-color);
    opacity: 0.55;
    padding-bottom: 2px;
}

.cal-day {
    min-height: 72px;
    border-radius: 12px;
    border: 1px solid rgba(128, 128, 128, 0.18);
    background: var(--bg-color);
    color: var(--font-color);
    padding: 8px;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}

.cal-day-num {
    font-size: 13px;
    font-weight: 700;
    line-height: 1;
}

.cal-day-meta {
    display: block;
    margin-top: 8px;
    font-size: 11px;
    font-weight: 600;
    color: var(--accent-green, #1f9d55);
}

.cal-day:hover:not(.disabled):not(.outside-month) {
    border-color: var(--accent-orange);
    transform: translateY(-1px);
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.08);
}

.cal-day.selected {
    border-color: var(--accent-orange);
    box-shadow: inset 0 0 0 2px var(--accent-orange);
}

.cal-day.today {
    background: rgba(255, 165, 0, 0.08);
}

.cal-day.outside-month {
    opacity: 0.45;
    cursor: default;
}

.cal-day.disabled {
    opacity: 0.35;
    cursor: default;
}

/* Availability — tint the whole cell, not just the dot (STB request). booking.js
   sets data-level high|medium|low; mirror the dot colours as soft cell fills. */
.cal-day[data-level="high"]:not(.disabled):not(.outside-month)   { background: rgba(44, 182, 167, 0.10); }
.cal-day[data-level="medium"]:not(.disabled):not(.outside-month) { background: rgba(245, 158, 11, 0.12); }
.cal-day[data-level="low"]:not(.disabled):not(.outside-month)    { background: rgba(220, 38, 38, 0.10); }

/* ---- Time Slot Buttons ---- */

.slot-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 8px;
    padding: 16px 0;
}

/* Hour-grouped picker mode — full-width rows */
.slot-grid.hour-mode {
    display: block;
    padding: 8px 0;
}

.slot-btn {
    padding: 12px;
    border: 1px solid rgba(128, 128, 128, 0.28);
    border-radius: 8px;
    background: var(--bg-color);
    color: var(--font-color);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s ease;
    text-align: center;
}

.slot-btn:hover:not(.sold-out) {
    border-color: var(--accent-orange);
    transform: translateY(-1px);
}

.slot-btn.selected {
    background-color: var(--accent-orange);
    color: #fff;
    font-weight: 600;
    border-color: var(--accent-orange);
}

.slot-btn.sold-out {
    opacity: 0.35;
    cursor: not-allowed;
    border-style: dashed;
    text-decoration: line-through;
}

.slot-remaining {
    font-size: 11px;
    opacity: 0.7;
    display: block;
    margin-top: 2px;
}

/* ---- Hold Timer Badge ---- */

.hold-timer {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 20px;
    background-color: rgba(255, 165, 0, 0.1);
    color: var(--accent-orange);
    font-size: 13px;
    font-weight: 600;
}

.hold-timer.expiring {
    background-color: rgba(220, 53, 69, 0.1);
    color: #dc3545;
}

/* Brief green pulse when the checkout page spends one of the customer's own
   extensions for them on their first keystroke. Purely an acknowledgement that
   the number just jumped on its own — without it the timer appears to correct
   itself, which reads as a glitch. .expiring is a separate state and keeps
   winning while it applies, because a low clock is the more urgent message. */
.hold-timer.time-added:not(.expiring) {
    background-color: rgba(25, 135, 84, 0.12);
    color: #198754;
    transition: background-color .3s ease, color .3s ease;
}

@media (prefers-reduced-motion: reduce) {
    .hold-timer.time-added:not(.expiring) { transition: none; }
}

/* ---- Hold Extend Slide-In Banner (from right side) ---- */
.hold-extend-slide {
    position: fixed;
    top: 50%;
    right: -360px;
    transform: translateY(-50%);
    width: 320px;
    padding: 20px 22px;
    background: var(--bg-color, #fff);
    border-radius: 16px 0 0 16px;
    box-shadow: -4px 0 24px rgba(0,0,0,0.15);
    z-index: 4500;
    transition: right 0.4s cubic-bezier(0.22, 1, 0.36, 1);
    font-size: 0.9rem;
    color: var(--font-color, #333);
}
.hold-extend-slide.active {
    right: 0;
}
.hold-extend-slide__icon {
    font-size: 1.6rem;
    color: var(--accent-orange, #ee513a);
    margin-bottom: 8px;
}
.hold-extend-slide__title {
    font-family: var(--heading-font);
    font-weight: 600;
    font-size: 1rem;
    margin-bottom: 4px;
}
.hold-extend-slide__text {
    font-size: 0.82rem;
    opacity: 0.7;
    margin-bottom: 12px;
    line-height: 1.4;
}
.hold-extend-slide__dismiss {
    position: absolute;
    top: 10px;
    right: 14px;
    background: none;
    border: none;
    font-size: 1.1rem;
    opacity: 0.4;
    cursor: pointer;
    color: var(--font-color, #333);
}
.hold-extend-slide__dismiss:hover { opacity: 0.8; }

/* ---- Hold Expired Modal (non-dismissable) ---- */
.hold-expired-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(6px);
    z-index: 6000;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
}
.hold-expired-backdrop.active {
    opacity: 1;
    pointer-events: auto;
}
.hold-expired-modal {
    position: fixed;
    top: -100%;
    left: 50%;
    transform: translateX(-50%);
    width: 90%;
    max-width: 420px;
    background: var(--bg-color, #fff);
    border-radius: 20px;
    padding: 36px 28px 28px;
    text-align: center;
    z-index: 6001;
    transition: top 0.4s cubic-bezier(0.22, 1, 0.36, 1);
    box-shadow: 0 12px 40px rgba(0,0,0,0.25);
}
.hold-expired-modal.active {
    top: 50%;
    transform: translate(-50%, -50%);
}
.hold-expired-modal__icon {
    font-size: clamp(2.6rem, 2.35rem + 1.05vw, 3.25rem);
    color: var(--accent-orange, #ee513a);
    margin-bottom: 14px;
}
.hold-expired-modal__title {
    font-family: var(--heading-font);
    font-weight: 600;
    font-size: clamp(1.2rem, 1.13rem + 0.3vw, 1.38rem);
    margin-bottom: 8px;
    color: var(--heading-color, #060550);
}
.hold-expired-modal__text {
    font-size: 0.9rem;
    opacity: 0.7;
    line-height: 1.5;
    margin-bottom: 22px;
}
.hold-expired-modal__btn {
    display: inline-block;
    padding: 12px 32px;
    border-radius: 20px;
    background-color: var(--accent-orange, #ee513a);
    color: #fff;
    font-weight: 700;
    font-size: 0.95rem;
    border: none;
    cursor: pointer;
    text-decoration: none;
    transition: background 0.2s ease;
}
.hold-expired-modal__btn:hover {
    background-color: var(--bg-light-color, #faf9f6);
    color: var(--accent-orange, #ee513a);
}

/* ---- Mini-Cart / Price Summary Bar ---- */

.price-summary {
    position: sticky;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: var(--bg-color);
    border-top: 1px solid var(--cart-grey, rgba(108, 117, 125, 0.3));
    padding: 12px 20px;
    z-index: 100;
    box-shadow: 0 -4px 16px var(--soft-shadow, rgba(0, 0, 0, 0.1));
}

.mode-dark .price-summary {
    background-color: var(--bg-dark-color);
    border-color: rgba(255, 255, 255, 0.1);
}

.price-summary .total-label {
    font-size: 14px;
    opacity: 0.8;
}

.price-summary .total-amount {
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--accent-orange);
}

/* ---- Package List (b1 alternating row style) ---- */

.package-list {
    margin-bottom: 2rem;
}

.package-list .border-bottom {
    border-color: rgba(128, 128, 128, 0.18) !important;
}

/* The BASIC layout's package card on the dedicated /book/package/{id} page.
 *
 * ⚠ THE ROW IS THIS PAGE'S ONLY CARD. The page shell is deliberately
 *   transparent (book/package.blade.php passes shell_card => false) because the
 *   premium layout gives every package a `.premium-pkg-card` and a shell card
 *   around those is a card inside a card. The basic row had no surface of its
 *   own, so it was left standing on the bare page ground while the very same
 *   packages on the calendar kept their `.pkg-card`. These rules are that
 *   missing surface, matching the calendar card token for token:
 *   --bg-light-secondary is the raised-surface colour all 24 microsite themes
 *   set, so this reads as a card on every theme without a hardcoded colour.
 */
.package-list .package-row-card {
    background-color: var(--bg-light-secondary);
    border: 1px solid var(--border-muted);
    border-radius: 14px;
    padding: 24px 20px;
    margin: 1.5rem 0rem;
    overflow: hidden;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
    transition: border-color 0.2s, box-shadow 0.2s;
}

@media (hover: hover) and (pointer: fine) {
    .package-list .package-row-card:hover {
        border-color: rgba(238, 81, 58, 0.4);
        box-shadow: 0 4px 20px rgba(238, 81, 58, 0.12);
    }
}

/* Selected + sold-out states. The markup has emitted these two classes since
 * the page shipped and nothing has ever styled them — with no card there was
 * no surface to state anything on. */
.package-list .package-row-card.package-selected-row {
    border-color: var(--accent-orange);
    box-shadow: 0 4px 24px rgba(238, 81, 58, 0.2);
}

.package-list .package-row-card.package-sold-out {
    opacity: 0.6;
}

/* Desktop slide-in animation */
@media (min-width: 740px) {
    .package-animate {
        opacity: 0;
        transform: translateX(var(--pkg-offset, 0));
        transition:
            opacity 0.9s cubic-bezier(0.19, 1, 0.22, 1),
            transform 1s cubic-bezier(0.19, 1, 0.22, 1);
        will-change: transform, opacity;
    }

    .package-animate.from-left  { --pkg-offset: -40px; }
    .package-animate.from-right { --pkg-offset:  40px; }

    .package-animate.in-view {
        opacity: 1;
        transform: translateX(0);
    }
}

@media (prefers-reduced-motion: reduce) {
    .package-animate {
        transition: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
}

.package-list img {
    transition: transform 200ms ease-out, box-shadow 200ms ease-out;
}

@media (hover: hover) and (pointer: fine) {
    .package-list img:hover {
        transform: translateY(-3px);
        box-shadow: 0 10px 22px rgba(0, 0, 0, 0.2);
    }
}

/* ---- Addon Rows (generic add-ons section) ---- */

.addon-row {
    padding: 12px 14px;
    border-radius: 10px;
    margin-bottom: 6px;
    border: 1px solid rgba(128, 128, 128, 0.15);
    transition: background-color 0.15s ease, border-color 0.15s ease;
    cursor: pointer;
}

.addon-row:hover {
    background-color: rgba(255, 165, 0, 0.05);
    border-color: rgba(255, 165, 0, 0.3);
}

.addon-row input[type="checkbox"]:checked ~ * {
    color: var(--accent-orange);
}

.addon-price {
    font-weight: 600;
    white-space: nowrap;
    font-size: 0.9rem;
    color: var(--accent-orange);
}

/* ---- Suggested Addons Modal Items ---- */

.addon-modal-item {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px 16px;
    border-radius: 10px;
    border: 1px solid rgba(128, 128, 128, 0.18);
    margin-bottom: 10px;
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

.addon-modal-item:hover {
    background-color: rgba(255, 165, 0, 0.04);
    border-color: rgba(255, 165, 0, 0.3);
}

.addon-modal-item.checked {
    border-color: var(--accent-orange);
    background-color: rgba(255, 165, 0, 0.06);
}

.addon-modal-item input[type="checkbox"] {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    margin-top: 2px;
    accent-color: var(--accent-orange);
    cursor: pointer;
}

.addon-modal-item .addon-modal-name {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--heading-color);
}

.addon-modal-item .addon-modal-desc {
    font-size: 0.82rem;
    color: var(--font-color);
    opacity: 0.7;
    margin-top: 2px;
}

.addon-modal-item .addon-modal-price {
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--accent-orange);
    white-space: nowrap;
    margin-left: auto;
    flex-shrink: 0;
    padding-left: 12px;
    align-self: center;
}

/* Modal theming */
#suggestedAddonsModal .modal-content {
    background: var(--bg-color);
    color: var(--font-color);
    border: 1px solid rgba(128, 128, 128, 0.2);
}

#suggestedAddonsModal .modal-header {
    border-bottom: 1px solid rgba(128, 128, 128, 0.15);
}

#suggestedAddonsModal .modal-footer {
    border-top: 1px solid rgba(128, 128, 128, 0.15);
}

/* ---- Utility ---- */

.thidden { display: none; }

.confirm-check {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background-color: var(--accent-green, #22c55e);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 28px;
    margin: 0 auto 16px;
}

.cal-add-links {
    display: flex;
    gap: 12px;
    justify-content: center;
    flex-wrap: wrap;
    margin-top: 16px;
}

.cal-add-links a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 16px;
    border: 1px solid var(--cart-grey, rgba(108, 117, 125, 0.3));
    border-radius: 8px;
    text-decoration: none;
    color: var(--font-color);
    font-size: 14px;
    transition: border-color 0.2s ease;
}

.cal-add-links a:hover {
    border-color: var(--accent-orange);
    color: var(--accent-orange);
}

/* ---- Responsive ---- */

@media (max-width: 768px) {
    .slot-grid {
        grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
    }

    .price-summary {
        padding: 10px 14px;
    }

    .price-summary .total-amount {
        font-size: 1.1rem;
    }
}

@media (max-width: 576px) {
    .booking-steps {
        font-size: 12px;
        gap: 4px;
    }

    .booking-steps .step-divider {
        width: 12px;
    }

    .cal-day {
        min-height: 56px;
        padding: 6px;
        font-size: 13px;
    }
}


/* ==========================================================================
   Checkout — shared styles for checkout_view.php.
   All colors use CSS custom properties so light/dark themes apply correctly.
   ========================================================================== */

/* Root additions — not in theme files */
:root {
    --border-muted:  rgba(128, 128, 128, 0.12);  /* neutral divider/border */
    --stripe-purple: #635bff;                     /* Stripe brand — never changes */
}

/* ---- Hold bar ---- */
.hold-bar {
    position: sticky;
    top: 0;
    z-index: 500;
    background: var(--heading-color);
    color: #fff;
    padding: 10px 20px;
    font-size: 0.88rem;
    transition: background 0.4s ease;
}
.hold-bar.expiring                    { background: var(--accent-orange) !important; }

.hold-bar__status-text  { font-size: 0.82rem; opacity: 0.75; }
.hold-bar__link         { color: var(--accent-orange); font-size: 0.82rem; text-decoration: none; }
.hold-bar__urgent-text  { font-size: 0.85rem; font-weight: 700; }
.hold-bar__urgent-link  { color: rgba(255,255,255,0.75); font-size: 0.78rem; text-decoration: none; }

/* ---- Checkout labels — Poppins light ---- */
.checkout-label {
    font-size: 13px;
    font-weight: 300;
    color: var(--heading-color);
    font-family: var(--heading-font);
    margin-bottom: 4px;
}

/* ---- Step card headings ---- */
.checkout-step-heading {
    font-family: var(--heading-font);
    font-size: clamp(1rem, .9rem + .4vw, 1.2rem);
    font-weight: 600;
    color: var(--heading-color);
    margin-bottom: 4px;
}
.checkout-step-subtext {
    font-size: 0.78rem;
    color: var(--font-color);
    opacity: 0.45;
    margin-bottom: 20px;
}
.checkout-step-subtext--donation {
    font-size: 0.82rem;
    opacity: 0.7;
    line-height: 1.6;
    margin-bottom: 20px;
}

/* ---- Back / edit button ---- */
.checkout-back-btn {
    background: none;
    border: none;
    padding: 0;
    font-size: 0.78rem;
    color: var(--font-color);
    opacity: 0.45;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 4px;
}
.checkout-back-btn:hover { opacity: 0.75; }

/* ---- Input group icons ---- */
.input-icon-left {
    background: transparent;
    border-right: 0;
    color: var(--heading-color);
    opacity: 0.5;
}
.input-icon-right {
    background: transparent;
    border-left: 0;
    padding-right: 12px;
}
.input-no-left-border  { border-left: 0; }
.input-mono            { font-family: monospace; font-size: 0.9rem; }
.stripe-icon           { font-size: 1.2rem; color: var(--stripe-purple); }

/* ---- Light mode form overrides ---- */
.form-control {
    color: #212529;
    background-color: #fff;
}
.form-control::placeholder { color: #6c757d; }
.form-control:focus {
    color: #212529;
    background-color: #fff;
}

/* ---- Dark mode form overrides ---- */
.mode-dark .form-control {
    background-color: var(--bg-dark-secondary);
    border-color: rgba(255,255,255,0.15);
    color: var(--font-dark-color);
}
.mode-dark .form-control::placeholder { color: rgba(255,255,255,0.3); }
.mode-dark .form-control:focus {
    background-color: var(--bg-dark-secondary);
    border-color: var(--accent-orange);
    box-shadow: 0 0 0 0.2rem rgba(238,81,58,0.2);
    color: var(--font-dark-color);
}
.mode-dark .input-group-text {
    background-color: var(--bg-dark-secondary);
    border-color: rgba(255,255,255,0.15);
    color: rgba(255,255,255,0.45);
}
.mode-dark .form-check-input {
    background-color: rgba(255,255,255,0.08);
    border-color: rgba(255,255,255,0.2);
}
.mode-dark .form-check-input:checked {
    background-color: var(--accent-orange);
    border-color: var(--accent-orange);
}
.mode-dark .modal-content {
    background-color: var(--bg-dark-secondary);
    border-color: rgba(255,255,255,0.1);
}

/* ---- Error messages ---- */
.checkout-error { font-size: 0.78rem; color: #dc3545; }

/* ---- Terms ---- */
.checkout-terms-label { font-size: 0.78rem; color: var(--font-color); opacity: 0.6; }
.checkout-terms-link  { color: var(--accent-orange); }

/* ---- Callout card — teal left border ---- */
.callout-teal {
    border-left: 4px solid var(--prepaid-border-color);
    background-color: var(--prepaid-background-color);
    color: var(--prepaid-font-color);
    border-bottom-right-radius: 8px;
    border-top-right-radius: 8px;
    padding: 12px 14px;
    font-size: 0.8rem;
}
.callout-teal i { color: var(--prepaid-border-color); }

/* ---- Reassurance line below submit ---- */
.checkout-reassurance {
    font-size: 0.75rem;
    color: var(--font-color);
    opacity: 0.45;
    text-align: center;
}

/* ---- Order summary card ---- */
.summary-card {
    position: sticky;
    top: 80px;
    height: auto !important;
}
.summary-location-block { border-bottom: 1px solid var(--border-muted); }
.summary-icon-accent    { color: var(--accent-orange); flex-shrink: 0; font-size: 0.78rem; }
.summary-location-name  { font-size: 0.85rem; font-weight: 700; color: var(--heading-color); line-height: 1.2; }
.summary-location-city  { font-size: 0.74rem; color: var(--font-color); opacity: 0.5; }
.summary-slot-date      { font-size: 0.83rem; font-weight: 600; color: var(--font-color); line-height: 1.3; }
.summary-slot-time      { font-size: 0.83rem; color: var(--font-color); opacity: 0.75; }
.summary-arrive-early   { font-size: 0.7rem; color: var(--accent-orange); font-weight: 600; margin-top: 3px; letter-spacing: 0.02em; }

/* ---- Summary section label (muted uppercase) ---- */
.summary-section-label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--font-color);
    opacity: 0.38;
    margin-bottom: 8px;
}

/* ---- Summary line items ---- */
.summary-line {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 6px;
}
.summary-line .lbl            { font-size: 0.83rem; color: var(--font-color); flex: 1; }
.summary-line .lbl.muted      { opacity: 0.55; }
.summary-line .amt            { font-size: 0.83rem; font-weight: 600; color: var(--font-color); white-space: nowrap; padding-left: 10px; }
.summary-line.total .lbl      { font-size: 0.95rem; font-weight: 700; color: var(--heading-color); }
.summary-line.total .amt      { font-size: clamp(1.25rem, 1.18rem + 0.3vw, 1.44rem); font-weight: 800; color: var(--accent-orange); font-family: var(--heading-font); }
.summary-line.donation .lbl,
.summary-line.donation .amt   { color: var(--prepaid-font-color); }

.summary-package-name     { font-weight: 600; }
.summary-package-service  { font-size: 0.74rem; opacity: 0.5; }
.summary-addon-icon       { font-size: 0.6rem; color: var(--accent-orange); }
.summary-addon-amt        { opacity: 0.75; }
/* "× 3" beside an itemised add-on. Drawn only where a count exists. */
.summary-addon-qty        { font-weight: 700; color: var(--accent-orange); white-space: nowrap; }
.summary-line-subtotal    { opacity: 0.55; font-size: 0.8rem; }
.summary-line-fee-amt     { opacity: 0.75; font-weight: 400; }
.summary-donation-gst-free { font-size: 0.7rem; opacity: 0.6; }
.summary-gst-note         { text-align: right; font-size: 0.72rem; opacity: 0.4; margin-top: 4px; }
.summary-security         { border-top: 1px solid var(--border-muted); }
.summary-security-badges  { font-size: 0.7rem; color: var(--font-color); opacity: 0.35; }

/* ---- Centered narrow divider ---- */
.summary-divider {
    border: none;
    border-top: 1.5px solid var(--border-muted);
    margin: 12px auto;
    width: 50%;
}

/* ---- Multi-booking order summary ----------------------------------------
   A two-session order used to render as one flat ledger. Every break was the
   same centred half-width rule, so the line separating two BOOKINGS looked
   exactly like the line separating one booking's items from its own total —
   the eye had nothing to group on. All three totals were set in the same big
   accent display face too, so nothing said which figure was the sum.

   Grouping now comes from ENCLOSURE — one numbered panel per booking — rather
   than from rules; a booking's own total is quiet; and the order total is the
   only display figure and the only full-width rule left on the panel. */
.summary-booking {
    border: 1px solid var(--border-muted);
    border-radius: 12px;
    background: rgba(128, 128, 128, 0.05);
    padding: 0 14px 14px;
    margin-bottom: 14px;
}
.summary-booking__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    margin: 0 -14px 12px;
    padding: 9px 14px;
    border-bottom: 1px solid var(--border-muted);
}
.summary-booking__num {
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--accent-orange);
    color: #fff;
    font-size: 0.68rem;
    font-weight: 700;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.summary-booking__title {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--heading-color);
    opacity: 0.6;
}
.summary-booking__tag {
    flex: 0 0 auto;
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--accent-orange);
    border: 1px solid var(--accent-orange);
    border-radius: 999px;
    padding: 2px 8px;
    line-height: 1.35;
    white-space: nowrap;
}
.summary-booking__remove {
    flex: 0 0 auto;
    background: none;
    border: 0;
    padding: 0;
    line-height: 1;
    font-size: 0.72rem;
    color: var(--font-color);
    opacity: 0.55;
    white-space: nowrap;
    cursor: pointer;
}
.summary-booking__remove:hover,
.summary-booking__remove:focus-visible {
    opacity: 1;
    color: #dc3545;
    text-decoration: underline;
}

/* The booking the form beside this panel is still configuring. */
.summary-booking--current { border-color: var(--accent-orange); }

/* Inside a panel the rule is a full-width hairline, never the centred
   half-width one — a floating 50% rule inside a card reads as decoration and
   competes with the panel edge for "this is where one booking ends". */
.summary-booking .summary-divider {
    width: 100%;
    margin: 10px 0;
    border-top-width: 1px;
}

/* A booking's OWN total, kept quiet so the order total is the only display
   figure on the panel. Beats `.summary-line.total .amt` on class count —
   deliberately, and that is why the modifier is written doubled up. */
.summary-line.total.summary-booking__total       { margin-top: 4px; }
.summary-line.total.summary-booking__total .lbl  { font-size: 0.85rem; opacity: 0.8; }
.summary-line.total.summary-booking__total .amt  {
    font-size: 0.98rem;
    font-weight: 700;
    color: var(--heading-color);
    font-family: inherit;
}

/* The sum. The only full-width rule left on the summary panel. */
.summary-order-total {
    border-top: 2px solid var(--border-muted);
    margin-top: 2px;
    padding-top: 12px;
}

/* ---- Donation step ---- */
.donation-amounts-wrapper  { flex: 1; }
.donation-roundup-subtext  { font-size: 0.7rem; font-weight: 400; opacity: 0.75; }

.donation-different-btn {
    background: none;
    border: none;
    padding: 0;
    font-size: 0.72rem;
    color: var(--prepaid-font-color);
    cursor: pointer;
    text-decoration: underline;
    opacity: 0.7;
}
.donation-loading-text {
    font-size: 0.78rem;
    margin: 0;
    color: var(--font-color);
    opacity: 0.5;
}
.donation-change-btn {
    background: none;
    border: none;
    padding: 0;
    font-size: 0.78rem;
    color: var(--font-color);
    opacity: 0.45;
    cursor: pointer;
    text-decoration: underline;
}
.donation-charity-link          { font-size: 0.7rem; opacity: 0.35; }
.donation-charity-link a        { color: var(--font-color); text-decoration: none; }
.donation-charity-link a:hover  { text-decoration: underline; }

/* ---- Donation amount buttons ---- */
.donate-btn {
    width: 100%;
    height: 52px;
    border-radius: 10px;
    border: 2px solid var(--prepaid-border-color);
    background: transparent;
    color: var(--prepaid-font-color);
    font-size: 1rem;
    font-weight: 700;
    cursor: pointer;
    transition: all 0.15s ease;
    font-family: var(--heading-font);
}
.donate-btn:hover,
.donate-btn.selected {
    background: var(--prepaid-font-color);
    color: #fff;
}

.roundup-btn {
    width: 100%;
    padding: 13px 12px;
    border-radius: 10px;
    border: 2px solid var(--prepaid-border-color);
    background: transparent;
    color: var(--prepaid-font-color);
    font-size: 0.82rem;
    font-weight: 700;
    cursor: pointer;
    transition: all 0.15s ease;
    text-align: center;
    line-height: 1.2;
}
.roundup-btn:hover,
.roundup-btn.selected {
    background: var(--prepaid-font-color);
    color: #fff;
}

.nothanks-btn {
    width: 100%;
    padding: 13px 12px;
    border-radius: 10px;
    border: 2px solid var(--border-muted);
    background: transparent;
    color: var(--font-color);
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s ease;
    opacity: 0.6;
    text-align: center;
}
.nothanks-btn:hover { opacity: 1; border-color: rgba(128,128,128,0.4); }

/* ---- Butterfly logo badge ---- */
.butterfly-badge {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    background: linear-gradient(135deg, #773DBD 0%, #2CB6A7 100%); /* Butterfly Foundation brand */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 0.56rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    line-height: 1.3;
    gap: 4px;
    flex-shrink: 0;
}

/* ---- Donation thank-you flash ---- */
.donation-thankyou {
    background: var(--accent-orange);
    color: #fff;
    border-radius: 10px;
    padding: 14px 16px;
    text-align: center;
    font-size: 0.88rem;
    font-weight: 700;
}

/* ---- Donation modal ---- */
.donation-modal-content  { border-radius: 18px; border: none; }
.donation-modal-heading  { font-family: var(--heading-font); font-size: 1rem; font-weight: 600; color: var(--heading-color); }
.donation-modal-icon     { color: var(--prepaid-font-color); }
.donation-modal-text     { font-size: 0.8rem; color: var(--font-color); opacity: 0.55; margin-bottom: 18px; }
.donation-modal-currency {
    background: var(--prepaid-background-color);
    border-color: var(--prepaid-border-color);
    color: var(--prepaid-font-color);
    font-weight: 700;
}
.donation-modal-input {
    border-color: var(--prepaid-border-color);
    font-size: 1.1rem;
    font-weight: 600;
    text-align: center;
}
.donation-confirm-btn {
    background: var(--prepaid-font-color);
    color: #fff;
    border: none;
    border-radius: 10px;
    font-weight: 700;
    font-size: 0.95rem;
}

/* ---- Floating checkout progress bar ---- */
.checkout-progress-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 999;
    background: var(--prepaid-background-color);
    border-radius: 25px 25px 0 0;
    box-shadow: 0 -6px 32px rgba(44,182,167,0.35), 0 -2px 8px rgba(44,182,167,0.2);
    padding: 12px 16px;
}
/* Showcase (Enhanced): the bar starts off-screen and slides up as the secondary
   nav reaches the top (toggled by the sentinel observer). */
.sc-progress-reveal           { transform: translateY(130%); transition: transform 0.32s ease; }
.sc-progress-reveal.is-visible { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) { .sc-progress-reveal { transition: none; } }
/* ============================================================================
   THE HOLD COUNTDOWN, IN THE BOTTOM BAR — the PHONE's copy of book/_slot-bar's pill.

   ⚠⚠ IT IS THE SECOND OF TWO COPIES AND EXACTLY ONE IS EVER ON SCREEN. This one is
      display:none at ≥576px and the top bar's pill is display:none below it, so the
      countdown does not appear twice at any width — and because both are hidden with
      `display`, the one that is off stays out of the accessibility tree, leaving a
      screen reader one role="timer" to find. Break that symmetry and the customer is
      told the same thing twice by two elements that a rotation can put out of step.

   ⚠⚠ WHY IT IS DOWN HERE AT ALL: on a phone the top bar cannot hold the pill, the
      studio's mark and a control on one line and still centre the mark. Measured at
      375px, centring needs 106px + 115px + 20px + 106px = 347px of bar and there are
      327px. The pill is the widest of the three and the least attached to a place, so
      it moves — to the bar the customer is already watching their progress on, and
      bigger than it was, because down here there is room for it to be read.

   ⚠ SIZED HERE, NOT BY A MODIFIER ON THE PILL. .secondary-svc-pill is shared with the
     top bar, so a size change on the class itself would grow the desktop copy too.

   ⚠⚠ AND IT PAINTS ITS OWN OPAQUE GROUND, WHICH IS A CORRECTNESS FIX RATHER THAN A
      LOOK. The pill's usual surface is a 10% wash of #ee513a, and the comment beside
      .bk-slot-bar-held pins its two reds to contrast figures measured over --bg-color
      — the top bar's ground, which is the same on every theme because that is what the
      wash sits on there. THIS bar's ground is --prepaid-background-color, which the 24
      microsite themes set to anything from #fafafa through #060e18 to pure red, so a
      translucent wash here means the digits sit on an unknown colour. Measured on the
      darkest theme the pinned #b91c1c reads 2.99:1 and on the red one 1.62:1 — both
      well under AA, on the one element a customer reads in a hurry.

      An opaque chip makes the ground known again and the arithmetic true again:
      #b91c1c on #fff5f4 reads 6.05:1, and the whole pill takes that same red so the
      "Slot Held" label is not left on the accent (3.34:1 at this size). The dark-mode
      red is overridden back for the same reason — #f87171 on this chip is 2.59:1.
      Change the chip colour and re-measure both, or do not change it.
   ============================================================================ */
.bk-stepbar-hold {
    display: flex;
    justify-content: center;
    margin-bottom: 8px;
}
@media (min-width: 576px) {
    .bk-stepbar-hold { display: none; }
}
.bk-stepbar-hold .secondary-svc-pill {
    font-size: 0.68rem;
    padding: 4px 12px;
    background: #fff5f4;
    border: 1px solid rgba(185,28,28,0.18);
    color: #b91c1c;
}
.bk-stepbar-hold .bk-slot-bar-held    { font-size: 0.95rem; }
.bk-stepbar-hold .bk-slot-bar-held i  { font-size: 0.84rem; }
.mode-dark .bk-stepbar-hold .secondary-svc-pill,
.mode-dark .bk-stepbar-hold .bk-slot-bar-held { color: #b91c1c; }

.checkout-progress-bar__inner {
    display: flex;
    align-items: center;
    justify-content: center;
    max-width: 460px;
    margin: 0 auto;
}
.checkout-progress-step {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    opacity: 0.6;
}
.checkout-progress-step--active { opacity: 1; }

.checkout-progress-step__dot {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--prepaid-font-color);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.6rem;
    color: var(--prepaid-background-color);
    font-weight: 700;
}
.checkout-progress-step__dot--active {
    width: 28px;
    height: 28px;
    font-size: 0.72rem;
    font-weight: 800;
    box-shadow: 0 0 0 3px rgba(44,182,167,0.3);
    animation: pulseGreen 1.9s infinite;
}
.checkout-progress-step__label {
    font-size: 0.64rem;
    color: var(--prepaid-font-color);
    white-space: nowrap;
}
.checkout-progress-step__label--active {
    font-size: 0.68rem;
    font-weight: 700;
}
.checkout-progress-connector {
    flex: 1;
    max-width: 60px;
    height: 1.5px;
    background: var(--prepaid-border-color);
    opacity: 0.4;
    margin: 0 8px;
    margin-bottom: 16px;
}
/* ===== Booking page — shared visual primitives ===== */

/* Back link on book page.
   ⚠ This was a hardcoded `color:#fff` — written when the booking card sat on a dark
   surface. Every caller now renders it inside book._shell-open's light .location-card,
   so on a light-themed booking site it was white-on-cream: present, focusable, and
   invisible. It reads the ink token like every other control on the card. */
.back-link       { font-size: 0.82rem; color: var(--font-color); opacity: 0.65; text-decoration: none; }
.back-link:hover { color: var(--accent-orange); opacity: 1; }

/* Service header in booking card */
.svc-header    { border-bottom: 1px solid var(--border-muted); }
.svc-icon-wrap { width: 40px; height: 40px; border-radius: 10px; background: var(--accent-orange); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.svc-icon      { color: #fff; font-size: 0.9rem; }
.svc-name      { font-size: 0.95rem; font-family: var(--heading-font); font-weight: 700; color: var(--heading-color); }
.svc-meta      { font-size: 0.75rem; color: var(--font-color); opacity: 0.5; }
.svc-meta-icon { color: var(--accent-orange); }

/* Month navigation */
.month-nav { background: none; border: 1.5px solid var(--border-muted); border-radius: 8px; padding: 6px 12px; cursor: pointer; font-size: 0.82rem; color: var(--font-color); opacity: 0.5; }
.month-nav[disabled] { opacity: 0.25; cursor: not-allowed !important; }
.month-nav:hover:not([disabled]) { border-color: var(--accent-orange) !important; opacity: 1 !important; color: var(--accent-orange) !important; }
.month-heading  { font-size: 0.95rem; font-weight: 700; color: var(--heading-color); font-family: var(--heading-font); }
.month-subtext  { font-size: 0.72rem; color: var(--font-color); opacity: 0.45; margin-top: 2px; }

/* Calendar picker (compact inline booking calendar) */
.cal-picker-wrap { max-width: 100%; }
.cal-dow-row  { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; margin-bottom: 6px; }
.cal-dow-row .cal-dow { text-align: center; font-size: 0.68rem; font-weight: 700; color: var(--font-color); opacity: 0.35; padding: 2px 0; }
.cal-picker-wrap .cal-grid { gap: 4px; }
.cal-legend { font-size: 0.72rem; color: var(--font-color); opacity: 0.5; }
.legend-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }

/* Calendar picker cells (compact inline booking calendar) */
.cal-pick-day { position: relative; height: 40px; display: flex; align-items: center; justify-content: center; font-size: 0.85rem; border-radius: 8px; color: var(--font-color); opacity: 0.28; }
.cal-pick-day.available { opacity: 1; cursor: pointer; font-weight: 600; color: var(--heading-color); background: rgba(44,182,167,0.15); border: 1px solid rgba(44,182,167,0.4); transition: background 0.15s, border-color 0.15s; }
.cal-pick-day.available:hover { background: rgba(44,182,167,0.28); border-color: rgba(44,182,167,0.6); }
/* Availability tints reflect the legend key: green = plenty, amber = filling up, red = almost full */
.cal-pick-day.available[data-level="high"]         { background: rgba(44,182,167,0.15); border-color: rgba(44,182,167,0.4); }
.cal-pick-day.available[data-level="high"]:hover   { background: rgba(44,182,167,0.28); border-color: rgba(44,182,167,0.6); }
.cal-pick-day.available[data-level="medium"]       { background: rgba(245,158,11,0.18); border-color: rgba(245,158,11,0.5); }
.cal-pick-day.available[data-level="medium"]:hover { background: rgba(245,158,11,0.3);  border-color: rgba(245,158,11,0.7); }
.cal-pick-day.available[data-level="low"]          { background: rgba(220,38,38,0.13);  border-color: rgba(220,38,38,0.4); }
.cal-pick-day.available[data-level="low"]:hover    { background: rgba(220,38,38,0.24);  border-color: rgba(220,38,38,0.6); }
.cal-pick-day.available.selected,
.cal-pick-day.available.selected[data-level]       { background: var(--accent-orange); border-color: var(--accent-orange); color: #fff; }
.cal-pick-day.past { opacity: 0.18; cursor: not-allowed; }
.avail-dot { position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%); width: 5px; height: 5px; border-radius: 50%; display: block; }
.cal-pick-day.available.selected .avail-dot { display: none; }

/* Scheduled-discount nudge badge (top-left; ! urgency mark is top-right, dot is bottom) */
.cal-discount-badge { position: absolute; top: 2px; left: 3px; font-size: 0.46rem; font-weight: 800; line-height: 1; color: #047857; background: #d1fae5; border: 1px solid #6ee7b7; border-radius: 5px; padding: 1px 2px; white-space: nowrap; pointer-events: none; letter-spacing: -0.02em; }
.cal-pick-day.available.has-discount { box-shadow: inset 0 0 0 1px rgba(4,120,87,0.35); }

/* Hour picker — block containers */
.hour-block { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: 10px; border: 1.5px solid var(--border-muted); margin-bottom: 6px; cursor: pointer; transition: border-color 0.15s, background 0.15s; background: var(--bg-color); }
.hour-block:hover:not(.full) { border-color: var(--accent-orange); background: rgba(238,81,58,0.04); }
.hour-block.expanded { border-color: var(--accent-orange); background: rgba(238,81,58,0.04); border-radius: 10px 10px 0 0; margin-bottom: 0; }
.hour-block.full { cursor: not-allowed; opacity: 0.45; }

/* Slot time chips */
.slot-chip { padding: 6px 14px; border-radius: 20px; border: 1.5px solid var(--border-muted); background: var(--bg-color); font-size: 0.82rem; font-weight: 600; color: var(--heading-color); cursor: pointer; transition: border-color 0.15s, background 0.15s; }
.slot-chip:hover  { border-color: var(--accent-orange); background: rgba(238,81,58,0.06); }
.slot-chip.selected { background: var(--accent-orange); border-color: var(--accent-orange); color: #fff; }

/* Hour picker */
.hour-dot        { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; display: inline-block; }
.hour-label      { font-size: 0.9rem; font-weight: 700; color: var(--heading-color); min-width: 76px; }
.hour-bar-bg     { flex: 1; height: 5px; border-radius: 3px; background: rgba(128,128,128,0.1); }
.hour-bar-fill   { height: 100%; border-radius: 3px; }
.hour-chevron    { font-size: 0.68rem; color: var(--font-color); opacity: 0.28; transition: transform 0.2s; }
.hour-avail-full { font-size: 0.73rem; color: rgba(128,128,128,0.5); }
.hour-avail-low  { font-size: 0.73rem; font-weight: 700; color: #dc2626; }
.hour-avail-norm { font-size: 0.73rem; color: var(--font-color); opacity: 0.45; }
.hour-slots      { padding: 8px 14px 14px; margin-top: -6px; margin-bottom: 6px; border: 1.5px solid var(--accent-orange); border-top: none; border-radius: 0 0 10px 10px; background: rgba(238,81,58,0.03); }
.hour-slots-label { font-size: 0.68rem; color: var(--font-color); opacity: 0.4; margin-bottom: 8px; }
.hour-slots-chips { display: flex; flex-wrap: wrap; gap: 6px; }
/* Day-part heading in the slot list ("Morning", "Afternoon", …), replacing the old
   hardcoded midday divider. Mirrors admin's .bkp-daypart in booking-blocks.css so
   the live page and the block preview read the same.
   (The old class name is deliberately not written down here: a guard asserts it
   appears nowhere under resources/ or public/assets/, and a prose mention would
   either fail that check or teach it to ignore comments.)
   ⚠ NO opacity on the word. The rule this replaced set opacity:0.3 on the whole
   element, which failed WCAG AA on the label text — and the label is now the
   photographer's own copy, not decoration. The hairlines carry the muted treatment
   instead, as ::before/::after, because they ARE decoration. */
.daypart-break   { display: flex; align-items: center; gap: 10px; margin: 10px 0 4px; padding: 4px 0; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--font-color); }
.daypart-break::before,
.daypart-break::after { content: ''; flex: 1 1 auto; height: 1px; background: var(--border-muted); }
.daypart-break > span { flex: 0 0 auto; }
.daypart-break:first-child { margin-top: 0; }
.hour-legend     { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border-muted); display: flex; align-items: center; gap: 16px; flex-wrap: wrap; font-size: 0.7rem; color: var(--font-color); opacity: 0.45; }

/* Hour picker — step B header */
.back-btn     { background: none; border: none; padding: 0; font-size: 0.82rem; color: var(--font-color); opacity: 0.55; cursor: pointer; display: flex; align-items: center; gap: 6px; }
.back-btn i   { font-size: 0.75rem; }
.date-heading { font-size: 0.88rem; font-weight: 700; color: var(--heading-color); }
.time-heading { font-family: var(--heading-font); font-size: 0.95rem; font-weight: 700; color: var(--heading-color); margin-bottom: 16px; }

/* Secondary menu */
#selectedSlotBarPackages { display: none; background: var(--bg-color); border-bottom: 1px solid var(--border-muted); padding: 8px 0; transition: box-shadow 0.2s ease; position: sticky; top: 0; z-index: 400; }
/* ⚠ flex-wrap matches .bk-slot-bar-inner, which has always had it. Without it this
   bar's right group (the countdown and "Change time") has nowhere to go on a phone
   and crowds up against the service pill, while the identical bar on every other
   booking step drops it onto its own line. Same bar to a customer, so same rule. */
#selectedSlotBarPackages .px-4 { display: flex; align-items: center; justify-content: space-between; gap: 6px 12px; flex-wrap: wrap; }
#selectedSlotBarPackages.is-stuck-shadow { box-shadow: 0 8px 26px rgba(0,0,0,0.18); }
/* ⚠ SIZED FOR A LINE OF ITS OWN, not for a row it shared. At 0.68rem/4px 12px this
   was a 24px chip, which read as a peer of the held date when the two sat side by
   side and as a heading over it once the bar stacked — and it was the single biggest
   contributor to a sticky bar that had grown to 107px on a phone. It is an eyebrow
   now: the same chip, at label weight, ~18px tall. It is worn ONLY by the two
   held-slot bars (book/_slot-bar and #selectedSlotBarPackages), so this is safe to
   size globally and is what keeps the two of them identical.

   ⚠ IT CARRIES THE HOLD ONLY — the clock and the words "Slot Held". The service
     used to sit in here and moved down to .bk-slot-bar-what with the package
     (owner's call, 2026-09-09); the class name is historical. Nothing else goes
     back in: the pill's job is one fact, and it is the only element on the bar a
     customer watches change. */
.secondary-svc-pill  { display: inline-flex; align-items: center; gap: 3px; flex-shrink: 0; white-space: nowrap; background: rgba(238,81,58,0.1); color: var(--accent-orange); font-size: 0.6rem; font-weight: 700; letter-spacing: 0.04em; padding: 2px 9px; border-radius: 20px; }
/* ⚠ SIZED FOR .bk-slot-bar-svc, NOT FOR THE PILL. It travelled with the service
   name out of the 0.6rem eyebrow onto the 0.8rem line, so 0.54rem now reads as a
   speck; it matches the padlock's 0.72rem instead. The right margin replaces the
   pill's flex `gap`, which no longer applies to it — inside .bk-slot-bar-svc the
   icon and the name are inline, so without it they touch. */
.secondary-svc-icon  { font-size: 0.72rem; color: var(--accent-orange); margin-right: 4px; }
/* The hold clock now OPENS this pill on both bars, and it is the one thing in there
   sized to be read rather than skimmed — the eyebrow decision above is about the
   service LABEL, not about a number the eye returns to every few seconds. Its own
   line box is what sets the pill's height, so the pill grows ~4px and no rule here
   has to know that.

   ⚠ The digits keep .bk-slot-bar-held's red rather than inheriting the pill's accent:
     the padlock says "held", the colour is what says "running out". They now sit on a
     10% wash of --accent-orange instead of the bar's own ground, so a studio whose
     accent IS red gets less separation than one whose accent is blue — the separator
     and the padlock are what carry it there.

   ⚠ letter-spacing:0 — the pill tracks its label at 0.04em, which on tabular digits
     reads as a gap opening up inside the number every time it ticks past a 1. */
.secondary-svc-pill .bk-slot-bar-held { font-size: 0.76rem; letter-spacing: 0; }
/* The "·" — between the clock and "Slot Held" in the pill, and between the service
   and the package on the line below. Decorative, and quieter than either side of it
   so it separates without becoming a third thing to read. */
.bk-pill-sep { opacity: 0.4; font-weight: 400; }
/* "Slot Held", the words the countdown is counting for. It rides the pill's own
   eyebrow type, so there is nothing to size here — only the gap after the "·",
   which is nested INSIDE this span rather than being a sibling of it so that
   hiding the label on expiry takes the separator with it. A stranded "5:36 ·" is
   the failure this shape prevents. */
.bk-slot-bar-holdlabel > .bk-pill-sep { margin-right: 3px; }
.secondary-date      { font-size: 0.88rem; font-weight: 600; color: var(--heading-color); white-space: nowrap; }
.secondary-date-icon { color: var(--accent-orange); font-size: 0.78rem; }
.countdown-wrap      { font-size: 0.78rem; color: var(--font-color); opacity: 0.55; display: flex; align-items: center; gap: 5px; }
.countdown-dot       { width: 8px; height: 8px; border-radius: 50%; background: var(--accent-orange); display: inline-block; animation: pulseGreen 1.9s infinite; }
.countdown-val       { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--heading-color); }
.change-time-link    { font-size: 0.78rem; color: var(--accent-orange); text-decoration: none; font-weight: 600; white-space: nowrap; background: none; border: none; padding: 0; cursor: pointer; }
.change-time-link:hover { color: var(--heading-color); }
.change-time-icon    { font-size: 0.68rem; }

/* Main content area */
.main-area  { background: var(--bg-color); flex: 1; padding-bottom: 120px; }
.page-wrap  { display: flex; flex-direction: column; min-height: 80vh; }

/* Package panel headings */
.active-product-heading { font-family: var(--heading-font); font-weight: 700; color: var(--heading-color); font-size: 1.25rem; margin-bottom: 6px; }
.active-product-subtext { font-size: 0.83rem; color: var(--font-color); opacity: 0.55; margin: 0; }

/* Addons panel heading */
.panel-eyebrow  { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent-orange); margin-bottom: 8px; }
.panel-heading  { font-family: var(--heading-font); font-size: 1.25rem; font-weight: 700; color: var(--heading-color); margin-bottom: 6px; }
.panel-subtext  { font-size: 0.83rem; color: var(--font-color); opacity: 0.55; margin: 0; }

/* Shared step heading (book/_step-head.blade.php) — the title + supporting line on
   EVERY booking step: calendar, packages, configure, add-ons, both paged add-on waves.

   ⚠⚠ THESE TWO CLASSES HAD NO RULE ANYWHERE. `_step-head` unified three heading
   languages onto the calendar's `h3.step-heading` / `p.step-copy`, but the calendar had
   only ever emitted them as bare markup — so the one heading the whole journey shares
   was the only one bound to nothing. It fell through to the browser's <h3>: the BODY
   font instead of --heading-font, the BODY ink instead of --heading-color, and full-
   strength copy where every sibling is muted. A photographer set a heading colour and a
   heading font in admin and watched the eyebrow above the title obey while the title
   itself ignored both — the eyebrow is .panel-eyebrow, which was styled all along.

   ⚠ The SIZE is deliberately Bootstrap's own <h3> ramp, not the .panel-heading scale
   above. Unstyled means every step has been rendering at that size, consistently, since
   the partial shipped; this binds the tokens without moving a single heading. Retuning
   the scale is a design decision, not part of making the theme reach it. */
.step-heading { font-family: var(--heading-font); font-weight: 700; color: var(--heading-color); font-size: calc(1.3rem + 0.6vw); line-height: 1.2; margin-bottom: 0.5rem; }
@media (min-width: 1200px) { .step-heading { font-size: 1.75rem; } }
.step-copy    { color: var(--font-color); opacity: 0.65; margin: 0; }

.addons-bar       { background: rgba(128,128,128,0.06); border: 1px solid var(--border-muted); }
.addons-bar-total { font-size: 1.1rem; font-weight: 700; color: var(--heading-color); font-family: var(--heading-font); }
.addons-bar-label { font-size: 0.82rem; color: var(--font-color); opacity: 0.6; }
/* The fee line above the total, shown only by an account that names its booking
   fee during booking. Its own opacity rather than .addons-bar-label's, because
   it sits ABOVE the total rather than beside it and has to read as a breakdown
   the eye skims, not as a second headline competing with the figure below. */
.addons-bar-breakdown     { font-size: 0.78rem; color: var(--font-color); opacity: 0.72; line-height: 1.3; margin-bottom: 2px; }
.addons-bar-breakdown b   { font-weight: 600; opacity: 0.92; }
.addons-bar-breakdown-sep { opacity: 0.45; margin: 0 0.45rem; }

/* Package cards (JS-generated) */
.pkg-selected-badge { background: var(--accent-orange); color: #fff; font-size: 0.65rem; font-weight: 700; padding: 4px 10px; border-radius: 20px; z-index: 1; }
.pkg-radio-ring     { flex-shrink: 0; width: 18px; height: 18px; margin-top: 2px; border-radius: 50%; border: 2px solid var(--accent-orange); display: flex; align-items: center; justify-content: center; }
.pkg-radio-dot      { width: 9px; height: 9px; border-radius: 50%; background: var(--accent-orange); }
.pkg-radio-ring-sm  { flex-shrink: 0; width: 16px; height: 16px; margin-top: 3px; border-radius: 50%; border: 2px solid var(--accent-orange); display: flex; align-items: center; justify-content: center; }
.pkg-radio-dot-sm   { width: 8px; height: 8px; border-radius: 50%; background: var(--accent-orange); }
/* ⚠ THIS is the heading on the BASIC package card — the layout almost every
   account is on (pkg_layout_mode='basic'). The premium card's name is a
   different class in a different file (.premium-pkg-name, inline in
   book/_premium-package-assets.blade.php); sizing only that one changes nothing
   for a basic account, which is the easy way to ship this and appear to have
   done nothing. Both were made fluid together on 2026-09-04.
   Fluid rather than a fixed bump because there is no device to guess at: a
   Pro Max, a mini and a flip phone all want a different number. min/max stay in
   rem (WCAG 1.4.4 — the bounds honour the reader's font size); only the middle
   term is viewport-relative. Same shape as .pkg-price two lines down. */
.pkg-name           { font-family: var(--heading-font); font-size: clamp(1.15rem, 1.04rem + 0.48vw, 1.4rem); font-weight: 700; color: var(--heading-color); margin: 0 0 4px; line-height: 1.25; }
.pkg-name-sm        { font-family: var(--heading-font); font-size: 0.92rem; font-weight: 700; color: var(--heading-color); }
.pkg-compare        { font-size: 0.78rem; color: var(--font-color); opacity: 0.35; text-decoration: line-through; margin-right: 6px; }
.pkg-compare-note   { font-size: 0.72rem; color: var(--font-color); opacity: 0.4; }
.pkg-price          { font-size: clamp(1.25rem, 1.18rem + 0.3vw, 1.44rem); font-weight: 700; color: var(--heading-color); font-family: var(--heading-font); }
.pkg-price-sm       { font-size: clamp(1.1rem, 1.05rem + 0.22vw, 1.24rem); font-weight: 700; color: var(--heading-color); }
.pkg-desc           { font-size: 0.82rem; color: var(--font-color); opacity: 0.65; line-height: 1.6; margin-bottom: 8px; }
.pkg-desc-sm        { font-size: 0.78rem; color: var(--font-color); opacity: 0.6; margin-top: 3px; }
.pkg-inclusions     { padding: 0; margin: 0 0 10px; }
.pkg-inclusion-item { font-size: 0.8rem; color: var(--font-color); opacity: 0.7; line-height: 1.7; padding-left: 2px; }
.pkg-includes       { list-style: none; padding: 0; margin: 0 0 12px; }
.pkg-includes li    { font-size: 0.76rem; color: var(--font-color); opacity: 0.65; margin-bottom: 3px; }
.pkg-includes-sm    { list-style: none; padding: 0; margin: 6px 0 0; }
.pkg-includes-sm li { font-size: 0.73rem; color: var(--font-color); opacity: 0.6; margin-bottom: 2px; }
.pkg-includes-icon     { color: var(--accent-orange); font-size: 0.6rem; }
.pkg-includes-icon-sm  { color: var(--accent-orange); font-size: 0.58rem; }

/* A .mini-list whose rows carry their own check icon. The check IS the list
   marker, so the disc bullet .mini-list inherits sits in front of it and reads
   as two markers on every line. Scoped to the modifier on purpose — the plain
   .mini-list on /manage/addons has no icon and still wants its bullet.
   ⚠ Lives here rather than in resources/css/app.css (where .mini-list is
   defined) because booking.css is served straight off disk and ships on a
   plain git pull; app.css needs a Vite build on the server. booking.css is
   linked after @vite in layouts/app.blade.php, so it wins on equal
   specificity. */
.mini-list.mini-list-check { padding-left: 0; list-style: none; }

/* Waitlist modal — custom-styled, not Bootstrap default
   ----------------------------------------------------------------- */
.wl-backdrop {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.55);
    backdrop-filter: blur(5px);
    z-index: 4099;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.2s ease;
}
.wl-backdrop.is-open { opacity: 1; }
.wl-modal {
    position: fixed;
    top: 50%; left: 50%;
    transform: translate(-50%, -48%);
    width: calc(100% - 32px);
    max-width: 480px;
    max-height: 90vh;
    overflow-y: auto;
    background: var(--bg-color, #faf9f6);
    border-radius: 20px;
    padding: 32px 28px 24px;
    box-shadow: 0 24px 60px rgba(0,0,0,0.25);
    z-index: 4100;
    opacity: 0;
    transition: opacity 0.25s ease, transform 0.25s ease;
}
.wl-modal.is-open {
    opacity: 1;
    transform: translate(-50%, -50%);
}
.wl-close {
    position: absolute; top: 14px; right: 16px;
    width: 36px; height: 36px;
    border: 0; border-radius: 50%;
    background: rgba(128,128,128,0.12);
    color: var(--font-color);
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, transform 0.15s;
}
.wl-close:hover, .wl-close:focus {
    background: rgba(238,81,58,0.15);
    color: var(--accent-orange);
    outline: none;
    transform: scale(1.05);
}
.wl-icon {
    width: 56px; height: 56px;
    border-radius: 50%;
    background: rgba(238,81,58,0.12);
    color: var(--accent-orange);
    display: flex; align-items: center; justify-content: center;
    margin: 0 auto 12px;
    font-size: clamp(1.4rem, 1.3rem + 0.42vw, 1.66rem);
}
.wl-title {
    margin: 0 0 6px;
    text-align: center;
    font-family: var(--heading-font);
    font-size: clamp(1.25rem, 1.18rem + 0.3vw, 1.44rem);
    font-weight: 700;
    color: var(--heading-color);
}
.wl-subtitle {
    text-align: center;
    color: var(--font-color);
    opacity: 0.7;
    font-size: 0.88rem;
    margin: 0 0 18px;
}
.wl-scope {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 18px;
}
.wl-scope__option {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 14px;
    border: 1.5px solid var(--border-muted, rgba(128,128,128,0.2));
    border-radius: 12px;
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
    margin: 0;
    position: relative;
}
.wl-scope__option:hover {
    border-color: rgba(238,81,58,0.4);
}
.wl-scope__option input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.wl-scope__option.is-selected {
    border-color: var(--accent-orange);
    background: rgba(238,81,58,0.06);
}
.wl-scope__check {
    color: var(--accent-orange);
    font-size: 1rem;
    margin-top: 2px;
    flex-shrink: 0;
    opacity: 0;
    transition: opacity 0.15s;
}
.wl-scope__option.is-selected .wl-scope__check { opacity: 1; }
.wl-scope__body { flex: 1; min-width: 0; }
.wl-scope__label {
    font-weight: 600;
    color: var(--heading-color);
    font-size: 0.92rem;
    line-height: 1.3;
}
.wl-scope__hint {
    font-size: 0.78rem;
    color: var(--font-color);
    opacity: 0.6;
    margin-top: 4px;
    line-height: 1.4;
}
.wl-banner {
    border-radius: 10px;
    padding: 10px 14px;
    font-size: 0.86rem;
    margin-bottom: 14px;
}
.wl-banner--ok {
    background: rgba(44,182,167,0.12);
    color: rgb(28, 128, 117);
    border: 1px solid rgba(44,182,167,0.35);
}
.wl-banner--err {
    background: rgba(220,38,38,0.1);
    color: #c52424;
    border: 1px solid rgba(220,38,38,0.3);
}
.wl-form { margin-bottom: 14px; }
.wl-form .form-label {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--font-color);
    opacity: 0.8;
    margin-bottom: 4px;
}
.wl-form .form-control {
    border: 1.5px solid var(--border-muted, rgba(128,128,128,0.2));
    border-radius: 10px;
    padding: 9px 12px;
    font-size: 0.9rem;
    background: var(--bg-color);
    color: var(--font-color);
}
.wl-form .form-control:focus {
    border-color: var(--accent-orange);
    box-shadow: 0 0 0 3px rgba(238,81,58,0.12);
    outline: none;
}
.wl-actions {
    display: flex; gap: 10px;
    justify-content: flex-end;
    flex-wrap: wrap;
}
.wl-btn-primary, .wl-btn-secondary {
    border: 0;
    border-radius: 999px;
    padding: 10px 22px;
    font-weight: 700;
    font-size: 0.88rem;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, transform 0.1s;
}
.wl-btn-primary {
    background: var(--accent-orange);
    color: #fff;
}
.wl-btn-primary:hover { transform: translateY(-1px); }
.wl-btn-primary[disabled] {
    opacity: 0.6; cursor: not-allowed; transform: none;
}
.wl-btn-secondary {
    background: transparent;
    color: var(--font-color);
    border: 1.5px solid var(--border-muted, rgba(128,128,128,0.25));
}
.wl-btn-secondary:hover {
    background: rgba(128,128,128,0.06);
}
.mode-dark .wl-modal { background: var(--bg-dark-secondary); }
.mode-dark .wl-scope__option { border-color: rgba(255,255,255,0.12); }
.mode-dark .wl-scope__option.is-selected { background: rgba(238,81,58,0.18); }
.mode-dark .wl-form .form-control {
    background: var(--bg-dark-color);
    border-color: rgba(255,255,255,0.12);
    color: var(--font-dark-color);
}

/* Service switcher (calendar mini-header) */
.svc-switcher { position: relative; flex-shrink: 0; }
.svc-switcher__trigger {
    background: transparent;
    border: 1.5px solid var(--border-muted, rgba(128,128,128,0.2));
    border-radius: 999px;
    padding: 6px 14px;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--font-color);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    transition: border-color 0.15s, background 0.15s, color 0.15s;
}
.svc-switcher__trigger:hover,
.svc-switcher__trigger:focus {
    border-color: var(--accent-orange);
    color: var(--accent-orange);
    background: rgba(238,81,58,0.05);
    outline: none;
}
.svc-switcher__menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    min-width: 240px;
    max-width: 320px;
    max-height: 340px;
    overflow-y: auto;
    list-style: none;
    margin: 0;
    padding: 6px;
    background: var(--bg-color, #faf9f6);
    border: 1px solid var(--border-muted, rgba(128,128,128,0.2));
    border-radius: 12px;
    box-shadow: 0 10px 32px rgba(0,0,0,0.12);
    z-index: 50;
    display: none;
}
.svc-switcher__menu.is-open { display: block; }
.svc-switcher__item {
    width: 100%;
    background: transparent;
    border: 0;
    padding: 10px 12px;
    border-radius: 8px;
    text-align: left;
    cursor: pointer;
    color: var(--font-color);
    display: flex;
    align-items: center;
    gap: 10px;
    transition: background 0.12s, color 0.12s;
}
.svc-switcher__item:hover,
.svc-switcher__item:focus {
    background: rgba(238,81,58,0.07);
    color: var(--accent-orange);
    outline: none;
}
.svc-switcher__icon {
    width: 18px;
    flex-shrink: 0;
    text-align: center;
    color: var(--accent-orange);
    opacity: 0.85;
}
.svc-switcher__name { flex: 1; font-size: 0.85rem; font-weight: 600; }
.svc-switcher__duration { font-size: 0.72rem; opacity: 0.55; flex-shrink: 0; }
.mode-dark .svc-switcher__menu { background: var(--bg-dark-secondary); border-color: rgba(255,255,255,0.12); }
.mode-dark .svc-switcher__item:hover,
.mode-dark .svc-switcher__item:focus { background: rgba(238,81,58,0.16); }

/* Package cards (JS-rendered) — sit on a secondary surface + faint shadow so
   they lift a touch off the section background (twin of the dark rule below). */
.pkg-card { cursor: pointer; transition: border-color 0.2s, box-shadow 0.2s, background-color 0.2s; background-color: var(--bg-light-secondary); box-shadow: 0 1px 4px rgba(0,0,0,0.05); }
.pkg-card:hover  { border-color: rgba(238,81,58,0.4) !important; box-shadow: 0 4px 20px rgba(238,81,58,0.12) !important; }
.pkg-card.selected { border-color: var(--accent-orange) !important; box-shadow: 0 4px 24px rgba(238,81,58,0.2) !important; }

/* Addon sheet (suggested) */
.sheet-backdrop     { position: fixed; inset: 0; background: rgba(0,0,0,0.48); backdrop-filter: blur(4px); z-index: 3999; cursor: pointer; }
.sheet-close-btn {
    position: absolute; top: 14px; right: 18px;
    width: 36px; height: 36px;
    border: 0; border-radius: 50%;
    background: rgba(128,128,128,0.12);
    color: var(--font-color);
    display: flex; align-items: center; justify-content: center;
    cursor: pointer; z-index: 5;
    transition: background 0.15s, color 0.15s, transform 0.15s;
}
.sheet-close-btn:hover,
.sheet-close-btn:focus { background: rgba(238,81,58,0.15); color: var(--accent-orange); outline: none; transform: scale(1.05); }
.sheet-close-btn i { font-size: 0.9rem; }
.sheet-change-pkg-btn {
    display: block; width: 100%; margin-top: 8px;
    background: transparent; border: 0;
    color: var(--font-color); opacity: 0.6;
    font-size: 0.85rem; font-weight: 600;
    padding: 8px;
    border-radius: 8px;
    cursor: pointer;
    transition: opacity 0.15s, background 0.15s, color 0.15s;
}
.sheet-change-pkg-btn:hover,
.sheet-change-pkg-btn:focus { opacity: 1; color: var(--accent-orange); background: rgba(238,81,58,0.06); outline: none; }
.sheet-handle       { padding: 12px 0 4px; text-align: center; flex-shrink: 0; }
.sheet-handle-bar   { width: 36px; height: 4px; border-radius: 2px; background: rgba(128,128,128,0.2); margin: 0 auto; }
.sheet-header       { padding: 12px 24px 16px; flex-shrink: 0; border-bottom: 1px solid var(--border-muted); }
.sheet-eyebrow      { font-size: 0.68rem; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--accent-orange); margin-bottom: 6px; }
.sheet-title        { font-size: 1rem; font-family: var(--heading-font); font-weight: 700; color: var(--heading-color); margin-bottom: 4px; }
.sheet-subtext      { font-size: 0.78rem; color: var(--font-color); opacity: 0.5; }
.sheet-body         { flex: 1; overflow-y: auto; padding: 16px 24px; }
.sheet-footer       { flex-shrink: 0; padding: 16px 24px; border-top: 1px solid var(--border-muted); background: var(--bg-color, #faf9f6); }
.sheet-so-far       { font-size: 0.75rem; color: var(--font-color); opacity: 0.5; }
.sheet-total        { font-size: 1rem; font-weight: 700; color: var(--heading-color); font-family: var(--heading-font); }
.sheet-footer-note  { text-align: center; margin-top: 8px; font-size: 0.7rem; color: var(--font-color); opacity: 0.35; }
.addons-sheet       { position: fixed; bottom: 0; left: 0; right: 0; margin: 0 auto; width: 100%; max-width: 720px; height: 90vh; max-height: none; transform: translateY(100%); transition: transform 0.35s cubic-bezier(0.32,0.72,0,1); z-index: 4000; background: var(--bg-color, #faf9f6); border-radius: 24px 24px 0 0; overflow: hidden; display: flex; flex-direction: column; box-shadow: 0 -24px 60px rgba(0,0,0,0.18); }
@media (min-width: 768px) { .addons-sheet { height: 80vh; } }
.sheet-addon-check       { flex-shrink: 0; width: 20px; height: 20px; border-radius: 6px; border: 2px solid var(--accent-orange); display: flex; align-items: center; justify-content: center; transition: background 0.15s, border-color 0.15s; }
.sheet-addon-check-icon  { font-size: 0.65rem; color: var(--accent-orange); }

/* Addon sheet item cards */
.addon-sheet-card { padding: 12px 14px; border-radius: 10px; border: 1.5px solid var(--border-muted); margin-bottom: 8px; cursor: pointer; transition: border-color 0.15s, background 0.15s; background: var(--bg-color); }
/* Same composite rule as .generic-card.selected — tint over the surface, never
   instead of it, or the pop-up sheet's selected card goes see-through. */
.addon-sheet-card.selected {
    border-color: var(--accent-orange);
    background-color: var(--bg-color);
    background-image: linear-gradient(rgba(238,81,58,0.04), rgba(238,81,58,0.04));
}
.addon-sheet-card.selected .sheet-addon-check { background: var(--accent-orange); border-color: var(--accent-orange); }
.addon-sheet-card.selected .sheet-addon-check-icon { color: #fff; }

/* ── Suggested-addons sheet layouts (list default · card grid · swipe carousel).
   booking.js renders one .addon-sheet-card structure (check · thumb · info · price);
   the sheet's .addons-sheet--<layout> modifier rearranges it (mobile-first). ── */
.addon-thumb--ph { display: flex; align-items: center; justify-content: center; color: var(--heading-color); opacity: 0.25; font-size: 1.2rem; }
/* List (default) — rows */
.addons-sheet--list .addon-sheet-card { display: flex; align-items: center; gap: 14px; }
.addons-sheet--list .addon-sheet-card__info { flex: 1; min-width: 0; }
/* Card grid — image-forward, tap to add */
.addons-sheet--card #bookingSheetAddonsList { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.addons-sheet--card .addon-sheet-card { display: flex; flex-direction: column; padding: 0; margin-bottom: 0; overflow: hidden; position: relative; }
.addons-sheet--card .addon-thumb, .addons-sheet--card .addon-thumb--ph { width: 100%; height: 120px; border-radius: 0; }
.addons-sheet--card .sheet-addon-check { position: absolute; top: 10px; left: 10px; background: var(--bg-color); z-index: 1; }
.addons-sheet--card .addon-sheet-card__info { padding: 10px 14px 2px; }
.addons-sheet--card .addon-price { padding: 0 14px 12px; }
/* Swipe carousel — horizontal scroll (best for several add-ons on mobile) */
.addons-sheet--carousel #bookingSheetAddonsList { display: flex; gap: 12px; overflow-x: auto; padding-bottom: 8px; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; }
/* Carousel is a single horizontal row — let the sheet hug its content height instead of
   filling 80/90vh (which left a tall empty gap above the footer). The body stops growing
   so the footer sits right under the cards; sheet still caps at 90vh as a safety net. */
.addons-sheet--carousel { height: auto; max-height: 90vh; }
.addons-sheet--carousel .sheet-body { flex: 0 0 auto; overflow-y: hidden; }
.addons-sheet--carousel .addon-sheet-card { flex: 0 0 200px; display: flex; flex-direction: column; padding: 0; margin-bottom: 0; overflow: hidden; position: relative; scroll-snap-align: start; }
.addons-sheet--carousel .addon-thumb, .addons-sheet--carousel .addon-thumb--ph { width: 100%; height: 120px; border-radius: 0; }
.addons-sheet--carousel .sheet-addon-check { position: absolute; top: 10px; left: 10px; background: var(--bg-color); z-index: 1; }
.addons-sheet--carousel .addon-sheet-card__info { padding: 10px 14px 2px; }
.addons-sheet--carousel .addon-price { padding: 0 14px 12px; }
/* Mobile: emphasise the add-ons by packing 2 per row (was 1-up) so at least 2–3
   sit on screen at once without a horizontal swipe. A shorter image + tighter
   gap/padding keep several emphasised cards in view on a phone. */
@media (max-width: 560px) {
  .addons-sheet--card #bookingSheetAddonsList { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .addons-sheet--card .addon-thumb, .addons-sheet--card .addon-thumb--ph { height: 92px; }
  .addons-sheet--card .addon-sheet-card__info { padding: 8px 10px 2px; }
  .addons-sheet--card .addon-price { padding: 0 10px 10px; }
}
/* Card layout scales with the viewport — the sheet widens to fit the page and the
   cards (and their images) get bigger on md → lg → xl. 2 columns throughout so the
   cards grow rather than multiply-and-shrink; mobile stays 1-up. */
@media (min-width: 768px)  { .addons-sheet--card { max-width: 760px; }  .addons-sheet--card .addon-thumb, .addons-sheet--card .addon-thumb--ph { height: 150px; } }
@media (min-width: 992px)  { .addons-sheet--card { max-width: 980px; }  .addons-sheet--card #bookingSheetAddonsList { grid-template-columns: repeat(3, 1fr); } .addons-sheet--card .addon-thumb, .addons-sheet--card .addon-thumb--ph { height: 160px; } }
@media (min-width: 1200px) { .addons-sheet--card { max-width: 1180px; } .addons-sheet--card .addon-thumb, .addons-sheet--card .addon-thumb--ph { height: 185px; } }
/* Carousel scales the same way — wider sheet + bigger cards/images on md → lg → xl;
   the row still scrolls horizontally, just with larger, more generous cards. */
@media (min-width: 768px)  { .addons-sheet--carousel { max-width: 760px; }  .addons-sheet--carousel .addon-sheet-card { flex-basis: 240px; } .addons-sheet--carousel .addon-thumb, .addons-sheet--carousel .addon-thumb--ph { height: 150px; } }
@media (min-width: 992px)  { .addons-sheet--carousel { max-width: 980px; }  .addons-sheet--carousel .addon-sheet-card { flex-basis: 280px; } .addons-sheet--carousel .addon-thumb, .addons-sheet--carousel .addon-thumb--ph { height: 180px; } }
@media (min-width: 1200px) { .addons-sheet--carousel { max-width: 1180px; } .addons-sheet--carousel .addon-sheet-card { flex-basis: 320px; } .addons-sheet--carousel .addon-thumb, .addons-sheet--carousel .addon-thumb--ph { height: 210px; } }

/* ═══════════════════════════════════════════════════════════════════════
   Booking Page Block Builder ("Spotlight") — block render (.bkb-*)
   Structure mirrors the admin editor preview (content/assets/css/
   booking-blocks.css); colours pick up the live storefront theme so the
   Spotlight page matches the booking-page branding. Phase 7 reconciles the
   admin preview to this. Per-block bg/font/card come inline from the row.
   ═══════════════════════════════════════════════════════════════════════ */
.bkb-page-blocks { width: 100%; }
.bkb-block { position: relative; padding: 56px 20px; }
.bkb-block[data-pad="compact"]  { padding-top: 32px; padding-bottom: 32px; }
.bkb-block[data-pad="spacious"] { padding-top: 88px; padding-bottom: 88px; }
.bkb-block--divider, .bkb-block--spacer { padding-top: 0; padding-bottom: 0; }
/* Full-bleed blocks (hero by default; image when full-width) fill edge to edge */
.bkb-block--bleed { padding: 0; }
.bkb-block--bleed .bkb-inner { max-width: none; margin: 0; }
/* Sticky Nav block — the OUTER block is the sticky element (its parent .bkb-page-blocks
   spans the rest of the page, so it pins from wherever it's dropped and carries down). */
.bkb-block--sticky_nav { position: sticky; top: 0; z-index: 1030; padding: 0; background: var(--bg-color); box-shadow: 0 2px 12px rgba(0, 0, 0, 0.14); }
.bkb-block--sticky_nav .bkb-inner { max-width: none; margin: 0; }
/* Sticky nav "on scroll" wording — ONE rule set, serving ALL THREE bars: the Block
   Builder's Sticky Nav block, the Enhanced Showcase layout's secondary nav, and the
   held-slot bar the booking steps carry (which owns no settings and inherits the
   block's — see .bk-slot-bar-brand below). booking-sticky-nav.js
   sets data-scroll-state="scrolled" on the inner once the bar has been pinned for the
   configured distance; everything below is the before/after of that one attribute.

   ⚠ THE GATE IS [data-scroll-mode], NOT A SURFACE CLASS, AND THAT IS DELIBERATE.
   .sc-secondary-nav__* is shared between the two bars, so these rules used to be scoped
   under .bkb-block--sticky_nav to keep them off the Showcase nav. That scope came off when
   the Showcase nav gained the same behaviour: a bar publishes data-scroll-mode ONLY when
   its settings chose a mode and carry wording, so the attribute already answers "does this
   bar opt in?" — better than a class does, because it is per-bar rather than per-surface.
   Re-adding a surface scope would silently switch one of the two bars back off.

   ⚠ Both admin previews draw the same two states side by side using these EXACT selectors
   (content/assets/css/booking-blocks.css for the block, the <style> block in
   locationpages_showcase_preview_view.php for the Showcase nav), so what the photographer
   sets up is what the page does. tests/sticky_nav_block_test.php compares them. */
.sc-nav-scroll-eyebrow { display: block; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; opacity: 0.75; }
.sc-nav-scroll-main { display: block; font-size: 1rem; font-weight: 700; }
/* swap — the logo lifts out and the wording rises into the space it left */
[data-scroll-mode="swap"] .sc-secondary-nav__logo { position: relative; display: block; overflow: hidden; min-height: 42px; }
[data-scroll-mode="swap"] .sc-nav-logo { display: flex; align-items: center; justify-content: center; height: 42px; }
[data-scroll-mode="swap"] .sc-nav-scroll { position: absolute; left: 0; right: 0; top: 0; bottom: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1.15; transform: translateY(110%); opacity: 0; }
[data-scroll-mode="swap"] .sc-nav-logo,
[data-scroll-mode="swap"] .sc-nav-scroll { transition: transform 0.28s ease, opacity 0.28s ease; }
[data-scroll-mode="swap"][data-scroll-state="scrolled"] .sc-nav-logo { transform: translateY(-110%); opacity: 0; }
[data-scroll-mode="swap"][data-scroll-state="scrolled"] .sc-nav-scroll { transform: translateY(0); opacity: 1; }
/* shift — the logo shrinks and the wording slides in beside it */
[data-scroll-mode="shift"] .sc-secondary-nav__logo { display: flex; align-items: center; justify-content: center; gap: 10px; text-align: left; min-height: 42px; }
[data-scroll-mode="shift"] .sc-nav-logo { flex: 0 0 auto; }
/* ⚠ SHIFT STARTS BIG AND SETTLES, it does not start normal and get small. Both
   numbers here override .sc-secondary-nav__logo img's 40px cap, and they have to move
   together: shrinking a 40px logo to 28px reads as a logo that went wrong, not as a
   bar making room. 150 → 75 is a halving the eye reads as deliberate. Owner's call,
   2026-09-09. Raising only the scrolled number would be a no-op — 75 is above the
   40px cap, so the logo would simply stop shrinking. */
[data-scroll-mode="shift"] .sc-nav-logo img { max-height: 150px; transition: max-height 0.28s ease; }
[data-scroll-mode="shift"] .sc-nav-scroll { display: flex; flex-direction: column; line-height: 1.15; max-width: 0; opacity: 0; overflow: hidden; white-space: nowrap; transition: max-width 0.28s ease, opacity 0.28s ease; }
[data-scroll-mode="shift"][data-scroll-state="scrolled"] .sc-nav-logo img { max-height: 75px; }
[data-scroll-mode="shift"][data-scroll-state="scrolled"] .sc-nav-scroll { max-width: 70%; opacity: 1; }
/* ⚠ Phones get a smaller pair. A 150px logo makes the bar ~166px tall, which on a
   667px screen is a quarter of the viewport pinned to the top before the visitor has
   read anything. The effect is the same shape, at a size a phone can carry. */
@media (max-width: 575.98px) {
  [data-scroll-mode="shift"] .sc-nav-logo img { max-height: 76px; }
  [data-scroll-mode="shift"][data-scroll-state="scrolled"] .sc-nav-logo img { max-height: 48px; }
}
/* The THIRD bar — the held-slot bar the booking steps carry once a slot is held
   (book/_slot-bar, and the calendar's own #selectedSlotBarPackages). It owns no
   settings: it INHERITS the Sticky Nav block's logo and wording, so the studio sets
   the effect up once and it follows the customer into the journey.

   ⚠ IT IS HERE BECAUSE THE NAV CANNOT STICK ON A BOOKING STEP. The block renders
   inside .bkb-step-blocks, a plain full-width div, and position:sticky is bounded by
   its parent box — so the nav pins for about its own height and is gone. This bar is
   what stays.

   ⚠ EVERYTHING ABOVE STILL APPLIES TO IT. The transitions, the transforms and the
   cross-fade come from the shared [data-scroll-mode] rules; these override only the
   two things that are wrong at this size — the CONTAINER (the nav's is
   .sc-secondary-nav__logo, which this bar does not have) and the SHIFT LOGO SIZE. The
   nav's shift logo starts at 150px, which is a hero treatment for a page-top bar and
   more than twice this bar's whole height.

   ⚠ WHERE THE CELL SITS IS NOT DECIDED HERE. From 576px up the bar is a three-track
   grid and this cell is its middle track — the rule is beside .bk-slot-bar-booking,
   because it is the BAR's layout rather than the mark's. The `flex` below governs
   the phone range alone, where the bar is still a wrapping flex row. */
.bk-slot-bar-brand { display: flex; align-items: center; justify-content: center; gap: 10px; flex: 1 1 auto; min-width: 0; overflow: hidden; }
.bk-slot-bar-brand img { max-height: 34px; max-width: 100%; object-fit: contain; display: block; }
/* ⚠ The main line is capped and truncates. This bar already carries a date long enough
   to overflow a phone — which is why it renders two forms of it — so an unbounded
   studio name here would push the clock and "Change time" off the right.
   ⚠⚠ white-space:nowrap IS WHAT MAKES THAT TRUE, and it was missing until 2026-09-10.
      `text-overflow: ellipsis` does nothing to text allowed to wrap, so a studio name
      of any length simply took a second line — "Scene To Believe - Office Testing"
      wrapped inside a 34px-tall cell on a phone and collided with the groups either
      side of it. The cap read as applied because the box was capped; the text was not. */
[data-scroll-mode] .bk-slot-bar-brand .sc-nav-scroll-main { font-size: 0.92rem; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
[data-scroll-mode] .bk-slot-bar-brand .sc-nav-scroll-eyebrow { font-size: 0.62rem; }
/* swap — same lift-and-rise, in this bar's own box */
[data-scroll-mode="swap"] .bk-slot-bar-brand { position: relative; display: block; min-height: 34px; }
[data-scroll-mode="swap"] .bk-slot-bar-brand .sc-nav-logo { height: 34px; }
/* shift — a compact shrink, not the nav's hero one */
[data-scroll-mode="shift"] .bk-slot-bar-brand { min-height: 34px; }
[data-scroll-mode="shift"] .bk-slot-bar-brand .sc-nav-logo img { max-height: 34px; }
[data-scroll-mode="shift"][data-scroll-state="scrolled"] .bk-slot-bar-brand .sc-nav-logo img { max-height: 26px; }
[data-scroll-mode="shift"] .bk-slot-bar-brand .sc-nav-scroll { max-width: 0; }
[data-scroll-mode="shift"][data-scroll-state="scrolled"] .bk-slot-bar-brand .sc-nav-scroll { max-width: 100%; }
/* ⚠ A PHONE KEEPS THE MARK AND DROPS THE SMALL LINE. Hiding the whole cell would take
   the studio's identity off the booking journey on most of the traffic, and letting it
   wrap onto its own row grows a bar that is pinned to the top of a short screen. The
   eyebrow is the half a customer can lose — "Mall A" is the substance of it.
   ⚠ The nav's own phone sizes (76px / 48px) are in a media query of LOWER specificity,
   so these have to be restated here or the desktop caps below would win on a phone. */
@media (max-width: 575.98px) {
  .bk-slot-bar-brand img { max-height: 26px; }
  [data-scroll-mode] .bk-slot-bar-brand .sc-nav-scroll-eyebrow { display: none; }
  [data-scroll-mode] .bk-slot-bar-brand .sc-nav-scroll-main { font-size: 0.82rem; }
  [data-scroll-mode="swap"] .bk-slot-bar-brand,
  [data-scroll-mode="shift"] .bk-slot-bar-brand { min-height: 26px; }
  [data-scroll-mode="swap"] .bk-slot-bar-brand .sc-nav-logo { height: 26px; }
  [data-scroll-mode="shift"] .bk-slot-bar-brand .sc-nav-logo img { max-height: 26px; }
  [data-scroll-mode="shift"][data-scroll-state="scrolled"] .bk-slot-bar-brand .sc-nav-logo img { max-height: 22px; }
}
@media (prefers-reduced-motion: reduce) {
  [data-scroll-mode] .sc-nav-logo,
  [data-scroll-mode] .sc-nav-logo img,
  [data-scroll-mode] .sc-nav-scroll { transition: none; }
}
/* Standard content container: a centered, capped reading width so sections don't run
   edge to edge on wide screens (Bootstrap's .container feel, on a Bootstrap-free page).
   The Full-width toggle (.bkb-block--bleed above) and the per-block max_width field
   both override it back to full width. Mirrors admin booking-blocks.css. */
.bkb-inner { max-width: 1140px; margin: 0 auto; }
/* Page logo bar (Phase B) — page-level logo at the very top, gated by the gear's show/hide. */
.bkb-page-logo { text-align: center; padding: 18px 20px 4px; }
.bkb-page-logo img { max-height: 76px; max-width: 60%; object-fit: contain; }
/* Designed-section header: uppercase eyebrow kicker + heading + sub (matches the
   admin preview's secHead so preview == live). */
.bkb-sec-head { margin: 0 auto 1.6rem; max-width: 680px; text-align: center; }
/* Alignment modifiers (2026-08-27). Every band centres its header, so the partial
   hardcoded centring — which is exactly why a section header could not be placed
   beside a picture. The auto side margin has to go too, not just text-align: with
   both margins auto the 680px box stays centred and left-aligned text inside it
   still reads as an indented column. Twin rules — value-identical with admin
   booking-blocks.css (guarded by tests/booking_type_scale_parity_test.php). */
.bkb-sec-head--left  { margin-left: 0; margin-right: auto; text-align: left; }
.bkb-sec-head--right { margin-left: auto; margin-right: 0; text-align: right; }
.bkb-eyebrow { font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .14em; color: var(--accent-orange); margin: 0 0 .5em; }
.bkb-h { font-size: clamp(1.6rem, 1.34rem + 1.1vw, 2.15rem); font-weight: 800; line-height: 1.2; margin: 0 0 .3em; text-align: center; color: var(--heading-color); font-family: var(--heading-font); }
.bkb-sub { text-align: center; color: var(--font-color); opacity: .6; margin: 0; line-height: 1.55; }
/* Heading-size presets — the block editor's Typography panel (config heading_size →
   .bkb-h--{size}). Fluid like the base scale; !important so a preset beats the theme
   chrome's own !important h1–h6 sizes and the hero h1 rule. These four rules MUST
   stay value-identical with the admin twin, content/assets/css/booking-blocks.css
   (guarded by admin's tests/booking_type_scale_parity_test.php). */
.bkb-h--sm { font-size: clamp(1.15rem, 1.02rem + .55vw, 1.45rem) !important; }
.bkb-h--lg { font-size: clamp(1.9rem, 1.56rem + 1.45vw, 2.65rem) !important; }
.bkb-h--xl { font-size: clamp(2.3rem, 1.88rem + 1.8vw, 3.25rem) !important; }
.bkb-h--display { font-size: clamp(2.7rem, 2.14rem + 2.4vw, 3.95rem) !important; line-height: 1.08; }
/* Gradient headings (config heading_gradient → .bkb-hgrad + a preset class, or
   an inline --bkb-hgrad for Custom). The gradient only paints inside @supports
   background-clip:text, so browsers without it keep the solid heading colour
   (Custom also emits its "from" colour as an inline color: fallback). text-shadow
   off: a shadow shows straight through transparent-fill glyphs. Twin rules —
   value-identical with admin booking-blocks.css (guarded by the parity test). */
.bkb-hgrad--sunset { --bkb-hgrad: linear-gradient(100deg, #f97316, #ec4899); }
.bkb-hgrad--ocean { --bkb-hgrad: linear-gradient(100deg, #0284c7, #2dd4bf); }
.bkb-hgrad--violet { --bkb-hgrad: linear-gradient(100deg, #7c3aed, #db2777); }
.bkb-hgrad--gold { --bkb-hgrad: linear-gradient(100deg, #b45309, #f59e0b); }
.bkb-hgrad--forest { --bkb-hgrad: linear-gradient(100deg, #15803d, #84cc16); }
.bkb-hgrad--fade { --bkb-hgrad: linear-gradient(180deg, currentColor 0%, transparent 165%); }
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
    .bkb-hgrad { background-image: var(--bkb-hgrad); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; text-shadow: none; }
}
/* Scrim (config scrim 0–100) — the darkening layer between a block's image
   background (or the hero's photo) and its content; the alpha arrives inline.
   The sibling rule lifts the content above the overlay. */
.bkb-scrim { position: absolute; inset: 0; pointer-events: none; }
.bkb-scrim + .bkb-inner { position: relative; }
.bkb-text { line-height: 1.65; color: var(--bkb-ink, var(--font-color)); }
.bkb-text p { margin: 0 0 1em; }

/* ⚠⚠ THE BLOCK'S OWN INK, AGAINST TWO BARE ELEMENT RULES.
   `p { color: var(--font-color) }` (:147) and `h1, h2, h3, h4, h5, h6 { color:
   var(--heading-color) }` (:66) are ELEMENT selectors, and an element selector beats
   plain INHERITANCE — so a block's authored "Text colour", which arrives here as an
   inherited `color:` from wrapStyle(), stopped at the container and never reached one
   visible character of editor copy. The rich-text editor always wraps a body in <p>.
   Same defect and same fix as `.bkb-hero-cap h1, .bkb-hero-cap p` above; this is that
   fix generalised to every rich-text sink instead of one block.

   ⚠ EVERY FALLBACK IS TODAY'S VALUE, which is what makes a block nobody has coloured
   byte-identical: --font-color for body copy, --heading-color for a heading typed
   inside one. Do NOT collapse either to `inherit` — `.bkb-text` and `.bkb-col` set a
   colour of their own, so `inherit` would hand a heading the body token and quietly
   repaint every published page that uses one.

   ⚠ `.bkb-html` IS DELIBERATELY ABSENT. The Custom HTML block is the escape hatch where
   the photographer writes their own <style>; a rule at this specificity would
   out-specify their own `p { color: … }` and leave them no way back.

   ⚠ `.mode-dark p` / `.mode-light p` (:154, :158) tie on specificity and lose on order.
   Nothing in this app has ever put those classes on <body> and no studio theme defines
   a dark palette (see manage/_chrome.blade.php), so they are dead either way — but the
   block's ink should win over a page-wide mode token regardless. */
.bkb-text p,
.bkb-col p,
.bkb-footer-text p,
.bkb-svc-empty p,
.bkb-block .sc-loc-detail p { color: var(--bkb-ink, var(--font-color)); }
.bkb-text  :is(h1, h2, h3, h4, h5, h6),
.bkb-col   :is(h1, h2, h3, h4, h5, h6),
.bkb-footer-text :is(h1, h2, h3, h4, h5, h6),
.bkb-svc-empty   :is(h1, h2, h3, h4, h5, h6),
.bkb-block .sc-loc-detail :is(h1, h2, h3, h4, h5, h6) { color: var(--bkb-ink, var(--heading-color)); }

/* A picture pasted or inserted into rich text (the widened column toolbar in the
   admin editor) has the photographer's own upload dimensions on it — usually
   thousands of pixels. Without a cap it blows the column out and takes the whole
   row with it. Applies to the Columns block's raw richtext as well, which is the
   surface that gained the Insert picture button. */
.bkb-text img, .bkb-col img { max-width: 100%; height: auto; }
/* Text block set to "Make it a heading" (h2–h4) — read as a heading, not body copy. */
.bkb-text--heading { line-height: 1.2; font-weight: 700; margin: 0 0 .4em; }
.bkb-text--heading p { margin: 0; }

/* ── Named text styles + link styles (richer editing, 2026-09-09) ──────────────────
   The admin rich-text editor applies these as CLASSES on a selection, never as inline
   styles. All three reasons are load-bearing: the look is designed once, here, so a
   photographer picks a ROLE and cannot land on something ugly; Htmlsanitizer's
   allowlist strips the `style` attribute outright, so inline styling would force a
   hole in it to work at all; and a class costs one CSS twin instead of a new
   allow-listed value in both renderers.

   ⚠⚠ SIZED IN `em`, AND MUTED WITH `opacity` ON currentColor RATHER THAN A COLOUR
   TOKEN. That is not a style preference. Every rule in this section is a
   byte-identical TWIN of admin booking-blocks.css (guarded by admin's
   tests/booking_type_scale_parity_test.php), and the two files carry DIFFERENT
   colour tokens for the same idea — --font-color here, --bkb-muted there. A rule
   naming either one CANNOT be a twin, so it would drift the preview off live
   silently. `em` also makes a role nest correctly inside whatever size the block
   itself resolves to. */
.bkb-t--lead { font-size: 1.15em; line-height: 1.55; }
.bkb-t--small { font-size: .875em; }
.bkb-t--fine { font-size: .72em; line-height: 1.5; opacity: .72; }
.bkb-t--caption { font-size: .8em; line-height: 1.45; opacity: .78; }
/* ⚠ `subtle` carries font-weight: 600 ON PURPOSE — do not "tidy" it out. Dropping the
   underline leaves COLOUR as the only cue that a link is a link, which fails WCAG
   1.4.1; the weight is the second, non-colour indicator, and the underline comes
   back on hover and keyboard focus. It is also exactly the pairing that was asked
   for: "no underline on the link — but bold the link". */
.bkb-a--subtle { text-decoration: none; font-weight: 600; }
.bkb-a--subtle:hover, .bkb-a--subtle:focus-visible { text-decoration: underline; }
.bkb-a--dotted { text-decoration: underline dotted; text-underline-offset: .18em; }
.bkb-a--button { display: inline-block; text-decoration: none; padding: .4em .9em; border: 1px solid currentColor; border-radius: 999px; font-weight: 600; line-height: 1.2; }
.bkb-a--button:hover, .bkb-a--button:focus-visible { opacity: .75; }

/* Block-level dials. Phase 4 sets these as custom properties on the <section> through
   wrapStyle(), so every partial inherits them without one blade being touched.

   ⚠⚠ BOTH GATE CLASSES ARE REQUIRED, AND THE LINK ONES ARE SPLIT IN TWO ON PURPOSE.
   A bare `color: var(--bkb-a-color, inherit)` on an <a> is NOT a safe no-op: on a
   link, `inherit` means the BODY ink, so an unset fallback would repaint every
   existing link on every published page the moment this file shipped. Gating on a
   class the renderers add only when the dial is set is what makes "set nothing,
   change nothing" true. Splitting colour from weight matters for the same reason —
   one shared gate would let a photographer who set only the WEIGHT silently lose the
   theme's link colour to `inherit`.
   The four body dials need no such split: they are inherited properties whose
   fallback IS the default, so the gate there is only for selector hygiene —
   rule_of() matches the FIRST `.bkb-block {` in the file, and a second one would
   make the twin comparison ambiguous.

   ⚠⚠ THE TWO :not() SHAPES ARE DIFFERENT ON PURPOSE, AND NEITHER IS TIDINESS.
   A block-level rule is `.class a` — one class plus a type, (0,1,1) — while a
   per-link role is `.bkb-a--dotted`, (0,1,0). The block default therefore BEATS the
   per-link choice unless the link is excluded, which would make the Link dialog
   (the whole answer to "two treatments in one block") lose to a dial.
     · WEIGHT and DECORATION are the axis the roles themselves set, so those rules
       exclude a link that has chosen a role: the per-link choice wins.
     · COLOUR is not set by any role, so there is nothing to lose — a `subtle` link
       still takes the block's link colour, which is what a photographer expects
       after setting one.
   BOTH exclude buttons: `.bkb-btn`'s label colour and weight belong to the button's
   own treatment (and it carries its own colour controls), so a Links dial that
   repainted a solid button's label would be free to destroy its contrast. */
.bkb-tdial { font-size: var(--bkb-body-size, inherit); line-height: var(--bkb-body-lh, inherit); font-weight: var(--bkb-body-weight, inherit); letter-spacing: var(--bkb-body-ls, normal); }
.bkb-adial-c a:not([class*="bkb-btn"]) { color: var(--bkb-a-color); }
.bkb-adial-c a:not([class*="bkb-btn"]):hover, .bkb-adial-c a:not([class*="bkb-btn"]):focus-visible { color: var(--bkb-a-hover, var(--bkb-a-color)); }
.bkb-adial-w a:not([class*="bkb-btn"]):not([class*="bkb-a--"]) { font-weight: var(--bkb-a-weight); }
/* Block-level link STYLE — the same treatments as the per-link roles above, applied
   to every plain link in the block.
   ⚠ `subtle` carries NO font-weight here, unlike .bkb-a--subtle. Dropping the
   underline still needs a second, non-colour indicator (WCAG 1.4.1), but at block
   level it arrives as --bkb-a-weight: BOTH renderers default the link weight to
   600 when the style is `subtle` and no weight was chosen. Putting the 600 in this
   rule instead would out-specify the weight dial, so a photographer who picked
   "No underline" and then "Normal" would keep getting bold with no way back. */
.bkb-adial-s--underline a:not([class*="bkb-btn"]):not([class*="bkb-a--"]) { text-decoration: underline; }
.bkb-adial-s--subtle a:not([class*="bkb-btn"]):not([class*="bkb-a--"]) { text-decoration: none; }
.bkb-adial-s--subtle a:not([class*="bkb-btn"]):not([class*="bkb-a--"]):hover, .bkb-adial-s--subtle a:not([class*="bkb-btn"]):not([class*="bkb-a--"]):focus-visible { text-decoration: underline; }
.bkb-adial-s--dotted a:not([class*="bkb-btn"]):not([class*="bkb-a--"]) { text-decoration: underline dotted; text-underline-offset: .18em; }

.bkb-live { border: 1px dashed var(--border-muted, rgba(128,128,128,.25)); border-radius: 12px; padding: 22px; text-align: center; color: var(--font-color); opacity: .6; }
.bkb-hero { position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center; }
.bkb-hero-img { position: absolute; inset: 0; width: 100%; height: 100%; }
.bkb-hero-ph { width: 100%; min-height: inherit; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg,#dfe6ee,#c9d4e0); color: #6b7280; }
.bkb-hero-cap { position: relative; z-index: 1; color: #fff; text-shadow: 0 2px 12px rgba(0,0,0,.45); padding: 20px; }
/* Inherit the caption colour (white default, or the block's font colour when set) so the
   storefront theme's own h1/p colour can't override an otherwise-unreadable hero heading. */
.bkb-hero-cap h1, .bkb-hero-cap p { color: inherit; }
.bkb-hero-cap h1 { font-size: clamp(2.6rem, 2.2rem + 1.6vw, 3.4rem); margin: 0 0 .2em; font-family: var(--heading-font); }
/* Natural-height hero: full width, the image's own aspect ratio, no fixed box / crop.
   The image flows in-block (not the absolute fill of the default banner); the caption
   overlays it, vertically centered, with its inline text-align controlling horizontal. */
.bkb-hero--natural { display: block; overflow: visible; min-height: 0; }
.bkb-hero--natural .bkb-hero-img { position: static; inset: auto; height: auto; object-fit: initial; display: block; }
.bkb-hero--natural .bkb-hero-cap { position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%); }
/* location_info split card: placeholder shown when no hero image is set (the .sc-*
   card rules at 3947-3983 are reused verbatim by locations/blocks/_location_info). */
.bkb-loc-hero-ph { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg,#e9edf2,#d3dbe4); color: rgba(127,127,127,.6); font-size: 2rem; }
.bkb-img img { max-width: 100%; height: auto; display: inline-block; }
.bkb-img--full { padding: 0; }
.bkb-img--full img { width: 100%; }
.bkb-img--round img { border-radius: 16px; }
.bkb-img-ph { border: 1px dashed var(--border-muted, rgba(128,128,128,.25)); border-radius: 12px; padding: 40px; text-align: center; color: var(--font-color); opacity: .55; }
/* selected service image — the picture of the service the customer chose, carried into an
   interior step. ONE axis: a width slider read as a PERCENTAGE OF THE BOOKING CARD.
   --bkb-ssi-base is that card: 640px, the width the booking card sits at inside
   .bk-content-col and the width the admin builder's step mirror draws. So the block's
   default of 100% lines the picture up with the card the customer is already looking at
   rather than floating narrower than it, and max-width holds the top end at the block's
   own column. Mirrors booking-blocks.css so the preview and the live page agree. No
   placeholder rule here on purpose: with no picture the blade renders nothing at all.

   ⚠ THE NAMED SCALE (.bkb-ssi--small/medium/large/full — max-width caps of 180 / 340 /
   560 / the full column) WAS RETIRED 2026-08-28 and the blade emits no modifier class any
   more. Blocks saved under it carry `image_size` and no `image_width`, and
   SelectedServiceImage::width() maps them to 25 / 47 / 78 / 160 so an already-published
   page renders exactly as it did. Do not re-add a rule for a modifier class: a legacy
   block would then take BOTH widths, and the cap would win over the slider silently. */
.bkb-ssi { --bkb-ssi-base: 640px; }
.bkb-ssi img { width: calc(var(--bkb-ssi-base) * var(--bkb-ssi-w, 100) / 100);
    max-width: 100%; height: auto; display: inline-block; border-radius: 14px; }
.bkb-ssi-cap { margin-top: .6em; font-weight: 700; color: var(--font-color); }
.bkb-btn { display: inline-block; text-decoration: none; font-weight: 700; border-radius: 999px; background: var(--accent-orange); color: #fff; padding: 12px 28px; }
.bkb-btn--outline { background: transparent; border: 2px solid var(--accent-orange); color: var(--accent-orange); }
.bkb-btn--link { background: transparent; color: var(--accent-orange); padding: 6px 4px; border-radius: 0; }
.bkb-btn--sm { padding: 8px 18px; font-size: .9rem; }
.bkb-btn--lg { padding: 16px 40px; font-size: 1.1rem; }
.bkb-btn--full { display: block; text-align: center; }
/* Button row (the button block is a ≤4 repeater): row/stack + alignment as
   allow-listed class tokens, gap inline (int-clamped). Gradient buttons reuse
   the .bkb-hgrad--* palette — the modifier class only sets the custom property,
   and the var() fallback is the violet preset. Full width: row buttons share
   the line equally; stacked buttons each stretch. Twin rules — value-identical
   with the admin builder's booking-blocks.css (guarded by the parity test). */
.bkb-btns { display: flex; flex-wrap: wrap; align-items: center; }
.bkb-btns--row { flex-direction: row; }
.bkb-btns--stack { flex-direction: column; }
.bkb-btns--left { justify-content: flex-start; }
.bkb-btns--center { justify-content: center; }
.bkb-btns--right { justify-content: flex-end; }
.bkb-btns--stack.bkb-btns--left { align-items: flex-start; }
.bkb-btns--stack.bkb-btns--center { align-items: center; }
.bkb-btns--stack.bkb-btns--right { align-items: flex-end; }
.bkb-btns--full .bkb-btn { flex: 1 1 0; text-align: center; }
.bkb-btns--stack.bkb-btns--full .bkb-btn { flex: none; align-self: stretch; }
.bkb-btn--gradient { background: var(--bkb-hgrad, linear-gradient(100deg, #7c3aed, #db2777)); color: #fff; border: 0; }
/* <420px: a side-by-side row collapses to stacked full-width buttons. */
@media (max-width: 419.98px) {
    .bkb-btns--row { flex-direction: column; }
    .bkb-btns--row .bkb-btn { flex: none; align-self: stretch; text-align: center; }
}
/* columns — the Columns block's own flex row (NOT the .bkb-gcols card grid).
   Mirrors content/assets/css/booking-blocks.css so preview == live page.
   flex-basis 220px + wrap keeps columns side by side until too narrow, then wraps
   (stacks on phones); min-width:0 lets long text/links wrap inside a column. */
.bkb-cols { display: flex; flex-wrap: wrap; align-items: flex-start; }
/* ⚠ The second container that sets a colour of its own, so it needs the same --bkb-ink
   read as `.bkb-text` — a Columns block's "Text colour" was dead for the same reason. */
.bkb-col { flex: 1 1 220px; min-width: 0; box-sizing: border-box; overflow-wrap: break-word; word-break: break-word; color: var(--bkb-ink, var(--font-color)); }
.bkb-cols--vtop    { align-items: flex-start; }
.bkb-cols--vmiddle { align-items: center; }
.bkb-cols--vbottom { align-items: flex-end; }
.bkb-cols--divided > .bkb-col + .bkb-col {
    border-left: 1px solid var(--bkb-col-divider, rgba(128,128,128,.25));
    padding-left: 20px;
}
@media (max-width: 575.98px) {
    .bkb-cols--divided > .bkb-col + .bkb-col { border-left: 0; padding-left: 0; }
}
/* Unequal column widths (2026-08-27) — 2 columns only; the class is emitted only
   when the resolver matched an allow-listed pair, so an unknown ratio silently
   stays equal rather than shipping a broken row.
   ⚠ flex-basis has to become 0 here. The base .bkb-col is `flex: 1 1 220px`, and a
   220px floor eats most of a phone-to-tablet row before growth is shared out, so a
   33/67 laid out as roughly 41/59 — close enough to look like the setting had no
   effect. With basis 0 the grow numbers ARE the ratio. That means no wrap trigger
   left, so nowrap is deliberate and the phone breakpoint restores both.
   Twin rules — value-identical with admin booking-blocks.css (parity test). */
.bkb-cols--ratio { flex-wrap: nowrap; }
.bkb-cols--ratio > .bkb-col { flex-basis: 0%; }
.bkb-cols--ratio > .bkb-col:nth-child(1) { flex-grow: var(--bkb-c1, 1); }
.bkb-cols--ratio > .bkb-col:nth-child(2) { flex-grow: var(--bkb-c2, 1); }
@media (max-width: 575.98px) {
    .bkb-cols--ratio { flex-wrap: wrap; }
    .bkb-cols--ratio > .bkb-col { flex-basis: 220px; }
}

/* image + text — one picture beside one column of copy. Same basis-0 reasoning as
   .bkb-cols--ratio above: the grow pair is the width ratio, so it has to be the
   only thing deciding the split. The ratio is ONE stored number (the image's
   share); both sides derive the body's as 100 - it, so the admin preview and this
   page cannot normalise a non-summing pair differently.
   Twin rules — value-identical with admin booking-blocks.css (parity test). */
.bkb-mt { display: flex; align-items: center; }
.bkb-mt--rev { flex-direction: row-reverse; }
.bkb-mt--vtop { align-items: flex-start; }
.bkb-mt--vmiddle { align-items: center; }
.bkb-mt--vbottom { align-items: flex-end; }
.bkb-mt__media { flex-grow: var(--bkb-mt-media, 50); flex-shrink: 1; flex-basis: 0%; min-width: 0; }
.bkb-mt__body { flex-grow: var(--bkb-mt-body, 50); flex-shrink: 1; flex-basis: 0%; min-width: 0; overflow-wrap: break-word; }
.bkb-mt__media img { display: block; width: 100%; height: auto; }
.bkb-mt__media--round img, .bkb-mt__media--round .bkb-img-ph { border-radius: 16px; }
/* The shared header is built to open a full-width band, so its 1.6rem gap and
   680px cap both read wrong stacked against a picture in a half-width column. */
.bkb-mt__body .bkb-sec-head { max-width: none; margin-bottom: .9rem; }
.bkb-mt__cta { margin-top: 1.1em; }
@media (max-width: 639.98px) {
    /* Stacked, and the picture leads in BOTH directions — column, never
       column-reverse: "image on the right" is a wide-screen composition, and
       honouring it on a phone buries the photo under the copy. */
    .bkb-mt, .bkb-mt--rev { flex-direction: column; align-items: stretch; }
    .bkb-mt__media, .bkb-mt__body { flex-basis: auto; }
}
.bkb-video-wrap { position: relative; display: inline-block; }
.bkb-video img { max-width: 100%; border-radius: 12px; }
.bkb-play { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 2.5rem; text-shadow: 0 2px 10px rgba(0,0,0,.5); }
.bkb-price-graphic { text-align: center; }
.bkb-price-graphic img { max-width: 100%; height: auto; }
.bkb-badges { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; }
.bkb-badge { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; color: var(--font-color); opacity: .85; }
.bkb-badge i { color: var(--accent-orange); }
.bkb-footer-img img { width: 100%; display: block; }
/* ⚠ THE PARTNER-LINK WRAPPER, AND IT MUST NOT BECOME A LAYOUT BOX. When a partner
   points their banner or footer at their own page, the artwork is wrapped in an
   <a>. An inline anchor would add a baseline gap under the picture and, worse,
   nothing here may establish a containing block: .bkb-hero-img is absolutely
   positioned against .bkb-hero, so giving this anchor a position would re-anchor
   the image to a zero-height inline box and collapse the banner. display:block +
   position:static keeps the linked hero pixel-identical to the unlinked one. */
.bkb-hero-link { display: block; position: static; }
.bkb-footer-img a { display: block; }

/* ⚠ NO `color` HERE, DELIBERATELY, AND IT IS A BUG FIX — corrected 2026-09-09.
   This pinned --font-color and admin's twin pinned --bkb-muted, and BOTH are the
   THEME's ink, not the block's. So the footer's own "Text colour" control has never
   reached its text on either surface: the photographer picked a colour, the preview
   and the live page both ignored it, and nothing was red. Inheriting is what makes
   that control real (same defect and same fix as .bkb-text in _text.blade.php).
   `opacity` keeps the muted, fine-print reading without spending the ink control to
   get it, and it is what makes this rule a byte-identical twin — the two files had
   no shared way to say "muted" before. Joined to $twinRules. */
.bkb-footer-text { padding: 16px; opacity: .7; }
.bkb-loc-card { background: var(--bg-light-secondary, #fff); border: 1px solid var(--border-muted, rgba(128,128,128,.2)); border-radius: 14px; padding: 20px; }
.bkb-loc-row { padding: 6px 0; border-bottom: 1px solid var(--border-muted, rgba(128,128,128,.15)); }
.bkb-loc-row:last-child { border-bottom: 0; }
.bkb-map-ph { background: linear-gradient(135deg,#e9edf2,#d3dbe4); border-radius: 12px; min-height: 160px; display: flex; align-items: center; justify-content: center; color: #6b7280; margin-bottom: 14px; }
[data-anim] { animation: bkb-fade .5s ease both; }
[data-anim="fade-up"] { animation-name: bkb-fade-up; }
[data-anim="fade-down"] { animation-name: bkb-fade-down; }
[data-anim="fade-left"] { animation-name: bkb-fade-left; }
[data-anim="fade-right"] { animation-name: bkb-fade-right; }
[data-anim="zoom"] { animation-name: bkb-zoom; }
@keyframes bkb-fade { from { opacity: 0; } }
@keyframes bkb-fade-up { from { opacity: 0; transform: translateY(24px); } }
@keyframes bkb-fade-down { from { opacity: 0; transform: translateY(-24px); } }
@keyframes bkb-fade-left { from { opacity: 0; transform: translateX(24px); } }
@keyframes bkb-fade-right { from { opacity: 0; transform: translateX(-24px); } }
@keyframes bkb-zoom { from { opacity: 0; transform: scale(.94); } }
@media (prefers-reduced-motion: reduce) { [data-anim] { animation: none; } }
/* live-data block layouts (Phase 6): hours list, package price list, map */
.bkb-hours-row, .bkb-price-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--border-muted, rgba(128,128,128,.15)); }
.bkb-hours-row:last-child, .bkb-price-row:last-child { border-bottom: 0; }
.bkb-hours-date, .bkb-price-name { font-weight: 600; color: var(--heading-color); }
.bkb-hours-time { color: var(--font-color); opacity: .8; }
.bkb-price-amt { font-weight: 700; color: var(--accent-orange); white-space: nowrap; }
.bkb-map { margin-bottom: 14px; }

/* ───────────────────────────────────────────────────────────────────────
   Account HOME-page sections — feature_cards · how_it_works · gallery_strip
   location_finder · manage_strip · featured_services
   Ported from the admin editor preview (content/assets/css/booking-blocks.css
   §"Account HOME-page sections"), with the preview's --bkb-* tokens translated
   to the storefront theme so a band picks up this account's branding. Structure,
   class names and breakpoints are kept identical so preview == live page.
   Widths come from .bkb-inner (the wrapper's own max-width), not from a token.
   ─────────────────────────────────────────────────────────────────────── */

/* Shared column grid for the card bands. Deliberately NOT .bkb-cols--*:
   .bkb-cols is the Columns block's own flex row and must stay untouched. */
.bkb-gcols--2, .bkb-gcols--3, .bkb-gcols--4 { display: grid; gap: 20px; margin: 0 auto; }
.bkb-gcols--2 { grid-template-columns: repeat(2, 1fr); }
.bkb-gcols--3 { grid-template-columns: repeat(3, 1fr); }
.bkb-gcols--4 { grid-template-columns: repeat(4, 1fr); }

/* 1 — Feature cards */
.bkb-featcard { background: var(--bg-light-secondary, #fff); border: 1px solid var(--border-muted, rgba(128,128,128,.2)); border-radius: 16px; padding: 26px 22px; }
.bkb-featcard-icon { display: inline-flex; align-items: center; justify-content: center; width: 52px; height: 52px; border-radius: 50%; background: rgba(128,128,128,.12); color: var(--accent-orange); font-size: 1.35rem; margin-bottom: 14px; }
.bkb-featcard h3 { font-size: clamp(1.05rem, .95rem + .4vw, 1.25rem); font-weight: 700; color: var(--heading-color); margin: 0 0 .4em; }
.bkb-featcard p  { font-size: .88rem; line-height: 1.55; color: var(--font-color); opacity: .7; margin: 0; }

/* 2 — How it works */
.bkb-step { position: relative; background: var(--bg-light-secondary, #fff); border: 1px solid var(--border-muted, rgba(128,128,128,.2)); border-radius: 16px; padding: 30px 22px 24px; text-align: center; }
.bkb-step-num { position: absolute; top: -16px; left: 50%; transform: translateX(-50%); width: 34px; height: 34px; border-radius: 50%; background: var(--accent-orange); color: #fff; font-weight: 800; font-size: .9rem; display: flex; align-items: center; justify-content: center; }
.bkb-step-icon { display: block; font-size: 1.5rem; color: var(--accent-orange); margin-bottom: 10px; }
.bkb-step h3 { font-size: clamp(1rem, .9rem + .4vw, 1.2rem); font-weight: 700; color: var(--heading-color); margin: 0 0 .4em; }
.bkb-step p  { font-size: .86rem; line-height: 1.55; color: var(--font-color); opacity: .7; margin: 0; }

/* 2b — Feature-callout styling (Phase 5). CSS TWINS with the admin editor's
   booking-blocks.css — every rule body byte-identical, same order (the admin
   parity test pins this). Neutral greys / currentColor / literal shadows keep
   the bodies side-agnostic; the gradient pieces consume var(--bkb-hgrad, …)
   exactly like .bkb-btn--gradient, so '' is the violet preset. */
.bkb-featcard-icon--sm { width: 40px; height: 40px; font-size: 1.05rem; }
.bkb-featcard-icon--lg { width: 68px; height: 68px; font-size: 1.8rem; }
.bkb-featcard-icon--square { border-radius: 14px; }
.bkb-featcard-icon--ring { background: transparent; border: 2px solid currentColor; }
.bkb-featcard-icon--gradient-tile { background: var(--bkb-hgrad, linear-gradient(100deg, #7c3aed, #db2777)); color: #fff; border-radius: 14px; }
.bkb-featcard-icon--bare { width: auto; height: auto; background: transparent; border-radius: 0; }
/* Card styles — one token class works on .bkb-featcard AND .bkb-step. */
.bkb-callout--filled { background: rgba(128,128,128,.1); border-color: transparent; }
.bkb-callout--bordered { background: transparent; border: 2px solid rgba(128,128,128,.4); }
.bkb-callout--top-accent { position: relative; }
.bkb-callout--top-accent::before { content: ""; position: absolute; top: 0; left: 18px; right: 18px; height: 4px; border-radius: 0 0 4px 4px; background: var(--bkb-hgrad, linear-gradient(100deg, #7c3aed, #db2777)); }
.bkb-callout--elevated { border-color: transparent; box-shadow: 0 8px 32px rgba(0,0,0,.12); }
/* Item layouts — left puts the icon beside a body wrapper; inline runs it into
   the title line. Default (no class) is today's stacked look, untouched. */
.bkb-callout--left { display: flex; align-items: flex-start; gap: 16px; text-align: left; }
.bkb-callout--left .bkb-featcard-icon, .bkb-callout--left .bkb-step-icon { flex: 0 0 auto; margin-bottom: 0; }
.bkb-callout-body { flex: 1 1 auto; min-width: 0; }
.bkb-callout--inline .bkb-featcard-icon { display: inline-flex; vertical-align: middle; width: 40px; height: 40px; font-size: 1.05rem; margin: 0 10px 0 0; }
.bkb-callout--inline .bkb-step-icon { display: inline; vertical-align: middle; font-size: 1.2rem; margin: 0 8px 0 0; }
.bkb-callout--inline h3 { display: inline; vertical-align: middle; }
.bkb-callout--inline p { margin-top: .7em; }

/* 3 — Photo strip */
.bkb-gallery { margin: 0 auto; }
.bkb-gallery--scroll { display: flex; gap: 12px; overflow-x: auto; padding-bottom: 8px; }
.bkb-gallery--scroll .bkb-gallery-thumb { flex: 0 0 auto; width: auto; }
.bkb-gallery--grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
.bkb-gallery--grid .bkb-gallery-thumb { width: 100%; aspect-ratio: 4 / 3; height: auto; }
.bkb-gallery-thumb { object-fit: cover; display: block; background: var(--border-muted, rgba(128,128,128,.2)); }
.bkb-gallery--round .bkb-gallery-thumb { border-radius: 12px; }

/* 3b — Testimonials
   CSS TWINS with the admin editor's booking-blocks.css from .bkb-quote-mark
   down — every rule body byte-identical, same order (the admin parity test
   pins this). The two rules ABOVE that line are the deliberate exceptions:
   they carry surface tokens, which are the storefront theme's here and the
   editor's --bkb-* over there.
   The carousel is scroll-snap on purpose — a JS slider would need a second
   copy of that JS in the admin preview and a drift surface between the two,
   to do what a browser already does for a scrollable strip. */
.bkb-quotes { margin: 0 auto; }
.bkb-quote { position: relative; background: var(--bg-light-secondary, #fff); border: 1px solid var(--border-muted, rgba(128,128,128,.2)); border-radius: 16px; padding: 26px 22px; margin: 0; display: flex; flex-direction: column; gap: 12px; }
.bkb-quote-mark { font-family: Georgia, "Times New Roman", serif; font-size: 3rem; line-height: .6; color: currentColor; opacity: .3; }
.bkb-quote-stars { display: inline-flex; gap: 3px; font-size: .9rem; color: #f59e0b; }
.bkb-quote-star--off { opacity: .35; }
.bkb-quote-txt { font-size: .95rem; line-height: 1.6; margin: 0; quotes: none; }
.bkb-quote-who { display: flex; align-items: center; gap: 12px; margin-top: auto; padding-top: 2px; }
.bkb-quote-face { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; background: rgba(128,128,128,.2); }
.bkb-quote-who-txt { display: flex; flex-direction: column; min-width: 0; }
.bkb-quote-name { font-style: normal; font-weight: 700; font-size: .88rem; }
.bkb-quote-detail { font-size: .8rem; opacity: .7; }
.bkb-quotes--carousel { display: flex; gap: 20px; overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: 10px; }
.bkb-quotes--carousel .bkb-quote { flex: 0 0 min(86%, 340px); scroll-snap-align: start; }
.bkb-quotes--carousel:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
.bkb-quotes--spotlight { display: flex; flex-direction: column; gap: 26px; }
.bkb-quotes--spotlight .bkb-quote { background: none; border: 0; padding: 6px 0; }
.bkb-quotes--spotlight .bkb-quote-txt { font-size: clamp(1.1rem, .95rem + .8vw, 1.5rem); line-height: 1.45; }
.bkb-quotes--spotlight .bkb-quote-mark { font-size: 4rem; }
.bkb-quotes--a-left { text-align: left; }
.bkb-quotes--a-center { text-align: center; }
.bkb-quotes--a-right { text-align: right; }
.bkb-quotes--a-center .bkb-quote { align-items: center; }
.bkb-quotes--a-right .bkb-quote { align-items: flex-end; }
.bkb-quotes--a-center .bkb-quote-who { justify-content: center; }
.bkb-quotes--a-right .bkb-quote-who { justify-content: flex-end; }
@media (prefers-reduced-motion: no-preference) { .bkb-quotes--carousel { scroll-behavior: smooth; } }
/* The star rating's text equivalent. The admin preview iframe carries this same
   rule in booking-blocks.css; the storefront had no bkb-namespaced one, and
   Bootstrap's .visually-hidden is not loaded on every booking layout, so the
   sentence would otherwise print beside the stars. */
.bkb-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }

/* ==========================================================================
   LOCATION CARDS — the shared system behind all FOUR card surfaces
   ..........................................................................
     .bkb-locfind-card   Location Finder block, map-off path   (this file, below)
     .bk-locdir-card     /locations plain directory grid       (this file, below)
     .bk-shop            store-locator scroll list             (this file, below)
     .bk-loc-card        legacy home "Our Locations" grid      (booking-landing.css)

   Four surfaces draw a location. Everything that is ABOUT a location rather
   than about a layout — the glass, the status tone, the logo chip, the blurb —
   is defined once here and consumed by all four, because four copies of "which
   colour is 'Closed for the season'" is four chances for one of them to drift.
   The layout of each grid stays with that grid.

   ⚠ GLASS HERE IS NOT ADMIN'S GLASS, and it cannot be copied from it. Admin
   owns both of its backgrounds, so a hardcoded rgba(255,255,255,.82) sheet is
   safe there. BYP owns neither: a studio picks one of 24 palette files (several
   genuinely dark) and may ALSO upload a background photo the layout paints
   cover/fixed behind every band. A white sheet greys out on theme-dark and
   muddies over a photograph.

   So the surface is mixed FROM the studio's own tokens — --bg-light-secondary
   is whatever colour that palette calls a card — and the mix stops at an
   opacity FLOOR, so a photographer's background reads through as a tint and
   never competes with the text sitting on it. color-mix() is the upgrade, not
   the baseline: the plain declarations are what a browser without it gets, and
   they are the solid token, so nothing depends on the mix landing.
   ========================================================================== */
:root {
    --bk-loc-surface:    var(--bg-light-secondary, #fff);
    --bk-loc-surface-hi: var(--bg-light-secondary, #fff);
    --bk-loc-line:       var(--border-muted, rgba(128,128,128,.2));
    --bk-loc-chip:       rgba(128,128,128,.14);
    --bk-loc-lift:       0 10px 30px var(--soft-shadow, rgba(0,0,0,.18));
    /* The card's RESTING shadow — the lift is what it grows into on hover, and a
       card with no resting shadow at all is what made the untouched band read as
       flat. Deliberately a fraction of --bk-loc-lift so the hover still reads as
       a change; neutral rgba rather than the studio palette, because a shadow is
       depth and must not become a second accent colour. */
    --bk-loc-rest:       0 1px 2px rgba(0,0,0,.04), 0 6px 18px rgba(0,0,0,.07);
    --bk-loc-blur:       none;
}
@supports (color: color-mix(in srgb, red, blue)) {
    :root {
        /* 88% is the floor, not a taste call: below it the background photo
           starts reading through the body copy rather than behind it. */
        --bk-loc-surface:    color-mix(in srgb, var(--bg-light-secondary, #fff) 88%, transparent);
        --bk-loc-surface-hi: color-mix(in srgb, var(--bg-light-secondary, #fff) 97%, transparent);
        --bk-loc-line:       color-mix(in srgb, var(--font-color, #333) 15%, transparent);
        --bk-loc-chip:       color-mix(in srgb, var(--font-color, #333) 9%, transparent);
        --bk-loc-blur:       blur(14px) saturate(1.08);
    }
}

/* --- Status tone ---------------------------------------------------------
   LocationService::statusBadge() has already decided WHICH kind of closed this
   is — limited / soon / closed, or '' when the status carries no customer
   meaning and the calendar's open/closed stands. The view adds the class; it
   never re-derives the mapping. The WORD is always rendered beside the colour,
   so colour is never the only signal (WCAG 1.4.1).

   The three status tones are FIXED colours rather than theme tokens, on
   purpose: they carry meaning a studio palette must not be able to repaint,
   and each is dark enough to hold 4.5:1 against the white ink it is paired
   with on any background. `open` is the deliberate exception — "we are open"
   is brand, not status semantics, so it keeps the studio's own accent green. */
.bk-tone           { --bk-tone-bg: #475569; --bk-tone-ink: #fff; }
.bk-tone--open     { --bk-tone-bg: var(--accent-green, #2e7d32); }
.bk-tone--limited  { --bk-tone-bg: #b45309; }
.bk-tone--soon     { --bk-tone-bg: #1d4ed8; }
.bk-tone--closed   { --bk-tone-bg: #475569; }
/* ⚠ The dot follows the INK, not a fixed white. A studio that picks its own pill
   colour may well pick a pale one, and _loc_badge then sets --bk-tone-ink dark —
   at which point a hardcoded white dot vanishes into the pill. The fallback is
   the white it has always been, so every preset tone renders byte-identically. */
.bk-tone-dot {
    display: inline-block; width: 6px; height: 6px; border-radius: 50%;
    background: var(--bk-tone-dot, rgba(255,255,255,.85)); margin-right: 5px; vertical-align: middle;
}

/* --- The picture ---------------------------------------------------------
   `card_media` defaults to `icon`, so this element appeared on ~258 live
   accounts the day it shipped. That is why there is no placeholder anywhere
   below: a location with no artwork renders NO element at all (see
   partials/_loc_media), not an empty chip and not a reserved gap. A grey hole
   on every card of every account that never uploaded a logo is a worse
   regression than the ragged row a missing picture leaves. */
.bk-locmedia { flex: 0 0 auto; }
.bk-locmedia--icon {
    width: 46px; height: 46px; border-radius: 12px; overflow: hidden;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--bk-loc-chip); border: 1px solid var(--bk-loc-line);
}
.bk-locmedia--icon .bk-locmedia-img { width: 100%; height: 100%; object-fit: contain; padding: 5px; display: block; }
.bk-locmedia--photo {
    display: block; width: 100%; aspect-ratio: 16 / 9; overflow: hidden;
    border-radius: 12px; margin-bottom: 14px; background: var(--bk-loc-chip);
}
.bk-locmedia--photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The dark logo follows the STUDIO theme, not the operating system: the studio
   picked the palette, so it decides which artwork reads. Both images render and
   CSS chooses, keyed off <body data-preferred-theme> — prefers-color-scheme
   settles only the `auto` case. The partial emits one <img> when
   LocationService resolved the dark URL to the light one (its documented
   fallback), so the common account ships no second request. */
.bk-locmedia-img--dark { display: none; }
body[data-preferred-theme="dark"] .bk-locmedia-img--light { display: none; }
body[data-preferred-theme="dark"] .bk-locmedia-img--dark  { display: block; }
@media (prefers-color-scheme: dark) {
    body[data-preferred-theme="auto"] .bk-locmedia-img--light { display: none; }
    body[data-preferred-theme="auto"] .bk-locmedia-img--dark  { display: block; }
}

/* --- The blurb -----------------------------------------------------------
   Already resolved, already strip_tags'd and already ≤300 chars by the time it
   reaches a view (BookingPageContent::cardBlurbs). Clamped to three lines so
   one wordy location cannot set the height of a whole grid row. */
.bk-locblurb {
    margin: 10px 0 0; font-size: calc(.86rem * var(--bkb-locbody, 1)); line-height: 1.55;
    color: var(--font-color, #444); opacity: .82;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
    overflow: hidden;
}

/* --- Next available ------------------------------------------------------
   One line per card, from partials/_loc_next, on all four card surfaces. The
   two states differ in WORDING first — "Next available …" against "Not
   currently accepting reservations" — so the colour below is reinforcement,
   never the signal (WCAG 1.4.1).

   `--open` uses the studio's own accent green for the same reason the open
   status pill does: a date you can book is brand, not a warning. `--none`
   deliberately does NOT go red. It is the ordinary state of every location
   between seasons — 202 of scenetobelieve's 202 today — and a grid of red
   cards reads as a site-wide fault rather than as a calendar that has not
   opened yet. It stays the muted body ink and lets the closed status pill
   carry the alarm, if there is one to carry.

   Never clamped and never truncated: this is one short line, and a customer
   scanning a directory for the soonest session is reading exactly this. */
.bk-locnext {
    display: flex; align-items: baseline; gap: 7px;
    margin: 9px 0 0; font-size: calc(.84rem * var(--bkb-locbody, 1)); line-height: 1.45;
    color: var(--font-color, #444);
}
.bk-locnext i { flex: 0 0 auto; font-size: .92em; }
.bk-locnext--open  { color: var(--accent-green, #2e7d32); }
.bk-locnext--open .bk-locnext-lead { color: var(--font-color, #444); opacity: .72; }
.bk-locnext--open .bk-locnext-when { font-weight: 600; }
.bk-locnext--none  { opacity: .68; }

/* --- /locations, map-off ------------------------------------------------
   The plain directory grid. It used to borrow .location-card — the 456px
   fixed-height card the booking flow and the auth pages use — which was
   accidental reuse: nothing about a directory tile wants that geometry, and
   every rule had to be overridden inline to get a grid out of it. It now has
   its own class on the Bootstrap .card base (framework base, semantic
   modifier) and takes the same glass, tone and media as the other three. */
.bk-locdir-link { display: block; height: 100%; text-decoration: none; color: inherit; }
.bk-locdir-card {
    height: 100%;
    background: var(--bk-loc-surface); -webkit-backdrop-filter: var(--bk-loc-blur);
    backdrop-filter: var(--bk-loc-blur);
    border: 1px solid var(--bk-loc-line); border-radius: 18px;
    border-left: 4px solid var(--accent-orange);
    color: var(--font-color);
    transition: transform .18s ease, box-shadow .18s ease, background .18s ease;
}
/* Which kind of closed, on the rail — the same signal the finder grid and the
   home grid carry, so a photographer with both surfaces published sees one
   convention rather than three. */
.bk-locdir-card.is-closed       { border-left-color: #475569; }
.bk-locdir-card.is-tone-limited { border-left-color: #b45309; }
.bk-locdir-card.is-tone-soon    { border-left-color: #1d4ed8; }
.bk-locdir-link:hover .bk-locdir-card,
.bk-locdir-link:focus-visible .bk-locdir-card {
    transform: translateY(-3px); box-shadow: var(--bk-loc-lift); background: var(--bk-loc-surface-hi);
}
.bk-locdir-link:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 3px; border-radius: 18px; }
@media (prefers-reduced-motion: reduce) {
    .bk-locdir-card { transition: none; }
    .bk-locdir-link:hover .bk-locdir-card, .bk-locdir-link:focus-visible .bk-locdir-card { transform: none; }
}
.bk-locdir-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 6px; }
.bk-locdir-headtext { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
.bk-locdir-name { font-size: 1.02rem; font-weight: 700; margin: 0; color: var(--heading-color); font-family: var(--heading-font); }
.bk-locdir-badge { flex-shrink: 0; font-size: .68rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; padding: 4px 10px; border-radius: 999px; white-space: nowrap; background: var(--bk-tone-bg); color: var(--bk-tone-ink); }
.bk-locdir-line { font-size: .84rem; color: var(--font-color); opacity: .7; }
/* Service chips — same treatment as .bk-loc-tag on the home grid, so a customer
   who lands on /locations instead of the home page reads the same card. */
.bk-locdir-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: .5rem; }
.bk-locdir-tag {
    font-size: .7rem; font-weight: 600; padding: 2px 8px; border-radius: 6px;
    background: color-mix(in srgb, var(--bk-accent) 12%, transparent);
    color: var(--bk-accent); white-space: nowrap;
}

/* 4 — Location finder. The map path renders the shared store locator, which brings
   its own styling; everything below is the no-map card grid. */
/* The filter row is part of the same glass surface as the cards it filters —
   one panel, so it does not read as chrome floating above a themed band. */
.bkb-locfind-bar {
    margin: 0 auto 20px; display: flex; flex-wrap: wrap; gap: 12px; align-items: center;
    background: var(--bk-loc-surface); -webkit-backdrop-filter: var(--bk-loc-blur);
    backdrop-filter: var(--bk-loc-blur); border: 1px solid var(--bk-loc-line);
    border-radius: 18px; padding: 12px 14px;
}
.bkb-locfind-search { flex: 1 1 240px; display: flex; align-items: center; gap: 8px; border: 1px solid var(--bk-loc-line); border-radius: 999px; padding: 9px 16px; background: var(--bk-loc-surface-hi); }
.bkb-locfind-search i { color: var(--font-color); opacity: .5; }
/* The preview draws the search box as static text; live it is a real input, which
   must sit flush inside the pill rather than painting its own box on top of it. */
.bkb-locfind-search input { flex: 1 1 auto; min-width: 0; border: 0; outline: 0; background: none; color: var(--font-color); font-size: .86rem; padding: 0; }
.bkb-locfind-search input::-webkit-search-cancel-button { cursor: pointer; }
.bkb-locfind-toggle { position: relative; display: inline-flex; align-items: center; gap: 8px; color: var(--font-color); font-size: .84rem; margin: 0; cursor: pointer; }
/* The real checkbox stays in the DOM (and in the tab order) behind the drawn switch —
   position:absolute is scoped by the label's position:relative above. */
.bkb-locfind-cb { position: absolute; left: 0; top: 50%; opacity: 0; width: 34px; height: 18px; margin: -9px 0 0; }
.bkb-locfind-sw { width: 34px; height: 18px; border-radius: 999px; background: rgba(128,128,128,.4); position: relative; flex: 0 0 auto; transition: background .15s; }
.bkb-locfind-sw::after { content: ''; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff; transition: transform .15s; }
.bkb-locfind-cb:checked + .bkb-locfind-sw { background: var(--accent-orange); }
.bkb-locfind-cb:checked + .bkb-locfind-sw::after { transform: translateX(16px); }
.bkb-locfind-cb:focus-visible + .bkb-locfind-sw { outline: 2px solid var(--accent-orange); outline-offset: 2px; }
.bkb-locfind-near { border: 1px solid var(--bk-loc-line); background: var(--bk-loc-surface-hi); color: var(--font-color); border-radius: 999px; padding: 9px 18px; font-size: .84rem; cursor: pointer; }
.bkb-locfind-near[disabled] { opacity: .55; cursor: default; }
.bkb-locfind { margin: 0 auto; }
/* 320, not 260: at 260 a card with a logo chip, a status word like "Closed for
   the season" and a blurb had nowhere to put any of them. */
.bkb-locfind--grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 22px; }
.bkb-locfind--list { display: flex; flex-direction: column; gap: 16px; }
/* ⚠ THE BASELINE, not a preset. Every loccard_* dial defaults to '' and emits no
   class, so THIS rule is the card every published band actually renders — the
   dials only move a card whose photographer deliberately opened one. Raising it
   is the only way an untouched band gets a current-looking card, which is why the
   resting shadow is a base property here rather than another opt-in. Twins the
   admin preview baseline in shape and measurement; the surface differs because
   the live band mixes glass from the studio theme and the preview from --bkb-*. */
.bkb-locfind-card {
    display: flex; flex-direction: column;
    background: var(--bk-loc-surface); -webkit-backdrop-filter: var(--bk-loc-blur);
    backdrop-filter: var(--bk-loc-blur);
    border: 1px solid var(--bk-loc-line); border-left: 4px solid var(--accent-orange);
    border-radius: 20px; padding: 24px 26px; box-shadow: var(--bk-loc-rest);
    transition: transform .18s ease, box-shadow .18s ease, background .18s ease;
}
.bkb-locfind-card:hover { transform: translateY(-3px); box-shadow: var(--bk-loc-lift); background: var(--bk-loc-surface-hi); }
@media (prefers-reduced-motion: reduce) { .bkb-locfind-card { transition: none; } .bkb-locfind-card:hover { transform: none; } }
/* The left rail is the one place the three kinds of closed are worth telling
   apart at a glance across a whole grid — it reads before you get to the word. */
.bkb-locfind-card.is-closed { border-left-color: #475569; }
.bkb-locfind-card.is-tone-limited { border-left-color: #b45309; }
.bkb-locfind-card.is-tone-soon { border-left-color: #1d4ed8; }
.bkb-locfind-card[hidden] { display: none; }
.bkb-locfind-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 10px; }
/* Name and badge share a row while they fit, and the badge drops under the name
   when the status is a sentence rather than a word. */
.bkb-locfind-headtext { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; }
.bkb-locfind-name { font-weight: 700; font-size: 1.08rem; line-height: 1.32; letter-spacing: -.01em; color: var(--heading-color); }
/* Open/closed carries a WORD, never colour alone (WCAG 1.4.1). Colour comes
   from the shared tone tokens above — this rule owns shape only. */
.bkb-locfind-badge { font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; border-radius: 999px; padding: 4px 12px; white-space: nowrap; background: var(--bk-tone-bg); color: var(--bk-tone-ink); }
/* ⚠ The body sizes on this card are scaled by ONE multiplier (--bkb-locbody, set
   on the card by .bkb-loccard--body-* below) rather than each being overridden to
   a flat size, so "Small" and "Large" keep the relationship between the address,
   the blurb, the phone line and the distance that the card was drawn with. The
   `1` fallback is what leaves an untouched card byte-identical to today. */
.bkb-locfind-addr, .bkb-locfind-city { font-size: calc(.84rem * var(--bkb-locbody, 1)); line-height: 1.5; color: var(--font-color); opacity: .7; }
.bkb-locfind-phone { display: flex; align-items: center; gap: 7px; margin-top: 6px; font-size: calc(.84rem * var(--bkb-locbody, 1)); }
.bkb-locfind-phone i { color: var(--font-color); opacity: .5; font-size: .78rem; }
.bkb-locfind-phone a { color: var(--font-color); opacity: .75; text-decoration: none; }
.bkb-locfind-phone a:hover, .bkb-locfind-phone a:focus-visible { opacity: 1; text-decoration: underline; }
.bkb-locfind-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.bkb-locfind-tag { font-size: .73rem; border: 1px solid var(--bk-loc-line); border-radius: 999px; padding: 3px 11px; color: var(--font-color); opacity: .8; }
.bkb-locfind-dist { margin-top: 10px; font-size: calc(.78rem * var(--bkb-locbody, 1)); color: var(--font-color); opacity: .7; }
/* The wrapper takes the auto margin, so a grid row of cards carrying different
   amounts of copy still lines its buttons up along the bottom; the button keeps
   a plain top margin for the single-card and list-layout cases. */
.bkb-locfind-ctawrap { margin-top: auto; padding-top: 18px; }
.bkb-locfind-cta { display: inline-block; text-decoration: none; background: var(--accent-orange); color: #fff; font-weight: 700; font-size: .86rem; border-radius: 999px; padding: 10px 24px; }
.bkb-locfind-cta:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 2px; }
/* Closed location: still a link (the page has hours, policies, what's offered),
   but must never read as a bookable CTA — outline, not fill. Text keeps the
   card's own --font-color pairing, so contrast holds on any studio palette. */
.bkb-locfind-cta--quiet { background: none; color: var(--font-color); border: 1px solid var(--bk-loc-line); font-weight: 600; }
.bkb-locfind-cta--quiet:hover { border-color: var(--accent-orange); color: var(--accent-orange); }
.bkb-locfind-empty { margin: 16px auto 0; font-size: .86rem; color: var(--font-color); opacity: .7; text-align: center; }

/* ── The card fold: "Show more" / "Show fewer" ────────────────────────────────
   `limit_mobile` / `limit_desktop` say how many cards a customer sees BEFORE the
   toggle. They are NOT the existing `limit`, which decides how many locations are
   in the band at all — one caps the band, these two fold it. Both default to 0,
   which emits no attribute and no button, so every band published before this
   renders byte-identically.

   ⚠ CSS-ENFORCED, NEVER A SERVER SLICE. The grid is repeat(auto-fill,
   minmax(320px, 1fr)): the server cannot know how many cards a viewport fits, and
   a slice would put the folded cards beyond the toggle's reach — "Show more" would
   have nothing left to show. Every card is in the DOM; the fold only decides which
   of them paint.

   ⚠ ONE RULE PER VALUE, because nth-child() takes no custom property. 12 is the
   cap everywhere — the inspector's max and the clamp in locFold() — so a value
   that arrives out of range folds at 12 rather than silently doing nothing.

   ⚠ data-fold-on is what ARMS the fold, and the live band does not emit it: a
   one-line inline script sets it the moment the grid closes, so a customer with no
   JavaScript gets the whole band and no toggle — exactly today's page. A
   server-emitted fold would hide cards that nothing could bring back.

   ⚠ And it is DISARMED while a search or filter is running. A filtered-out card is
   `hidden` but is still a child, so a fold of 3 over a filtered list would show the
   third match and nothing else. */
.bkb-locfind-more { display: none; margin-top: 20px; text-align: center; }
.bkb-locfind-morebtn { border: 1px solid rgba(128,128,128,.45); background: none; color: inherit; font-weight: 600; font-size: .86rem; border-radius: 999px; padding: 9px 22px; cursor: pointer; }
.bkb-locfind-morebtn:hover { background: rgba(128,128,128,.12); }
.bkb-locfind-morebtn:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
@media (max-width: 767.98px) {
    .bkb-locfind[data-fold-on][data-fold-m="1"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+2) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-m="2"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+3) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-m="3"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+4) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-m="4"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+5) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-m="5"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+6) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-m="6"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+7) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-m="7"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+8) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-m="8"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+9) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-m="9"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+10) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-m="10"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+11) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-m="11"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+12) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-m="12"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+13) { display: none; }
    .bkb-locfind[data-fold-on] ~ .bkb-locfind-more--m { display: block; }
}
@media (min-width: 768px) {
    .bkb-locfind[data-fold-on][data-fold-d="1"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+2) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-d="2"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+3) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-d="3"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+4) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-d="4"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+5) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-d="5"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+6) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-d="6"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+7) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-d="7"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+8) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-d="8"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+9) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-d="9"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+10) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-d="10"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+11) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-d="11"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+12) { display: none; }
    .bkb-locfind[data-fold-on][data-fold-d="12"]:not([data-fold-open]) > .bkb-locfind-card:nth-child(n+13) { display: none; }
    .bkb-locfind[data-fold-on] ~ .bkb-locfind-more--d { display: block; }
}

/* ── Location-card appearance dials — CSS TWINS with admin booking-blocks.css ──
   Every rule below is byte-identical on the live side and pinned by $twinRules
   in tests/booking_type_scale_parity_test.php, which is only possible because
   they use neutral rgba() rather than either file's palette — the same trick
   .bkb-callout--* uses. The base .bkb-locfind-card rule keeps the themed
   surface; these override one property each on top of it.
   ⚠ Corner and shadow classes are deliberately NOT merged into the look
   classes: a photographer picking "Filled" should not silently lose the corner
   radius they chose, so the four dials compose instead of competing. */
.bkb-loccard--filled { background: rgba(128,128,128,.1); border-top-color: transparent; border-right-color: transparent; border-bottom-color: transparent; }
.bkb-loccard--bordered { background: transparent; border-top: 2px solid rgba(128,128,128,.4); border-right: 2px solid rgba(128,128,128,.4); border-bottom: 2px solid rgba(128,128,128,.4); }
.bkb-loccard--elevated { border-top-color: transparent; border-right-color: transparent; border-bottom-color: transparent; box-shadow: 0 8px 32px rgba(0,0,0,.12); }
.bkb-loccard--square { border-radius: 0; }
.bkb-loccard--soft { border-radius: 8px; }
.bkb-loccard--xround { border-radius: 28px; }
.bkb-loccard--shadow-sm { box-shadow: 0 8px 32px rgba(0,0,0,.12); }
.bkb-loccard--shadow-lg { box-shadow: 0 18px 50px rgba(0,0,0,.18); }
/* ⚠ A REAL token, not the '' default. The standard card carries a resting shadow
   of its own now, so "no shadow" is a deliberate choice a photographer has to be
   able to make — before the baseline was raised, '' WAS shadowless and this rule
   would have been redundant. Ordered after --elevated on purpose: at equal
   specificity the later rule wins, so an explicit "None" beats the shadow that
   the Raised card style implies rather than losing to it silently. */
.bkb-loccard--shadow-none { box-shadow: none; }
.bkb-loccard--compact { padding: 14px 16px; }
.bkb-loccard--roomy { padding: 30px 32px; }
/* Off, not transparent: a 4px transparent edge would still push the content in
   by 4px and leave the card looking mysteriously off-centre next to its row.
   ⚠ Doubled selector on purpose — `.bkb-locfind-card.is-closed` sets the rail
   colour at two classes, so a single class here would lose to it and the rail
   would switch off on open cards only. */
.bkb-locfind-card.bkb-loccard--norail { border-left-width: 1px; border-left-color: rgba(128,128,128,.25); }

/* ── Location-card typography and chrome — CSS TWINS with admin booking-blocks.css ──
   Phase 2, same contract as the block above: neutral rgba() and inherited colour
   only, so every body can be pinned byte-for-byte by $twinRules, and '' emits no
   class at all so an untouched card renders exactly as it does today.
   ⚠ The three button treatments deliberately exclude .bkb-locfind-cta--quiet.
   A closed location's "View details" is quiet BECAUSE it must never read as a
   bookable CTA, and these are two-class rules — without the :not() they would
   out-specify the one-class quiet rule and flatten that distinction on every
   closed card. Full width is the one that DOES apply to both: it is layout, not
   emphasis, and a row of half-width and full-width buttons would just look broken. */
.bkb-loccard--name-sm .bkb-locfind-name { font-size: .92rem; }
.bkb-loccard--name-lg .bkb-locfind-name { font-size: 1.16rem; }
.bkb-loccard--name-xl .bkb-locfind-name { font-size: 1.34rem; }
.bkb-loccard--namewt-medium .bkb-locfind-name { font-weight: 600; }
.bkb-loccard--namewt-heavy .bkb-locfind-name { font-weight: 800; }
.bkb-loccard--namecase-upper .bkb-locfind-name { text-transform: uppercase; letter-spacing: .045em; }
.bkb-loccard--namecase-small .bkb-locfind-name { font-variant-caps: all-small-caps; letter-spacing: .04em; }
.bkb-loccard--body-sm { --bkb-locbody: .9; }
.bkb-loccard--body-lg { --bkb-locbody: 1.14; }
.bkb-loccard--tags-filled .bkb-locfind-tag { background: rgba(128,128,128,.16); border-color: transparent; }
.bkb-loccard--tags-plain .bkb-locfind-tags { gap: 4px 14px; }
.bkb-loccard--tags-plain .bkb-locfind-tag { border-color: transparent; padding-left: 0; padding-right: 0; }
.bkb-loccard--btn-outline .bkb-locfind-cta:not(.bkb-locfind-cta--quiet) { background: none; color: inherit; border: 1px solid rgba(128,128,128,.45); }
.bkb-loccard--btn-soft .bkb-locfind-cta:not(.bkb-locfind-cta--quiet) { background: rgba(128,128,128,.16); color: inherit; }
.bkb-loccard--btn-link .bkb-locfind-cta:not(.bkb-locfind-cta--quiet) { background: none; color: inherit; padding: 0; border-radius: 0; text-decoration: underline; }
.bkb-loccard--btn-full .bkb-locfind-cta { display: block; width: 100%; text-align: center; }

/* 4b — Hero + Location Search (Phase 6). CSS TWINS with the admin editor's
   booking-blocks.css — every rule body byte-identical, same order (parity test
   $twinRules). The band sits ON the hero photo, so surfaces are literal
   white/black glass (side-agnostic — the hero caption already forces #fff
   text); the geo pill inherits the caption colour. Admin previews a static
   mock (span input); this side wires a real input, so selectors stay
   CLASS-based — both elements carry the same classes. */
.bkb-hsearch-cap { width: 100%; max-width: 720px; margin-left: auto; margin-right: auto; }
.bkb-hsearch-bar { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-top: 18px; }
.bkb-hsearch-box { position: relative; flex: 1 1 300px; max-width: 460px; display: flex; align-items: center; gap: 10px; background: rgba(255,255,255,.94); border: 1px solid rgba(255,255,255,.6); border-radius: 999px; padding: 12px 20px; color: rgba(0,0,0,.8); text-align: left; text-shadow: none; box-shadow: 0 10px 30px rgba(0,0,0,.25); }
.bkb-hsearch-box i { color: inherit; opacity: .55; flex: 0 0 auto; }
.bkb-hsearch-input { flex: 1 1 auto; min-width: 0; border: 0; outline: 0; background: transparent; font-family: inherit; font-size: .95rem; color: inherit; padding: 0; }
.bkb-hsearch-input::placeholder { color: rgba(0,0,0,.45); opacity: 1; }
.bkb-hsearch-geo { display: inline-flex; align-items: center; gap: 8px; border: 1px solid rgba(255,255,255,.55); border-radius: 999px; padding: 12px 18px; background: rgba(0,0,0,.25); color: inherit; font-family: inherit; font-size: .9rem; cursor: pointer; }
.bkb-hsearch-geo:hover { background: rgba(0,0,0,.4); }
.bkb-hsearch-cap .bkb-btns { margin-top: 16px; }

/* 5 — Manage-booking strip */
.bkb-manage { margin: 0 auto; display: flex; align-items: center; gap: 18px; background: var(--bg-light-secondary, #fff); border: 1px solid var(--border-muted, rgba(128,128,128,.2)); border-radius: 16px; padding: 22px 26px; }
.bkb-manage--center { justify-content: center; text-align: center; }
.bkb-manage--right  { flex-direction: row-reverse; text-align: right; }
.bkb-manage-icon { display: inline-flex; align-items: center; justify-content: center; width: 46px; height: 46px; flex: 0 0 auto; border-radius: 50%; background: rgba(128,128,128,.12); color: var(--accent-orange); font-size: 1.2rem; }
.bkb-manage-text { flex: 1 1 auto; }
.bkb-manage-text h3 { font-size: clamp(1.02rem, .92rem + .4vw, 1.2rem); font-weight: 700; color: var(--heading-color); margin: 0 0 .25em; }
.bkb-manage-text p  { font-size: .86rem; color: var(--font-color); opacity: .7; margin: 0; }
.bkb-manage-btn { flex: 0 0 auto; text-decoration: none; background: var(--accent-orange); color: #fff; font-weight: 700; font-size: .86rem; border-radius: 999px; padding: 10px 22px; }

/* 6 — Featured sessions */
.bkb-featsvc-card { background: var(--bg-light-secondary, #fff); border: 1px solid var(--border-muted, rgba(128,128,128,.2)); border-radius: 16px; padding: 20px; text-align: center; cursor: pointer; }
.bkb-featsvc-card:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 3px; }
.bkb-featsvc-img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 12px; display: block; margin-bottom: 14px; background: var(--border-muted, rgba(128,128,128,.2)); }
.bkb-featsvc-card h3 { font-size: clamp(1rem, .9rem + .4vw, 1.2rem); font-weight: 700; color: var(--heading-color); margin: 0 0 .35em; }
.bkb-featsvc-card p  { font-size: .85rem; line-height: 1.5; color: var(--font-color); opacity: .7; margin: 0 0 .6em; }
/* Price sits between the blurb and the cue. Tokenized like the card's own h3
   (this block reads --heading-color directly rather than carrying .mode-dark
   overrides) so it tracks the card it is in. */
.bkb-featsvc-price { display: block; font-size: 1rem; font-weight: 800; color: var(--heading-color); margin: 0 0 .5em; }
.bkb-featsvc-cue { font-size: .78rem; font-weight: 700; color: var(--accent-orange); }

/* Featured-sessions info pop-up (live only — the editor has no modal to preview) */
.bkb-featsvc-modal { position: fixed; inset: 0; z-index: 1080; display: flex; align-items: center; justify-content: center; padding: 20px; }
.bkb-featsvc-modal[hidden] { display: none; }
.bkb-featsvc-modal-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,.55); }
.bkb-featsvc-modal-card { position: relative; z-index: 1; width: 100%; max-width: 520px; max-height: 88vh; overflow-y: auto; background: var(--bg-color, #fff); border-radius: 18px; padding: 30px 28px 26px; text-align: center; box-shadow: 0 18px 50px rgba(0,0,0,.3); }
.bkb-featsvc-modal-x { position: absolute; top: 10px; right: 14px; border: 0; background: none; font-size: 1.6rem; line-height: 1; color: var(--font-color); opacity: .6; cursor: pointer; }
.bkb-featsvc-modal-x:hover { opacity: 1; }
.bkb-featsvc-modal-title { font-size: clamp(1.3rem, 1.14rem + .65vw, 1.6rem); font-weight: 800; color: var(--heading-color); margin: 0 0 .5em; font-family: var(--heading-font); }
.bkb-featsvc-modal-about { font-size: .92rem; line-height: 1.6; color: var(--font-color); white-space: pre-line; }
.bkb-featsvc-modal-who { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border-muted, rgba(128,128,128,.2)); font-size: .88rem; color: var(--font-color); white-space: pre-line; }
.bkb-featsvc-modal-who[hidden] { display: none; }
.bkb-featsvc-modal-who-label { display: block; font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .12em; color: var(--accent-orange); margin-bottom: .5em; }
.bkb-featsvc-modal-cta { margin-top: 22px; border: 0; cursor: pointer; }

@media (max-width: 720px) {
    .bkb-gcols--2, .bkb-gcols--3, .bkb-gcols--4 { grid-template-columns: 1fr; }
    .bkb-manage, .bkb-manage--right { flex-direction: column; text-align: center; }
}

/* Card + carousel sheet items behave like the generic "A Special Treat" cards:
   hover-lift, image zoom-on-hover, and an Add-to-cart button (green "Added" when
   selected). The compact list layout keeps its checkbox-row look (button hidden). */
.addons-sheet--card .addon-sheet-card, .addons-sheet--carousel .addon-sheet-card { transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.15s; }
.addons-sheet--card .addon-sheet-card:hover, .addons-sheet--carousel .addon-sheet-card:hover { transform: translateY(-3px); box-shadow: 0 10px 24px rgba(0,0,0,0.10), 0 2px 6px rgba(0,0,0,0.05); }
.addons-sheet--card .addon-thumb, .addons-sheet--carousel .addon-thumb { transition: transform 0.3s ease; }
.addons-sheet--card .addon-sheet-card:hover .addon-thumb, .addons-sheet--carousel .addon-sheet-card:hover .addon-thumb { transform: scale(1.05); }
.addon-sheet-card__btn { display: none; }
.addons-sheet--card .addon-sheet-card__btn, .addons-sheet--carousel .addon-sheet-card__btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 4px;
    margin: 0 14px 14px; padding: 9px 14px; font-size: 0.82rem; font-weight: 700;
    border-radius: 999px; background: var(--accent-orange); border: 1.5px solid var(--accent-orange);
    color: #fff; cursor: pointer; transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.addons-sheet--card .addon-sheet-card__btn:hover, .addons-sheet--carousel .addon-sheet-card__btn:hover { background: var(--bg-color); color: var(--accent-orange); }
.addons-sheet--card .addon-sheet-card.selected .addon-sheet-card__btn, .addons-sheet--carousel .addon-sheet-card.selected .addon-sheet-card__btn { background: var(--accent-green); border-color: var(--accent-green); color: #fff; }
.addons-sheet--card .addon-sheet-card.selected .addon-sheet-card__btn:hover, .addons-sheet--carousel .addon-sheet-card.selected .addon-sheet-card__btn:hover { background: var(--bg-color); color: var(--accent-green); border-color: var(--accent-green); }
/* Match the generic cards: the check is a circular badge on the RIGHT (faint tick
   always, fills orange when selected); the image area sits on white. */
.addons-sheet--card .sheet-addon-check, .addons-sheet--carousel .sheet-addon-check {
    position: absolute; top: 10px; right: 10px; left: auto; z-index: 1;
    width: 30px; height: 30px; border-radius: 50%; border: none;
    background: var(--bg-color); box-shadow: 0 2px 8px rgba(0,0,0,0.18);
}
.addons-sheet--card .sheet-addon-check-icon, .addons-sheet--carousel .sheet-addon-check-icon {
    display: inline-flex !important; font-size: 0.78rem; color: var(--font-color); opacity: 0.45;
}
.addons-sheet--card .addon-sheet-card.selected .sheet-addon-check, .addons-sheet--carousel .addon-sheet-card.selected .sheet-addon-check { background: var(--accent-orange); border-color: var(--accent-orange); }
.addons-sheet--card .addon-sheet-card.selected .sheet-addon-check-icon, .addons-sheet--carousel .addon-sheet-card.selected .sheet-addon-check-icon { color: #fff; opacity: 1; }
.addons-sheet--card .addon-thumb, .addons-sheet--carousel .addon-thumb,
.addons-sheet--card .addon-thumb--ph, .addons-sheet--carousel .addon-thumb--ph { background: var(--bg-light-secondary, #fff); }

/* Generic addon cards */
.generic-card { padding: 14px 16px; border-radius: 12px; border: 1.5px solid var(--border-muted); margin-bottom: 8px; cursor: pointer; transition: border-color 0.15s, background 0.15s; background: var(--bg-color); }
/* Selected: the accent tint COMPOSITES over the card's own opaque surface.
   Setting it as a translucent background-color instead REPLACES var(--bg-color),
   which let the page background show straight through a selected card — the
   "white goes away on select" defect. background-image keeps the fill intact. */
.generic-card.selected {
    border-color: var(--accent-orange);
    background-color: var(--bg-color);
    background-image: linear-gradient(rgba(238,81,58,0.04), rgba(238,81,58,0.04));
}
.generic-addon-check      { flex-shrink: 0; width: 20px; height: 20px; border-radius: 6px; border: 2px solid rgba(128,128,128,0.25); display: flex; align-items: center; justify-content: center; transition: border-color 0.1s; }
.generic-addon-check-icon { font-size: 0.65rem; color: var(--accent-orange); }

/* ============================================================
   Generic addon GRID cards (Amazon "order again" style)
   Uses theme tokens — themes drive every text + accent color.
   Shadows stay neutral (they're depth, not branding).
   ============================================================ */
.generic-card-grid {
    padding: 0; margin: 0;
    display: flex; flex-direction: column;
    /* Fill the parent column so siblings in the same row match height */
    width: 100%; height: 100%; flex: 1;
    background: var(--bg-color);
    border: 1px solid var(--border-muted, rgba(128,128,128,0.18));
    border-radius: 16px;
    overflow: hidden;
    box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 1px 3px rgba(0,0,0,0.05);
    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
    cursor: pointer;
}
.generic-card-grid:hover    { transform: translateY(-3px); box-shadow: 0 10px 24px rgba(0,0,0,0.10), 0 2px 6px rgba(0,0,0,0.05); }
/* Selected: colored border + soft accent glow (outside the card).
   No inset shadow — that paints over the image's top edge. */
.generic-card-grid.selected { border-color: var(--accent-orange); box-shadow: 0 10px 24px rgba(0,0,0,0.08), 0 0 0 1px var(--accent-orange); }

/* Image area */
.generic-card-img-wrap         { position: relative; width: 100%; aspect-ratio: 4 / 3; background: var(--bg-light-secondary, rgba(128,128,128,0.06)); overflow: hidden; }
.generic-card-img              { width: 100%; height: 100%; object-fit: contain; padding: 3.5%; display: block; transition: transform 0.3s ease; cursor: pointer; }
.generic-card-grid:hover .generic-card-img { transform: scale(1.04); }
.generic-card-img-placeholder  { display: flex; align-items: center; justify-content: center; color: var(--icon-color, var(--heading-color)); opacity: 0.25; font-size: 2.6rem; }

/* Selected check badge (top-right of image) */
.generic-card-check            { position: absolute; top: 10px; right: 10px; width: 30px; height: 30px; border-radius: 50%; background: var(--bg-color); border: none; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 8px rgba(0,0,0,0.18); transition: background 0.15s, transform 0.15s; }
.generic-card-check .fa-check  { font-size: 0.78rem; color: var(--font-color); opacity: 0.45; }
.generic-card-grid.selected .generic-card-check          { background: var(--accent-orange); transform: scale(1.08); }
.generic-card-grid.selected .generic-card-check .fa-check { color: #fff; opacity: 1; }

/* Body — centered, product-card hierarchy:
   name is the hero (heading size), description quietly underneath,
   price sits muted as supporting info just above the CTA. */
.generic-card-body             { padding: 16px 16px 16px; display: flex; flex-direction: column; flex: 1; gap: 6px; text-align: center; align-items: center; }
.generic-card-name             { font-size: clamp(1.12rem, 1.06rem + 0.26vw, 1.28rem); font-weight: 700; color: var(--heading-color); font-family: var(--heading-font); line-height: 1.25; letter-spacing: -0.01em; }
.generic-card-desc             { font-size: 0.86rem; color: var(--font-color); opacity: 0.6; line-height: 1.4; flex: 1; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.generic-card-desc-spacer      { flex: 1; min-height: 4px; }
.generic-card-price            { font-size: 0.92rem; font-weight: 600; color: var(--font-color); opacity: 0.75; line-height: 1.1; letter-spacing: 0.01em; }

/* Add-to-cart button */
.generic-card-add-btn          { margin-top: 12px; padding: 9px 14px; font-size: 0.82rem; font-weight: 700; border-radius: 999px; background: var(--accent-orange); border: 1.5px solid var(--accent-orange); color: #fff; transition: background 0.15s, border-color 0.15s, color 0.15s; }
.generic-card-add-btn:hover    { background: var(--bg-color); color: var(--accent-orange); }
.generic-card-grid.selected .generic-card-add-btn       { background: var(--accent-green); border-color: var(--accent-green); color: #fff; }
.generic-card-grid.selected .generic-card-add-btn:hover { background: var(--bg-color); color: var(--accent-green); border-color: var(--accent-green); }

/* ── Quantity stepper (2026-08-20) ────────────────────────────────────────────
   Drawn only for an add-on whose max_qty is above 1, and only while its card is
   selected — an add-on nobody may buy twice shows no control at all, which is
   every add-on until a photographer raises the bound.

   The stepper lives INSIDE the card, which is itself the click target, so its
   controls are excluded from the card toggle the same way the zoomable image is
   (`[data-addon-img]`) — see the `[data-addon-qty]` guards in booking.js and in
   the add-ons step's scoped script. Both card producers emit this exact markup;
   server- and client-rendered cards must stay indistinguishable. */
.addon-qty            { display: inline-flex; align-items: center; gap: 2px; margin-top: 10px; padding: 2px; border: 1.5px solid var(--border-muted); border-radius: 999px; background: var(--bg-color); }
.addon-qty-btn        { width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center; padding: 0; border: none; border-radius: 50%; background: transparent; color: var(--font-color); font-size: 0.82rem; line-height: 1; transition: background 0.15s, color 0.15s; }
.addon-qty-btn:hover:not(:disabled) { background: var(--accent-orange); color: #fff; }
.addon-qty-btn:disabled { opacity: 0.35; cursor: default; }
.addon-qty-input      { width: 3.2ch; min-width: 34px; padding: 0; border: none; background: transparent; color: var(--font-color); font-size: 0.92rem; font-weight: 700; text-align: center; -moz-appearance: textfield; appearance: textfield; }
/* Native spinners would sit beside our own −/+ and disagree with the bounds. */
.addon-qty-input::-webkit-outer-spin-button,
.addon-qty-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.addon-qty-btn:focus-visible,
.addon-qty-input:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 2px; }
/* Sheet rows are horizontal, so the stepper sits beside the price rather than under it. */
.addon-sheet-card .addon-qty { margin-top: 0; margin-left: 8px; flex: 0 0 auto; }

/* ── Add-On Presentation axes (2026-07-21) — generic-grid layout + no-image check ──
   Card content (image/desc/price) is toggled by omission in booking.js; these rules
   cover the two things that need styling: the selection check when the image is
   hidden, and the list / carousel grid layouts (default 'card' = the Bootstrap row). */
.generic-card-grid { position: relative; }  /* anchor the no-image inline check to the card */
/* List — one card per row, laid out horizontally (thumb | body). */
.generic-grid--list > [class*="col-"]        { flex: 0 0 100%; max-width: 100%; }
.generic-grid--list .generic-card-grid       { flex-direction: row; align-items: stretch; }
.generic-grid--list .generic-card-img-wrap   { flex: 0 0 34%; aspect-ratio: auto; }
.generic-grid--list .generic-card-body       { text-align: left; align-items: flex-start; justify-content: center; }
/* Carousel — horizontal scroll strip of fixed-width cards. */
.generic-grid--carousel               { flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; padding-bottom: 8px; }
.generic-grid--carousel > [class*="col-"] { flex: 0 0 240px; max-width: 240px; scroll-snap-align: start; }

/* ============================================================
   Generic addon LIST rows — the "soft treat" second wave in the
   page-by-page add-ons flow. Same .generic-card control + money
   contract as the grid; a horizontal row with a bigger image and
   larger type (photographer asked for a calmer, more readable list).
   ============================================================ */
.generic-card-list {
    padding: 0; margin: 0;
    display: flex; flex-direction: row; align-items: center; gap: 16px;
    width: 100%;
    background: var(--bg-color);
    border: 1px solid var(--border-muted, rgba(128,128,128,0.18));
    border-radius: 16px;
    overflow: hidden;
    box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 1px 3px rgba(0,0,0,0.05);
    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
    cursor: pointer;
}
.generic-card-list:hover    { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(0,0,0,0.09), 0 2px 6px rgba(0,0,0,0.05); }
.generic-card-list.selected { border-color: var(--accent-orange); box-shadow: 0 8px 20px rgba(0,0,0,0.08), 0 0 0 1px var(--accent-orange); }

/* Image — a fixed square on the left, bigger than the grid card's tile. */
.generic-card-list .generic-card-img-wrap { width: 128px; min-width: 128px; height: 128px; aspect-ratio: auto; border-radius: 12px; margin: 12px 0 12px 12px; }
.generic-card-list .generic-card-img      { padding: 6%; }
.generic-card-list:hover .generic-card-img { transform: none; }
.generic-card-list .generic-card-check    { top: 6px; right: 6px; }
.generic-card-list.selected .generic-card-check          { background: var(--accent-orange); transform: scale(1.08); }
.generic-card-list.selected .generic-card-check .fa-check { color: #fff; opacity: 1; }

/* Body — left-aligned, larger type; price above the name, Add pinned left. */
.generic-card-list .generic-card-body   { padding: 14px 16px 14px 0; text-align: left; align-items: flex-start; justify-content: center; gap: 4px; flex: 1; }
.generic-card-list .generic-card-price  { font-size: 1.02rem; opacity: 0.85; order: -1; }
.generic-card-list .generic-card-name   { font-size: clamp(1.1rem, 1.02rem + 0.36vw, 1.24rem); line-height: 1.2; }
.generic-card-list .generic-card-desc   { font-size: 0.95rem; -webkit-line-clamp: 3; }
.generic-card-list .generic-card-desc-spacer { display: none; }
.generic-card-list .generic-card-add-btn { margin-top: 8px; align-self: flex-start; }
.generic-card-list.selected .generic-card-add-btn       { background: var(--accent-green); border-color: var(--accent-green); color: #fff; }
.generic-card-list.selected .generic-card-add-btn:hover { background: var(--bg-color); color: var(--accent-green); border-color: var(--accent-green); }

@media (max-width: 575.98px) {
    .generic-card-list { gap: 12px; }
    .generic-card-list .generic-card-img-wrap { width: 96px; min-width: 96px; height: 96px; margin: 10px 0 10px 10px; }
    .generic-card-list .generic-card-desc     { font-size: 0.9rem; -webkit-line-clamp: 2; }
}

/* ============================================================
   Photo size axis (2026-08-04) — the named Small/Medium/Large scale the
   photographer sets per add-on block in the builder. Twin of the builder
   preview's .bkp-imgsize-* (admin booking-blocks.css).

   The modifier rides the row/grid CONTAINER, so ONE class sizes both the
   list-row thumb and the card image and the partial needs no size param.

   ⚠ MEDIUM HAS NO RULE HERE ON PURPOSE. Medium IS the base rendering above
   (128px list thumb / 4:3 card image), so a page that predates this axis
   resolves to medium and is pixel-for-pixel unchanged. Adding a
   .bk-imgsize-medium override is the one edit that breaks that promise
   silently — size medium by editing the BASE rules, never by adding one.

   Each rule names the card variant it targets (.generic-card-grid /
   .generic-card-list) rather than bare .generic-card-img-wrap: the two
   variants size their well completely differently (aspect-ratio vs fixed
   square), and an unscoped rule would land on both at equal specificity and
   let source order decide which one wins.

   The photo already fills and clips its well at every size — the base
   .generic-card-img is width/height 100% with object-fit, and
   .generic-card-img-wrap is overflow:hidden — so unlike the builder preview
   this needs no object-fit fix. Deliberately NOT switched to `cover`:
   `contain` is the existing product-photo look and changing it would move
   every card that exists today. Asserted in BookingAddonPagedPresentationTest.
   ============================================================ */
.bk-imgsize-small .generic-card-grid .generic-card-img-wrap { aspect-ratio: 16 / 9; }
.bk-imgsize-large .generic-card-grid .generic-card-img-wrap { aspect-ratio: 1 / 1; }

.bk-imgsize-small .generic-card-list .generic-card-img-wrap { width: 88px;  min-width: 88px;  height: 88px;  border-radius: 10px; }
.bk-imgsize-large .generic-card-list .generic-card-img-wrap { width: 200px; min-width: 200px; height: 200px; border-radius: 14px; }
/* A 200px photo crowds the name + price against it without more room. */
.bk-imgsize-large .generic-card-list { gap: 20px; }

@media (max-width: 575.98px) {
    /* Without these the desktop sizes above (higher specificity than the base
       mobile rule) would follow the page down to a phone — a 200px square on a
       320px screen leaves no room for the name. */
    .bk-imgsize-small .generic-card-list .generic-card-img-wrap { width: 72px;  min-width: 72px;  height: 72px; }
    .bk-imgsize-large .generic-card-list .generic-card-img-wrap { width: 128px; min-width: 128px; height: 128px; }
    .bk-imgsize-large .generic-card-list { gap: 14px; }
}

/* Dark mode */
.mode-dark .generic-card-grid             { background: var(--bg-dark-secondary); border-color: rgba(255,255,255,0.1); box-shadow: 0 1px 3px rgba(0,0,0,0.4); }
.mode-dark .generic-card-grid:hover       { box-shadow: 0 12px 30px rgba(0,0,0,0.45); }
.mode-dark .generic-card-img-wrap         { background: rgba(255,255,255,0.04); }
.mode-dark .generic-card-check            { background: rgba(20,20,20,0.85); }

/* Addon thumb image */
.addon-thumb { width: 52px; height: 52px; object-fit: contain; border-radius: 8px; background: rgba(128,128,128,0.06); flex-shrink: 0; cursor: zoom-in; }

/* Addon text (used in JS-generated HTML) */
.addon-name      { font-size: 0.88rem; font-weight: 700; color: var(--heading-color); }
.addon-desc      { font-size: 0.75rem; color: var(--font-color); opacity: 0.58; }
.addon-desc-clamp { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.addon-price     { font-size: 0.95rem; font-weight: 700; color: var(--heading-color); white-space: nowrap; flex-shrink: 0; }

/* Mini cart panel */
.cart-backdrop   { position: fixed; inset: 0; background: rgba(0,0,0,0.35); backdrop-filter: blur(3px); z-index: 4998; }
.cart-panel      { position: fixed; top: 0; right: 0; height: 100%; width: 380px; max-width: 90vw; background: var(--bg-color, #faf9f6); border-radius: 20px 0 0 20px; z-index: 4999; transform: translateX(100%); transition: transform 0.3s ease; display: flex; flex-direction: column; box-shadow: -8px 0 40px rgba(0,0,0,0.18); }
.cart-header     { padding: 20px 24px 16px; border-bottom: 1px solid var(--border-muted); flex-shrink: 0; display: flex; align-items: center; justify-content: space-between; }
.cart-title      { font-family: var(--heading-font); font-size: 1rem; font-weight: 700; color: var(--heading-color); }
.cart-title-icon { color: var(--accent-orange); }
.cart-close-btn  { background: none; border: none; padding: 4px 8px; cursor: pointer; font-size: 1rem; color: var(--font-color); opacity: 0.4; line-height: 1; }
.cart-body       { flex: 1; overflow-y: auto; padding: 20px 24px; }
.cart-section-lbl { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--font-color); opacity: 0.4; margin-bottom: 12px; }
.cart-slot-line  { font-size: 0.78rem; color: var(--font-color); opacity: 0.5; margin-bottom: 14px; padding-bottom: 14px; border-bottom: 1px solid var(--border-muted); }
.cart-pkg-name   { font-size: 0.85rem; font-weight: 600; color: var(--heading-color); }
.cart-pkg-price  { font-size: 0.85rem; font-weight: 700; color: var(--heading-color); white-space: nowrap; padding-left: 16px; }
.cart-total-row  { border-top: 1.5px solid var(--border-muted); }
.cart-total-lbl  { font-size: 0.9rem; font-weight: 700; color: var(--heading-color); }
.cart-total-amt  { font-size: clamp(1.4rem, 1.3rem + 0.42vw, 1.66rem); font-weight: 700; color: var(--accent-orange); font-family: var(--heading-font); }
/* "Your Order" slide-in — saved reservations + enriched current-booking meta */
.cart-saved-line    { gap: 12px; }
.cart-saved-name    { font-size: 0.82rem; font-weight: 600; color: var(--heading-color); }
.cart-saved-meta    { font-size: 0.72rem; color: var(--font-color); opacity: 0.5; margin-top: 1px; }
.cart-saved-divider { border-top: 1px solid var(--border-muted); margin: 10px 0 14px; }
/* Each saved reservation = an editable mini-block: package line, removable
   add-on rows, then a "Remove reservation" foot + per-item subtotal. */
.cart-saved-item    { padding-bottom: 12px; margin-bottom: 12px; }
.cart-saved-item:not(:last-of-type) { border-bottom: 1px solid var(--border-muted); }
.cart-saved-addon   { margin-top: 6px; gap: 12px; }
.cart-saved-foot    { margin-top: 10px; gap: 12px; }
.cart-saved-subtotal { font-size: 0.72rem; font-weight: 600; color: var(--font-color); opacity: 0.55; white-space: nowrap; }
/* Layout-transparent wrapper so an inline POST form doesn't break the flex row. */
.cart-inline-form   { display: contents; }
/* × that removes a single add-on (saved-reservation form button + live-booking
   JS button share this style). */
.cart-addon-remove  { background: none; border: 0; padding: 0; margin-right: 6px; line-height: 1;
                      font-size: 0.7rem; color: var(--font-color); opacity: 0.5; cursor: pointer; transition: opacity .12s, color .12s; }
.cart-addon-remove:hover { opacity: 1; color: #dc3545; }
.cart-remove-reservation { background: none; border: 0; padding: 0; line-height: 1; cursor: pointer;
                      font-size: 0.74rem; font-weight: 600; color: #dc3545; opacity: 0.85; }
.cart-remove-reservation:hover { opacity: 1; text-decoration: underline; }
.cart-current-meta      { margin-bottom: 12px; }
.cart-current-experience { font-size: 0.85rem; font-weight: 600; color: var(--heading-color); }
.cart-current-location   { font-size: 0.76rem; color: var(--font-color); opacity: 0.6; margin-top: 3px; }
.cart-order-note    { font-size: 0.72rem; color: var(--font-color); opacity: 0.6; margin-top: 12px; }
.cart-footer     { flex-shrink: 0; padding: 16px 24px 24px; border-top: 1px solid var(--border-muted); }
.cart-trust      { font-size: 0.68rem; color: var(--font-color); opacity: 0.35; }
.sidebar-addon-name  { font-size: 0.76rem; color: var(--font-color); opacity: 0.65; }
.sidebar-addon-price { font-size: 0.76rem; font-weight: 700; color: var(--font-color); white-space: nowrap; padding-left: 8px; }
.sidebar-addon-icon  { font-size: 0.55rem; color: var(--accent-orange); }
/* "× 3" beside a cart line. Only drawn when a count exists, so a single of
   everything reads exactly as it always has. */
.sidebar-addon-qty   { font-weight: 700; color: var(--accent-orange); white-space: nowrap; }

/* Nudge modal */
.nudge-modal    { position: fixed; inset: 0; z-index: 5100; align-items: center; justify-content: center; padding: 20px; }
.nudge-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,0.5); backdrop-filter: blur(5px); }
.nudge-card     { position: relative; width: 100%; max-width: 400px; background: var(--bg-color, #faf9f6); border-radius: 20px; padding: 28px 28px 24px; box-shadow: 0 24px 60px rgba(0,0,0,0.25); text-align: center; }
.nudge-img      { width: 120px; height: 120px; object-fit: contain; border-radius: 14px; background: rgba(128,128,128,0.06); }
.nudge-badge    { display: inline-block; background: var(--accent-orange); color: #fff; font-size: 0.68rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; border-radius: 50px; padding: 4px 14px; }
.nudge-headline { font-family: var(--heading-font); font-size: 1rem; font-weight: 700; color: var(--heading-color); margin-bottom: 8px; line-height: 1.4; }
.nudge-body     { font-size: 0.82rem; color: var(--font-color); opacity: 0.65; margin-bottom: 24px; line-height: 1.6; }
.nudge-skip-btn { background: none; border: none; font-size: 0.78rem; color: var(--font-color); opacity: 0.4; cursor: pointer; padding: 6px; width: 100%; }

/* Addon image zoom tooltip */
#addonImgZoom { background: var(--bg-color, #fff); border-radius: 14px; box-shadow: 0 8px 32px rgba(0,0,0,0.22); padding: 10px; }

/* Home view — config sidebar */
.cfg-sidebar    { flex-shrink: 0; border-right: 1px solid rgba(128,128,128,0.1); background: rgba(128,128,128,0.03); transition: width 0.25s ease; overflow: hidden; }
.cfg-toggle-btn { background: none; border: none; padding: 2px 4px; cursor: pointer; color: var(--font-color); opacity: 0.3; font-size: 0.75rem; flex-shrink: 0; line-height: 1; }
.cfg-dev-label  { font-size: 0.62rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--font-color); opacity: 0.35; white-space: nowrap; overflow: hidden; }
.cfg-section-label { font-size: 0.65rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--font-color); opacity: 0.35; margin-bottom: 16px; }

/* Home view — service badges */
.svc-badge        { display: inline-flex; align-items: center; gap: 4px; font-size: 0.68rem; font-weight: 700; letter-spacing: 0.04em; padding: 3px 9px; border-radius: 20px; white-space: nowrap; }
.svc-badge-green  { background: var(--prepaid-background-color); color: var(--prepaid-font-color); border: 1px solid var(--prepaid-border-color); }
.svc-badge-orange { background: rgba(238,81,58,0.1); color: var(--accent-orange); border: 1px solid rgba(238,81,58,0.25); }

/* Home view — banner / grid / list card containers */
.banner-card { display: flex; flex-direction: column; border-radius: 16px; overflow: hidden; background: var(--bg-color); box-shadow: 0 2px 14px rgba(0,0,0,0.08); text-decoration: none !important; color: var(--font-color) !important; transition: transform 0.2s ease, box-shadow 0.2s ease; }
.banner-card:hover { transform: translateY(-2px); box-shadow: 0 6px 24px rgba(0,0,0,0.13); }
.banner-card img { width: 100%; height: auto; flex-shrink: 0; }
/* Banner column: 640px cap by default, widen to 800px on xl (≥1200px). */
@media (min-width: 1200px) { .bk-banner-col { max-width: 800px !important; } }
.banner-card-body { padding: 16px 18px; }
.grid-card  { transition: transform 0.2s ease; border: 1px solid var(--border-muted) !important; height: auto !important; max-width: none !important; }
.grid-card:hover { transform: translateY(-3px); }
.list-card  { background: var(--bg-color); border-radius: 14px; box-shadow: 0 2px 12px rgba(0,0,0,0.08); transition: transform 0.2s ease, box-shadow 0.2s ease; }
.list-card:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0,0,0,0.12); }

/* Compact layout — same grid card markup, denser via the .bk-cards-compact row.
   Tightens padding, image height, icon, type scale, and button so the most
   services fit in the least space (selected in Bookings → Settings). */
.bk-cards-compact .compact-card .card-body      { padding: 0.55rem 0.65rem !important; }
.bk-cards-compact .compact-card .card-img-top   { height: 92px !important; }
.bk-cards-compact .compact-card .svc-icon-block { width: 38px; height: 38px; border-radius: 10px; margin-bottom: 0.4rem !important; }
.bk-cards-compact .compact-card .svc-icon-inner { font-size: 1rem; }
.bk-cards-compact .compact-card .card-title-xs  { font-size: 0.84rem; }
.bk-cards-compact .compact-card .card-tagline   { font-size: 0.68rem; margin-bottom: 3px; }
.bk-cards-compact .compact-card .card-desc-sm   { font-size: 0.74rem; line-height: 1.4; margin-bottom: 0.5rem; }
.bk-cards-compact .compact-card .card-duration  { font-size: 0.68rem; }
.bk-cards-compact .compact-card .card-price     { font-size: 0.78rem; }
.bk-cards-compact .compact-card .svc-badge      { font-size: 0.6rem; padding: 2px 7px; }
.bk-cards-compact .compact-card .btn-book,
.bk-cards-compact .compact-card .btn-secondary  { font-size: 0.7rem !important; padding: 0.2rem 0.55rem !important; }
/* Fit more per row on wider screens (5-up on lg vs grid's 4-up). */
@media (min-width: 992px) {
    .bk-cards-compact > [class*="col-"] { flex: 0 0 auto; width: 20%; }
}

/* Home view — sidebar config sections */
.cfg-section    { margin-bottom: 16px; }
.cfg-label      { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--font-color); opacity: 0.35; margin-bottom: 8px; }
.cfg-divider    { height: 1px; background: var(--border-muted); margin: 12px 0; }
.radio-group    { display: flex; flex-direction: column; gap: 6px; }
.radio-opt      { display: flex; align-items: center; gap: 8px; font-size: 0.8rem; color: var(--font-color); cursor: pointer; }
.toggle-row     { display: flex; align-items: center; justify-content: space-between; font-size: 0.78rem; color: var(--font-color); margin-bottom: 8px; cursor: pointer; gap: 8px; }
.toggle-row input[type="checkbox"] { display: none; }
.toggle-track   { width: 32px; height: 18px; border-radius: 9px; background: rgba(128,128,128,0.2); position: relative; flex-shrink: 0; transition: background 0.2s; }
.toggle-row input[type="checkbox"]:checked + .toggle-track { background: var(--accent-orange); }
.toggle-thumb   { position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff; transition: left 0.2s; box-shadow: 0 1px 4px rgba(0,0,0,0.2); }
.toggle-row input[type="checkbox"]:checked + .toggle-track .toggle-thumb { left: 16px; }

/* Home view — card text (JS-generated) */
.card-title     { font-family: var(--heading-font); font-size: 0.97rem; font-weight: 700; color: var(--heading-color); }
.card-title-sm  { font-family: var(--heading-font); font-size: 1.05rem; font-weight: 700; color: var(--heading-color); margin-bottom: 4px; }
.card-title-xs  { font-family: var(--heading-font); font-size: 0.95rem; font-weight: 700; color: var(--heading-color); }
.card-tagline   { font-size: 0.79rem; font-weight: 600; color: var(--accent-orange); margin-bottom: 6px; }
.card-tagline-sm { font-size: 0.78rem; font-weight: 600; color: var(--accent-orange); margin-bottom: 10px; }
.card-desc      { font-size: 0.83rem; color: var(--font-color); opacity: 0.7; line-height: 1.6; margin-bottom: 10px; }
.card-desc-sm   { font-size: 0.82rem; color: var(--font-color); opacity: 0.7; line-height: 1.6; flex-grow: 1; margin-bottom: 14px; }
.card-desc-list { font-size: 0.82rem; color: var(--font-color); opacity: 0.7; line-height: 1.55; margin: 0; }
.card-duration  { font-size: 0.75rem; color: var(--font-color); opacity: 0.45; }
/* Service card price. Sits beside .card-duration in the card footer and is
   deliberately the louder of the two — full opacity against the duration's
   0.45, because the price is what the customer is scanning the row for. */
.card-price     { font-size: 0.88rem; font-weight: 700; color: var(--heading-color); }
.svc-icon-block  { width: 52px; height: 52px; border-radius: 14px; display: flex; align-items: center; justify-content: center; }
.svc-icon-inner  { color: #fff; }
.list-icon-block { flex-shrink: 0; width: 54px; height: 54px; border-radius: 14px; display: flex; align-items: center; justify-content: center; margin-top: 2px; }
.list-text-col   { flex: 1; min-width: 0; }
.list-right-col  { flex-shrink: 0; text-align: center; padding-top: 2px; }

/* Home view — page header */
.home-eyebrow  { font-size: 0.78rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent-orange); }
.home-title    { font-family: var(--heading-font); font-size: clamp(1.8rem, 1.52rem + 1.15vw, 2.35rem); font-weight: 700; color: var(--heading-color); margin-bottom: 8px; }
.home-location { color: var(--font-color); opacity: 0.65; font-size: 0.92rem; margin-bottom: 8px; }
.home-avail    { font-size: 0.83rem; color: var(--font-color); opacity: 0.75; }
.home-avail-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; background: rgba(44,182,167,1); animation: pulseGreen 1.9s infinite; }

/* Home view — feature icons */
.feature-icon  { font-size: 1.2rem; color: var(--accent-orange); margin-bottom: 4px; }
.feature-text  { font-size: 0.75rem; color: var(--font-color); opacity: 0.6; line-height: 1.3; }
.home-main-col { flex: 1; min-width: 0; padding: 32px 24px; }

/* Confirm view */
.confirm-card-override    { height: auto !important; max-width: 700px; }
.confirm-success-icon     { font-size: clamp(3.5rem, 3.1rem + 1.7vw, 4.6rem); color: var(--accent-orange); }
.confirm-easter-egg-icon  { font-size: 3.5rem; }
.confirm-heading          { font-family: var(--heading-font); font-size: clamp(1.5rem, 1.28rem + .9vw, 1.95rem); font-weight: 700; color: var(--heading-color); margin-bottom: 6px; }
.confirm-subtext          { color: var(--font-color); opacity: 0.65; font-size: 0.9rem; }
.confirm-subtext-italic   { color: var(--font-color); opacity: 0.45; font-size: 0.78rem; font-style: italic; margin-bottom: 24px; }
/* Scannable ticket QR */
.confirm-qr-wrap          { display: flex; flex-direction: column; align-items: center; }
.confirm-qr-frame         { position: relative; display: inline-block; padding: 14px; background: #fff; border-radius: 16px; box-shadow: 0 6px 22px rgba(0,0,0,.10); border: 1px solid rgba(0,0,0,.06); color: var(--heading-color); }
.confirm-qr               { line-height: 0; }
.confirm-qr img,
.confirm-qr canvas        { display: block; border-radius: 4px; }
.confirm-qr-caption       { font-size: 0.72rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--font-color); opacity: 0.5; margin-top: 10px; }
/* After the session: desaturate + dim the pass, stamp it used */
.confirm-qr-wrap.is-expired .confirm-qr-frame { filter: grayscale(1); opacity: 0.45; }
.confirm-qr-expired-badge { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(-8deg); background: rgba(20,20,20,.82); color: #fff; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; padding: 6px 14px; border-radius: 8px; white-space: nowrap; }
/* Multi-slot order: one TAB per booking — its pass, its code, its calendar links.
   A pass and a calendar entry each describe one session, so the bookings are
   switched between rather than stacked. */
.confirm-tabs             { text-align: center; }
.confirm-tablist          { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-bottom: 22px; }
.confirm-tab              { display: flex; flex-direction: column; align-items: center; gap: 2px; background: transparent; border: 1px solid var(--border, rgba(0,0,0,.14)); border-radius: 12px; padding: 8px 18px; cursor: pointer; color: var(--font-color); transition: background .15s ease, border-color .15s ease, color .15s ease; }
.confirm-tab:hover        { border-color: var(--accent-orange); }
.confirm-tab:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 2px; }
.confirm-tab.is-active    { background: var(--accent-orange); border-color: var(--accent-orange); color: #fff; }
.confirm-tab-index        { font-size: 0.68rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.6; }
.confirm-tab.is-active .confirm-tab-index { opacity: 0.85; }
.confirm-tab-when         { font-size: 0.84rem; font-weight: 600; white-space: nowrap; }
.confirm-panel-heading    { display: none; margin-bottom: 14px; }
.confirm-tabpanel         { display: none; }
.confirm-tabpanel.is-active { display: block; }
.confirm-tabpanel:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 4px; border-radius: 12px; }
.confirm-code-label       { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--font-color); opacity: 0.45; margin-bottom: 8px; }
.confirm-code-pill        { display: inline-block; background: var(--accent-orange); color: #fff; font-size: 1.15rem; letter-spacing: 3px; font-family: 'Courier New', monospace; border-radius: 50px; padding: 8px 24px; white-space: nowrap; }
.confirm-code-note        { font-size: 0.75rem; color: var(--font-color); opacity: 0.45; margin-top: 8px; max-width: 320px; }
.confirm-detail-wrap      { max-width: 460px; text-align: left; }
.confirm-table            { color: var(--font-color); font-size: 0.88rem; }
.confirm-table-label      { width: 38%; opacity: 0.6; text-align: right; padding-right: 16px; }
.confirm-table-label-no-width { opacity: 0.6; text-align: right; padding-right: 16px; }
.confirm-total-amt        { color: var(--accent-orange); font-size: 1.05rem; }
.confirm-btn-sm           { font-size: 0.85rem; }
.confirm-location-sub     { opacity: 0.65; font-size: 0.8rem; }
.confirm-whats-next       { background: rgba(238,81,58,0.06); border: 1px solid rgba(238,81,58,0.18); max-width: 460px; text-align: left; }
.confirm-whats-next-heading { font-size: 0.8rem; font-weight: 700; color: var(--heading-color); margin-bottom: 10px; }
.confirm-whats-next-icon  { color: var(--accent-orange); }
.confirm-whats-next-list  { list-style: none; padding: 0; margin: 0; font-size: 0.8rem; color: var(--font-color); opacity: 0.75; }
.confirm-create-acct      { background: rgba(6,5,80,0.04); border: 1px solid rgba(6,5,80,0.1); max-width: 460px; }
.confirm-acct-eyebrow     { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--font-color); opacity: 0.4; margin-bottom: 6px; }
.confirm-acct-heading     { font-family: var(--heading-font); font-size: 1rem; font-weight: 700; color: var(--heading-color); margin-bottom: 6px; }
.confirm-acct-subtext     { font-size: 0.8rem; color: var(--font-color); opacity: 0.6; margin-bottom: 16px; line-height: 1.5; }
.confirm-acct-note        { font-size: 0.72rem; color: var(--font-color); opacity: 0.35; margin-top: 10px; }
.confirm-acct-sign-in     { color: var(--accent-orange); text-decoration: none; }

/* Confirmation sidebar — My Reservation / My Order Summary / account CTA */
.confirm-sidebar          { display: flex; flex-direction: column; gap: 18px; }
@media (min-width: 992px) {
    .confirm-sidebar      { position: sticky; top: 18px; }
}
/* Reset the fixed-height/centred .location-card geometry for stacked side cards */
.confirm-side-card.location-card { height: auto; max-width: none; width: 100%; margin: 0; padding: 22px 22px; border: 1px solid var(--border, rgba(0,0,0,.08)); }
.confirm-side-card.confirm-create-acct { max-width: none; }
.confirm-side-head        { font-family: var(--heading-font); font-size: 0.78rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--heading-color); opacity: 0.85; margin-bottom: 14px; }
/* My Reservation definition list */
.confirm-side-dl          { margin: 0; }
.confirm-side-dl dt       { font-size: 0.68rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--font-color); opacity: 0.4; margin-top: 12px; }
.confirm-side-dl dt:first-child { margin-top: 0; }
.confirm-side-dl dd       { font-size: 0.9rem; font-weight: 600; color: var(--font-color); margin: 2px 0 0; }
/* Receipt rows */
.confirm-receipt-rows     { display: flex; flex-direction: column; gap: 8px; }
.confirm-receipt-row      { display: flex; justify-content: space-between; gap: 12px; font-size: 0.86rem; color: var(--font-color); opacity: 0.85; }
.confirm-receipt-row span:last-child { font-variant-numeric: tabular-nums; white-space: nowrap; }
.confirm-receipt-sub      { padding-top: 8px; margin-top: 2px; border-top: 1px dashed var(--border, rgba(0,0,0,.12)); font-weight: 600; opacity: 1; }
.confirm-receipt-discount span { color: var(--accent-green, #2cb6a7); }
.confirm-receipt-total    { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; margin-top: 12px; padding-top: 12px; border-top: 2px solid var(--border, rgba(0,0,0,.14)); font-family: var(--heading-font); font-weight: 700; color: var(--heading-color); }
.confirm-receipt-total span:last-child { font-size: 1.1rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.confirm-receipt-foot     { font-size: 0.72rem; color: var(--font-color); opacity: 0.45; margin-top: 14px; }
/* Multi-booking orders — one block per booking in the sidebar and again in the
   receipt. Only ever emitted when an order has 2+ bookings, so a single
   booking renders byte-for-byte as it always has. */
.confirm-leg-head         { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; padding-bottom: 8px; margin-bottom: 12px; border-bottom: 1px dashed var(--border, rgba(0,0,0,.12)); }
.confirm-leg-head.mt-4    { padding-top: 16px; border-top: 1px solid var(--border, rgba(0,0,0,.10)); }
.confirm-leg-index        { font-family: var(--heading-font); font-size: 0.72rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--heading-color); }
.confirm-leg-code         { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.04em; color: var(--font-color); opacity: 0.5; font-variant-numeric: tabular-nums; white-space: nowrap; }
.confirm-receipt-leg      { display: flex; flex-direction: column; gap: 6px; }
.confirm-receipt-leg-head { font-size: 0.68rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--font-color); opacity: 0.4; }

/* The .auth-* block that used to sit here retired 2026-08-29: /auth/* moved to
   the neutral, scheme-aware system in account.css. Its accent came from
   hardcoded rgba(238,81,58,…) literals, which are theme-default's orange — on
   any of the other 23 microsite themes the focus ring and the icon plate did
   not match the buttons beside them. */

/* Password meter — live requirements + advisory strength bar.
   @see resources/views/auth/_password-meter.blade.php
   The requirement rows carry their state as an ICON SHAPE as well as a
   colour (dot -> tick -> cross) plus a visually-hidden word, so the meter
   still reads correctly with no colour perception at all. */
.pw-meter                 { margin-top: 8px; }
.pw-meter-strength        { display: flex; align-items: center; gap: 10px; }
.pw-meter-bar             { display: flex; gap: 4px; flex: 1 1 auto; }
.pw-meter-seg             { flex: 1 1 0; height: 4px; border-radius: 2px; background: var(--border, rgba(0,0,0,0.12)); transition: background-color 0.18s ease; }
.pw-meter-seg[data-pw-on="1"]                       { background: var(--accent-orange); }
.pw-meter-bar[data-pw-level="1"] .pw-meter-seg[data-pw-on="1"] { background: #d9534f; }
.pw-meter-bar[data-pw-level="2"] .pw-meter-seg[data-pw-on="1"] { background: #e0a340; }
.pw-meter-bar[data-pw-level="3"] .pw-meter-seg[data-pw-on="1"],
.pw-meter-bar[data-pw-level="4"] .pw-meter-seg[data-pw-on="1"] { background: var(--accent-green, #2cb6a7); }
.pw-meter-verdict         { margin: 0; font-size: 0.72rem; white-space: nowrap; color: var(--font-color); opacity: 0.7; }
.pw-meter-verdict-label   { opacity: 0.6; }
.pw-meter-verdict-label::after { content: ':'; }
.pw-req-list              { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.pw-req                   { display: flex; align-items: center; gap: 7px; font-size: 0.74rem; color: var(--font-color); opacity: 0.6; }
.pw-req-icon              { font-size: 0.5rem; width: 12px; text-align: center; }
.pw-req[data-pw-state="met"]  { opacity: 1; color: var(--accent-green, #2cb6a7); }
.pw-req[data-pw-state="fail"] { opacity: 1; color: #d9534f; }
.pw-req[data-pw-state="met"] .pw-req-icon,
.pw-req[data-pw-state="fail"] .pw-req-icon { font-size: 0.78rem; }
.pw-meter-note            { margin: 8px 0 0; font-size: 0.72rem; color: var(--font-color); opacity: 0.5; line-height: 1.4; }

@media (prefers-reduced-motion: reduce) {
    .pw-meter-seg { transition: none; }
}

/* Password meter — dark mode. The three .auth-card rules that used to lead this
   block went with the .auth-* block above.
   ⚠ These stay, but on today's three callers (signup, reset, account security —
   all inside .acct) they are overridden by account.css §26. Both selectors are
   two classes, so the tie is broken by LOAD ORDER, and account.css is stacked
   after booking.css. Reorder those two links and the meter goes back to the
   studio palette on a neutral card. */
.mode-dark .pw-meter-seg                 { background: rgba(255,255,255,0.14); }
.mode-dark .pw-meter-verdict,
.mode-dark .pw-req,
.mode-dark .pw-meter-note                { color: var(--font-dark-color); }
.mode-dark .pw-req[data-pw-state="met"]  { color: var(--accent-green, #2cb6a7); }
.mode-dark .pw-req[data-pw-state="fail"] { color: #f08b87; }
.mode-dark .pw-meter-bar[data-pw-level="1"] .pw-meter-seg[data-pw-on="1"] { background: #f08b87; }

@media (max-width: 767px) {
    .cfg-sidebar { display: none; }
}

/* ==========================================================================
   Dark Mode — Booking-specific component overrides
   Mirrors the .mode-dark pattern from version3.findyourpictures.com.
   All new components added since the core booking.css was branched from
   version3 need explicit overrides here — var(--bg-color) and
   var(--heading-color) do not switch automatically in dark mode.
   ========================================================================== */

/* ---- Home page card backgrounds ---- */
.mode-dark .banner-card { background: var(--bg-dark-secondary); }
.mode-dark .grid-card   { background-color: var(--bg-dark-secondary) !important; }
.mode-dark .list-card   { background: var(--bg-dark-secondary) !important; }

/* ---- Home page card text ---- */
.mode-dark .card-title,
.mode-dark .card-title-sm,
.mode-dark .card-title-xs  { color: var(--heading-dark-color); }
.mode-dark .card-desc,
.mode-dark .card-desc-sm,
.mode-dark .card-desc-list { color: var(--font-dark-color); }
.mode-dark .card-duration  { color: var(--font-dark-color); opacity: 0.45; }
.mode-dark .card-price     { color: var(--heading-dark-color); }

/* ---- Config sidebar ---- */
.mode-dark .cfg-sidebar       { background: var(--bg-dark-secondary); border-color: rgba(255,255,255,0.08); }
.mode-dark .cfg-section-label,
.mode-dark .cfg-label         { color: var(--font-dark-color); opacity: 0.5; }
.mode-dark .radio-opt         { color: var(--font-dark-color); }

/* ---- Booking card service header ---- */
.mode-dark .svc-name { color: var(--heading-dark-color); }
.mode-dark .svc-meta { color: var(--font-dark-color); }

/* ---- Month navigation ---- */
.mode-dark .month-heading { color: var(--heading-dark-color); }
.mode-dark .month-subtext { color: var(--font-dark-color); }
.mode-dark .month-nav     { border-color: rgba(255,255,255,0.15); color: var(--font-dark-color); }

/* ---- Time/date headings & navigation ---- */
.mode-dark .date-heading { color: var(--heading-dark-color); }
.mode-dark .time-heading { color: var(--heading-dark-color); }
.mode-dark .back-btn     { color: var(--font-dark-color); }

/* ---- Calendar picker cells ---- */
.mode-dark .cal-dow-row .cal-dow             { color: var(--font-dark-color); }
.mode-dark .cal-pick-day                     { color: var(--font-dark-color); }
.mode-dark .cal-pick-day.available           { color: var(--heading-dark-color); background: rgba(238,81,58,0.08); border-color: rgba(238,81,58,0.2); }
.mode-dark .cal-pick-day.available:hover     { background: rgba(238,81,58,0.15); }
.mode-dark .cal-pick-day.available.selected  { background: var(--accent-orange); border-color: var(--accent-orange); color: #fff; }
/* Availability tints (dark) — match the legend key */
.mode-dark .cal-pick-day.available[data-level="high"]         { background: rgba(44,182,167,0.22); border-color: rgba(44,182,167,0.5); }
.mode-dark .cal-pick-day.available[data-level="high"]:hover   { background: rgba(44,182,167,0.34); }
.mode-dark .cal-pick-day.available[data-level="medium"]       { background: rgba(245,158,11,0.24); border-color: rgba(245,158,11,0.55); }
.mode-dark .cal-pick-day.available[data-level="medium"]:hover { background: rgba(245,158,11,0.36); }
.mode-dark .cal-pick-day.available[data-level="low"]          { background: rgba(220,38,38,0.22);  border-color: rgba(220,38,38,0.5); }
.mode-dark .cal-pick-day.available[data-level="low"]:hover    { background: rgba(220,38,38,0.34); }
.mode-dark .cal-pick-day.available.selected,
.mode-dark .cal-pick-day.available.selected[data-level]       { background: var(--accent-orange); border-color: var(--accent-orange); color: #fff; }
.mode-dark .cal-legend                       { color: var(--font-dark-color); }

/* ---- Time slot pickers ---- */
.mode-dark .hour-block            { background: var(--bg-dark-secondary); border-color: rgba(255,255,255,0.1); }
.mode-dark .hour-block.expanded   { border-color: var(--accent-orange); background: rgba(238,81,58,0.08); }
.mode-dark .hour-label            { color: var(--heading-dark-color); }
.mode-dark .hour-avail-norm       { color: var(--font-dark-color); }
.mode-dark .hour-chevron          { color: var(--font-dark-color); }
.mode-dark .hour-legend           { color: var(--font-dark-color); border-color: rgba(255,255,255,0.1); }
.mode-dark .hour-slots            { background: rgba(238,81,58,0.06); }
.mode-dark .hour-slots-label      { color: var(--font-dark-color); }
.mode-dark .slot-chip             { background: var(--bg-dark-secondary); border-color: rgba(255,255,255,0.1); color: var(--font-dark-color); }
.mode-dark .slot-chip.selected    { background: var(--accent-orange); border-color: var(--accent-orange); color: #fff; }

/* ---- Main area below secondary nav ---- */
.mode-dark .main-area             { background: var(--bg-dark-color); }
.mode-dark .active-product-heading { color: var(--heading-dark-color); }
.mode-dark .active-product-subtext { color: var(--font-dark-color); }
.mode-dark .panel-heading         { color: var(--heading-dark-color); }
.mode-dark .panel-subtext         { color: var(--font-dark-color); }

/* ---- Package cards + text ---- */
.mode-dark .pkg-card                  { background-color: var(--bg-dark-secondary) !important; border-color: rgba(255,255,255,0.1) !important; box-shadow: 0 1px 4px rgba(0,0,0,0.22); }
.mode-dark .pkg-name,
.mode-dark .pkg-name-sm               { color: var(--heading-dark-color); }
.mode-dark .pkg-price,
.mode-dark .pkg-price-sm              { color: var(--heading-dark-color); }
.mode-dark .pkg-desc,
.mode-dark .pkg-desc-sm               { color: var(--font-dark-color); }
.mode-dark .pkg-inclusion-item        { color: var(--font-dark-color); }
.mode-dark .pkg-includes li,
.mode-dark .pkg-includes-sm li        { color: var(--font-dark-color); }

/* ---- Addon cards + text ---- */
.mode-dark .addon-sheet-card          { background: var(--bg-dark-secondary); border-color: rgba(255,255,255,0.1); }
.mode-dark .addon-sheet-card.selected { border-color: var(--accent-orange); }
.mode-dark .generic-card              { background: var(--bg-dark-secondary); border-color: rgba(255,255,255,0.1); }
.mode-dark .generic-card.selected     { border-color: var(--accent-orange); }
.mode-dark .addon-name                { color: var(--heading-dark-color); }
.mode-dark .addon-price               { color: var(--heading-dark-color); }
.mode-dark .addon-desc                { color: var(--font-dark-color); }

/* ---- Addons bar + sheet chrome ---- */
.mode-dark .addons-bar                { background: rgba(255,255,255,0.06); border-color: rgba(255,255,255,0.1); }
.mode-dark .addons-bar-total          { color: var(--heading-dark-color); }
.mode-dark .addons-bar-label          { color: var(--font-dark-color); }
.mode-dark .addons-bar-breakdown      { color: var(--font-dark-color); opacity: 0.8; }
.mode-dark .sheet-header              { border-color: rgba(255,255,255,0.1); }
.mode-dark .sheet-footer              { background: var(--bg-dark-secondary); border-color: rgba(255,255,255,0.1); }

/* ---- Cart panel text ---- */
.mode-dark .cart-pkg-name             { color: var(--heading-dark-color); }
.mode-dark .cart-pkg-price            { color: var(--heading-dark-color); }
.mode-dark .cart-saved-name           { color: var(--heading-dark-color); }
.mode-dark .cart-saved-meta           { color: var(--font-dark-color); }
.mode-dark .cart-saved-subtotal       { color: var(--font-dark-color); }
.mode-dark .cart-addon-remove         { color: var(--font-dark-color); }
.mode-dark .cart-saved-divider        { border-color: rgba(255,255,255,0.1); }
.mode-dark .cart-saved-item:not(:last-of-type) { border-color: rgba(255,255,255,0.1); }
.mode-dark .cart-current-experience   { color: var(--heading-dark-color); }
.mode-dark .cart-current-location     { color: var(--font-dark-color); }
.mode-dark .cart-order-note           { color: var(--font-dark-color); }
.mode-dark .sidebar-addon-name        { color: var(--font-dark-color); }
.mode-dark .sidebar-addon-price       { color: var(--font-dark-color); }

/* ---- Checkout labels + form ---- */
.mode-dark .checkout-label                  { color: var(--font-dark-color); }
.mode-dark .checkout-step-subtext--donation { color: var(--font-dark-color); }
.mode-dark .checkout-reassurance            { color: var(--font-dark-color); }
.mode-dark .checkout-terms-label            { color: var(--font-dark-color); }

/* ---- Order summary card ---- */
.mode-dark .summary-section-label           { color: var(--font-dark-color); opacity: 0.45; }
.mode-dark .summary-location-name           { color: var(--heading-dark-color); }
.mode-dark .summary-location-city           { color: var(--font-dark-color); }
.mode-dark .summary-slot-date               { color: var(--font-dark-color); }
.mode-dark .summary-slot-time               { color: var(--font-dark-color); }
.mode-dark .summary-package-name            { color: var(--heading-dark-color); }
.mode-dark .summary-package-service         { color: var(--font-dark-color); }
.mode-dark .summary-gst-note                { color: var(--font-dark-color); }
.mode-dark .summary-line .lbl               { color: var(--font-dark-color); }
.mode-dark .summary-line .amt               { color: var(--font-dark-color); }
.mode-dark .summary-line.total .lbl         { color: var(--heading-dark-color); }
.mode-dark .summary-divider                 { border-color: rgba(255,255,255,0.1); }
.mode-dark .summary-booking                 { background: rgba(255,255,255,0.035); border-color: rgba(255,255,255,0.1); }
.mode-dark .summary-booking__head           { border-bottom-color: rgba(255,255,255,0.1); }
.mode-dark .summary-booking__title          { color: var(--heading-dark-color); }
.mode-dark .summary-booking__remove         { color: var(--font-dark-color); }
.mode-dark .summary-booking--current        { border-color: var(--accent-orange); }
.mode-dark .summary-line.total.summary-booking__total .amt { color: var(--heading-dark-color); }
.mode-dark .summary-order-total             { border-top-color: rgba(255,255,255,0.16); }

/* ---- Secondary nav (on dark sticky bar) ---- */
.mode-dark #selectedSlotBarPackages { background: var(--bg-dark-color); border-color: rgba(255,255,255,0.08); }
.mode-dark .secondary-date  { color: var(--font-dark-color); }
.mode-dark .countdown-wrap  { color: var(--font-dark-color); }
.mode-dark .countdown-val   { color: var(--font-dark-color); }

/* ---- Cart panel ---- */
.mode-dark .cart-panel      { background: var(--bg-dark-secondary); }
.mode-dark .cart-title      { color: var(--heading-dark-color); }
.mode-dark .cart-total-lbl  { color: var(--heading-dark-color); }
.mode-dark .cart-slot-line  { color: var(--font-dark-color); border-color: rgba(255,255,255,0.1); }

/* ---- Addon sheet (slide-up) ---- */
.mode-dark .addons-sheet    { background: var(--bg-dark-secondary); }
.mode-dark .sheet-title     { color: var(--heading-dark-color); }
.mode-dark .sheet-subtext   { color: var(--font-dark-color); }
.mode-dark .sheet-total     { color: var(--heading-dark-color); }

/* ---- Nudge modal ---- */
.mode-dark .nudge-card      { background: var(--bg-dark-secondary); }
.mode-dark .nudge-headline  { color: var(--heading-dark-color); }
.mode-dark .nudge-body      { color: var(--font-dark-color); }
.mode-dark .nudge-skip-btn  { color: var(--font-dark-color); }



/* ============================================================
   Booking Page SHOWCASE layout (Showcase build, Phase 5)
   The album_select-style location page: two background zones
   (top + services), a hero/details location card, sponsor card,
   confidence badges and a footer. Opt-in; Standard is untouched.
   ============================================================ */
.sc-zone               { width: 100%; }
/* CP15 — explicit top-padding:0 so the top area meets the page top with no gap. */
.sc-zone-top           { padding-top: 0; padding-bottom: 8px; }
.sc-page               { display: block; }
/* The site footer (Locations | Manage Booking) sits below the showcase — give it
   room to clear the fixed progress bar so it stays visible. */
body:has(.sc-page) #footer { padding-bottom: 84px; }
/* Services zone: no top padding (the secondary nav sits flush at the very top),
   and — like FYP's #main — paints the plain theme body color by default (NOT the
   storefront pattern behind it). A photographer-set color/image overrides via the
   inline style. */
.sc-zone-services      { padding-top: 0; background-color: var(--bg-color); }
.mode-dark .sc-zone-services { background-color: var(--bg-dark-color); }
/* Banner caps at the location card's width (720px) so the two line up. */
.sc-banner             { max-width: min(720px, 100%); max-height: 160px; object-fit: contain; }
/* Page logo at the very top of the page (mirrors the sticky menu-bar logo). */
.sc-page-logo          { padding: 18px 0 6px; }
.sc-page-logo img      { max-height: 60px; max-width: 70%; object-fit: contain; display: inline-block; }

.sc-location-card      { max-width: 720px; margin: 0 auto; border-radius: 16px; overflow: hidden; border: none;
                         background: var(--bg-color); color: var(--font-color); }
.mode-dark .sc-location-card { background: var(--bg-dark-color); color: var(--font-dark-color); }
/* Hero column is the positioning context; the image is absolutely filled so
   "cover" truly covers the whole left side of the card (the col is flex-stretched
   to the taller details column). */
.sc-hero-col           { position: relative; min-height: 240px; overflow: hidden; }
.sc-hero               { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* Desktop / mobile hero swap (the card restacks on phones). */
.sc-hero--mobile       { display: none; }
@media (max-width: 767.98px) {
    .sc-hero-col       { min-height: 220px; }
    .sc-hero--desktop  { display: none; }
    .sc-hero--mobile   { display: block; }
}
/* Force the whole details column left-aligned — the storefront theme centers
   <h1>/headings globally, which made the title + address read centered while the
   detail text and rows stayed left (looked mis-aligned). */
.sc-details            { padding: 24px 28px; text-align: left; }
.sc-loc-name           { font-size: clamp(1.35rem, 1.18rem + 0.72vw, 1.6rem); margin: 0 0 6px; color: var(--heading-color, var(--font-color)); text-align: left; }
.sc-loc-city           { font-size: 0.9rem; opacity: 0.7; margin-bottom: 10px; text-align: left; }
.sc-details .sc-loc-detail, .sc-details .sc-loc-rows, .sc-details .sc-loc-avail { text-align: left; }
/* Bulletproof: a storefront theme may center the card heading via a
   higher-specificity rule OR via flex align-items:center on the column. Force
   left on both axes, !important, so the title/address can't drift centered. */
.sc-location-card .sc-details { text-align: left !important; align-items: flex-start !important; }
.sc-location-card .sc-details > * { text-align: left !important; align-self: stretch !important; }
.sc-loc-detail         { font-size: 0.92rem; line-height: 1.6; opacity: 0.85; }
/* Optional location-card detail rows (Where to find us / Directions / Parking /
   Please note / Extra details) — each toggled in admin. */
.sc-loc-rows           { border-top: 1px solid rgba(127,127,127,0.18); }
.sc-loc-row            { padding: 9px 0; border-bottom: 1px solid rgba(127,127,127,0.12); }
.sc-loc-row-label      { font-size: 0.7rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; opacity: 0.6; }
.sc-loc-row-val        { font-size: 0.9rem; line-height: 1.5; opacity: 0.9; margin-top: 2px; }
.sc-loc-row-extra      { opacity: 0.85; }
.sc-loc-avail          { font-size: 0.82rem; opacity: 0.85; display: flex; align-items: center; gap: 6px; }

/* Scroll-triggered secondary nav (FYP album_select parity) — hamburger ·
   centered logo · account action. Hidden at top, slides in on scroll. */
/* Affixed to the top of the services zone, then sticky as you scroll past it. */
.sc-secondary-nav {
    position: sticky; top: 0; z-index: 1030;
    background-color: var(--bg-color);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.14);
}
.sc-secondary-nav__inner {
    display: flex; align-items: center; gap: 12px;
    max-width: 1100px; margin: 0 auto; padding: 8px 16px;
}
.sc-secondary-nav__btn {
    background: none; border: 0; padding: 6px; line-height: 1;
    font-size: 1.15rem; color: var(--font-color); text-decoration: none;
}
.sc-secondary-nav__logo {
    flex: 1; text-align: center; text-decoration: none;
    color: var(--heading-color); font-weight: 700; font-size: 1.05rem;
}
.sc-secondary-nav__logo img { max-height: 40px; max-width: 60%; object-fit: contain; display: inline-block; }

/* Enhanced Showcase: the TOP background reaches the very top of the page —
   the storefront nav overlays it transparently (FYP album_select parity).
   Scoped via :has(#scSecondaryNav) so only the Enhanced page is affected;
   the Standard/Basic pages are untouched. */
body:has(#scSecondaryNav) #company-logo-container {
    position: absolute; top: 0; left: 0; right: 0; z-index: 4;
    background: transparent !important; box-shadow: none;
    /* Bootstrap's .navbar adds --bs-navbar-padding-y: .5rem which pushed the logo
       down off the very top — zero it so the logo sits flush at the top. */
    --bs-navbar-padding-y: 0; padding-top: 0;
}
body:has(#scSecondaryNav) main { padding-top: 0 !important; }
/* CP15 — no top gap: the top-area (banner / location card) background must meet
   the page/top at the very top with no stray empty band. Zero the top padding so
   the top zone sits flush (mirrors the admin showcase preview .sc-zone-top /
   .sc-zone-services top-padding:0 fix). The transparent storefront logo overlays
   the top zone (FYP album_select parity), so no clearance padding is needed. */
body:has(#scSecondaryNav) .sc-zone-top { padding-top: 0; }

/* Booking-flow pages inherit the booking-page background (felt) but have no
   #scSecondaryNav, so the navbar kept Bootstrap's .5rem top padding — that's the
   gap above the logo. Sit it flush like the landing does. */
body.has-storefront-bg:not(:has(#scSecondaryNav)) #company-logo-container {
    --bs-navbar-padding-y: 0; padding-top: 0;
}

/* Booking-flow content column — matched to the landing page's SERVICE-CARD grid,
   which is the surface the customer was looking at one click earlier.

   ⚠ 900px IS A MEASUREMENT, NOT A TASTE CALL. locations/_service_cards wraps the
   grid family (grid + compact) at max-width:900px, so a 720px booking column made
   the page NARROW as the customer moved forward — pick a service on a 900px grid,
   land on a 720px calendar. 900 is the widest the landing ever goes, so this is
   "at least as wide" for every service_card_layout: banner and list cap at 640 and
   are unaffected by the comparison.

   ⚠ It also closes the other end. Add-ons and configure already pass shell_wide
   (1180px, below), so the flow ran 720 → 1180 with nothing in between; this is the
   one step that made that jump look like two different sites.

   Only .bk-content-col's BASE width changes here, and only two surfaces read it:
   the single-page calendar flow and /book/package. Every other step passes the
   --wide variant and is untouched.

   Was 720px until 2026-09-02, chosen to match the landing's .location-card. That
   card is the LOGIN/entry card (655px + a fixed 456px height), not the service
   grid — so the number it was matched to was never the surface it sits next to. */
.bk-content-col { max-width: 900px; }

/* ── ALERTS — the platform shell ──────────────────────────────────────────
   Bootstrap's .alert stays the structural base (position, padding, dismiss
   button, the variant class names) and this block only re-points the
   --bs-alert-* variables it reads. That is the whole reason it is one block:
   every alert in the app inherits it with no call site touched, so the family
   cannot drift view by view. booking.css loads AFTER the Bootstrap bundle, so
   at equal specificity these beat .alert-success and friends.

   THE SURFACE IS THE STUDIO'S; THE MEANING IS THE PLATFORM'S.
   · Surface and body text come from the active microsite palette, so an alert
     reads as part of the page on any of the 24 themes rather than as stock
     Bootstrap dropped on top of one.
   · The semantic accent is a FIXED colour, for exactly the reason .bk-tone--*
     above is fixed: a warning must not turn gold on theme-navy because the
     studio's accent is gold, and on the gold and deep-red palettes every
     variant would otherwise collapse into one indistinguishable colour.
   · The accent is only ever the RAIL and the ICON — never body text. Text stays
     on --font-color, which each palette guarantees against its own surface, so
     no theme swap can break contrast. The alert's meaning is always written out
     in words, so colour is never the sole signal (WCAG 1.4.1).

   ⚠ THE SURFACE IS OPAQUE ON PURPOSE — mixed INTO --bg-light-secondary, never
   toward `transparent`. A studio may paint a photograph behind the entire flow
   (the cover/fixed background in layouts/app.blade.php), and a translucent tint
   puts body copy straight onto that photograph. Same call, same reason, as
   --bk-loc-surface above; color-mix() is the upgrade and the plain declaration
   is the baseline, so nothing depends on the mix landing. */
:root {
    --bk-alert-info:    #3f6bb5;  /* muted slate — an aside, not a hyperlink blue */
    --bk-alert-success: #12916a;
    --bk-alert-warning: #b45309;  /* the amber .bk-tone--limited already uses */
    --bk-alert-danger:  #be2f36;
    --bk-alert-neutral: #475569;  /* the slate .bk-tone--closed already uses */
}

.alert,
.bk-notice-alert {
    --bk-alert-accent:  var(--bk-alert-neutral);
    --bk-alert-surface: var(--bg-light-secondary, #fff);
    --bk-alert-line:    rgba(128, 128, 128, 0.22);

    /* Consumed by Bootstrap's own .alert declarations. */
    --bs-alert-bg:            var(--bk-alert-surface);
    --bs-alert-color:         var(--font-color);
    --bs-alert-border-color:  var(--bk-alert-line);
    --bs-alert-border-radius: 14px;
    --bs-alert-padding-x:     16px;
    --bs-alert-padding-y:     14px;
    --bs-alert-link-color:    var(--bk-alert-accent);

    /* Spelled out as well, because .bk-notice-alert is NOT a Bootstrap .alert
       and reads none of the variables above. On .alert these restate what
       Bootstrap computes from them — identical result, one shell. */
    background-color: var(--bk-alert-surface);
    color: var(--font-color);
    border: 1px solid var(--bk-alert-line);
    border-left: 3px solid var(--bk-alert-accent);
    border-radius: 14px;
    padding: 14px 16px;
    box-shadow: var(--bk-loc-rest);
    font-size: 0.94rem;
}
@supports (color: color-mix(in srgb, red, blue)) {
    .alert,
    .bk-notice-alert {
        --bk-alert-surface: color-mix(in srgb, var(--bk-alert-accent)  7%, var(--bg-light-secondary, #fff));
        --bk-alert-line:    color-mix(in srgb, var(--bk-alert-accent) 30%, var(--bg-light-secondary, #fff));
    }
}

/* The photographer's own booking notice keeps the STUDIO accent — it is their
   copy in their voice, not a platform status message. Everything else about it
   (surface, rail, radius, shadow, type) is the shared shell above. Declared
   BEFORE the modifiers so --bk-notice-alert--info can still override it. */
.bk-notice-alert { --bk-alert-accent: var(--accent-orange); }

.alert-info,      .bk-notice-alert--info    { --bk-alert-accent: var(--bk-alert-info); }
.alert-success,   .bk-notice-alert--success { --bk-alert-accent: var(--bk-alert-success); }
.alert-warning,   .bk-notice-alert--warning { --bk-alert-accent: var(--bk-alert-warning); }
.alert-danger,    .bk-notice-alert--danger  { --bk-alert-accent: var(--bk-alert-danger); }
.alert-primary                              { --bk-alert-accent: var(--heading-color); }
.alert-secondary, .alert-light, .alert-dark { --bk-alert-accent: var(--bk-alert-neutral); }

.alert i,
.bk-notice-alert i        { color: var(--bk-alert-accent); }
.alert strong             { color: var(--heading-color); }
.alert a:not(.btn)        { color: var(--bk-alert-accent); font-weight: 700; }
.alert > :last-child      { margin-bottom: 0; }
.alert .btn-close         { opacity: 0.45; }
.alert .btn-close:hover   { opacity: 0.9; }
.mode-dark .alert,
.mode-dark .bk-notice-alert { color: var(--font-dark-color); }

/* Footer promo (booking-page freeform) — a centered band at the bottom of the
   flow, not crammed into the location-info card. */
.bk-footer-promo { max-width: 720px; margin: 8px auto 0; text-align: center; }

/* Scroll-down cue at the bottom of the Enhanced top zone. */
.sc-scroll-cue { padding: 8px 0 20px; }
.sc-scroll-cue__btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; border-radius: 50%;
    background: rgba(255, 255, 255, 0.18); color: #fff; text-decoration: none;
    border: 1px solid rgba(255, 255, 255, 0.35);
    animation: sc-cue-bounce 1.8s ease-in-out infinite;
}
.sc-scroll-cue__btn:hover { background: rgba(255, 255, 255, 0.3); color: #fff; }
@keyframes sc-cue-bounce { 0%,100% { transform: translateY(0); } 50% { transform: translateY(5px); } }
@media (prefers-reduced-motion: reduce) { .sc-scroll-cue__btn { animation: none; } }

.sc-sponsor            { max-width: 720px; border-radius: 14px;
                         border: 1px solid var(--border-muted, rgba(0,0,0,0.08)); background: var(--bg-color); }
.mode-dark .sc-sponsor { background: var(--bg-dark-color); border-color: rgba(255,255,255,0.10); }
.sc-sponsor-logo       { max-height: 70px; max-width: 80%; object-fit: contain; }
/* Image-only sponsor: NO card chrome — the graphic stands on its own (no white
   backfill, border, or shadow), filling edge-to-edge (FYP donation-banner style). */
.sc-sponsor--image { background: transparent; border: none; box-shadow: none; }
.mode-dark .sc-sponsor--image { background: transparent; }
.sc-sponsor--image .card-body { padding: 0; }
.sc-sponsor-logo--full { display: block; width: 100%; height: auto; max-width: 100%; max-height: 220px; object-fit: contain; margin: 0; }
.sc-sponsor-name       { font-weight: 600; font-size: 1rem; color: var(--font-color); }
.mode-dark .sc-sponsor-name { color: var(--font-dark-color); }
.sc-sponsor-text       { font-size: 0.85rem; opacity: 0.75; margin-top: 4px; }
.sc-sponsor-link       { font-size: 0.82rem; text-decoration: none; display: inline-block; margin-top: 8px;
                         color: var(--prepaid-font-color, var(--accent-color)); }

/* "Share this page" row (opt-in show_share_card) — ported from the FYP
   album_select gallery-share row, themed with the storefront tokens. */
.sc-share-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.35rem 0.5rem; }
.sc-share-label { font-weight: 600; font-size: 0.95rem; color: var(--font-color); margin-right: 0.35rem; }
.mode-dark .sc-share-label { color: var(--font-dark-color); }
.sc-share-btns { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.4rem; }
.sc-share-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; padding: 0;
    border: 1px solid transparent; border-radius: 50%;
    background-color: rgba(0, 0, 0, 0.06); color: var(--font-color);
    cursor: pointer; font-size: 1.15rem; line-height: 1;
    transition: background-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease, color 0.15s ease;
}
.mode-dark .sc-share-btn { background-color: rgba(255, 255, 255, 0.10); color: var(--font-dark-color); }
.sc-share-btn:hover, .sc-share-btn:focus-visible {
    background-color: var(--accent-color); color: var(--font-white, #fff);
    transform: translateY(-2px);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--accent-color) 35%, transparent);
}
.sc-share-btn:focus-visible { outline: 2px solid var(--accent-color); outline-offset: 2px; }
.sc-share-toast {
    position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%) translateY(20px);
    background-color: var(--accent-green, #16a34a); color: #fff;
    font-weight: 600; font-size: 0.9rem; padding: 0.6rem 1.1rem; border-radius: 999px;
    box-shadow: 0 6px 22px rgba(0, 0, 0, 0.18);
    opacity: 0; pointer-events: none; z-index: 1080;
    transition: opacity 0.2s ease, transform 0.2s ease;
}
.sc-share-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Playful roll-out entrance — ported from the FYP album_select share row. The
   label pill grows in (scShareGrow) and the icons roll out within it, staggered
   (scShareRollIn), each starting as a filled accent circle that settles to the
   base look. JS adds .sc-share-armed (hidden) then .sc-share-run when in view. */
.sc-share-row.sc-share-armed { opacity: 0; transform: scale(0.82); }
.sc-share-row.sc-share-armed .sc-share-btn { opacity: 0; }
.sc-share-row.sc-share-run { animation: scShareGrow 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) backwards; }
@keyframes scShareGrow {
    0%   { opacity: 0; transform: scale(0.55); }
    60%  { opacity: 1; }
    100% { opacity: 1; transform: scale(1); }
}
.sc-share-row.sc-share-run .sc-share-btn {
    animation: scShareRollIn 0.62s cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
}
@keyframes scShareRollIn {
    0%   { opacity: 0; transform: translateX(-28px) rotate(-220deg) scale(0.4); background-color: var(--accent-color); color: var(--font-white, #fff); }
    55%  { opacity: 1; transform: translateX(0) rotate(0deg) scale(1.12);       background-color: var(--accent-color); color: var(--font-white, #fff); }
    78%  { transform: scale(1);                                                 background-color: var(--accent-color); color: var(--font-white, #fff); }
    100% { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    .sc-share-row.sc-share-armed,
    .sc-share-row.sc-share-run { opacity: 1; transform: none; animation: none; }
    .sc-share-row.sc-share-armed .sc-share-btn,
    .sc-share-row.sc-share-run .sc-share-btn { opacity: 1; animation: none; }
}

.sc-services-heading   { font-size: 1.3rem; font-weight: 600; color: var(--heading-color, var(--font-color)); }
.sc-services-sub       { font-size: 0.95rem; opacity: 0.7; color: var(--font-color); }
/* Confidence-badge strip gets padding/rounding so its own background (set in
   admin) reads as a panel; with no background it's transparent over the
   services area (which itself inherits the body theme color). */
/* Confidence band: full-bleed; its own background spans the full width. The
   badges themselves stay centered + capped. */
.sc-confidence-band    { width: 100%; padding: 26px 16px; }
.sc-confidence         { max-width: 560px; margin: 0 auto; }

/* Footer band: full-width block after the services content. */
.sc-footer-band        { width: 100%; padding: 28px 16px; }
.sc-footer             { padding: 28px 16px 90px; }
.sc-footer-img         { max-width: 100%; max-height: 120px; object-fit: contain; }
/* Opt-in full-size footer image (footer_image_fullsize): drop the height cap so a
   tall or long footer graphic renders at its natural size (e.g. a footer built to
   centre a logo on mobile). Width still can't exceed the page. */
.sc-footer-img--full   { max-height: none; }
.sc-footer-text        { font-size: 0.85rem; opacity: 0.7; color: var(--font-color); }
.mode-dark .sc-footer-text { color: var(--font-dark-color); }

@media (max-width: 767.98px) {
    .sc-hero    { max-height: 280px; }
    .sc-details { padding: 18px 20px; }
}

/* ==========================================================================
   Store-locator (/locations when bk_settings.locations_map_enabled = 1)
   WP-style split: filter bar → scrollable shop list + clustered Leaflet map.
   Uses the active theme tokens; falls back gracefully on unthemed pages.
   ========================================================================== */
.bk-locator {
    border: 1px solid var(--border-color, rgba(0,0,0,0.1));
    border-radius: 14px;
    overflow: hidden;
    background: var(--bg-color);
}
.bk-locator-filters {
    padding: 16px 18px;
    border-bottom: 1px solid var(--border-color, rgba(0,0,0,0.08));
    display: flex;
    flex-wrap: wrap;
    gap: 14px 22px;
    align-items: flex-end;
}
.bk-locator-search {
    display: flex;
    gap: 8px;
    flex: 1 1 280px;
    min-width: 240px;
}
.bk-locator-search .form-control { flex: 1 1 auto; }
.bk-locator-selects {
    display: grid;
    grid-template-columns: repeat(4, minmax(120px, 1fr));
    gap: 12px;
    flex: 2 1 520px;
}
.bk-locator-label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    margin-bottom: 3px;
    color: var(--font-color, #555);
    opacity: 0.8;
}

.bk-locator-body {
    display: flex;
    align-items: stretch;
    min-height: 560px;
}
.bk-locator-list {
    flex: 0 0 380px;
    max-width: 380px;
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--border-color, rgba(0,0,0,0.08));
}
.bk-locator-count {
    background: var(--accent-orange, #c62828);
    color: #fff;
    font-weight: 700;
    padding: 11px 18px;
    font-size: 14px;
}
.bk-locator-geo {
    padding: 8px 18px 0;
    margin: 0;
    color: var(--font-color, #555);
    opacity: 0.75;
}
.bk-locator-scroll {
    overflow-y: auto;
    flex: 1 1 auto;
    max-height: 620px;
}
.bk-locator-empty {
    padding: 28px 18px;
    text-align: center;
    color: var(--font-color, #777);
    opacity: 0.7;
}

.bk-shop {
    padding: 16px 18px;
    border-bottom: 1px solid var(--border-color, rgba(0,0,0,0.07));
    /* Rail reserved on every row so a closed one doesn't shift 3px sideways. */
    border-left: 3px solid transparent;
    transition: background 0.12s ease;
}
.bk-shop:hover { background: var(--bg-color, rgba(0,0,0,0.02)); }
/* Which kind of closed, on the rail — the same signal the three card grids
   carry, so scrolling this list reads the same as scanning one of them. */
.bk-shop.is-closed       { border-left-color: #475569; }
.bk-shop.is-tone-limited { border-left-color: #b45309; }
.bk-shop.is-tone-soon    { border-left-color: #1d4ed8; }
.bk-shop-head {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    cursor: pointer;
}
/* The locator list is a 380px column beside a map, so the logo chip is the one
   piece of artwork that fits here — a banner would leave no room for the
   address. `card_media` is a Location Finder block option; this surface has no
   block config, so it draws the icon the option defaults to. */
.bk-shop .bk-locmedia--icon { width: 38px; height: 38px; border-radius: 10px; }
.bk-shop-headtext {
    flex: 1 1 auto; min-width: 0;
    display: flex; flex-wrap: wrap; align-items: center;
    justify-content: space-between; gap: 8px;
}
.bk-shop-name {
    font-size: 1.02rem;
    font-weight: 700;
    margin: 0;
    color: var(--heading-color, #222);
    font-family: var(--heading-font);
}
.bk-shop-badge {
    flex-shrink: 0;
    font-size: 10.5px;
    font-weight: 600;
    padding: 3px 9px;
    border-radius: 999px;
    line-height: 1.4;
    white-space: nowrap;
    background: var(--bk-tone-bg);
    color: var(--bk-tone-ink);
}
.bk-shop .bk-locblurb { font-size: 12.5px; margin-top: 8px; -webkit-line-clamp: 2; }
.bk-shop-addr, .bk-shop-phone {
    display: flex;
    gap: 7px;
    margin-top: 6px;
    font-size: 13px;
    color: var(--font-color, #555);
    opacity: 0.82;
}
.bk-shop-addr i, .bk-shop-phone i { margin-top: 2px; color: var(--accent-orange, #c62828); }
.bk-shop-phone a { color: inherit; text-decoration: none; }
.bk-shop-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 9px;
}
.bk-shop-tag {
    font-size: 11px;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 6px;
    background: rgba(198,40,40,0.08);
    color: var(--accent-orange, #c62828);
    white-space: nowrap;
}
.bk-shop-tag i { margin-right: 4px; font-size: 9px; }
.bk-shop-distance {
    margin-top: 7px;
    font-size: 12px;
    font-weight: 600;
    color: var(--accent-orange, #c62828);
}
.bk-shop-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    margin-top: 12px;
}
.bk-shop-actions .btn { font-size: 12.5px; padding: 4px 12px; }

.bk-locator-map { flex: 1 1 auto; min-width: 0; }
#locationsMap { width: 100%; height: 100%; min-height: 560px; }

/* Leaflet popup actions */
.bk-pop-actions { margin-top: 9px; display: flex; gap: 10px; flex-wrap: wrap; }
.bk-pop-actions a {
    font-size: 12px; font-weight: 600;
    color: var(--accent-orange, #c62828); text-decoration: none;
}
.bk-pop-actions a:hover { text-decoration: underline; }

/* "Open locations only" switch — sits on the filter bar next to the selects. */
.bk-locator-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 38px;
    flex: 0 0 auto;
    padding-left: 0;
    margin-bottom: 0;
}
.bk-locator-toggle .form-check-input { margin: 0; flex-shrink: 0; cursor: pointer; }
.bk-locator-toggle .form-check-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--font-color, #333);
    cursor: pointer;
    white-space: nowrap;
    margin: 0;
}

/* Search auto-fill (window.bkAttachAutocomplete) ------------------------- */
.bk-ac-wrap { position: relative; }
.bk-ac-menu {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 1200;
    margin: 0;
    padding: 4px;
    list-style: none;
    max-height: 320px;
    overflow-y: auto;
    background: var(--bg-color);
    border: 1px solid var(--border-color, rgba(0,0,0,0.12));
    border-radius: 10px;
    box-shadow: 0 12px 28px rgba(0,0,0,0.16);
}
.bk-ac-menu[hidden] { display: none; }
.bk-ac-item {
    display: grid;
    grid-template-columns: 18px 1fr;
    align-items: baseline;
    column-gap: 8px;
    padding: 7px 9px;
    border-radius: 7px;
    cursor: pointer;
}
.bk-ac-item i {
    grid-row: 1 / span 2;
    align-self: center;
    font-size: 12px;
    color: var(--accent-orange, #c62828);
}
.bk-ac-item.is-active,
.bk-ac-item:hover { background: var(--bg-color, rgba(0,0,0,0.05)); }
.bk-ac-item-main {
    font-size: 13.5px;
    font-weight: 600;
    color: var(--font-color, #333);
}
.bk-ac-item-sub {
    grid-column: 2;
    font-size: 11.5px;
    color: var(--font-color, #666);
    opacity: 0.62;
}
.bk-ac-item-closed {
    margin-left: 7px;
    padding: 1px 6px;
    border-radius: 20px;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    background: rgba(120,120,120,0.15);
    color: var(--font-color, #666);
}

/* The card a search / suggestion landed on, so the answer is obvious after
   the page scrolls. Fades itself out — see focusEid() in the locator. */
.bk-shop.is-focused {
    background: rgba(198, 40, 40, 0.08);
    background: color-mix(in srgb, var(--accent-orange, #c62828) 9%, transparent);
    box-shadow: inset 3px 0 0 var(--accent-orange, #c62828);
}

@media (max-width: 991.98px) {
    .bk-locator-body { flex-direction: column; }
    .bk-locator-list { flex: 1 1 auto; max-width: none; border-right: none; border-bottom: 1px solid var(--border-color, rgba(0,0,0,0.08)); }
    .bk-locator-scroll { max-height: 360px; }
    .bk-locator-map { min-height: 360px; }
    #locationsMap { min-height: 360px; }
    .bk-locator-selects { grid-template-columns: repeat(2, 1fr); }
}

/* ============================================================
   ADDED VALUE PACKAGES — "value pack" upsize ladder (variations modal)
   Vertical good->better->best rungs in the bottom sheet. Mirrors the
   .addon-sheet-card language (accent-orange selection, muted borders).
   ============================================================ */
.variations-ladder { display: flex; flex-direction: column; gap: 12px; padding-top: 6px; }

.var-rung {
    position: relative; display: flex; align-items: flex-start; gap: 14px; width: 100%; text-align: left;
    padding: 16px; border: 1.5px solid var(--border-muted); border-radius: 14px; background: var(--bg-color);
    cursor: pointer; transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;
    font-family: inherit; color: inherit; -webkit-tap-highlight-color: transparent;
}
.var-rung:hover { border-color: var(--accent-orange); }
.var-rung:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 2px; }

/* Selected rung — the customer's current pick (the swap target). */
.var-rung--selected { border-color: var(--accent-orange); background: rgba(238,81,58,0.05); box-shadow: 0 0 0 1px var(--accent-orange) inset; }

/* Featured "Most Popular" rung — accent ring + ribbon. */
.var-rung--featured { border-color: var(--accent-orange); }
.var-rung-ribbon {
    position: absolute; top: -10px; left: 16px; z-index: 2; display: inline-flex; align-items: center;
    padding: 3px 10px; border-radius: 999px; background: var(--accent-orange); color: #fff;
    font-size: 0.68rem; font-weight: 700; letter-spacing: 0.02em; text-transform: uppercase;
    box-shadow: 0 4px 12px rgba(238,81,58,0.35);
}

/* Radio check dot — filled when selected. */
.var-rung-check {
    position: absolute; top: 12px; right: 12px; z-index: 2;
    width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--border-muted);
    display: inline-flex; align-items: center; justify-content: center; color: transparent;
    font-size: 0.7rem; transition: background 0.15s, border-color 0.15s, color 0.15s; background: var(--bg-color);
}
.var-rung--selected .var-rung-check { background: var(--accent-orange); border-color: var(--accent-orange); color: #fff; }

.var-rung-img { flex: 0 0 27%; width: 27%; height: auto; border-radius: 10px; }

.var-rung-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.var-rung-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.var-rung-name { font-weight: 700; font-size: 0.98rem; color: var(--heading-color); }
.var-rung-tag  { font-size: 0.68rem; font-weight: 600; color: var(--accent-dark-orange); background: rgba(238,81,58,0.10); padding: 2px 8px; border-radius: 999px; }

.var-rung-price { display: flex; align-items: baseline; gap: 6px; margin-top: 2px; }
.var-rung-was { text-decoration: line-through; opacity: 0.5; font-size: 0.85rem; }
.var-rung-now { font-size: 1.15rem; font-weight: 800; color: var(--heading-color); }

.var-rung-desc { font-size: 0.85rem; opacity: 0.8; line-height: 1.35; margin-top: 2px; }

/* What's-included list — CSS multi-column balances items as evenly as possible by height.
   Column count is chosen in booking.js by item count (c1/c2/c3). */
.var-rung-inc { margin-top: 8px; }
.var-rung-inc--c1 { column-count: 1; }
.var-rung-inc--c2 { column-count: 2; column-gap: 18px; }
.var-rung-inc--c3 { column-count: 3; column-gap: 16px; }
.var-rung-inc-item { display: flex; align-items: flex-start; gap: 6px; font-size: 0.82rem; opacity: 0.85; break-inside: avoid; margin-bottom: 4px; }
.var-rung-inc-tick { color: var(--accent-orange); font-size: 0.68rem; margin-top: 4px; flex: 0 0 auto; }

@media (max-width: 480px) {
    .var-rung-now { font-size: 1.05rem; }
    .var-rung { padding: 14px; }
}

/* Folded "Most Popular with {package}" band — single-row peek+arrows scroll strip (3+
   items) so it stays compact atop the add-ons page instead of wrapping to 2 grid rows.
   1–2 items keep the plain .row g-3 grid (set in booking.js). */
.var-pop-strip-wrap { position: relative; }
.var-pop-strip {
    display: flex; gap: 12px; margin: 0; padding-bottom: 6px; overflow-x: auto;
    scroll-behavior: smooth; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
}
.var-pop-strip::-webkit-scrollbar { height: 6px; }
.var-pop-strip::-webkit-scrollbar-thumb { background: var(--border-muted); border-radius: 3px; }
.var-pop-strip-item { flex: 0 0 230px; max-width: 230px; scroll-snap-align: start; }
.var-pop-strip-item > .generic-card { width: 100%; }
@media (max-width: 420px) { .var-pop-strip-item { flex-basis: 80%; max-width: 80%; } }
.var-pop-arrow {
    position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
    width: 38px; height: 38px; border-radius: 50%; border: 1px solid var(--border-muted);
    background: var(--bg-color); box-shadow: 0 3px 12px rgba(0,0,0,0.14); cursor: pointer;
    display: none; align-items: center; justify-content: center; color: var(--heading-color);
}
.var-pop-arrow--prev { left: -8px; }
.var-pop-arrow--next { right: -8px; }
.var-pop-arrow[hidden] { display: none; }
/* Arrows are a desktop affordance only; phones use native touch-scroll. */
@media (min-width: 768px) {
    .var-pop-strip-wrap--scrollable .var-pop-arrow:not([hidden]) { display: inline-flex; }
}

/* "Most Popular with {package}" — the folded suggested add-ons section (value-pack step).
   A soft accent band sets it apart from the "A Special Treat" grid below it. */
#generic-popular-section { padding: 18px 18px 6px; border: 1px solid rgba(238,81,58,0.22); border-radius: 16px; background: rgba(238,81,58,0.035); }
#generic-popular-section .panel-eyebrow { color: var(--accent-dark-orange); }

/* ============================================================================
   CONFIGURATOR — full-screen two-column Book render mode (book.layout=configurator)
   Live product hero on the LEFT, ordered configurator steps on the RIGHT.
   Mobile-first: single column (hero on top). ============================== */
.bkc-shell { display: grid; grid-template-columns: 1fr; gap: 20px; max-width: 1080px; margin: 0 auto; padding: 20px 16px 56px; }
.bkc-hero-col { order: -1; }
.bkc-hero { background: var(--bg-color); border: 1px solid rgba(0,0,0,0.08); border-radius: 18px; padding: 22px; box-shadow: 0 6px 24px rgba(0,0,0,0.06); }
/* Absolute top ribbon (not inline) so the hero title sits at the SAME top position whether
   or not the package is featured — otherwise the badge pushed the title down inconsistently. */
.bkc-hero-badge { position: absolute; top: -11px; left: 20px; margin: 0; background: var(--accent-orange, #c0392b); color: #fff; font-size: 0.68rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; padding: 3px 12px; border-radius: 999px; box-shadow: 0 3px 10px rgba(0,0,0,0.18); z-index: 2; }
.bkc-hero-img { width: 100%; max-height: 300px; object-fit: cover; border-radius: 12px; margin-bottom: 14px; }
.bkc-hero-name { font-size: clamp(1.6rem, 1.48rem + 0.5vw, 1.9rem); line-height: 1.15; color: var(--heading-color); margin: 0 0 6px; }
.bkc-hero-price { margin-bottom: 16px; }
.bkc-hero-now { font-size: clamp(1.5rem, 1.39rem + 0.46vw, 1.78rem); font-weight: 800; color: var(--accent-orange, #c0392b); }
.bkc-hero-was { text-decoration: line-through; color: var(--font-color); opacity: .5; margin-right: 8px; font-size: 1rem; }
.bkc-hero-items { list-style: none; padding: 0; margin: 0 0 14px; }
.bkc-hero-items li { display: flex; align-items: baseline; gap: 8px; padding: 6px 0; border-bottom: 1px dashed rgba(0,0,0,0.08); font-size: .95rem; color: var(--font-color); transition: background .3s, transform .3s; }
.bkc-hero-items .bkc-qty { font-weight: 800; min-width: 34px; color: var(--accent-orange, #c0392b); }
.bkc-hero-items li.bkc-bump { animation: bkcBump .5s ease; }
@keyframes bkcBump { 0% { background: rgba(192,57,43,.16); transform: translateX(4px); } 100% { background: transparent; transform: none; } }
.bkc-hero-person { margin-top: 6px; }
.bkc-person-line { font-size: .85rem; color: var(--font-color); opacity: .85; padding: 3px 0; }
.bkc-person-line i { color: var(--accent-orange, #c0392b); margin-right: 6px; }

.bkc-section { background: var(--bg-color); border: 1px solid rgba(0,0,0,0.08); border-radius: 16px; padding: 18px 20px; margin-bottom: 16px; }
.bkc-heading { font-size: clamp(1.15rem, 1.09rem + 0.26vw, 1.31rem); color: var(--heading-color); margin: 0 0 4px; }
.bkc-subtext { color: var(--font-color); opacity: .7; font-size: .92rem; margin: 0 0 14px; }
.bkc-help { color: var(--font-color); opacity: .65; font-size: .85rem; margin: 0 0 10px; }
.bkc-included-note { font-size: .82rem; color: var(--font-color); opacity: .7; margin: 0 0 10px; }

/* gap bumped from 10px so the featured card's top ribbon has room above it */
.bkc-pkg-list { display: flex; flex-direction: column; gap: 16px; }
.bkc-pkg { position: relative; display: flex; justify-content: space-between; align-items: center; gap: 12px; width: 100%; text-align: left; border: 2px solid rgba(0,0,0,0.12); border-radius: 12px; background: transparent; padding: 14px 16px; cursor: pointer; color: var(--font-color); transition: border-color .15s, background .15s; }
.bkc-pkg:hover { border-color: var(--accent-orange, #c0392b); }
.bkc-pkg.is-selected { border-color: var(--accent-orange, #c0392b); background: rgba(192,57,43,0.05); }
.bkc-pkg-main { display: flex; align-items: center; gap: 8px; }
.bkc-pkg-name { font-weight: 600; }
/* Top ribbon (was inline next to the name, which wrapped the featured card taller).
   Absolute so it never affects the name's flow — matches the hero card's ribbon. */
.bkc-pkg-badge { position: absolute; top: -10px; left: 14px; z-index: 1; background: var(--accent-orange, #c0392b); color: #fff; font-size: .62rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; padding: 3px 10px; border-radius: 999px; box-shadow: 0 3px 10px rgba(0,0,0,0.18); white-space: nowrap; }
.bkc-pkg-price { font-weight: 800; white-space: nowrap; }

/* Rungs are full-width rows (label left, price right) — same shape as the package
   names, not a grid of squares. */
.bkc-rungs { display: flex; flex-direction: column; gap: 10px; }
.bkc-rung { display: flex; justify-content: space-between; align-items: center; gap: 12px; width: 100%; text-align: left; border: 2px solid rgba(0,0,0,0.12); border-radius: 12px; background: transparent; padding: 14px 16px; cursor: pointer; color: var(--font-color); transition: border-color .15s, background .15s; }
.bkc-rung:hover { border-color: var(--accent-orange, #c0392b); }
.bkc-rung.is-selected { border-color: var(--accent-orange, #c0392b); background: rgba(192,57,43,0.06); }
.bkc-rung.is-included { opacity: .5; cursor: default; }
.bkc-rung-label { font-weight: 700; font-size: 1rem; }
.bkc-rung-price { font-size: .85rem; opacity: .8; font-weight: 700; white-space: nowrap; }

/* Personalization options are full-width radio rows (circle + label). */
.bkc-opts { display: flex; flex-direction: column; gap: 10px; }
.bkc-opt { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; border: 2px solid rgba(0,0,0,0.12); border-radius: 12px; background: transparent; padding: 14px 16px; cursor: pointer; color: var(--font-color); font-size: .95rem; transition: border-color .15s, background .15s; }
.bkc-opt::before { content: ''; flex-shrink: 0; width: 20px; height: 20px; border-radius: 50%; border: 2px solid rgba(128,128,128,0.4); transition: border-color .15s, background .15s, box-shadow .15s; }
.bkc-opt:hover { border-color: var(--accent-orange, #c0392b); }
.bkc-opt.is-selected { border-color: var(--accent-orange, #c0392b); background: rgba(192,57,43,0.06); font-weight: 600; }
.bkc-opt.is-selected::before { border-color: var(--accent-orange, #c0392b); background: var(--accent-orange, #c0392b); box-shadow: inset 0 0 0 3px #fff; }

.bkc-module-eyebrow { font-size: .7rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--accent-orange, #c0392b); margin-bottom: 6px; }
.bkc-text { max-width: 320px; }

.bkc-actions { margin-top: 88px; }   /* room so a parallax-drifted last card (max 84px) can't overlap the CTA */
.bkc-cta { width: 100%; border: 0; border-radius: 12px; padding: 15px; background: var(--accent-orange, #c0392b); color: #fff; font-weight: 700; font-size: 1.05rem; cursor: pointer; box-shadow: 0 4px 16px rgba(192,57,43,0.3); }
.bkc-cta:disabled { opacity: .6; cursor: default; }

@media (min-width: 992px) {
    /* Hero-heavy: the live product preview dominates; the config column is compact. */
    .bkc-shell { grid-template-columns: 8fr 4fr; align-items: start; max-width: 1180px; }
    .bkc-hero-col { order: 0; position: sticky; top: 16px; }
}

/* ---- Configurator: full-page Premium Upgrade shell ----
   The page's own header (.bkc-page-head / -back / -title / -svc / -slot) is GONE: it
   was a fourth dialect of the same three controls every other booking step shows, so
   book/configure.blade.php now renders book/_flow-steps + _slot-bar + _back-link like
   the rest of the journey. Only the interior stays configurator-specific. */
.bkc-page { min-height: 60vh; }

/* ---- Configurator hero: premium "What's included" badge bump ---- */
.premium-included-qty.bkc-qty-bump,
.premium-included-delta-plus.bkc-qty-bump { animation: bkcQtyBump .55s cubic-bezier(.34,1.56,.64,1); display: inline-block; }
@keyframes bkcQtyBump { 0% { transform: scale(1); } 35% { transform: scale(1.5); } 100% { transform: scale(1); } }

/* ---- Configurator hero: "+N over base" delta — a faded cover band across the
       bottom of each item thumbnail (cover-card style), fades in on reveal ---- */
.premium-included-delta { position: absolute; left: 0; right: 0; bottom: 0; padding: 16px 3px 3px; text-align: center; font-size: .56rem; line-height: 1.15; font-weight: 600; color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.4); background: linear-gradient(to top, var(--accent-orange, #c0392b), transparent); animation: bkcDeltaFade .4s ease both; }
.premium-included-delta-plus { color: var(--accent-green, #2e7d32); font-weight: 800; white-space: nowrap; margin-left: 2px; }
.premium-included-delta-plus .fa-caret-up { font-size: .5rem; margin-right: 1px; }
@keyframes bkcDeltaFade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
@media (prefers-reduced-motion: reduce) { .premium-included-delta { animation: none; } }

/* ---- Configurator: mobile-only slot for the relocated benefits (empty on desktop) ---- */
.bkc-benefits-slot-mobile:empty { display: none; }
.bkc-benefits-slot-mobile { margin-top: 4px; }
.bkc-hero.premium-pkg-card { padding: 20px; display: block; }
.bkc-hero .bkc-hero-inc-title { margin-top: 16px; margin-bottom: 8px; }
.bkc-hero .premium-love-row { margin-top: 14px; }
.bkc-hero .bkc-hero-person { margin: 6px 0 0; }

/* ---- Configurator hero: lg+ info column (title · description · highlight badges
       · price) beside the promo image (col-4 / col-8); "Valued at" is a faded band
       across the bottom of the image (cover-card style). Stacks + centers on mobile. ---- */
.bkc-hero-top { display: block; }
.bkc-hero-info { text-align: center; }
.bkc-hero .bkc-hero-name { margin: 0 0 6px; }
.bkc-hero-desc { font-size: .84rem; line-height: 1.5; color: var(--font-color); opacity: .78; margin: 0 0 10px; }
.bkc-hero .bkc-hero-highlights { display: inline-block; text-align: left; margin: 4px 0 12px; }
.bkc-hero .bkc-hero-price { display: block; font-size: clamp(1.8rem, 1.66rem + 0.58vw, 2.16rem); font-weight: 800; line-height: 1.1; }
.bkc-hero .bkc-hero-was { display: block; font-size: .85rem; opacity: .7; margin-top: 2px; }
.bkc-hero .bkc-hero-figure { margin: 0 auto; }
@media (min-width: 992px) {
    .bkc-hero-top { display: grid; grid-template-columns: 4fr 8fr; gap: 22px; align-items: center; }
    .bkc-hero-info { text-align: left; }
    .bkc-hero .bkc-hero-highlights { display: block; }
    .bkc-hero .bkc-hero-figure { margin: 0; }
}

/* ---- Configurator hero: compact "What's included" cards (more fit; changes visible) ---- */
.bkc-hero .premium-included-grid { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 10px; }
.bkc-hero .premium-included-item { font-size: .72rem; }
.bkc-hero .premium-included-thumb { aspect-ratio: 1 / 1; border-radius: 8px; }
.bkc-hero .premium-included-thumb img { border-radius: 8px; }
.bkc-hero .premium-included-qty { font-size: .72rem; padding: 1px 6px; min-width: 22px; }
.bkc-hero .premium-included-name { font-size: .72rem; line-height: 1.15; margin-top: 4px; }

/* Booking Page Builder — interior-step content-block band (steps-as-blocks 2026-07-07).
   Wraps a journey step's authored content blocks rendered ABOVE/BELOW the live component
   (calendar / cart / receipt). Each .bkb-block inside carries its own section padding, so
   the band only needs to be full-width and reset the page's inherited text alignment. */
.bkb-step-blocks { width: 100%; }
.bkb-step-blocks .bkb-block { text-align: left; }

/* The LIVE step's styling shell (locations/_live_open + _live_close). The live-data
   anchor block is never drawn — the real calendar / cart / receipt is the page markup —
   but its background, ink, card surface and max width are authored, so the shell carries
   them around that markup.

   ⚠ IT IS A SHELL, NOT A BAND: it must contribute NO spacing and NO width cap of its
   own, or every step someone tints would silently gain 56px of padding and a 1140px cap
   the photographer never asked for. .bkb-block[data-pad] still wins on specificity, so
   the Spacing control keeps working, and innerStyle()'s inline max-width beats the class
   reset, so the Max width control does too. */
.bkb-block--live { padding: 0; }
.bkb-block--live > .bkb-inner { max-width: none; margin: 0; }

/* ⚠ THE STEP SHELL NO LONGER CONTAINS .page-wrap, SO IT NO LONGER INHERITS ITS FLOOR.
   The book step used to open the Date & Time Picker's shell ABOVE .page-wrap and close it
   at the bottom of the file, which nested the Experiences band inside the calendar band —
   the shape the Block Builder, where the two are peer blocks, can never draw. The blade
   now closes each shell around its own block and .page-wrap holds both as siblings.

   One thing came free from that nesting and has to be replaced: .page-wrap is
   min-height:80vh, so a shell wrapping it was always at least a screen tall and its colour
   filled the viewport while the slots were still loading. A content-height sibling stops
   where the short container stops, leaving the studio's colour in a strip above bare page.
   Grow the first shell into the leftover instead. Later siblings must NOT grow — the
   packages band is revealed below and would otherwise take half the slack. */
.page-wrap > .bkb-block--live:first-child { flex: 1 0 auto; }

/* ⚠ THE LIVE MARKUP PAINTS OVER ITS OWN BAND, so an authored background inside the shell
   has to be uncovered explicitly. The step's interactive markup is full-bleed and OPAQUE:
   #container-calendar / the confirmation wrapper carry .location-container
   (rgba(255,255,255,1), or near-black in dark mode) and the revealed packages section is
   .main-area (var(--bg-color)). Both stretch edge to edge INSIDE the shell, so the colour
   the photographer set on the Date & Time Picker block rendered and was then covered — it
   flashed first only because .page-wrap is min-height:80vh, so the band showed under a
   short container until the slots loaded, then vanished as the calendar filled it.

   Same neutralisation body.has-storefront-bg above already performs for a cascaded
   background image, and the same result: white surface comes only from the floating cards
   (#bookingCard / .location-card / package cards), which is what the admin preview draws.

   Gated on [data-bg] — a band whose author only changed ink, spacing or width keeps its
   opaque surface, because blanking it would rewrite a page nobody asked to change. An
   inline background on .main-area (a service's own graphic) still wins over this rule.

   Two classes plus the attribute outrank `.mode-dark .location-container` and
   `.mode-dark .main-area`, so ONE pair of selectors covers both themes.

   ⚠ .main-area IS REACHED FROM THE EXPERIENCES BAND'S OWN SHELL NOW, NOT FROM THE
   CALENDAR'S. While the two sections were nested, one [data-bg] on the outer shell
   uncovered both surfaces, and the packages band's tint was really the calendar band's
   colour showing through. They are siblings now, so the band carries its own [data-bg] —
   from its own background when the photographer set one, and otherwise from the step's,
   which BookingPageBlocksResolver::liveBand() copies onto it. Same painted result, but
   reproducible by a preview that draws the blocks side by side. */
.bkb-block--live[data-bg] .location-container,
.bkb-block--live[data-bg] .main-area {
    background-color: transparent;
}

/* ⚠ THE SECOND BAND STARTS HIDDEN. The book step's Experiences / Services block wraps
   #experience-packages, which booking.js reveals only once a slot is held (and never at
   all in paged_full mode, where packages get their own page). The shell itself has no
   .d-none of its own, so a band whose author picked the Spacious spacing preset would
   paint a bare 88px strip of their colour above the calendar for the whole first stage.
   Collapse the shell while its one child is still hidden — the rule stops matching the
   moment booking.js drops the class, so nothing has to reveal the shell as well. */
.bkb-block--live:has(> .bkb-inner > #experience-packages.d-none) {
    display: none;
}

/* ==========================================================================
   Fixed-page consistency pass (booking workflow modern styling, 2026-08-15).

   These rules serve the storefront's NON-block pages — package, configure,
   intake, walk-in, gate, manage, sign-in, the locations index, FAQ and policy.
   They are BYP-only: the admin block editor has no preview of these pages, so
   nothing here belongs to the .bkb-* twin contract.

   Both-themes note: a studio theme bakes light or dark straight into
   --bg-color / --font-color / --heading-color (theme-dark's --bg-color is
   near-black, its --font-color a light cream). So a hardcoded #fff or #333 is
   not "the light value" — it is a bug on every dark-token theme. Everything
   below resolves through tokens all 24 themes define.
   ========================================================================== */

/* Bootstrap's .text-muted is a near-black at 75% opacity (--bs-secondary-color)
   and !important, so it survived every theme: on the dark-token themes muted
   copy came out near-black on near-black. Tie it to the studio's own text
   colour instead — one rule covers ~50 uses across the workflow. */
.text-muted { color: var(--font-color) !important; opacity: 0.7; }

/* ---- FAQ + policy pages ------------------------------------------------- */
/* Both render photographer-authored HTML that previously carried no styling of
   its own, so links fell back to Bootstrap blue and headings to browser sizes. */
.bk-back-link           { color: var(--accent-orange); font-size: 0.92rem; }
.bk-back-link:hover     { color: var(--accent-orange); text-decoration: underline !important; }

/* Disclosure markers were the browser's own — `list-style: revert` put a raw ▶
   beside every question and a ▾ beside the section title, in the UA's colour and
   at the UA's size. Both are drawn here instead: a bordered box rotated into a
   chevron, so it needs no icon font (FontAwesome is not guaranteed on a Block
   Builder page), inherits currentColor on all 24 themes, and turns on open. */
.bk-faq__toggle         { cursor: pointer; list-style: none; }
.bk-faq__toggle::-webkit-details-marker { display: none; }
.bk-faq__toggle::after  { content: ''; display: inline-block; vertical-align: middle;
                          width: 0.45rem; height: 0.45rem; margin-left: 0.6rem;
                          border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
                          transform: rotate(45deg); opacity: 0.5;
                          transition: transform 0.18s ease; }
.bk-faq[open] > .bk-faq__toggle::after { transform: rotate(-135deg); }

.bk-faq__item           { border-bottom: 1px solid var(--border-muted); padding: 0.85rem 0; }
.bk-faq__item > summary { cursor: pointer; font-weight: 600; list-style: none; color: var(--heading-color);
                          position: relative; padding-right: 1.9rem; }
.bk-faq__item > summary::-webkit-details-marker { display: none; }
.bk-faq__item > summary::after { content: ''; position: absolute; right: 0.4rem; top: 0.42em;
                          width: 0.5rem; height: 0.5rem;
                          border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
                          transform: rotate(45deg); opacity: 0.55;
                          transition: transform 0.18s ease; }
.bk-faq__item[open] > summary::after { transform: rotate(-135deg); }
.bk-faq__item > summary:hover      { color: var(--accent-orange); }
.bk-faq__item > summary:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 3px; border-radius: 4px; }
.bk-faq__answer         { color: var(--font-color); line-height: 1.6; }

@media (prefers-reduced-motion: reduce) {
    .bk-faq__toggle::after,
    .bk-faq__item > summary::after { transition: none; }
}

.bk-policy-body         { color: var(--font-color); line-height: 1.65; }
.bk-faq__answer > :last-child,
.bk-policy-body > :last-child { margin-bottom: 0; }
.bk-faq__answer p, .bk-policy-body p { margin-bottom: 0.9rem; }
.bk-faq__answer a, .bk-policy-body a { color: var(--accent-orange); }
.bk-faq__answer ul, .bk-faq__answer ol,
.bk-policy-body ul, .bk-policy-body ol { padding-left: 1.35rem; margin-bottom: 0.9rem; }
.bk-faq__answer li, .bk-policy-body li { margin-bottom: 0.35rem; }
.bk-policy-body h2, .bk-policy-body h3, .bk-policy-body h4 { margin-top: 1.6rem; margin-bottom: 0.6rem; }
.bk-faq__answer img, .bk-policy-body img { max-width: 100%; height: auto; }
/* An authored table can be wider than the 760px column — scroll it, never the page. */
.bk-policy-body table   { width: 100%; margin-bottom: 1rem; }
.bk-policy-body table td, .bk-policy-body table th { padding: 6px 10px; border: 1px solid var(--border-muted); }

/* ---- Reservation gate + walk-in: the status icon and its lead line -------
   Were inline font-size pins on the page; on the fluid scale they grow with
   the viewport like every other heading in the workflow. */
.bk-status-icon         { font-size: clamp(3rem, 2.65rem + 1.5vw, 4rem); line-height: 1; }
.bk-status-lead         { font-size: clamp(1.1rem, 1.04rem + 0.26vw, 1.26rem); }
.bk-status-countdown    { font-size: clamp(1.4rem, 1.3rem + 0.42vw, 1.66rem); font-weight: 700; }

/* ---- Shared inline badges + accent notes -------------------------------
   --brand and --card-bg are admin-side property names that NO studio theme
   defines, so `var(--brand, #7c3aed)` was never a fallback — it was a hard
   violet on every storefront, whatever palette the photographer chose. These
   resolve through --accent-orange, which all 24 themes set to their own
   primary. The soft variant outlines rather than tints, so it reads on a
   light and a dark surface without needing the accent's rgb components. */
.bk-badge-inline        { font-size: 0.7rem; vertical-align: middle; }
.bk-badge-inline-xs     { font-size: 0.65rem; vertical-align: middle; }
.bk-badge-accent        { background: var(--accent-orange); color: #fff; }
.bk-badge-accent-soft   { background: transparent; color: var(--accent-orange); border: 1px solid var(--accent-orange); }
.bk-accent-note         { color: var(--accent-orange); font-weight: 600; }

/* The offer banner pill ("You Win!", "Early Bird", …).
 *
 * ⚠ nowrap IS THE WHOLE POINT. Bootstrap 5 dropped `white-space: nowrap` from
 *   `.badge`, so in the narrow col-md-5 price column the banner broke onto two
 *   lines — and `rounded-pill`'s 50rem radius on a two-line box is not a pill,
 *   it is a red blob. banner_text is varchar(120), so a photographer CAN write
 *   more than a pill can hold: the ellipsis is there so an over-long banner
 *   shows as clipped rather than being silently sheared off by the card's own
 *   `overflow: hidden`. Matches `.premium-pkg-offer`, which carries the same
 *   three properties for the same reason. */
.bk-offer-pill {
    display: inline-block;
    max-width: 100%;
    padding: 0.4em 0.85em;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: middle;
}
.bk-pkg-price           { font-size: clamp(1.15rem, 1.09rem + 0.26vw, 1.31rem); }

/* ============================================================
   SUGGESTED PACKAGES — the package UPGRADE card
   ------------------------------------------------------------
   Rendered by resources/views/book/_suggested-package-card.blade.php and by
   buildPackageUpgradeCol() in resources/js/booking.js.

   ⚠⚠ VISUALLY DISTINCT IS THE REQUIREMENT, NOT A PREFERENCE. Taking one of
      these REPLACES the customer's package; the .generic-card beside it appends
      a paid line. If the two look alike, the customer reads the swap as another
      add-on and is surprised at checkout by a package they did not choose.

   ⚠⚠ BUT DISTINCT IS THE SKIN, NOT THE SHAPE — CHANGED 2026-09-09. Until then
      this was a full-width horizontal band on every surface, so on a step whose
      add-ons are a grid of cards it read as a foreign object dropped onto the
      page. The owner's call: FOLLOW the step's Add-On Presentation layout, and
      carry the distinction in the five things below, every one of which survives
      both shapes. Shape is what makes it belong on the page; these are what stop
      it being read as an addition:
        1. a 2px accent FRAME where the add-on card has a 1px muted one
        2. an accent TINT composited over the card surface
        3. the "Upgrade your package" eyebrow
        4. the "Replaces … — you only pay the difference" line
        5. the taken state moving to green, not to the add-ons' orange

   ⚠ Colour is never the only signal (WCAG 2.1 AA): the eyebrow says "Upgrade
     your package", the note says what it replaces, and the taken state adds a
     check icon and the word "Upgraded".

   ⚠ Every colour resolves through the theme tokens all 24 studio themes set
     (--accent-orange / --accent-green / --bg-color / --border-muted /
     --font-color / --heading-color). --brand and --card-bg are ADMIN-side names
     that no storefront theme defines — see the badge block above for what that
     mistake looks like in production.
   ============================================================ */

/* ---- The skin: everything that is true in both shapes -------------------- */
.pkg-upgrade-card {
    display: flex;
    width: 100%;
    padding: 0;
    margin: 0;
    border: 2px solid var(--accent-orange);
    border-radius: 16px;
    overflow: hidden;
    cursor: pointer;
    /* The tint COMPOSITES over the card's own opaque surface. A translucent
       background-color would replace var(--bg-color) and let the page show
       through — the same defect the .generic-card.selected note above records. */
    background-color: var(--bg-color);
    background-image: linear-gradient(rgba(238, 81, 58, 0.06), rgba(238, 81, 58, 0.06));
    transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
}
.pkg-upgrade-card:hover  { box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12); transform: translateY(-2px); }
.pkg-upgrade-card:focus-visible { outline: 3px solid var(--accessibility-blue); outline-offset: 2px; }

/* Taken: the frame and the CTA move to the confirmation green, so "offered" and
   "yours" are never one hue apart — and never the add-ons' orange, which on this
   card would mean "still on offer". */
.pkg-upgrade-card.selected {
    border-color: var(--accent-green);
    background-image: linear-gradient(rgba(46, 160, 67, 0.07), rgba(46, 160, 67, 0.07));
}

.pkg-upgrade-media {
    flex: 0 0 auto;
    overflow: hidden;
    background: rgba(238, 81, 58, 0.06);
}
.pkg-upgrade-media--ph {
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(238, 81, 58, 0.10);
    color: var(--accent-orange);
    font-size: 1.5rem;
}
/* ⚠ `cover`, where the add-on card's photo is `contain` on a light well, and the
   difference is deliberate: an add-on photo is a product cut-out that must not be
   cropped, while package artwork is a scene. Same reasoning the add-on side
   records for keeping `contain` — changing either one moves every card that
   exists today. */
.pkg-upgrade-img { width: 100%; height: 100%; object-fit: cover; display: block; }

.pkg-upgrade-body { flex: 1 1 auto; min-width: 0; }
.pkg-upgrade-eyebrow {
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--accent-orange);
    margin-bottom: 4px;
}
.pkg-upgrade-name {
    font-family: var(--heading-font);
    font-size: clamp(1rem, 0.96rem + 0.2vw, 1.12rem);
    font-weight: 700;
    color: var(--heading-color);
    line-height: 1.25;
}
.pkg-upgrade-blurb { font-size: 0.85rem; color: var(--font-color); margin-top: 3px; }
/* The line that says this REPLACES what they hold. Quieter than the blurb but
   never hidden — it is the sentence that prevents the surprise at checkout, and
   it is not gated on the step's "show description" axis for that reason. */
.pkg-upgrade-note  { font-size: 0.76rem; color: var(--font-color); opacity: 0.75; margin-top: 6px; }

.pkg-upgrade-side {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.pkg-upgrade-price { font-size: 1.3rem; font-weight: 800; color: var(--accent-orange); line-height: 1; }
.pkg-upgrade-card.selected .pkg-upgrade-price { color: var(--accent-green); }
.pkg-upgrade-sub   { font-size: 0.72rem; color: var(--font-color); opacity: 0.7; }
.pkg-upgrade-btn {
    border: 0;
    border-radius: 20px;
    padding: 8px 16px;
    font-size: 0.82rem;
    font-weight: 700;
    color: #fff;
    background: var(--accent-orange);
    white-space: nowrap;
    /* The whole card is the control; this is its label, not a second target. */
    pointer-events: none;
}
.pkg-upgrade-card.selected .pkg-upgrade-btn { background: var(--accent-green); }

/* ---- LIST shape — twin of .generic-card-list ----------------------------
   Drawn when the step's add-ons are a list: a horizontal row with a fixed square
   thumb on the left. Metrics track the add-on row (128px thumb inset 12px, 16px
   radius) so the offer sits in the same rhythm; the 2px accent frame is what
   still tells them apart.
   ------------------------------------------------------------------------ */
.pkg-upgrade-card--list { flex-direction: row; align-items: center; gap: 16px; }
.pkg-upgrade-card--list .pkg-upgrade-media {
    width: 128px; min-width: 128px; height: 128px;
    border-radius: 12px;
    margin: 12px 0 12px 12px;
}
.pkg-upgrade-card--list .pkg-upgrade-body { padding: 14px 0; }
/* Artwork switched off for this step: the media element is not rendered at all,
   so the copy would otherwise start hard against the frame. The checkbox is the
   only element before it (and is out of flow — Bootstrap's .visually-hidden is
   position:absolute), so this adjacency matches ONLY when there is no media. */
.pkg-upgrade-card--list .pkg-upgrade-check + .pkg-upgrade-body { padding-left: 16px; }
.pkg-upgrade-card--list .pkg-upgrade-side {
    padding: 14px 16px 14px 0;
    align-items: flex-end;
    text-align: right;
}

/* ---- CARD shape — twin of .generic-card-grid ----------------------------
   Drawn when the step's add-ons are cards (and for carousel, which IS the grid
   card). Artwork on top, copy centred, price and CTA pinned to the foot.

   ⚠ height:100% + the column's own d-flex is what makes two offers side by side
     match height, exactly as the add-on grid card does it. The body carries the
     flex:1 that pushes the price block down.
   ------------------------------------------------------------------------ */
.pkg-upgrade-card--card { flex-direction: column; height: 100%; }
.pkg-upgrade-card--card .pkg-upgrade-media {
    width: 100%;
    aspect-ratio: 4 / 3;
    border-radius: 0;
    margin: 0;
}
.pkg-upgrade-card--card .pkg-upgrade-body { padding: 16px 16px 0; text-align: center; }
.pkg-upgrade-card--card .pkg-upgrade-side {
    padding: 12px 16px 16px;
    align-items: center;
    text-align: center;
    width: 100%;
}

/* ---- Photo size axis — twin of the .bk-imgsize-* rules for add-on cards ----
   The modifier rides the ROW the offer sits in, so one class sizes the add-ons
   and the offer above them together.

   ⚠ MEDIUM HAS NO RULE, on purpose: medium IS the base above, so a page that
     predates this axis resolves to medium and is unchanged. Size medium by
     editing the base rules, never by adding a .bk-imgsize-medium override.
   ------------------------------------------------------------------------- */
.bk-imgsize-small .pkg-upgrade-card--card .pkg-upgrade-media { aspect-ratio: 16 / 9; }
.bk-imgsize-large .pkg-upgrade-card--card .pkg-upgrade-media { aspect-ratio: 1 / 1; }

.bk-imgsize-small .pkg-upgrade-card--list .pkg-upgrade-media { width: 88px;  min-width: 88px;  height: 88px;  border-radius: 10px; }
.bk-imgsize-large .pkg-upgrade-card--list .pkg-upgrade-media { width: 200px; min-width: 200px; height: 200px; border-radius: 14px; }
.bk-imgsize-large .pkg-upgrade-card--list { gap: 20px; }

/* Narrow screens: the list row stacks, and the price column takes its own line
   instead of squeezing beside the copy. The card shape needs nothing — its
   column is already full width at xs. */
@media (max-width: 575.98px) {
    .pkg-upgrade-card--list { flex-wrap: wrap; gap: 12px; padding-bottom: 12px; }
    .pkg-upgrade-card--list .pkg-upgrade-media { width: 84px; min-width: 84px; height: 84px; margin: 12px 0 0 12px; }
    .pkg-upgrade-card--list .pkg-upgrade-body  { flex: 1 1 100%; order: 3; padding: 0 14px; }
    .pkg-upgrade-card--list .pkg-upgrade-side  { flex: 1 1 auto; padding: 12px 14px 0 0; }
    /* Without these the desktop sizes above (higher specificity than the base
       mobile rule) would follow the page down to a phone. */
    .bk-imgsize-small .pkg-upgrade-card--list .pkg-upgrade-media { width: 68px;  min-width: 68px;  height: 68px; }
    .bk-imgsize-large .pkg-upgrade-card--list .pkg-upgrade-media { width: 112px; min-width: 112px; height: 112px; }
}

/* Dark mode — the surface follows the add-on cards; the accent frame does not. */
.mode-dark .pkg-upgrade-card { background-color: var(--bg-dark-secondary); }

/* ---- Staff preview ("dry-run") dock + its exit control --------------------
   Was a block of inline style attributes on the partial; moved here so the dock
   can grow a second element without growing a second style attribute.

   ⚠ NEW RULES GO ABOVE THIS COMMENT, NEVER AT THE END OF THIS FILE. Everything
     from the countdown block's "layout shared by every preset" marker to EOF is
     compared byte-for-byte against admin's content/assets/css/booking-blocks.css
     by admin's tests/booking_countdown_test.php. Appending a rule down there
     turns that test red in the OTHER repo, which is a confusing place to find
     out.

   The violet is deliberately NOT --accent-orange, and that is the one place on
   this page where ignoring the studio palette is correct: every storefront
   theme sets its own primary, and a staff warning painted in the photographer's
   own accent blends into the design it is warning about. Same reasoning that
   pins .bkb-cd's flip faces dark in both themes. Fixed in light and dark, on
   all 24 themes.

   ⚠ THE TAB AND THE PANEL ARE TWO INDEPENDENTLY FIXED ELEMENTS, NOT A FLEX ROW.
     A row anchored right:0 keeps its full width when the panel slides out, so
     the tab would strand itself a panel's width in from the edge. Each is
     pinned to right:0 on its own and offset by the SAME custom property, which
     is why --bk-preview-dock-w exists rather than a literal in two places: they
     can never disagree about how far the drawer travels.

   ⚠ .bk-preview-dock ITSELF MUST NOT BE TRANSFORMED (or filtered, or given
     contain/will-change). Any of those make it a containing block for its own
     fixed children, and the drawer would then be positioned against a zero-high
     div in the document flow instead of the viewport. */
.bk-preview-dock {
    --bk-preview-dock-w: min(360px, 92vw);
}

/* The panel. Off the right edge when closed, and hidden with it — visibility,
   not opacity, so the exit link and the Current/Proposed pair leave the tab
   order rather than sitting invisible in it for a keyboard user to fall into
   (WCAG 2.4.3). The 0s delay is what keeps it visible for the whole slide out
   and makes it visible immediately on the way in. */
.bk-preview-banner {
    position: fixed;
    top: 50%;
    right: 0;
    z-index: 1080;
    box-sizing: border-box;
    width: var(--bk-preview-dock-w);
    max-height: min(84vh, 640px);
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    padding: 16px 18px;
    border-radius: 14px 0 0 14px;
    background: #7c3aed;
    color: #fff;
    text-align: left;
    font-size: 0.85rem;
    font-weight: 700;
    line-height: 1.4;
    box-shadow: 0 10px 34px rgba(0, 0, 0, 0.34);
    transform: translateY(-50%) translateX(100%);
    visibility: hidden;
}
.bk-preview-dock__ctl[open] ~ .bk-preview-banner {
    transform: translateY(-50%);
    visibility: visible;
}
/* ⚠ THE PARAGRAPH IS LIGHTER THAN THE BAR'S WAS, ON PURPOSE. As a one-line
     strip this copy was 700 with tracking, which is right for a label; the
     drawer gives it six lines, and six lines of tracked bold is a wall a
     partner skips rather than reads. The emphasis moved to the opening words,
     which is the part that has to carry at a glance. */
.bk-preview-banner__text {
    flex: 0 0 auto;
    min-width: 0;
    font-weight: 500;
    line-height: 1.5;
}
.bk-preview-banner__text strong { font-weight: 800; letter-spacing: 0.06em; }

/* The tab — the collapsed state's entire user interface, so it is sized to be
   read and hit rather than to be discreet. It travels the drawer's width so it
   ends up on the panel's outer edge when open, where it reads as the close
   control it also is. */
.bk-preview-dock__ctl {
    position: fixed;
    top: 50%;
    right: 0;
    z-index: 1081;
    transform: translateY(-50%);
}
.bk-preview-dock__ctl[open] {
    transform: translateY(-50%) translateX(calc(-1 * var(--bk-preview-dock-w)));
}
.bk-preview-dock__tab {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 9px;
    padding: 16px 7px;
    border-radius: 12px 0 0 12px;
    background: #7c3aed;
    color: #fff;
    cursor: pointer;
    box-shadow: -3px 0 14px rgba(0, 0, 0, 0.3);
    list-style: none;   /* the native marker has nowhere to sit on a vertical tab */
}
.bk-preview-dock__tab::-webkit-details-marker { display: none; }
/* ⚠ THE LABEL IS VERTICAL, THE CARET IS NOT. writing-mode inherits, so a caret
     left inside the vertical run rotates about the wrong axis and points at the
     floor in one of the two states. */
.bk-preview-dock__tab-label {
    writing-mode: vertical-rl;
    font-size: 0.68rem;
    font-weight: 800;
    letter-spacing: 0.16em;
    white-space: nowrap;
}
.bk-preview-dock__caret {
    writing-mode: horizontal-tb;
    font-size: 0.72rem;
    line-height: 1;
}
.bk-preview-dock__ctl[open] .bk-preview-dock__caret { transform: rotate(180deg); }
.bk-preview-dock__tab:hover { background: #6d28d9; }
/* Light ring for the same reason every other control in here has one: violet is
   the only thing behind it, and a browser-default dark ring vanishes on it. */
.bk-preview-dock__tab:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

/* ⚠ MOTION IS GATED ON is-ready, WHICH THE PARTIAL'S SCRIPT ADDS IN THE SAME
     TICK AS THE STORED STATE. Without the gate, restoring a drawer the partner
     had already closed plays as the panel sliding out on every page — an
     animation of work being undone that they never asked for. With JS off the
     class never lands, the dock still opens and closes natively, and it simply
     does so instantly. */
.bk-preview-dock.is-ready .bk-preview-dock__ctl,
.bk-preview-dock.is-ready .bk-preview-dock__caret {
    transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
}
.bk-preview-dock.is-ready .bk-preview-banner {
    transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1),
                visibility 0s linear 0.28s;
}
.bk-preview-dock.is-ready .bk-preview-dock__ctl[open] ~ .bk-preview-banner {
    transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1), visibility 0s;
}
@media (prefers-reduced-motion: reduce) {
    .bk-preview-dock.is-ready .bk-preview-dock__ctl,
    .bk-preview-dock.is-ready .bk-preview-dock__caret,
    .bk-preview-dock.is-ready .bk-preview-banner,
    .bk-preview-dock.is-ready .bk-preview-dock__ctl[open] ~ .bk-preview-banner {
        transition: none;
    }
}

/* A button, not a footnote. This bar is the only thing between a staffer and
   the customer view, and until it carried a control the ways out were clearing
   cookies or waiting out a 72-hour token. */
.bk-preview-banner__exit {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 7px 14px;
    border: 1px solid rgba(255, 255, 255, 0.75);
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.bk-preview-banner__exit:hover,
.bk-preview-banner__exit:focus {
    background: #fff;
    border-color: #fff;
    color: #7c3aed;
    text-decoration: none;
}
/* The bar's own violet is the only thing behind this control, so the ring has
   to be light — a browser default dark ring is invisible against it. */
.bk-preview-banner__exit:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

/* Current vs Proposed — the segmented pair sitting between the sentence and the
   exit. Two links styled as one control: a hairline track, and the half that is
   showing filled white.

   ⚠ THE FILL IS NOT THE ONLY SIGNAL, AND MUST NOT BECOME ONE. The showing half
     also carries a tick and a screen-reader "— showing now", and the sentence to
     its left names it in words. Colour alone would fail WCAG 1.4.1 for anyone who
     cannot separate white-on-violet from violet-on-white — which on a bar this
     small is a realistic miss, not a theoretical one. */
.bk-preview-banner__compare {
    flex: 0 0 auto;
    display: flex;
    align-items: stretch;
    padding: 2px;
    border: 1px solid rgba(255, 255, 255, 0.55);
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.16);
}
.bk-preview-banner__opt {
    flex: 1 1 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 5px 13px;
    border-radius: 999px;
    color: #fff;
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.15s ease, color 0.15s ease;
}
.bk-preview-banner__opt:hover,
.bk-preview-banner__opt:focus {
    background: rgba(255, 255, 255, 0.22);
    color: #fff;
    text-decoration: none;
}
.bk-preview-banner__opt.is-showing,
.bk-preview-banner__opt.is-showing:hover,
.bk-preview-banner__opt.is-showing:focus {
    background: #fff;
    color: #5b21b6;   /* violet-800 — 7.4:1 on white, so the fill is readable */
}
/* Light ring for the same reason the exit's is: the bar's violet is the only
   thing behind it, and a browser-default dark ring disappears against it. */
.bk-preview-banner__opt:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

/* "N changes waiting for approval" — the disclosure under the toggle, and the
   list it opens.

   ⚠ IT OPENS IN PLACE NOW, NOT AS A DROPDOWN. It used to float out from under a
     sticky top bar because a list of up to forty overlaid columns rendered
     inline would have pushed the page it describes off the screen. Inside a
     drawer that is no longer true: the drawer scrolls, so the list can simply
     take its place in the column and stay inside the surface it belongs to. A
     panel still floating out of a fixed drawer would be clipped by the drawer's
     own overflow.

   ⚠ THE LIST IS PAINTED, NOT TINTED. It carries dark text on white rather than
     white on violet, because it holds sentences rather than labels and the
     dock's own violet is a warning colour that should not be describing
     ordinary work. */
.bk-preview-banner__changes {
    flex: 0 0 auto;
}
.bk-preview-banner__changes-summary {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 6px 13px;
    border: 1px solid rgba(255, 255, 255, 0.55);
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.16);
    color: #fff;
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    line-height: 1.3;
    cursor: pointer;
    text-align: center;
    list-style: none;   /* the native marker sits outside the pill */
}
/* ⚠ IT WRAPS. It was nowrap as a pill on a wide bar; in a 300px drawer that
     sentence is wider than the column, and a nowrap flex item does not shrink —
     the pill ran out past the drawer's padding on both sides with the count and
     the last word sliced off. The caret rides the last line rather than being
     pushed off it. */
.bk-preview-banner__changes-summary > * { flex: 0 0 auto; }
.bk-preview-banner__changes-summary::-webkit-details-marker { display: none; }
/* The caret is an ADDITION to the state <details> already reports to assistive
   tech, never the carrier of it — summary announces expanded/collapsed itself. */
.bk-preview-banner__changes-summary::after {
    content: "\25be";
    font-size: 0.9em;
    line-height: 1;
    transition: transform 0.15s ease;
}
.bk-preview-banner__changes[open] > .bk-preview-banner__changes-summary::after {
    transform: rotate(180deg);
}
.bk-preview-banner__changes-summary:hover {
    background: rgba(255, 255, 255, 0.22);
}
/* Light ring, same reason as the exit and the toggle: the bar's violet is the
   only thing behind it and a browser-default dark ring vanishes against it. */
.bk-preview-banner__changes-summary:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}
.bk-preview-banner__changes-list {
    margin: 8px 0 0;
    padding: 10px 16px 10px 30px;
    border-radius: 10px;
    background: #fff;
    color: #1f2937;
    text-align: left;
    font-size: 0.8rem;
    font-weight: 500;
    letter-spacing: 0;
    line-height: 1.45;
}
.bk-preview-banner__changes-list > li + li { margin-top: 4px; }
/* Muted, but the words carry the meaning on their own — the clearing is said in
   the sentence, so this tone is emphasis and never the signal (WCAG 1.4.1). */
.bk-preview-banner__cleared {
    color: #6b7280;
    font-weight: 400;
    font-style: italic;
}

/* Shown once, on the page landed on after leaving. Green rather than violet on
   purpose: it reports a finished action, and reusing the warning colour would
   read at a glance as "still in preview" — the exact confusion being fixed. */
.bk-preview-exited {
    padding: 8px 14px;
    background: #166534;
    color: #fff;
    text-align: center;
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1.35;
}

@media (max-width: 575.98px) {
    /* Narrower, and shorter: a phone drawer pinned to the middle of the viewport
       has to clear the sticky held-slot bar at the bottom of the booking steps,
       which a 84vh panel does not. */
    .bk-preview-dock  { --bk-preview-dock-w: min(300px, 86vw); }
    .bk-preview-banner {
        max-height: 66vh;
        padding: 14px 15px;
        font-size: 0.78rem;
    }
    /* The tab keeps its hit area — it is the only control on screen while the
       drawer is away, and this is the size where mis-taps actually happen. */
    .bk-preview-dock__tab       { padding: 15px 8px; }
    .bk-preview-dock__tab-label { font-size: 0.64rem; letter-spacing: 0.13em; }
}

/* ══════════════════════════════════════════════════════════════════════════
   Countdown block (.bkb-cd) — six presets over one engine
   ──────────────────────────────────────────────────────────────────────────
   Twin of admin's content/assets/css/booking-blocks.css. Everything below the
   token rule is byte-identical across the two repos and pinned that way by
   admin's tests/booking_countdown_parity_test.php — the ONE rule that differs
   is .bkb-cd's token block, because each repo names its palette differently.
   Re-theme by editing that rule, never by touching a rule body.

   All markup below .bkb-cd is written by booking-countdown.js, so these
   selectors are a contract with that file, not with any Blade partial.
   ══════════════════════════════════════════════════════════════════════════ */
.bkb-cd {
    --bkb-cd-accent: var(--accent-orange, #e8590c);
    --bkb-cd-ink:    var(--heading-color, #1f2937);
    --bkb-cd-muted:  var(--font-color, #6b7280);
    --bkb-cd-hair:   rgba(127, 127, 127, .24);
    /* The flip card is a deliberately fixed dark canvas in both themes — a
       split-flap board reads as one, and a light "flap" folding over a light
       face has nothing to show. */
    --bkb-cd-face:   #151a22;
    --bkb-cd-face-2: #222b38;
    --bkb-cd-radius: 14px;
}

/* ── layout shared by every preset ──────────────────────────────────────────
   The container starts life holding a readable sentence (the server fallback)
   and is replaced by .bkb-cd-body once the engine has a target it can tick. */
.bkb-cd            { color: var(--bkb-cd-ink); font-size: clamp(1rem, .94rem + .3vw, 1.15rem); line-height: 1.5; }
.bkb-cd--left      { text-align: left; }
.bkb-cd--center    { text-align: center; }
.bkb-cd--right     { text-align: right; }
.bkb-cd-units      { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: center; gap: clamp(.55rem, .3rem + .9vw, 1.2rem); }
.bkb-cd--left  .bkb-cd-units, .bkb-cd--left  .bkb-cd-pill { justify-content: flex-start; }
.bkb-cd--right .bkb-cd-units, .bkb-cd--right .bkb-cd-pill { justify-content: flex-end; }
.bkb-cd-unit       { display: flex; flex-direction: column; align-items: center; gap: .5em; }
/* Tabular figures everywhere: without them "11" is narrower than "00" and the
   whole row twitches sideways once a second, which reads as a rendering bug. */
.bkb-cd-num, .bkb-cd-top, .bkb-cd-bot { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }
.bkb-cd-lab        { font-size: .66rem; font-weight: 700; text-transform: uppercase; letter-spacing: .14em; color: var(--bkb-cd-muted); opacity: .78; }
/* The at-zero message, and the optional line under the clock. */
.bkb-cd-msg        { margin: 0; font-size: clamp(1.15rem, 1rem + .7vw, 1.6rem); font-weight: 700; color: var(--bkb-cd-accent); }
.bkb-cd-foot       { margin: .95rem 0 0; text-align: center; font-size: .85rem; color: var(--bkb-cd-muted); opacity: .75; }

/* ── clean — hairline-divided numerals, no chrome ───────────────────────── */
.bkb-cd--clean .bkb-cd-units             { gap: 0; }
.bkb-cd--clean .bkb-cd-unit              { padding: 0 clamp(.75rem, .4rem + 1.1vw, 1.6rem); border-left: 1px solid var(--bkb-cd-hair); }
.bkb-cd--clean .bkb-cd-unit:first-child  { border-left: 0; padding-left: 0; }
.bkb-cd--clean .bkb-cd-unit:last-child   { padding-right: 0; }
.bkb-cd--clean .bkb-cd-num               { font-size: clamp(2.1rem, 1.5rem + 2.4vw, 3.6rem); font-weight: 300; line-height: 1; letter-spacing: -.02em; color: var(--bkb-cd-ink); }

/* ── flip — a split-flap card that folds on every change ────────────────────
   The two faces carry the SAME text; the illusion is the clipping. .bkb-cd-top
   has a full line-height so the glyph centres halfway down and only its upper
   half survives the overflow; .bkb-cd-bot has line-height 0, so the glyph
   centres on the box's top edge and only its lower half survives. The flap is
   a decorative third face that folds away over the seam. */
.bkb-cd--flip .bkb-cd-card       { position: relative; display: block; overflow: hidden; min-width: 1.5em; padding: .3em .24em; text-align: center; font-size: clamp(2rem, 1.4rem + 2.3vw, 3.3rem); font-weight: 700; color: #fff; background: linear-gradient(180deg, var(--bkb-cd-face-2), var(--bkb-cd-face)); border-radius: var(--bkb-cd-radius); box-shadow: 0 8px 22px rgba(15, 23, 42, .26), inset 0 1px 0 rgba(255, 255, 255, .07); perspective: 340px; }
.bkb-cd--flip .bkb-cd-top,
.bkb-cd--flip .bkb-cd-bot        { display: block; overflow: hidden; height: .62em; }
.bkb-cd--flip .bkb-cd-top        { line-height: 1.24em; }
.bkb-cd--flip .bkb-cd-bot        { line-height: 0; }
.bkb-cd--flip .bkb-cd-card::after{ content: ''; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: rgba(0, 0, 0, .45); }
.bkb-cd--flip .bkb-cd-flap       { position: absolute; top: 0; left: 0; right: 0; bottom: 50%; opacity: 0; pointer-events: none; border-radius: var(--bkb-cd-radius) var(--bkb-cd-radius) 0 0; background: linear-gradient(180deg, var(--bkb-cd-face-2), var(--bkb-cd-face)); transform-origin: 50% 100%; }
.bkb-cd--flip .bkb-cd-card.is-flipping .bkb-cd-flap { animation: bkb-cd-flip .34s cubic-bezier(.36, .1, .3, 1) 1; }
.bkb-cd--flip .bkb-cd-lab        { color: var(--bkb-cd-accent); opacity: 1; }
@keyframes bkb-cd-flip { 0% { opacity: 1; transform: rotateX(0deg); } 99% { opacity: 1; } 100% { opacity: 0; transform: rotateX(-90deg); } }

/* ── circles — a draining ring per unit, arc set by the engine ──────────── */
.bkb-cd--circles .bkb-cd-ring     { position: relative; display: block; width: clamp(66px, 52px + 3.8vw, 98px); height: clamp(66px, 52px + 3.8vw, 98px); }
.bkb-cd--circles .bkb-cd-ring svg { display: block; width: 100%; height: 100%; transform: rotate(-90deg); }
.bkb-cd-track                     { fill: none; stroke: var(--bkb-cd-hair); stroke-width: 2.6; }
.bkb-cd-prog                      { fill: none; stroke: var(--bkb-cd-accent); stroke-width: 2.6; stroke-linecap: round; transition: stroke-dashoffset .3s linear; }
/* The millisecond ring is redrawn every animation frame — a transition on it
   would queue 60 interpolations a second and never finish one. */
.bkb-cd-unit[data-u="ms"] .bkb-cd-prog { transition: none; }
.bkb-cd--circles .bkb-cd-num      { position: absolute; top: 0; right: 0; bottom: 0; left: 0; display: flex; align-items: center; justify-content: center; font-size: clamp(1.05rem, .85rem + .7vw, 1.5rem); font-weight: 700; color: var(--bkb-cd-ink); }

/* ── pill — one compact bar, for a countdown that sits beside other copy ── */
.bkb-cd-pill              { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: .15rem .75rem; padding: .6em 1.25em; border-radius: 999px; background: rgba(127, 127, 127, .09); border: 1px solid var(--bkb-cd-hair); box-shadow: 0 2px 10px rgba(15, 23, 42, .06); }
.bkb-cd-seg               { display: inline-flex; align-items: baseline; gap: .08em; }
.bkb-cd--pill .bkb-cd-num { font-size: clamp(1.3rem, 1.1rem + .8vw, 1.85rem); font-weight: 800; color: var(--bkb-cd-ink); }
.bkb-cd-suf               { font-size: .78em; font-weight: 700; text-transform: lowercase; color: var(--bkb-cd-accent); }

/* ── inline — one sentence, numerals in the accent ──────────────────────── */
.bkb-cd-sentence            { font-size: clamp(1rem, .92rem + .4vw, 1.25rem); font-weight: 600; color: var(--bkb-cd-ink); }
.bkb-cd--inline .bkb-cd-num { font-weight: 800; color: var(--bkb-cd-accent); }

/* ── ticket — the loud one, for a genuine deadline ──────────────────────── */
.bkb-cd--ticket .bkb-cd-unit        { position: relative; min-width: 3.5em; padding: .7em .95em .58em; gap: .75em; border-radius: 12px; background: var(--bkb-cd-accent); box-shadow: 0 10px 26px rgba(15, 23, 42, .22); }
/* Perforation between the numeral and its label — a ticket tear line, drawn
   inside the card so it needs no knowledge of the page background behind it. */
.bkb-cd--ticket .bkb-cd-unit::after { content: ''; position: absolute; left: .55em; right: .55em; bottom: 1.95em; border-top: 1px dashed rgba(255, 255, 255, .38); }
.bkb-cd--ticket .bkb-cd-num         { font-size: clamp(1.9rem, 1.4rem + 2vw, 3rem); font-weight: 900; line-height: 1; color: #fff; }
.bkb-cd--ticket .bkb-cd-lab         { color: rgba(255, 255, 255, .85); opacity: 1; }

@media (max-width: 575.98px) {
    .bkb-cd--clean .bkb-cd-unit    { padding: 0 .6rem; }
    .bkb-cd--circles .bkb-cd-ring  { width: 62px; height: 62px; }
}

/* The engine already drops milliseconds under prefers-reduced-motion; these
   settle what is left — the fold and the ring sweep. */
@media (prefers-reduced-motion: reduce) {
    .bkb-cd--flip .bkb-cd-card.is-flipping .bkb-cd-flap { animation: none; }
    .bkb-cd-prog { transition: none; }
}


/* ================================================================================
   OFFCANVAS SIDEBAR — #bookingSidebar (partials/nav.blade.php)
   --------------------------------------------------------------------------------
   The panel used to be a bare Bootstrap .nav list, so every studio got stock
   link-blue rows on a white sheet no matter what their theme said, and the icons
   rag-aligned because each glyph is a different width. Both are fixed here:
   colour comes from the theme tokens, and the icon sits in a fixed-size chip so
   the labels start on one vertical line.

   ⚠ Every row is a FLEX container with justify-content:flex-start. That is not
   decoration — it is what pins the alignment. A flex container ignores an
   inherited text-align for the placement of its items, so a centring rule
   anywhere up the tree (the panel renders as a direct child of <body>, outside
   any page wrapper) can no longer drag the menu into the middle.
   ================================================================================ */

.bk-sidebar {
    width: min(86vw, 316px);
    background: var(--bg-light-secondary, #fff);
    color: var(--font-color);
    border-right: 1px solid var(--border-muted);
    box-shadow: 0 0 44px var(--shadow-color, rgba(0, 0, 0, 0.18));
}

/* ---- header: brand + close -------------------------------------------------- */
.bk-sidebar-head {
    align-items: center;
    gap: 12px;
    padding: 18px 18px 14px;
    border-bottom: 1px solid var(--border-muted);
}
.bk-sidebar-title {
    margin: 0;
    min-width: 0;
    font-family: var(--heading-font);
    font-size: 1.02rem;
    font-weight: 700;
    line-height: 1.25;
    text-align: left;
    color: var(--heading-color, var(--font-color));
}
.bk-sidebar-logo  { display: block; max-width: 100%; max-height: 42px; object-fit: contain; }
.bk-sidebar-close { flex-shrink: 0; opacity: 0.45; }
.bk-sidebar-close:hover { opacity: 0.85; }

/* ---- body: two stacked groups, the account one pinned to the bottom --------- */
.bk-sidebar-body {
    display: flex;
    flex-direction: column;
    padding: 16px 14px 18px;
}
.bk-sidebar-foot { margin-top: auto; padding-top: 18px; }

.bk-sidebar-eyebrow {
    margin: 0 0 8px;
    padding: 0 10px;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    text-align: left;
    color: var(--font-color);
    opacity: 0.42;
}
.bk-sidebar-foot .bk-sidebar-eyebrow {
    padding-top: 16px;
    border-top: 1px solid var(--border-muted);
}

/* ---- rows ------------------------------------------------------------------- */
.bk-sidebar-nav { list-style: none; margin: 0; padding: 0; }
.bk-sidebar-nav li + li { margin-top: 2px; }

.bk-sidebar-link {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 12px;
    padding: 10px 10px;
    border-radius: 12px;
    font-size: 0.95rem;
    font-weight: 600;
    line-height: 1.2;
    text-align: left;
    text-decoration: none;
    color: var(--font-color);
    transition: background-color 0.16s ease, color 0.16s ease, transform 0.16s ease;
}
.bk-sidebar-label { min-width: 0; }

/* The chip is what gives the labels a single left edge — a fixed box per glyph,
   rather than each icon's own advance width. */
.bk-sidebar-ico {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 10px;
    font-size: 0.85rem;
    background: rgba(127, 127, 127, 0.1);
    color: var(--accent-orange);
    transition: background-color 0.16s ease, color 0.16s ease;
}

.bk-sidebar-link:hover,
.bk-sidebar-link:focus-visible {
    background: rgba(127, 127, 127, 0.09);
    color: var(--font-color);
    transform: translateX(2px);
}
.bk-sidebar-link:focus-visible,
.bk-sidebar-cta:focus-visible,
.bk-sidebar-close:focus-visible {
    outline: 2px solid var(--accent-orange);
    outline-offset: 2px;
}

/* Active row. Colour is never the only cue — the chip inverts to a solid accent
   and the weight steps up, so the current section still reads without it. */
.bk-sidebar-link.is-active {
    background: rgba(127, 127, 127, 0.12);
    color: var(--accent-orange);
    font-weight: 700;
}
.bk-sidebar-link.is-active .bk-sidebar-ico {
    background: var(--accent-orange);
    color: #fff;
}
@supports (color: color-mix(in srgb, red, blue)) {
    .bk-sidebar-ico            { background: color-mix(in srgb, var(--accent-orange) 12%, transparent); }
    .bk-sidebar-link.is-active { background: color-mix(in srgb, var(--accent-orange) 11%, transparent); }
    .bk-sidebar-link:hover,
    .bk-sidebar-link:focus-visible { background: color-mix(in srgb, var(--accent-orange) 7%, transparent); }
}

/* Sign Out is a leaving action, not a destination — it sits quieter than the
   rows above it so it can't be mistaken for the current section. */
.bk-sidebar-link--quiet { color: var(--font-color); opacity: 0.72; font-weight: 600; }
.bk-sidebar-link--quiet .bk-sidebar-ico { color: var(--font-color); opacity: 0.8; }
.bk-sidebar-link--quiet:hover { opacity: 1; }

/* ---- signed-out call to action ---------------------------------------------- */
.bk-sidebar-cta-group { display: flex; flex-direction: column; gap: 8px; }
.bk-sidebar-cta {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 11px 14px;
    border: 1px solid var(--accent-orange);
    border-radius: 12px;
    background: var(--accent-orange);
    color: #fff;
    font-size: 0.92rem;
    font-weight: 700;
    text-decoration: none;
    transition: filter 0.16s ease, background-color 0.16s ease, color 0.16s ease;
}
.bk-sidebar-cta:hover { filter: brightness(0.93); color: #fff; }
.bk-sidebar-cta--ghost {
    background: transparent;
    color: var(--accent-orange);
    border-color: var(--border-muted);
}
.bk-sidebar-cta--ghost:hover { background: rgba(127, 127, 127, 0.08); color: var(--accent-orange); }

.bk-sidebar-note {
    margin: 10px 2px 0;
    font-size: 0.76rem;
    line-height: 1.45;
    text-align: left;
    color: var(--font-color);
    opacity: 0.55;
}

/* ---- studio support text ---------------------------------------------------- */
.bk-sidebar-support {
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--border-muted);
    font-size: 0.78rem;
    line-height: 1.5;
    text-align: left;
    color: var(--font-color);
    opacity: 0.6;
}

/* Dark surface — matches the .mode-dark convention the rest of this file uses. */
.mode-dark .bk-sidebar {
    background: var(--bg-dark-secondary);
    color: var(--font-dark-color);
    border-right-color: rgba(255, 255, 255, 0.1);
}
.mode-dark .bk-sidebar-head,
.mode-dark .bk-sidebar-foot .bk-sidebar-eyebrow,
.mode-dark .bk-sidebar-support { border-color: rgba(255, 255, 255, 0.1); }
.mode-dark .bk-sidebar-title,
.mode-dark .bk-sidebar-link,
.mode-dark .bk-sidebar-eyebrow,
.mode-dark .bk-sidebar-note,
.mode-dark .bk-sidebar-support { color: var(--font-dark-color); }
.mode-dark .bk-sidebar-close   { filter: invert(1) grayscale(1); }

@media (prefers-reduced-motion: reduce) {
    .bk-sidebar-link, .bk-sidebar-ico, .bk-sidebar-cta { transition: none; }
    .bk-sidebar-link:hover, .bk-sidebar-link:focus-visible { transform: none; }
}

/* ===== Shared booking-flow page chrome =====================================
   book/_shell-open · _shell-close · _step-head · _back-link · _flow-steps ·
   _slot-bar — the chrome the single-page calendar flow established, extracted
   so /book/package, /book/addons (both waves) and /book/configure render the
   same page rather than three hand-rolled approximations of it.

   ⚠ Everything here is either a NEW class or a wider variant of an existing
   one. The calendar's own selectors are untouched on purpose: it is the
   reference look, so a rule that changed it would be changing the target. */

/* Grid steps (add-on cards, package cards) need room the 720px reading column
   does not give them. Declared after .bk-content-col so it wins on order. */
.bk-content-col--wide { max-width: 1180px; }

/* The held-slot bar. Same visual language as the calendar's secondary nav
   (#selectedSlotBarPackages) — but that one starts hidden and is revealed by
   booking.js, and this one is server-rendered from a hold that already exists,
   so it cannot share the selector. */
/* ⚠ 8px, not the 12px this carried while the bar was one line. Stacking the pill
   above the date added a whole row, and a sticky bar spends that height on every
   screen of the journey at once — measured on a phone it reached 107px, which is a
   quarter of the viewport permanently spent on facts the customer already knows.
   The same trim is on #selectedSlotBarPackages, which is the same bar. */
.bk-slot-bar {
    background: var(--bg-color);
    border-bottom: 1px solid var(--border-muted);
    padding: 8px 0;
    position: sticky;
    top: 0;
    z-index: 400;
}
.mode-dark .bk-slot-bar { background: var(--bg-dark-color); }
.bk-slot-bar-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    /* ⚠ ROW gap first, and smaller than the column gap on purpose. This wraps on a
       phone, where the clock and "Change time" drop to their own line — a symmetric
       12px there reads as a paragraph break inside one control strip. */
    gap: 6px 12px;
    flex-wrap: wrap;
    max-width: 1180px;
    margin: 0 auto;
    padding: 0 24px;
}

/* The WHAT half of both held-slot bars — the pill (hold clock · service) on its own
   line, the chosen package on the line beneath it.

   ⚠⚠ ONE CLASS, BOTH BARS. .bk-slot-bar here and #selectedSlotBarPackages on the
      calendar cannot share markup — one is revealed and filled live by booking.js,
      the other is server-rendered from a hold that already exists — so a shared
      class is the only thing stopping them drifting into two arrangements of the
      same facts. Style this group here, never in either bar's own block.

   ⚠ STACKED AT EVERY WIDTH, deliberately. It used to be an inline row that wrapped
     only once the bar ran out of room, so the same bar read as one line on a laptop
     and two on a tablet, and the pill and the date changed places on a rotation.
     Owner's call, 2026-09-09.

   ⚠ align-items:flex-start, not stretch: .secondary-svc-pill is a pill, and a
     stretched one spans the width of the longest line under it.

   ⚠ min-width:0. The package carries white-space:nowrap, so without it this column
     sets the bar's own minimum width and pushes the right-hand group off a phone. */
.bk-slot-bar-booking {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    min-width: 0;
}

/* The WHEN half of both bars — "Change time" with the held date beneath it. Named
   for the same reason .bk-slot-bar-booking is: the two bars cannot share markup, so
   a shared class is what keeps them one bar to a customer.

   ⚠⚠ THE HELD DATE SITS HERE, NOT UNDER THE SERVICE PILL. It used to open the left
      column's second line, which put the bar's longest string ("Saturday, September
      19 · 5:42 PM") in the same column as its shortest and left the right of the bar
      carrying a single link. Owner's call, 2026-09-09. Move it and you move it on
      BOTH bars — the markup differs, this rule does not.

   ⚠ A COLUMN, MIRRORING .bk-slot-bar-booking, and right-aligned rather than merely
     pushed right: the two lines are different lengths, so align-items:flex-end is
     what keeps their right edges on the bar's edge instead of ragged.

   ⚠ justify-self:end is for the three-track grid below — it is what pins this group
     to the right edge of its own column once the bar carries a mark. Without it the
     group sits at the left of a column that is wider than it is. */
.bk-slot-bar-actions {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    min-width: 0;
    justify-self: end;
}

/* ⚠⚠ THE STUDIO'S MARK IS CENTRED ON THE BAR, NOT ON WHAT THE TWO GROUPS LEFT OVER —
   which is why the bar becomes a GRID the moment it carries one.

   FLEX CANNOT DO THIS. A middle item centres its content inside the space the groups
   either side did not take, so it lands (left − right) / 2 off the bar's own centre:
   tens of pixels off it on any step where one group runs longer than the other, which
   is most of them — the held date makes the right group the wider now, and a long
   package name can swing it back. Auto margins, space-between and equal flex-grow all
   reduce to the same offset — the leftover space is all flex can centre in. Three
   tracks sharing one flex factor put the middle one dead centre whatever the sides
   hold, because the outer two are always sized equal to each other.

   ⚠ minmax(min-content, 1fr) ON THE OUTER TRACKS, NOT A BARE 1fr. The held date, the
     package and the clock all carry white-space:nowrap, so a bare 1fr lets a narrow
     bar squeeze them out past their own boxes and under the logo. Floored at
     min-content they stop shrinking and the middle track gives up the room instead —
     the logo scales down on its max-width and the wording ellipsises — so a bar too
     tight to centre drifts off centre rather than overlapping.

   ⚠ :has() IS WHAT KEEPS THIS OFF A BAR WITH NO MARK. The cell renders only when the
     inherited Sticky Nav carries a logo, and two children in a three-track grid park
     the right-hand group in the middle column.

   ⚠ ≥576px ONLY. Below it this bar wraps "Change time" and the held date onto their
     own line — flex behaviour a fixed track count cannot express — and a phone has no
     spare width to centre anything in anyway. .bk-slot-bar-brand keeps its flex
     sizing for exactly that range. */
@media (min-width: 576px) {
    .bk-slot-bar-inner:has(.bk-slot-bar-brand),
    #selectedSlotBarPackages .px-4:has(.bk-slot-bar-brand) {
        display: grid;
        grid-template-columns: minmax(min-content, 1fr) minmax(0, 1fr) minmax(min-content, 1fr);
    }
}

/* ============================================================================
   THE PHONE COLLAPSE — below 576px the bar closes to ONE row: the hold clock, the
   studio's mark, and a chevron. The service, the package, the held date and
   "Change time" move into a panel underneath it. Owner's call, 2026-09-09.

   ⚠⚠ THE ARRANGEMENT IS A GRID, NOT THE WRAP IT REPLACES. The bar used to be
      flex-wrap here, so its three groups fought for one 375px line and the middle
      one — the studio's mark, which has no minimum of its own — was squeezed to
      nothing between them. Named areas put each group somewhere by name instead of
      by whatever room the group before it left, and .bk-slot-bar-booking becomes
      `display:contents` so the pill can sit on the closed row while the line under
      it drops into the panel. Those two are siblings in the markup and neither bar
      may be re-nested to separate them: the shared group classes and the DOM order
      both bars are pinned to are what stop them drifting apart.

   ⚠⚠ THE COLLAPSE IS GATED ON [data-bk-slot-panel], WHICH ONLY THE SCRIPT WRITES.
      That is the whole no-JS story and it is easy to undo by accident: hide the
      panel on the media query alone and a phone with JS off loses the held date,
      the package and the way back to the calendar, with no control on the page that
      could bring them back. The grid below is unconditional — it is simply a better
      stack — and only the hiding and the chevron are behind the attribute.

   ⚠ THE CHEVRON IS HIDDEN BY DEFAULT AND REVEALED BY THAT SAME ATTRIBUTE, rather
     than carrying `hidden` in the markup: `[hidden]` is a UA rule, so any class rule
     setting `display` beats it and the button would come back on exactly the pages
     where it does nothing. Same trap .dm-full documents two thousand lines up.

   ⚠ THE .bk-slot-bar-* CLASSES NAMED HERE BELONG TO THESE TWO BARS AND NOWHERE ELSE,
     which is why they are written unscoped, the way .bk-slot-bar-booking's own rule is.
     Reuse one of them somewhere else and it inherits a grid area on a phone.
     ⚠⚠ .secondary-svc-pill IS THE EXCEPTION AND ALREADY BIT ONCE: the step bar's
        countdown chip is built from that same class, so its rule below is scoped under
        .bk-slot-bar-booking. Unscoped, it hid both copies and left a held slot with no
        countdown anywhere on a phone.
   ============================================================================ */

/* The disclosure itself, declared BEFORE the breakpoint that places it so this stays
   its first rule in the file. Hidden everywhere by default — at ≥576px because the
   bar shows all of this at once, and below it until the script has proved it can open
   what the chevron promises.

   ⚠ THE ICON IS THE ONLY VISIBLE CONTENT, so the button carries an aria-label. The
     state is aria-expanded's to announce, which is also why the label does not change
     with it: "Your booking details" reads correctly collapsed and expanded, and a
     label that flipped would be announced as a rename mid-interaction.

   ⚠⚠ IT TAKES THE ACCENT, NOT --border-muted, AND THAT IS DISCOVERABILITY RATHER
      THAN DECORATION. On the closed bar this chevron is the ONLY way to the held
      date, the package and the way back to the calendar — everything the bar used to
      say out loud. Drawn in the muted divider colour it was a 12%-alpha grey ring
      that read as a disabled control, so the customer's own booking was behind
      something that did not look pressable. The accent is what "Change time" is
      drawn in on the same bar, which is the point: this is the control that stands in
      for it. No .mode-dark twin, for the same reason .change-time-link has none. */
.bk-slot-bar-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid var(--accent-orange);
    border-radius: 50%;
    background: none;
    color: var(--accent-orange);
    font-size: 0.78rem;
    line-height: 1;
    cursor: pointer;
}
.bk-slot-bar-toggle:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 2px; }
/* ⚠ The rotation is on the ICON, not the button: the button is the focus ring's
   element, and a rotated box turns the ring with it. */
.bk-slot-bar-toggle-icon { transition: transform 0.18s ease; }
.bk-slot-bar-toggle[aria-expanded="true"] .bk-slot-bar-toggle-icon { transform: rotate(180deg); }

@media (max-width: 575.98px) {
    /* ⚠⚠ `1fr auto 1fr`, AND THE OUTER TRACKS ARE WHAT CENTRE THE MARK. They share one
       flex factor, so they are always sized equal to each other and the middle track
       lands dead centre whatever sits either side of it — the same reasoning as the
       ≥576px rule above, arrived at the hard way. With `auto` on the outer tracks the
       mark centred inside its OWN track instead, which on a 375px phone put it 35px
       right of the bar's centre and hard against the chevron. Measured: 106px pill +
       115px mark + 20px gaps wants 347px of equal side tracks in 327px of bar, which
       is why the pill had to leave the row rather than be squeezed. */
    .bk-slot-bar-inner,
    #selectedSlotBarPackages .px-4 {
        display: grid;
        grid-template-columns: 1fr auto 1fr;
        grid-template-areas:
            "pill  brand  toggle"
            "what  what   what"
            "when  when   when";
        align-items: center;
        column-gap: 10px;
        /* ⚠⚠ ROW-GAP:0, AND THE PANEL'S SPACING IS A MARGIN INSTEAD. grid-template-areas
           declares all three rows whether or not anything sits in them, and a gutter is
           drawn between adjacent tracks even when both are zero high — so a row-gap here
           left 8px of dead space under a CLOSED bar, on the one screen this whole change
           exists to give height back to. A margin on the hidden element goes with it. */
        row-gap: 0;
    }

    /* Dissolved so its two children can land in different rows. Everything this
       group carries at wider widths is layout the grid is now doing. */
    .bk-slot-bar-booking { display: contents; }

    /* ⚠⚠ THE HOLD PILL LEAVES THE TOP BAR HERE AND IS DRAWN IN THE BOTTOM STEP BAR
       INSTEAD (.bk-stepbar-hold, from book/_flow-steps). It is the widest thing on the
       row and the least tied to a place, and with it here the mark cannot be centred at
       any phone width. It keeps its grid area so that showing it again is a one-line
       change rather than a rebuild. Owner's call, 2026-09-10: phones only — above
       576px the pill still opens the bar exactly as it did.

       ⚠⚠ SCOPED UNDER .bk-slot-bar-booking, AND THAT IS LOAD-BEARING. .secondary-svc-pill
          is no longer a class only the two top bars use: the step bar's copy is built
          from the same one, deliberately, so the two read as one chip. An unscoped
          `display: none` here therefore hides BOTH copies below 576px — the pill leaves
          the top bar and never arrives at the bottom, and a customer on a phone holds a
          slot with no countdown anywhere on screen. Nothing errors; the row is simply
          0px tall. */
    .bk-slot-bar-booking > .secondary-svc-pill { grid-area: pill; display: none; }
    .bk-slot-bar-toggle  { grid-area: toggle; justify-self: end; }
    .bk-slot-bar-what    { grid-area: what; margin-top: 4px; }

    /* ⚠ CAPPED, because the middle track is `auto` and would otherwise take a very wide
       logo's full width, leaving the 1fr tracks at their minimums — unequal, so the mark
       drifts off centre again and the chevron is squeezed. 55vw leaves both sides room
       at 320px, and most marks never reach it: the 26px height cap puts a typical one
       at about 115px. */
    .bk-slot-bar-brand   { grid-area: brand; max-width: 55vw; }

    /* ⚠ LEFT, not the flex-end it takes at wider widths. In the panel this is a
       full-width row under the service line, and a right-aligned pair there reads
       as a stray column rather than as the rest of one summary. The ORDER is
       untouched — "Change time" with the held date beneath it, the same on both
       bars and at every width; only the edge they hang off changes.

       ⚠⚠ justify-self MUST BE UNDONE HERE. The base rule sets `end` for the
          three-track grid at ≥576px, where this group is one column of three. In
          this grid it spans the full width, and `end` shrinks it to its own content
          and parks it on the right edge — so the panel reads as a right-aligned
          column under a left-aligned service line, which looks like a wrapping bug
          rather than a setting. */
    .bk-slot-bar-actions { grid-area: when; align-items: flex-start; justify-self: start; margin-top: 4px; }

    [data-bk-slot-panel] .bk-slot-bar-toggle { display: inline-flex; }

    [data-bk-slot-panel="closed"] .bk-slot-bar-what,
    [data-bk-slot-panel="closed"] .bk-slot-bar-actions { display: none; }
}

/* The held date, in two forms — "Friday, September 25 · 5:42 PM" and the medium
   "Fri, Sep 25 · 5:42 PM". The full form overflowed a phone, which is the symptom
   the regional-date build started from.

   ⚠⚠ THIS IS CSS AND MUST STAY CSS. The bar is server-rendered again on every
      booking step, so a JS resize listener would be right on the first paint and
      gone on the next; the media query survives rotation and a dragged window for
      free. Same reasoning as .dm-mobile-only.

   ⚠ display:none, not visibility/opacity: it keeps the hidden copy out of the
     accessibility tree, so a screen reader reads the date exactly once.

   Mobile-first — the medium form is the default and the full one is the ≥576px
   (Bootstrap `sm`) upgrade. */
.bk-slot-bar-when { display: none; }
.bk-slot-bar-when-sm { display: inline; }
@media (min-width: 576px) {
    .bk-slot-bar-when { display: inline; }
    .bk-slot-bar-when-sm { display: none; }
}
/* ⚠ THE PHONE NO LONGER SHRINKS THIS, and the removal is part of the same change
   rather than a taste one. It was set to 0.8rem on 2026-09-09 because the date had
   just moved into a narrow right-hand column of a flex-wrap bar, where a 320px
   screen could only hold both groups side by side at the smaller size. The phone
   collapse below gives the date a full-width row of its own — in the panel, or
   stacked when the script has not run — so it reads at the size the rest of the bar
   does. Put a shrink back only if something puts it beside another group again. */

/* The hold countdown. This slot used to hold the words "SLOT HELD" — a static label
   set in 0.68rem uppercase with tracking, which is right for a label and wrong for a
   number the eye returns to every few seconds. The padlock still carries "held"; the
   digits carry the urgency, so they are sized to be read rather than skimmed.

   ⚠ tabular-nums is load-bearing, not polish: proportional digits change width as the
     clock ticks, so every element to the right of the timer jitters once a second.

   ⚠⚠ BOTH REDS ARE FIXED BY CONTRAST, NOT BY TASTE, and they are what they are
      because this now sits INSIDE .secondary-svc-pill rather than on the bar's own
      ground. The pill's wash is a hardcoded 10% of #ee513a, so the surface under the
      digits is the same on every theme and the arithmetic holds:

        light — #dc2626 on that wash over --bg-color reads 4.07:1, UNDER AA for text
                this size. #b91c1c reads 5.45:1. On the bare bar #dc2626 passed at
                4.72:1, which is why moving the clock is what broke it.
        dark  — #dc2626 on the wash over --bg-dark-color reads 3.60:1 (and read 3.96:1
                on the bare bar, so this one has never passed). #f87171 reads 6.29:1.

      Lighten either one and check it; the digits are the element on this bar a
      customer is most likely to be reading in a hurry. */
.bk-slot-bar-held {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex-shrink: 0;
    white-space: nowrap;
    font-size: 0.8rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
    color: #b91c1c;
}
.mode-dark .bk-slot-bar-held { color: #f87171; }
.bk-slot-bar-held i { font-size: 0.72rem; }

/* WHAT THE CUSTOMER CHOSE, on one line: the service, then the chosen package.
   Second row of both bars, under the hold pill. Owner's call, 2026-09-09 — the
   two used to sit on separate rows either side of the pill, which read as a
   heading with a caption rather than as the one sentence they are.

   ⚠⚠ IT WRAPS, IT NEVER TRUNCATES. "Traditional Santa Photos · Digital Memories
      Pack" is wider than a 320px phone at this size, and an ellipsis here cuts a
      package name the customer is paying for. Both names keep white-space:nowrap
      and the ROW wraps between them, so a phone gets two lines and a laptop one —
      the same arrangement at every width, only re-flowed, which is the distinction
      .bk-slot-bar-booking's own rule draws.

   ⚠ The "·" is a flex child and lands at the END of the first line when the row
     wraps, the way a breadcrumb separator does. It is not worth a modifier to
     chase: it is 4px at 40% opacity, and hiding it would need a wrap detection CSS
     does not have.

   ⚠ row-gap:0. The two names are the same line-height, so any row gap here opens a
     paragraph break inside one sentence on exactly the narrow screens that can
     least afford the height. */
.bk-slot-bar-what {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 5px;
    row-gap: 0;
    min-width: 0;
}
/* ⚠ THE HEADING INK, NOT THE ACCENT. The service was accent-orange while it lived
   in the pill, where the whole chip is a wash of that accent. On the bar's own
   ground two accent-orange strings either side of a dot read as one link; the
   service takes the heading colour (matching .secondary-date, the bar's other
   plain fact) and the package keeps the accent, so the pair reads as "this
   session, with this package" rather than as two buttons. */
.bk-slot-bar-svc {
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--heading-color);
    white-space: nowrap;
}
.mode-dark .bk-slot-bar-svc { color: var(--font-dark-color); }
.bk-slot-bar-pkg {
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--accent-orange);
    white-space: nowrap;
}

/* ============================================================================
   BOOKING-PAGE TEXT PANEL — "Where to find us" / "Special Instructions" / the
   optional info link, drawn inside the booking card above the step heading and
   again in the add-ons stage (book/calendar.blade.php).

   Replaces a bare `.border.rounded.p-3.mb-4` with Bootstrap's `.text-muted`
   micro-labels. That treatment put the two most operationally important
   sentences on the page — where the studio actually is, and what to bring —
   into the lowest-contrast type on the card, inside a hairline box that read as
   a disabled field rather than as guidance. The rebuild gives it a real surface,
   an accent rail, and body-weight copy in the theme's own ink.

   ⚠ THEME TOKENS ONLY. This panel sits inside a card whose colours come from the
     tenant's selected microsite theme (--cart-grey / --font-color / --accent-*),
     so a literal grey here would be correct on theme-default and wrong on forest
     and rose. .mode-dark gets the dark twin of each, matching .location-card.

   ⚠ MIRRORED IN ADMIN as .bkp-pt-* in content/assets/css/booking-blocks.css.
     The Page Builder iframe loads NO Bootstrap and NO theme file, so it
     reproduces this geometry against its own tokens rather than sharing a
     stylesheet. Restyle one, restyle the other, or the builder previews a panel
     the customer never sees. Guarded by
     tests/booking_preview_storefront_parity_test.php.
   ========================================================================== */
.pagetext-card {
    display: flex;
    flex-direction: column;
    gap: 14px;
    margin-bottom: 24px;
    padding: 16px 18px;
    border-radius: 12px;
    border-left: 3px solid var(--accent-green);
    background-color: var(--cart-grey);
    color: var(--font-color);
    text-align: start;
}
.mode-dark .pagetext-card {
    background-color: var(--cart-dark-grey);
    color: var(--font-dark-color);
}
.pagetext-row {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}
/* The icon reads as a marker, not as decoration adrift in the left margin: a
   tinted chip the same green as the rail, sized to the label's cap height. */
.pagetext-icon {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 8px;
    background-color: rgba(44, 182, 167, 0.14);
    color: var(--accent-green);
    font-size: 0.78rem;
}
.pagetext-body { min-width: 0; }
.pagetext-label {
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    opacity: 0.7;
    margin-bottom: 2px;
}
/* Body weight and full contrast — this is the copy the customer came for. */
.pagetext-text {
    font-size: 0.95rem;
    line-height: 1.5;
    overflow-wrap: anywhere;
}
.pagetext-row--link { align-items: center; }
.pagetext-link {
    font-weight: 600;
    color: var(--accent-green);
    text-decoration: underline;
    overflow-wrap: anywhere;
}
.pagetext-link:hover,
.pagetext-link:focus { color: var(--accent-dark-green); }

@media (max-width: 575.98px) {
    .pagetext-card { padding: 14px; gap: 12px; }
    .pagetext-text { font-size: 0.9rem; }
}
