/*
 * Dakhla Booking Engine — frontend styles.
 *
 * Two rules govern this file:
 *
 * 1. ONE markup, responsive by CSS. There is no desktop block and mobile block. The system
 *    this replaces rendered every screen twice and wired JavaScript to only the first copy,
 *    so the mobile one was inert — prices missing, prefills empty, buttons dead. A layout
 *    that exists once cannot fall out of sync with itself.
 *
 * 2. Mobile-first. Base styles are the phone; wider screens add via min-width. Guests book
 *    trips from their phones.
 *
 * Everything is driven by the tokens below — no component hardcodes a colour.
 */

/* ---------------------------------------------------------------- tokens */

.dkb {
  /* Brand, matching the site's existing buttons (e.g. Login): #ff6a3d with white text.

     Accessibility note, for a decision rather than a silent fix: white on this orange
     measures 2.85:1, below WCAG AA (4.5:1) and below even the 3:1 floor for UI text. It is
     used here because it is the established brand style across the site, and one button
     that disagrees with every other button is its own problem. Two accessible routes exist
     whenever the site wants them, each a one-line change here:
       --dkb-on-primary: #1a1a1a            → 6.12:1, keeps the exact orange
       --dkb-primary: var(--dkb-primary-strong) → 4.88:1, keeps white text
  */
  --dkb-primary: #ff6a3d;
  --dkb-on-primary: #ffffff;
  --dkb-primary-hover: #f4571f;

  /* The same orange darkened until white text passes AA (4.88:1). */
  --dkb-primary-strong: #c9431a;

  /* Rate-plan pills (search + detail), distinct from CTA orange. */
  --dkb-plan: #57b8ff;
  --dkb-on-plan: #ffffff;

  /* Selector highlights (age bands, etc.). */
  --dkb-accent: #ff9e57;
  --dkb-calendar-range: #fff2e8;

  /* Search result “Select” hover. */
  --dkb-select-hover: #8f5c57;

  --dkb-sand: #ede9d0;
  --dkb-sand-deep: #ded7b4;

  --dkb-ink: #1a1a1a;
  --dkb-ink-soft: #5c5750;
  --dkb-line: #d9d4c4;
  --dkb-surface: #ffffff;
  --dkb-surface-alt: #faf9f4;

  --dkb-ok: #1f7a4c;
  --dkb-warn: #8a5a00;
  --dkb-error: #b3261e;

  --dkb-radius: 10px;
  --dkb-radius-lg: 16px;
  --dkb-gap: 1rem;
  --dkb-shadow: 0 1px 2px rgba(26, 26, 26, .06), 0 4px 16px rgba(26, 26, 26, .06);

  /* A comfortable finger target. Never shrink below this on any breakpoint. */
  --dkb-touch: 44px;

  color: var(--dkb-ink);
  font-family: inherit;
  line-height: 1.5;
}

/* ---------------------------------------------------------------- layout */

/*
 * Single bungalow / package pages: widen the content column that holds the booking
 * widget. Block themes cap width on constrained *children* via --wp--style--global--content-size
 * (often 645px/900px from the template). :has(.dkb) scopes this to the page content only.
 */
body.dkb-single-bungalow-page :where(.is-layout-constrained):has(.dkb),
body.dkb-single-bungalow-page :where([class*="wp-container-core-group-is-layout-"]):has(.dkb),
body.dkb-single-package-page :where(.is-layout-constrained):has(.dkb),
body.dkb-single-package-page :where([class*="wp-container-core-group-is-layout-"]):has(.dkb),
body.package-template-default :where(.is-layout-constrained):has(.dkb),
body.package-template-default :where([class*="wp-container-core-group-is-layout-"]):has(.dkb),
body.bungalow-template-default :where(.is-layout-constrained):has(.dkb),
body.bungalow-template-default :where([class*="wp-container-core-group-is-layout-"]):has(.dkb) {
  --wp--style--global--content-size: 90% !important;
  --wp--style--global--wide-size: 90% !important;
}

body.dkb-single-bungalow-page :where(.is-layout-constrained):has(.dkb) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
body.dkb-single-bungalow-page :where([class*="wp-container-core-group-is-layout-"]):has(.dkb) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
body.dkb-single-package-page :where(.is-layout-constrained):has(.dkb) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
body.dkb-single-package-page :where([class*="wp-container-core-group-is-layout-"]):has(.dkb) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
body.package-template-default :where(.is-layout-constrained):has(.dkb) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
body.package-template-default :where([class*="wp-container-core-group-is-layout-"]):has(.dkb) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
body.bungalow-template-default :where(.is-layout-constrained):has(.dkb) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
body.bungalow-template-default :where([class*="wp-container-core-group-is-layout-"]):has(.dkb) > :where(:not(.alignleft):not(.alignright):not(.alignfull)) {
  max-width: 90% !important;
  margin-left: auto !important;
  margin-right: auto !important;
}

/*
 * My Requests / a request thread: the page that embeds these can be a full-width theme
 * template (some copies run their Group block at 90%/95% content-size) — a plain list/table
 * doesn't need that width and reads badly stretched that wide, especially the table's empty
 * gaps between short cells. Capped on the widget's own element so it's correct regardless of
 * what width the surrounding page template declares, matching the .dkb-portal (My Bookings) cap.
 */
[data-dkb="request-list"],
[data-dkb="request-thread"],
[data-dkb="staff-dashboard"],
[data-dkb="staff-thread"] {
  max-width: 52rem;
  margin-left: auto;
  margin-right: auto;
}

/*
 * Guest request list / thread: some of the site's own page templates set the block
 * theme's content column to 90% width for these pages. That works for the bungalow/package
 * widgets above (they need the room) but leaves this simple table and reply form stretched
 * into one thin readable strip with huge empty gaps between columns. Narrow it back down to
 * the theme's own default reading width instead, scoped to the widget itself (via data-dkb)
 * so it applies no matter which page/template happens to embed it.
 */
:where(.is-layout-constrained):has([data-dkb="request-list"]),
:where([class*="wp-container-core-group-is-layout-"]):has([data-dkb="request-list"]),
:where(.is-layout-constrained):has([data-dkb="request-thread"]),
:where([class*="wp-container-core-group-is-layout-"]):has([data-dkb="request-thread"]),
:where(.is-layout-constrained):has([data-dkb="staff-dashboard"]),
:where([class*="wp-container-core-group-is-layout-"]):has([data-dkb="staff-dashboard"]),
:where(.is-layout-constrained):has([data-dkb="staff-thread"]),
:where([class*="wp-container-core-group-is-layout-"]):has([data-dkb="staff-thread"]) {
  --wp--style--global--content-size: 645px !important;
  --wp--style--global--wide-size: 645px !important;
}

:where(.is-layout-constrained):has([data-dkb="request-list"]) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
:where([class*="wp-container-core-group-is-layout-"]):has([data-dkb="request-list"]) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
:where(.is-layout-constrained):has([data-dkb="request-thread"]) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
:where([class*="wp-container-core-group-is-layout-"]):has([data-dkb="request-thread"]) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
:where(.is-layout-constrained):has([data-dkb="staff-dashboard"]) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
:where([class*="wp-container-core-group-is-layout-"]):has([data-dkb="staff-dashboard"]) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
:where(.is-layout-constrained):has([data-dkb="staff-thread"]) > :where(:not(.alignleft):not(.alignright):not(.alignfull)),
:where([class*="wp-container-core-group-is-layout-"]):has([data-dkb="staff-thread"]) > :where(:not(.alignleft):not(.alignright):not(.alignfull)) {
  max-width: 645px !important;
  margin-left: auto !important;
  margin-right: auto !important;
}

.dkb * { box-sizing: border-box; }

/*
 * Neutralise the theme's element spacing inside our widgets.
 *
 * Block themes apply generous margins to labels, paragraphs, lists and fieldsets via
 * low-specificity :where() rules. Those are right for an article and wrong for a dense
 * booking form — unchecked, a single extra grew to about 300px tall and a list of 32 became
 * unusable. We own the spacing in here; everything below sets it back deliberately.
 */
.dkb :where(p, ul, ol, li, label, fieldset, legend, h2, h3, figure) {
  margin: 0;
  padding: 0;
}

