/*
  Public marketing site — Delight Beauty Hub.
  Served straight from public/, no build step. Loaded only by the public
  layout, so nothing here reaches the admin panel or auth screens.

  Bootstrap 5 supplies the grid, buttons and offcanvas; this file carries the
  brand layer on top: the --dbh-* tokens, the display type scale, and the
  handful of components Bootstrap has no equivalent for.
*/

/* ── Tokens ─────────────────────────────────────────────────────────────
   Sampled from the shipped logo gradient. Mirrors the values in the
   approved design system so the site and the prototype cannot drift. */
:root {
    --dbh-brand-50: #f9ecff;
    --dbh-brand-100: #edc6ff;
    --dbh-brand-200: #dc8cff;
    --dbh-brand-300: #c440ff;
    --dbh-brand-400: #a800f2;
    --dbh-brand-500: #8000b8;
    --dbh-brand-600: #58007f;
    --dbh-brand-700: #4d0070;
    --dbh-brand-800: #42005f;
    --dbh-brand-900: #300046;

    /* Ink — near-black with a violet undertone. */
    --dbh-ink-100: #f0eff0;
    --dbh-ink-200: #dedddf;
    --dbh-ink-300: #c7c4ca;
    --dbh-ink-400: #a9a1b0;
    --dbh-ink-500: #8e7e9a;
    --dbh-ink-600: #755f87;
    --dbh-ink-700: #543d66;
    --dbh-ink-900: #1a1023;

    /* ink-500 is a 3.6:1 colour — fine for borders and icons, but below the
       4.5:1 floor as text. This is the same hue darkened just far enough to
       pass on paper, surface and white, and it is what every muted text
       style below uses. */
    --dbh-ink-muted: #766682;

    /* Surfaces — warm sand and paper carry the page. */
    --dbh-paper: #fbf9f6;
    --dbh-surface: #f3eee7;
    --dbh-line: #e2dacd;
    --dbh-line-soft: #efeae2;

    /* The one non-brand accent, used only for the "open today" indicator. */
    --dbh-success-600: #16a34a;

    /* Caution copy — the booking picker's "replaces X" note. Deliberately
       the darker amber rather than a mid tone: it runs as small text on
       warm paper, where a lighter amber drops under 4.5:1. */
    --dbh-warn-ink: #8a4b06;

    --dbh-font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    --dbh-font-display: 'Poppins', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

    /* The editorial voice. Playfair carries the headlines a beauty studio
       is judged on; Poppins stays for UI-scale headings, where a high-
       contrast serif turns fragile. Never set this below ~20px. */
    --dbh-font-serif: 'Playfair Display', 'Iowan Old Style', Georgia, 'Times New Roman', serif;

    /* Spacing — one scale, 8px-derived. */
    --dbh-space-2: 8px;
    --dbh-space-4: 16px;
    --dbh-space-6: 24px;
    --dbh-space-8: 32px;
    --dbh-space-12: 48px;
    --dbh-space-16: 64px;
    --dbh-space-24: 96px;

    --dbh-radius-sm: 8px;
    --dbh-radius-md: 12px;
    --dbh-radius-lg: 20px;
    --dbh-radius-full: 9999px;

    /* Shadows — always neutral ink, never brand-tinted. */
    --dbh-shadow-xs: 0 1px 2px rgba(26, 16, 35, 0.04);
    --dbh-shadow-sm: 0 1px 3px rgba(26, 16, 35, 0.06), 0 1px 2px rgba(26, 16, 35, 0.04);
    --dbh-shadow-md: 0 4px 12px rgba(26, 16, 35, 0.06), 0 2px 4px rgba(26, 16, 35, 0.04);
    --dbh-shadow-lg: 0 12px 32px rgba(26, 16, 35, 0.08), 0 4px 8px rgba(26, 16, 35, 0.04);
    --dbh-shadow-xl: 0 24px 48px rgba(26, 16, 35, 0.1), 0 8px 16px rgba(26, 16, 35, 0.06);

    --dbh-dur-sm: 160ms;
    --dbh-dur-md: 240ms;
    --dbh-dur-lg: 320ms;
    --dbh-ease-out: cubic-bezier(0.22, 1, 0.36, 1);

    /* Section rhythm — tightened on small screens, generous from md up. */
    --dbh-section-y: 64px;
}

@media (min-width: 768px) {
    :root {
        --dbh-section-y: 96px;
    }
}

/* Bootstrap overrides — brand the framework rather than fight it. */
.dbh-site {
    --bs-body-bg: var(--dbh-paper);
    --bs-body-color: var(--dbh-ink-900);
    --bs-body-font-family: var(--dbh-font-sans);
    --bs-body-font-size: 1rem;
    --bs-body-line-height: 1.6;
    --bs-link-color: var(--dbh-brand-600);
    --bs-link-hover-color: var(--dbh-brand-700);
    --bs-border-color: var(--dbh-line);
    --bs-emphasis-color: var(--dbh-ink-900);

    background: var(--dbh-paper);
    color: var(--dbh-ink-900);
    font-family: var(--dbh-font-sans);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    overflow-x: hidden;
}

/* The admin theme toggle writes data-bs-theme on <html>. The marketing site
   is light-only by design (warm paper is the brand), so it opts out rather
   than inheriting a dark palette it was never designed against. */
.dbh-site,
.dbh-site * {
    color-scheme: light;
}

/* ── Type scale ─────────────────────────────────────────────────────────
   Playfair at genuine display size, Poppins from h3 down. clamp() keeps
   the hero from overflowing narrow phones without a separate mobile rule
   for every heading.

   The serif runs at 400–500, not 700: Playfair's weight lives in its
   stroke contrast, and bolding it trades elegance for heft. Tracking sits
   near zero for the same reason — the negative tracking that flatters a
   geometric sans closes up a serif's counters. */
.dbh-display {
    font-family: var(--dbh-font-serif);
    font-weight: 400;
    font-size: clamp(2.5rem, 1.5rem + 4.4vw, 4.5rem); /* 40 → 72px */
    line-height: 1.04;
    letter-spacing: -0.015em;
}

.dbh-h2 {
    font-family: var(--dbh-font-serif);
    font-weight: 400;
    font-size: clamp(1.875rem, 1.4rem + 2vw, 2.75rem); /* 30 → 44px */
    line-height: 1.14;
    letter-spacing: -0.01em;
    /* Centred section titles otherwise strand a word on the last line. */
    text-wrap: balance;
}

.dbh-h3 {
    font-family: var(--dbh-font-display);
    font-weight: 600;
    font-size: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem); /* 20 → 24px */
    line-height: 1.25;
    letter-spacing: -0.01em;
}

.dbh-h4 {
    font-family: var(--dbh-font-sans);
    font-weight: 600;
    font-size: 1.125rem;
    line-height: 1.45;
}

.dbh-h5 {
    font-family: var(--dbh-font-sans);
    font-weight: 600;
    font-size: 1rem;
    line-height: 1.45;
}

.dbh-lead {
    font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem); /* 17 → 19px */
    line-height: 1.6;
    color: var(--dbh-ink-700);
}

.dbh-body {
    font-size: 1rem;
    line-height: 1.6;
    color: var(--dbh-ink-700);
}

.dbh-small {
    font-size: 0.875rem;
    line-height: 1.5;
}

/* Long-form admin-authored content (legal pages) rendered from Markdown —
   headings/lists/paragraphs need real spacing since the source has no
   hand-tuned margins of its own. */
.dbh-prose {
    color: var(--dbh-ink-700);
    font-size: 1rem;
    line-height: 1.7;
}

.dbh-prose h2 {
    font-family: var(--dbh-font-display);
    font-weight: 700;
    font-size: 1.5rem;
    line-height: 1.3;
    margin-top: 2rem;
    margin-bottom: 0.75rem;
}

.dbh-prose h3 {
    font-family: var(--dbh-font-display);
    font-weight: 600;
    font-size: 1.25rem;
    line-height: 1.35;
    margin-top: 1.75rem;
    margin-bottom: 0.5rem;
}

.dbh-prose p {
    margin-bottom: 1rem;
}

.dbh-prose ul,
.dbh-prose ol {
    margin-bottom: 1rem;
    padding-left: 1.25rem;
}

.dbh-prose li + li {
    margin-top: 0.35rem;
}

.dbh-prose > :first-child {
    margin-top: 0;
}

.dbh-overline {
    font-family: var(--dbh-font-sans);
    font-size: 0.6875rem;
    font-weight: 600;
    line-height: 1.45;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--dbh-brand-600);
}

/* Tight measure — 65–75 characters. Applied to prose, never to headings. */
.dbh-measure {
    max-width: 62ch;
}

.dbh-measure-tight {
    max-width: 48ch;
}

/* Muted text. Both names resolve to the contrast-safe value; -500 is kept
   because earlier markup uses it. */
.dbh-ink-500,
.dbh-ink-muted {
    color: var(--dbh-ink-muted);
}
.dbh-ink-600 {
    color: var(--dbh-ink-600);
}
.dbh-ink-700 {
    color: var(--dbh-ink-700);
}
.dbh-ink-900 {
    color: var(--dbh-ink-900);
}
.dbh-brand {
    color: var(--dbh-brand-600);
}

/* ── Layout ─────────────────────────────────────────────────────────── */
.dbh-section {
    padding-block: var(--dbh-section-y);
}

.dbh-section--surface {
    background: var(--dbh-surface);
}

/* For a section that continues the band above it rather than starting a
   new one — the two share a background, so only one gap belongs between. */
.dbh-section--continues {
    padding-top: 0;
}

.dbh-section--ink {
    background: var(--dbh-brand-900);
    color: var(--dbh-paper);
}

.dbh-container {
    width: 100%;
    max-width: 1200px;
    margin-inline: auto;
    padding-inline: 20px;
}

@media (min-width: 768px) {
    .dbh-container {
        padding-inline: 24px;
    }
}

/* Bootstrap's `g-5` sets a 3rem gutter, and a row offsets itself by half of
   that on each side. Inside a plain padded container the row therefore ends
   up wider than the viewport and the page scrolls sideways. Capping the
   horizontal gutter at the container's own padding keeps the row flush with
   the text above it; `g-5` still controls the vertical rhythm. */
.dbh-container .row {
    --bs-gutter-x: 2.5rem;
}

@media (max-width: 767.98px) {
    .dbh-container .row {
        --bs-gutter-x: 1.5rem;
    }
}

/* Section heading block — overline, title, optional lead. */
.dbh-section-head {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: var(--dbh-space-12);
}

/* ── Focus ──────────────────────────────────────────────────────────────
   One visible ring for everything interactive. Uses a double shadow so the
   ring stays legible on both paper and photography. */
.dbh-site :focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: 3px;
    border-radius: var(--dbh-radius-sm);
}

.dbh-section--ink :focus-visible,
.dbh-hero :focus-visible {
    outline-color: #fff;
}

/* ── Buttons ────────────────────────────────────────────────────────────
   44px minimum height on every variant — these are the tap targets that
   matter most on a phone. */
.dbh-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 48px;
    padding: 12px 26px;
    border: 1px solid transparent;
    border-radius: var(--dbh-radius-full);
    font-family: var(--dbh-font-sans);
    font-size: 1rem;
    font-weight: 500;
    line-height: 1.2;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition:
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        color var(--dbh-dur-sm) var(--dbh-ease-out),
        box-shadow var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-btn:hover {
    text-decoration: none;
}

/* No variant defined a disabled state, so a disabled button rendered at
   full opacity with a pointer cursor — identical to a live one. A
   visitor clicking what looks like a working "Pay deposit" button and
   getting nothing back reads as the page being broken, not as the form
   being incomplete. */
.dbh-btn:disabled,
.dbh-btn[aria-disabled='true'] {
    opacity: 0.5;
    box-shadow: none;
    cursor: not-allowed;
}

.dbh-btn:disabled:hover,
.dbh-btn[aria-disabled='true']:hover {
    background: var(--dbh-brand-600);
    box-shadow: none;
}

.dbh-btn--primary {
    background: var(--dbh-brand-600);
    color: #fff;
    box-shadow: var(--dbh-shadow-sm);
}

.dbh-btn--primary:hover {
    background: var(--dbh-brand-700);
    color: #fff;
    box-shadow: var(--dbh-shadow-md);
}

/* Outline on paper — the two secondary entry points. */
.dbh-btn--outline {
    background: transparent;
    border-color: var(--dbh-ink-300);
    color: var(--dbh-ink-900);
}

.dbh-btn--outline:hover {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-50);
    color: var(--dbh-brand-700);
}

/* Outline over photography — needs its own contrast treatment. */
.dbh-btn--on-photo {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.55);
    color: #fff;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}

.dbh-btn--on-photo:hover {
    background: rgba(255, 255, 255, 0.95);
    border-color: #fff;
    color: var(--dbh-ink-900);
}

.dbh-btn--light {
    background: var(--dbh-paper);
    color: var(--dbh-ink-900);
}

.dbh-btn--light:hover {
    background: #fff;
    color: var(--dbh-brand-700);
}

.dbh-btn--sm {
    min-height: 44px;
    padding: 10px 20px;
    font-size: 0.9375rem;
}

.dbh-btn--block {
    width: 100%;
}

/* Text link with a chevron — used for in-card secondary actions. Also used
   as a <button> (e.g. the scoped-booking "browse all services" toggle),
   so browser button chrome is stripped to keep it reading as a link. */
.dbh-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    font-weight: 500;
    color: var(--dbh-brand-600);
    text-decoration: none;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    font-size: inherit;
    font-family: inherit;
}

.dbh-link:hover {
    color: var(--dbh-brand-700);
    text-decoration: underline;
}

.dbh-link i {
    transition: transform var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-link:hover i {
    transform: translateX(3px);
}

/* ── Header ─────────────────────────────────────────────────────────── */
.dbh-header {
    position: sticky;
    top: 0;
    z-index: 1030;
    background: rgba(251, 249, 246, 0.85);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-bottom: 1px solid transparent;
    transition:
        border-color var(--dbh-dur-md) var(--dbh-ease-out),
        box-shadow var(--dbh-dur-md) var(--dbh-ease-out);
}

.dbh-header[data-scrolled='true'] {
    border-bottom-color: var(--dbh-line);
    box-shadow: var(--dbh-shadow-sm);
}

.dbh-header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--dbh-space-6);
    min-height: 72px;
}

.dbh-logo {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    text-decoration: none;
    color: var(--dbh-ink-900);
}

.dbh-logo:hover {
    color: var(--dbh-ink-900);
    text-decoration: none;
}

.dbh-logo img {
    width: 48px;
    height: 48px;
    border-radius: var(--dbh-radius-full);
}

.dbh-logo__text {
    display: none;
    font-family: var(--dbh-font-display);
    font-weight: 700;
    font-size: 1.0625rem;
    line-height: 1.15;
    letter-spacing: -0.01em;
}

@media (min-width: 400px) {
    .dbh-logo__text {
        display: block;
    }
}

.dbh-nav {
    display: none;
    align-items: center;
    gap: 4px;
}

.dbh-nav a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 14px;
    border-radius: var(--dbh-radius-sm);
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--dbh-ink-700);
    text-decoration: none;
    transition:
        color var(--dbh-dur-sm) var(--dbh-ease-out),
        background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-nav a:hover {
    color: var(--dbh-brand-600);
    background: var(--dbh-brand-50);
    text-decoration: none;
}

/* Current page. Weight and colour together, never colour alone. */
.dbh-nav a[aria-current='page'] {
    color: var(--dbh-brand-600);
    font-weight: 600;
}

@media (min-width: 992px) {
    .dbh-nav {
        display: flex;
    }
}

.dbh-header__cta {
    display: none;
}

@media (min-width: 768px) {
    .dbh-header__cta {
        display: inline-flex;
    }
}

/* Hamburger — hidden once the inline nav appears. */
.dbh-burger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-sm);
    background: transparent;
    color: var(--dbh-ink-900);
    font-size: 1.375rem;
    cursor: pointer;
    transition: background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-burger:hover {
    background: var(--dbh-surface);
}

@media (min-width: 992px) {
    .dbh-burger {
        display: none;
    }
}

/* ── Mobile drawer ──────────────────────────────────────────────────────
   The whole site on a phone, so it is built as a place rather than as a
   list: brand identity at the top, navigation with meaning-carrying icons,
   then the two things a salon visitor actually reaches for (where we are,
   and a way to ask). The actions stay pinned to the bottom edge.

   Previously .dbh-drawer__actions, __book and __contact carried no CSS at
   all, so the phone link rendered as a raw underlined browser anchor. */
.dbh-drawer {
    /* Set through Bootstrap's own variable, not the width property: its
       .offcanvas.offcanvas-end rule is two classes (0,2,0) against this
       one class (0,1,0), so a plain `width` here loses on specificity no
       matter where it sits in the file. That is why the previous
       min(88vw, 340px) never took effect and the panel always covered the
       whole screen.

       92vw leaves a visible strip of backdrop even at 320px, so the panel
       reads as an overlay rather than as a new page. */
    --bs-offcanvas-width: min(92vw, 366px);
    background: var(--dbh-paper);
    border-left: 1px solid var(--dbh-line);
}

.dbh-drawer__head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 14px 14px 18px;
    border-bottom: 1px solid var(--dbh-line-soft);
    background: var(--dbh-paper);
}

.dbh-drawer__brand {
    display: flex;
    align-items: center;
    gap: 11px;
    min-width: 0;
}

.dbh-drawer__mark {
    width: 40px;
    height: 40px;
    flex: none;
    border-radius: var(--dbh-radius-full);
    object-fit: contain;
}

.dbh-drawer__brandtext {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.dbh-drawer__brandname {
    font-family: var(--dbh-font-display);
    font-size: 0.9375rem;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.01em;
    color: var(--dbh-ink-900);
}

.dbh-drawer__brandmeta {
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0.02em;
    color: var(--dbh-ink-muted);
}

/* 44px, replacing Bootstrap's 16px .btn-close. */
.dbh-drawer__close {
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    flex: none;
    margin-left: auto;
    padding: 0;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-paper);
    color: var(--dbh-ink-700);
    font-size: 0.9375rem;
    cursor: pointer;
    transition:
        background-color 180ms var(--dbh-ease, cubic-bezier(0.16, 1, 0.3, 1)),
        color 180ms var(--dbh-ease, cubic-bezier(0.16, 1, 0.3, 1));
}

.dbh-drawer__close:hover {
    background: var(--dbh-surface);
    color: var(--dbh-ink-900);
}

.dbh-drawer__close:active {
    transform: scale(0.96);
}

.dbh-drawer__close:focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: 2px;
}

.dbh-drawer__body {
    display: flex;
    flex-direction: column;
    padding: 0;
    overscroll-behavior: contain;
}

/* NAVIGATION */
.dbh-drawer__nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 14px 12px 8px;
}

.dbh-drawer__nav a {
    position: relative;
    display: flex;
    align-items: center;
    gap: 13px;
    min-height: 56px;
    padding: 0 12px 0 10px;
    border-radius: var(--dbh-radius-md);
    font-family: var(--dbh-font-display);
    font-size: 1.0625rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--dbh-ink-900);
    text-decoration: none;
    transition:
        background-color 180ms cubic-bezier(0.16, 1, 0.3, 1),
        color 180ms cubic-bezier(0.16, 1, 0.3, 1);
}

.dbh-drawer__nav a:hover {
    background: var(--dbh-surface);
    color: var(--dbh-brand-600);
    text-decoration: none;
}

.dbh-drawer__nav a:active {
    background: var(--dbh-line-soft);
}

.dbh-drawer__nav a:focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: -2px;
}

/* The icon tile is what turns a wall of same-weight text into something
   scannable at a glance. */
.dbh-drawer__navicon {
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    flex: none;
    border-radius: var(--dbh-radius-sm);
    background: var(--dbh-surface);
    color: var(--dbh-brand-600);
    font-size: 1rem;
    transition:
        background-color 180ms cubic-bezier(0.16, 1, 0.3, 1),
        color 180ms cubic-bezier(0.16, 1, 0.3, 1);
}

.dbh-drawer__nav a:hover .dbh-drawer__navicon {
    background: var(--dbh-brand-50);
}

.dbh-drawer__navlabel {
    flex: 1 1 auto;
    min-width: 0;
}

/* Pushed to the right edge by the label's flex-grow. Previously the row had
   no justification at all, so the chevron sat against the label and the two
   read as one clump. */
.dbh-drawer__navgo {
    flex: none;
    font-size: 0.75rem;
    color: var(--dbh-ink-400);
}

.dbh-drawer__nav a[aria-current='page'] {
    background: var(--dbh-brand-50);
    color: var(--dbh-brand-700);
}

.dbh-drawer__nav a[aria-current='page'] .dbh-drawer__navicon {
    background: var(--dbh-brand-600);
    color: #fff;
}

.dbh-drawer__nav a[aria-current='page'] .dbh-drawer__navgo {
    color: var(--dbh-brand-400);
}

/* REACH BLOCK — address + WhatsApp. */
/* margin-top:auto lives here rather than on the actions so the leftover
   space falls BETWEEN the navigation and this block. That reads as two
   deliberate groups (browse / get in touch) instead of a hole punched in
   the middle of the panel. */
.dbh-drawer__reach {
    margin: auto 12px 0;
    padding: 14px;
    border: 1px solid var(--dbh-line-soft);
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-surface);
}

.dbh-drawer__addr {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin: 0;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--dbh-ink-700);
}

.dbh-drawer__addr i {
    flex: none;
    margin-top: 1px;
    color: var(--dbh-brand-600);
    font-size: 0.875rem;
}

.dbh-drawer__wa {
    display: flex;
    align-items: center;
    gap: 9px;
    min-height: 44px;
    margin-top: 8px;
    padding-top: 10px;
    border-top: 1px solid var(--dbh-line);
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--dbh-ink-900);
    text-decoration: none;
}

.dbh-drawer__wa > span {
    flex: 1 1 auto;
}

.dbh-drawer__wa i:first-child {
    flex: none;
    /* WhatsApp brand green, the same value the floating widget uses. */
    color: #25d366;
    font-size: 1.0625rem;
}

.dbh-drawer__wa:hover {
    color: var(--dbh-brand-600);
    text-decoration: none;
}

.dbh-drawer__wa:focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: 3px;
    border-radius: var(--dbh-radius-sm);
}

/* ACTIONS — pinned to the bottom edge. mt-auto is carried here rather than
   in the markup so the spacing rule lives with the rest of the drawer. */
/* Sticky, not just last-in-flow: on a 568px phone the nav plus the contact
   block genuinely overflow, and without this the booking CTA sits below the
   fold inside a scrolling panel. Pinned to the bottom edge it stays reachable
   while the navigation scrolls behind it. The solid paper background and the
   safe-area padding are what make that legible over scrolling content and
   clear of the iOS home indicator. */
