/* =========================================================================
   booking.css — the BOOKING modal. Loaded on every page.

   NATIVE FLOW, 2026-07-29. Cal.com is a backend API only: no iframe, no embed
   script, no third-party CSS. Everything here is ours and every value is a
   token — no new colour, font or button style was introduced for this.

   Scoped under `.bk-` throughout. It declares NO global rule at all: the
   scroll lock reuses `body.ct-modal-open` from contact.css, which is loaded on
   every page beside this one. One lock, two dialogs.
   ========================================================================= */

.bk-modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: var(--sp-4);
}
.bk-modal[hidden] { display: none; }

.bk-modal__scrim {
  position: absolute;
  inset: 0;
  background: rgba(3, 6, 12, .72);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.bk-modal.is-in .bk-modal__scrim { opacity: 1; }

/* Sized for OUR flow, not for Cal.com's iframe. The old window was 980px wide
   because Cal.com collapsed its two-pane layout below ~870px; we render one
   column, so it only has to hold a seven-day strip and a slot grid.

   Height is capped, not fixed: the steps are genuinely different heights (a
   slot grid vs a three-field form vs a confirmation) and pinning it would
   leave the confirmation floating in 400px of nothing. The SLOT AREA carries
   its own min-height instead, which is what stops the window resizing while
   times load — the no-layout-shift requirement, solved where it belongs. */
.bk-modal__window {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(560px, 100%);
  max-height: min(92dvh, 780px);
  background: linear-gradient(180deg, #0a1120 0%, var(--bg-deep) 60%);
  border: 1px solid var(--stroke-strong);
  border-radius: var(--r-xl);
  box-shadow: 0 40px 80px -20px rgba(0, 0, 0, .8), 0 0 0 1px rgba(80, 161, 249, .10);
  overflow: hidden;
  isolation: isolate;
  opacity: 0;
  transform: translateY(12px) scale(.985);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.bk-modal.is-in .bk-modal__window { opacity: 1; transform: none; }
.bk-modal__window:focus { outline: none; }

/* ---- The bar ---------------------------------------------------------- */
.bk-modal__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  flex: 0 0 auto;
  padding: 14px 14px 14px 20px;
  border-bottom: 1px solid var(--stroke);
  background: rgba(10, 16, 28, .6);
}
.bk-modal__title {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--text);
  letter-spacing: .01em;
}
.bk-modal__close {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--stroke);
  border-radius: var(--r-pill);
  background: rgba(10, 16, 28, .8);
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.bk-modal__close svg { width: 18px; height: 18px; }
.bk-modal__close:hover { color: var(--text); border-color: var(--stroke-strong); }
.bk-modal__close:focus-visible { outline: 2px solid var(--vos-blue); outline-offset: 2px; }

/* ---- The stage --------------------------------------------------------
   min-height:0 so the flex child can actually shrink and scroll internally
   rather than forcing the window past its cap. */
.bk-modal__stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: var(--sp-5);
}

.bk-step { display: flex; flex-direction: column; gap: var(--sp-4); }
.bk-step[hidden] { display: none; }

/* ---- Timezone --------------------------------------------------------- */
.bk-tz { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.bk-tz__lab { font-size: var(--fs-xs); color: var(--text-muted); }
.bk-tz__sel {
  flex: 0 1 auto;
  min-width: 0;
  padding: .3em .5em;
  border: 1px solid var(--stroke);
  border-radius: var(--r-sm);
  background: rgba(10, 16, 28, .8);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-xs);
}
.bk-tz__sel:focus-visible { outline: 2px solid var(--vos-blue); outline-offset: 2px; }

/* ---- Week nav --------------------------------------------------------- */
.bk-week { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.bk-week__label { margin: 0; font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--text); }
.bk-week__nav {
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  border: 1px solid var(--stroke);
  border-radius: var(--r-pill);
  background: rgba(10, 16, 28, .8);
  color: var(--text-muted);
  cursor: pointer;
}
.bk-week__nav svg { width: 16px; height: 16px; }
.bk-week__nav:hover:not(:disabled) { color: var(--text); border-color: var(--stroke-strong); }
.bk-week__nav:disabled { opacity: .35; cursor: default; }
.bk-week__nav:focus-visible { outline: 2px solid var(--vos-blue); outline-offset: 2px; }

/* ---- Day strip -------------------------------------------------------- */
.bk-days { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; }
.bk-day {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  /* 44px tall minimum: a date cell is a touch target before it is a label. */
  min-height: 52px;
  padding: 6px 2px;
  border: 1px solid var(--stroke);
  border-radius: var(--r-md);
  background: rgba(10, 16, 28, .6);
  color: var(--text);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.bk-day__dow { font-size: 10px; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); }