.dkb :where(fieldset) { border: 0; min-width: 0; }
.dkb :where(ul, ol) { list-style: none; }

/*
 * Keep our widgets clickable when a layout floats them over decorative layers.
 *
 * The theme's hero video stacks a tint overlay (z-index 1) and a full-size content layer
 * (z-index 2) over the whole hero, and the search form overlaps that area on the front
 * page — unpositioned, it painted UNDERNEATH both, so every click landed on the overlay
 * instead of the fields. Raising the widget wrapper is the surgical fix: the overlay keeps
 * covering the video (it also shields the video element from stray clicks) everywhere
 * except directly over our controls.
 */
.dkb { position: relative; z-index: 10; }

/*
 * WordPress's wpautop turns the newlines in shortcode markup into <br> tags. Inside a flex
 * or grid form column each stray <br> is a 22px item, so a field with more source lines
 * (the date fields carry hidden value inputs) ends up TALLER than its neighbours and the
 * whole search bar falls out of alignment. We never author <br> in structural containers —
 * any found there is autop noise. Content areas (request messages use nl2br deliberately)
 * are untouched.
 */
.dkb :where(.dkb-field, .dkb-searchbar, .dkb-stack, .dkb-card, .dkb-pills, .dkb-choice, .dkb-totals, .dkb-checkout, [data-dkb-checkout]) > br,
.dkb :where(.dkb-field, .dkb-searchbar, .dkb-stack, .dkb-card, .dkb-pills, .dkb-choice, .dkb-totals, .dkb-checkout, [data-dkb-checkout]) > p:empty {
  /*
   * Both are wpautop artifacts: stray <br>s AND empty <p></p>s. An empty paragraph has no
   * height of its own but still counts as a flex/grid item, so it adds a phantom gap that
   * pushes one column out of line with its neighbours.
   */
  display: none;
}

/* wpautop sometimes wraps a lone submit button in <p>…</p> with <br> inside. */
.dkb [data-dkb-checkout] p {
  margin: 0;
}

.dkb [data-dkb-checkout] p > br {
  display: none;
}

.dkb [data-dkb-checkout] > p:only-child {
  display: contents;
}

.dkb-stack > * + * { margin-top: var(--dkb-gap); }

.dkb-card {
  background: var(--dkb-surface);
  border: 1px solid var(--dkb-line);
  border-radius: var(--dkb-radius-lg);
  padding: 1rem;
}

@media (min-width: 48em) {
  .dkb-card { padding: 1.25rem; }
}

/* ---------------------------------------------------------------- form */

.dkb-field { display: flex; flex-direction: column; gap: .35rem; }

.dkb-label {
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--dkb-ink-soft);
}

.dkb-input,
.dkb-select {
  min-height: var(--dkb-touch);
  width: 100%;
  padding: .5rem .75rem;
  border: 1px solid var(--dkb-line);
  border-radius: var(--dkb-radius);
  background: var(--dkb-surface);
  color: var(--dkb-ink);
  /* 16px stops iOS Safari zooming the page when a field is focused. */
  font-size: 1rem;
  font-family: inherit;
  accent-color: var(--dkb-accent);
}

.dkb-input:focus-visible,
.dkb-select:focus-visible,
.dkb-btn:focus-visible {
  outline: 3px solid var(--dkb-primary);
  outline-offset: 2px;
}

.dkb-input[aria-invalid="true"] { border-color: var(--dkb-error); }

/* The whole date field opens the calendar, not just a 20px icon. */
.dkb-input[type="date"],
.dkb-field .flatpickr-input,
.dkb-field .form-control.input { cursor: pointer; }

/*
 * flatpickr's visible input already carries .dkb-input, so it inherits the field styling.
 * What it does NOT inherit is the native date field's calendar icon, so an empty field
 * would read as a plain, blank box with nothing to suggest it opens anything.
 *
 * The icon is an inline data URI: no extra request, and nothing to break if an external
 * host is unreachable.
 */
.dkb-input--date {
  cursor: pointer;
  padding-right: 2.25rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235c5750' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'/%3E%3Cline x1='16' y1='2' x2='16' y2='6'/%3E%3Cline x1='8' y1='2' x2='8' y2='6'/%3E%3Cline x1='3' y1='10' x2='21' y2='10'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .7rem center;
  background-size: 16px 16px;
}

.dkb-input--date:hover,
.dkb-input--date:focus { border-color: var(--dkb-primary); }

/* An empty field should invite, not just sit there. */
.dkb-input--date::placeholder { color: var(--dkb-ink-soft); opacity: 1; }

.dkb-field { position: relative; }

/* ------------------------------------------------------- calendar (flatpickr) */

/* Dress the calendar in the brand rather than flatpickr's blue defaults. It renders at the
   end of <body>, outside .dkb, so these rules are deliberately not nested under it. */
.flatpickr-calendar {
  border-radius: var(--dkb-radius-lg, 16px);
  box-shadow: 0 8px 30px rgba(26, 26, 26, .18);
  font-family: inherit;
}

.flatpickr-months,
.flatpickr-month,
.flatpickr-current-month .flatpickr-monthDropdown-months {
  background: #ede9d0;
  color: #1a1a1a;
  fill: #1a1a1a;
  border-radius: var(--dkb-radius-lg, 16px) var(--dkb-radius-lg, 16px) 0 0;
}

.flatpickr-weekdays,
span.flatpickr-weekday {
  background: #ede9d0;
  color: #5c5750;
  font-weight: 600;
}