.dbh-drawer__actions {
    position: sticky;
    bottom: 0;
    z-index: 1;
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 14px;
    padding: 14px 16px calc(16px + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid var(--dbh-line-soft);
    background: var(--dbh-paper);
}

.dbh-drawer__book {
    min-height: 52px;
}

.dbh-drawer__contact {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 44px;
    border-radius: var(--dbh-radius-md);
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--dbh-ink-700);
    text-decoration: none;
    transition: color 180ms cubic-bezier(0.16, 1, 0.3, 1);
}

.dbh-drawer__contact i {
    font-size: 0.8125rem;
    color: var(--dbh-brand-600);
}

.dbh-drawer__contact:hover {
    color: var(--dbh-brand-600);
    text-decoration: none;
}

.dbh-drawer__contact:focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: -2px;
}

/* Entrance stagger. Pure CSS off Bootstrap's own .show class — no JS, no
   scroll listeners. It exists to give the rows a sense of arriving in
   order rather than snapping in as one block. */
@media (prefers-reduced-motion: no-preference) {
    .dbh-drawer.show .dbh-drawer__nav a,
    .dbh-drawer.show .dbh-drawer__reach {
        animation: dbh-drawer-in 320ms cubic-bezier(0.16, 1, 0.3, 1) backwards;
        animation-delay: calc(60ms + (var(--row, 5) * 32ms));
    }
}

@keyframes dbh-drawer-in {
    from {
        opacity: 0;
        transform: translateX(10px);
    }
}

/* ── Hero ───────────────────────────────────────────────────────────────
   Photography is the design: a full-bleed image with the copy laid over a
   gradient scrim. The scrim is what guarantees the 4.5:1 text contrast,
   so it is not optional decoration. */
.dbh-hero {
    position: relative;
    isolation: isolate;
    background: var(--dbh-ink-900);
    color: #fff;
}

.dbh-hero__media {
    position: absolute;
    inset: 0;
    z-index: -2;
    overflow: hidden;
}

.dbh-hero__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 28%;
}

/* Portrait: the copy occupies most of the lower two-thirds, so the scrim
   stays heavy across all of it and only lifts near the top. Measured
   rather than guessed — at the previous mid-stops the lead paragraph sat
   on roughly 4.6:1, which is under the floor for 17px text and worse
   again over the bright slats in the photograph. */
.dbh-hero__scrim {
    position: absolute;
    inset: 0;
    z-index: -1;
    background:
        linear-gradient(to top, rgba(26, 16, 35, 0.95) 0%, rgba(26, 16, 35, 0.9) 38%, rgba(26, 16, 35, 0.78) 62%, rgba(26, 16, 35, 0.5) 85%, rgba(26, 16, 35, 0.4) 100%);
}

@media (min-width: 768px) {
    /* Desktop: the subject sits right of centre, so the scrim leans left
       to keep the photograph readable behind the copy column. */
    .dbh-hero__scrim {
        background:
            linear-gradient(to right, rgba(26, 16, 35, 0.92) 0%, rgba(26, 16, 35, 0.78) 38%, rgba(26, 16, 35, 0.34) 66%, rgba(26, 16, 35, 0.22) 100%);
    }

    .dbh-hero__media img {
        object-position: 62% 26%;
    }
}

.dbh-hero__inner {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    min-height: 88svh;
    padding-block: 120px 56px;
}

@media (min-width: 768px) {
    .dbh-hero__inner {
        justify-content: center;
        min-height: 92svh;
        padding-block: 140px 100px;
    }
}

.dbh-hero__copy {
    max-width: 640px;
}

/* The service list is the page's h1: it names what the studio does, in the
   words a client would search for. Set small and tracked-out rather than at
   display size — heading rank is semantic, and the visual lead belongs to
   the headline beneath it. */
.dbh-hero__eyebrow {
    margin: 12px 0 14px;
    color: var(--dbh-brand-200);
    font-family: var(--dbh-font-display), system-ui, sans-serif;
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.4;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    text-wrap: pretty;
}

/* Carries the display type the h1 used to, without the heading rank. */
.dbh-hero__headline {
    color: #fff;
    margin: 0;
    text-wrap: balance;
}

.dbh-hero__sub {
    margin: 20px 0 0;
    color: rgba(255, 255, 255, 0.9);
    max-width: 52ch;
}

/* The invitation that hands off to the CTAs below it — set apart from the
   descriptive sub-line by weight rather than size, so it reads as a prompt
   without competing with the h1. */
.dbh-hero__cta-line {
    margin: 16px 0 0;
    color: #fff;
    font-family: var(--dbh-font-display), system-ui, sans-serif;
    font-weight: 600;
    font-size: 1.0625rem;
    line-height: 1.5;
    max-width: 46ch;
}

.dbh-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 32px;
}

@media (max-width: 419px) {
    /* Full-width stacked CTAs below 420px — side-by-side pills wrap badly
       and the primary action loses its rank. */
    .dbh-hero__actions .dbh-btn {
        width: 100%;
    }
}

/* Trust line — real, verifiable facts only. */
.dbh-trust {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 20px;
    margin-top: 32px;
    padding-top: 24px;
    border-top: 1px solid rgba(255, 255, 255, 0.2);
}

.dbh-trust__item {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 0.9375rem;
    color: rgba(255, 255, 255, 0.92);
}

.dbh-trust__item i {
    color: var(--dbh-brand-200);
    font-size: 1rem;
}

/* Small brand chip. */
.dbh-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-brand-50);
    color: var(--dbh-brand-700);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.dbh-badge--solid {
    background: var(--dbh-brand-600);
    color: #fff;
}

.dbh-badge--warn {
    background: #fef3c7;
    color: #92400e;
}

.dbh-badge--ghost {
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
}

/* ── Gallery band ───────────────────────────────────────────────────── */
.dbh-gallery {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
}

@media (min-width: 768px) {
    .dbh-gallery {
        grid-template-columns: repeat(4, 1fr);
        gap: 16px;
    }
}

.dbh-gallery figure {
    position: relative;
    margin: 0;
    border-radius: var(--dbh-radius-md);
    overflow: hidden;
    background: var(--dbh-ink-100);
    aspect-ratio: 4 / 3;
}

.dbh-gallery img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--dbh-dur-lg) var(--dbh-ease-out);
}

.dbh-gallery figure:hover img {
    transform: scale(1.05);
}

.dbh-gallery figcaption {
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    padding: 28px 12px 10px;
    background: linear-gradient(to top, rgba(26, 16, 35, 0.85), transparent);
    color: #fff;
    font-size: 0.8125rem;
    font-weight: 500;
}

/* ── Training ───────────────────────────────────────────────────────────
   Deliberately distinct from the services section: dark brand ground,
   so it reads as a different offering rather than more services. */
.dbh-course {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 28px;
    border-radius: var(--dbh-radius-lg);
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.14);
    transition:
        background-color var(--dbh-dur-md) var(--dbh-ease-out),
        border-color var(--dbh-dur-md) var(--dbh-ease-out);
}

.dbh-course:hover {
    background: rgba(255, 255, 255, 0.1);
    border-color: rgba(255, 255, 255, 0.28);
}

.dbh-course__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 16px;
}

.dbh-course h3 {
    color: #fff;
    margin: 0 0 12px;
}

.dbh-course p {
    color: rgba(255, 255, 255, 0.78);
    font-size: 0.9375rem;
    margin: 0 0 24px;
}

.dbh-course__facts {
    list-style: none;
    margin: 0 0 24px;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
    flex: 1 1 auto;
}

.dbh-course__facts li {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 0.9375rem;
    color: rgba(255, 255, 255, 0.9);
}

.dbh-course__facts i {
    color: var(--dbh-brand-200);
    flex-shrink: 0;
}

.dbh-course__price {
    font-family: var(--dbh-font-display);
    font-size: 1.75rem;
    font-weight: 700;
    color: #fff;
    letter-spacing: -0.01em;
}


.dbh-includes {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 12px;
}

@media (min-width: 576px) {
    .dbh-includes {
        grid-template-columns: repeat(2, 1fr);
    }
}

.dbh-includes li {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 0.9375rem;
    color: var(--dbh-ink-700);
}

.dbh-includes i {
    color: var(--dbh-brand-600);
    margin-top: 2px;
    flex-shrink: 0;
}

/* ── Hours & contact ────────────────────────────────────────────────── */
.dbh-hours {
    list-style: none;
    margin: 0;
    padding: 0;
}

.dbh-hours li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 11px 0;
    border-bottom: 1px solid var(--dbh-line-soft);
    font-size: 0.9375rem;
}

.dbh-hours li:last-child {
    border-bottom: 0;
}

.dbh-hours__day {
    color: var(--dbh-ink-700);
}

.dbh-hours li[data-today='true'] .dbh-hours__day,
.dbh-hours li[data-today='true'] .dbh-hours__time {
    font-weight: 600;
    color: var(--dbh-brand-600);
}

.dbh-hours__time {
    color: var(--dbh-ink-900);
    font-variant-numeric: tabular-nums;
}

.dbh-hours__time--closed {
    color: var(--dbh-ink-muted);
}

.dbh-contact-row {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 16px 0;
    border-bottom: 1px solid var(--dbh-line-soft);
    text-decoration: none;
    color: inherit;
}

.dbh-contact-row:last-of-type {
    border-bottom: 0;
}

a.dbh-contact-row {
    min-height: 44px;
}

a.dbh-contact-row:hover {
    color: inherit;
    text-decoration: none;
}

a.dbh-contact-row:hover .dbh-contact-row__value {
    color: var(--dbh-brand-600);
    text-decoration: underline;
}

.dbh-contact-row__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-brand-50);
    color: var(--dbh-brand-600);
    font-size: 1.125rem;
}

.dbh-contact-row__label {
    display: block;
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

.dbh-contact-row__value {
    display: block;
    font-weight: 500;
    color: var(--dbh-ink-900);
}

/* ── Visit page ─────────────────────────────────────────────────────── */

/* Page header band. Deliberately shorter than the home hero: a visitor on
   this page is usually mid-journey and needs the call button in reach, not
   a full-height image. */
.dbh-pagehead {
    background: linear-gradient(180deg, var(--dbh-surface) 0%, var(--dbh-paper) 100%);
    padding-block: 32px var(--dbh-section-y);
    border-bottom: 1px solid var(--dbh-line-soft);
}

.dbh-pagehead__title {
    margin: 0;
    text-wrap: balance;
}

.dbh-pagehead__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 32px;
}

@media (max-width: 419px) {
    .dbh-pagehead__actions .dbh-btn {
        width: 100%;
    }
}

/* Breadcrumb. Only two levels deep, so it exists to give a way back up
   rather than to map a hierarchy. */
.dbh-crumbs ol {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    /* The link inside is 44px tall for tap purposes, so the visual gap
       below is trimmed to keep the header band's rhythm. */
    margin: 0 0 8px;
    padding: 0;
    list-style: none;
    font-size: 0.875rem;
}

.dbh-crumbs li + li::before {
    content: '/';
    margin-right: 8px;
    color: var(--dbh-ink-400);
}

/* The breadcrumb link is a standalone navigation target rather than a link
   inside a sentence, so it gets a real tap height. */
.dbh-crumbs a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    color: var(--dbh-ink-muted);
    text-decoration: none;
}

.dbh-crumbs a:hover {
    color: var(--dbh-brand-600);
    text-decoration: underline;
}

.dbh-crumbs [aria-current='page'] {
    color: var(--dbh-ink-900);
    font-weight: 500;
}

/* Open / closed today. The dot is decorative — the words carry the meaning,
   so the state is never colour-only. */
.dbh-openstate {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 10px 16px;
    border-radius: var(--dbh-radius-full);
    background: #fff;
    border: 1px solid var(--dbh-line);
    font-size: 0.9375rem;
    color: var(--dbh-ink-700);
}

.dbh-openstate strong {
    color: var(--dbh-ink-900);
}

.dbh-openstate__dot {
    width: 9px;
    height: 9px;
    flex-shrink: 0;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-ink-400);
}

.dbh-openstate__dot--open {
    background: var(--dbh-success-600, #16a34a);
}

/* A tighter section, for the closure notice that sits between bands. */
.dbh-section--tight {
    padding-block: 0;
    margin-top: calc(var(--dbh-section-y) * -0.35);
}

.dbh-notice {
    display: flex;
    gap: 16px;
    padding: 20px 24px;
    border-radius: var(--dbh-radius-lg);
    background: #fef3c7;
    border: 1px solid #fcd34d;
    color: #78350f;
}

.dbh-notice__icon {
    flex-shrink: 0;
    font-size: 1.25rem;
    color: #b45309;
    line-height: 1.2;
}

.dbh-notice h2 {
    color: #78350f;
}

.dbh-notice__list {
    margin: 8px 0 0;
    padding-left: 18px;
    font-size: 0.9375rem;
}

.dbh-notice__list li + li {
    margin-top: 4px;
}

/* Address block — <address> resets to italic in most UAs. */
.dbh-address {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-style: normal;
    font-size: 1.125rem;
    line-height: 1.6;
    color: var(--dbh-ink-900);
}

.dbh-contact-list--boxed {
    padding: 8px 20px;
    background: #fff;
    border: 1px solid var(--dbh-line-soft);
    border-radius: var(--dbh-radius-lg);
}

/* Embedded map, only rendered once there is a real place to point at. */
/* The map is a wayfinding aid, not the subject of the page, so its height
   is capped rather than left to follow the container width. At 4/3 across
   a full-width column it rendered around 960px tall on a laptop — a whole
   screen of map that pushed the address and opening hours below the fold.

   The ratio widens as the viewport does (a wide strip reads as "here is
   the street", a squarer frame suits a phone), and max-height stops it
   growing without bound on a large monitor. */
.dbh-map {
    position: relative;
    /* Slightly taller than wide on a phone — enough map to place the
       street without filling the whole screen. 4/5 keeps it under half
       the viewport on a small handset. */
    aspect-ratio: 4 / 5;
    max-height: 56vh;
    border-radius: var(--dbh-radius-lg);
    overflow: hidden;
    background: var(--dbh-ink-100);
    border: 1px solid var(--dbh-line);
}

@media (min-width: 576px) {
    .dbh-map {
        aspect-ratio: 4 / 3;
        max-height: 60vh;
    }
}

@media (min-width: 992px) {
    .dbh-map {
        aspect-ratio: 21 / 9;
        max-height: 520px;
    }
}

/* Sits under the map: what the embed can do, and the way out to a real
   routing app. Stacks on a phone so the button keeps its full tap width. */
.dbh-map__aside {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 12px 0 0;
    font-size: 0.9375rem;
    color: var(--dbh-ink-700);
}

.dbh-map__aside > span {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.dbh-map__aside i {
    color: var(--dbh-brand-600);
    flex: 0 0 auto;
}

@media (max-width: 575.98px) {
    .dbh-map__aside .dbh-btn {
        width: 100%;
        justify-content: center;
    }
}

.dbh-map iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

/* Shopfront photo, shown in place of the map while the address is
   unconfirmed — recognising the building is the next best thing to a pin. */
.dbh-shopfront {
    margin: 0;
}

.dbh-shopfront img {
    width: 100%;
    height: auto;
    display: block;
    border-radius: var(--dbh-radius-lg);
}

.dbh-shopfront figcaption {
    margin-top: 12px;
    font-size: 0.875rem;
    color: var(--dbh-ink-muted);
}

/* Hours, boxed on the Visit page where the table is the main content. */
.dbh-hours-card {
    padding: 8px 24px;
    background: #fff;
    border: 1px solid var(--dbh-line-soft);
    border-radius: var(--dbh-radius-lg);
}

/* Getting-here notes. */
.dbh-arrival {
    display: flex;
    gap: 16px;
    height: 100%;
    padding: 24px;
    background: var(--dbh-surface);
    border: 1px solid var(--dbh-line-soft);
    border-radius: var(--dbh-radius-lg);
}

.dbh-arrival__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-brand-50);
    color: var(--dbh-brand-600);
    font-size: 1.25rem;
}

/* First-visit steps — numbered via a counter so the markup stays an <ol>. */
.dbh-steps {
    counter-reset: dbh-step;
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 28px;
}

.dbh-steps li {
    counter-increment: dbh-step;
    position: relative;
    padding-left: 56px;
}

.dbh-steps li::before {
    content: counter(dbh-step);
    position: absolute;
    left: 0;
    top: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--dbh-radius-full);
    background: rgba(255, 255, 255, 0.12);
    border: 1px solid rgba(255, 255, 255, 0.24);
    color: #fff;
    font-family: var(--dbh-font-display);
    font-weight: 600;
    font-size: 0.9375rem;
}

.dbh-steps h3 {
    color: #fff;
    margin: 8px 0 0;
}

.dbh-steps p {
    margin: 8px 0 0;
    font-size: 0.9375rem;
    color: rgba(255, 255, 255, 0.78);
    max-width: 60ch;
}

/* Routing cards back to the three booking entry points. */
.dbh-routecard {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 24px;
    background: #fff;
    border: 1px solid var(--dbh-line-soft);
    border-radius: var(--dbh-radius-lg);
    text-decoration: none;
    color: inherit;
    transition:
        box-shadow var(--dbh-dur-md) var(--dbh-ease-out),
        border-color var(--dbh-dur-md) var(--dbh-ease-out);
}

.dbh-routecard:hover {
    border-color: var(--dbh-brand-200);
    box-shadow: var(--dbh-shadow-md);
    color: inherit;
    text-decoration: none;
}

.dbh-routecard__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    margin-bottom: 16px;
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-brand-50);
    color: var(--dbh-brand-600);
    font-size: 1.25rem;
}

.dbh-routecard__title {
    font-family: var(--dbh-font-display);
    font-weight: 600;
    font-size: 1.0625rem;
    color: var(--dbh-ink-900);
}

.dbh-routecard__body {
    margin-top: 6px;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--dbh-ink-600);
}

.dbh-routecard__more {
    margin-top: 16px;
    color: var(--dbh-brand-600);
    transition: transform var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-routecard:hover .dbh-routecard__more {
    transform: translateX(4px);
}

/* ── About page ─────────────────────────────────────────────────────────
   The site's most text-heavy page, and the one with the least data behind
   it: no collected reviews, no accreditations entered yet, no staff
   headshots. So the design earns trust with the things that are real —
   the studio's own words, the live treatment counts, and photographs of
   the actual premises — and gives them a hierarchy that can be scanned.

   Deliberately typographic where the services page is photographic. Both
   pages share the type, colour and spacing scale; neither is a copy of
   the other. */

/* Running prose. The measure is enforced here rather than left to each
   block, because this is where long copy actually lands. */
.dbh-prose p {
    max-width: 68ch;
    margin: 0 0 16px;
    font-size: 1.0625rem;
    line-height: 1.7;
    color: var(--dbh-ink-700);
}

.dbh-prose p:last-child {
    margin-bottom: 0;
}

.dbh-prose--invert p {
    color: rgba(255, 255, 255, 0.82);
}

/* A promoted opening paragraph. Nothing is rewritten to produce these —
   the business's first sentence is simply set larger, so a block of copy
   opens with something readable at a glance instead of a wall. */
.dbh-statement {
    max-width: 34ch;
    margin: 20px 0 0;
    font-family: var(--dbh-font-serif);
    font-weight: 400;
    font-size: clamp(1.1875rem, 1rem + 0.9vw, 1.5rem);
    line-height: 1.45;
    letter-spacing: -0.005em;
    color: var(--dbh-ink-900);
    text-wrap: pretty;
}

.dbh-statement--invert {
    /* Wider than the light variant: this one sits in a full-bleed band
       with no image beside it, and at 34ch it broke into six short lines
       against a screen of empty ground. */
    max-width: 44ch;
    color: #fff;
}

/* ── Hero ───────────────────────────────────────────────────────────────
   Split, with the studio itself alongside. A landscape crop rather than
   the services hero's portrait, so the two pages open differently. */
.dbh-abouthero {
    padding-block: 28px 40px;
    background: var(--dbh-paper);
    border-bottom: 1px solid var(--dbh-line-soft);
}

@media (min-width: 768px) {
    .dbh-abouthero {
        padding-block: 32px 64px;
    }
}

.dbh-abouthero__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 28px;
    align-items: center;
    margin-top: 20px;
}

@media (min-width: 992px) {
    .dbh-abouthero__grid {
        grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr);
        gap: 56px;
    }
}

.dbh-abouthero__body {
    min-width: 0;
}

.dbh-abouthero__title {
    margin: 10px 0 0;
    max-width: 16ch;
}

.dbh-abouthero__lead {
    max-width: 46ch;
    margin: 18px 0 0;
}

.dbh-abouthero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 28px;
}

@media (max-width: 400px) {
    .dbh-abouthero__actions {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
    }
}

/* 3:2, matching the source, so the room is shown whole. A 4:3 box cropped
   the mirror and the feature wall out of frame — the two things that make
   it read as a studio rather than any room. */
.dbh-abouthero__media {
    position: relative;
    margin: 0;
    overflow: hidden;
    border-radius: var(--dbh-radius-lg);
    background: var(--dbh-ink-100);
    aspect-ratio: 3 / 2;
}

.dbh-abouthero__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ── Story ──────────────────────────────────────────────────────────────
   Image first in the source and on the left from lg, so the band reads in
   the opposite direction to the hero above it and the page does not
   settle into a single repeated shape. */
.dbh-storyblock {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 28px;
    align-items: center;
}

@media (min-width: 992px) {
    .dbh-storyblock {
        grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr);
        gap: 64px;
    }
}

.dbh-storyblock__media {
    position: relative;
    margin: 0;
    overflow: hidden;
    border-radius: var(--dbh-radius-lg);
    background: var(--dbh-ink-100);
    aspect-ratio: 4 / 3;
}

@media (min-width: 992px) {
    .dbh-storyblock__media {
        aspect-ratio: 4 / 5;
    }
}

.dbh-storyblock__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.dbh-storyblock__body {
    min-width: 0;
}

.dbh-storyblock__title {
    margin: 10px 0 0;
    max-width: 18ch;
}

.dbh-storyblock__prose {
    margin-top: 20px;
}

.dbh-storyblock__sign {
    margin: 24px 0 0;
    padding-top: 20px;
    border-top: 1px solid var(--dbh-line);
    font-family: var(--dbh-font-display);
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--dbh-ink-900);
}

/* ── Mission ────────────────────────────────────────────────────────────
   Label above the statement on a phone, beside it from lg — an asymmetric
   band on the brand ground, so it reads as a declaration rather than as
   more body copy. */
.dbh-missionblock {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}

@media (min-width: 992px) {
    .dbh-missionblock {
        grid-template-columns: 200px minmax(0, 1fr);
        gap: 56px;
    }
}

.dbh-missionblock__label {
    color: var(--dbh-brand-200);
}

