  * { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
  /* Disable text selection globally — prototype taps/swipes shouldn't trigger
     selection UI. Re-enabled on form inputs below so search/location fields
     still work. */
  html, body { -webkit-user-select: none; user-select: none; }
  input, textarea { -webkit-user-select: text; user-select: text; }

  body {
    font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', sans-serif;
    background: #fff;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    overflow: hidden;
  }

  /* iPhone frame for desktop. Stronger border + soft shadow so the device
     reads as a distinct surface against a white page; the previous 1px
     #e4e5e7 against #fff body was effectively invisible (especially on
     high-DPI displays where 1px sub-pixels). */
  .device-frame {
    width: 393px;
    height: 852px;
    background: #fff;
    border: 1px solid #dfe2e5;
    border-radius: 40px;
    overflow: hidden;
    position: relative;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.08);
  }

  /* On mobile, go full screen */
  @media (max-width: 430px) {
    body { background: #fff; align-items: flex-start; }
    .device-frame {
      width: 100vw;
      height: 100vh;
      height: 100dvh;
      border: none;
      border-radius: 0;
      box-shadow: none;
    }
  }

  /* Persistent map backdrop */
  #live-map {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    z-index: 0;
    background: #e8e8e8;
    filter: none;
  }

  /* Screen container */
  .screen {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    width: 100%;
    height: 100%;
    display: none;
    flex-direction: column;
    background: #fff;
    overflow: hidden;
    z-index: 1;
  }
  .screen.active {
    display: flex;
  }
  /* Map screens are transparent — the map shows through from behind */
  .screen.map-screen {
    background: transparent;
    pointer-events: none;
  }
  /* Re-enable pointer events on interactive children within map screens */
  .screen.map-screen > * {
    pointer-events: auto;
  }

  /* Transitions */
  .screen.anim-fade-in {
    animation: fadeIn 0.25s ease-in;
  }
  .screen.anim-fade-out {
    animation: fadeOut 0.35s ease-out forwards;
    z-index: 5;
  }
  .screen.anim-fade-out-behind {
    animation: fadeOut 0.2s ease-in forwards;
  }
  .screen.anim-bg-fade-in {
    background: transparent;
    animation: fadeIn 0.2s ease-in backwards;
  }
  .screen.anim-bg-fade-in::before {
    content: '';
    position: absolute;
    inset: 0;
    background: #f1f2f3;
    animation: fadeIn 0.2s ease-in forwards;
    z-index: -1;
  }
  .screen.anim-bg-fade-in > *:not(.search-bar-container):not(.status-bar):not(.keyboard):not(.map-overlay-bar) {
    animation: fadeIn 0.2s ease-in backwards;
  }
  .screen.anim-bg-fade-in > .search-bar-container {
    animation: fadeIn 0.2s ease-in backwards;
  }
  .screen.anim-bg-fade-out {
    background: transparent;
    z-index: 5;
  }
  .screen.anim-bg-fade-out::before {
    content: '';
    position: absolute;
    inset: 0;
    background: #f1f2f3;
    animation: fadeOut 0.2s ease-in forwards;
    z-index: -1;
  }
  .screen.anim-bg-fade-out > *:not(.status-bar):not(.keyboard) {
    animation: fadeOut 0.2s ease-in forwards;
  }
  .screen.anim-slide-up {
    animation: slideUp 0.3s ease-out;
    z-index: 5;
  }

  .screen.anim-screen-fade-in {
    animation: fadeIn 0.25s ease-in forwards;
    z-index: 5;
  }

  .screen.anim-slide-down {
    animation: slideDown 0.25s ease-in forwards;
    z-index: 5;
  }
  @keyframes fadeIn {
    from { opacity: 0; } to { opacity: 1; }
  }
  @keyframes fadeOut {
    from { opacity: 1; } to { opacity: 0; }
  }
  @keyframes bgFadeIn {
    from { background-color: transparent; } to { background-color: #f1f2f3; }
  }
  @keyframes bgFadeOut {
    from { background-color: #f1f2f3; } to { background-color: transparent; }
  }
  @keyframes slideUp {
    from { transform: translateY(100%); } to { transform: translateY(0); }
  }
  @keyframes slideDown {
    from { transform: translateY(0); } to { transform: translateY(100%); }
  }
  @keyframes kbSlideUp {
    from { transform: translateY(100%); } to { transform: translateY(0); }
  }
  .keyboard.anim-kb-slide-up {
    animation: kbSlideUp 0.3s ease-out;
  }
  @keyframes kbSlideDown {
    from { transform: translateY(0); } to { transform: translateY(100%); }
  }
  .keyboard.anim-kb-slide-down {
    animation: kbSlideDown 0.3s ease-in forwards;
  }
  @keyframes closeBtnSlideIn {
    from { margin-left: -52px; opacity: 0; transform: translateX(52px); }
    to   { margin-left: 0;    opacity: 1; transform: translateX(0); }
  }
  @keyframes closeBtnSlideOut {
    from { margin-left: 0;    opacity: 1; transform: translateX(0); }
    to   { margin-left: -52px; opacity: 0; transform: translateX(52px); }
  }
  .search-bar-container.anim-search-enter .close-btn {
    animation: none;
  }
  .search-bar-container.anim-search-exit .close-btn {
    animation: none;
  }

  /* Status bar */
  .status-bar {
    flex-shrink: 0;
    z-index: 10;
    width: 100%;
    transition: opacity 0.15s ease-out;
  }
  .status-bar img {
    width: 100%;
    height: auto;
    display: block;
    object-fit: contain;
  }

  /* ========== MAP SCREEN (image-based) ========== */
  .map-screen {
    position: relative;
  }
  .map-screen > img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top;
  }
  .map-search-hotspot {
    position: absolute;
    top: 26px;
    left: 8px;
    right: 8px;
    height: 62px;
    cursor: pointer;
    z-index: 20;
    border-radius: 12px;
  }
  .map-x-hotspot {
    position: absolute;
    top: 26px;
    right: 8px;
    width: 52px;
    height: 62px;
    cursor: pointer;
    z-index: 21;
  }

  /* Dynamic search bar overlay on map result screens */
  .map-overlay-bar {
    position: absolute;
    top: 62px;
    left: 0;
    right: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 24px;
  }
  .map-search-pill {
    flex: 1;
    display: flex;
    align-items: center;
    height: 48px;
    gap: 4px;
    background: #fff;
    border-radius: 9999px;
    padding: 0 16px;
    cursor: pointer;
    box-shadow: 0 1px 4px rgba(0,0,0,0.08);
  }
  .map-search-pill .pill-icon {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    color: #8e8e93;
  }
  .map-search-pill .pill-text {
    flex: 1;
    font-size: 16px;
    color: #000;
    font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', sans-serif;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .pill-clear-btn {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
  }
  .map-close-pill {
    width: 44px;
    height: 44px;
    background: #fff;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
    box-shadow: 0 1px 4px rgba(0,0,0,0.08);
  }
  .map-close-pill svg { width: 20px; height: 20px; color: #000; }

  /* ========== SEARCH / INPUT SCREENS ========== */
  .input-screen {
    background: #f1f2f3;
  }

  /* Search bar area — two stacked fields */
  .search-bar-container {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 8px 24px 16px;
    flex-shrink: 0;
    background: #f1f2f3;
  }
  .search-field {
    display: flex;
    align-items: center;
    height: 48px;
    width: 100%;
    background: #fff;
    border-radius: 40px;
    padding: 0 16px;
    gap: 12px;
    box-sizing: border-box;
  }
  .back-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: #020203;
    cursor: pointer;
    width: 24px;
    height: 24px;
  }
  .search-field input {
    flex: 1;
    border: none;
    outline: none;
    font-size: 16px;
    font-weight: 400;
    font-family: 'DM Sans', -apple-system, sans-serif;
    background: transparent;
    color: #020203;
  }
  .search-field input::placeholder {
    color: #717171;
  }
  #search-input-field {
    font-size: 16px;
    color: #020203;
  }
  .search-field .clear-btn {
    width: 20px;
    height: 20px;
    background: #c7c7cc;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
  }
  .search-field .clear-btn.hidden { display: none; }
  .search-field .clear-btn svg { width: 10px; height: 10px; color: #fff; }


  /* Location field */
  .location-field {
    display: flex;
    align-items: center;
    height: 48px;
    width: 100%;
    background: #fff;
    border-radius: 24px;
    padding: 0 16px;
    gap: 10px;
    box-sizing: border-box;
  }
  .location-field .loc-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    background: unset;
    background-color: unset;
    color: rgba(0, 0, 0, 0);
  }
  .location-field .loc-icon svg { width: 24px; height: 24px; }
  .location-field input {
    flex: 1;
    border: none;
    outline: none;
    font-size: 16px;
    font-family: inherit;
    background: transparent;
    color: #000;
  }
  .location-field input::placeholder { color: #717171; }
  #location-input-field {
    font-size: 16px;
  }
  .location-field .clear-btn {
    width: 20px;
    height: 20px;
    background: #c7c7cc;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
  }
  .location-field .clear-btn.hidden { display: none; }
  .location-field .clear-btn svg { width: 10px; height: 10px; color: #fff; }

  #unified-search-field { gap: 4px; padding-left: 16px; padding-right: 16px; }
  #unified-location-field { gap: 4px; padding-left: 16px; padding-right: 16px; }

  /* Current location link — Figma: neutral hover pill, 8px gap, left-aligned */
  .location-section {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 12px 24px 24px;
    flex-shrink: 0;
  }
  .location-section-heading {
    font-size: 20px;
    font-weight: 900;
    color: #020203;
    line-height: 28px;
    font-family: 'DM Sans', -apple-system, sans-serif;
  }
  .current-location {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 16px;
    background: #fff;
    border-radius: 24px;
    cursor: pointer;
  }
  .current-location:active {
    background: #f5f5f5;
  }
  .current-location .loc-arrow-icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
  }
  .current-location .loc-arrow-icon img {
    width: 16px;
    height: 16px;
  }
  .current-location .loc-label {
    flex: 1;
    font-size: 16px;
    font-weight: 400;
    color: #000;
    font-family: 'DM Sans', -apple-system, sans-serif;
  }
  .current-location .loc-chevron {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .current-location .loc-chevron svg {
    width: 8px;
    height: 13px;
    color: #c7c7cc;
  }

  /* Content area */
  .content-area {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 20px;
    scrollbar-width: thin;
    scrollbar-color: transparent transparent;
    transition: scrollbar-color 0.25s ease;
  }
  .content-area.is-scrolling {
    scrollbar-color: rgba(0, 0, 0, 0.28) transparent;
  }
  .content-area::-webkit-scrollbar { width: 4px; }
  .content-area::-webkit-scrollbar-track { background: transparent; }
  .content-area::-webkit-scrollbar-thumb {
    background-color: transparent;
    border-radius: 4px;
    transition: background-color 0.25s ease;
  }
  .content-area.is-scrolling::-webkit-scrollbar-thumb {
    background-color: rgba(0, 0, 0, 0.28);
  }

  /* Section heading — Figma heading/h3: 20px, black */
  .section-heading {
    font-family: "DM Sans";
    font-size: 20px;
    font-weight: 900;
    padding: 12px 20px 4px;
    color: #020203;
    line-height: 28px;
  }
  .section-heading-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 20px 4px;
  }
  .section-heading-row h2 {
    font-family: "DM Sans";
    font-size: 20px;
    font-weight: 900;
    color: #020203;
    line-height: 28px;
    display: flex;
    align-items: center;
    gap: 6px;
  }
  .section-heading-row h2 .chevron {
    display: flex;
    align-items: center;
    flex-shrink: 0;
  }
  .section-heading-row h2 .chevron svg {
    width: 10px;
    height: 16px;
    color: #c7c7cc;
  }
  .section-heading-row .clear-link {
    font-size: 15px;
    color: #8e8e93;
    cursor: pointer;
  }

  /* Category chips — Figma: white card 24px radius, chip pill 64px radius, 14px semibold */
  .chips-container {
    padding: 4px 20px;
  }
  .chips-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    background: #fff;
    border-radius: 24px;
    padding: 16px;
  }
  .chip {
    padding: 8px 12px;
    background: #f1f1f4;
    border-radius: 64px;
    font-size: 14px;
    font-weight: 600;
    color: #020203;
    cursor: pointer;
    transition: background 0.15s;
  }
  .chip:active { background: #e3e4e8; }

  /* Recents chips */
  .recents-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    background: #fff;
    border-radius: 16px;
    padding: 16px;
    margin: 4px 20px 0;
  }

  /* Current location CTA */
  .current-location-cta {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 34px;
    cursor: pointer;
  }
  .current-location-cta:active {
    opacity: 0.6;
  }
  .cta-icon-pill {
    width: 32px;
    height: 32px;
    background: #e4e5e7;
    border-radius: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
  }
  .cta-label {
    font-size: 16px;
    font-weight: 500;
    color: #020203;
  }

  /* Autocomplete results */
  .autocomplete-list {
    margin: 0 20px;
    background: #fff;
    border-radius: 16px;
    overflow: hidden;
  }
  .autocomplete-item {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 16px;
    cursor: pointer;
    transition: background 0.15s;
  }
  .autocomplete-item:active { background: #f2f2f7; }
  .autocomplete-item + .autocomplete-item {
    border-top: none;
  }
  .autocomplete-item .ac-icon {
    width: 36px;
    height: 36px;
    background: #f2f2f7;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
  }
  .autocomplete-item .ac-icon svg { width: 16px; height: 16px; color: #8e8e93; }
  .autocomplete-item .ac-text {
    font-size: 17px;
    color: #000;
    font-family: 'DM Sans', -apple-system, sans-serif;
  }
  .autocomplete-item .ac-text strong { font-weight: 500; }

  /* Location autocomplete */
  .loc-autocomplete-item {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 16px;
    cursor: pointer;
    transition: background 0.15s;
  }
  .loc-autocomplete-item:active { background: #f2f2f7; }
  .loc-autocomplete-item + .loc-autocomplete-item {
    border-top: none;
  }
  .loc-autocomplete-item .loc-ac-icon {
    width: 36px;
    height: 36px;
    background: #e4e5e7;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
  }
  .loc-autocomplete-item .loc-ac-icon svg { width: 24px; height: 24px; color: #6e6e73; }
  .loc-autocomplete-item .loc-ac-info { display: flex; flex-direction: column; gap: 2px; }
  .loc-autocomplete-item .loc-ac-name { font-size: 17px; color: #000; }
  .loc-autocomplete-item .loc-ac-name strong { font-weight: 500; }
  .loc-autocomplete-item .loc-ac-sub { font-size: 13px; color: #8e8e93; }

  /* Keyboard */
  .keyboard {
    background: #e1e4e7;
    padding: 12px 0 10px;
    border-radius: 28px 28px 0 0;
    flex-shrink: 0;
  }
  .keyboard-keys {
    display: flex;
    flex-direction: column;
    gap: 11px;
    padding: 12px 8.5px 0;
  }
  .keyboard-row {
    display: flex;
    justify-content: center;
    gap: 6px;
  }
  .keyboard-row.row-2 { padding: 0 20px; }
  .keyboard-row.row-3 { gap: 14.25px; }
  .row-3-letters { display: flex; flex: 1; gap: 6px; height: 45px; }
  .key {
    flex: 1;
    height: 45px;
    background: #fff;
    border-radius: 8.5px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: -apple-system, 'SF Pro', 'SF Compact', 'Helvetica Neue', sans-serif;
    font-size: 25px;
    font-weight: 400;
    color: #595959;
    box-shadow: none;
    cursor: pointer;
    user-select: none;
  }
  .key:active { background: #cdd0d6; }
  .key.shift {
    flex: 0 0 44.667px;
  }
  .key.shift, .key.backspace { display: flex; align-items: center; justify-content: center; }
  .key.shift img, .key.backspace img, .key.shift svg, .key.backspace svg { width: 23px; height: 20px; }
  .key.backspace {
    flex: 0 0 45px;
  }
  .key.space { flex: 1; }
  .key.search-key {
    flex: 0 0 92px;
    background: #131414;
    border-radius: 8.5px;
    color: #fff;
  }
  .key.search-key { display: flex; align-items: center; justify-content: center; }
  .key.search-key img { width: 100%; height: 100%; object-fit: contain; border-radius: 8.5px; }
  .key.num { flex: 0 0 45px; font-size: 18px; font-family: -apple-system, 'SF Compact Rounded', 'SF Pro Rounded', sans-serif; }
  .key.emoji { flex: 0 0 45px; font-size: 24px; }
  .keyboard-bottom {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 70px;
    padding: 27px 39px 15px 36px;
  }
  .keyboard-bottom img.kb-globe { width: 26px; height: 26px; }
  .keyboard-bottom img.kb-mic { width: 19px; height: 28px; }

  /* Explore cards (for screen 09 variant) */
  .explore-cards {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    padding: 0 20px;
  }
  .explore-card {
    background: #f2f2f7;
    border-radius: 12px;
    padding: 14px;
    height: 80px;
    display: flex;
    align-items: flex-end;
    font-size: 15px;
    font-weight: 600;
    color: #000;
    cursor: pointer;
    position: relative;
    overflow: hidden;
  }
  .explore-card::after {
    content: '';
    position: absolute;
    top: 8px;
    right: 8px;
    width: 50px;
    height: 50px;
    background: #d8d8dc;
    border-radius: 8px;
    transform: rotate(12deg);
  }

  /* old tab bar styles removed — see new .tab-bar below */
  .tab-item.active svg { color: #E10E0E; }
  .tab-item.active span { color: #E10E0E; }
  .tab-item:not(.active) svg { color: #000; }
  .tab-item:not(.active) span { color: #000; }

  /* Helper */
  .hidden { display: none !important; }

  /* Prototype hint overlay */
  .hint-overlay {
    position: absolute;
    bottom: 114px;
    left: 50%;
    transform: translateX(-50%);
    background: rgba(0,0,0,0.7);
    color: #fff;
    padding: 10px 20px;
    border-radius: 20px;
    font-size: 13px;
    font-weight: 500;
    z-index: 100;
    pointer-events: none;
    opacity: 1;
    transition: opacity 0.5s;
    white-space: nowrap;
  }
  .hint-overlay.fade-out { opacity: 0; }

  /* ========== INTERACTIVE MAP ========== */
  .mapboxgl-canvas {
    filter: none;
  }
  .mapboxgl-ctrl-attrib,
  .mapboxgl-ctrl-logo,
  .mapboxgl-ctrl { display: none !important; }
  .playlist-pin {
    background: none !important;
    border: none !important;
    /* No explicit size — the child element (SVG <img> for venue pins,
       .user-location-dot for the blue dot, inline SVG for location pin)
       supplies its own intrinsic dimensions. The default pin SVG is 37×48
       with its tip at y≈28 (rest is drop shadow). Mapbox markers default
       to a center anchor, so the tip lands a few pixels below the actual
       lng/lat — intentional, makes the pin look like it "rests on" the
       location with its shadow on the ground. */
    cursor: pointer;
    line-height: 0; /* prevent inline-image whitespace from inflating the box */
  }
  .playlist-pin img {
    display: block;
    pointer-events: none; /* clicks bubble up to .playlist-pin's click handler */
    -webkit-user-drag: none;
    user-select: none;
  }
  /* ========== HTML CLUSTER MARKER ==========
     Replaces the old Mapbox cluster symbol + text layers so the count
     can render in DM Sans (Mapbox glyph fonts don't include our app
     fonts) and the bubble can scale up on tap via CSS.

     Structure: .cluster-pin (Mapbox positions this) → .cluster-pin-inner
     (gets the scale transform on tap, isolated from Mapbox's translate
     on the outer element) → SVG <img> + count <span>. */
  .cluster-pin {
    line-height: 0;
    /* The marker box is 80×80 (room for the drop shadow) but the visible
       bubble is only ~28px wide, so adjacent markers' boxes overlap. Make the
       box itself non-clickable and limit the hit area to the bubble (::after
       below) — otherwise a neighbouring cluster's box steals the tap and the
       wrong cluster scales up. Clicks on the bubble still bubble to this
       element's listener despite pointer-events:none here. !important beats
       the inline `pointer-events: auto` Mapbox sets on every marker element;
       pointer-events is inherited, so the inner box goes none too and only the
       ::after (explicit auto) stays hittable. */
    pointer-events: none !important;
  }
  /* Clickable hit target limited to the visible red bubble (centered at
     ~40,26 in the 80×80 canvas, radius ~14) so overlapping marker boxes can't
     capture each other's taps. */
  .cluster-pin-inner::after {
    content: '';
    position: absolute;
    top: 26px;
    left: 50%;
    width: 32px;
    height: 32px;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    pointer-events: auto;
    cursor: pointer;
  }
  .cluster-pin-inner {
    position: relative;
    transform: scale(1);
    /* Anchor at the teardrop's bottom tip (~y=43 in the 80px SVG) so the pin
       grows UPWARD on tap, keeping the point planted at the map location.
       One gentle overshoot via the easing's >1 control point (1.3) — both
       the pop-up and the release back to scale(1) share this transition. */
    transform-origin: 50% 43px;
    transition: transform 0.3s cubic-bezier(.34, 1.3, .64, 1);
  }
  .cluster-pin.is-tapped .cluster-pin-inner {
    transform: scale(1.6);
  }
  @media (prefers-reduced-motion: reduce) {
    .cluster-pin-inner { transition: none; }
  }
  .cluster-pin img {
    display: block;
    pointer-events: none;
    -webkit-user-drag: none;
    user-select: none;
  }
  /* Count text sits on the red bubble. pin-cluster.svg has its bubble
     centered at (40.375, 26) in the 80×80 canvas — so the count's
     center lands at (50%, 26). */
  .cluster-count {
    position: absolute;
    top: 26px;
    left: 50%;
    transform: translate(-50%, -50%);
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 700;
    line-height: 1;
    color: #ffffff;
    pointer-events: none;
    user-select: none;
    -webkit-font-smoothing: antialiased;
  }
  .pin-dot-numbered {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: linear-gradient(to bottom, #FF5858, #CA0D0D);
    border: 3px solid white;
    box-shadow: 0 3px 3px rgba(0,0,0,0.25);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    font-weight: 600;
    color: white;
    font-family: 'DM Sans', -apple-system, sans-serif;
  }
  .user-location-wrapper {
    position: relative;
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: visible;
  }
  .user-location-dot {
    position: relative;
    z-index: 1;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: white;
    box-shadow: 0 1px 4px rgba(0,0,0,0.3);
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .user-location-dot::after {
    content: '';
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #0569FF;
    animation: location-pulse 2.5s ease-in-out infinite;
  }
  @keyframes location-pulse {
    0%, 100% { transform: scale(0.9); }
    50%      { transform: scale(1.05); }
  }

  /* Visible search pill on default map screen */
  .map-search-pill-default {
    position: absolute;
    top: 62px;
    left: 24px;
    right: 24px;
    height: 48px;
    background: rgba(255,255,255,0.89);
    border-radius: 40px;
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 0 16px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
    z-index: 20;
    cursor: pointer;
    color: #4F5159;
    font-size: 16px;
    font-family: 'DM Sans', -apple-system, sans-serif;
  }
  .map-search-pill-default .pill-icon { flex-shrink: 0; display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; }

  /* Search this area button */
  .search-this-area-btn {
    position: absolute;
    top: 122px; /* 62px pill top + 48px pill height + 12px gap */
    left: 50%;
    transform: translateX(-50%);
    background: #020203;
    color: #fff;
    border: none;
    border-radius: 64px;
    padding: 12px 16px;
    font-family: 'DM Sans', -apple-system, sans-serif;
    font-weight: 600;
    font-size: 14px;
    line-height: 20px;
    white-space: nowrap;
    cursor: pointer;
    box-shadow: 0 2px 8px rgba(0,0,0,0.12);
    z-index: 25;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease, transform 0.12s cubic-bezier(.25,.46,.45,.94);
  }
  .search-this-area-btn:active {
    /* Preserve the centering translate, just add the press scale on top. */
    transform: translateX(-50%) scale(0.96);
  }
  .search-this-area-btn.visible {
    opacity: 1;
    pointer-events: auto;
  }

  /* Current location / navigate button on map */
  .map-nav-btn {
    position: absolute;
    right: 16px;
    z-index: 9;
    width: 48px;
    height: 48px;
    background: white;
    border-radius: 100px;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 12px rgba(45,45,45,0.2);
    border: 1px solid rgba(255,255,255,0.35);
    cursor: pointer;
    padding: 12px;
    transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.35s cubic-bezier(0.4, 0, 0.2, 1);
  }
  .map-nav-btn.collapsed {
    transform: translateY(291px);
  }
  .map-nav-btn img, .map-nav-btn svg {
    width: 24px;
    height: 24px;
  }
  .map-nav-btn.active svg path {
    fill: #0569FF;
  }

  /* Tab bar */
  .tab-bar {
    position: absolute;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%);
    width: 349px;
    height: 62px;
    background: rgba(255,255,255,0.55);
    -webkit-backdrop-filter: blur(20px) saturate(1.6);
    backdrop-filter: blur(20px) saturate(1.6);
    border: 1px solid rgba(255,255,255,0.5);
    border-radius: 100px;
    box-shadow: 0 4px 20px rgba(0,0,0,0.15);
    display: flex;
    align-items: center;
    padding: 4px;
    z-index: 25;
  }
  .tab-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    height: 54px;
    border-radius: 100px;
    padding: 4px;
    cursor: pointer;
    position: relative;
  }
  .tab-item.active {
    position: relative;
  }
  .tab-item.active::before {
    content: '';
    position: absolute;
    inset: 0;
    background: rgba(219,219,219,0.5);
    border-radius: 100px;
    pointer-events: none;
    z-index: 0;
  }
  .tab-item.active svg, .tab-item.active span {
    position: relative;
    z-index: 1;
  }
  .tab-item img, .tab-item svg {
    width: 24px;
    height: 24px;
  }
  .tab-item span {
    font-size: 11px;
    font-weight: 500;
    color: black;
    font-family: 'DM Sans', -apple-system, sans-serif;
    text-align: center;
    line-height: 14px;
  }

  /* ========== BOTTOM SHEET ========== */
  .results-sheet {
    position: absolute;
    bottom: -266px; /* overflow so translateY(-266) still reaches screen bottom */
    left: 0;
    right: 0;
    height: 726px; /* 460px visible + 266px overflow to cover full screen when dragged up */
    background: #f1f2f3;
    border-radius: 32px 32px 0 0;
    z-index: 10;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
    user-select: none;
  }
  .results-sheet.collapsed {
    transform: translateY(291px); /* sheet top lands at ~683px from screen top */
  }
  .results-sheet.expanded {
    transform: translateY(-266px); /* sheet top lands at ~126px = 16px below search bar */
  }
  .sheet-handle {
    width: 49px;
    height: 6px;
    background: rgba(17,17,17,0.3);
    border-radius: 20px;
    margin: 8px auto 0;
    flex-shrink: 0;
  }

  /* Cluster venues sheet — same geometry as .results-sheet (bottom:-266,
     height 726) so translateY(0) lands at the default ~half-open position
     and translateY(-266) reaches 16px below the search bar. Transform is
     driven entirely from JS (inline style); classes here only control
     visibility + the expanded-state list scroll. z-index 31 sits above the
     tab bar (30), its blur (25), and the "Search this area" button (25) so
     the open sheet covers them, but BELOW #venue-detail (32) so tapping a
     venue card opens its detail on top of (not behind) this sheet — the sheet
     stays put and is revealed again when the detail closes. Stays at
     device-frame level (NOT re-parented into a screen, whose z-index:1 context
     would trap it below the tab bar). */
  .cluster-sheet {
    position: absolute;
    bottom: -266px;
    left: 0;
    right: 0;
    height: 726px;
    background: #f1f2f3;
    border-radius: 32px 32px 0 0;
    z-index: 31;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    transform: translateY(760px);
    visibility: hidden;
    transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
    user-select: none;
  }
  .cluster-sheet.is-open {
    visibility: visible;
  }
  /* The header now covers from the sheet top (to kill the seam), so lift the
     handle above it (header is z-index:2) to keep it visible. */
  .cluster-sheet .sheet-handle {
    position: relative;
    z-index: 3;
  }
  /* Header is lifted OUT of flow and overlaid on top of the list (which is
     padded to rest below it). Solid #F1F2F3 behind the title, fading to
     transparent over the lower ~half, so venue cards dissolve into the sheet
     as they scroll up underneath it. pointer-events:none lets scroll/drag
     pass through to the cards (the close button re-enables its own). */
  .cluster-sheet-header {
    position: absolute;
    top: 0;               /* cover from the very top of the sheet so the solid
                             region overlaps the list's overflow-clip boundary
                             (~14px) with margin — otherwise a sub-pixel seam at
                             that boundary lets a 1px line of the card behind
                             peek through below the handle. The drag handle is
                             raised above this via z-index. */
    left: 0;
    right: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px 20px 38px;   /* 24px top keeps the title where it was after
                                  moving top 14px→0; header is ~86px tall */
    /* Solid down past the title (~64%) so scrolling cards are hidden behind a
       clean buffer below the title, then a gradual fade over the lower third so
       cards dissolve softly into the sheet (not a hard grey block). The list's
       padding-top is matched to the fade's end so the first card rests just
       clear of it. */
    background: linear-gradient(180deg, #F1F2F3 0%, #F1F2F3 24%, rgba(241, 242, 243, 0.00) 100%);
    z-index: 2;
    pointer-events: none;
  }
  .cluster-sheet-close {
    position: absolute;
    left: 20px;
    top: 36px;            /* aligned to the title row (was 22px; +14 to track the
                             header's top moving 14px→0) */
    transform: translateY(-50%);
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 2px 8px rgba(0,0,0,0.12);
    border: none;
    cursor: pointer;
    display: grid;
    place-items: center;
    padding: 0;
    pointer-events: auto;   /* header is pointer-events:none; re-enable the button */
    z-index: 1;
  }
  .cluster-sheet-close:active { background: #f4f4f6; }
  .cluster-sheet-title {
    margin: 0;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
  }
  /* Default (half-open) keeps the list non-scrollable so a drag anywhere
     expands the sheet; once expanded the list scrolls under the header. */
  /* padding-top drops the first card clear of the overlaid header so it isn't
     covered (cards still scroll up under the header's fade). The selector
     includes .venue-list to out-specify the `.venue-list` shorthand `padding`
     declared further down — otherwise that shorthand resets padding-top to 4px. */
  .cluster-sheet-list.venue-list { overflow-y: hidden; padding-top: 72px; }
  .cluster-sheet.is-expanded .cluster-sheet-list { overflow-y: auto; }

  /* Filter bar */
  .filter-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 14px 20px 10px;
    flex-shrink: 0;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .filter-bar::-webkit-scrollbar { display: none; }

  .filter-toggle {
    display: flex;
    background: #e3e4e8;
    border-radius: 25px;
    padding: 4px;
    flex-shrink: 0;
  }
  .filter-toggle .toggle-opt {
    padding: 8px 16px;
    border-radius: 20px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .filter-toggle .toggle-opt.active {
    background: white;
  }
  .filter-toggle .toggle-opt svg, .filter-toggle .toggle-opt img { width: 20px; height: 20px; }

  .filter-chip {
    display: flex;
    align-items: center;
    gap: 4px;
    background: white;
    border-radius: 64px;
    padding: 10px 16px;
    font-size: 14px;
    font-weight: 600;
    color: #282828;
    white-space: nowrap;
    flex-shrink: 0;
    cursor: pointer;
    font-family: 'DM Sans', -apple-system, sans-serif;
  }
  .filter-chip svg { width: 10px; height: 10px; flex-shrink: 0; }

  /* Venue list */
  .venue-list {
    flex: 1;
    overflow-y: hidden;
    padding: 4px 20px 100px;
    display: flex;
    flex-direction: column;
    gap: 16px;
    -webkit-overflow-scrolling: touch;
    -ms-overflow-style: none;
    scrollbar-width: none;
  }
  .results-sheet.expanded .venue-list {
    overflow-y: auto;
  }
  .venue-list::-webkit-scrollbar { display: none; }

  .venue-card {
    background: white;
    border-radius: 24px;
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
  .venue-intro-badge {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 8px;
  }
  .venue-intro-badge svg { display: block; flex-shrink: 0; }
  .venue-intro-badge-label {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 700;
    line-height: 20px;
    color: #296b49;
  }
  .venue-header {
    display: flex;
    gap: 12px;
  }
  .venue-image {
    width: 108px;
    height: 108px;
    background: #e4e5e7;
    border-radius: 16px;
    flex-shrink: 0;
  }
  .venue-info {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 0;
    min-width: 0;
  }
  .venue-info-text {
    display: flex;
    flex-direction: column;
    gap: 0;
  }
  .venue-title {
    font-size: 18px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
    font-family: 'DM Sans', -apple-system, sans-serif;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .venue-tags {
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
    color: #90939d;
    font-family: 'DM Sans', -apple-system, sans-serif;
  }
  .venue-rating {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 13px;
    line-height: 16px;
    font-family: 'DM Sans', -apple-system, sans-serif;
  }
  .venue-rating .star-icon { width: 12px; height: 12px; flex-shrink: 0; }
  .venue-rating-score { font-weight: 700; color: #020203; }
  .venue-rating-reviews { font-weight: 500; color: #90939d; }
  .venue-rating-distance { font-weight: 500; color: #90939d; }
  .venue-desc {
    font-size: 14px;
    font-weight: 500;
    color: #90939d;
    line-height: 20px;
    font-family: 'DM Sans', -apple-system, sans-serif;
  }
  .venue-action-btn {
    align-self: flex-start;
    margin-top: 8px;
    display: flex;
    align-items: center;
    gap: 8px;
    background: #f1f2f3;
    border-radius: 999px;
    padding: 8px 12px;
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
    cursor: pointer;
    font-family: 'DM Sans', -apple-system, sans-serif;
  }
  .venue-action-btn svg, .venue-action-btn img { width: 20px; height: 20px; flex-shrink: 0; }

  /* ========== SEARCH TAB TOGGLE ========== */
  .search-toggle-wrapper {
    padding: 8px 24px 12px;
    flex-shrink: 0;
  }
  .search-toggle {
    position: relative;
    display: flex;
    align-items: center;
    background: #fff;
    border-radius: 24px;
    padding: 4px;
    gap: 12px;
  }
  .search-toggle::before {
    content: '';
    position: absolute;
    top: 4px;
    bottom: 4px;
    left: 4px;
    width: calc(50% - 10px);
    background: #f1f2f3;
    border-radius: 64px;
    transition: left 0.2s ease;
    pointer-events: none;
  }
  .search-toggle.tab-location::before {
    left: calc(50% + 6px);
  }
  .search-toggle-opt {
    flex: 1;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px 12px;
    border-radius: 64px;
    font-size: 16px;
    font-weight: 500;
    color: #020203;
    font-family: 'DM Sans', -apple-system, sans-serif;
    cursor: pointer;
    text-align: center;
    white-space: nowrap;
  }

  /* ========== VENUE DETAIL MODAL ========== */
  #venue-detail {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    /* Above the persistent tab bar (z:30) and the cluster sheet (z:31) so a
       venue opened from a cluster sheet sits in front of it. The class
       detail's booking bar (z:35) and checkout sheet (z:36) still sit above
       this so their docked card pokes above the venue sheet. */
    z-index: 32;
    pointer-events: none;
    transition: background 0.35s ease;
  }
  /* No default overlay dim — the venue sheet itself provides the visual.
     The JS applies an inline rgba background only when a class detail is stacked on top. */
  #venue-detail.venue-detail-visible .venue-detail-sheet {
    pointer-events: auto;
  }

  .venue-detail-sheet {
    position: absolute;
    bottom: 0; left: 0; right: 0;
    height: calc(100% - 54px);
    background: #f1f2f3;
    border-radius: 32px 32px 0 0;
    overflow: hidden;
    transform: translateY(100%);
    transform-origin: top center;
    will-change: transform, border-radius, filter;
    visibility: hidden;
  }
  #venue-detail.venue-detail-visible .venue-detail-sheet {
    visibility: visible;
  }
  /* iOS-style stacked-sheet effect — applied while class detail is on top.
     translateY(0) keeps the venue's top edge at the status bar bottom (54px),
     and the class detail sits 70px from top → 16px visible peek. */
  .venue-detail-sheet.stacked {
    transform: scale(0.95) translateY(0px);
    border-radius: 20px 20px 0 0;
    filter: brightness(0.92);
    transition: transform 0.35s cubic-bezier(.25,.46,.45,.94),
                border-radius 0.35s ease,
                filter 0.35s ease;
  }
  .venue-detail-sheet.unstacking {
    transition: transform 0.35s cubic-bezier(.25,.46,.45,.94),
                border-radius 0.35s ease,
                filter 0.35s ease;
  }
  /* Hide venue's drag handle while stacked — class detail's handle takes over.
     Fade back in immediately when unstacking so there's no perceived lag
     between the sheet scaling back and the handle reappearing. */
  .venue-detail-sheet.stacked .venue-detail-handle {
    opacity: 0;
    transition: opacity 0.2s ease;
  }
  .venue-detail-sheet .venue-detail-handle {
    transition: opacity 0.2s ease;
  }

  /* Blurred wash behind the persistent tab bar. Fades from opaque at the
     bottom to transparent at the top so scrolling content dissolves into it. */
  .tab-bar-blur {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 40px;
    pointer-events: none;
    z-index: 25;
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    -webkit-mask-image: linear-gradient(to top, #000 50%, transparent);
    mask-image: linear-gradient(to top, #000 50%, transparent);
    transition: opacity 0.3s ease;
  }
  .tab-bar-blur.hidden-down { opacity: 0; }

  /* Persistent tab bar that floats above venue detail */
  .tab-bar-persistent {
    position: absolute;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%);
    width: 349px;
    height: 62px;
    background: rgba(255,255,255,0.4);
    -webkit-backdrop-filter: blur(20px) saturate(1.6);
    backdrop-filter: blur(20px) saturate(1.6);
    border: 1px solid rgba(255,255,255,0.5);
    border-radius: 100px;
    box-shadow: 0 4px 20px rgba(0,0,0,0.15);
    display: flex;
    align-items: center;
    padding: 4px;
    z-index: 30;
    pointer-events: auto;
    transition: transform 0.3s cubic-bezier(.25,.46,.45,.94), opacity 0.3s ease;
  }
  /* Hidden state: tab bar slides down off-screen when class detail content is scrolled */
  .tab-bar-persistent.hidden-down {
    transform: translateX(-50%) translateY(120px);
    opacity: 0;
    pointer-events: none;
  }

  .venue-detail-handle {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 6;
    padding: 10px 0 8px;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: grab;
    touch-action: none;
    pointer-events: auto;
  }
  .venue-detail-handle::before {
    content: '';
    width: 56px;
    height: 5px;
    background: #111;
    opacity: 0.3;
    border-radius: 20px;
  }

  /* Top bar: close/back left, title center, share right */
  .vd-top-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 0 20px;
    gap: 12px;
    position: relative;
  }
  /* Left-side icon stack: holds the venue close (X) and class back (<) which
     occupy the same slot and crossfade based on which pane is active. */
  .vd-nav-left {
    position: relative;
    width: 44px;
    height: 44px;
    flex-shrink: 0;
  }
  .venue-detail-close,
  .vd-nav-back {
    position: absolute;
    inset: 0;
    width: 44px;
    height: 44px;
    background: rgba(255, 255, 255, 0.55);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: opacity 0.25s ease, background 0.25s ease, box-shadow 0.25s ease;
  }
  /* Default state: X visible, back hidden. Class-active state inverts. */
  .vd-nav-back {
    opacity: 0;
    pointer-events: none;
  }
  .venue-detail-sheet.show-class .venue-detail-close {
    opacity: 0;
    pointer-events: none;
  }
  .venue-detail-sheet.show-class .vd-nav-back {
    opacity: 1;
    pointer-events: auto;
  }
  /* Once the active pane has scrolled past the title, swap the icon backdrops
     to solid white (matches the sticky nav adopting a solid bg). */
  .vd-sticky-nav.scrolled .venue-detail-close,
  .vd-sticky-nav.scrolled .vd-nav-back {
    background: #fff;
    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
  }
  .vd-actions-pill {
    display: flex;
    align-items: center;
    gap: 8px;
    background: rgba(255, 255, 255, 0.55);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    border-radius: 999px;
    width: 44px;
    height: 44px;
    overflow: hidden;
    flex-shrink: 0;
    transition: background 0.25s ease, box-shadow 0.25s ease;
  }
  .vd-sticky-nav.scrolled .vd-actions-pill {
    background: #fff;
    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
  }
  .vd-action-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    cursor: pointer;
  }
  .vd-action-icon svg { width: 24px; height: 24px; }

  /* Shared sticky nav: stationary overlay above the pane stack. Spans from
     top:0 of the sheet so its solid bg (added on .scrolled) also covers the
     strip behind the drag handle. The padding-top reserves room for the
     drag handle area, so the 44px icon row sits with breathing room below
     it. Total nav height: 28 + 44 + 8 = 80px. */
  .vd-sticky-nav {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 5;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 28px 0 8px;
    /* Shared nav is now permanently transparent — the grey wash lives inside
       each pane (.vd-pane-nav-bg) so it slides horizontally with its pane.
       This nav only carries the icons + titles, which stay fixed. */
    background: transparent;
    pointer-events: none;
  }
  /* Re-enable pointer-events on the interactive controls inside the nav.
     IMPORTANT: do NOT include .vd-nav-back here — its pointer-events are
     toggled explicitly by show-class state below, and adding it here would
     out-specificity the default `pointer-events: none` and let the
     invisible back arrow eat clicks on top of the X. */
  .vd-sticky-nav .vd-top-bar,
  .vd-sticky-nav .vd-nav-left,
  .vd-sticky-nav .venue-detail-close,
  .vd-sticky-nav .vd-actions-pill {
    pointer-events: auto;
  }
  /* Per-pane grey nav backdrop. Lives inside each pane's scroll container
     and pinned with `position: sticky; top: 0` so it stays anchored to the
     top of its pane visually while translating with the pane during the
     class-detail slide. Negative margin pulls the next sibling up so the
     bg overlays the top 80px of pane content (transparent until scrolled
     past the title). z-index keeps it above pane content but below the
     shared nav (z:5). */
  .vd-pane-nav-bg {
    position: sticky;
    top: 0;
    left: 0;
    right: 0;
    height: 80px;
    margin-bottom: -80px;
    background: transparent;
    transition: background 0.18s ease;
    /* Must outrank .cd-content which is z-index:1 — otherwise the description
       and other pane content render on top of the sticky bg and the grey
       wash never appears at the top once scrolled. Still below the shared
       nav (z:5) so the icons + title remain on top. */
    z-index: 3;
    pointer-events: none;
  }
  .vd-pane-nav-bg.scrolled {
    background: #f1f2f3;
  }
  /* Title wrap: holds the venue title and class title overlapping in the same
     slot so they can crossfade based on the active pane. */
  .vd-sticky-title-wrap {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: calc(100% - 160px);
    height: 44px;
    pointer-events: none;
  }
  .vd-sticky-title {
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    transform: translateY(-50%) translateY(6px);
    font-family: 'DM Sans', sans-serif;
    font-size: 17px;
    font-weight: 700;
    line-height: 22px;
    color: #020203;
    opacity: 0;
    text-align: center;
    pointer-events: none;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: opacity 0.25s ease, transform 0.25s ease, font-size 0.15s ease, line-height 0.15s ease;
  }
  /* iOS-style shrink: long titles that would overflow at 17px get bumped
     down to 14px so they can fit on two lines. JS toggles this class. */
  .vd-sticky-title.is-compact {
    font-size: 14px;
    line-height: 18px;
  }
  /* Venue title — visible only when the venue pane is active (i.e. the sheet
     does NOT have .show-class) AND the nav is .scrolled. Excluded the
     class-variant via :not() so the two titles never both fade in at once. */
  .vd-sticky-nav.scrolled .vd-sticky-title:not(.vd-sticky-title--class) {
    opacity: 1;
    transform: translateY(-50%) translateY(0);
  }
  .venue-detail-sheet.show-class .vd-sticky-nav .vd-sticky-title:not(.vd-sticky-title--class) {
    opacity: 0;
    transform: translateY(-50%) translateY(6px);
  }
  /* Class title — only when class pane is active AND the nav is .scrolled. */
  .venue-detail-sheet.show-class .vd-sticky-nav.scrolled .vd-sticky-title.vd-sticky-title--class {
    opacity: 1;
    transform: translateY(-50%) translateY(0);
  }

  /* Pane stack: spans the entire sheet so the class-pane hero can extend up
     behind the drag handle and the shared sticky nav. Both panes are
     absolutely positioned siblings that translate horizontally. */
  .vd-pane-stack {
    position: absolute;
    inset: 0;
    overflow: hidden;
  }
  .vd-pane-stack > .venue-detail-scroll,
  .vd-pane-stack > .class-detail-scroll {
    position: absolute;
    inset: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    will-change: transform;
    transition: transform 0.5s cubic-bezier(0.32, 0.72, 0, 1);
  }
  .vd-pane-stack > .venue-detail-scroll::-webkit-scrollbar,
  .vd-pane-stack > .class-detail-scroll::-webkit-scrollbar { display: none; }

  /* Class pane: parked off-screen to the right, slides in when the sheet
     gets .show-class. Solid bg matches the sheet so the venue pane (drifted
     left) doesn't bleed through when an active hero slide is faded out
     during a lightbox open. */
  .vd-pane-stack > .class-detail-scroll {
    transform: translateX(100%);
    pointer-events: none;
    background: #f1f2f3;
  }
  .venue-detail-sheet.show-class .vd-pane-stack > .class-detail-scroll {
    transform: translateX(0);
    pointer-events: auto;
  }
  /* Venue pane drifts a quarter-screen left underneath the class pane (iOS
     push pattern). It keeps its solid sheet bg so it doesn't bleed through. */
  .venue-detail-sheet.show-class .vd-pane-stack > .venue-detail-scroll {
    transform: translateX(-25%);
  }

  /* Fallback for any .venue-detail-scroll that is NOT inside a pane stack
     (kept for robustness — currently unused). */
  .venue-detail-scroll {
    position: relative;
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  .venue-detail-scroll::-webkit-scrollbar { display: none; }

  .venue-detail-content {
    /* Top padding clears the 80px shared sticky nav (which sits over the
       venue scroll). Bottom padding is just breathing room — the venue
       sheet now sits in front of the persistent tab bar so we no longer
       need to clear it. */
    padding: 84px 20px 32px;
    display: flex;
    flex-direction: column;
    gap: 40px;
    margin-top: 0;
    box-sizing: border-box;
  }
  .vd-header-group {
    display: flex;
    flex-direction: column;
    gap: 16px;
    /* Tighten the gap below the carousel from the parent's 40px down to
       24px (40 + (-16)). Works whether tabs or the promo card follows. */
    margin-bottom: -16px;
  }

  /* Header — no fixed height; column stacks h1 → meta → tags */
  .vd-header#vd-section-header {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    width: 100%;
    height: fit-content;
    min-height: 0;
    flex-shrink: 0;
  }
  /* Header */
  .vd-name {
    font-family: 'DM Sans', sans-serif;
    font-size: 28px;
    font-weight: 700;
    line-height: 32px;
    color: #020203;
    margin: 0;
    overflow-wrap: anywhere;
  }
  .vd-info {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 4px;
  }
  #vd-section-header > .vd-meta {
    margin-top: 8px;
  }
  .vd-tags {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 500;
    line-height: 24px;
    color: #4F5159;
  }
  .vd-meta {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 4px;
  }
  .vd-star { display: flex; align-items: center; flex-shrink: 0; }
  .vd-rating-num {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
    flex-shrink: 0;
  }
  .vd-rating-meta {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 24px;
    color: #4f5159;
    flex: 1 1 0;
    min-width: 0;
    overflow-wrap: anywhere;
  }


  /* Shared: full-bleed horizontal scroll (breaks out of content padding) */
  .vd-hscroll {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    margin-left: -20px;
    margin-right: -20px;
    padding-left: 20px;
    padding-right: 20px;
    scroll-snap-type: x proximity;
  }
  .vd-hscroll::-webkit-scrollbar { display: none; }

  /* Images */
  .vd-image-placeholder {
    width: 166px;
    height: 166px;
    background: #d9d9d9;
    border-radius: 16px;
    flex-shrink: 0;
  }

  /* Tabs sit in the scroll flow right below the image carousel and stick
     to the top of the scroll container (just below the sticky nav) once
     scrolled past. Always visible. */
  .vd-tabs {
    display: flex;
    gap: 32px;
    border-bottom: 1px solid #e4e5e7;
    position: sticky;
    /* Pin flush below the 80px shared sticky nav. */
    top: 80px;
    z-index: 3;
    background: #f1f2f3;
    margin-left: -20px;
    margin-right: -20px;
    padding-left: 20px;
    padding-right: 20px;
  }
  .vd-tab {
    padding: 12px 0;
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    line-height: 20px;
    color: #020203;
    cursor: pointer;
    white-space: nowrap;
    position: relative;
  }
  /* Bold label is always in the flow (sets the width), but invisible by default */
  .vd-tab-label-bold {
    font-weight: 700;
    visibility: hidden;
  }
  /* Regular label overlays on top */
  .vd-tab-label {
    font-weight: 500;
    position: absolute;
    left: 0;
    right: 0;
    text-align: center;
  }
  /* When active, hide regular and show bold */
  .vd-tab.active .vd-tab-label {
    visibility: hidden;
  }
  .vd-tab.active .vd-tab-label-bold {
    visibility: visible;
  }
  .vd-tab-indicator {
    position: absolute;
    bottom: -1px;
    left: 0;
    height: 4px;
    background: #020203;
    border-radius: 4px 4px 0 0;
    /* Motion.js handles animation */
    pointer-events: none;
  }

  /* Tab panels */
  .vd-panel {
    display: none;
    flex-direction: column;
    gap: 40px;
    /* Trim 20px off the 40px venue-detail-content flex gap so the visual
       gap from the sticky tabs to the active panel's first card lands at
       20px (matches the class-detail tabs→intro card spacing). */
    margin-top: -20px;
  }
  /* Overview ends with the map card; pad below it so the absolutely-positioned
     floating "See full schedule" button (52px tall + 40px bottom offset = 92px
     from the sheet bottom) doesn't cover it at max scroll. The
     .venue-detail-content already adds 32px below, so 80px here gives ~20px
     breathing room above the floating button. */
  .vd-panel-overview {
    padding-bottom: 80px;
  }
  .vd-panel-schedule {
    gap: 0;
  }
  .vd-panel-classes {
    gap: 12px;
  }
  .vd-panel.active {
    display: flex;
    /* Content is intentionally NOT animated on tab switch — only the
       scroll position glides (see `smoothScrollVdTo` in activateTab).
       The view appears to glide to the pin while the new tab's contents
       are simply already there. Matches the class-detail behavior; see
       [[feedback-tab-switch-polish]] in memory for the why. */
  }

  /* ===== SCHEDULE PANEL ===== */
  .vd-date-picker {
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    position: sticky;
    /* Pin flush below the sticky vd-tabs (which sit at top:80, height 45). */
    top: 125px;
    z-index: 2;
    background: #f1f2f3;
    /* Cancels the effective 20px tabs→panel gap (40px venue-detail-content
       flex gap minus the -20px margin-top on .vd-panel) so the picker sits
       flush below the tab bar from the start. */
    margin-top: -20px;
    margin-left: -20px;
    margin-right: -20px;
    padding-top: 16px;
    padding-bottom: 16px;
  }
  .vd-date-picker::-webkit-scrollbar { display: none; }
  .vd-week {
    flex: 0 0 100%;
    width: 100%;
    display: flex;
    gap: 12px;
    align-items: center;
    padding: 0 20px;
    box-sizing: border-box;
  }
  .vd-date-cell {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    cursor: pointer;
    padding-top: 4px;
  }
  .vd-date-letter {
    font-family: 'DM Sans', sans-serif;
    font-size: 11px;
    font-weight: 500;
    line-height: 14px;
    color: #020203;
  }
  .vd-date-day {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 500;
    line-height: 24px;
    color: #020203;
    transition: background 0.2s ease, color 0.2s ease;
  }
  .vd-date-cell.past .vd-date-day { color: #b3b5bc; }
  /* Today is highlighted with a white circle even when not the selected date */
  .vd-date-cell.today .vd-date-day {
    background: #fff;
    color: #020203;
  }
  /* Selected date overrides today with the dark pill */
  .vd-date-cell.selected .vd-date-day {
    background: #020203;
    color: white;
  }

  .vd-schedule-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
  .vd-schedule-card {
    background: white;
    border-radius: 24px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    cursor: pointer;
  }
  .vd-schedule-card.disabled { cursor: default; }
  .vd-schedule-top {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    font-family: 'DM Sans', sans-serif;
    line-height: 20px;
  }
  .vd-schedule-time {
    font-size: 14px;
    font-weight: 500;
    color: #020203;
  }
  .vd-schedule-duration {
    font-size: 14px;
    font-weight: 500;
    color: #020203;
  }
  .vd-schedule-card.disabled .vd-schedule-time,
  .vd-schedule-card.disabled .vd-schedule-duration { color: #b3b5bc; }
  .vd-schedule-title {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
  }
  .vd-schedule-card.disabled .vd-schedule-title { color: #b3b5bc; }
  .vd-schedule-bottom {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
  }
  .vd-schedule-rating {
    display: flex;
    align-items: center;
    gap: 0;
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
    color: #020203;
  }
  .vd-schedule-card.disabled .vd-schedule-rating { color: #b3b5bc; }
  .vd-schedule-card.disabled .vd-schedule-rating svg path { fill: #b3b5bc; }
  .vd-schedule-price {
    display: flex;
    align-items: center;
    gap: 4px;
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 500;
    line-height: 16px;
  }
  .vd-schedule-price-label { color: #020203; }
  .vd-schedule-card.disabled .vd-schedule-price-label { color: #b3b5bc; }
  .vd-price-strike {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 500;
    line-height: 24px;
    color: #4F5159;
    text-decoration: line-through;
  }
  .vd-schedule-card.disabled .vd-price-strike { color: #b3b5bc; }
  .vd-price-final {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    color: #379062;
  }
  .vd-price-plain {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 600;
    line-height: 24px;
    color: #020203;
  }
  .vd-schedule-card.disabled .vd-price-final,
  .vd-schedule-card.disabled .vd-price-plain { color: #b3b5bc; }
  /* Sold-out state (matches Figma node 6493:11678): hide the price and
     show "Sold out" in --text/emphasis red. Other text already greys via
     the .disabled rules above. Two markup variants exist: a wrapper
     `.vd-schedule-price` with child spans (finalPrice path), or a bare
     `.vd-price-plain` span (plainPrice path) — handle both. */
  .vd-schedule-card.disabled .vd-schedule-price,
  .vd-schedule-card.disabled .vd-price-plain {
    font-size: 0;
    line-height: 0;
  }
  .vd-schedule-card.disabled .vd-schedule-price::before,
  .vd-schedule-card.disabled .vd-price-plain::before {
    content: 'Sold out';
    color: #e10e0e;
    font-weight: 600;
    font-size: 16px;
    line-height: 24px;
    display: inline-block;
    vertical-align: middle;
  }

  /* ===== CLASSES PANEL ===== */
  .vd-class-summary-card {
    background: #fff;
    border-radius: 24px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }
  .vd-class-summary-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    width: 100%;
  }
  .vd-class-summary-title {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
  }
  .vd-class-summary-desc {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
    color: #020203;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .vd-class-summary-seemore {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 700;
    line-height: 20px;
    color: #020203;
    cursor: pointer;
  }
  .vd-class-summary-btn {
    background: transparent;
    border: 1px solid #e4e5e7;
    border-radius: 999px;
    padding: 8px 12px;
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
    cursor: pointer;
    white-space: nowrap;
  }
  .vd-class-summary-btn:active {
    background: #f1f2f3;
  }

  /* ===== REVIEWS PANEL ===== */
  .vd-panel-reviews { gap: 16px; }
  /* Pushes the "Class reviews" title 16px further from the summary so the
     gap between them is 32px while other .vd-panel-reviews gaps stay 16px. */
  .vd-panel-reviews .vd-rev-summary + .vd-section-title { margin-top: 16px; }

  /* Rating summary — sits directly on the panel's gray background;
     only the bar histogram below gets its own white card. */
  .vd-rev-summary {
    display: flex;
    flex-direction: column;
    gap: 24px;
  }
  .vd-rev-top {
    display: flex;
    align-items: center;
    gap: 12px;
  }
  .vd-rev-score {
    font-family: 'DM Sans', sans-serif;
    font-size: 32px;
    font-weight: 700;
    line-height: 40px;
    color: #020203;
  }
  .vd-rev-stars-group {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .vd-rev-stars { display: flex; gap: 0; }
  .vd-rev-stars svg { width: 24px; height: 24px; }
  .vd-rev-count {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
    color: #4F5159;
  }
  .vd-rev-summary-head {
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .vd-rev-source {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 500;
    line-height: 16px;
    color: #4F5159;
  }

  /* White card that contains only the rating-distribution bars. */
  .vd-rev-bars-card {
    background: #fff;
    border-radius: 24px;
    padding: 20px;
  }

  /* Rating bars */
  .vd-rev-bars {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }
  .vd-rev-bar-row {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .vd-rev-bar-label {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 500;
    line-height: 16px;
    color: #020203;
    width: 12px;
    flex-shrink: 0;
  }
  .vd-rev-bar-track {
    flex: 1;
    height: 8px;
    background: #f1f2f3;
    border-radius: 5px;
    overflow: hidden;
  }
  .vd-rev-bar-fill {
    height: 100%;
    background: #ffb54d;
    border-radius: 5px;
  }

  /* AI summary */
  .vd-rev-ai-summary {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 400;
    line-height: 20px;
    color: #020203;
  }

  /* Individual review cards */
  .vd-rev-list {
    display: flex;
    flex-direction: column;
    gap: 16px;
  }
  .vd-rev-card {
    background: white;
    border-radius: 24px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
  .vd-rev-card-header {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    width: 100%;
  }
  .vd-rev-avatar {
    width: 32px;
    height: 32px;
    border-radius: 28px;
    background: #d9dadd;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: white;
    flex-shrink: 0;
  }
  .vd-rev-card-meta {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
  }
  .vd-rev-name-row {
    display: flex;
    align-items: center;
    gap: 4px;
  }
  .vd-rev-name {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
  }
  .vd-rev-card-stars { display: flex; gap: 0; }
  .vd-rev-card-stars svg { display: block; flex-shrink: 0; }
  .vd-rev-date {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 500;
    line-height: 16px;
    color: #90939d;
  }
  .vd-rev-class-title {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
  }
  .vd-rev-body {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 24px;
    color: #020203;
    /* Pulls the body 8px closer to the class title so the gap between them
       is 4px while the other .vd-rev-card gaps stay at 12px. */
    margin-top: -8px;
  }

  /* Promo card */
  .vd-promo {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    padding: 12px 16px;
    background: white;
    border-radius: 24px;
    /* Tighten the gap below the promo card from the parent's 40px down to
       24px (40 + (-16)), matching the image-carousel→promo spacing above. */
    margin-bottom: -16px;
  }
  .vd-promo-icon { flex-shrink: 0; margin-top: 2px; }
  .vd-promo-title {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
  }
  .vd-promo-subtitle {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 500;
    line-height: 16px;
    color: #4F5159;
  }

  /* Section titles */
  .vd-section {
    display: flex;
    flex-direction: column;
    gap: 16px;
  }
  #vd-section-reviews {
    gap: 16x;
  }
  .vd-reviews-group {
    display: flex;
    flex-direction: column;
    gap: 16px;
  }
  .vd-amenities {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 24px;
    color: #020203;
  }
  /* "·" separator between amenity spans, drawn from an ASCII-safe CSS escape
     so it survives Vercel serving/encoding (a literal "·" in JS shipped as
     "MatsTowelsShowers"). Applies to both the venue + class detail lists. */
  .vd-amenities .amenity-item + .amenity-item::before,
  .cd-amenities .amenity-item + .amenity-item::before {
    content: "\00B7";
    margin: 0 6px;
  }
  /* Available today preview — sits between the carousel and the tabs. */
  .vd-available-today {
    display: flex;
    flex-direction: column;
    gap: 16px;
  }
  .vd-see-schedule-btn {
    /* Absolutely positioned at the bottom of the venue-detail sheet so it
       stays "fixed" as the user scrolls. .vd-pane-stack is the containing
       block. Full width with 20px gutters. Hidden on non-overview tabs and
       while the class-detail pane is showing (rules below). */
    position: absolute;
    left: 20px;
    right: 20px;
    bottom: 32px;
    z-index: 5;
    white-space: nowrap;
    background: #e10e0e;
    color: #fff;
    border: none;
    border-radius: 999px;
    padding: 12px 24px;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 500;
    line-height: 28px;
    cursor: pointer;
    transition: transform 0.12s cubic-bezier(.25,.46,.45,.94),
                opacity 0.2s ease;
  }
  .vd-see-schedule-btn:active {
    background: #c00b0b;
    transform: scale(0.96);
  }
  /* Blurred wash that sits behind the floating CTA — fades smoothly from
     opaque at the bottom to transparent at the top. Multi-stop ease-out
     mask keeps the top edge of the blur from reading as a hard line; the
     wash itself is also softened with `filter: blur` so the masked edge
     dissolves rather than terminating sharply. */
  /* Blurred wash behind the floating CTA — copy of the search view's
     `.tab-bar-blur` (height 40px, blur 12px, linear-gradient mask). */
  .vd-see-schedule-blur {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 40px;
    pointer-events: none;
    z-index: 4;
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    -webkit-mask-image: linear-gradient(to top, #000 50%, transparent);
    mask-image: linear-gradient(to top, #000 50%, transparent);
    transition: opacity 0.3s ease;
  }
  /* Hide the floating CTA + its blur wash on non-overview tabs (JS toggles
     `vd-tab-overview` on the sheet) and while the class-detail pane is up.
     Both elements are siblings of the sheet now, so we target them via
     subsequent-sibling combinators. */
  .venue-detail-sheet:not(.vd-tab-overview) ~ .vd-see-schedule-blur,
  .venue-detail-sheet:not(.vd-tab-overview) ~ .vd-see-schedule-btn,
  .venue-detail-sheet.show-class ~ .vd-see-schedule-blur,
  .venue-detail-sheet.show-class ~ .vd-see-schedule-btn {
    opacity: 0;
    pointer-events: none;
  }
  /* Hidden by default until #venue-detail becomes visible (siblings of the
     sheet don't inherit its `visibility: hidden`, so they need their own
     gate). */
  #venue-detail:not(.venue-detail-visible) .vd-see-schedule-blur,
  #venue-detail:not(.venue-detail-visible) .vd-see-schedule-btn {
    opacity: 0;
    pointer-events: none;
  }
  /* `#venue-detail` itself is `pointer-events: none` (so the area around
     the sheet doesn't block map clicks). Sheet descendants get re-enabled
     by `#venue-detail.venue-detail-visible .venue-detail-sheet`, but the
     floating button is a SIBLING of the sheet — re-enable it explicitly
     when the venue is visible, on the overview tab, and class detail
     isn't on top. */
  #venue-detail.venue-detail-visible .venue-detail-sheet.vd-tab-overview:not(.show-class) ~ .vd-see-schedule-btn {
    pointer-events: auto;
  }

  /* Static "See full schedule" CTA — sits at the very bottom of the
     Available today preview, in natural flow. White pill counterpart to
     the floating red button. */
  .vd-see-schedule-btn-static {
    width: 100%;
    background: #fff;
    color: #020203;
    border: none;
    border-radius: 999px;
    padding: 12px 24px;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 500;
    line-height: 28px;
    cursor: pointer;
    white-space: nowrap;
    transition: transform 0.12s cubic-bezier(.25,.46,.45,.94);
  }
  .vd-see-schedule-btn-static:active {
    background: #f0f0f0;
    transform: scale(0.96);
  }
  .vd-section-title {
    font-family: 'DM Sans', sans-serif;
    font-size: 20px;
    font-weight: 800;
    line-height: 28px;
    color: #020203;
    margin: 0;
  }
  .vd-section-header {
    display: flex;
    align-items: center;
    gap: 0px;
  }

  /* Classes scroll */
  .vd-class-card {
    flex-shrink: 0;
    background: white;
    border-radius: 24px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 240px;
  }
  .vd-class-name {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
  }
  .vd-class-instructor {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
    color: #4F5159;
  }
  .vd-class-time {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 500;
    line-height: 24px;
    color: #4f5159;
    margin-top: 4px;
  }
  .vd-class-slots {
    display: flex;
    gap: 8px;
    margin-top: 8px;
  }
  .vd-slot-btn {
    padding: 8px 12px;
    border: 1px solid #e4e5e7;
    border-radius: 999px;
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
    white-space: nowrap;
    cursor: pointer;
  }
  .vd-see-all-card {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-width: auto;
    padding: 12px 16px;
    background: white;
    border-radius: 24px;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 500;
    color: #020203;
    cursor: pointer;
    white-space: nowrap;
  }

  /* Map card: map image stacked on an address footer */
  .vd-map-card {
    border-radius: 24px;
    overflow: hidden;
    background: #fff;
    display: flex;
    flex-direction: column;
  }
  .vd-map-thumb {
    height: 168px;
    background: #e8e8e8;
    position: relative;
  }
  .vd-map-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  .vd-map-pin {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
  .vd-map-address {
    padding: 16px 16px;
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
    color: #020203;
    background: #fff;
  }

  /* Description */
  .vd-description {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 24px;
    color: #020203;
  }

  /* Rating summary */
  .vd-rating-summary {
    display: flex;
    align-items: center;
    gap: 12px;
  }
  .vd-rating-big {
    font-family: 'DM Sans', sans-serif;
    font-size: 32px;
    font-weight: 700;
    line-height: 40px;
    color: #020203;
  }
  .vd-rating-stars-group {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .vd-stars-row {
    display: flex;
    gap: 0;
  }
  .vd-reviews-count {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 500;
    line-height: 16px;
    color: #4F5159;
  }

  /* Review cards scroll */
  .vd-review-card {
    flex-shrink: 0;
    width: 311px;
    background: white;
    border-radius: 24px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
  .vd-review-header {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    width: 100%;
  }
  .vd-review-avatar {
    width: 32px;
    height: 32px;
    background: #d9dadd;
    border-radius: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: white;
    flex-shrink: 0;
  }
  .vd-review-meta {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
  }
  .vd-review-name-row {
    display: flex;
    align-items: center;
    gap: 4px;
  }
  .vd-reviewer {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
  }
  .vd-review-stars { display: flex; gap: 0; }
  .vd-review-stars svg { display: block; flex-shrink: 0; }
  .vd-review-date {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 500;
    line-height: 16px;
    color: #90939d;
  }
  .vd-review-body-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .vd-review-title {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
  }
  .vd-review-body {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 24px;
    color: #020203;
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  /* "See all" card at the end of the reviews carousel */
  .vd-review-see-all {
    flex-shrink: 0;
    align-self: stretch;
    background: white;
    border-radius: 24px;
    padding: 16px 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    cursor: pointer;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
    white-space: nowrap;
  }

  /* About block wraps the clamped text + "see more" in a tight column (4px gap). */
  .vd-about-block {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px 16px;
    border-radius: 24px;
    background-color: #fff;
    /* Trim 20px off the 40px venue-detail-content flex gap so the visual
       gap from the sticky tabs to this intro card lands at 20px, matching
       the class-detail tabs→intro card spacing. */
    margin-top: -20px;
  }
  .vd-about-block[hidden] { display: none; }

  /* About — clamped to 3 lines by default. JS unhides the adjacent
     "see more" span only when the text actually overflows; tapping it
     toggles .expanded to reveal the full copy. */
  .vd-about-text {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 24px;
    color: #020203;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .vd-about-text.expanded {
    display: block;
    -webkit-line-clamp: unset;
    overflow: visible;
  }
  .vd-see-more {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
    cursor: pointer;
    display: block;
  }

  /* Quick actions: horizontal pill row above the image carousel */
  .vd-quick-actions {
    display: flex;
    gap: 8px;
    align-items: flex-start;
  }
  .vd-quick-btn {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px 16px;
    background: white;
    border-radius: 999px;
    cursor: pointer;
    flex-shrink: 0;
  }
  .vd-quick-btn span {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
    white-space: nowrap;
  }

  /* ========== CLASS DETAIL MODAL ========== */
  #class-detail {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    z-index: 25;
    pointer-events: none;
    transition: background 0.3s ease;
  }
  #class-detail.class-detail-visible {
    background: rgba(0,0,0,0.15);
  }
  #class-detail.class-detail-visible .class-detail-sheet {
    pointer-events: auto;
    visibility: visible;
  }

  .class-detail-sheet {
    position: absolute;
    bottom: 0; left: 0; right: 0;
    height: calc(100% - 70px);
    background: #f1f2f3;
    border-radius: 32px 32px 0 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transform: translateY(100%);
    transform-origin: top center;
    will-change: transform;
    visibility: hidden;
  }

  /* Handle floats absolutely at the top of the sheet so the scroll content
     (including the hero image) can scroll behind it. */
  .class-detail-handle {
    position: absolute;
    top: 0; left: 0; right: 0;
    z-index: 6;
    padding: 10px 0 4px;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: grab;
    touch-action: none;
    pointer-events: auto;
  }
  .class-detail-handle::before {
    content: '';
    width: 56px;
    height: 5px;
    background: #111;
    opacity: 0.3;
    border-radius: 20px;
  }

  /* Scroll container fills the entire sheet so the hero scrolls edge-to-edge */
  .class-detail-scroll {
    position: absolute;
    inset: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  .class-detail-scroll::-webkit-scrollbar { display: none; }

  /* Sticky nav: back arrow left, fade-in title center, share right.
     Top padding matches .vd-sticky-nav so the icon doesn't jump vertically
     when sliding between the venue and class panes. */
  .cd-sticky-nav {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 20px 8px;
    background: transparent;
    gap: 12px;
    transition: background 0.25s ease;
  }
  .cd-sticky-nav.scrolled {
    background: #f1f2f3;
  }
  .cd-sticky-title {
    position: absolute;
    left: 50%;
    transform: translateX(-50%) translateY(6px);
    font-family: 'DM Sans', sans-serif;
    font-size: 17px;
    font-weight: 700;
    color: #020203;
    opacity: 0;
    transition: opacity 0.25s ease, transform 0.25s ease;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: calc(100% - 260px);
    pointer-events: none;
  }
  .cd-sticky-nav.scrolled .cd-sticky-title {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
  .cd-icon-btn {
    width: 44px;
    height: 44px;
    background: rgba(255, 255, 255, 0.55);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    border-radius: 999px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
    transition: background 0.25s ease, box-shadow 0.25s ease;
  }
  .cd-actions-pill {
    display: flex;
    align-items: center;
    gap: 8px;
    background: rgba(255, 255, 255, 0.55);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    border-radius: 999px;
    width: 44px;
    height: 44px;
    overflow: hidden;
    flex-shrink: 0;
    transition: background 0.25s ease, box-shadow 0.25s ease;
  }
  .cd-sticky-nav.scrolled .cd-icon-btn,
  .cd-sticky-nav.scrolled .cd-actions-pill {
    background: #fff;
    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
  }
  .cd-action-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    cursor: pointer;
  }
  .cd-action-icon svg { width: 24px; height: 24px; }

  /* Bookmark toggle states (shared selectors for venue + class detail) */
  .vd-bookmark-btn.bookmarked svg path,
  .cd-bookmark-btn.bookmarked svg path {
    fill: #020203;
    stroke: #020203;
  }

  /* Hero carousel — first child of the class scroll, so it extends to the
     very top of the sheet (behind the venue handle and the shared sticky
     nav, both of which overlay this pane). 3 swipeable slides with a
     scroll-snap pagination, plus a "1/N" counter pinned bottom-right.
     Height is generous (340px) so the image reads as the dominant visual
     and the counter clears the rounded corner of the cd-content overlap. */
  .cd-hero {
    position: relative;
    width: 100%;
    height: 340px;
    margin-top: 0;
    flex-shrink: 0;
    overflow: hidden;
    /* Lock the entire hero region to horizontal panning so any touch in
       it (slides, gaps, counter area) can't leak into the page scroll. */
    touch-action: pan-x;
  }
  /* Transform-based pagination (mirrors the lightbox track). The track is
     a flex row of full-width slides; drag updates `transform` directly and
     a CSS transition handles the snap on release. `touch-action: pan-x`
     stops native vertical scroll from firing during a horizontal swipe —
     otherwise the class detail view drifts up alongside the gesture. To
     scroll the page, the user touches outside the hero (content below). */
  .cd-hero-track {
    display: flex;
    width: 100%;
    height: 100%;
    transform: translate3d(0, 0, 0);
    transition: transform 0.32s cubic-bezier(0.25, 0.46, 0.45, 0.94);
    will-change: transform;
    touch-action: pan-x;
  }
  .cd-hero-track.dragging { transition: none; }
  .cd-hero-slide {
    flex: 0 0 100%;
    width: 100%;
    height: 100%;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    cursor: pointer;
    /* Lock to horizontal-only so vertical movement on the slide doesn't
       leak into the class-detail scroll while the user is swiping. */
    touch-action: pan-x;
  }
  /* Distinct gray gradients per slide so the carousel reads as 3 separate
     images and swiping is visually obvious until real photos are wired. */
  .cd-hero-slide:nth-child(1) {
    background: #D9D9D9;
  }
  .cd-hero-slide:nth-child(2) {
    background: #CFCFCF;
  }
  .cd-hero-slide:nth-child(3) {
    background: #C4C4C4;
  }
  /* "1/3" pill, bottom-right of the hero. Sits above the carousel via
     pointer-events:none so it doesn't intercept swipe gestures. The 64px
     bottom offset clears the 48px rounded-corner overlap of cd-content
     with breathing room so the counter is fully visible. */
  .cd-hero-counter {
    position: absolute;
    bottom: 64px;
    right: 16px;
    background: rgba(2, 2, 3, 0.7);
    color: #fff;
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
    padding: 4px 12px;
    border-radius: 999px;
    pointer-events: none;
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
  }

  /* Content area — overlaps the hero image with rounded top corners.
     The negative margin pulls the title block up over the hero so the
     image area reads less tall. */
  .cd-content {
    position: relative;
    z-index: 1;
    margin-top: -48px;
    padding: 24px 20px 0;
    background: #f1f2f3;
    border-radius: 24px 24px 0 0;
    display: flex;
    flex-direction: column;
    gap: 24px;
  }

  /* Venue header — full-width info stack (hero image is full-bleed above) */
  .cd-venue-header {
    display: flex;
  }
  .cd-venue-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .cd-title {
    font-family: 'DM Sans', sans-serif;
    font-size: 24px;
    font-weight: 700;
    line-height: 28px;
    color: #020203;
  }
  .cd-venue-link {
    display: flex;
    align-items: center;
    gap: 6px;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 500;
    line-height: 24px;
    color: #020203;
    cursor: pointer;
    min-width: 0;
  }
  .cd-venue-link > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
  }
  #cd-venue-text {
    font-size: 16px;
    line-height: 24px;
  }
  .cd-header-rating {
    display: flex;
    align-items: center;
    gap: 4px;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    line-height: 24px;
  }
  .cd-header-rating svg { display: block; flex-shrink: 0; }
  .cd-header-rating-num {
    font-weight: 700;
    color: #020203;
  }
  .cd-header-rating-count {
    font-weight: 500;
    color: #4f5159;
  }
  /* Intro offer line — plain green text (no pill), rendered last in the info stack */
  .cd-intro-chip {
    align-self: flex-start;
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
  }
  .cd-intro-chip-icon { display: none; }
  .cd-intro-chip-label {
    font-family: 'DM Sans', sans-serif;
    font-size: 18px;
    font-weight: 500;
    line-height: 24px;
    color: rgba(2, 2, 3, 1);
  }
  .cd-intro-chip-price {
    font-family: 'DM Sans', sans-serif;
    font-size: 18px;
    font-weight: 500;
    line-height: 24px;
    color: rgba(55, 144, 98, 1);
  }
  .cd-intro-chip-strike {
    font-family: 'DM Sans', sans-serif;
    font-size: 18px;
    font-weight: 400;
    line-height: 24px;
    color: rgba(144, 147, 157, 1);
    text-decoration: line-through;
  }
  .cd-intro-chip-plain {
    font-family: 'DM Sans', sans-serif;
    font-size: 18px;
    font-weight: 500;
    line-height: 24px;
    color: #020203;
  }

  /* Wraps date picker + time slots so spacing between them is one knob (gap).
     `flex: 1` lets the stack fill the panel's full height (panel has
     min-height: 800), which extends the sticky context for `.cd-date-picker`
     — without this the stack is only as tall as the picker + a few time
     slots, and the picker un-sticks when scrolled to the bottom of the
     stack instead of staying pinned. */
  .cd-schedule-stack {
    display: flex;
    flex-direction: column;
    gap: 0;
    flex: 1;
  }

  /* Date picker — horizontally paginated by week (carousel).
     Native scroll-snap is disabled because we drive the snap with a JS
     ease-out animation in prototype.js for a slower, more deliberate
     carousel feel. Pinned flush below the sticky cd-tabs (which sit at
     top:80, height 45) at top:125. Negative top margin cancels the
     effective tabs→panel gap (20px, after the -4px margin on .cd-panel)
     so the picker sits flush below the tabs from the start. */
  .cd-date-picker {
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    margin-left: -20px;
    margin-right: -20px;
    margin-top: -20px;
    position: sticky;
    top: 125px;
    z-index: 2;
    background: #f1f2f3;
  }
  .cd-date-picker::-webkit-scrollbar { display: none; }
  .cd-week {
    flex: 0 0 100%;
    width: 100%;
    display: flex;
    gap: 12px;
    padding: 8px 20px 12px 20px;
    box-sizing: border-box;
    scroll-snap-align: start;
  }
  .cd-date-cell {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding-top: 4px;
    cursor: pointer;
  }
  .cd-date-letter {
    font-family: 'DM Sans', sans-serif;
    font-size: 11px;
    font-weight: 500;
    line-height: 14px;
    color: #020203;
  }
  .cd-date-day {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 500;
    line-height: 24px;
    color: #020203;
    transition: background 0.2s ease, color 0.2s ease;
  }
  .cd-date-cell.past .cd-date-day { color: #b3b5bc; }
  /* Today is highlighted with a white circle even when not the selected date */
  .cd-date-cell.today .cd-date-day {
    background: #fff;
    color: #020203;
  }
  /* Selected date overrides today with the dark pill */
  .cd-date-cell.selected .cd-date-day {
    background: #020203;
    color: #fff;
  }

  /* Time slot list — vertical stack of cards. Padding-top creates the 16px
     gap below the date picker; 4px bottom matches the tabs gap below. */
  .cd-time-slots {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 16px 0 4px;
  }
  /* Card layout per Figma: 80px tall, 16px padding, 24px radius, two rows
     (time/duration on top, instructor/price on bottom) with 4px between. */
  .cd-time-slot {
    background: #fff;
    border: 2px solid transparent;
    border-radius: 24px;
    padding: 14px 16px;
    min-height: 80px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 4px;
    cursor: pointer;
    transition: border-color 0.15s ease;
    box-sizing: border-box;
  }
  .cd-time-slot.selected {
    border-color: #161618;
  }
  .cd-time-slot-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }
  .cd-time-slot-time {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
  }
  .cd-time-slot-duration {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
    color: #020203;
  }
  .cd-time-slot-instructor {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
  }
  .cd-time-slot-price {
    display: flex;
    align-items: baseline;
    gap: 4px;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
  }
  .cd-time-slot-price-final {
    color: #379062;
  }
  .cd-time-slot-price-strike {
    color: #696c77;
    text-decoration: line-through;
    font-weight: 400;
  }
  /* Reserved state (matches Figma node 6524:15291): all text greys out to
     --text/disabled (#b3b5bc), price is replaced with the word "Reserved"
     in --text/secondary (#696c77). Applied to both class-detail time-slots
     and venue-detail schedule cards via .is-reserved on the card root. */
  .cd-time-slot.is-reserved .cd-time-slot-time,
  .cd-time-slot.is-reserved .cd-time-slot-duration,
  .cd-time-slot.is-reserved .cd-time-slot-instructor {
    color: #b3b5bc;
  }
  .cd-time-slot.is-reserved .cd-time-slot-price {
    font-size: 0;
  }
  .cd-time-slot.is-reserved .cd-time-slot-price::before {
    content: 'Reserved';
    color: #696c77;
    font-weight: 600;
    font-size: 16px;
    line-height: 24px;
  }
  .vd-schedule-card.is-reserved .vd-schedule-time,
  .vd-schedule-card.is-reserved .vd-schedule-duration,
  .vd-schedule-card.is-reserved .vd-schedule-title {
    color: #b3b5bc;
  }
  .vd-schedule-card.is-reserved .vd-schedule-rating { color: #b3b5bc; }
  .vd-schedule-card.is-reserved .vd-schedule-rating svg path { fill: #b3b5bc; }
  .vd-schedule-card.is-reserved .vd-schedule-price > *,
  .vd-schedule-card.is-reserved .vd-schedule-price-label {
    display: none;
  }
  .vd-schedule-card.is-reserved .vd-schedule-price::before {
    content: 'Reserved';
    color: #696c77;
    font-weight: 600;
    font-size: 16px;
    line-height: 24px;
  }

  /* Class detail header simplification: the intro chip is redundant (per-slot
     prices already show the offer). Venue name + location stays visible as a
     subtitle under the class title. */
  .cd-intro-chip { display: none; }

  /* Summary description sits between the header and the date picker. The
     cd-content gap is 24px between siblings — pull the summary up 12px so
     the visual gap from the bottom of the rating to the top of the summary
     text is 12px (per spec). */
  .cd-section.cd-header-section + .cd-summary {
    margin-top: -12px;
  }

  /* Tabs (sticky below nav, animated indicator) */
  .cd-tabs {
    display: flex;
    gap: 32px;
    border-bottom: 1px solid #e4e5e7;
    position: sticky;
    top: 80px;
    z-index: 3;
    background: #f1f2f3;
    margin-left: -20px;
    margin-right: -20px;
    padding-left: 20px;
    padding-right: 20px;
  }
  .cd-tab {
    padding: 12px 0;
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    line-height: 20px;
    color: #020203;
    cursor: pointer;
    white-space: nowrap;
    position: relative;
  }
  .cd-tab-label-bold {
    font-weight: 700;
    visibility: hidden;
  }
  .cd-tab-label {
    font-weight: 500;
    position: absolute;
    left: 0;
    right: 0;
    text-align: center;
  }
  .cd-tab.active .cd-tab-label { visibility: hidden; }
  .cd-tab.active .cd-tab-label-bold { visibility: visible; }
  .cd-tab-indicator {
    position: absolute;
    bottom: -1px;
    left: 0;
    height: 4px;
    background: #020203;
    border-radius: 4px 4px 0 0;
    pointer-events: none;
  }

  /* Panels */
  .cd-panel {
    display: none;
    /* Trim 4px off the 24px cd-content flex gap so the visual gap from the
       sticky tabs to the active panel's first card lands at 20px. */
    margin-top: -4px;
  }
  .cd-panel.active {
    display: flex;
    flex-direction: column;
    gap: 40px;
    /* Min-height is set dynamically in JS (`fitCdActivePanelHeight`) — just
       enough to allow the tab-pin scroll to land but not so much that the
       user can scroll into empty space below a short time-slot list. */
    /* Content is intentionally NOT animated on tab switch — only the scroll
       position animates (see `smoothScrollCdTo` in activateCdTab). The user
       perception is "the view glides to the pin" while the new panel's
       contents are simply already there. */
  }
  @keyframes cd-panel-fade {
    from { opacity: 0; }
    to { opacity: 1; }
  }

  /* Description */
  .cd-description {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 24px;
    color: #020203;
    margin: 0;
  }
  #cd-description-collapsible {
    padding: 12px 16px;
    border-radius: 24px;
    background-color: #fff;
  }
  /* Collapsible text sections (description, prep, cancellation) */
  .cd-collapsible p {
    overflow: hidden;
    transition: max-height 0.3s ease;
  }
  .cd-collapsible.collapsed p {
    max-height: 72px; /* ~3 lines at 16px/24px */
  }
  .cd-collapsible.expanded p {
    max-height: 600px;
  }
  .cd-see-more {
    display: block;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
    cursor: pointer;
    margin-top: 4px;
  }

  /* Sections */
  .cd-section {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
  .cd-section.cd-header-section {
    gap: 20px;
  }
  .cd-section.cd-section-reviews {
    gap: 16px;
  }
  .cd-section-heading-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .cd-reviews-group {
    display: flex;
    flex-direction: column;
    gap: 16px;
  }
  .cd-amenities {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 24px;
    color: #020203;
  }
  .cd-map-card {
    border-radius: 24px;
    overflow: hidden;
    background: #fff;
    display: flex;
    flex-direction: column;
  }
  .cd-map-thumb {
    height: 168px;
    background: #e8e8e8;
    position: relative;
  }
  .cd-map-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  .cd-map-pin {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
  .cd-map-address {
    padding: 16px 16px;
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
    color: #020203;
    background: #fff;
  }
  .cd-section-heading-group .cd-section-subtitle {
    margin: 0;
  }
  .cd-section-header {
    display: flex;
    align-items: center;
    gap: 0px;
  }
  .cd-section-title {
    font-family: 'DM Sans', sans-serif;
    font-size: 20px;
    font-weight: 800;
    line-height: 28px;
    color: #020203;
  }
  .cd-section-body {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 24px;
    color: #020203;
    margin: 0;
  }
  .cd-section-subtitle {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 500;
    line-height: 24px;
    color: #4f5159;
    margin: -8px 0 0;
  }
  #cd-reviews-subtitle {
    font-size: 14px;
    line-height: 20px;
  }

  /* Ratings & Reviews — inline summary (Overview tab) */
  .cd-rating-summary {
    display: flex;
    align-items: center;
    gap: 12px;
  }
  /* Ratings & Reviews — full summary (Reviews tab). Mirrors the venue-detail
     pattern: the outer container is transparent and sits on the sheet's gray
     background; only the bar histogram gets its own white card. */
  .cd-rating-card {
    display: flex;
    flex-direction: column;
    gap: 16px;
  }
  #cd-rating-card-reviews {
    gap: 24px;
  }
  /* Scoped to .cd-rating-card so the Overview tab's inline .cd-rating-summary
     (which reuses .cd-rating-big / .cd-rating-summary-count) stays unchanged. */
  .cd-rating-card .cd-rating-big {
    font-size: 32px;
    font-weight: 700;
    line-height: 40px;
  }
  .cd-rating-card .cd-stars svg { width: 24px; height: 24px; }
  .cd-rating-card .cd-rating-summary-count {
    font-size: 14px;
    line-height: 20px;
  }
  .cd-rating-card .cd-rating-summary-head {
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .cd-rating-card .cd-rating-source {
    font-size: 13px;
    font-weight: 500;
    line-height: 16px;
  }
  .cd-rating-card .cd-rating-ai-summary {
    font-size: 14px;
    font-weight: 400;
    line-height: 20px;
  }
  .cd-rating-card .cd-rating-bars { gap: 8px; }
  .cd-rating-card .cd-rating-bar-track {
    background: #f1f2f3;
    border-radius: 5px;
  }
  .cd-rating-card .cd-rating-bar-fill { border-radius: 5px; }
  .cd-rating-bars-card {
    background: #fff;
    border-radius: 24px;
    padding: 20px;
  }
  .cd-rating-card-top {
    display: flex;
    align-items: center;
    gap: 12px;
  }
  .cd-rating-big {
    font-family: 'DM Sans', sans-serif;
    font-size: 32px;
    font-weight: 900;
    line-height: 40px;
    color: #020203;
  }
  .cd-rating-stars-row {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .cd-stars { display: flex; gap: 0; }
  .cd-stars svg { display: block; }
  .cd-rating-summary-count {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 500;
    line-height: 16px;
    color: #4F5159;
  }
  .cd-rating-source {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 400;
    line-height: 20px;
    color: #4F5159;
  }
  .cd-rating-bars {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
  .cd-rating-bar-row {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .cd-rating-bar-label {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 500;
    line-height: 16px;
    color: #020203;
    width: 12px;
    text-align: right;
  }
  .cd-rating-bar-track {
    flex: 1;
    height: 8px;
    background: #e4e5e7;
    border-radius: 4px;
    overflow: hidden;
  }
  .cd-rating-bar-fill {
    height: 100%;
    background: #FFB54D;
    border-radius: 4px;
  }
  .cd-rating-ai-summary {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 400;
    line-height: 20px;
    color: #020203;
    margin: 0;
  }
  .cd-review-cards {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    margin: 0 -20px;
    padding: 0 20px;
    scroll-padding-left: 20px;
    scroll-snap-type: x proximity;
  }
  .cd-review-cards::-webkit-scrollbar { display: none; }
  .cd-review-card {
    flex-shrink: 0;
    width: 311px;
    background: #fff;
    border-radius: 24px;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
  .cd-review-card-header {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    width: 100%;
  }
  .cd-review-avatar {
    width: 32px;
    height: 32px;
    border-radius: 28px;
    background: #d9dadd;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: white;
    flex-shrink: 0;
  }
  .cd-review-card-meta {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
  }
  .cd-review-name-row {
    display: flex;
    align-items: center;
    gap: 4px;
  }
  .cd-review-card-name {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
  }
  .cd-review-card-stars { display: flex; gap: 0; }
  .cd-review-card-stars svg { display: block; flex-shrink: 0; }
  .cd-review-card-date {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 500;
    line-height: 16px;
    color: #90939d;
  }
  .cd-review-card-body-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .cd-review-card-title {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
    margin: 0;
  }
  .cd-review-card-body {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 400;
    line-height: 24px;
    color: #020203;
    margin: 0;
  }
  /* Carousel-only: clamp the body to 4 lines. JS unhides the adjacent
     "see more" span when the text actually overflows; tapping it toggles
     .expanded to reveal the full copy. Reviews-tab list cards are
     unclamped (their block is full-width and gets its own styles below). */
  .cd-review-cards .cd-review-card-body {
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .cd-review-cards .cd-review-card-body.expanded {
    display: block;
    -webkit-line-clamp: unset;
    overflow: visible;
  }
  .cd-review-card-seemore {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 700;
    line-height: 20px;
    color: #020203;
    cursor: pointer;
  }
  /* Without this, the span's default `display` would override the UA
     [hidden] rule, making the link visible even when JS left hidden=true. */
  .cd-review-card-seemore[hidden] { display: none; }
  /* Reviews-tab list variant: pulls the body 8px closer to the class title
     so they sit 4px apart while the other .cd-review-card gaps stay at 12px. */
  .cd-review-card-list .cd-review-card-body {
    margin-top: -8px;
  }
  .cd-review-see-all {
    flex-shrink: 0;
    align-self: stretch;
    background: #fff;
    border-radius: 24px;
    padding: 16px 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    cursor: pointer;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
    white-space: nowrap;
  }

  /* Reviews panel list */
  .cd-reviews-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }
  .cd-reviews-list .cd-review-card { width: 100%; }

  /* Fixed booking footer: pinned to the device frame so it can sit above the
     persistent tab bar. Hidden offscreen by default; `.cd-booking-visible`
     adds the reveal transform so JS can animate it in when class detail opens. */
  /* Slide + visibility flip are driven by Motion in JS. CSS only defines the
     hidden resting state so first paint (before JS hydrates) doesn't flash
     the bar onscreen. The `.cd-booking-visible` class is a state marker only
     — no CSS rules tied to it beyond pointer-events. */
  .cd-booking-bar {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: #fff;
    border-radius: 0;
    /* Vertical padding asymmetric: more bottom space (32px) for breathing
       room from the device bottom edge. Matches the sheet's Book CTA
       `bottom: 32`, so the morph and hand-off keep the button's y stable. */
    padding: 16px 20px 32px;
    box-shadow: 0 -2px 16px rgba(0, 0, 0, 0.12);
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    z-index: 35;
    pointer-events: none;
    visibility: hidden;
    transform: translateY(calc(100% + 24px));
    will-change: transform;
  }
  .cd-booking-bar.cd-booking-visible {
    pointer-events: auto;
  }
  .cd-booking-info {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    min-width: 0;
    gap: 2px;
  }
  /* Top row: bold black datetime — "Tue, Mar 1 · 2:00 PM" */
  /* Booking bar AND checkout-sheet mini-summary share the same type stack
     so the morph endpoint matches the bar pixel-for-pixel — drifted sizes
     read as a visible font flicker at the end of the close animation. */
  .cd-booking-datetime,
  .cd-mini-meta {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
  }
  /* Bottom row: green final price, optional strike, then "· {instructor}" */
  .cd-booking-price-row,
  .cd-mini-price-row {
    display: flex;
    align-items: baseline;
    gap: 4px;
    font-family: 'DM Sans', sans-serif;
    font-size: 15px;
    font-weight: 500;
    line-height: 20px;
    color: #696c77;
    max-width: 100%;
    overflow: hidden;
  }
  .cd-booking-price,
  .cd-mini-price {
    display: flex;
    align-items: baseline;
    gap: 4px;
    font-family: 'DM Sans', sans-serif;
    font-size: 15px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
  }
  .cd-booking-price-strike {
    color: #696c77;
    text-decoration: line-through;
    font-weight: 400;
  }
  /* Discount price (intro offer) renders in the brand green; plain price
     stays in the default text color. */
  .cd-booking-price-final {
    color: #379062;
  }
  .cd-booking-price-plain {
    color: #020203;
    font-size: 14px;
    font-weight: 600;
  }
  .cd-booking-price-sep,
  .cd-mini-price-sep {
    color: #696c77;
  }
  .cd-booking-instructor,
  .cd-mini-instructor {
    color: #696c77;
    font-size: 14px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .cd-booking-cta {
    flex-shrink: 0;
    width: 100px;
    background: #e10e0e;
    color: #fff;
    border: none;
    border-radius: 999px;
    padding: 12px 16px;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 600;
    line-height: 24px;
    cursor: pointer;
    transition: transform 0.12s cubic-bezier(.25,.46,.45,.94);
  }
  .cd-booking-cta:active {
    background: #c00b0b;
    transform: scale(0.96);
  }
  /* Reserved state: after a successful booking the bar CTA becomes a
     black "Cancel" pill. Tapping it un-reserves and restores the
     default red Book state. */
  .cd-booking-cta.is-reserved {
    background: #020203;
  }
  .cd-booking-cta.is-reserved:active {
    background: #1a1a1c;
  }

  /* Checkout: morph-in-place from the booking bar. Shares the same
     bottom/left/right/border-radius geometry as .cd-booking-bar so the
     seam is invisible when the sheet first appears; then grows upward
     while its background transitions from glass → solid white. */
  .cd-checkout-scrim {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.32);
    opacity: 0;
    pointer-events: none;
    z-index: 35;
    transition: opacity 0.25s ease;
  }
  .cd-checkout-scrim.is-visible {
    opacity: 1;
    pointer-events: auto;
  }
  .cd-checkout-sheet {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    /* Height is controlled by JS; CSS default keeps it invisible offscreen. */
    height: 130px;
    border-radius: 0;
    /* Padding is shared with .is-open so it doesn't transition during the
       morph. Earlier this animated 16 → 24, which shifted the header (and
       its close button) by 8px during close — visible as jitter while the
       content was still partially opaque. CTA-reserved space lives on
       .cd-checkout-body (padding-bottom 72) instead of here so the sheet's
       own padding-bottom is small enough to fit inside its closed height
       (~96px) without forcing the box taller than `style.height` lets it. */
    padding: 24px 24px 24px 24px;
    display: flex;
    flex-direction: column;
    gap: 16px;
    overflow: hidden;
    visibility: hidden;
    z-index: 36;
    /* Closed state — matches .cd-booking-bar exactly (solid white + shadow). */
    background: #fff;
    box-shadow: 0 -2px 16px rgba(0, 0, 0, 0.12);
    transition:
      background 0.44s cubic-bezier(.32,.72,0,1),
      box-shadow 0.44s cubic-bezier(.32,.72,0,1),
      left 0.44s cubic-bezier(.32,.72,0,1),
      right 0.44s cubic-bezier(.32,.72,0,1),
      bottom 0.44s cubic-bezier(.32,.72,0,1),
      border-radius 0.44s cubic-bezier(.32,.72,0,1),
      height 0.44s cubic-bezier(.32,.72,0,1);
  }
  .cd-checkout-sheet.is-open {
    left: 0;
    right: 0;
    bottom: 0;
    border-radius: 24px 24px 0 0;
    background: #fff;
    box-shadow: 0 -2px 16px rgba(0, 0, 0, 0.12);
  }
  /* Header and body fade in/out with the geometry morph. The CTA is NOT
     in this group — it morphs between Next-shape (closed) and Book-shape
     (open) so it can hand off cleanly to the booking bar's Next button. */
  .cd-checkout-sheet .cd-checkout-header,
  .cd-checkout-sheet .cd-checkout-body {
    opacity: 0;
    transition: opacity 0.22s ease;
  }
  .cd-checkout-sheet.is-open .cd-checkout-header,
  .cd-checkout-sheet.is-open .cd-checkout-body {
    opacity: 1;
    transition: opacity 0.22s ease 0.18s;
  }
  .cd-checkout-header {
    position: relative;
    width: 100%;
    height: 44px;
    flex-shrink: 0;
  }
  .cd-checkout-title {
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    margin: 0;
    font-family: 'DM Sans', sans-serif;
    font-size: 20px;
    font-weight: 900;
    line-height: 28px;
    color: #020203;
    white-space: nowrap;
  }
  .cd-checkout-close {
    position: absolute;
    right: 0;
    top: 0;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
    border: none;
    cursor: pointer;
    display: grid;
    place-items: center;
    padding: 0;
  }
  .cd-checkout-close:active {
    background: #f4f4f6;
  }
  .cd-checkout-body {
    display: flex;
    flex-direction: column;
    gap: 16px;
    flex: 1 1 auto;
    overflow: hidden;
    min-height: 0;
    /* Reserves space below body content so the absolutely-positioned CTA
       (bottom:32 + height 48 = 80 from sheet bottom) doesn't overlap it.
       Lives on body — not on the sheet — so the sheet itself can shrink to
       the bar's ~96px height during close without padding-bottom forcing
       the rendered box taller than style.height. */
    padding-bottom: 72px;
    transition: opacity 0.18s ease;
  }
  .cd-checkout-sheet.is-success .cd-checkout-body {
    opacity: 0;
    pointer-events: none;
  }
  /* Success-state content: 176×176 phone image stacked above the
     "You're all set!" caption. Positioned absolutely between the header
     (top: sheet padding 24 + header 44 + gap 16 = 84) and the CTA
     (bottom: cta-bottom 32 + cta-height 48 + gap 16 = 96). Hidden by
     default; fades + scales in AFTER the body has finished fading out
     (180ms delay) so the two don't visually overlap mid-transition. */
  .cd-checkout-success {
    position: absolute;
    left: 24px;
    right: 24px;
    top: 84px;
    bottom: 96px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 20px;
    transform: scale(0.6);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s ease, transform 0.25s ease;
  }
  .cd-checkout-sheet.is-success .cd-checkout-success {
    opacity: 1;
    transform: scale(1);
    transition:
      opacity 0.25s ease 0.18s,
      transform 0.4s cubic-bezier(0.22, 1, 0.36, 1) 0.18s;
  }
  .cd-checkout-success-image {
    width: 80px;
    height: 80px;
    object-fit: contain;
    display: block;
    user-select: none;
    -webkit-user-drag: none;
  }
  .cd-checkout-success-caption {
    margin: 0;
    font-family: 'DM Sans', sans-serif;
    font-size: 18px;
    font-weight: 700;
    line-height: 26px;
    color: #020203;
    text-align: center;
  }
  /* Bordered card wrapping class info + payment + total in checkout mode.
     Matches the Figma "Content Container" — 1px border, 16px radius,
     12px/16px padding. The three children are separated by 1px dividers
     (applied as border-bottom on all but the last child). */
  .cd-checkout-card {
    display: flex;
    flex-direction: column;
    gap: 16px;
    border: 1px solid #e4e5e7;
    border-radius: 16px;
    padding: 16px;
  }
  .cd-checkout-card > .cd-checkout-info,
  .cd-checkout-card > .cd-checkout-payment {
    padding-bottom: 20px;
    border-bottom: 1px solid #e4e5e7;
  }
  .cd-checkout-info,
  .cd-cancel-info {
    display: flex;
    flex-direction: column;
  }
  .cd-checkout-class-title {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 24px;
    color: #020203;
  }
  .cd-checkout-meta,
  .cd-checkout-time,
  .cd-checkout-instructor,
  .cd-checkout-venue {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 400;
    line-height: 20px;
    color: #020203;
  }
  /* Cancel-mode overrides — the cancel-reservation modal uses a slightly
     larger class title and a semibold time row (per Figma cancel design,
     node 6074:15094). Booking modal stays unchanged. */
  .cd-cancel-info .cd-checkout-class-title {
    font-size: 18px;
    line-height: 26px;
  }
  .cd-cancel-info .cd-checkout-time {
    font-size: 16px;
    font-weight: 600;
    line-height: 24px;
  }
  /* Total + collapsible price breakdown.
     - Default: only the Total row is visible; the .cd-checkout-breakdown
       has 0 height and is hidden.
     - .is-expanded: breakdown reveals (Subtotal + Taxes rows above Total)
       with a height + opacity transition and the chevron flips 180°. */
  .cd-checkout-total-section {
    display: flex;
    flex-direction: column;
    width: 100%;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .cd-checkout-breakdown {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 0;
    padding-bottom: 0;
    opacity: 0;
    overflow: hidden;
    transition:
      max-height 0.3s cubic-bezier(.25,.46,.45,.94),
      padding-bottom 0.3s cubic-bezier(.25,.46,.45,.94),
      opacity 0.2s ease;
  }
  .cd-checkout-total-section.is-expanded .cd-checkout-breakdown {
    /* Generous ceiling to allow growth; actual height is content-driven. */
    max-height: 120px;
    padding-bottom: 4px;
    opacity: 1;
  }
  .cd-checkout-breakdown-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    /* Padding-right pushes the amount left so its right edge aligns with
       the Total row's amount text (not its chevron column). 14px = chevron
       width 10px + 4px gap between amount and chevron. */
    padding-right: 14px;
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 400;
    line-height: 20px;
    color: #696c77;
  }
  .cd-checkout-total-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
  }
  .cd-checkout-total-label {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    line-height: 24px;
    color: #020203;
  }
  .cd-checkout-total-amount {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    line-height: 24px;
    color: #020203;
  }
  .cd-checkout-total-chevron {
    display: block;
    flex-shrink: 0;
    transition: transform 0.3s cubic-bezier(.25,.46,.45,.94);
  }
  .cd-checkout-total-section.is-expanded .cd-checkout-total-chevron {
    transform: rotate(180deg);
  }
  /* Grey rounded panel (Figma surface/subtle) wrapping the cancellation
     policy: a bold heading block (title + free-cancellation cutoff) above a
     bulleted list of fee/refund details. */
  .cd-checkout-cancellation {
    display: flex;
    flex-direction: column;
    gap: 4px;
    background: #f1f2f3;
    border-radius: 16px;
    padding: 16px 12px;
  }
  .cd-checkout-cancellation-heading {
    display: flex;
    flex-direction: column;
  }
  .cd-checkout-cancellation-title,
  .cd-checkout-cancellation-cutoff {
    margin: 0;
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 700;
    line-height: 16px;
    color: #020203;
  }
  .cd-checkout-cancellation-list {
    margin: 0;
    padding-left: 18px;
    list-style: disc;
  }
  .cd-checkout-cancellation-list li {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 500;
    line-height: 16px;
    color: #020203;
  }
  .cd-checkout-cancellation-list li + li {
    margin-top: 4px;
  }
  .cd-checkout-cancellation-list li strong {
    font-weight: 700;
  }
  .cd-checkout-terms {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 400;
    line-height: 16px;
    color: #020203;
  }
  .cd-checkout-link {
    color: #0032d7;
    text-decoration: underline;
  }
  .cd-checkout-link:active { opacity: 0.6; }
  /* Cancel-reservation mode: same sheet chrome, different body content.
     Mode-specific subsections opt-in to display with .cd-checkout-mode-*. */
  .cd-checkout-sheet:not(.is-cancel-mode) .cd-checkout-mode-cancel {
    display: none;
  }
  .cd-checkout-sheet.is-cancel-mode .cd-checkout-mode-checkout {
    display: none;
  }
  /* Refund summary card — mirrors the booking modal's bordered card.
     Two rows: "Refund amount" (with bottom-border separator) and
     "Refund to". */
  .cd-cancel-block {
    display: flex;
    flex-direction: column;
    gap: 16px;
    border: 1px solid #e4e5e7;
    border-radius: 16px;
    padding: 16px;
  }
  .cd-cancel-line {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
  }
  .cd-cancel-line--amount {
    padding-bottom: 16px;
    border-bottom: 1px solid #e4e5e7;
  }
  .cd-cancel-label {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
  }
  .cd-cancel-amount {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
  }
  .cd-cancel-caption {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 400;
    line-height: 16px;
    color: #020203;
    padding: 16px 0;
  }
  /* Cancellation toast — black pill that floats just above the booking
     bar after a successful cancel. 12px radius, 8px gap between the
     check icon and the message text. Slides up + fades on show, slides
     down + fades on dismiss. Auto-hides after 2s (driven by JS). */
  .cd-toast {
    position: absolute;
    left: 50%;
    bottom: 112px;
    transform: translateX(-50%) translateY(8px);
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 16px;
    background: #020203;
    color: #fff;
    border-radius: 12px;
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 600;
    line-height: 16px;
    white-space: nowrap;
    z-index: 37;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s ease, transform 0.25s ease;
  }
  .cd-toast.is-visible {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
  .cd-toast-icon {
    display: inline-flex;
    width: 20px;
    height: 20px;
    flex-shrink: 0;
  }
  .cd-toast-icon svg {
    display: block;
    width: 100%;
    height: 100%;
  }
  .cd-checkout-payment {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
  }
  .cd-checkout-payment-left {
    display: inline-flex;
    align-items: center;
    gap: 16px;
    min-width: 0;
  }
  .cd-checkout-payment-label {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: #020203;
  }
  .cd-checkout-payment-card {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 400;
    line-height: 16px;
    color: #020203;
  }
  .cd-checkout-card-mark {
    display: inline-flex;
    width: 29px;
    height: 20px;
    flex-shrink: 0;
  }
  .cd-checkout-card-mark svg { display: block; }
  .cd-checkout-card-last4 {
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 400;
    line-height: 16px;
    color: #020203;
    letter-spacing: 0.5px;
  }
  .cd-checkout-payment-change {
    background: none;
    border: none;
    padding: 0;
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    color: #0032d7;
    cursor: pointer;
  }
  .cd-checkout-payment-change:active { opacity: 0.6; }
  .cd-checkout-applepay-mark svg {
    width: 100%;
    height: 100%;
  }
  .cd-checkout-cta {
    /* Anchored to bottom-right at the booking bar's Next coordinates
       (right:20, bottom:32). The morph is intentionally minimal — only
       the left edge moves, so the button grows leftward into a full-width
       Book CTA. Right edge, bottom, padding and font stay fixed so there
       is no vertical shift or right-edge jerk during the transition. */
    position: absolute;
    left: calc(100% - 120px);
    right: 20px;
    bottom: 32px;
    background: #e10e0e;
    color: #fff;
    border: none;
    outline: none;
    -webkit-tap-highlight-color: transparent;
    border-radius: 999px;
    padding: 12px 16px;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 600;
    line-height: 24px;
    /* Flex so the calendar icon in success mode can sit 8px left of the
       label without disturbing the existing absolute spinner overlay. */
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    /* Long checkout label ("Book and Pay") must never wrap into a
       second line during the morph. */
    white-space: nowrap;
    overflow: hidden;
    cursor: pointer;
    transition:
      left 0.44s cubic-bezier(.32,.72,0,1),
      right 0.44s cubic-bezier(.32,.72,0,1),
      transform 0.12s cubic-bezier(.25,.46,.45,.94),
      background-color 0.22s ease,
      color 0.22s ease;
  }
  /* Success-state CTA: gray neutral background, dark text, with the
     calendar icon revealed left of the "Add" label. Right edge pulls
     in to the midpoint so the Share button sits beside it. */
  .cd-checkout-sheet.is-success .cd-checkout-cta {
    background: #f1f2f3;
    color: #020203;
    right: calc(50% + 6px);
  }
  .cd-checkout-sheet.is-success .cd-checkout-cta:active {
    background: #e6e7e9;
    transform: scale(0.96);
  }
  /* Reserved morph: when closing from the success state, the sheet's CTA
     morphs to the black Cancel state that the booking bar underneath
     shows, so the final frame of the close matches the bar's CTA exactly
     instead of flashing red Book mid-morph. */
  .cd-checkout-sheet .cd-checkout-cta.is-reserved {
    background: #020203;
    color: #fff;
  }
  .cd-checkout-sheet .cd-checkout-cta.is-reserved:active {
    background: #1a1a1c;
  }
  .cd-cta-icon-calendar {
    display: none;
    width: 20px;
    height: 20px;
    flex-shrink: 0;
    pointer-events: none;
    user-select: none;
    -webkit-user-drag: none;
  }
  .cd-checkout-sheet.is-success .cd-cta-icon-calendar {
    display: inline-block;
  }
  .cd-checkout-sheet.is-open .cd-checkout-cta {
    left: 20px;
  }
  .cd-checkout-cta:active {
    background: #c00b0b;
    transform: scale(0.96);
  }
  .cd-checkout-cta:focus,
  .cd-checkout-cta:focus-visible {
    outline: none;
  }
  /* Share button: hidden by default, fades in on success state. Mirrors
     the Add CTA's typography + pill shape so the row reads as a paired set. */
  .cd-checkout-share {
    position: absolute;
    left: calc(50% + 6px);
    right: 20px;
    bottom: 32px;
    background: #f1f2f3;
    color: #020203;
    border: none;
    outline: none;
    -webkit-tap-highlight-color: transparent;
    border-radius: 999px;
    padding: 12px 16px;
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 600;
    line-height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    white-space: nowrap;
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transition:
      opacity 0.25s ease,
      transform 0.12s cubic-bezier(.25,.46,.45,.94),
      background-color 0.22s ease;
  }
  .cd-checkout-sheet.is-success .cd-checkout-share {
    opacity: 1;
    pointer-events: auto;
  }
  .cd-checkout-share:active {
    background: #e6e7e9;
    transform: scale(0.96);
  }
  .cd-checkout-share:focus,
  .cd-checkout-share:focus-visible {
    outline: none;
  }
  .cd-share-icon {
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    pointer-events: none;
  }
  /* Loading state: hide the label and reveal a centered iOS-style spinner.
     The button keeps its position/size so only the inner content changes. */
  .cd-checkout-cta .cd-cta-label {
    transition: opacity 0.15s ease;
  }
  .cd-checkout-cta.is-loading .cd-cta-label {
    opacity: 0;
  }
  .cd-cta-spinner {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 20px;
    height: 20px;
    transform: translate(-50%, -50%);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
  }
  .cd-checkout-cta.is-loading .cd-cta-spinner {
    opacity: 1;
  }
  .cd-cta-spinner > span {
    position: absolute;
    top: 0;
    left: 50%;
    width: 2px;
    height: 6px;
    margin-left: -1px;
    background: #fff;
    border-radius: 1px;
    transform-origin: 50% 10px;
    animation: cd-cta-spinner-fade 1s linear infinite;
  }
  .cd-cta-spinner > span:nth-child(1)  { transform: rotate(0deg);   animation-delay: -1.0000s; }
  .cd-cta-spinner > span:nth-child(2)  { transform: rotate(30deg);  animation-delay: -0.9167s; }
  .cd-cta-spinner > span:nth-child(3)  { transform: rotate(60deg);  animation-delay: -0.8333s; }
  .cd-cta-spinner > span:nth-child(4)  { transform: rotate(90deg);  animation-delay: -0.7500s; }
  .cd-cta-spinner > span:nth-child(5)  { transform: rotate(120deg); animation-delay: -0.6667s; }
  .cd-cta-spinner > span:nth-child(6)  { transform: rotate(150deg); animation-delay: -0.5833s; }
  .cd-cta-spinner > span:nth-child(7)  { transform: rotate(180deg); animation-delay: -0.5000s; }
  .cd-cta-spinner > span:nth-child(8)  { transform: rotate(210deg); animation-delay: -0.4167s; }
  .cd-cta-spinner > span:nth-child(9)  { transform: rotate(240deg); animation-delay: -0.3333s; }
  .cd-cta-spinner > span:nth-child(10) { transform: rotate(270deg); animation-delay: -0.2500s; }
  .cd-cta-spinner > span:nth-child(11) { transform: rotate(300deg); animation-delay: -0.1667s; }
  .cd-cta-spinner > span:nth-child(12) { transform: rotate(330deg); animation-delay: -0.0833s; }
  @keyframes cd-cta-spinner-fade {
    0%   { opacity: 1; }
    100% { opacity: 0.15; }
  }
  /* Compact info inside the sheet that mirrors .cd-booking-info. Hidden
     while the sheet is open; fades in during the close so the sheet's
     end-of-morph state visually matches the bar (meta on top, price below
     — same order as .cd-booking-info) instead of showing an empty white
     card. The bar takes over once the sheet hides — both display the
     same content in the same position so the swap is invisible. */
  .cd-checkout-mini-summary {
    position: absolute;
    /* 20 matches the bar's padding-left so the swap from mini-summary to
       the actual booking bar's info doesn't shift content horizontally. */
    left: 20px;
    /* Bar height ≈ 96 (padding 16+32 + cta content 48). Info content
       (datetime 20 + 2 gap + price-row 20 = 42) is centered in the 48px
       content row, so info bottom is ~35px above the bar's bottom. */
    bottom: 35px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.16s ease;
  }
  .cd-checkout-sheet.is-collapsing .cd-checkout-mini-summary {
    /* Fade in starts after the sheet's body has finished its 0.22s
       fade-out so the two don't overlap visually. */
    opacity: 1;
    transition: opacity 0.14s ease 0.18s;
  }
  /* Mini-summary type rules live alongside the booking-bar rules above
     (combined selectors) so the two can never drift out of sync. The shared
     rules cover .cd-mini-meta / .cd-mini-price-row / .cd-mini-price /
     .cd-mini-price-sep / .cd-mini-instructor. */

  /* Hide original booking card while the sheet covers it. The sheet's
     CTA closed-state matches the bar's Next exactly, so the hand-off is
     visually seamless. Opacity is applied to the children (not the bar
     itself) so removing is-under-checkout at end-of-close fades the info
     and CTA back in over 0.18s instead of snapping them in. */
  .cd-booking-bar .cd-booking-info,
  .cd-booking-bar .cd-booking-cta {
    transition: opacity 0.18s ease;
  }
  .cd-booking-bar.is-under-checkout {
    pointer-events: none;
  }
  /* Bar's shadow is suppressed for the entire time the sheet is on top —
     including the close animation. Otherwise the bar's shadow + sheet's
     shadow stack along the same edge as the sheet morphs into bar
     geometry, producing a visibly darker shadow at the end of close.
     This class lives on the bar separately from is-under-checkout (which
     is released at close start so the children can fade in invisibly
     behind the sheet) and is only released at transitionend. */
  .cd-booking-bar.is-sheet-overlay {
    box-shadow: none;
  }
  .cd-booking-bar.is-under-checkout .cd-booking-info,
  .cd-booking-bar.is-under-checkout .cd-booking-cta {
    opacity: 0;
  }

  /* ========== LIGHTBOX ==========
     Image gallery scoped to the phone frame (positioned absolute relative
     to .device-frame, which has overflow:hidden + rounded corners). The
     active slide morphs from the tapped thumbnail's bounding rect into
     its natural lightbox position when opening. */
  .lightbox {
    position: absolute;
    inset: 0;
    background: transparent;
    z-index: 200;
    display: flex;
    flex-direction: column;
    pointer-events: none;
  }
  .lightbox.open {
    pointer-events: auto;
  }
  /* Solid background panel — separated from .lightbox so the dismiss
     gesture can fade it independently of chrome and slides. */
  .lightbox-bg {
    position: absolute;
    inset: 0;
    background: #ededee;
    opacity: 0;
    transition: opacity 0.2s ease-out;
    pointer-events: none;
  }
  .lightbox.open .lightbox-bg { opacity: 1; }
  .lightbox-close {
    position: absolute;
    top: 60px;
    left: 20px;
    width: 40px;
    height: 40px;
    background: #fff;
    border: none;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
    z-index: 2;
    opacity: 0;
    transition: opacity 0.2s ease-out;
  }
  .lightbox.open .lightbox-close { opacity: 1; }
  .lightbox-header {
    position: absolute;
    top: 60px;
    left: 0;
    right: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    pointer-events: none;
    z-index: 1;
    opacity: 0;
    transition: opacity 0.2s ease-out;
  }
  .lightbox.open .lightbox-header { opacity: 1; }
  /* Drag-time: kill chrome transitions so each frame's opacity write isn't
     interpolated by CSS (which would lag the drag and cause a flash on
     release when the underlying inline value pops back). */
  .lightbox.dragging .lightbox-bg,
  .lightbox.dragging .lightbox-close,
  .lightbox.dragging .lightbox-header,
  .lightbox.dragging .lightbox-status-bar { transition: none; }
  .lightbox-title {
    font-family: 'DM Sans', sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 22px;
    color: #020203;
    width: calc(100% - 160px);
    text-align: center;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    word-break: break-word;
  }
  /* iOS-style shrink: long titles that won't fit on one line at 16px get
     bumped down to 13px so they can fit on up to two lines. JS toggles
     this class with the same logic used by the sticky nav title. */
  .lightbox-title.is-compact {
    font-size: 13px;
    line-height: 18px;
  }
  .lightbox-counter {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
    color: #90939d;
  }
  .lightbox-status-bar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 3;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.2s ease-out;
  }
  .lightbox.open .lightbox-status-bar { opacity: 1; }
  .lightbox-status-bar img {
    width: 100%;
    display: block;
  }
  .lightbox-viewport {
    position: relative;
    z-index: 1;
    flex: 1;
    overflow: hidden;
    display: flex;
    align-items: center;
  }
  .lightbox-track {
    display: flex;
    width: 100%;
    height: 100%;
    align-items: center;
    transform: translate3d(0, 0, 0);
    transition: transform 0.32s cubic-bezier(0.25, 0.46, 0.45, 0.94);
    will-change: transform;
  }
  .lightbox-track.dragging { transition: none; }
  .lightbox-slide {
    flex: 0 0 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 8px;
    box-sizing: border-box;
  }
  .lightbox-slide-image {
    width: 100%;
    aspect-ratio: 4 / 3;
    background: #d9d9d9;
    border-radius: 24px;
    transform-origin: center center;
    will-change: transform, opacity;
    transition: opacity 0.2s ease-out, aspect-ratio 0.22s cubic-bezier(0.22, 1, 0.36, 1);
  }