.flatpickr-months .flatpickr-prev-month:hover svg,
.flatpickr-months .flatpickr-next-month:hover svg { fill: #ff9e57; }

.flatpickr-day:hover,
.flatpickr-day:focus { background: #ede9d0; border-color: transparent; }

.flatpickr-day.today { border-color: #ff9e57; }

/*
 * Range selection — flatpickr paints start / in-range / end as separate classes.
 * Do not style .startRange and .endRange like a lone .selected circle, or the band
 * breaks into disconnected chips (gaps between days).
 */
.flatpickr-day.inRange,
.flatpickr-day.prevMonthDay.inRange,
.flatpickr-day.nextMonthDay.inRange {
  border-radius: 0;
  background: var(--dkb-calendar-range);
  border-color: transparent;
  box-shadow: -5px 0 0 var(--dkb-calendar-range), 5px 0 0 var(--dkb-calendar-range);
  color: #1a1a1a;
}

.flatpickr-day.inRange:hover {
  background: var(--dkb-calendar-range);
  border-color: transparent;
}

.flatpickr-day.startRange,
.flatpickr-day.startRange:hover {
  background: var(--dkb-accent);
  border-color: var(--dkb-accent);
  color: #fff;
  border-radius: 50px 0 0 50px;
  box-shadow: none;
}

.flatpickr-day.endRange,
.flatpickr-day.endRange:hover {
  background: var(--dkb-accent);
  border-color: var(--dkb-accent);
  color: #fff;
  border-radius: 0 50px 50px 0;
  box-shadow: none;
}

/* One night only, or single-day pickers */
.flatpickr-day.startRange.endRange {
  border-radius: 50px;
}

.flatpickr-day.startRange.inRange {
  border-radius: 50px 0 0 50px;
  box-shadow: 5px 0 0 var(--dkb-calendar-range);
}

.flatpickr-day.endRange.inRange {
  border-radius: 0 50px 50px 0;
  box-shadow: -5px 0 0 var(--dkb-calendar-range);
}

/* Non-range highlight (should be rare with rangePlugin) */
.flatpickr-day.selected:not(.startRange):not(.endRange) {
  background: var(--dkb-accent);
  border-color: var(--dkb-accent);
  color: #fff;
}

.flatpickr-day.flatpickr-disabled,
.flatpickr-day.prevMonthDay,
.flatpickr-day.nextMonthDay { color: rgba(92, 87, 80, .35); }


/* The search form: stacked on a phone, one row once there is room.
   Dates need width; guest counts do not — equal columns starved the number fields until
   their value was clipped to an ellipsis. */
.dkb-searchbar { display: grid; gap: .75rem; }

@media (min-width: 40em) {
  .dkb-searchbar {
    grid-template-columns:
      minmax(8.5rem, 1.1fr)   /* check in  */
      minmax(8.5rem, 1.1fr)   /* check out */
      5rem                    /* adults    */
      5rem                    /* children  */
      minmax(7rem, .8fr)      /* category  */
      auto;                   /* submit    */
    align-items: end;
  }

  /* Bungalow / package date row — four fields only, no category or submit. */
  .dkb-searchbar--stay {
    grid-template-columns:
      minmax(8rem, 1.2fr)     /* check in  */
      minmax(8rem, 1.2fr)     /* check out */
      5rem                    /* adults    */
      minmax(9rem, 1fr);       /* children  */
  }
}

/*
 * Child-age selectors belong to the Children field, not to the whole form.
 *
 * On a phone (stacked layout) they flow in place directly beneath the Children input. On a
 * wide screen they become a small panel anchored under that field — the guest opens it by
 * touching the field, and the chosen ages keep submitting even while it is closed.
 */
.dkb-ages { display: grid; gap: .5rem; }

.dkb-ages-summary {
  margin: .35rem 0 0;
  font-size: .8125rem;
  color: var(--dkb-ink-soft);
  line-height: 1.35;
}

@media (min-width: 40em) {
  /* Keep the summary out of the search-bar row height so Children stays aligned
     with Adults and the date fields (align-items: end on the grid). */
  .dkb-searchbar .dkb-ages-summary {
    position: absolute;
    top: 100%;
    left: 0;
    margin: .2rem 0 0;
    width: max-content;
    max-width: none;
    white-space: nowrap;
    z-index: 5;
  }

  .dkb-searchbar [data-dkb-ages][data-open="1"] ~ .dkb-ages-summary {
    visibility: hidden;
  }

  /* Stay fields on bungalow / package pages: wrap inside the Children column. */
  .dkb-searchbar--stay .dkb-ages-summary {
    width: 100%;
    min-width: 0;
    max-width: none;
    white-space: normal;
  }

  .dkb-searchbar [data-dkb-ages] {
    position: absolute;
    top: calc(100% + .4rem);
    left: 0;
    z-index: 40;
    min-width: 13rem;
    padding: .75rem;
    background: #fff;
    border-radius: var(--dkb-radius, 10px);
    box-shadow: 0 8px 30px rgba(26, 26, 26, .18);
  }
  .dkb-searchbar [data-dkb-ages]:not([data-open="1"]) { display: none; }
}

/*
 * Custom dropdown for short, fixed-choice selects (child age band, "Looking for").
 *
 * The real <select> stays in the DOM (hidden) so its name/value still travel with the form
 * exactly as before, and its own change events still fire; only this button + list are what
 * a guest sees and touches. `.dkb-select` (shared with text/date/number fields) gives the
 * closed button the same border, height, and theme font as every other field — this block
 * only adds what a plain select can't do: a caret, and a listbox we can brand and size
 * ourselves instead of handing the guest whatever the OS renders.
 */
.dkb-combo { position: relative; }

.dkb-combo-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  width: 100%;
  text-align: start;
  cursor: pointer;
  padding-right: 2.25rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235c5750' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .7rem center;
  background-size: 16px 16px;
}

.dkb-combo-btn__label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dkb-combo-btn:hover,
.dkb-combo-btn:focus-visible,
.dkb-combo-btn[aria-expanded="true"] { border-color: var(--dkb-primary); }

/*
 * Match the outline every other field gets on `:focus-visible` (see `.dkb-input,
 * .dkb-select` above). A <button> opened by a click/tap isn't treated as focus-visible in
 * most browsers, so without this rule "Looking for" and the age/guest-count selects showed
 * no outline (or a mismatched one) at exactly the moment Adults/Children showed theirs.
 */
.dkb-combo-btn:focus-visible,
.dkb-combo-btn[aria-expanded="true"] {
  outline: 3px solid var(--dkb-primary);
  outline-offset: 2px;
}

.dkb-combo-list {
  position: absolute;
  top: calc(100% + .35rem);
  left: 0;
  right: 0;
  z-index: 45;
  margin: 0;
  padding: .35rem;
  list-style: none;
  background: var(--dkb-surface);
  border: 1px solid var(--dkb-line);
  border-radius: var(--dkb-radius);
  box-shadow: 0 8px 30px rgba(26, 26, 26, .18);
  max-height: 14rem;
  overflow: auto;
  font-size: 1rem;
  font-family: inherit;
}

.dkb-combo-option {
  padding: .55rem .65rem;
  border-radius: calc(var(--dkb-radius) - 4px);
  cursor: pointer;
  min-height: var(--dkb-touch);
  display: flex;
  align-items: center;
}

.dkb-combo-option.is-active { background: var(--dkb-sand); }
.dkb-combo-option.is-selected { color: var(--dkb-primary-strong); font-weight: 600; }
/* The chosen option while highlighted (hover/keyboard): background stays the accent
   orange, but dark ink on that orange reads poorly, so the label goes white here only. */
.dkb-combo-option.is-selected.is-active { background: var(--dkb-accent); color: var(--dkb-on-primary); }

/* A radio/checkbox row. The whole row is the target, not just the 16px control — the
   single biggest usability win on a phone. */
.dkb-choice {
  display: flex;
  align-items: start;
  gap: .6rem;
  min-height: var(--dkb-touch);
  padding: .6rem .75rem;
  border: 1px solid var(--dkb-line);
  border-radius: var(--dkb-radius);
  background: var(--dkb-surface);
  cursor: pointer;
}

.dkb-choice:hover { background: var(--dkb-surface-alt); }

.dkb-choice input {
  /* Nudge the control onto the first line of text. */
  margin-top: .2rem;
  width: 1.15rem;
  height: 1.15rem;
  accent-color: var(--dkb-primary);
  flex: none;
}

.dkb-choice span { display: grid; gap: .15rem; }
.dkb-choice em { font-style: normal; }

.dkb-choice:has(input:checked) {
  border-color: var(--dkb-primary);
  background: var(--dkb-sand);
}

/* Payment option (deposit/full) drives this highlight from JS (syncPaymentOptionSelection)
   rather than leaning on the browser's own :checked tracking above — see that function's
   comment for why. Same look, applied on a class this file alone ever sets. */
.dkb-choice.is-selected {
  border-color: var(--dkb-primary);
  background: var(--dkb-sand);
}

.dkb-choice:focus-within {
  outline: 3px solid var(--dkb-primary);
  outline-offset: 2px;
}

fieldset.dkb-card { border: 1px solid var(--dkb-line); }
fieldset.dkb-card legend { padding: 0 .35rem; }

/* ---------------------------------------------------------------- buttons */

.dkb-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: var(--dkb-touch);
  padding: .5rem 1.25rem;
  border: 1px solid transparent;
  border-radius: var(--dkb-radius);
  background: var(--dkb-primary);
  color: var(--dkb-on-primary);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  transition: background-color .15s ease, transform .05s ease;
}

.dkb-btn:hover { background: var(--dkb-primary-hover); }
.dkb-btn:active { transform: translateY(1px); }

.dkb-btn[disabled],
.dkb-btn[aria-busy="true"] {
  opacity: .6;
  cursor: not-allowed;
  transform: none;
}

.dkb-btn--ghost {
  background: transparent;
  border-color: var(--dkb-line);
  color: var(--dkb-ink);
}
.dkb-btn--ghost:hover { background: var(--dkb-sand); }

.dkb-btn--quiet {
  background: transparent;
  border-color: transparent;
  color: var(--dkb-ink-soft);
  text-decoration: underline;
  min-height: auto;
  padding: .25rem;
}
.dkb-btn--quiet:hover { background: transparent; color: var(--dkb-error); }

.dkb-btn--block { width: 100%; }

@media (min-width: 40em) {
  .dkb-btn--block { width: auto; }
}

/* While a search shows results, the theme hides anything marked .resa-hide-on-search (the
   hero). The theme already styles this; the rule is repeated here so the behaviour does not
   depend on the theme's copy surviving. Intentionally not scoped under .dkb — the marked
   elements live in the theme's templates, outside our widgets. */
body.resa-search-active .resa-hide-on-search { display: none !important; }

/* ---------------------------------------------------------------- results */

[data-dkb="search-results"] {
  margin-top: 1.25rem;
}

[data-dkb="search-results"] [data-dkb-status] {
  min-height: 2.25rem;
  margin: 0 0 .75rem;
}

[data-dkb="search-results"] [data-dkb-status] .dkb-note {
  margin: 0 0 .35rem;
}

/* One result per row. A guest comparing two stays needs the whole offer — plan, prices,
   what's included — visible at once; a narrow grid card can only carry a headline price
   and forces them into three tabs to answer one question. */
.dkb-results { display: grid; gap: var(--dkb-gap); }

.dkb-result {
  display: grid;
  gap: 0;
  overflow: hidden;
  padding: 0;
}

/* Picture beside the offer once there is room; stacked on a phone. */
@media (min-width: 48em) {
  .dkb-result { grid-template-columns: minmax(0, 45%) minmax(0, 1fr); }
}

/*
 * A fixed ratio at every width, on purpose: package cards carry an extra "Inclusions" list
 * (and sometimes a badge/accommodation line) that bungalow cards never have, so their body
 * column is naturally taller. Letting the image stretch to match the row height — as it did
 * before — meant the same picture rendered a different size on a package card than on a
 * bungalow card purely because of how much text sat next to it. A fixed ratio keeps every
 * card's photo the same shape regardless of how tall its text column is.
 *
 * 4:3 rather than a wide 16:10 — closer to square reads better for the bungalow/interior
 * photos this feeds, and crops less of a portrait-leaning source image on a phone.
 */
.dkb-result__media {
  aspect-ratio: 4 / 3;
  background: var(--dkb-sand);
  overflow: hidden;
}

.dkb-result__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.dkb-result__body {
  padding: 1rem;
  display: grid;
  gap: .4rem;
  align-content: start;
}

@media (min-width: 48em) {
  .dkb-result__body { padding: 1.25rem; }
}

.dkb-result__title {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}

.dkb-result__meta { margin: 0; font-size: .8125rem; color: var(--dkb-ink-soft); }

.dkb-result__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
  margin-top: .5rem;
}