.dbh-missionblock__body {
    min-width: 0;
}

.dbh-missionblock__body .dbh-statement {
    margin-top: 0;
}

/* ── Specialisms ────────────────────────────────────────────────────────
   A numbered index rather than cards. The services page already answers
   "what can I book and for how much" with photographs and prices; this
   answers "do they actually know how to do it", which is a reading task,
   not a browsing one. */
.dbh-crafts {
    margin: 0;
    padding: 0;
    list-style: none;
    border-top: 1px solid var(--dbh-line);
}

.dbh-craft {
    display: grid;
    grid-template-columns: 44px minmax(0, 1fr);
    gap: 4px 16px;
    padding: 24px 0;
    border-bottom: 1px solid var(--dbh-line);
}

/* From lg the numeral, the name and the prose become three columns, so
   the approach text sits on its own measure instead of running the full
   width of a desktop container. */
@media (min-width: 992px) {
    .dbh-craft {
        grid-template-columns: 56px 240px minmax(0, 1fr);
        gap: 8px 40px;
        padding: 32px 0;
    }
}

/* brand-500, not the lighter brand-300 it started as: against the surface
   band that measured 3.29:1, and although the numerals are aria-hidden
   they are still text a sighted reader is meant to read. */
.dbh-craft__index {
    grid-row: span 2;
    font-family: var(--dbh-font-serif);
    font-size: 1.25rem;
    line-height: 1.2;
    color: var(--dbh-brand-500);
}

@media (min-width: 992px) {
    .dbh-craft__index {
        grid-row: auto;
        font-size: 1.5rem;
    }
}

.dbh-craft__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 12px;
}

.dbh-craft__name {
    margin: 0;
    font-family: var(--dbh-font-display);
    font-size: 1.125rem;
    font-weight: 600;
    line-height: 1.25;
    color: var(--dbh-ink-900);
}

@media (min-width: 992px) {
    .dbh-craft__head {
        display: block;
    }

    .dbh-craft__name {
        font-size: 1.25rem;
    }
}

.dbh-craft__count {
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

@media (min-width: 992px) {
    .dbh-craft__count {
        display: block;
        margin-top: 4px;
    }
}

.dbh-craft__body {
    grid-column: 2;
    min-width: 0;
}

@media (min-width: 992px) {
    .dbh-craft__body {
        grid-column: 3;
    }
}

.dbh-craft__approach {
    max-width: 62ch;
    margin: 0 0 10px;
    font-size: 0.9375rem;
    line-height: 1.65;
    color: var(--dbh-ink-700);
}

@media (min-width: 768px) {
    .dbh-craft__approach {
        font-size: 1rem;
    }
}

/* ── Inside the studio ──────────────────────────────────────────────────
   A swipeable rail on a phone and a three-up grid from md, matching the
   home page's featured-work band so the two read as one site. */
.dbh-rooms {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 78%;
    gap: 12px;
    margin: 0;
    padding: 0 20px 4px;
    list-style: none;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    /* Keeps a flick at the end of the rail from scrolling the page. */
    overscroll-behavior-x: contain;
    scrollbar-width: none;
}

.dbh-rooms::-webkit-scrollbar {
    display: none;
}

/* Edge-to-edge on a phone so a tile can bleed off-screen and read as
   continuing rather than stopping inside the container's gutter. */
@media (max-width: 767.98px) {
    .dbh-rooms {
        margin-inline: calc(50% - 50vw);
    }
}

@media (min-width: 768px) {
    .dbh-rooms {
        grid-auto-flow: row;
        /* minmax(0, 1fr), not a bare 1fr, which would floor each track at
           the 960px image's min-content width and blow the grid out. */
        grid-template-columns: repeat(3, minmax(0, 1fr));
        grid-auto-columns: auto;
        gap: 16px;
        padding: 0;
        overflow: visible;
    }
}

.dbh-room {
    position: relative;
    margin: 0;
    height: 100%;
    overflow: hidden;
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-ink-100);
    aspect-ratio: 4 / 3;
    scroll-snap-align: center;
}

.dbh-room img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--dbh-dur-lg) var(--dbh-ease-out);
}

@media (hover: hover) {
    .dbh-room:hover img {
        transform: scale(1.04);
    }
}

.dbh-room figcaption {
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    padding: 32px 14px 12px;
    background: linear-gradient(to top, rgba(26, 16, 35, 0.86), transparent);
    color: #fff;
    font-size: 0.8125rem;
    font-weight: 500;
    letter-spacing: 0.01em;
}

/* ── Team ───────────────────────────────────────────────────────────── */
.dbh-person {
    height: 100%;
    padding: 24px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-lg);
    background: var(--dbh-paper);
}

.dbh-person__photo {
    width: 84px;
    height: 84px;
    border-radius: var(--dbh-radius-full);
    object-fit: cover;
    background: var(--dbh-ink-100);
}

.dbh-person__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 14px 0 0;
    padding: 0;
    list-style: none;
}

/* ── Training and rental ────────────────────────────────────────────────
   Two claims of standing beside the sentence that frames them. */
.dbh-standingblock {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 28px;
}

@media (min-width: 992px) {
    .dbh-standingblock {
        grid-template-columns: minmax(0, 0.8fr) minmax(0, 1fr);
        gap: 56px;
        align-items: start;
    }
}

.dbh-standingblock__title {
    margin: 10px 0 0;
    max-width: 14ch;
}

.dbh-standingblock__cards {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}

@media (min-width: 576px) {
    .dbh-standingblock__cards {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.dbh-standing {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 24px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-lg);
    background: var(--dbh-paper);
}

.dbh-standing__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-brand-50);
    color: var(--dbh-brand-600);
    font-size: 1.125rem;
}

.dbh-standing p {
    margin: 0 0 16px;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: var(--dbh-ink-700);
}

/* ── Accreditations ─────────────────────────────────────────────────── */
.dbh-credential {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    height: 100%;
    padding: 20px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-lg);
    background: var(--dbh-paper);
}

.dbh-credential > i {
    flex: none;
    margin-top: 2px;
    color: var(--dbh-success-600);
    font-size: 1.25rem;
}

/* ── Closing CTA ────────────────────────────────────────────────────────
   On the brand ground rather than as a white card: this is the page's
   last word and the only band allowed to raise its voice. */
.dbh-closer {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

.dbh-closer__title {
    margin: 0;
    color: #fff;
}

.dbh-closer__lead {
    margin: 16px 0 0;
    color: rgba(255, 255, 255, 0.82);
}

.dbh-closer__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
    margin-top: 32px;
}

@media (max-width: 419px) {
    .dbh-closer__actions .dbh-btn {
        width: 100%;
    }
}

.dbh-closer__note {
    margin: 28px 0 0;
    font-size: 0.875rem;
    color: rgba(255, 255, 255, 0.72);
}

.dbh-closer__note a {
    color: #fff;
    font-weight: 500;
    text-underline-offset: 3px;
}

/* ── Training flow ──────────────────────────────────────────────────── */

.dbh-pagehead--tight {
    padding-bottom: var(--dbh-space-8);
}

/* Inner-page titles, matching the homepage's editorial voice so the site
   reads as one brand rather than a landing page bolted to an app. */
.dbh-h1 {
    font-family: var(--dbh-font-serif);
    font-weight: 400;
    font-size: clamp(2.125rem, 1.55rem + 2.5vw, 3.25rem);
    line-height: 1.1;
    letter-spacing: -0.012em;
    margin: 0;
}

/* Course card. */
.dbh-coursecard {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 24px;
    background: #fff;
    border: 1px solid var(--dbh-line-soft);
    border-radius: var(--dbh-radius-lg);
    transition:
        box-shadow var(--dbh-dur-md) var(--dbh-ease-out),
        border-color var(--dbh-dur-md) var(--dbh-ease-out);
}

.dbh-coursecard:hover {
    border-color: var(--dbh-brand-200);
    box-shadow: var(--dbh-shadow-lg);
}

/* A full course stays legible but visibly stands down. */
.dbh-coursecard.is-full {
    background: var(--dbh-surface);
}

.dbh-coursecard.is-full:hover {
    border-color: var(--dbh-line-soft);
    box-shadow: none;
}

.dbh-coursecard__top {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* Stretched link — the whole card is clickable, but the accessible name
   still comes from the heading text rather than a wrapping anchor. */
.dbh-coursecard__link {
    color: var(--dbh-ink-900);
    text-decoration: none;
}

.dbh-coursecard__link::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
}

.dbh-coursecard {
    position: relative;
}

.dbh-coursecard__link:hover {
    color: var(--dbh-brand-700);
    text-decoration: none;
}

.dbh-coursecard__desc {
    font-size: 0.9375rem;
    margin: 0 0 16px;
}

.dbh-coursecard__facts {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 16px;
    margin: 0 0 20px;
    padding: 0;
    list-style: none;
    flex: 1 1 auto;
    align-content: flex-start;
}

.dbh-coursecard__facts li {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.875rem;
    color: var(--dbh-ink-muted);
}

.dbh-coursecard__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: auto;
    padding-top: 16px;
    border-top: 1px solid var(--dbh-line-soft);
}

.dbh-coursecard__price {
    font-family: var(--dbh-font-display);
    font-size: 1.375rem;
    font-weight: 700;
    color: var(--dbh-ink-900);
}

/* Sits above the card's stretched link so it stays clickable. */
.dbh-coursecard__foot .dbh-btn {
    position: relative;
    z-index: 2;
}

.dbh-btn--disabled {
    background: var(--dbh-ink-100);
    color: var(--dbh-ink-muted);
    border-color: transparent;
    cursor: not-allowed;
    pointer-events: none;
}

.dbh-badge--neutral {
    background: var(--dbh-ink-100);
    color: var(--dbh-ink-700);
}

/* Empty state. */
.dbh-empty {
    max-width: 520px;
    margin-inline: auto;
    padding: 48px 24px;
    text-align: center;
    background: var(--dbh-surface);
    border: 1px solid var(--dbh-line-soft);
    border-radius: var(--dbh-radius-lg);
}

.dbh-empty__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-brand-50);
    color: var(--dbh-brand-600);
    font-size: 1.5rem;
}

/* Course detail. */
.dbh-coursehead {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.dbh-curriculum {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.dbh-curriculum li {
    display: flex;
    gap: 12px;
    max-width: 68ch;
    font-size: 1rem;
    line-height: 1.6;
    color: var(--dbh-ink-700);
}

.dbh-curriculum i {
    flex-shrink: 0;
    margin-top: 3px;
    color: var(--dbh-brand-600);
}

/* Registration panel. */
.dbh-enrol {
    padding: 28px;
    background: #fff;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-lg);
    box-shadow: var(--dbh-shadow-md);
}

@media (min-width: 992px) {
    .dbh-enrol {
        position: sticky;
        top: 96px;
    }
}

.dbh-enrol__price {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-bottom: 20px;
    border-bottom: 1px solid var(--dbh-line-soft);
}

.dbh-enrol__amount {
    font-family: var(--dbh-font-display);
    font-size: 2.25rem;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--dbh-ink-900);
}

.dbh-enrol__facts {
    margin: 20px 0 0;
}

.dbh-enrol__facts > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 10px 0;
    border-bottom: 1px solid var(--dbh-line-soft);
}

.dbh-enrol__facts > div:last-child {
    border-bottom: 0;
}

.dbh-enrol__facts dt {
    font-size: 0.9375rem;
    font-weight: 400;
    color: var(--dbh-ink-700);
}

.dbh-enrol__facts dd {
    margin: 0;
    font-weight: 600;
    color: var(--dbh-ink-900);
    text-align: right;
}

/* Forms. 16px inputs are deliberate — anything smaller makes iOS zoom on
   focus, which throws the user out of the layout mid-form. */
.dbh-form {
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.dbh-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.dbh-field label {
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--dbh-ink-900);
}

/* Required-field marker, shared across every public form. */
.req {
    color: var(--dbh-danger-600);
    margin-left: 2px;
    font-weight: 700;
}

.dbh-field input {
    width: 100%;
    min-height: 48px;
    padding: 12px 14px;
    font-family: var(--dbh-font-sans);
    font-size: 1rem;
    color: var(--dbh-ink-900);
    background: var(--dbh-paper);
    border: 1px solid var(--dbh-ink-300);
    border-radius: var(--dbh-radius-md);
    transition:
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        box-shadow var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-field input:hover {
    border-color: var(--dbh-ink-400);
}

.dbh-field input:focus {
    outline: none;
    border-color: var(--dbh-brand-600);
    box-shadow: 0 0 0 3px var(--dbh-brand-50);
}

.dbh-field input[aria-invalid='true'] {
    border-color: #b91c1c;
}

.dbh-field__hint {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

/* Error text carries an icon as well as colour, so it does not rely on
   colour alone to register as an error. */
.dbh-field__error {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    margin: 0;
    font-size: 0.8125rem;
    color: #b91c1c;
}

.dbh-radio-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.dbh-radio {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    font-size: 0.9375rem;
    color: var(--dbh-ink-900);
    background: var(--dbh-paper);
    border: 1px solid var(--dbh-ink-300);
    border-radius: var(--dbh-radius-md);
    cursor: pointer;
    transition: border-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-radio:has(input:checked) {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-50);
    box-shadow: 0 0 0 1px var(--dbh-brand-600);
}

.dbh-radio:has(input:focus-visible) {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: 2px;
}

.dbh-radio input {
    width: auto;
    min-height: 0;
    margin: 0;
    /* Without this the two payment options use the browser's default
       blue radio — the one blue dot on an otherwise aubergine page. */
    accent-color: var(--dbh-brand-600);
}

/* A consent tickbox and its statement. Unlike .dbh-radio the label is a
   paragraph of legal copy, so the box pins to the first line rather than
   centring against the whole block. */
.dbh-consent-check {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.dbh-consent-check input {
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    min-height: 0;
    /* Aligns the box with the cap height of the first line of the label. */
    margin: 2px 0 0;
    accent-color: var(--dbh-brand-600);
}

.dbh-consent-check label {
    font-size: 0.9375rem;
    font-weight: 400;
    line-height: 1.5;
    color: var(--dbh-ink-900);
    cursor: pointer;
}

/* .dbh-field input[aria-invalid] only moves border-color, which a native
   checkbox does not render — this needs an outline to show at all. */
.dbh-consent-check input[aria-invalid='true'] {
    outline: 2px solid #b91c1c;
    outline-offset: 2px;
}

.dbh-consent-statement {
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: var(--dbh-ink-700);
}

.dbh-inline-note {
    display: flex;
    gap: 12px;
    padding: 14px 16px;
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-brand-50);
    border: 1px solid var(--dbh-brand-100);
    font-size: 0.9375rem;
    line-height: 1.5;
    color: var(--dbh-ink-900);
}

.dbh-inline-note > i {
    flex-shrink: 0;
    margin-top: 2px;
    color: var(--dbh-brand-600);
}

.dbh-inline-note--warn {
    background: #fef3c7;
    border-color: #fcd34d;
    color: #78350f;
}

.dbh-inline-note--warn > i {
    color: #b45309;
}

.dbh-inline-note--warn a {
    color: #78350f;
    font-weight: 600;
}

/* Submit spinner. */
.dbh-spinner {
    display: inline-block;
    width: 15px;
    height: 15px;
    margin-right: 8px;
    vertical-align: -2px;
    border: 2px solid rgba(255, 255, 255, 0.4);
    border-top-color: #fff;
    border-radius: var(--dbh-radius-full);
    animation: dbh-spin 700ms linear infinite;
}

@keyframes dbh-spin {
    to {
        transform: rotate(360deg);
    }
}

@media (prefers-reduced-motion: reduce) {
    .dbh-spinner {
        animation: none;
        border-top-color: rgba(255, 255, 255, 0.4);
    }
}

/* Confirmation receipt. */
.dbh-receipt {
    max-width: 620px;
    margin-inline: auto;
    padding: 40px 28px;
    text-align: center;
    background: #fff;
    border: 1px solid var(--dbh-line-soft);
    border-radius: var(--dbh-radius-lg);
    box-shadow: var(--dbh-shadow-md);
}

.dbh-receipt__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    border-radius: var(--dbh-radius-full);
    font-size: 1.75rem;
}

.dbh-receipt__icon--paid {
    background: #dcfce7;
    color: #15803d;
}

.dbh-receipt__icon--pending {
    background: #fef3c7;
    color: #b45309;
}

.dbh-receipt__ref {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 32px 0 0;
    padding: 20px;
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-brand-50);
    border: 1px dashed var(--dbh-brand-200);
}

.dbh-receipt__ref-label {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--dbh-brand-700);
}

.dbh-receipt__ref-code {
    font-family: var(--dbh-font-display);
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--dbh-brand-700);
}

.dbh-receipt__rows {
    margin: 24px 0 0;
    text-align: left;
}

.dbh-receipt__rows > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 0;
    border-bottom: 1px solid var(--dbh-line-soft);
}

.dbh-receipt__rows dt {
    font-size: 0.9375rem;
    font-weight: 400;
    color: var(--dbh-ink-700);
}

.dbh-receipt__rows dd {
    margin: 0;
    font-weight: 500;
    color: var(--dbh-ink-900);
    text-align: right;
}

.dbh-receipt__total {
    border-bottom: 0 !important;
    border-top: 2px solid var(--dbh-ink-900) !important;
    margin-top: 4px;
}

.dbh-receipt__total dt,
.dbh-receipt__total dd {
    font-family: var(--dbh-font-display);
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--dbh-ink-900);
}

.dbh-receipt__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
    margin-top: 32px;
}

@media (max-width: 419px) {
    .dbh-receipt__actions .dbh-btn {
        width: 100%;
    }
}

/* ── Space booking ──────────────────────────────────────────────────── */

.dbh-spacecard {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: #fff;
    border: 1px solid var(--dbh-line-soft);
    border-radius: var(--dbh-radius-lg);
    overflow: hidden;
    transition:
        box-shadow var(--dbh-dur-md) var(--dbh-ease-out),
        border-color var(--dbh-dur-md) var(--dbh-ease-out);
}

.dbh-spacecard:hover {
    border-color: var(--dbh-brand-200);
    box-shadow: var(--dbh-shadow-lg);
}

.dbh-spacecard__media {
    aspect-ratio: 3 / 2;
    background: var(--dbh-ink-100);
    overflow: hidden;
}

.dbh-spacecard__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.dbh-spacecard__body {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    padding: 24px;
}

.dbh-rates {
    list-style: none;
    margin: 20px 0 0;
    padding: 0;
}

.dbh-rates li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 10px 0;
    border-bottom: 1px solid var(--dbh-line-soft);
}

.dbh-rates li:last-child {
    border-bottom: 0;
}

.dbh-rates__label {
    font-size: 0.9375rem;
    color: var(--dbh-ink-700);
}

.dbh-rates__value {
    font-family: var(--dbh-font-display);
    font-weight: 600;
    color: var(--dbh-ink-900);
}

.dbh-includes-panel {
    padding: 28px;
    background: var(--dbh-surface);
    border: 1px solid var(--dbh-line-soft);
    border-radius: var(--dbh-radius-lg);
}

/* Numbered booking steps. */
.dbh-step-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    margin-right: 10px;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-brand-600);
    color: #fff;
    font-family: var(--dbh-font-sans);
    font-size: 0.9375rem;
    font-weight: 600;
    vertical-align: 3px;
}

/* The space picker. Cards rather than table rows: a space is a thing you
   pick, and on a phone a bordered card gives the whole row — name, state
   and price — one obvious tap target instead of a 22px control floating
   at the start of a hairline-separated line. */
.dbh-picker {
    display: grid;
    gap: 10px;
}

/* Until a date and a duration exist there is no price and no availability
   to show, so the list is visibly not-yet-live rather than a set of rows
   that look pickable and silently are not. */
.dbh-picker.is-waiting {
    opacity: 0.55;
    pointer-events: none;
}

.dbh-picker__gate {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 12px 14px;
    border: 1px dashed var(--dbh-ink-300);
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-surface);
    font-size: 0.9375rem;
    color: var(--dbh-ink-700);
}

.dbh-picker__gate > i {
    color: var(--dbh-brand-600);
}

.dbh-picker__gate[hidden] {
    display: none;
}

.dbh-picker__row {
    position: relative;
    display: flex;
    /* nowrap on purpose. Wrapping is decided on max-content sizes, and a
       space name like "Hair Dressing Chair For Rent" measures wider than
       the card on a phone — so the price was pushed onto its own line
       even though it is only 62px wide and would have fit beside a name
       that had simply wrapped. The name wraps within its column instead. */
    flex-wrap: nowrap;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 14px 16px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-paper);
    transition:
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        box-shadow var(--dbh-dur-sm) var(--dbh-ease-out);
}

/* Hover only where a pointer can actually hover, so a phone does not keep
   the last-tapped card looking pre-selected. */
@media (hover: hover) {
    .dbh-picker__row:not(.is-unavailable):hover {
        border-color: var(--dbh-brand-200);
        background: #fff;
    }
}

/* The chosen space, in the same language the service picker uses for a
   chosen service — tinted, brand-bordered, and carrying the only shadow
   in the list. */
.dbh-picker__row:has(input:checked) {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-50);
    box-shadow: var(--dbh-shadow-sm);
}

.dbh-picker__row:has(input:focus-visible) {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: 2px;
}

.dbh-picker__row.is-unavailable {
    background: var(--dbh-surface);
    opacity: 0.7;
}

/* Basis auto with min-width:0, not a 240px basis. A fixed basis plus the
   price no longer fit inside a 375px card, so the price wrapped onto its
   own line and every card grew to 137px — over 1500px of picker for
   eleven spaces. Name and price now share one line and the card is half
   the height. */
.dbh-picker__choose {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    flex: 1 1 auto;
    min-width: 0;
}

.dbh-picker__choose input[type='radio'],
.dbh-picker__choose input[type='checkbox'] {
    width: 22px;
    height: 22px;
    margin-top: 11px;
    flex-shrink: 0;
    accent-color: var(--dbh-brand-600);
    cursor: pointer;
}

.dbh-picker__choose input:disabled {
    cursor: not-allowed;
}

/* The label carries the tap target, so the whole row is comfortably
   selectable rather than just the 22px box. Stretched over the card by
   ::before so the price side is tappable too — on a phone the price is
   where the thumb goes. */
.dbh-picker__choose label {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-height: 44px;
    justify-content: center;
    cursor: pointer;
}

.dbh-picker__choose label::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
}

.dbh-picker__row.is-unavailable label {
    cursor: not-allowed;
}

.dbh-picker__name {
    font-weight: 500;
    color: var(--dbh-ink-900);
}

.dbh-picker__state {
    font-size: 0.8125rem;
    color: var(--dbh-warn-ink);
}