.bk-day__n { font-size: var(--fs-sm); font-weight: var(--fw-semibold); }
.bk-day:hover:not(:disabled) { border-color: var(--stroke-strong); }
.bk-day:focus-visible { outline: 2px solid var(--vos-blue); outline-offset: 2px; }
/* Shut days stay VISIBLE and disabled rather than hidden — a week with holes
   in it tells the reader the calendar is real; a week with days missing looks
   broken. Contrast is held above the 3:1 non-text floor. */
.bk-day.is-shut { opacity: .32; cursor: default; }
.bk-day.is-on {
  border-color: var(--vos-blue);
  background: rgba(80, 161, 249, .16);
}

/* ---- Slots -------------------------------------------------------------
   THE ANTI-LAYOUT-SHIFT RULE. The wrapper reserves the height of a full slot
   grid before anything loads, so the skeleton, the times and the empty state
   all occupy the same box and the window never resizes under the reader. */
.bk-slotwrap { position: relative; min-height: 188px; }

.bk-slots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 8px;
  align-content: start;
}
.bk-slot {
  min-height: 44px;
  padding: .55em .4em;
  border: 1px solid var(--stroke);
  border-radius: var(--r-md);
  background: rgba(10, 16, 28, .7);
  color: var(--text);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.bk-slot:hover { border-color: var(--vos-blue); background: rgba(80, 161, 249, .14); }
.bk-slot:focus-visible { outline: 2px solid var(--vos-blue); outline-offset: 2px; }

/* Skeleton, not a spinner on blank: the shape of what is coming. */
.bk-skeleton { display: grid; }
.bk-slotskel {
  position: absolute;
  inset: 0;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 8px;
  align-content: start;
  overflow: hidden;
}
.bk-slotskel[hidden] { display: none; }
.bk-sk__slot { height: 44px; border-radius: var(--r-md); background: rgba(255, 255, 255, .06); }
.bk-slotskel::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, .05) 50%, transparent 70%);
  background-size: 220% 100%;
  animation: bk-shimmer 1.6s linear infinite;
  pointer-events: none;
}
@keyframes bk-shimmer {
  from { background-position: 120% 0; }
  to   { background-position: -120% 0; }
}

/* ---- Empty ------------------------------------------------------------- */
.bk-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  text-align: center;
}
.bk-empty[hidden] { display: none; }
.bk-empty__t { margin: 0; font-size: var(--fs-sm); color: var(--text-muted); }

/* ---- Form -------------------------------------------------------------- */
.bk-back {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  align-self: flex-start;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-muted);
  font: inherit;
  font-size: var(--fs-xs);
  cursor: pointer;
}
.bk-back svg { width: 14px; height: 14px; }
.bk-back:hover { color: var(--text); }
.bk-back:focus-visible { outline: 2px solid var(--vos-blue); outline-offset: 2px; }

.bk-chosen {
  margin: 0;
  padding: .7em .8em;
  border: 1px solid rgba(80, 161, 249, .28);
  border-radius: var(--r-md);
  background: rgba(80, 161, 249, .10);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--text);
}