.dkb-result__foot .dkb-btn {
  color: #fff;
}

.dkb-result__foot .dkb-btn:hover,
.dkb-result__foot .dkb-btn:focus-visible {
  background: var(--dkb-select-hover);
  color: #fff;
}

.dkb-result__foot .dkb-btn--disabled,
.dkb-result__foot .dkb-btn--disabled:hover,
.dkb-result__foot .dkb-btn--disabled:focus-visible {
  background: var(--dkb-line);
  color: var(--dkb-ink-soft);
  cursor: not-allowed;
  opacity: .85;
}

.dkb-btn.dkb-btn--disabled,
.dkb-btn.dkb-btn--disabled:hover {
  opacity: .45;
  pointer-events: none;
  cursor: not-allowed;
}

/* A labelled figure: "Price/night:  945.00  850.50" */
.dkb-figure {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: .4rem;
  flex-wrap: wrap;
  font-size: .9375rem;
}

.dkb-figure__label { color: var(--dkb-ink-soft); font-size: .8125rem; font-weight: 600; }

/* The headline Total: bold is enough emphasis on its own — 1.375rem read oversized next to
   the rest of a result card on a phone, so the bump over the row's own 1.125rem is modest. */
.dkb-figure--lead { font-size: 1.125rem; margin-bottom: .25rem; }
.dkb-figure--lead strong { font-size: 1.2rem; }

.dkb-inclusions {
  display: grid;
  gap: .45rem;
  padding: .75rem .85rem;
  margin: .35rem 0;
  border: 1px solid var(--dkb-line);
  border-radius: var(--dkb-radius);
  background: linear-gradient(180deg, #fff 0%, var(--dkb-surface-alt) 100%);
}

.dkb-inclusions .dkb-extras {
  margin: 0;
  padding: 0;
  display: grid;
  gap: .2rem;
}

.dkb-inclusions .dkb-extras li {
  display: block;
  color: var(--dkb-ink);
  text-align: start;
  font-size: .875rem;
  line-height: 1.35;
}
.dkb-inclusions .dkb-extras li::before { content: "• "; color: var(--dkb-primary); font-weight: 700; }

.dkb-inclusions .dkb-figure {
  margin-top: .25rem;
  padding-top: .45rem;
  border-top: 1px dashed var(--dkb-line);
}

.dkb-cart-actions { margin-top: .75rem; }

.dkb-booking-customer { margin: .75rem 0; display: grid; gap: .35rem; }

.dkb-note--info {
  border-left-color: var(--dkb-primary);
  background: #fff8f4;
}

/* ---------------------------------------------------------------- price */

.dkb-price { display: flex; align-items: baseline; gap: .35rem; }
.dkb-price__amount { font-size: 1.25rem; font-weight: 700; }
.dkb-price__unit { font-size: .8125rem; color: var(--dkb-ink-soft); }

.dkb-money { font-variant-numeric: tabular-nums; }

/* The pre-discount price, struck through beside what is actually charged — so a guest can
   see the saving rather than be told about it. */
.dkb-pricepair { display: inline-flex; align-items: baseline; gap: .4rem; }

.dkb-was {
  color: var(--dkb-ink-soft);
  font-weight: 400;
  font-size: .875em;
  text-decoration-thickness: 1px;
}

/* Package accommodation / inclusions discount — neutral grey strike. */
.dkb-was--package {
  color: var(--dkb-ink-soft);
  text-decoration-color: currentColor;
}

/* Automatic promotion — warmer accent so it reads differently from package savings. */
.dkb-was--promo {
  color: var(--dkb-accent, #b45309);
  text-decoration-color: currentColor;
}

/* ---------------------------------------------------------------- gallery */

/*
 * A full-width slider: one photo at a time, edge to edge.
 *
 * Built on scroll-snap rather than a carousel library — it swipes natively on touch,
 * responds to the wheel and arrow keys, is keyboard-focusable, and still shows the photos
 * if CSS or JS fails. The buttons and dots are conveniences layered on top, not the
 * mechanism.
 */
.dkb-slider { position: relative; }

.dkb-gallery {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  border-radius: var(--dkb-radius-lg);
  -webkit-overflow-scrolling: touch;
  /* The scrollbar would sit over the photo; the dots do that job instead. */
  scrollbar-width: none;
}

.dkb-gallery::-webkit-scrollbar { display: none; }

.dkb-gallery:focus-visible { outline: 3px solid var(--dkb-primary); outline-offset: 3px; }

/* One photo per view, always — the picture is the point. */
.dkb-gallery__slide {
  flex: 0 0 100%;
  scroll-snap-align: center;
  scroll-snap-stop: always;
  margin: 0;
  aspect-ratio: 1 / 1;
  background: var(--dkb-sand);
  overflow: hidden;
}

.dkb-gallery__slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* --- controls --- */

.dkb-slider__btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .92);
  color: var(--dkb-ink);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--dkb-shadow);
}

.dkb-slider__btn:hover { background: #fff; }
.dkb-slider__btn:focus-visible { outline: 3px solid var(--dkb-primary); outline-offset: 2px; }

.dkb-slider__btn--prev { left: .6rem; }
.dkb-slider__btn--next { right: .6rem; }

.dkb-slider__dots {
  position: absolute;
  bottom: .6rem;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: .35rem;
  padding: .3rem .5rem;
  border-radius: 999px;
  background: rgba(26, 26, 26, .35);
}

.dkb-slider__dot {
  width: .5rem;
  height: .5rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .55);
  cursor: pointer;
}