.dbh-picker__rate select {
    min-height: 44px;
    padding: 8px 12px;
    font-family: var(--dbh-font-sans);
    font-size: 1rem;
    color: var(--dbh-ink-900);
    background: var(--dbh-paper);
    border: 1px solid var(--dbh-ink-300);
    border-radius: var(--dbh-radius-md);
}

.dbh-picker__rate select:disabled {
    opacity: 0.5;
}

.dbh-field textarea {
    width: 100%;
    padding: 12px 14px;
    font-family: var(--dbh-font-sans);
    font-size: 1rem;
    color: var(--dbh-ink-900);
    background: var(--dbh-paper);
    border: 1px solid var(--dbh-ink-300);
    border-radius: var(--dbh-radius-md);
    resize: vertical;
}

.dbh-field textarea:focus {
    outline: none;
    border-color: var(--dbh-brand-600);
    box-shadow: 0 0 0 3px var(--dbh-brand-50);
}

/* Running summary. Doubles as the mobile bottom sheet — see the block
   below the sticky bar for its off-screen/slide-up behaviour. */
.dbh-summary {
    padding: 28px;
    background: #fff;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-lg);
    box-shadow: var(--dbh-shadow-md);
}

.dbh-summary__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

/* Only meaningful once the panel is a dismissible sheet. */
.dbh-sheet-close,
.dbh-sheet-handle {
    display: none;
}

@media (min-width: 992px) {
    .dbh-summary {
        position: sticky;
        top: 96px;
    }
}

.dbh-summary__when {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 16px;
    padding: 10px 14px;
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-brand-50);
    font-size: 0.9375rem;
    color: var(--dbh-brand-700);
}

.dbh-summary__items {
    list-style: none;
    margin: 20px 0 0;
    padding: 0;
}

.dbh-summary__items li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 0;
    border-bottom: 1px solid var(--dbh-line-soft);
}

.dbh-summary__empty {
    font-size: 0.9375rem;
    color: var(--dbh-ink-muted);
}

.dbh-summary__name {
    display: block;
    font-weight: 500;
    color: var(--dbh-ink-900);
}

.dbh-summary__rate {
    display: block;
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

.dbh-summary__price {
    font-family: var(--dbh-font-display);
    font-weight: 600;
    white-space: nowrap;
}

.dbh-summary__totals {
    margin: 20px 0 0;
}

.dbh-summary__totals > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 8px 0;
}

.dbh-summary__totals dt {
    font-size: 0.9375rem;
    font-weight: 400;
    color: var(--dbh-ink-700);
}

.dbh-summary__totals dd {
    margin: 0;
    font-weight: 600;
    color: var(--dbh-ink-900);
}

/* The deposit is what is actually charged now, so it is the emphasised
   figure rather than the booking total. */
.dbh-summary__due {
    margin-top: 4px;
    padding-top: 12px !important;
    border-top: 2px solid var(--dbh-ink-900);
}

.dbh-summary__due dt,
.dbh-summary__due dd {
    font-family: var(--dbh-font-display);
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--dbh-ink-900);
}

/* Booked items on the confirmation. */
.dbh-booked-items {
    list-style: none;
    margin: 0;
    padding: 0;
    text-align: left;
}

.dbh-booked-items li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 0;
    border-bottom: 1px solid var(--dbh-line-soft);
}

.dbh-booked-items__name {
    display: block;
    font-weight: 500;
    color: var(--dbh-ink-900);
}

.dbh-booked-items__rate {
    display: block;
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

.dbh-booked-items__price {
    font-family: var(--dbh-font-display);
    font-weight: 600;
    white-space: nowrap;
}

.dbh-receipt__notes {
    margin-top: 24px;
    padding: 16px 20px;
    text-align: left;
    background: var(--dbh-surface);
    border-radius: var(--dbh-radius-md);
}

/* ── Footer ─────────────────────────────────────────────────────────────
   Three bands: closing CTA, link directory, legal bar. The directory is a
   grid rather than Bootstrap columns so the brand block can hold a wider,
   readable measure while the link columns size themselves evenly. */
.dbh-footer {
    background: var(--dbh-surface);
    border-top: 1px solid var(--dbh-line);
    padding-block: var(--dbh-space-12) var(--dbh-space-8);
}

@media (min-width: 768px) {
    .dbh-footer {
        padding-block: var(--dbh-space-16) var(--dbh-space-8);
    }
}

.dbh-footer h2 {
    font-family: var(--dbh-font-sans);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--dbh-ink-muted);
    margin-bottom: 4px;
}

/* Closing CTA — sits on paper so it lifts off the surface-toned footer
   without needing a shadow to do the work. */
.dbh-footer__cta {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--dbh-space-6);
    padding: var(--dbh-space-8);
    margin-bottom: var(--dbh-space-12);
    background: var(--dbh-paper);
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-lg);
}

@media (min-width: 768px) {
    .dbh-footer__cta {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
        padding: var(--dbh-space-8) var(--dbh-space-12);
    }
}

.dbh-footer__cta-eyebrow {
    margin: 0 0 4px;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--dbh-brand-600);
}

.dbh-footer__cta-title {
    margin: 0;
    font-family: var(--dbh-font-display);
    font-size: 1.375rem;
    font-weight: 600;
    line-height: 1.25;
    color: var(--dbh-ink-900);
}

@media (min-width: 768px) {
    .dbh-footer__cta-title {
        font-size: 1.625rem;
    }
}

.dbh-footer__cta-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

@media (max-width: 575.98px) {
    .dbh-footer__cta-actions {
        width: 100%;
    }

    .dbh-footer__cta-actions .dbh-btn {
        flex: 1 1 100%;
    }
}

.dbh-footer__main {
    display: grid;
    gap: var(--dbh-space-12);
}

@media (min-width: 992px) {
    .dbh-footer__main {
        grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
        gap: var(--dbh-space-16);
        align-items: start;
    }
}

.dbh-footer__brand .dbh-logo {
    margin-bottom: var(--dbh-space-4);
}

/* Held to a comfortable measure rather than the full column, so the
   sentence breaks at roughly the same place the eye wants it to. */
.dbh-footer__blurb {
    max-width: 34ch;
    margin-bottom: var(--dbh-space-6);
    font-size: 0.9375rem;
    line-height: 1.65;
    color: var(--dbh-ink-700);
}

/* Two independent flowing columns rather than a 2×2 grid: a grid sizes
   both cells in a row to the taller one, and "Also at the hub" (3 links)
   forced a gap under "Services" (2 links) before "Visit" could start.
   column-count lets each side stack to its own content height, the same
   way the four-across desktop layout already does. */
.dbh-footer__columns {
    column-count: 2;
    column-gap: var(--dbh-space-6);
}

.dbh-footer__col {
    /* Keeps a heading from ever landing at the bottom of one column with
       its links pushed into the next. */
    break-inside: avoid;
    margin-bottom: var(--dbh-space-8);
}

.dbh-footer__col:last-child {
    margin-bottom: 0;
}

@media (min-width: 768px) {
    .dbh-footer__columns {
        display: grid;
        grid-template-columns: repeat(4, minmax(0, 1fr));
        column-gap: var(--dbh-space-6);
    }

    .dbh-footer__col {
        margin-bottom: 0;
    }
}

.dbh-footer__nav {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Full-width so a short label still presents a comfortable target across
   the column, not just the width of the word. The 44px floor is met by
   padding rather than min-height, which keeps multi-line labels ("Find us
   & opening hours") from being forced into an oversized row. */
.dbh-footer__nav a {
    display: block;
    padding-block: 11px;
    font-size: 0.9375rem;
    line-height: 1.4;
    color: var(--dbh-ink-700);
    text-decoration: none;
    transition: color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-footer__nav a:hover {
    color: var(--dbh-brand-600);
    text-decoration: underline;
}

/* Contact rows lead with an icon, so the label needs to hang rather than
   wrap back underneath it. */
.dbh-footer__nav--contact a {
    display: flex;
    align-items: center;
    gap: 10px;
}

.dbh-footer__nav--contact i {
    flex: none;
    font-size: 1rem;
    color: var(--dbh-ink-muted);
}

.dbh-footer__nav--contact a:hover i {
    color: var(--dbh-brand-600);
}

.dbh-social {
    display: flex;
    gap: 10px;
}

.dbh-social a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--dbh-radius-full);
    border: 1px solid var(--dbh-line);
    background: var(--dbh-paper);
    color: var(--dbh-ink-700);
    font-size: 1.125rem;
    transition:
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        color var(--dbh-dur-sm) var(--dbh-ease-out),
        border-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-social a:hover {
    background: var(--dbh-brand-600);
    border-color: var(--dbh-brand-600);
    color: #fff;
}

.dbh-footer__bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px 24px;
    margin-top: var(--dbh-space-12);
    padding-top: var(--dbh-space-6);
    border-top: 1px solid var(--dbh-line);
    font-size: 0.875rem;
    color: var(--dbh-ink-muted);
}

.dbh-footer__legal {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 24px;
}

.dbh-footer__legal a {
    color: var(--dbh-ink-muted);
    text-decoration: none;
    transition: color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-footer__legal a:hover {
    color: var(--dbh-brand-600);
    text-decoration: underline;
}

/* ── Motion ─────────────────────────────────────────────────────────────
   Fade-and-rise on scroll entry. Transform/opacity only, so it stays on
   the compositor. Elements start visible and are hidden by JS only when
   IntersectionObserver is available — without JS the content still reads. */
.dbh-reveal {
    opacity: 1;
}

.js-reveal-ready .dbh-reveal {
    opacity: 0;
    transform: translateY(12px);
    transition:
        opacity var(--dbh-dur-lg) var(--dbh-ease-out),
        transform var(--dbh-dur-lg) var(--dbh-ease-out);
    transition-delay: var(--dbh-reveal-delay, 0ms);
}

.js-reveal-ready .dbh-reveal.is-visible {
    opacity: 1;
    transform: none;
}

@media (prefers-reduced-motion: reduce) {
    .dbh-site *,
    .dbh-site *::before,
    .dbh-site *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    /* Never leave a reveal element stuck at opacity 0. */
    .js-reveal-ready .dbh-reveal {
        opacity: 1;
        transform: none;
    }

    .dbh-gallery figure:hover img {
        transform: none;
    }
}

/* Smooth in-page anchors, offset for the sticky header. */
@media (prefers-reduced-motion: no-preference) {
    .dbh-site {
        scroll-behavior: smooth;
    }
}

.dbh-site [id] {
    scroll-margin-top: 88px;
}

/* Skip link. */
.dbh-skip {
    position: absolute;
    top: 8px;
    left: 8px;
    z-index: 1080;
    padding: 12px 20px;
    border-radius: var(--dbh-radius-sm);
    background: var(--dbh-brand-600);
    color: #fff;
    font-weight: 500;
    text-decoration: none;
    transform: translateY(-150%);
    transition: transform var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-skip:focus {
    transform: translateY(0);
    color: #fff;
}

/* ── Service booking ─────────────────────────────────────────────────────
   The picker for the public booking flow. The selection rule (one service
   per department, up to four) is shown as a filling indicator rather than
   enforced by surprise at the point of selection. */

/* The chosen-service indicator.
 *
 * Content-sized rather than a fixed four-column grid. The chips are built
 * from the selection, so a rigid grid gave every chip an identical quarter
 * of the row whatever it held — which squeezed the "2 of 4 chosen" counter
 * into an ellipsis while the service chips beside it sat half empty. Sizing
 * to content lets each chip take what it needs, and only a genuinely long
 * service name hits the cap and truncates. */
.dbh-slots {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 20px 0 24px;
}

.dbh-slot {
    position: relative;
    display: flex;
    flex: 0 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    max-width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-paper);
    transition:
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        box-shadow var(--dbh-dur-sm) var(--dbh-ease-out);
}

/* A chosen service. Capped so one long name cannot run the width of the
   row, and padded on the right for the remove control. */
.dbh-slot[data-filled='true'] {
    max-width: 260px;
    padding-right: 44px;
    border-color: var(--dbh-brand-300);
    background: var(--dbh-brand-50);
}

/* The counter ("2 of 4 chosen") and the empty-state chip. Neither is a
   selection, so both stay quiet against the filled chips and size to their
   own text — this is the chip that was being truncated. */
.dbh-slot[data-filled='false'] {
    flex: 0 0 auto;
    border-style: dashed;
    background: transparent;
}

.dbh-slot[data-filled='false'] .dbh-slot__value {
    overflow: visible;
    text-overflow: clip;
}

/* On a phone the strip has one row's worth of room before it starts
   costing the menu its place on screen, so the chips tighten and share
   the row rather than stacking one per line. */
@media (max-width: 575.98px) {
    .dbh-slots {
        gap: 6px;
        margin: 16px 0 20px;
    }

    .dbh-slot {
        padding: 8px 10px;
    }

    .dbh-slot[data-filled='true'] {
        max-width: calc(100% - 92px);
        padding-right: 40px;
    }

    .dbh-slot__remove {
        width: 40px;
    }
}

/* Marks a chip that just changed — added, swapped, or cleared — so the
   change reads as an event rather than the list silently reflowing. */
.dbh-slot.is-updated {
    animation: dbh-slot-pop var(--dbh-dur-lg) var(--dbh-ease-out);
}

@keyframes dbh-slot-pop {
    0% {
        box-shadow: 0 0 0 0 var(--dbh-brand-100);
    }
    40% {
        box-shadow: 0 0 0 6px var(--dbh-brand-100);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(196, 64, 255, 0);
    }
}

/* Kept to one line. A style like "Sew Ins & Wig Install & Tape Ins" wraps
   to three rows otherwise, and the chip strip is the last thing that
   should be pushing the menu down the page. */
.dbh-slot__dept {
    overflow: hidden;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--dbh-ink-muted);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The chosen service name can be long; it truncates rather than pushing
   the four chips out of their row. */
.dbh-slot__value {
    overflow: hidden;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--dbh-ink-muted);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dbh-slot[data-filled='true'] .dbh-slot__value {
    color: var(--dbh-brand-700);
}

/* One-tap removal straight from the slot chip — the fastest path back out
   of a selection, without hunting the service back down in the menu.
 *
 * The visible disc stays small so it never competes with the service name,
 * but the ::after pane below stretches the hit area to the full height of
 * the chip and a comfortable 44px wide. A 22px control is a coin-flip to
 * hit with a thumb; the target it accepts taps on is not the dot you see. */
.dbh-slot__remove {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    padding: 0;
    border: 0;
    border-radius: 0 var(--dbh-radius-md) var(--dbh-radius-md) 0;
    background: transparent;
    color: var(--dbh-brand-600);
    font-size: 0.75rem;
    cursor: pointer;
    touch-action: manipulation;
    transition: color var(--dbh-dur-sm) var(--dbh-ease-out);
}

/* The disc that actually reads as a button. */
.dbh-slot__remove i {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: var(--dbh-radius-full);
    transition: background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-slot__remove:hover i {
    background: var(--dbh-brand-100);
}

.dbh-slot__remove:focus-visible {
    outline-offset: -2px;
}

/* Department filter chips. A short, fixed set on desktop; on a narrow
   screen the same row scrolls horizontally with a snap so it never wraps
   into a second, height-stealing line above the menu. */
.dbh-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 24px;
}

@media (max-width: 575.98px) {
    .dbh-filters {
        flex-wrap: nowrap;
        overflow-x: auto;
        scroll-snap-type: x proximity;
        padding-bottom: 2px;
        margin-inline: -2px;
        padding-inline: 2px;
        -ms-overflow-style: none;
        scrollbar-width: none;
    }

    .dbh-filters::-webkit-scrollbar {
        display: none;
    }

    .dbh-filters .dbh-chip {
        flex: 0 0 auto;
        scroll-snap-align: start;
    }
}

.dbh-chip {
    min-height: 44px;
    padding: 8px 18px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-paper);
    font-family: var(--dbh-font-sans);
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--dbh-ink-700);
    white-space: nowrap;
    cursor: pointer;
    touch-action: manipulation;
    transition:
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-chip:hover {
    border-color: var(--dbh-brand-300);
    color: var(--dbh-brand-700);
}

.dbh-chip.is-active {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-600);
    color: #fff;
}

/* The list of dates a Daily space booking has chosen so far — each a
   removable pill, same shape as .dbh-chip so it reads as one family with the
   filter chips rather than a new pattern. */
.dbh-selected-dates {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    list-style: none;
    margin: 0;
    padding: 0;
}

.dbh-selected-dates__pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 36px;
    padding: 6px 10px 6px 14px;
    border: 1px solid var(--dbh-brand-600);
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-brand-600);
    font-family: var(--dbh-font-sans);
    font-size: 0.8125rem;
    font-weight: 500;
    color: #fff;
    cursor: pointer;
    touch-action: manipulation;
}

.dbh-selected-dates__pill:hover {
    background: var(--dbh-brand-700);
    border-color: var(--dbh-brand-700);
}

.dbh-selected-dates__pill i {
    font-size: 0.875rem;
}

/* The service menu — a stack of collapsible variant groups (an accordion)
   rather than one long always-open list. A menu running to dozens of
   services across every style made scrolling to the one you want the
   slowest part of adding a second treatment; collapsing everything but the
   first group, plus whatever already holds a choice, cuts that scroll to
   whatever the visitor actually opens. */
.dbh-menu__group {
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-md);
    background: #fff;
    transition: border-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-menu__group + .dbh-menu__group {
    margin-top: 12px;
}

/* A chosen service lifts its group's border so it reads apart from an
   untouched one even while collapsed. */
.dbh-menu__group:has([data-service-toggle][aria-pressed='true']) {
    border-color: var(--dbh-brand-300);
}

.dbh-menu__head {
    display: flex;
    align-items: center;
    width: 100%;
    gap: 14px;
    min-height: 56px;
    padding: 14px 16px;
    border: 0;
    /* Matches the card's own radius, so the hover fill never squares off
       the rounded corners it sits inside. */
    border-radius: var(--dbh-radius-md) var(--dbh-radius-md) 0 0;
    background: none;
    text-align: left;
    cursor: pointer;
    touch-action: manipulation;
    transition: background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

/* A collapsed card is a single control, so its header rounds on all four
   corners; an open one only on the two it still owns. */
.dbh-menu__group:not(.is-open) .dbh-menu__head {
    border-radius: var(--dbh-radius-md);
}

.dbh-menu__head:hover {
    background: var(--dbh-surface);
}

/* Inset, because the default 3px offset would fall outside the card and
   collide with the neighbouring group. */
.dbh-menu__head:focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: -2px;
}

.dbh-menu__headtext {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}

.dbh-menu__headmeta {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    gap: 10px;
}

/* "Selected" on a group that holds a choice.
 *
 * A wash rather than a solid fill: this marks state on as many groups as
 * the visitor has chosen from, and at full brand strength four of them
 * would each carry the same weight as the one real primary action on the
 * page. The tick beside it does the confirming; the pill only labels. */
.dbh-menu__count {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-brand-50);
    font-family: var(--dbh-font-sans);
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--dbh-brand-700);
    white-space: nowrap;
}

.dbh-menu__count::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-brand-600);
}

.dbh-menu__chevron {
    display: block;
    color: var(--dbh-ink-500);
    font-size: 0.875rem;
    transition: transform var(--dbh-dur-md) var(--dbh-ease-out);
}

.dbh-menu__group.is-open .dbh-menu__chevron {
    transform: rotate(180deg);
}

/* The grid-rows trick: animating a wrapper's fractional row from 0fr to 1fr
   gives a smooth expand/collapse without JS ever measuring content height. */
.dbh-menu__panelwrap {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--dbh-dur-md) var(--dbh-ease-out);
}

.dbh-menu__group.is-open .dbh-menu__panelwrap {
    grid-template-rows: 1fr;
}

.dbh-menu__panel {
    min-height: 0;
    overflow: hidden;
}

.dbh-menu__head[aria-expanded='true'] + .dbh-menu__panelwrap .dbh-menu__list {
    padding-top: 4px;
}

/* Optional: groups without a photo keep a heading that fills the row, so
   the flex container above degrades to exactly its previous layout. */
.dbh-menu__thumb {
    flex: 0 0 auto;
    width: 56px;
    height: 56px;
    object-fit: cover;
    border-radius: var(--dbh-radius-sm);
    background: var(--dbh-line-soft);
}

/* The card runs on one inset rhythm.
 *
 * 8px here plus the row's own 8px puts the tick on exactly the 16px line
 * the group header's text sits on, so the card has a single left edge
 * running top to bottom. The 8px also gives a chosen row's tint a visible,
 * even margin inside the card — at the 4px it had before, the gap read as
 * a rendering slip rather than an inset. */
.dbh-menu__list {
    list-style: none;
    margin: 0;
    padding: 0 8px 8px;
}

.dbh-menu__item {
    border-bottom: 1px solid var(--dbh-line-soft);
}

/* The card's own edge closes the list; a rule under the last row would
   double it. Hidden items are skipped so the rule lands on whatever the
   current filter left visible, not on a filtered-out row. */
.dbh-menu__item:last-child,
.dbh-menu__item:has(~ .dbh-menu__item[hidden]):not(:has(~ .dbh-menu__item:not([hidden]))) {
    border-bottom: 0;
}

/* A button, not a checkbox: choosing a service can *replace* another, which
   on/off checkbox semantics cannot express. aria-pressed carries the state. */
.dbh-menu__choose {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    width: 100%;
    min-height: 56px;
    padding: 14px 8px;
    border: 0;
    /* Rounded, so a chosen row reads as a card inside the group rather
       than a square-cornered band cutting across a rounded one. */
    border-radius: var(--dbh-radius-sm);
    background: none;
    text-align: left;
    cursor: pointer;
    touch-action: manipulation;
    transition: background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-menu__choose:hover {
    background: var(--dbh-surface);
}

.dbh-menu__choose:focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: -2px;
}

.dbh-menu__check {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    margin-top: 2px;
    border: 2px solid var(--dbh-ink-300);
    border-radius: var(--dbh-radius-sm);
    color: transparent;
    transition:
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        color var(--dbh-dur-sm) var(--dbh-ease-out),
        transform var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-menu__choose[aria-pressed='true'] .dbh-menu__check {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-600);
    color: #fff;
    transform: scale(1.08);
}

.dbh-menu__choose[aria-pressed='true'] {
    background: var(--dbh-brand-50);
}

/* One flash on the moment of choice — added, swapped, or removed — rather
   than the row silently changing colour underneath the tap. */
.dbh-menu__item.is-flashed .dbh-menu__choose {
    animation: dbh-menu-flash var(--dbh-dur-lg) var(--dbh-ease-out);
}

@keyframes dbh-menu-flash {
    0% {
        background: var(--dbh-brand-100);
    }
}