.bk-field { display: flex; flex-direction: column; gap: 6px; }
.bk-label { font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--text-muted); }
.bk-req { color: var(--vos-blue); }
.bk-optional { font-weight: var(--fw-regular); opacity: .75; }
.bk-input,
.bk-textarea {
  width: 100%;
  padding: .65em .75em;
  border: 1px solid var(--stroke);
  border-radius: var(--r-md);
  background: rgba(10, 16, 28, .8);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-sm);
}
.bk-textarea { min-height: 76px; resize: vertical; }
.bk-input:focus-visible,
.bk-textarea:focus-visible { outline: 2px solid var(--vos-blue); outline-offset: 1px; }
.bk-input[aria-invalid="true"] { border-color: #FF5A66; }

.bk-error, .bk-formerr {
  margin: 0;
  font-size: var(--fs-xs);
  color: #FF5A66;   /* 6.2:1 on this panel — measured */
}
.bk-error:empty, .bk-formerr:empty { display: none; }

/* The honeypot. Off-screen, not display:none — a bot reading computed styles
   skips hidden fields, and this one has to look fillable. */
.bk-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ---- Buttons — the site's own, not a new style ------------------------- */
.bk-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: .7em 1.2em;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  text-align: center;
  cursor: pointer;
  transition: opacity var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.bk-btn--primary { background: var(--vos-blue); color: #04101f; }
.bk-btn--primary:hover { opacity: .9; }
.bk-btn--primary:disabled { opacity: .55; cursor: default; }
.bk-btn--ghost { background: transparent; border-color: var(--stroke); color: var(--text); }
.bk-btn--ghost:hover { border-color: var(--stroke-strong); }
.bk-btn:focus-visible { outline: 2px solid var(--vos-blue); outline-offset: 2px; }

/* ---- Done / dead ------------------------------------------------------- */
.bk-done, .bk-dead { align-items: center; text-align: center; padding: var(--sp-5) 0; }

/* THE CONFIRMATION CARRIES THE ENGRAVING (Troy, 2026-07-29). The success step
   was a tick and three lines on an empty panel — the one screen a converted
   prospect actually stops and reads, and the only one with no brand on it.

   BUILT AS A MASK + FLAT FILL, not as an <img> or a background photo, and that
   is this codebase's own idiom (the guilloche plates in 06 and 07 do the same):
     · the hero art is dark ink on transparency, so as a WATERMARK the only
       information needed is WHERE the ink is — the alpha channel. Storing just
       that took the asset from 465K to 48K.
     · a mask cannot brighten anything. It only ever subtracts, so the figure
       physically cannot lift the panel behind the text the way a screen-blended
       or inverted image would.
     · the fill is a token, so the engraving is the same ink as the type it
       sits behind rather than a baked-in blue that drifts from the palette.

   Loaded only when it is needed: the step is `hidden` until a booking
   succeeds, and browsers do not fetch a background for a display:none element.
   Nobody who never books pays for it. */
.bk-done { position: relative; overflow: hidden; }
.bk-done::before {
  content: "";
  position: absolute;
  /* Sits low and slightly right, so the figure reads as standing BEHIND the
     message rather than centred under it like a stamp. */
  right: -6%;
  bottom: -14%;
  width: min(78%, 280px);
  aspect-ratio: 1;
  background: var(--text);
  opacity: .07;
  -webkit-mask-image: url("/assets/img/booking/gw-mask.webp"),
                      linear-gradient(200deg, transparent 8%, #000 46%);
  mask-image: url("/assets/img/booking/gw-mask.webp"),
              linear-gradient(200deg, transparent 8%, #000 46%);
  -webkit-mask-size: contain, cover;
  mask-size: contain, cover;
  -webkit-mask-repeat: no-repeat, no-repeat;
  mask-repeat: no-repeat, no-repeat;
  /* Intersected, so the SECOND mask fades the figure out toward the top-left —
     which is exactly where "You're booked" and the date sit. The art is
     strongest in the corner the text never reaches. */
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  pointer-events: none;
  z-index: 0;
}
/* The message rides above it. Without this the tick and the type share a
   stacking context with the watermark and the order is left to chance. */
.bk-done > * { position: relative; z-index: 1; }
.bk-done__mark {
  display: grid;
  place-items: center;
  width: 52px; height: 52px;
  border-radius: var(--r-pill);
  background: rgba(52, 199, 123, .16);
  color: #34C77B;
}
.bk-done__mark svg { width: 26px; height: 26px; }
.bk-done__t { margin: 0; font-size: var(--fs-h4); font-weight: var(--fw-semibold); color: var(--text); }
.bk-done__when {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.bk-done__sub, .bk-dead__t { margin: 0; font-size: var(--fs-sm); color: var(--text-muted); }

/* ---- Fallback --------------------------------------------------------- */
.bk-modal__fallback {
  flex: 0 0 auto;
  margin: 0;
  padding: 10px 20px;
  border-top: 1px solid var(--stroke);
  background: rgba(10, 16, 28, .6);
  font-size: var(--fs-xs);
  color: var(--text-muted);
  text-align: center;
}
.bk-modal__fallback a { color: var(--text); text-decoration: underline; }
.bk-modal__fallback a:focus-visible { outline: 2px solid var(--vos-blue); outline-offset: 2px; }

/* ---- Phone ------------------------------------------------------------
   Near-fullscreen. Most demo bookings happen on a phone, so this is the
   layout that matters, not the desktop one. */
@media (max-width: 639px) {
  /* A SHEET THAT HUGS ITS CONTENT, not a forced full screen. The flow is
     short — timezone, seven days, a slot grid — and pinning the window to
     100dvh left ~500px of empty panel under it on a tall phone, which reads as
     a broken page rather than a compact booker. Auto height with a cap keeps
     it a sheet, and the form step simply grows into the room it needs. */
  .bk-modal { padding: var(--sp-3); }
  .bk-modal__window {
    width: 100%;
    max-height: 92dvh;
    border-radius: var(--r-lg);
  }
  .bk-modal__bar { padding: 10px 10px 10px 16px; }
  .bk-modal__stage { padding: var(--sp-4); }
  .bk-modal__fallback { padding: 8px 16px; }
  .bk-days { gap: 4px; }
  .bk-day { min-height: 48px; }
  .bk-slots, .bk-slotskel { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); }
}

@media (prefers-reduced-motion: reduce) {
  .bk-modal__scrim,
  .bk-modal__window { transition: none; }
  .bk-modal__window { transform: none; }
  .bk-slotskel::after { animation: none; }
}