.dkb-slider__dot[aria-current="true"] { background: #fff; width: 1.25rem; border-radius: 999px; }

/* A single photo is not a slider. */
.dkb-slider--single .dkb-slider__btn,
.dkb-slider--single .dkb-slider__dots { display: none; }

/* ---------------------------------------------------------------- pills */

.dkb-pills { display: flex; flex-wrap: wrap; gap: .4rem; }

.dkb-pill {
  position: relative;
  display: inline-flex;
  cursor: pointer;
}

/* The radio itself is hidden but still focusable and announced. */
.dkb-pill input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.dkb-pill__label {
  display: inline-flex;
  align-items: center;
  min-height: 2.25rem;
  padding: .35rem .85rem;
  border: 1px solid var(--dkb-line);
  border-radius: 999px;
  background: var(--dkb-surface);
  font-size: .875rem;
  font-weight: 600;
}

.dkb-pill--is-selected .dkb-pill__label,
.dkb-pill input:checked + .dkb-pill__label {
  background: var(--dkb-plan);
  border-color: var(--dkb-plan);
  color: var(--dkb-on-plan);
}

.dkb-pill input:focus-visible + .dkb-pill__label {
  outline: 3px solid var(--dkb-plan);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------- extras */

/*
 * One extra = one line: [✓] Name .......... Days [2] Qty [1]
 *
 * 32 of these have to be scannable. The name and its controls stay on a single row and the
 * whole row is a hit target, so the list reads as a list rather than 32 stacked blocks.
 */
.dkb-extra {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .45rem .65rem;
  margin: 0 0 .35rem;
  border: 1px solid transparent;
  border-radius: var(--dkb-radius);
  background: transparent;
  box-sizing: border-box;
}

.dkb-extra:last-of-type { margin-bottom: 0; }

/* Author display:flex must not defeat the HTML hidden attribute used by category filters. */
.dkb-extra[hidden] { display: none !important; }

.dkb-extra .dkb-choice {
  flex: 1 1 auto;
  min-width: 0;
  align-items: center;
  border: 0;
  border-radius: 0;
  background: transparent;
  padding: .3rem 0;
  min-height: 2.5rem;
  /* Avoid a second “focus box” on click — the row border is enough. */
  outline: none;
}

.dkb-extra .dkb-choice:hover { background: transparent; }
.dkb-extra .dkb-choice:hover span strong { color: var(--dkb-primary-strong); }
.dkb-extra .dkb-choice:focus,
.dkb-extra .dkb-choice:focus-within {
  outline: none;
  box-shadow: none;
}

.dkb-extra .dkb-choice input:focus,
.dkb-extra .dkb-choice input:focus-visible {
  outline: none;
  box-shadow: none;
}

/* The name sits beside its checkbox, not under it. */
.dkb-extra .dkb-choice span {
  display: flex;
  align-items: center;
  gap: .4rem;
  flex-wrap: wrap;
  font-size: .9375rem;
  line-height: 1.3;
}

.dkb-extra .dkb-choice input {
  margin-top: 0;
  accent-color: var(--dkb-primary);
  flex: none;
}

/* Selected extra: full box on all four sides (not only top/bottom rules). */
.dkb-extra:has(input[name="extras[]"]:checked) {
  background: var(--dkb-sand);
  border: 1px solid var(--dkb-primary);
}

.dkb-extra:has(input[name="extras[]"]:checked) .dkb-choice input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 1.15rem;
  height: 1.15rem;
  border: 2px solid var(--dkb-primary);
  border-radius: .2rem;
  background: var(--dkb-primary);
  display: inline-grid;
  place-content: center;
  color-scheme: dark;
}

.dkb-extra:has(input[name="extras[]"]:checked) .dkb-choice input[type="checkbox"]::after {
  content: "";
  width: .45rem;
  height: .25rem;
  border: 2px solid #fff;
  border-top: 0;
  border-right: 0;
  transform: rotate(-45deg) translate(1px, -1px);
}

.dkb-extra__inputs {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex: 0 0 auto;
  flex-wrap: wrap;
}

/* Label and box on one line — "Days [2]" reads faster stacked than side by side. */
.dkb-inline {
  display: flex;
  align-items: center;
  gap: .3rem;
}

.dkb-inline .dkb-sublabel { font-size: .75rem; white-space: nowrap; }

.dkb-input--tiny {
  width: 3.75rem;
  min-height: 2.25rem;
  padding: .2rem .4rem;
  text-align: center;
}

.dkb-extra .dkb-badge { font-size: .6875rem; font-style: normal; padding: .1rem .4rem; }

/* A long catalogue should not bury the price panel — cap it and let it scroll. */
.dkb-extras-scroll {
  max-height: 22rem;
  overflow-x: hidden;
  overflow-y: auto;
  padding: .15rem .15rem .35rem;
}

.dkb-totals__row--sub {
  font-size: .8125rem;
  color: var(--dkb-ink-soft);
  padding-left: .75rem;
}

/* ---------------------------------------------------------------- badges */

.dkb-badge {
  display: inline-block;
  padding: .15rem .5rem;
  border-radius: 999px;
  background: var(--dkb-sand);
  color: var(--dkb-ink);
  font-size: .75rem;
  font-weight: 600;
}

.dkb-badge--low { background: var(--dkb-accent); color: #fff; }
/* Matches the occupancy calendar's colour codes for the same flags. */
.dkb-badge--warn { background: #FF9E57; color: #1d2327; }
.dkb-badge--cancelled { background: #FF6A3D; color: #fff; }
.dkb-badge--noshow { background: #EDE9D0; color: #1d2327; }
.dkb-badge--confirmed { background: #57B8FF; color: #1d2327; }

/* ---------------------------------------------------------------- cart */

.dkb-line {
  display: grid;
  gap: .5rem;
  padding: 1rem 0;
  border-bottom: 1px solid var(--dkb-line);
}

.dkb-line:last-of-type { border-bottom: 0; }

.dkb-line__head {
  display: flex;
  justify-content: space-between;
  align-items: start;
  gap: .75rem;
}

.dkb-line__title { margin: 0; font-size: 1rem; font-weight: 700; }

.dkb-line__price-col {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .15rem;
  text-align: right;
}

.dkb-extras-filters {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-bottom: .75rem;
}

.dkb-pill--filter {
  cursor: pointer;
  border: 1px solid var(--dkb-line);
  background: #fff;
}

.dkb-bungalow-pick__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .75rem;
}

.dkb-bungalow-pick__row .dkb-select {
  flex: 1 1 12rem;
  min-width: 0;
}

.dkb-bungalow-details-row {
  text-align: left;
}

.dkb-checkout__aside [data-dkb-quote].dkb-quote-panel {
  position: relative;
}

.dkb-quote-stock {
  position: absolute;
  top: .75rem;
  right: .75rem;
  margin: 0;
}

.dkb-quote-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: .75rem;
  margin-top: 1.25rem;
}

.dkb-prose {
  white-space: pre-wrap;
  font-size: .9rem;
  line-height: 1.5;
}

.dkb-booking-item__guests {
  font-size: .9rem;
}

.dkb-line__actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: .5rem;
}

.dkb-extras { margin: 0; padding: 0; list-style: none; display: grid; gap: .25rem; }

.dkb-extras li {
  display: flex;
  justify-content: space-between;
  gap: .75rem;
  font-size: .875rem;
  color: var(--dkb-ink-soft);
}

.dkb-totals { display: grid; gap: .4rem; }

.dkb-totals__row { display: flex; justify-content: space-between; gap: 1rem; }

.dkb-totals__row--grand {
  padding-top: .6rem;
  border-top: 2px solid var(--dkb-ink);
  font-size: 1.125rem;
  font-weight: 700;
}

/* A promotion is a saving — coloured so it reads as money coming off, not another charge. */
.dkb-totals__row--discount { color: #1a7f37; font-weight: 600; }
.dkb-offer { color: #1a7f37; font-weight: 600; }

/* The promo-code box: a labelled input with an inline "Apply" button. */
.dkb-promo { display: grid; gap: .4rem; margin-top: .75rem; }
.dkb-promo__row { display: flex; gap: .5rem; align-items: stretch; }
.dkb-promo__row .dkb-input { flex: 1 1 auto; text-transform: uppercase; }
.dkb-promo__row .dkb-btn { flex: 0 0 auto; }

/* ----------------------------------------------------------------- requests */

/* A thread message; internal staff notes are tinted and marked off from guest replies. */
.dkb-msg { padding: .75rem 0; border-top: 1px solid rgba(0, 0, 0, .08); }
.dkb-msg:first-child { border-top: 0; }
.dkb-msg--internal {
  background: color-mix(in srgb, var(--dkb-sand) 55%, transparent);
  border-left: 3px solid var(--dkb-primary);
  padding-left: .75rem;
  border-radius: 6px;
}

/* Inline mini-form in a list row (e.g. the staff status selector). */
.dkb-inline-form { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }

/* Status filter chips. */
.dkb-filter { display: flex; gap: .5rem; flex-wrap: wrap; }
.dkb-chip {
  align-content: center;
  display: inline-block;
  padding: .3rem .75rem;
  border-radius: 999px;
  background: var(--dkb-sand);
  color: var(--dkb-ink);
  text-decoration: none;
  font-size: .875rem;
}
.dkb-chip.is-active { background: var(--dkb-primary); color: var(--dkb-on-primary); }
.dkb-badge--ok { background: #1a7f37; color: #fff; }

.dkb-table-wrap {
  overflow-x: auto;
}
.dkb-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--dkb-card, #fff);
}
.dkb-table th,
.dkb-table td {
  text-align: left;
  padding: .7rem .75rem;
  border-bottom: 1px solid var(--dkb-line, #e6e1d8);
  vertical-align: top;
}
.dkb-table th {
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--dkb-muted, #6b655c);
}

/* Two-column checkout only when a summary aside exists (cart / booking details). */
.dkb-checkout:has(.dkb-checkout__aside) {
  display: grid;
  gap: var(--dkb-gap);
}

@media (min-width: 56em) {
  .dkb-checkout:has(.dkb-checkout__aside) {
    grid-template-columns: minmax(0, 1fr) 22rem;
    align-items: start;
  }

  .dkb-checkout:has(.dkb-checkout__aside) .dkb-checkout__aside {
    position: sticky;
    top: 1.5rem;
  }
}

/* My bookings — always single column; never inherit checkout grid. */
.dkb-portal:not(:has(.dkb-checkout__aside)) {
  display: block;
  max-width: 52rem;
}

/* ---------------------------------------------------------------- messages */

.dkb-note {
  padding: .6rem .75rem;
  border-radius: var(--dkb-radius);
  border-left: 4px solid var(--dkb-line);
  background: var(--dkb-surface-alt);
  font-size: .875rem;
}

.dkb-note--error { border-left-color: var(--dkb-error); color: var(--dkb-error); }
.dkb-note--warn  { border-left-color: var(--dkb-warn); color: var(--dkb-warn); }
.dkb-note--ok    { border-left-color: var(--dkb-ok); color: var(--dkb-ok); }

.dkb-errors { margin: 0; padding-left: 1.1rem; }

.dkb-empty {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--dkb-ink-soft);
  background: var(--dkb-surface-alt);
  border-radius: var(--dkb-radius-lg);
}

/* ---------------------------------------------------------------- states */

.dkb-skeleton {
  background: linear-gradient(90deg, var(--dkb-sand) 25%, var(--dkb-sand-deep) 50%, var(--dkb-sand) 75%);
  background-size: 200% 100%;
  animation: dkb-shimmer 1.2s infinite;
  border-radius: var(--dkb-radius);
  min-height: 1rem;
}

@keyframes dkb-shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

[data-dkb-busy="true"] { opacity: .55; pointer-events: none; }

/* Toast after add-to-cart (API can succeed while the guest sees nothing without this). */
.dkb-toast {
  position: fixed;
  left: 50%;
  bottom: 1.25rem;
  transform: translateX(-50%) translateY(120%);
  z-index: 100000;
  max-width: min(24rem, calc(100vw - 2rem));
  padding: .85rem 1.1rem;
  border-radius: var(--dkb-radius-lg);
  background: var(--dkb-ink);
  color: var(--dkb-surface);
  box-shadow: var(--dkb-shadow);
  font-size: .95rem;
  line-height: 1.4;
  transition: transform .25s ease;
  pointer-events: none;
}

.dkb-toast.is-visible {
  transform: translateX(-50%) translateY(0);
}

.dkb-toast--ok { background: var(--dkb-ok); color: #fff; }

dialog.dkb-dialog {
  border: none;
  border-radius: var(--dkb-radius, 0.5rem);
  padding: 1.25rem;
  max-width: 36rem;
  width: min(36rem, calc(100vw - 2rem));
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
  color: inherit;
  background: var(--dkb-surface, #fff);
}

dialog.dkb-dialog::backdrop {
  background: rgba(0, 0, 0, 0.45);
}

/* Guest details modal — mounted on <body>, so the root carries .dkb for tokens + resets. */
body.dkb-modal-open { overflow: hidden; }

.dkb-modal {
  position: fixed;
  inset: 0;
  z-index: 100000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  pointer-events: none;
}

.dkb-modal[hidden] { display: none !important; }

.dkb-modal.is-open,
.dkb-modal.dkb-modal--open { pointer-events: auto; }

.dkb-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(26, 26, 26, .52);
  opacity: 0;
  transition: opacity .24s ease;
}

.dkb-modal.is-open .dkb-modal__backdrop,
.dkb-modal.dkb-modal--open .dkb-modal__backdrop { opacity: 1; }

.dkb-modal__dialog,
.dkb-modal__panel {
  position: relative;
  z-index: 1;
  width: min(36rem, 100%);
  max-height: min(90vh, 760px);
  overflow: auto;
  background: var(--dkb-surface);
  border-radius: var(--dkb-radius-lg);
  box-shadow: 0 12px 40px rgba(26, 26, 26, .18);
  display: flex;
  flex-direction: column;
  opacity: 0;
  transform: translateY(14px) scale(.98);
  transition: opacity .24s ease, transform .24s ease;
}

.dkb-modal.is-open .dkb-modal__dialog,
.dkb-modal.is-open .dkb-modal__panel,
.dkb-modal.dkb-modal--open .dkb-modal__dialog,
.dkb-modal.dkb-modal--open .dkb-modal__panel {
  opacity: 1;
  transform: none;
}

.dkb-modal__title {
  margin: 0;
  font-size: 1.25rem;
  line-height: 1.35;
}

.dkb-modal__actions {
  display: flex;
  justify-content: flex-end;
  gap: .75rem;
  flex-wrap: wrap;
  padding: 1rem 1.5rem 1.35rem;
  border-top: 1px solid var(--dkb-line);
  background: var(--dkb-surface-alt);
  border-radius: 0 0 var(--dkb-radius-lg) var(--dkb-radius-lg);
}

.dkb-modal__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.35rem 1.5rem 1.15rem;
  border-bottom: 1px solid var(--dkb-line);
}

.dkb-modal__head .dkb-line__title {
  font-size: 1.25rem;
  line-height: 1.35;
  letter-spacing: -.01em;
}

.dkb-modal__close {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  margin: -.35rem -.45rem 0 0;
  padding: 0;
  border: 0;
  border-radius: var(--dkb-radius);
  background: transparent;
  color: var(--dkb-ink-soft);
  font-size: 1.65rem;
  line-height: 1;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}

.dkb-modal__close:hover {
  background: var(--dkb-surface-alt);
  color: var(--dkb-ink);
}

.dkb-modal__close:focus-visible {
  outline: 3px solid var(--dkb-primary);
  outline-offset: 2px;
}

.dkb-modal__body {
  padding: 1.35rem 1.5rem 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1.125rem;
}

.dkb-modal__features-label { margin-bottom: -.5rem; }

.dkb-modal__features {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: .55rem;
}

.dkb-modal__features-item {
  display: flex;
  align-items: baseline;
  gap: .5rem;
}

.dkb-modal__features-item::before {
  content: '✓';
  color: var(--dkb-primary);
  font-weight: 700;
  flex-shrink: 0;
}

.dkb-modal__foot {
  display: flex;
  justify-content: flex-end;
  gap: .75rem;
  flex-wrap: wrap;
  padding: 1rem 1.5rem 1.35rem;
  border-top: 1px solid var(--dkb-line);
  background: var(--dkb-surface-alt);
  border-radius: 0 0 var(--dkb-radius-lg) var(--dkb-radius-lg);
}

.dkb-req { color: var(--dkb-error); font-weight: 700; }

.dkb-guest-form__row {
  display: grid;
  gap: 1rem;
}

@media (min-width: 32em) {
  .dkb-guest-form__row { grid-template-columns: 1fr 1fr; }
}

.dkb-guest-fieldset {
  margin: 0;
  padding: 1rem 1.125rem;
  border: 1px solid var(--dkb-line);
  border-radius: var(--dkb-radius);
  background: var(--dkb-surface-alt);
  display: flex;
  flex-direction: column;
  gap: .75rem;
}

/* Author display:flex must not defeat the HTML hidden attribute (bank / phone wraps). */
.dkb-guest-fieldset[hidden] {
  display: none !important;
}

.dkb-guest-fieldset legend {
  padding: 0 .35rem;
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--dkb-ink-soft);
}

.dkb-guest-radios {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

@media (min-width: 30em) {
  .dkb-guest-radios--inline {
    flex-direction: row;
    flex-wrap: wrap;
  }

  .dkb-guest-radios--inline .dkb-choice { flex: 1 1 calc(33.333% - .5rem); }
}

/* Confirm page — saved guest summary */
.dkb-guest-panel,
.dkb-payment-block {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.dkb-guest-panel.dkb-stack > * + *,
.dkb-payment-block.dkb-stack > * + * {
  margin-top: 0;
}

.dkb-guest-panel {
  padding: 1.35rem 1.5rem;
}

.dkb-guest-panel__title {
  font-size: 1.125rem;
  letter-spacing: -.01em;
}

.dkb-guest-dl {
  margin: 0;
  display: grid;
  gap: .85rem;
}

.dkb-guest-dl__row {
  display: grid;
  gap: .3rem;
}

@media (min-width: 36em) {
  .dkb-guest-dl__row {
    grid-template-columns: minmax(9rem, 11rem) 1fr;
    gap: 1.25rem;
    align-items: baseline;
  }
}

.dkb-guest-dl dt {
  margin: 0;
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--dkb-ink-soft);
}

.dkb-guest-dl dd {
  margin: 0;
  font-size: 1rem;
  line-height: 1.45;
  color: var(--dkb-ink);
}

.dkb-guest-panel__actions {
  padding-top: 1rem;
  margin-top: .25rem;
  border-top: 1px solid var(--dkb-line);
}

.dkb-payment-block {
  padding: 1.35rem 1.5rem;
}

.dkb-payment-block .dkb-line__title {
  font-size: 1.0625rem;
  margin-top: .25rem;
}

.dkb-payment-block .dkb-line__title:first-child { margin-top: 0; }

/* Wide / narrow galleries.

   A post can carry a second, mobile-only set of photos. Both are rendered and CSS chooses,
   which keeps the markup free of any device sniffing. Mobile-first: the narrow set is the
   one on screen until there is room for the wide one. Images in the hidden strip are marked
   lazy by the renderer, so the set that loses is never downloaded. */
.dkb-slider--wide-only { display: none; }

@media (min-width: 40em) {
  .dkb-slider--wide-only { display: block; }
  .dkb-slider--narrow-only { display: none; }
}
.dkb-payment-block fieldset.dkb-stack { gap: .65rem; }

/* The payment rows draw their own radio dot.

   The row highlight is driven from JS (syncPaymentSelection) because something outside this
   codebase clears the input's checked state shortly after load. The dot inside the circle,
   though, was still the browser's own :checked rendering — so when that state was cleared the
   row stayed highlighted and the dot vanished, leaving a selected-looking row with an empty
   circle. Drawing the dot from the same class the highlight uses means the two can no longer
   disagree, whatever happens to the underlying checked flag. Scoped to the payment block, so
   every other choice row on the site keeps the native control. */
.dkb-payment-block .dkb-choice input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  border: 2px solid var(--dkb-line);
  border-radius: 50%;
  background: var(--dkb-surface);
}

.dkb-payment-block .dkb-choice.is-selected input[type="radio"] {
  border-color: var(--dkb-primary);
}

.dkb-payment-block .dkb-choice.is-selected input[type="radio"]::after {
  content: "";
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--dkb-primary);
}

/* appearance:none also removes the focus ring, and the row outline only appears once focus
   is inside — keyboard users still need to see which option they are on. */
.dkb-payment-block .dkb-choice input[type="radio"]:focus-visible {
  outline: 3px solid var(--dkb-primary);
  outline-offset: 2px;
}

/* In forced-colors mode a custom-drawn control loses its meaning: system colours replace
   the background above and the dot would disappear. Hand these back to the browser. */
@media (forced-colors: active) {
  .dkb-payment-block .dkb-choice input[type="radio"] {
    appearance: auto;
    -webkit-appearance: auto;
  }
  .dkb-payment-block .dkb-choice.is-selected input[type="radio"]::after { content: none; }
}

.dkb-payment-block .dkb-note {
  margin-top: .15rem;
  line-height: 1.55;
}

/* ---------------------------------------------------------------- guest portal */

.dkb-portal__head {
  margin-bottom: 1.25rem;
}

.dkb-portal__title {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -.02em;
}

.dkb-portal__list {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
}

/* One booking on My Bookings — stacked list of lines + payment summary. */
.dkb-booking-group {
  border: 1px solid var(--dkb-line);
  border-radius: var(--dkb-radius-lg);
  background: var(--dkb-surface);
  overflow: hidden;
}

.dkb-booking-group__head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-start;
  gap: .75rem 1.25rem;
  padding: 1.15rem 1.35rem;
  background: var(--dkb-surface-alt);
  border-bottom: 1px solid var(--dkb-line);
}

.dkb-booking-group__title {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 700;
}

.dkb-booking-group__meta {
  margin: .25rem 0 0;
  font-size: .8125rem;
  color: var(--dkb-ink-soft);
}

.dkb-booking-group__head-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  align-items: center;
}

.dkb-booking-items {
  margin: 0;
  padding: 0;
  list-style: none;
}

.dkb-booking-item {
  padding: 1.15rem 1.35rem;
  border-bottom: 1px solid var(--dkb-line);
  display: flex;
  flex-direction: column;
  gap: .85rem;
}

.dkb-booking-item:last-child { border-bottom: 0; }

.dkb-booking-item__top {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-start;
  gap: .75rem 1rem;
}

.dkb-booking-item__title {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.35;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .45rem;
}

.dkb-booking-item__amounts {
  text-align: right;
  font-size: .8125rem;
  line-height: 1.5;
  color: var(--dkb-ink-soft);
}

.dkb-booking-item__amounts strong {
  color: var(--dkb-ink);
  font-weight: 600;
}

.dkb-booking-item__body {
  display: grid;
  gap: .45rem;
  font-size: .875rem;
  line-height: 1.5;
  color: var(--dkb-ink-soft);
}

.dkb-booking-item__body strong {
  color: var(--dkb-ink);
  font-weight: 600;
}

.dkb-booking-item__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: .5rem;
  padding-top: .35rem;
}