.dbh-menu__body {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.dbh-menu__name {
    font-weight: 600;
    line-height: 1.35;
    color: var(--dbh-ink-900);
}

.dbh-menu__desc {
    font-size: 0.875rem;
    line-height: 1.55;
    color: var(--dbh-ink-muted);
}

.dbh-menu__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: 2px;
    font-size: 0.875rem;
    color: var(--dbh-ink-muted);
}

/* The price is the datum the row is scanned for, so it carries a step more
   size and weight than the duration beside it. Tabular figures keep the
   column of prices aligned down a long list. */
.dbh-menu__price {
    font-family: var(--dbh-font-display);
    font-size: 0.9375rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--dbh-ink-900);
}

.dbh-menu__tag {
    padding: 2px 10px;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-surface);
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--dbh-ink-700);
}

/*
 * The way out of the single-service scope a "Book this" link arrives in.
 *
 * Deliberately a text button rather than a filled one: adding a second
 * service is an option, not the expected next step, and it sits directly
 * above the chosen service it must not compete with.
 */
.dbh-link-button {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 0;
    border: 0;
    background: none;
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--dbh-brand-600);
    cursor: pointer;
}

.dbh-link-button:hover {
    text-decoration: underline;
}

/* Says what picking this will replace, so a swap is never a surprise.
 *
 * Both of these hang off the service name rather than the row edge: 8px of
 * row padding, a 24px tick, and the 14px gap. The right margin is 0 so
 * they close on the same line the row's tint does. */
.dbh-menu__replaces {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 14px 46px;
    font-size: 0.875rem;
    line-height: 1.45;
    color: var(--dbh-warn-ink);
}

/* Per-service add-ons, revealed once its service is chosen.

   Reads as part of the service above it rather than a detached grey slab:
   it is tinted with the same brand wash the chosen row carries, and hangs
   from it on a left rule so the relationship is structural rather than
   left to proximity. */
.dbh-addons {
    display: grid;
    gap: 6px;
    margin: 0 0 16px 46px;
    padding: 12px 14px 14px;
    border-left: 2px solid var(--dbh-brand-200);
    border-radius: 0 var(--dbh-radius-md) var(--dbh-radius-md) 0;
    background: var(--dbh-brand-50);
}

/* On a phone the 46px indent costs more than the alignment is worth, so
   both drop back to the row's own edge and take the full width. */
@media (max-width: 575.98px) {
    .dbh-menu__replaces,
    .dbh-addons {
        margin-left: 8px;
    }
}

.dbh-addons__title {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 2px;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--dbh-brand-700);
}

.dbh-addons__title > i {
    font-size: 0.875rem;
}

/* The whole row is the label, so the tick, the name and the price are one
   target rather than a 20px box beside them. */
.dbh-addons__row {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    padding: 8px 12px;
    border: 1px solid transparent;
    border-radius: var(--dbh-radius-md);
    background: #fff;
    cursor: pointer;
    transition:
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        box-shadow var(--dbh-dur-sm) var(--dbh-ease-out);
}

/* Real and keyboard-operable, just not drawn — the tick below is its
   visible form, matching the service rows above. */
.dbh-addons__row input[type='checkbox'] {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.dbh-addons__check {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    border: 1px solid var(--dbh-ink-300);
    border-radius: 6px;
    background: #fff;
    color: #fff;
    font-size: 0.75rem;
    transition:
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        border-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-addons__check > i {
    opacity: 0;
    transition: opacity var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-addons__name {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.9375rem;
    color: var(--dbh-ink-900);
    line-height: 1.35;
}

.dbh-addons__price {
    flex: 0 0 auto;
    font-family: var(--dbh-font-display);
    font-weight: 700;
    color: var(--dbh-ink-900);
    white-space: nowrap;
}

@media (hover: hover) {
    .dbh-addons__row:hover {
        border-color: var(--dbh-brand-200);
    }
}

.dbh-addons__row:has(input:checked) {
    border-color: var(--dbh-brand-600);
    box-shadow: var(--dbh-shadow-sm);
}

.dbh-addons__row:has(input:checked) .dbh-addons__check {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-600);
}

.dbh-addons__row:has(input:checked) .dbh-addons__check > i {
    opacity: 1;
}

.dbh-addons__row:has(input:checked) .dbh-addons__price {
    color: var(--dbh-brand-700);
}

.dbh-addons__row:has(input:focus-visible) {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .dbh-addons__row,
    .dbh-addons__check,
    .dbh-addons__check > i {
        transition: none;
    }
}

/* Start-time grid. */
.dbh-times {
    min-width: 0;
    padding: 0;
    border: 0;
}

.dbh-times legend {
    float: left;
    width: 100%;
    margin-bottom: 4px;
}

.dbh-times__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: 8px;
    clear: both;
}

.dbh-time {
    min-height: 44px;
    padding: 10px 8px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-paper);
    font-family: var(--dbh-font-sans);
    font-size: 0.9375rem;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--dbh-ink-700);
    cursor: pointer;
    transition:
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-time:hover {
    border-color: var(--dbh-brand-300);
    color: var(--dbh-brand-700);
}

.dbh-time[aria-pressed='true'] {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-600);
    color: #fff;
}

/* ── Appointment type ───────────────────────────────────────────────────
   Normal vs Emergency. These used to borrow the time-slot chip, which
   squeezed "Emergency (+£50.00)" into a 96px square and wrapped the fee
   onto its own line — and read as just another slot in the grid below,
   when it is actually a choice about hours and money. Two cards instead,
   each saying what it means, with the fee set apart from the label. */
.dbh-typepick {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 10px;
    margin-top: 8px;
}

.dbh-typepick__option {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    padding: 12px 14px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-paper);
    text-align: left;
    cursor: pointer;
    transition:
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        box-shadow var(--dbh-dur-sm) var(--dbh-ease-out);
}

/* Reserves its space whether ticked or not, so choosing cannot reflow the
   pair — the same rule the duration cards follow. */
.dbh-typepick__tick {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    border: 1px solid var(--dbh-ink-300);
    border-radius: 50%;
    background: transparent;
    color: #fff;
    font-size: 0.75rem;
    transition:
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        border-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-typepick__tick > i {
    opacity: 0;
    transition: opacity var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-typepick__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1 1 auto;
    min-width: 0;
}

.dbh-typepick__label {
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.3;
    color: var(--dbh-ink-900);
}

.dbh-typepick__meta {
    font-size: 0.8125rem;
    line-height: 1.35;
    color: var(--dbh-ink-700);
}

/* The surcharge, kept out of the label so it reads as a consequence of the
   choice rather than part of its name. */
.dbh-typepick__fee {
    flex: 0 0 auto;
    padding: 3px 9px;
    border-radius: 999px;
    background: var(--dbh-surface);
    font-family: var(--dbh-font-display);
    font-size: 0.8125rem;
    font-weight: 700;
    color: var(--dbh-ink-900);
    white-space: nowrap;
}

@media (hover: hover) {
    .dbh-typepick__option:hover {
        border-color: var(--dbh-brand-200);
        background: #fff;
    }
}

.dbh-typepick__option[aria-pressed='true'] {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-50);
    box-shadow: var(--dbh-shadow-sm);
}

.dbh-typepick__option[aria-pressed='true'] .dbh-typepick__tick {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-600);
}

.dbh-typepick__option[aria-pressed='true'] .dbh-typepick__tick > i {
    opacity: 1;
}

.dbh-typepick__option[aria-pressed='true'] .dbh-typepick__label {
    color: var(--dbh-brand-700);
}

/* Amber rather than the neutral chip once chosen: this is the state that
   costs extra, and the note below repeats why. */
.dbh-typepick__option[aria-pressed='true'] .dbh-typepick__fee {
    background: #fef3c7;
    color: #78350f;
}

.dbh-typepick__option:focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .dbh-typepick__option,
    .dbh-typepick__tick,
    .dbh-typepick__tick > i {
        transition: none;
    }
}

/* Deposit / cancellation policy, stated before payment. */
.dbh-policy {
    padding: 20px 24px;
    border: 1px solid var(--dbh-line);
    border-left: 4px solid var(--dbh-brand-600);
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-surface);
}

.dbh-policy h2,
.dbh-policy h3 {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--dbh-ink-900);
}

.dbh-policy h2 > i,
.dbh-policy h3 > i {
    color: var(--dbh-brand-600);
}

.dbh-policy__list {
    margin: 12px 0 0;
    padding-left: 20px;
}

.dbh-policy__list li {
    font-size: 0.9375rem;
    line-height: 1.6;
    color: var(--dbh-ink-700);
}

.dbh-policy__list li + li {
    margin-top: 8px;
}

/* Mobile sticky summary bar. The desktop panel is off-screen below lg, so
   the deposit has to stay visible there too. */
.dbh-stickybar {
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1030;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
    border-top: 1px solid var(--dbh-line);
    background: #fff;
    box-shadow: 0 -4px 16px rgba(26, 16, 35, 0.08);
    animation: dbh-stickybar-in var(--dbh-dur-lg) var(--dbh-ease-out);
}

@keyframes dbh-stickybar-in {
    from {
        transform: translateY(100%);
    }
}

@media (min-width: 992px) {
    /* Above lg the sticky panel is visible, so this would be a duplicate. */
    .dbh-stickybar {
        display: none;
    }
}

.dbh-stickybar__figures {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    font-size: 0.875rem;
}

.dbh-stickybar__count {
    overflow: hidden;
    color: var(--dbh-ink-muted);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dbh-stickybar__deposit strong,
.dbh-stickybar__price strong {
    font-family: var(--dbh-font-display);
    font-size: 1.0625rem;
    color: var(--dbh-ink-900);
}

.dbh-stickybar__balance {
    color: var(--dbh-ink-muted);
}

/* The bar is fixed, so the last card would otherwise sit underneath it.
   The height comes from JS because the figures wrap to a second line on
   narrow phones — a flat 88px left the last card 11px short there. */
@media (max-width: 991.98px) {
    .dbh-booking.has-sticky-bar {
        padding-bottom: calc(var(--dbh-stickybar-h, 88px) + 16px);
    }

    /* The footer, not the form, is the end of the document — without this
       the bar parks on top of the Terms and Privacy links and they cannot
       be reached at all once a service is chosen. */
    body:has(.dbh-booking.has-sticky-bar) .dbh-footer {
        padding-bottom: calc(var(--dbh-stickybar-h, 88px) + 16px);
    }
}

/* The mobile bottom sheet. Below lg, the same panel that sits sticky in
   the desktop sidebar parks off-screen behind everything and slides up
   over the picker when "Review" is tapped — reviewing or removing a
   choice never means scrolling away from the service list to find the
   summary and back again to keep browsing.
 *
 * Scoped to [data-summary-panel], not to .dbh-summary alone. The class is
 * shared with any page that has a running summary, but only a page that
 * also ships the sheet machinery — a bar to open it, a button and backdrop
 * to close it — can ever add .is-open. On a page without that, the bare
 * class parked the summary and its submit button permanently off-screen
 * with no way to reach either. Without the attribute the panel simply
 * stays in flow. */
@media (max-width: 991.98px) {
    .dbh-sheet-backdrop {
        position: fixed;
        inset: 0;
        z-index: 1040;
        background: rgba(26, 16, 35, 0.44);
        opacity: 0;
        transition: opacity var(--dbh-dur-md) var(--dbh-ease-out);
    }

    .dbh-sheet-backdrop[hidden] {
        display: none;
    }

    .dbh-sheet-backdrop.is-visible {
        opacity: 1;
    }

    .dbh-summary[data-summary-panel] {
        position: fixed;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: 1041;
        max-height: 82vh;
        overflow-y: auto;
        /* Keeps a flick at the end of the sheet's own scroll from carrying
           on into the page behind it. */
        overscroll-behavior: contain;
        border-radius: var(--dbh-radius-lg) var(--dbh-radius-lg) 0 0;
        padding: 12px 20px calc(20px + env(safe-area-inset-bottom));
        box-shadow: 0 -8px 24px rgba(26, 16, 35, 0.16);
        visibility: hidden;
        transform: translateY(100%);
        transition:
            transform var(--dbh-dur-lg) var(--dbh-ease-out),
            visibility 0s linear var(--dbh-dur-lg);
    }

    .dbh-summary[data-summary-panel].is-open {
        visibility: visible;
        transform: translateY(0);
        transition: transform var(--dbh-dur-lg) var(--dbh-ease-out);
    }

    .dbh-sheet-handle {
        display: block;
        width: 36px;
        height: 4px;
        margin: 0 auto 14px;
        border-radius: var(--dbh-radius-full);
        background: var(--dbh-line);
    }

    .dbh-sheet-close {
        display: flex;
        flex-shrink: 0;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 44px;
        margin: -6px -6px 0 0;
        border: 0;
        border-radius: var(--dbh-radius-full);
        background: var(--dbh-surface);
        color: var(--dbh-ink-700);
        cursor: pointer;
        touch-action: manipulation;
    }
}

/* Every moving part the picker added, answered in one place.
 *
 * The states themselves still apply — a sheet still opens, a chosen row is
 * still tinted — they just arrive instead of travelling. The sheet keeps
 * its visibility switch, or opening it would leave an invisible panel
 * swallowing taps. */
@media (prefers-reduced-motion: reduce) {
    .dbh-slot.is-updated,
    .dbh-menu__item.is-flashed .dbh-menu__choose,
    .dbh-stickybar {
        animation: none;
    }

    .dbh-menu__panelwrap,
    .dbh-menu__chevron,
    .dbh-menu__check,
    .dbh-picker__row,
    .dbh-sheet-backdrop {
        transition: none;
    }

    .dbh-summary[data-summary-panel],
    .dbh-summary[data-summary-panel].is-open {
        transition: visibility 0s;
    }
}

/* Inline link inside muted body copy — 44px tall so it is a real tap target
   rather than a 38px line of text. */
.dbh-inline-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    /* Without this the link falls back to Bootstrap's #0d6efd, which is the
       one blue on an otherwise aubergine-and-paper page. */
    color: var(--dbh-brand-600);
    font-weight: 500;
}

.dbh-inline-link:hover,
.dbh-inline-link:focus-visible {
    color: var(--dbh-brand-700);
}

/* ── WhatsApp widget ─────────────────────────────────────────────────────
   Floating contact button, rendered only when a number is configured.

   WhatsApp's brand green (#25d366) is a 1.98:1 colour against white, so it
   is used only as a large fill — never behind white text. Anything carrying
   white text uses the darker brand green, which clears 4.5:1. */
:root {
    --dbh-wa-green: #25d366;
    --dbh-wa-deep: #0f7a6c;
}

.dbh-wa {
    position: fixed;
    right: 16px;
    bottom: 16px;
    /* Above the sticky header (1030), below the skip link (1080). */
    z-index: 1040;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 12px;
}

@media (min-width: 576px) {
    .dbh-wa {
        right: 24px;
        bottom: 24px;
    }
}

/* The booking page's sticky summary bar owns the bottom edge on mobile, so
   the widget stands down entirely while a service is chosen. Lifting it
   clear of the bar only moved the collision up into the add-on list, where
   it hid the "+£30.00" prices and — because it paints over the row — made
   the add-on beneath it impossible to tick.

   Standing down is only defensible because the chat route survives it: the
   booking footer carries an inline "Need help booking?" WhatsApp link that
   sits in the flow and cannot overlap anything, and the header keeps a
   tap-to-call button. A floating button that covers the form it is meant
   to support is worse than no floating button. */
@media (max-width: 991.98px) {
    .dbh-booking.has-sticky-bar ~ * .dbh-wa,
    body:has(.dbh-booking.has-sticky-bar) .dbh-wa {
        display: none;
    }
}

.dbh-wa__toggle {
    /* Anchors the pulse ring and the absolutely-positioned icon pair. */
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    padding: 0;
    border: 0;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-wa-green);
    color: #fff;
    font-size: 1.6rem;
    cursor: pointer;
    box-shadow: 0 6px 20px rgba(18, 121, 107, 0.35);
    transition:
        transform var(--dbh-dur-sm) var(--dbh-ease-out),
        box-shadow var(--dbh-dur-sm) var(--dbh-ease-out),
        background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-wa__toggle:hover {
    background: #1ebe57;
    box-shadow: 0 8px 26px rgba(18, 121, 107, 0.45);
}

/* A resting pulse draws the eye once without becoming a distraction. It is
   purely decorative, so it is dropped entirely under reduced motion. */
.dbh-wa__toggle::after {
    content: '';
    position: absolute;
    /* Behind the icons, which are themselves positioned. */
    z-index: -1;
    width: 56px;
    height: 56px;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-wa-green);
    opacity: 0.45;
    animation: dbh-wa-pulse 2.4s var(--dbh-ease-out) infinite;
    pointer-events: none;
}

@keyframes dbh-wa-pulse {
    0% { transform: scale(1); opacity: 0.45; }
    70% { transform: scale(1.6); opacity: 0; }
    100% { transform: scale(1.6); opacity: 0; }
}

/* Icon crossfade between the chat and close states. */
.dbh-wa__icon {
    position: absolute;
    display: block;
    transition:
        opacity var(--dbh-dur-sm) var(--dbh-ease-out),
        transform var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-wa__icon--close,
.dbh-wa__toggle[aria-expanded='true'] .dbh-wa__icon {
    opacity: 0;
    transform: rotate(-90deg) scale(0.6);
}

.dbh-wa__toggle[aria-expanded='true'] .dbh-wa__icon--close {
    opacity: 1;
    transform: rotate(0) scale(1);
    font-size: 1.25rem;
}

.dbh-wa__toggle[aria-expanded='true']::after {
    animation: none;
    opacity: 0;
}

/* The panel. */
.dbh-wa__panel {
    width: min(310px, calc(100vw - 32px));
    overflow: hidden;
    border-radius: var(--dbh-radius-lg);
    background: #fff;
    box-shadow: 0 12px 40px rgba(26, 16, 35, 0.22);
    transform-origin: bottom right;
    animation: dbh-wa-in var(--dbh-dur-md, 220ms) var(--dbh-ease-out);
}

@keyframes dbh-wa-in {
    from { opacity: 0; transform: translateY(8px) scale(0.96); }
    to { opacity: 1; transform: translateY(0) scale(1); }
}

.dbh-wa__head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    background: var(--dbh-wa-deep);
    color: #fff;
}

.dbh-wa__avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border-radius: var(--dbh-radius-full);
    background: rgba(255, 255, 255, 0.18);
    font-size: 1.25rem;
}

.dbh-wa__ident {
    display: flex;
    flex-direction: column;
    min-width: 0;
    margin-right: auto;
}

.dbh-wa__name {
    font-family: var(--dbh-font-display);
    font-weight: 600;
    font-size: 0.9375rem;
}

.dbh-wa__status {
    font-size: 0.75rem;
    /* Not rgba white: a translucent white on this green drops under 4.5:1.
       This tint measures 4.67:1 against --dbh-wa-deep. */
    color: #e4f6f2;
}

.dbh-wa__close {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    margin-right: -10px;
    padding: 0;
    border: 0;
    background: none;
    color: #fff;
    font-size: 0.9375rem;
    cursor: pointer;
    opacity: 0.85;
}

.dbh-wa__close:hover {
    opacity: 1;
}

/* The faint tiled texture of a WhatsApp thread, without shipping an image. */
.dbh-wa__body {
    padding: 18px 16px;
    background:
        radial-gradient(circle at 20% 30%, rgba(18, 121, 107, 0.05) 1px, transparent 1px),
        var(--dbh-paper);
    background-size: 22px 22px;
}

.dbh-wa__bubble {
    position: relative;
    margin: 0;
    padding: 12px 14px;
    border-radius: 4px 14px 14px 14px;
    background: #fff;
    box-shadow: var(--dbh-shadow-sm);
    font-size: 0.9375rem;
    line-height: 1.55;
    color: var(--dbh-ink-700);
}

.dbh-wa__cta {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 52px;
    padding: 14px 16px;
    background: var(--dbh-wa-deep);
    color: #fff;
    font-family: var(--dbh-font-sans);
    font-weight: 600;
    font-size: 0.9375rem;
    text-decoration: none;
    transition: background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-wa__cta:hover,
.dbh-wa__cta:focus {
    background: #0b6357;
    color: #fff;
}

@media (prefers-reduced-motion: reduce) {
    .dbh-wa__toggle::after {
        animation: none;
        opacity: 0;
    }

    .dbh-wa__panel {
        animation: none;
    }

    .dbh-wa__icon {
        transition: none;
    }
}

/* ── Back-to-top ───────────────────────────────────────────────────────
   Visible by default (see the partial's own comment): the scroll-triggered
   hide/reveal below only applies once initScrollTop() has marked <html> as
   ready, so a visitor without JS gets a permanently-present, working link
   rather than one stuck invisible. */
.dbh-totop {
    position: fixed;
    left: 16px;
    bottom: 16px;
    z-index: 1040;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-paper);
    color: var(--dbh-brand-600);
    font-size: 1.125rem;
    text-decoration: none;
    box-shadow: 0 6px 18px rgba(26, 16, 35, 0.14);
    transition:
        opacity var(--dbh-dur-sm) var(--dbh-ease-out),
        transform var(--dbh-dur-sm) var(--dbh-ease-out),
        box-shadow var(--dbh-dur-sm) var(--dbh-ease-out),
        background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-totop:hover,
.dbh-totop:focus-visible {
    background: var(--dbh-brand-600);
    color: #fff;
    box-shadow: 0 8px 22px rgba(26, 16, 35, 0.22);
}

@media (min-width: 576px) {
    .dbh-totop {
        left: 24px;
        bottom: 24px;
    }
}

/* Same collision this codebase already avoids for the WhatsApp widget: the
   booking page's sticky summary bar owns the bottom edge on mobile, and a
   floating button sitting on top of the form it is meant to support is
   worse than no floating button. */
@media (max-width: 991.98px) {
    .dbh-booking.has-sticky-bar ~ * .dbh-totop,
    body:has(.dbh-booking.has-sticky-bar) .dbh-totop {
        display: none;
    }
}

/* Hidden until scrolled — only once JS is confirmed running (see comment
   above). Opacity/pointer-events rather than `hidden`, so the fade is
   animatable and focus never lands on an invisible control mid-transition. */
.js-totop-ready .dbh-totop {
    opacity: 0;
    pointer-events: none;
    transform: translateY(8px);
}

.js-totop-ready .dbh-totop.is-visible {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
    .dbh-totop {
        transition: opacity var(--dbh-dur-sm) linear;
    }

    .js-totop-ready .dbh-totop {
        transform: none;
    }
}

/* ── Space rental: duration + payment-type selectors ─────────────────────
   Replaces the old per-space rate <select>: duration is chosen once for the
   whole booking, so it is a small set of radio pills rather than a dropdown
   per row. */
/* ── Choice cards ───────────────────────────────────────────────────────
   The duration and payment radios on the booking page. Bare pills gave a
   label and nothing else, so "Daily / Weekly / Monthly" made the visitor
   look back up at the rate list to find out what each one cost. Each
   choice now carries its own supporting figure, and the selected one is
   marked by a tick rather than by colour alone. */
.dbh-choices {
    display: grid;
    /* Equal columns that collapse to a single one when they can no longer
       hold their content, so three durations tile on a laptop and stack on
       a phone with no breakpoint to maintain. */
    grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
    gap: 10px;
    margin-top: 8px;
}

/* Payment options carry a sentence each, so they always stack. */
.dbh-choices--stack {
    grid-template-columns: 1fr;
}

.dbh-choice {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    padding: 12px 14px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-paper);
    cursor: pointer;
    transition:
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        box-shadow var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-choice input {
    /* Kept in the accessibility tree and keyboard-operable, not display:none —
       only visually hidden, so a screen reader still gets a real radio. */
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.dbh-choice__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1 1 auto;
}

.dbh-choice__label {
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.3;
    color: var(--dbh-ink-900);
}

.dbh-choice__meta {
    font-size: 0.8125rem;
    line-height: 1.35;
    color: var(--dbh-ink-700);
}

/* The tick reserves its space at all times, so selecting a choice cannot
   reflow the row it sits in. */
.dbh-choice__tick {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    border: 1px solid var(--dbh-ink-300);
    border-radius: 50%;
    color: #fff;
    background: transparent;
    font-size: 0.75rem;
    transition:
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        border-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-choice__tick > i {
    opacity: 0;
    transition: opacity var(--dbh-dur-sm) var(--dbh-ease-out);
}

@media (hover: hover) {
    .dbh-choice:not(.is-disabled):hover {
        border-color: var(--dbh-brand-200);
        background: #fff;
    }
}

.dbh-choice:has(input:checked) {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-50);
    box-shadow: var(--dbh-shadow-sm);
}

.dbh-choice:has(input:checked) .dbh-choice__label {
    color: var(--dbh-brand-700);
}

.dbh-choice:has(input:checked) .dbh-choice__tick {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-600);
}

.dbh-choice:has(input:checked) .dbh-choice__tick > i {
    opacity: 1;
}

.dbh-choice:has(input:focus-visible) {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: 2px;
}

/* A duration the space is not offered at. Still readable — it explains
   why it cannot be picked — but not selectable. */
.dbh-choice.is-disabled {
    background: var(--dbh-surface);
    cursor: not-allowed;
    opacity: 0.7;
}

.dbh-choice.is-disabled .dbh-choice__label {
    color: var(--dbh-ink-700);
}

@media (prefers-reduced-motion: reduce) {
    .dbh-choice,
    .dbh-choice__tick,
    .dbh-choice__tick > i {
        transition: none;
    }
}

/* The read-only per-space price, replacing the old rate <select>. It is a
   figure, not a control, so it does not need a 44px target of its own —
   the label overlay already makes the whole card tappable. */
.dbh-picker__rate {
    flex: 0 0 auto;
}

.dbh-picker__rate span {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    font-family: var(--dbh-font-display);
    font-weight: 600;
    color: var(--dbh-ink-900);
    white-space: nowrap;
}

/* ── The chosen space, on the booking page ──────────────────────────────
   Not a picker: the space arrived on the URL, so this states what is being
   booked and what it costs. It replaces a single joined string of rates
   ("£150.00/day · £800.00/week · …") that could not wrap sensibly — at
   375px it either overflowed or broke mid-figure. Each rate is its own
   item now, so the row reflows to a column on a phone and the chosen
   duration can be marked. */
.dbh-spacepick {
    display: grid;
    gap: 14px;
    padding: 16px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-lg);
    background: var(--dbh-paper);
    box-shadow: var(--dbh-shadow-sm);
}

.dbh-spacepick__head {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.dbh-spacepick__icon {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--dbh-brand-50);
    color: var(--dbh-brand-600);
    font-size: 1.125rem;
}

.dbh-spacepick__ident {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.dbh-spacepick__name {
    font-family: var(--dbh-font-display);
    font-size: 1.0625rem;
    font-weight: 600;
    line-height: 1.3;
    color: var(--dbh-ink-900);
    /* Long names ("Hair Dressing Chair For Rent") wrap rather than
       stretching the card past the viewport. */
    overflow-wrap: anywhere;
}

/* Only shown once there is something to say — a availability warning. It
   carries its own icon so colour is never the only signal. */
.dbh-spacepick__state {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--dbh-warn-ink);
}

.dbh-spacepick__state[hidden] {
    display: none;
}

.dbh-spacepick__state::before {
    content: '\f332'; /* bi-exclamation-circle-fill */
    font-family: 'bootstrap-icons';
    font-size: 0.75rem;
    line-height: 1;
    flex: 0 0 auto;
}

.dbh-spacepick__rates {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Each rate is a chip so three of them tile onto one line on a laptop and
   stack into a readable column on a phone, instead of one long line that
   had to be truncated or scrolled. */
.dbh-spacepick__rate {
    display: flex;
    align-items: baseline;
    gap: 5px;
    flex: 1 1 auto;
    padding: 8px 12px;
    border: 1px solid var(--dbh-line-soft);
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-surface);
    transition:
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        color var(--dbh-dur-sm) var(--dbh-ease-out);
}

/* The duration actually chosen, so the figure being charged is obvious
   among the three on offer. */
.dbh-spacepick__rate.is-active {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-50);
}

/* Dimmed rather than hidden: the full menu stays readable, but the two
   that do not apply stop competing with the one that does. */
.dbh-spacepick__rates.has-active .dbh-spacepick__rate:not(.is-active) {
    opacity: 0.55;
}

.dbh-spacepick__amount {
    font-family: var(--dbh-font-display);
    font-size: 1rem;
    font-weight: 600;
    color: var(--dbh-ink-900);
    white-space: nowrap;
}

.dbh-spacepick__per {
    font-size: 0.8125rem;
    color: var(--dbh-ink-700);
    white-space: nowrap;
}

/* Below 420px the three chips share a row too tightly to read, so each
   takes the full width and the amount sits opposite its unit. */
@media (max-width: 420px) {
    .dbh-spacepick__rates {
        gap: 6px;
    }

    .dbh-spacepick__rate {
        flex: 1 1 100%;
        justify-content: space-between;
    }
}

@media (prefers-reduced-motion: reduce) {
    .dbh-spacepick__rate {
        transition: none;
    }
}

/* ── Service catalogue ──────────────────────────────────────────────────
   The public /services browse page, and the filtered price list at
   /services/category/* and /services/style/* that it opens into.

   Browse leads with four photographed department cards, then a ruled index
   of every style carrying its price spread and duration — enough to
   compare two styles without opening either. The list pages below it keep
   the sticky filter bar and collapsible groups. */

/* Menu hero. A split band — the numbers that decide whether to keep
   reading on one side, a real photograph on the other. Deliberately not
   the home page's scrimmed full-bleed: the two pages share a language,
   not a layout. */
.dbh-menuhero {
    padding-block: 28px 40px;
    background: var(--dbh-paper);
    border-bottom: 1px solid var(--dbh-line-soft);
}

@media (min-width: 768px) {
    .dbh-menuhero {
        padding-block: 32px 64px;
    }
}

.dbh-menuhero__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 28px;
    align-items: center;
    margin-top: 20px;
}

@media (min-width: 992px) {
    .dbh-menuhero__grid {
        grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr);
        gap: 56px;
    }
}

.dbh-menuhero__body {
    min-width: 0;
}

.dbh-menuhero__title {
    margin: 10px 0 0;
}

.dbh-menuhero__lead {
    max-width: 46ch;
    margin: 16px 0 0;
}

/* 4:3 on a phone — a tall crop here would push the lead text below the
   fold before anything has been read. */
.dbh-menuhero__media {
    position: relative;
    margin: 0;
    overflow: hidden;
    border-radius: var(--dbh-radius-lg);
    background: var(--dbh-ink-100);
    aspect-ratio: 4 / 3;
}

@media (min-width: 992px) {
    .dbh-menuhero__media {
        aspect-ratio: 4 / 5;
    }
}

.dbh-menuhero__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 30%;
}

/* ── Department cards ───────────────────────────────────────────────────
   The only photography on this page, and the page's focal grid. Each card
   is a single link: one target, one tap, no nested controls to miss. */
.dbh-depts {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}

@media (min-width: 576px) {
    .dbh-depts {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 1200px) {
    .dbh-depts {
        grid-template-columns: repeat(4, minmax(0, 1fr));
        gap: 20px;
    }
}

/* Below sm the card lies on its side: a square photograph beside the text
   rather than above it. Stacked, four cards ran to 1590px — four phone
   screens of scrolling before the comparison table below them is even
   reachable — for four choices. On its side each card is ~120px and all
   four are visible at once, which is what a chooser needs to be. */
.dbh-dept {
    min-width: 0;
    display: grid;
    grid-template-columns: 116px minmax(0, 1fr);
    align-items: stretch;
    overflow: hidden;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-lg);
    background: var(--dbh-paper);
    text-decoration: none;
    color: inherit;
    transition:
        border-color var(--dbh-dur-md) var(--dbh-ease-out),
        box-shadow var(--dbh-dur-md) var(--dbh-ease-out);
}

@media (min-width: 576px) {
    .dbh-dept {
        display: flex;
        flex-direction: column;
    }
}

@media (hover: hover) {
    .dbh-dept:hover {
        border-color: var(--dbh-brand-200);
        box-shadow: var(--dbh-shadow-md);
    }
}

.dbh-dept:focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: 2px;
}

/* aspect-ratio only from sm up. On the side-by-side phone layout the media
   takes its height from the card's own row instead, so the photograph can
   never be the thing that decides how tall the card is. */
.dbh-dept__media {
    position: relative;
    display: block;
    overflow: hidden;
    background: var(--dbh-ink-100);
}

@media (min-width: 576px) {
    .dbh-dept__media {
        aspect-ratio: 4 / 3;
    }
}

/* Absolutely positioned so the photograph contributes no height of its
   own — the ratio box governs, and a 800px-wide source cannot stretch
   the card. */
.dbh-dept__media img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--dbh-dur-lg) var(--dbh-ease-out);
}

@media (hover: hover) {
    .dbh-dept:hover .dbh-dept__media img {
        transform: scale(1.04);
    }
}

.dbh-dept__body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    flex: 1;
    gap: 5px;
    padding: 14px;
}

@media (min-width: 576px) {
    .dbh-dept__body {
        gap: 6px;
        padding: 16px;
    }
}

.dbh-dept__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    /* nowrap plus min-width: 0 on the name — the price must stay on the
       title's line, and it is the name that should ellipsis, not the
       figure someone is scanning for. */
    flex-wrap: nowrap;
    gap: 12px;
}

.dbh-dept__name {
    min-width: 0;
    font-family: var(--dbh-font-display);
    font-size: 1.125rem;
    font-weight: 600;
    line-height: 1.25;
    color: var(--dbh-ink-900);
}

.dbh-dept__price {
    flex: none;
    font-family: var(--dbh-font-display);
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--dbh-brand-600);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.dbh-dept__from {
    margin-right: 3px;
    font-family: var(--dbh-font-sans);
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--dbh-ink-muted);
}

.dbh-dept__count {
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

.dbh-dept__styles {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 6px;
}

/* The style tags are a widescreen nicety. Beside a photograph on a phone
   there is no room to say more than "Locs / Sisterlocks …", which tells a
   visitor nothing, and the filterable style index directly below answers
   the same question — what does Hair cover — in full. Dropping them also
   evens the four cards to a single height. */
@media (max-width: 575.98px) {
    .dbh-dept__styles {
        display: none;
    }
}

.dbh-dept__style {
    max-width: 100%;
    padding: 3px 9px;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-surface);
    font-size: 0.75rem;
    line-height: 1.4;
    color: var(--dbh-ink-700);
    /* Style names run long ("Knotless (Box/Twist) / Ponytail Braids …");
       a tag that wraps to three lines stops being a tag. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dbh-dept__style--more {
    background: transparent;
    color: var(--dbh-ink-muted);
    padding-inline: 2px;
}

.dbh-dept__go {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: auto;
    padding-top: 10px;
    font-family: var(--dbh-font-display);
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--dbh-brand-600);
}

@media (min-width: 576px) {
    .dbh-dept__go {
        padding-top: 14px;
        font-size: 0.875rem;
    }
}

.dbh-dept__go i {
    transition: transform var(--dbh-dur-md) var(--dbh-ease-out);
}

@media (hover: hover) {
    .dbh-dept:hover .dbh-dept__go i {
        transform: translateX(3px);
    }
}

/* ── Style index ────────────────────────────────────────────────────
   The comparison layer: one row per style, carrying its price spread and
   how long its treatments run. A single column at every width — this is a
   table people read down, and side-by-side columns would break the
   scanning order the comparison depends on.

   Base rules first, breakpoint overrides at the end: these selectors all
   share a specificity, so an override placed above the rule it modifies
   silently loses. */

.dbh-styletools {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: 20px;
}

/* Full container width. The meta columns widen with the container rather
   than the name track absorbing all of it — otherwise the price drifts
   half a screen from the style it belongs to and the row stops reading
   as a pair. See the breakpoint block at the end. */
.dbh-styleindex {
    margin: 0;
    /* The floating WhatsApp button is fixed to the bottom-right corner and
       sits above this list, so the last rows need clearance or the button
       paints over their price/arrow. */
    padding: 0 0 88px;
    list-style: none;
    border-top: 1px solid var(--dbh-line);
}

.dbh-styleindex__item {
    border-bottom: 1px solid var(--dbh-line);
}

/* Below md the row is two lines — name and price on the first, the count
   and duration together beneath — because three columns inside 320px
   leaves the price wrapping mid-figure. Stacking name, count and duration
   on separate lines instead ran the 17-row index to 1960px of phone.
   The arrow spans both lines so it stays optically centred. */
.dbh-stylerow {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto 28px;
    grid-template-areas:
        'name  price go'
        'meta  meta  go';
    align-items: center;
    gap: 4px 14px;
    /* Clears 44px comfortably: two lines of text plus 24px of padding. */
    padding: 12px 4px;
    text-decoration: none;
    color: inherit;
    transition: background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-stylerow:focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: -2px;
    border-radius: var(--dbh-radius-sm);
}

.dbh-stylerow__name {
    grid-area: name;
    min-width: 0;
    font-family: var(--dbh-font-display);
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--dbh-ink-900);
    transition: color var(--dbh-dur-sm) var(--dbh-ease-out);
    /* Names like "Boho Braids (Knotless/Twist/Box Braids)" contain no
       break opportunity a browser will take — a slash is not one — so at
       320px the word ran straight through the price beside it. */
    overflow-wrap: anywhere;
}

.dbh-stylerow__meta {
    grid-area: meta;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 12px;
}

.dbh-stylerow__count {
    grid-area: count;
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

.dbh-stylerow__time {
    grid-area: time;
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

.dbh-stylerow__price {
    grid-area: price;
    text-align: right;
    font-family: var(--dbh-font-display);
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--dbh-ink-900);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.dbh-stylerow__go {
    grid-area: go;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--dbh-radius-full);
    color: var(--dbh-ink-400);
    font-size: 0.875rem;
    transition:
        transform var(--dbh-dur-md) var(--dbh-ease-out),
        color var(--dbh-dur-md) var(--dbh-ease-out);
}

/* Only present when the business has uploaded a photo for at least one
   style; the empty span holds the column open for the ones it has not. */
.dbh-stylerow__thumb {
    grid-area: thumb;
    align-self: center;
    width: 40px;
    height: 40px;
    overflow: hidden;
    border-radius: var(--dbh-radius-sm);
    background: var(--dbh-ink-100);
}

.dbh-stylerow__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.dbh-styleindex--photos .dbh-stylerow {
    grid-template-columns: 40px minmax(0, 1fr) auto 28px;
    grid-template-areas:
        'thumb name  price go'
        'thumb meta  meta  go';
}

/* From md the meta wrapper dissolves with display: contents and its two
   children become columns of the row's own grid. Fixed track widths, not
   auto: every row is a separate grid, so only a fixed width makes the
   counts, durations and prices line up down the page — which is the
   entire point of a comparison table. */
@media (min-width: 768px) {
    .dbh-styletools {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
        gap: 20px;
    }

    .dbh-stylerow {
        grid-template-columns: minmax(0, 1fr) 118px 148px 116px 28px;
        grid-template-areas: 'name count time price go';
        align-items: baseline;
        gap: 16px;
        padding-block: 16px;
    }

    .dbh-styleindex--photos .dbh-stylerow {
        grid-template-columns: 40px minmax(0, 1fr) 118px 148px 116px 28px;
        grid-template-areas: 'thumb name count time price go';
    }

    .dbh-stylerow__meta {
        display: contents;
    }

    .dbh-stylerow__name {
        font-size: 1rem;
    }

    .dbh-stylerow__time {
        color: var(--dbh-ink-700);
    }

    .dbh-stylerow__price {
        font-size: 0.9375rem;
    }

    .dbh-stylerow__go {
        align-self: center;
    }
}

/* Now the index runs the full container, the extra width is given to the
   data columns rather than to the name track. Left as one wide 1fr, the
   price ended up ~700px from the style it priced, which is the distance
   at which a ruled row stops reading as a single line. */
@media (min-width: 1200px) {
    .dbh-stylerow {
        grid-template-columns: minmax(0, 1fr) 168px 210px 150px 28px;
        gap: 24px;
    }

    .dbh-styleindex--photos .dbh-stylerow {
        grid-template-columns: 40px minmax(0, 1fr) 168px 210px 150px 28px;
    }
}

@media (hover: hover) {
    .dbh-stylerow:hover {
        background: var(--dbh-surface);
    }

    .dbh-stylerow:hover .dbh-stylerow__name {
        color: var(--dbh-brand-600);
    }

    .dbh-stylerow:hover .dbh-stylerow__go {
        color: var(--dbh-brand-600);
        transform: translateX(3px);
    }
}

/* ── Menu help ──────────────────────────────────────────────────────────
   The page's own closing note. The footer already says "book now", so
   this answers the other thing a 114-line menu provokes: not knowing
   which line to pick. */
.dbh-menuhelp {
    display: flex;
    flex-direction: column;
    gap: 20px;
    padding: 24px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-lg);
    background: var(--dbh-paper);
}

@media (min-width: 992px) {
    .dbh-menuhelp {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
        gap: 40px;
        padding: 32px;
    }
}

.dbh-menuhelp__body {
    min-width: 0;
}

.dbh-menuhelp__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

@media (max-width: 400px) {
    .dbh-menuhelp__actions {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (min-width: 992px) {
    .dbh-menuhelp__actions {
        flex: none;
        flex-wrap: nowrap;
    }
}

/* Sticky filter bar. Sits directly under the header so changing filter
   never costs a scroll back to the top. */
.dbh-filterbar {
    position: sticky;
    top: 0;
    z-index: 1020;
    padding-block: 10px;
    background: rgba(251, 249, 246, 0.92);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--dbh-line-soft);
}

.dbh-filterbar__inner {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

@media (min-width: 992px) {
    .dbh-filterbar__inner {
        flex-direction: row;
        align-items: center;
        gap: 16px;
    }
}

/* The chip row scrolls sideways on a phone rather than wrapping to two
   lines and pushing the menu down the page. */
.dbh-filters--bar {
    flex-wrap: nowrap;
    margin-top: 0;
    overflow-x: auto;
    scrollbar-width: none;
}

.dbh-filters--bar::-webkit-scrollbar {
    display: none;
}

.dbh-filters--bar .dbh-chip {
    flex: none;
}

@media (min-width: 992px) {
    .dbh-filters--bar {
        flex-wrap: wrap;
        margin-left: auto;
        overflow-x: visible;
    }
}

/* Search. */
.dbh-search {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1;
    min-width: 0;
}

.dbh-search > .bi-search {
    position: absolute;
    left: 14px;
    color: var(--dbh-ink-500);
    pointer-events: none;
}

/* 16px font size is deliberate: anything smaller makes iOS zoom the page
   on focus, which on this page means zooming into the sticky bar. */
.dbh-search__input {
    width: 100%;
    min-height: 44px;
    padding: 10px 40px 10px 40px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-paper);
    font-family: var(--dbh-font-sans);
    font-size: 1rem;
    color: var(--dbh-ink-900);
}

.dbh-search__input::placeholder {
    color: var(--dbh-ink-muted);
}

.dbh-search__input:focus {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: 1px;
    border-color: transparent;
}

/* The native search clear affordance is inconsistent across browsers, so
   the page ships its own and hides Safari's. */
.dbh-search__input::-webkit-search-cancel-button {
    display: none;
}

.dbh-search__clear {
    position: absolute;
    right: 4px;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--dbh-ink-muted);
    cursor: pointer;
}

.dbh-search__clear:hover {
    color: var(--dbh-ink-900);
}

/* Menu toolbar. */
.dbh-menu__toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
}

/* Grouped list. */
.dbh-group {
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-lg);
    background: var(--dbh-paper);
    overflow: hidden;
}

.dbh-group + .dbh-group {
    margin-top: 12px;
}

.dbh-group[hidden] {
    display: none;
}

/* A full-width button: the whole header row is the tap target, which on a
   phone is the difference between hitting it and missing it. */
.dbh-group__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    min-height: 56px;
    padding: 14px 16px;
    border: 0;
    background: transparent;
    text-align: left;
    cursor: pointer;
}

.dbh-group__head:hover {
    background: var(--dbh-surface);
}

.dbh-group__head:focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: -2px;
}