.dkb-booking-group__foot {
  padding: 1rem 1.35rem 1.15rem;
  background: var(--dkb-surface-alt);
  border-top: 1px dashed var(--dkb-line);
  display: flex;
  justify-content: flex-end;
}

.dkb-booking-group__totals {
  text-align: right;
  font-size: .875rem;
  line-height: 1.55;
  display: grid;
  gap: .25rem;
}

.dkb-booking-group__totals strong { font-weight: 600; }

.dkb-booking-group__totals .dkb-totals__row--grand {
  margin-top: .35rem;
  padding-top: .5rem;
  border-top: 2px solid var(--dkb-ink);
  font-size: 1rem;
  font-weight: 700;
}

.dkb-btn--danger {
  color: var(--dkb-error);
  border-color: var(--dkb-error);
  background: transparent;
}

.dkb-btn--danger:hover {
  background: rgba(179, 38, 30, .08);
}

@media (min-width: 40em) {
  .dkb-portal__list { gap: 2rem; }
}

.dkb-portal-card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.35rem 1.5rem;
}

.dkb-portal-card__head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
}

.dkb-portal-card__title {
  margin: 0 0 .35rem;
  font-size: 1.0625rem;
  font-weight: 700;
}

.dkb-portal-meta-stack { display: grid; gap: .2rem; }

.dkb-portal-meta {
  margin: 0;
  font-size: .875rem;
  line-height: 1.45;
  color: var(--dkb-ink-soft);
}

.dkb-portal-card__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
}

.dkb-portal-card__amount { font-size: 1.125rem; font-weight: 700; }

.dkb-badge--warn {
  background: var(--dkb-sand-deep);
  color: var(--dkb-ink);
}

.dkb-portal-detail__head {
  display: grid;
  gap: 1rem;
  margin-bottom: 1.25rem;
}

@media (min-width: 48em) {
  .dkb-portal-detail__head {
    grid-template-columns: 1fr auto;
    align-items: start;
  }

  .dkb-portal-actions--head {
    grid-column: 1 / -1;
    justify-content: flex-start;
  }
}

.dkb-portal-detail__title {
  margin: 0 0 .35rem;
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: -.02em;
}

.dkb-portal-item {
  padding: 1.35rem 1.5rem;
  margin-bottom: 1rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.dkb-portal-item__head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
}

.dkb-portal-item__title {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.35;
}

.dkb-portal-item__subtitle {
  margin: 0;
  font-size: .8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--dkb-ink-soft);
}

.dkb-portal-dl {
  margin: 0;
  display: grid;
  gap: .65rem;
}
 
.dkb-portal-dl__row {
  display: grid;
  gap: .2rem;
}