.dbh-group__heading {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.dbh-group__count {
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

.dbh-group__chev {
    flex: none;
    color: var(--dbh-ink-500);
    transition: transform var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-group__head[aria-expanded='false'] .dbh-group__chev {
    transform: rotate(-90deg);
}

.dbh-group__body {
    padding: 0 16px 8px;
}

/* Reclaim a little width on a phone: the row already insets its own hover
   band by 12px, so the group's 16px on top of the card gutter left the
   names with noticeably less room than the heading above them. */
@media (max-width: 575.98px) {
    .dbh-group__body {
        padding-inline: 12px;
    }
}

.dbh-group__head[aria-expanded='false'] + .dbh-group__body {
    display: none;
}

.dbh-group__desc {
    margin-top: 0;
    margin-bottom: 12px;
}

/* Service row. Stacks on a phone with the price above the button, and
   becomes a single row from sm up. */
.dbh-svclist {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* On a phone the row is a two-column grid: the name and its price run down
   the left, the Book button sits in the right column beside them. The
   button used to take a full line of its own under the meta, which turned
   six services into a tall column of slabs and pushed the sixth off the
   first screen — while the space to the right of a short name like
   "Eyebrow tint" sat empty. From sm up it becomes a single flex row. */
.dbh-svc {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: 12px;
    /* Negative inline margin with matching padding, so the hover tint reads
       as a band across the row rather than a box floating inside it. */
    margin: 0 -12px;
    padding: 14px 12px;
    border-radius: var(--dbh-radius-md);
    transition: background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

/* The dividing rule is drawn inset by a pseudo-element rather than as a
   border: a border would run the full width and sit under the rounded
   corners of the hover band. Skipped on the first row, which needs no
   rule above it. */
.dbh-svc + .dbh-svc::before {
    content: '';
    position: absolute;
    top: 0;
    left: 12px;
    right: 12px;
    height: 1px;
    background: var(--dbh-line-soft);
}

.dbh-svc[hidden] {
    display: none;
}

@media (hover: hover) {
    .dbh-svc:hover {
        background: var(--dbh-surface);
    }
}

@media (min-width: 576px) {
    .dbh-svc {
        display: flex;
        flex-direction: row;
        align-items: center;
        gap: 16px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .dbh-svc {
        transition: none;
    }
}

.dbh-svc__main {
    min-width: 0;
    flex: 1;
    grid-column: 1;
}

.dbh-svc__name {
    margin: 0;
    font-family: var(--dbh-font-display);
    font-size: 1rem;
    font-weight: 600;
    color: var(--dbh-ink-900);
    line-height: 1.35;
}

.dbh-svc__desc {
    margin: 4px 0 0;
    font-size: 0.875rem;
    color: var(--dbh-ink-muted);
}

.dbh-svc__meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin: 6px 0 0;
    font-size: 0.9375rem;
    color: var(--dbh-ink-700);
}

@media (min-width: 576px) {
    .dbh-svc__meta {
        margin-top: 8px;
    }
}

/* The price leads: it is what the eye runs down the column comparing, so
   it is the largest thing in the row after the name. */
.dbh-svc__price {
    font-family: var(--dbh-font-display);
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.2;
    color: var(--dbh-ink-900);
}

/* Duration is supporting detail, so it is set as a quiet chip rather than
   another run of text competing with the price beside it. */
.dbh-svc__time {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border-radius: 999px;
    background: var(--dbh-surface);
    font-size: 0.8125rem;
    color: var(--dbh-ink-700);
    white-space: nowrap;
}

/* Decorative (the duration is spelled out beside it), but kept at text
   contrast anyway so it does not read as a rendering fault. */
.dbh-svc__time > i {
    font-size: 0.75rem;
    color: var(--dbh-ink-700);
}

/* Quiet by default rather than solid brand: a long category repeats this
   button once per service, and a column of filled blocks competes with
   the names and prices that are the reason to read the list at all. It
   fills in on hover/focus, so the affordance is unmistakable at the
   moment of use without shouting for the whole scroll. */
.dbh-svc__book {
    flex: none;
    justify-content: center;
    /* Sits in the grid's second column on a phone, spanning both the name
       and meta rows so it stays vertically centred against them. */
    grid-column: 2;
    grid-row: 1 / -1;
    /* 44px minimum tap target even though the label is two words. */
    min-height: 44px;
    min-width: 76px;
    background: transparent;
    border-color: var(--dbh-brand-200);
    color: var(--dbh-brand-700);
    box-shadow: none;
}

@media (hover: hover) {
    .dbh-svc__book:hover {
        background: var(--dbh-brand-600);
        border-color: var(--dbh-brand-600);
        color: #fff;
    }
}

.dbh-svc__book:focus-visible {
    background: var(--dbh-brand-600);
    border-color: var(--dbh-brand-600);
    color: #fff;
}

/* On a phone there is no hover to reveal the fill, so the button carries a
   soft tint from the start — readable as tappable without being the solid
   slab that used to run down the whole list. */
@media (max-width: 575.98px) {
    .dbh-svc__book {
        padding-inline: 14px;
        background: var(--dbh-brand-50);
        border-color: var(--dbh-brand-200);
        color: var(--dbh-brand-700);
    }

    .dbh-svc__book:active {
        background: var(--dbh-brand-600);
        border-color: var(--dbh-brand-600);
        color: #fff;
    }
}

@media (min-width: 576px) {
    .dbh-svc__book {
        grid-column: auto;
        grid-row: auto;
        width: auto;
    }
}

/* Add-ons attached to a style. Read-only here — they are chosen in the
   booking flow, this just says they exist and what they cost. */
.dbh-group__addons {
    margin-top: 4px;
    padding: 12px 14px 14px;
    border-radius: var(--dbh-radius-md);
    background: var(--dbh-surface);
}

.dbh-group__addons-title {
    margin: 0 0 8px;
    font-family: var(--dbh-font-display);
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--dbh-ink-900);
}

.dbh-group__addons-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.dbh-group__addons-list li {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-size: 0.875rem;
    color: var(--dbh-ink-700);
}

.dbh-group__addons-price {
    flex: none;
    font-weight: 600;
    color: var(--dbh-ink-900);
}

/* The sticky filter bar owns the top edge, so anchored groups must clear
   both it and the header. */
.dbh-catalog [id] {
    scroll-margin-top: 152px;
}

/* ── Date picker ──────────────────────────────────────────────────────
   A calendar that can grey out unavailable days, which a native
   <input type="date"> cannot: browsers draw that popup themselves and
   honour only min/max, so every Sunday and every closure still looks
   bookable until the customer picks one and is told otherwise.

   The native input stays in the DOM as the no-JS fallback and the value
   the form actually submits; this is revealed only once the script has
   taken over. */

.dbh-cal {
    position: relative;
}

.dbh-cal__trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    min-height: 48px;
    padding: 12px 14px;
    font-family: var(--dbh-font-sans);
    font-size: 1rem;
    text-align: left;
    color: var(--dbh-ink-900);
    background: var(--dbh-paper);
    border: 1px solid var(--dbh-ink-300);
    border-radius: var(--dbh-radius-md);
    cursor: pointer;
    transition: border-color var(--dbh-dur-sm) var(--dbh-ease-out),
                box-shadow var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-cal__trigger:hover {
    border-color: var(--dbh-ink-400);
}

/* Matches .dbh-field input:focus so the trigger reads as the input it
   replaces rather than as a button. */
.dbh-cal__trigger:focus {
    outline: none;
    border-color: var(--dbh-brand-600);
    box-shadow: 0 0 0 3px var(--dbh-brand-50);
}

.dbh-cal__trigger[aria-expanded='true'] {
    border-color: var(--dbh-brand-600);
}

.dbh-cal__trigger[data-empty='true'] span {
    color: var(--dbh-ink-muted);
}

.dbh-cal__panel {
    position: absolute;
    z-index: 30;
    top: calc(100% + 6px);
    right: 0;
    left: 0;
    /* Spans the field it belongs to (full step width since the date field
       stopped sitting in a half-width column) rather than a fixed 324px —
       that cap dated from when this shared a col-sm-6 with nothing else,
       and left the grid looking squeezed into a corner of the space it
       now has. Still bounded so it cannot overflow a narrow viewport. */
    width: auto;
    max-width: calc(100vw - 32px);
    padding: 14px;
    background: #fff;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-lg);
    box-shadow: var(--dbh-shadow-lg);
    animation: dbh-cal-in var(--dbh-dur-md) var(--dbh-ease-out);
}

@keyframes dbh-cal-in {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .dbh-cal__panel {
        animation: none;
    }
}

.dbh-cal__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 10px;
}

.dbh-cal__month {
    font-family: var(--dbh-font-display);
    font-size: 1rem;
    font-weight: 600;
    color: var(--dbh-ink-900);
}

.dbh-cal__nav {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    color: var(--dbh-ink-700);
    background: var(--dbh-paper);
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-sm);
    cursor: pointer;
}

.dbh-cal__nav:hover:not(:disabled) {
    border-color: var(--dbh-brand-300);
    color: var(--dbh-brand-700);
}

.dbh-cal__nav:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.dbh-cal__dow,
.dbh-cal__grid {
    display: grid;
    /* Monday-first columns. The data behind them is keyed on JS getDay(),
       where 0 is Sunday, so the render offsets by (getDay() + 6) % 7.

       minmax(0, 1fr), never a bare 1fr: a bare 1fr floors each track at
       the cell's min-content width, so on a narrow panel the seven
       columns push wider than the panel instead of shrinking to fit. */
    grid-template-columns: repeat(7, minmax(0, 1fr));
    /* >=6px, so the global :focus-visible ring (outline-offset: 3px) on
       two neighbouring days cannot collide. */
    gap: 6px;
}

.dbh-cal__dow {
    margin-bottom: 6px;
}

.dbh-cal__dow span {
    padding: 4px 0;
    font-size: 0.75rem;
    font-weight: 600;
    text-align: center;
    color: var(--dbh-ink-muted);
}

/* Day cells speak the same visual language as .dbh-time, the slot
   buttons directly below them. */
.dbh-cal__day {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 40px;
    padding: 0;
    font-family: var(--dbh-font-sans);
    font-size: 0.9375rem;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--dbh-ink-700);
    background: var(--dbh-paper);
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-sm);
    cursor: pointer;
    transition: background-color var(--dbh-dur-sm) var(--dbh-ease-out),
                border-color var(--dbh-dur-sm) var(--dbh-ease-out),
                color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-cal__day:hover:not([aria-disabled='true']) {
    border-color: var(--dbh-brand-300);
    color: var(--dbh-brand-700);
}

.dbh-cal__day[aria-pressed='true'] {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-600);
    color: #fff;
}

/* Today, when it is not the selected day. */
.dbh-cal__day[data-today='true']:not([aria-pressed='true']) {
    border-color: var(--dbh-brand-300);
    font-weight: 700;
}

/* aria-disabled rather than the disabled attribute: the cell stays
   focusable so arrow-key users land on it and hear why it cannot be
   picked, which a disabled button would swallow. ink-muted rather than
   ink-500 because this is text and has to clear 4.5:1. */
.dbh-cal__day[aria-disabled='true'] {
    color: var(--dbh-ink-muted);
    background: var(--dbh-surface);
    border-color: var(--dbh-line-soft);
    cursor: not-allowed;
    text-decoration: line-through;
    text-decoration-thickness: 1px;
}

/* Emergency-only: still a normal, clickable cell — no cursor change and
   no line-through, both of which are reserved for aria-disabled='true'
   above. The warning border and flag icon are additive so this reads
   correctly layered under both the pressed and today states below. */
.dbh-cal__day[data-emergency-only='true'] {
    position: relative;
    border-color: #fcd34d;
}

.dbh-cal__day[data-emergency-only='true']:hover {
    border-color: #b45309;
}

.dbh-cal__day-flag {
    position: absolute;
    top: 2px;
    right: 2px;
    font-size: 0.5rem;
    color: var(--dbh-warn-ink);
}

/* Kept legible once the day is also selected: the flag has to survive
   moving onto the solid brand-600 fill the pressed state paints. */
.dbh-cal__day[aria-pressed='true'] .dbh-cal__day-flag {
    color: #fff;
}

.dbh-cal__day--blank {
    background: none;
    border-color: transparent;
    cursor: default;
}

.dbh-cal__key {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 12px 0 0;
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

/* Carries the same strike-through the disabled cells do — the muted fill
   alone is too quiet on white to read as a key. */
.dbh-cal__key-swatch {
    position: relative;
    flex: none;
    width: 16px;
    height: 16px;
    background: var(--dbh-surface);
    border: 1px solid var(--dbh-line);
    border-radius: 4px;
}

.dbh-cal__key-swatch::after {
    content: '';
    position: absolute;
    top: 50%;
    right: 2px;
    left: 2px;
    height: 1px;
    background: var(--dbh-ink-muted);
}

/* No strike-through here — this swatch marks a day that can still be
   picked, so it carries the warning border and icon instead, without the
   "cannot be selected" line the plain swatch above uses. */
.dbh-cal__key-swatch--emergency {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--dbh-paper);
    border-color: #fcd34d;
}

.dbh-cal__key-swatch--emergency::after {
    content: none;
}

.dbh-cal__key-swatch--emergency i {
    font-size: 0.625rem;
    color: var(--dbh-warn-ink);
}

/* No narrow-screen centering override here, deliberately.
   There used to be one — `left: 50%; transform: translateX(-50%)` — from
   when the panel had a fixed 324px width and sat in a half-width column.
   Once the width became `auto` between `left: 0` and `right: 0`, that
   override stopped centring anything: with `right: 0` still in force,
   `left: 50%` resolves the panel to *half* its container, and the seven
   day columns then spilled out past its right edge. The panel already
   spans the full-width date field, so on a phone it needs no help. */

/* ══════════════════════════════════════════════════════════════════════
   HOMEPAGE — EDITORIAL LAYER

   The public shopfront's own components. Everything here composes the
   existing tokens; nothing redefines them, so the rest of the site keeps
   moving in step with this page.

   The through-line is restraint: one accent, generous whitespace, the
   photography doing the persuading. Where a choice was between another
   card and more air, it went to air.
   ══════════════════════════════════════════════════════════════════════ */

/* A centred section head, for the bands that read as editorial chapters
   rather than as a column of content. Capped by measure so a centred
   lead never runs to an unreadable line length. */
.dbh-section-head--center {
    align-items: center;
    text-align: center;
}

.dbh-section-head--center .dbh-measure {
    margin-inline: auto;
}

/* The hairline that sits under an overline on the editorial bands. Purely
   decorative, so it is a pseudo-element rather than markup. */
.dbh-section-head--center .dbh-overline::after {
    content: '';
    display: block;
    width: 32px;
    height: 1px;
    margin: 10px auto 0;
    background: var(--dbh-brand-300);
}

/* ── Brand introduction ───────────────────────────────────────────────
   The "who we are" band. An asymmetric two-column: a serif statement
   against a single portrait, with the live figures underneath. It runs
   on paper rather than surface so it reads as a continuation of the
   hero's calm rather than as the first content block. */
.dbh-intro__statement {
    font-family: var(--dbh-font-serif);
    font-weight: 400;
    font-size: clamp(1.375rem, 1.05rem + 1.5vw, 2rem);
    line-height: 1.3;
    letter-spacing: -0.01em;
    color: var(--dbh-ink-900);
    margin: 0;
    text-wrap: balance;
}

.dbh-intro__body {
    margin: 24px 0 0;
    max-width: 52ch;
}

/* The portrait beside the statement. Tall on desktop so the column has a
   vertical axis to sit against; a calmer 4:3 on a phone, where a tall
   crop would push the statement off-screen entirely. */
.dbh-intro__media {
    position: relative;
    margin: 0;
    border-radius: var(--dbh-radius-lg);
    overflow: hidden;
    background: var(--dbh-ink-100);
    aspect-ratio: 4 / 3;
}

@media (min-width: 992px) {
    .dbh-intro__media {
        aspect-ratio: 4 / 5;
    }
}

.dbh-intro__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ── Featured work ────────────────────────────────────────────────────
   On a phone this is a scroll-snap rail rather than a grid: eight 4:3
   tiles stacked two-up ran to most of a screen height each and buried
   everything below them. Swiping a rail is also how the audience for
   this page already browses beauty work.

   From md up it becomes a real editorial grid, where the first tile
   takes a 2×2 block so the layout has a focal point instead of eight
   equal squares. */
.dbh-worklist {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 74%;
    gap: 12px;
    margin: 0;
    padding: 0 20px 4px;
    list-style: none;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    /* Keeps a flick at the end of the rail from scrolling the page. */
    overscroll-behavior-x: contain;
    scrollbar-width: none;
}

.dbh-worklist::-webkit-scrollbar {
    display: none;
}

/* The rail is edge-to-edge on a phone so a tile can bleed off-screen and
   read as continuing, rather than stopping inside the container's
   gutter. Its own padding restores the alignment. */
@media (max-width: 767.98px) {
    .dbh-worklist {
        margin-inline: calc(50% - 50vw);
    }
}

@media (min-width: 576px) {
    .dbh-worklist {
        grid-auto-columns: 46%;
    }
}

@media (min-width: 768px) {
    .dbh-worklist {
        grid-auto-flow: row;
        /* minmax(0, 1fr), not 1fr: a bare 1fr floors each track at its
           content's min-content width, and these tiles hold 960px-wide
           images — which pulled the four tracks to 568/568/276/276
           instead of four equal columns. */
        grid-template-columns: repeat(4, minmax(0, 1fr));
        grid-auto-columns: auto;
        gap: 16px;
        padding: 0;
        overflow: visible;
    }

    .dbh-worklist > li:first-child {
        grid-column: span 2;
        grid-row: span 2;
    }

    /* With a 2×2 feature leading, the remaining tiles have to pack into a
       whole number of rows or the block ends on a notch. Cell arithmetic
       alone is not enough — the feature's shape blocks placement, so the
       arrangement has to be checked as a layout, not a total.

       Nine tiles — the current count — need no help at all: the feature
       fills rows 1–2 of the first two columns and eight singles fill the
       remaining eight cells exactly. Neither rule below matches, which is
       the point of scoping them by count.

       Eight tiles: the feature fills rows 1–2 of the first two columns,
       six singles fill the rest, and widening the last closes row 3.

       Seven tiles: one fewer single leaves two cells short, which widening
       the last alone cannot fix (it closes one and leaves one). Widening
       the last two fills row 3 exactly.

       All selected on count rather than assumed, so editing $work in
       welcome.blade.php cannot silently reopen the gap:
       :nth-last-child(n):first-child matches only at that exact length. */
    .dbh-worklist > li:nth-last-child(8):first-child ~ li:last-child {
        grid-column: span 2;
    }

    .dbh-worklist > li:nth-last-child(7):first-child ~ li:nth-last-child(-n + 2) {
        grid-column: span 2;
    }
}

.dbh-work {
    position: relative;
    margin: 0;
    height: 100%;
    border-radius: var(--dbh-radius-md);
    overflow: hidden;
    background: var(--dbh-ink-100);
    aspect-ratio: 4 / 3;
    scroll-snap-align: center;
}

/* The two tiles that span extra columns drop their aspect-ratio and take
   their height from the row instead. Left at 4:3 they would size from
   their own doubled width and blow the row out to twice the height of
   its neighbours. */
@media (min-width: 768px) {
    .dbh-worklist > li:first-child .dbh-work,
    .dbh-worklist > li:last-child .dbh-work,
    /* The seven-tile layout widens the second-to-last tile as well, and a
       spanning tile must drop its ratio for the same reason as the others. */
    .dbh-worklist > li:nth-last-child(7):first-child ~ li:nth-last-child(2) .dbh-work {
        aspect-ratio: auto;
    }
}

/* Absolutely positioned so the photograph contributes no height of its
   own. The spanning tiles carry no aspect-ratio and must take their
   height from the grid row; while the image was in flow it sized itself
   from its doubled width instead and forced the row to twice the height
   of its neighbours. */
.dbh-work img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--dbh-dur-lg) var(--dbh-ease-out);
}

@media (hover: hover) {
    .dbh-work:hover img {
        transform: scale(1.05);
    }
}

.dbh-work figcaption {
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    padding: 32px 14px 12px;
    background: linear-gradient(to top, rgba(26, 16, 35, 0.86), transparent);
    color: #fff;
    font-size: 0.8125rem;
    font-weight: 500;
    letter-spacing: 0.01em;
}

/* Tells a touch visitor the rail moves sideways, and disappears once the
   grid takes over. */
.dbh-rail-hint {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 14px 0 0;
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

@media (min-width: 768px) {
    .dbh-rail-hint {
        display: none;
    }
}

/* ── Why choose us ────────────────────────────────────────────────────
   Four claims, no cards. Cards would make this the third bordered grid
   on the page; a rule and generous spacing separate them just as well
   and keep the band quiet. */
.dbh-values {
    display: grid;
    gap: 4px 40px;
    margin: 0;
    padding: 0;
    list-style: none;
}

@media (min-width: 576px) {
    .dbh-values {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 992px) {
    .dbh-values {
        grid-template-columns: repeat(4, 1fr);
    }
}

/* Below sm the icon sits beside the heading rather than above it. Stacked,
   four of these ran to over a thousand pixels of phone for four short
   claims; paired, the same content scans in a glance. */
.dbh-value {
    display: grid;
    grid-template-columns: 40px 1fr;
    gap: 0 16px;
    padding: 24px 0;
    border-top: 1px solid var(--dbh-line);
}

@media (min-width: 576px) {
    .dbh-value {
        display: block;
        padding: 28px 0;
    }
}

.dbh-value__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-brand-50);
    color: var(--dbh-brand-600);
    font-size: 1.125rem;
}

.dbh-value__title {
    /* Optically centred against the 40px icon on the paired layout. */
    margin: 8px 0 0;
    font-family: var(--dbh-font-display);
    font-size: 1.0625rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--dbh-ink-900);
}

.dbh-value__body {
    grid-column: 2;
    margin: 8px 0 0;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: var(--dbh-ink-700);
}

@media (min-width: 576px) {
    .dbh-value__title {
        margin-top: 18px;
    }
}

/* ── Testimonials ─────────────────────────────────────────────────────
   A horizontal scroll rail, not a carousel. Nothing auto-advances, so a
   quote cannot slide away mid-sentence, and the browser's own scroller
   brings keyboard, trackpad, touch and screen-reader support with it —
   none of which a hand-rolled carousel gets for free. */
.dbh-testimonials {
    background:
        radial-gradient(120% 90% at 50% 0%, var(--dbh-brand-50) 0%, transparent 60%),
        var(--dbh-paper);
}

.dbh-quotes {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(280px, 340px);
    gap: 20px;
    margin: 0;
    padding: 4px 0 20px;
    list-style: none;

    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;

    /* Kept visible but quiet: hiding the scrollbar entirely removes the
       only persistent hint that there is more to the right. */
    scrollbar-width: thin;
    scrollbar-color: var(--dbh-brand-100) transparent;
}

/* Edge-to-edge on a phone so a card can bleed off-screen and read as
   continuing, rather than stopping inside the container's gutter — the
   same treatment .dbh-worklist and .dbh-rooms already use. Its own
   padding restores the alignment with the heading above. */
@media (max-width: 767.98px) {
    .dbh-quotes {
        margin-inline: calc(50% - 50vw);
        padding-inline: 20px;
        scroll-padding-inline: 20px;
    }
}

/* The rail is focusable so a keyboard can reach off-screen cards; that
   focus needs to be visible, like every other focus ring on the site. */
.dbh-quotes:focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: 4px;
    border-radius: var(--dbh-radius-md);
}

@media (min-width: 992px) {
    .dbh-quotes {
        grid-auto-columns: minmax(320px, 380px);
        gap: 24px;
    }
}

.dbh-quote {
    scroll-snap-align: start;
    display: flex;
    flex-direction: column;
    padding: 28px;
    background: #fff;
    border: 1px solid var(--dbh-line-soft);
    border-radius: var(--dbh-radius-lg);

    /* Colour and shadow only — a transform here would shunt the card into
       its neighbour inside a scroll container. */
    transition:
        border-color var(--dbh-dur-md) var(--dbh-ease-out),
        box-shadow var(--dbh-dur-md) var(--dbh-ease-out);
}

.dbh-quote:hover {
    border-color: var(--dbh-brand-100);
    box-shadow: var(--dbh-shadow-lg);
}

.dbh-quote__rating {
    display: flex;
    gap: 3px;
    margin: 0 0 16px;
    font-size: 0.875rem;

    /* Not the brand purple: five purple stars read as decoration, and a
       rating is the one thing on this card nobody should have to decode.

       A deeper amber than the usual star gold, which sits at about 2:1 on
       white — under the 4.5:1 floor. These stars *are* the visible rating,
       so they have to clear it rather than rely on the visually-hidden
       text beside them. This reads as gold and measures 5:1. */
    color: #b45309;
}

.dbh-quote__body {
    flex: 1 1 auto;
    margin: 0;
}

.dbh-quote__body p {
    margin: 0;
    font-family: var(--dbh-font-display);
    font-size: 1.0625rem;
    font-weight: 500;
    line-height: 1.55;
    color: var(--dbh-ink-900);
    text-wrap: pretty;
}

/* The quotation mark is set as a background flourish rather than typed
   into the markup, so a screen reader is not told "left double quote"
   before every testimonial. */
.dbh-quote__body::before {
    content: '\201C';
    display: block;
    margin-bottom: -14px;
    font-family: var(--dbh-font-serif);
    font-size: 3.5rem;
    line-height: 1;
    color: var(--dbh-brand-100);
}

.dbh-quote__meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: 22px;
    padding-top: 18px;
    border-top: 1px solid var(--dbh-line-soft);
}

.dbh-quote__name {
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--dbh-ink-900);
}

.dbh-quote__service {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

.dbh-quotes__cta {
    margin: var(--dbh-space-8) 0 0;
    text-align: center;
}

/* The rail's own scrollbar, kept visible but quiet: hiding it entirely
   removes the only persistent hint that there is more to the right. */
.dbh-quotes::-webkit-scrollbar {
    height: 6px;
}

.dbh-quotes::-webkit-scrollbar-track {
    background: transparent;
}

.dbh-quotes::-webkit-scrollbar-thumb {
    background: var(--dbh-brand-100);
    border-radius: 999px;
}

/* Snapping fights an assistive or reduced-motion scroll, so it comes off
   with everything else that moves. */
@media (prefers-reduced-motion: reduce) {
    .dbh-quotes {
        scroll-snap-type: none;
    }
}

/* ── Closing booking band ─────────────────────────────────────────────
   The page's last word, and the one section that is allowed to be loud.
   Photography behind a scrim rather than a flat brand fill: the work is
   what sells the appointment. */
.dbh-bookband {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    background: var(--dbh-ink-900);
    color: #fff;
}

.dbh-bookband__media {
    position: absolute;
    inset: 0;
    z-index: -2;
}

.dbh-bookband__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 32%;
}

.dbh-bookband__scrim {
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(
        to right,
        rgba(26, 16, 35, 0.93) 0%,
        rgba(26, 16, 35, 0.82) 45%,
        rgba(26, 16, 35, 0.55) 100%
    );
}

@media (max-width: 767.98px) {
    /* Portrait: the copy sits over the lower half, so the scrim runs
       bottom-up instead of left-in. */
    .dbh-bookband__scrim {
        background: linear-gradient(
            to top,
            rgba(26, 16, 35, 0.94) 0%,
            rgba(26, 16, 35, 0.86) 50%,
            rgba(26, 16, 35, 0.6) 100%
        );
    }
}

.dbh-bookband__inner {
    max-width: 34rem;
    padding-block: 12px;
}

.dbh-bookband h2 {
    color: #fff;
    margin: 14px 0 0;
    text-wrap: balance;
}

.dbh-bookband p {
    margin: 18px 0 0;
    color: rgba(255, 255, 255, 0.86);
}

.dbh-bookband__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 32px;
}

@media (max-width: 419px) {
    .dbh-bookband__actions .dbh-btn {
        width: 100%;
    }
}

/* ── Motion ───────────────────────────────────────────────────────────
   The homepage's own reveals ride the shared .dbh-reveal machinery, so
   they already stop under prefers-reduced-motion. This only answers the
   transforms declared above it. */
@media (prefers-reduced-motion: reduce) {
    .dbh-work img {
        transition: none;
    }

    .dbh-work:hover img {
        transform: none;
    }

    .dbh-worklist {
        scroll-snap-type: none;
    }
}

/* ══════════════════════════════════════════════════════════════════════
   BOOKING — FOCUSED CHROME

   The header and footer a checkout gets instead of the marketing ones.
   Both are deliberately quiet: the only thing on these pages that should
   compete for attention is the next step of the booking.
   ══════════════════════════════════════════════════════════════════════ */

.dbh-bookhead {
    position: sticky;
    top: 0;
    z-index: 1020;
    background: rgba(251, 249, 246, 0.92);
    border-bottom: 1px solid var(--dbh-line-soft);
    backdrop-filter: blur(8px);
}

.dbh-bookhead__inner {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 60px;
}

.dbh-bookhead__back {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    /* 44px, not 40: this is the only way out of the flow and the most
       likely mis-tap on the page. */
    width: 44px;
    height: 44px;
    margin-left: -10px;
    border-radius: var(--dbh-radius-full);
    color: var(--dbh-ink-900);
    font-size: 1.125rem;
    transition: background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

@media (hover: hover) {
    .dbh-bookhead__back:hover {
        background: var(--dbh-surface);
        color: var(--dbh-ink-900);
    }
}

.dbh-bookhead__brand {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    margin-right: auto;
    color: var(--dbh-ink-900);
    font-family: var(--dbh-font-display);
    font-size: 0.9375rem;
    font-weight: 600;
    text-decoration: none;
}

.dbh-bookhead__brand img {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
}

.dbh-bookhead__brand span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dbh-bookhead__call {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 44px;
    min-width: 44px;
    padding-inline: 14px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-full);
    background: #fff;
    color: var(--dbh-brand-600);
    font-size: 0.875rem;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    transition:
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

@media (hover: hover) {
    .dbh-bookhead__call:hover {
        border-color: var(--dbh-brand-300);
        background: var(--dbh-brand-50);
        color: var(--dbh-brand-700);
    }
}

/* The number itself is the first thing to go on a narrow phone — the icon
   still says "call", and the header's job there is the brand and the way
   out, not a legible phone number. */
@media (max-width: 575.98px) {
    .dbh-bookhead__call {
        padding-inline: 0;
    }

    .dbh-bookhead__call-text {
        display: none;
    }
}

/* ── Booking footer ──────────────────────────────────────────────────── */
/* No margin of its own: the flow section above already ends on a full
   band of padding, and adding to it stacked two gaps into 128px of empty
   page between the last field and the footer. */
.dbh-bookfoot {
    border-top: 1px solid var(--dbh-line-soft);
    background: var(--dbh-surface);
}

.dbh-bookfoot__inner {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding-block: 28px;
    font-size: 0.8125rem;
    color: var(--dbh-ink-muted);
}

.dbh-bookfoot__trust {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 0;
    color: var(--dbh-ink-700);
}

.dbh-bookfoot__trust > i {
    margin-top: 1px;
    color: var(--dbh-brand-600);
}

.dbh-bookfoot__meta,
.dbh-bookfoot__legal {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 20px;
}

.dbh-bookfoot__meta a,
.dbh-bookfoot__meta span,
.dbh-bookfoot__legal a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    color: var(--dbh-ink-muted);
    text-decoration: none;
}

.dbh-bookfoot__legal a {
    text-decoration: underline;
    text-underline-offset: 3px;
}

@media (hover: hover) {
    .dbh-bookfoot__meta a:hover,
    .dbh-bookfoot__legal a:hover {
        color: var(--dbh-brand-600);
    }
}

/* The bar is fixed over the end of the page, so the footer's last line
   would otherwise sit underneath it. */
@media (max-width: 991.98px) {
    body:has(.dbh-booking.has-sticky-bar) .dbh-bookfoot {
        padding-bottom: calc(var(--dbh-stickybar-h, 88px) + 16px);
    }
}

/* ── Booking intro + progress rail ───────────────────────────────────────
   Replaces the marketing pagehead on the booking flow. The rail answers
   "where am I and how much is left", which a checkout owes the visitor
   and a headline does not. */
.dbh-bookintro {
    padding-block: 24px 4px;
}

.dbh-bookintro__title {
    margin: 0;
    font-family: var(--dbh-font-serif);
    font-weight: 400;
    font-size: clamp(1.625rem, 1.35rem + 1.2vw, 2.25rem);
    line-height: 1.15;
    letter-spacing: -0.01em;
    color: var(--dbh-ink-900);
}

/* Horizontally scrollable rather than wrapped: four labels plus their
   connectors do not fit a 320px phone, and a wrapped rail reads as two
   separate lists instead of one sequence. */
.dbh-progress {
    display: flex;
    align-items: center;
    gap: 0;
    margin: 20px 0 0;
    padding: 0 0 2px;
    list-style: none;
    overflow-x: auto;
    scrollbar-width: none;
}

.dbh-progress::-webkit-scrollbar {
    display: none;
}

.dbh-progress__item {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
    font-size: 0.875rem;
    white-space: nowrap;
}

/* The rail marker is a button now, since a finished step is somewhere the
   visitor can jump back to. Reset to plain text-and-icon layout so it reads
   exactly as the old static markup did. */
.dbh-progress__trigger {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    cursor: pointer;
    border-radius: var(--dbh-radius-sm);
}

.dbh-progress__trigger:disabled {
    cursor: default;
}

.dbh-progress__trigger:not(:disabled):hover .dbh-progress__label {
    color: var(--dbh-ink-900);
}

.dbh-progress__trigger:focus-visible {
    outline: 2px solid var(--dbh-brand-600);
    outline-offset: 2px;
}

/* The connector between markers. A pseudo-element on every item but the
   first, so the markup stays a plain ordered list. */
.dbh-progress__item + .dbh-progress__item::before {
    content: '';
    width: clamp(16px, 4vw, 40px);
    height: 1px;
    margin-inline: 10px;
    background: var(--dbh-line);
}

.dbh-progress__dot {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    flex: 0 0 auto;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-full);
    background: #fff;
    color: transparent;
    font-size: 0.6875rem;
    transition:
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-progress__label {
    color: var(--dbh-ink-muted);
    transition: color var(--dbh-dur-sm) var(--dbh-ease-out);
}

/* Done — the tick appears and the marker fills. */
.dbh-progress__item[data-step-state='done'] .dbh-progress__dot {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-600);
    color: #fff;
}

.dbh-progress__item[data-step-state='done'] .dbh-progress__label {
    color: var(--dbh-ink-700);
}

/* Current — ringed rather than filled, so it reads as "you are here"
   instead of "this is finished". */
.dbh-progress__item[data-step-state='current'] .dbh-progress__dot {
    border-color: var(--dbh-brand-600);
    background: #fff;
    box-shadow: 0 0 0 3px var(--dbh-brand-50);
}

.dbh-progress__item[data-step-state='current'] .dbh-progress__dot::after {
    content: '';
    width: 8px;
    height: 8px;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-brand-600);
}

.dbh-progress__item[data-step-state='current'] .dbh-progress__dot > i {
    display: none;
}

.dbh-progress__item[data-step-state='current'] .dbh-progress__label {
    color: var(--dbh-ink-900);
    font-weight: 600;
}

/* A tighter top for the flow itself: the progress rail already carries
   the space a section head would have. Its own name rather than reusing
   .dbh-section--tight, which is a different thing elsewhere on the site
   (a negative pull-up under a page head). */
.dbh-section--flow {
    padding-top: var(--dbh-space-6);
}

@media (prefers-reduced-motion: reduce) {
    .dbh-progress__dot,
    .dbh-progress__label {
        transition: none;
    }
}

/* ── Scoped booking: one service, presented as a card ────────────────────
   Arriving from "Book this" means the service is already decided. The
   variant accordion's header — a group name, a "Selected" badge and a
   collapse chevron — is then pure overhead: there is one group, it is
   open, and collapsing it would hide the only thing on the page. Hidden
   while scoped, and restored the instant [data-expand-menu] brings the
   rest of the menu in, where those headers are the only way to navigate. */
.dbh-booking.is-scoped .dbh-menu {
    margin-top: 12px;
}

.dbh-booking.is-scoped .dbh-menu__head {
    display: none;
}

.dbh-booking.is-scoped .dbh-menu__group {
    border-color: var(--dbh-line);
    background: #fff;
    box-shadow: var(--dbh-shadow-sm);
}

/* The chosen row already sits inside a brand-bordered card, so its own
   tint would be a second selected state for the same fact. */
.dbh-booking.is-scoped .dbh-menu__list {
    padding: 8px;
}

.dbh-booking.is-scoped .dbh-menu__item .dbh-menu__choose {
    cursor: default;
}

/* The step title, now that the numeral has gone to the progress rail. */
.dbh-booking__steptitle {
    margin: 0;
}

/* Focused programmatically on every step change (see goToStep in
   site.js), not by pointer or Tab — a visible focus ring here would be
   noise on every single step transition rather than feedback for a
   keyboard user choosing to move. Screen readers still announce it. */
.dbh-booking__steptitle:focus {
    outline: none;
}

/* ── Wizard step navigation ──────────────────────────────────────────────
   The Back/Continue row under steps 1 and 2, and the lone Back under step
   3 (its forward action is the summary panel's submit button, not one of
   these). Two-up on desktop when both buttons are present; Continue always
   claims the remaining space so its tap target matches the full-width
   submit button one step later. */
/* Every step's forward action gets the same shape as the deposit button
   it eventually becomes: full width, stacked, with the reason it is
   disabled written directly underneath. Paired side by side, "Continue"
   was both narrower and silent — a greyed-out button with nothing
   attached reads as broken rather than as not-yet-earned. */
.dbh-wizard-nav {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    margin-top: 28px;
}

.dbh-wizard-nav [data-step-next],
.dbh-wizard-nav__submit {
    width: 100%;
}

/* From lg the summary panel sits beside the form and carries the submit,
   so this one would be the second identical button on screen. Below lg
   that panel is an off-screen sheet and this is the only reachable way
   to pay — without it the last step of a checkout ends on "Back". */
@media (min-width: 992px) {
    .dbh-wizard-nav__submit {
        display: none;
    }
}

/* Sits under the primary action rather than beside it, styled like plain
   text rather than a second button — "Continue"/"Pay deposit" is the only
   button that should read as a call to action here. */
.dbh-wizard-nav__back {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    margin: 0;
    padding: 4px;
    border: 0;
    background: transparent;
    font-family: inherit;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--dbh-ink-muted);
    text-align: center;
}

.dbh-wizard-nav__back:hover,
.dbh-wizard-nav__back:focus-visible {
    color: var(--dbh-ink-700);
}

/* Why this step's "Continue" is disabled, under the button rather than
   inside it — the same job the summary panel's submit hint does, on the
   steps that have their own forward action. Icon as well as colour, so it
   does not rely on colour alone. */
.dbh-wizard-nav__hint {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    gap: 6px;
    margin: 0;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--dbh-ink-muted);
    text-align: center;
}

/* The house rules on the first booking step. A plain list, but the points
   are the conditions of the appointment rather than marketing copy, so
   each is marked read-and-noted rather than bulleted. */
.dbh-terms-list {
    margin: 16px 0 0;
    padding: 0;
    list-style: none;
}

.dbh-terms-list__item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: var(--dbh-ink-700);
}

.dbh-terms-list__item + .dbh-terms-list__item {
    margin-top: 10px;
}

.dbh-terms-list__item > i {
    flex-shrink: 0;
    margin-top: 3px;
    font-size: 0.875rem;
    color: var(--dbh-brand-600);
}

/* "Add another service" — a secondary action, sized and coloured like
   one. It was previously the loudest thing above the fold: full brand
   purple, offering a second service before the first was visible. */
.dbh-addmore {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 44px;
    padding: 10px 18px;
    border: 1px dashed var(--dbh-ink-300);
    border-radius: var(--dbh-radius-full);
    background: transparent;
    color: var(--dbh-ink-700);
    font-family: var(--dbh-font-sans);
    font-size: 0.9375rem;
    font-weight: 500;
    cursor: pointer;
    transition:
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        color var(--dbh-dur-sm) var(--dbh-ease-out);
}

@media (hover: hover) {
    .dbh-addmore:hover {
        border-color: var(--dbh-brand-300);
        background: var(--dbh-brand-50);
        color: var(--dbh-brand-700);
    }
}

/* ── Day rail ────────────────────────────────────────────────────────────
   The next fortnight, swipeable. Sits above the full calendar, which
   stays for anything further out. */
.dbh-dayrail {
    margin-top: 4px;
}

.dbh-dayrail__list {
    display: flex;
    gap: 8px;
    margin: 0;
    padding: 2px 0 6px;
    list-style: none;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
}

.dbh-dayrail__list::-webkit-scrollbar {
    display: none;
}

.dbh-daypill {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    /* 60×72 keeps the whole pill a comfortable thumb target while fitting
       five across a 320px screen. */
    width: 60px;
    min-height: 72px;
    padding: 8px 4px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-md);
    background: #fff;
    color: var(--dbh-ink-900);
    font-family: var(--dbh-font-sans);
    cursor: pointer;
    scroll-snap-align: start;
    transition:
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        background-color var(--dbh-dur-sm) var(--dbh-ease-out),
        color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-daypill__dow,
.dbh-daypill__mon {
    font-size: 0.6875rem;
    line-height: 1.2;
    color: var(--dbh-ink-muted);
    transition: color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-daypill__num {
    font-family: var(--dbh-font-display);
    font-size: 1.125rem;
    font-weight: 600;
    line-height: 1.15;
}

@media (hover: hover) {
    .dbh-daypill:not(:disabled):not([aria-pressed='true']):hover {
        border-color: var(--dbh-brand-300);
        background: var(--dbh-brand-50);
    }
}

.dbh-daypill[aria-pressed='true'] {
    border-color: var(--dbh-brand-600);
    background: var(--dbh-brand-600);
    color: #fff;
}

.dbh-daypill[aria-pressed='true'] .dbh-daypill__dow,
.dbh-daypill[aria-pressed='true'] .dbh-daypill__mon {
    color: rgba(255, 255, 255, 0.86);
}

/* Fully booked. Struck through as well as dimmed, so the state does not
   rely on colour alone. */
.dbh-daypill:disabled {
    border-style: dashed;
    background: var(--dbh-surface);
    color: var(--dbh-ink-muted);
    cursor: not-allowed;
}

.dbh-daypill:disabled .dbh-daypill__num {
    text-decoration: line-through;
}

/* Emergency-only: still a normal pill — enabled, no dashed border, no
   strike-through, none of which :disabled above uses — with a warning
   border and a small flag badge so the state does not rely on colour
   alone on a screen with no hover to reveal a tooltip. */
.dbh-daypill[data-emergency-only='true'] {
    border-color: #fcd34d;
}

.dbh-daypill__flag {
    position: absolute;
    top: 4px;
    right: 4px;
    font-size: 0.625rem;
    color: var(--dbh-warn-ink);
}

.dbh-daypill[aria-pressed='true'] .dbh-daypill__flag {
    color: #fff;
}

/* The calendar becomes the secondary route once the rail exists, so its
   trigger stops looking like the primary date control. */
.dbh-dayrail:not([hidden]) ~ .dbh-cal .dbh-cal__trigger {
    justify-content: center;
    gap: 8px;
    border-style: dashed;
    background: transparent;
}

@media (prefers-reduced-motion: reduce) {
    .dbh-daypill,
    .dbh-daypill__dow,
    .dbh-daypill__mon {
        transition: none;
    }

    .dbh-dayrail__list {
        scroll-snap-type: none;
    }
}

/* ── Booking help ────────────────────────────────────────────────────────
   The chat and call routes, in the flow rather than floating over it.
   Sits at the end of the booking footer, where it is reachable from any
   point in the form via one scroll and can never cover a control. */
.dbh-bookhelp {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 16px;
    padding: 14px 16px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-md);
    background: #fff;
}

.dbh-bookhelp__label {
    font-family: var(--dbh-font-display);
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--dbh-ink-900);
}

.dbh-bookhelp__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-left: auto;
}

.dbh-bookhelp__action {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
    padding: 8px 16px;
    border: 1px solid var(--dbh-line);
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-paper);
    color: var(--dbh-ink-900);
    font-size: 0.875rem;
    font-weight: 500;
    text-decoration: none;
    transition:
        border-color var(--dbh-dur-sm) var(--dbh-ease-out),
        background-color var(--dbh-dur-sm) var(--dbh-ease-out);
}

.dbh-bookhelp__action--wa > i {
    color: var(--dbh-wa-deep, #0f7a6c);
}

@media (hover: hover) {
    .dbh-bookhelp__action:hover {
        border-color: var(--dbh-brand-300);
        background: var(--dbh-brand-50);
        color: var(--dbh-brand-700);
    }
}

@media (max-width: 419px) {
    .dbh-bookhelp__actions {
        margin-left: 0;
        width: 100%;
    }

    .dbh-bookhelp__action {
        flex: 1 1 auto;
        justify-content: center;
    }
}

/* The floating widget's label, for the viewports that still show it (from
   lg up, where there is no sticky bar to collide with). Hover and focus
   only — a permanently expanded pill parked over the summary column would
   be the same mistake as the floating button covering the form. */
.dbh-wa__toggle::after {
    content: 'Need help booking?';
    position: absolute;
    right: calc(100% + 12px);
    top: 50%;
    transform: translateY(-50%) translateX(6px);
    padding: 8px 14px;
    border-radius: var(--dbh-radius-full);
    background: var(--dbh-ink-900);
    color: #fff;
    font-family: var(--dbh-font-sans);
    font-size: 0.8125rem;
    font-weight: 500;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition:
        opacity var(--dbh-dur-sm) var(--dbh-ease-out),
        transform var(--dbh-dur-sm) var(--dbh-ease-out);
}

@media (hover: hover) {
    .dbh-wa__toggle:hover::after {
        opacity: 1;
        transform: translateY(-50%) translateX(0);
    }
}

.dbh-wa__toggle:focus-visible::after {
    opacity: 1;
    transform: translateY(-50%) translateX(0);
}

/* Once the panel is open the button means "close", and a tooltip still
   offering help would contradict the X it is showing. */
.dbh-wa[data-open='true'] .dbh-wa__toggle::after,
.dbh-wa__toggle[aria-expanded='true']::after {
    content: none;
}

@media (prefers-reduced-motion: reduce) {
    .dbh-wa__toggle::after {
        transition: none;
    }
}