@media (min-width: 36em) {
  .dkb-portal-dl__row {
    grid-template-columns: 7.5rem 1fr;
    gap: 1rem;
    align-items: baseline;
  }
}

.dkb-portal-dl dt {
  margin: 0;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--dkb-ink-soft);
}

.dkb-portal-dl dd {
  margin: 0;
  font-size: .9375rem;
  line-height: 1.45;
}

.dkb-extras--portal { margin-top: -.25rem; }

.dkb-portal-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .65rem;
  padding-top: .35rem;
  border-top: 1px solid var(--dkb-line);
}

.dkb-portal-pay {
  padding: 1.35rem 1.5rem;
  gap: 1rem;
}

.dkb-portal-pay__title {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 700;
}

.dkb-staff-tools {
  padding: 1.35rem 1.5rem;
  gap: 1rem;
  margin-top: 1rem;
}

.dkb-staff-tools__title {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 700;
}

.dkb-staff-tools__subtitle {
  margin: 0;
  font-size: .875rem;
  font-weight: 600;
}

.dkb-staff-tools__form {
  padding-top: .75rem;
  border-top: 1px solid var(--dkb-line);
}

.dkb-ledger {
  list-style: none;
  margin: 0;
  padding: 0;
}

.dkb-ledger__row {
  display: flex;
  justify-content: space-between;
  gap: .75rem;
  padding: .35rem 0;
  border-bottom: 1px solid var(--dkb-line);
  font-size: .875rem;
}

.dkb-staff-item-actions {
  flex-wrap: wrap;
  margin-top: .75rem;
  padding-top: .75rem;
  border-top: 1px dashed var(--dkb-line);
}

.dkb-staff-item-actions__units {
  min-width: 10rem;
  flex: 1 1 10rem;
}

.dkb-history__meta {
  font-size: .75rem;
  opacity: .85;
  max-width: 55%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dkb-personal-form__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
}

@media (max-width: 640px) {
  .dkb-personal-form__grid { grid-template-columns: 1fr; }

  .dkb-portal-item__head {
    flex-direction: column;
    align-items: stretch;
  }

  .dkb-portal-item__head .dkb-money {
    align-self: flex-start;
  }

  .dkb-portal-detail__head {
    gap: .75rem;
  }

  .dkb-portal-actions {
    flex-direction: column;
    align-items: stretch;
  }

  .dkb-portal-actions .dkb-btn {
    width: 100%;
    justify-content: center;
    min-height: 2.75rem;
  }

  .dkb-staff-item-actions {
    flex-direction: column;
    align-items: stretch;
  }

  .dkb-staff-item-actions .dkb-btn,
  .dkb-staff-item-actions .dkb-select {
    width: 100%;
    min-height: 2.75rem;
  }

  .dkb-staff-item-actions__units {
    min-width: 0;
  }

  .dkb-line__head {
    flex-direction: column;
    align-items: flex-start;
    gap: .5rem;
  }

  .dkb-result__foot {
    flex-direction: column;
    align-items: stretch;
    gap: .5rem;
  }

  .dkb-history__meta {
    max-width: 100%;
    white-space: normal;
  }

  dialog.dkb-dialog {
    width: calc(100vw - 1rem);
    max-height: min(90vh, 640px);
    overflow: auto;
  }

  .dkb-payment-block fieldset.dkb-stack .dkb-choice {
    min-height: 2.75rem;
  }

  /* An extra's name and its Days/Hours + Qty boxes no longer fit on one line at this width —
     give the boxes their own row instead of squeezing both onto the name's line. */
  .dkb-extra {
    flex-wrap: wrap;
  }

  .dkb-extra__inputs {
    flex-basis: 100%;
    padding-left: 1.9rem;
  }

  /* Cart line: .dkb-line__head stacks to one column just above, so the price column needs
     to span that column's full width for its own right-alignment to mean anything. */
  .dkb-line__price-col {
    align-self: stretch;
  }

  /* Booking-item amounts (Subtotal/Tourism tax/Total): wraps to its own row once it no longer
     fits beside the title, but a wrapped flex item is only as wide as its content by default —
     stretch it so its own text-align: right lands against the card's actual right edge. */
  .dkb-booking-item__amounts {
    flex-basis: 100%;
  }

  /* My Requests table: six columns don't fit a phone width, and the horizontal scrollbar
     needed to reach Actions is easy to miss entirely — a guest could scroll right past
     Status/Last updated without ever finding the View button. Drop those two least-needed
     columns instead, so Topic/Booking/Subject/Actions fit without scrolling at all. */
  .dkb-table th:nth-child(4),
  .dkb-table td:nth-child(4),
  .dkb-table th:nth-child(5),
  .dkb-table td:nth-child(5) {
    display: none;
  }

  /* Even with those two columns gone, the remaining cell padding and the View button's
     normal (comfortable, 44px-touch-target) size together still don't leave room for the
     button to land inside the viewport — tighten both, scoped to this table only. */
  .dkb-table th,
  .dkb-table td {
    padding: .5rem .4rem;
  }

  .dkb-table .dkb-btn {
    min-height: auto;
    padding: .35rem .6rem;
    font-size: .8125rem;
  }
}

.dkb-bank-instructions {
  margin: .35rem 0 0;
  white-space: pre-wrap;
  font-family: inherit;
  font-size: .875rem;
}

.dkb-portal__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
}

.dkb-portal-cancel {
  padding: 1rem 1.25rem;
  margin-top: .5rem;
}

.dkb-portal-cancel__summary {
  cursor: pointer;
  font-weight: 600;
  font-size: .9375rem;
  list-style: none;
}

.dkb-portal-cancel__summary::-webkit-details-marker { display: none; }

.dkb-portal-cancel .dkb-note { margin-top: .75rem; }

.dkb-portal-cancel .dkb-btn { margin-top: 1rem; }

/* Screen-reader-only, but still announced. Used for live regions. */
.dkb-sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Team calendar — half-bar occupancy grid (§3.5-TC) */
.dkb-cal__row {
  margin-bottom: 1.25rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--dkb-border, #e5e7eb);
}

.dkb-cal__unit {
  font-weight: 600;
  margin-bottom: .5rem;
}

.dkb-cal__track {
  display: flex;
  gap: 2px;
  overflow-x: auto;
  padding-bottom: .25rem;
}

.dkb-cal__cell {
  flex: 0 0 10px;
  height: 18px;
  background: var(--dkb-surface-muted, #f3f4f6);
  border-radius: 2px;
}

.dkb-cal__cell--full { background: var(--dkb-accent, #0ea5e9); }

.dkb-cal__cell--in {
  background: linear-gradient(90deg, transparent 50%, var(--dkb-accent, #0ea5e9) 50%);
}

.dkb-cal__cell--out {
  background: linear-gradient(90deg, var(--dkb-accent, #0ea5e9) 50%, transparent 50%);
}

.dkb-cal__cell--turn {
  background: linear-gradient(90deg, var(--dkb-accent, #0ea5e9) 50%, var(--dkb-accent-soft, #7dd3fc) 50%);
}

.dkb-cal__stays {
  margin: .5rem 0 0;
  padding: 0;
  list-style: none;
  font-size: .875rem;
}

.dkb-cal__stays li { margin-top: .25rem; }

/* Respect a guest who has asked the OS for less movement. */
@media (prefers-reduced-motion: reduce) {
  .dkb *,
  .dkb *::before,
  .dkb *::after,
  .dkb-modal *,
  .dkb-modal *::before,
  .dkb-modal *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}
.dkb.dkb-stack .dkb-slider .dkb-gallery {
    display: none;
}