/* ==========================================================================
   Durley Builder — front end
   --------------------------------------------------------------------------
   Everything is scoped beneath .ddb so a host theme can never reach in, and
   low-specificity :where() resets keep component rules predictable without
   resorting to !important.

   Measurements are read from the signed-off 1728px Figma frame. Where a value
   comes from a specific node it is cited beside it.

   Contents
     1  Reset & scope
     2  Typography
     3  Buttons & links
     4  Interactive cards
     5  Header
     6  Footer
     7  Marquee
     8  Hero
     9  Intro
    10  Category tiles
    11  Bento overview
    12  Image band
    13  Treatment cards, carousel & grid
    14  Cross-area panels
    15  Process
    16  Testimonials
    17  Reviews
    18  FAQs
    19  Team
    20  Locations
    21  Gallery
    22  Resources
    23  Pricing
    24  Contact, forms & map
    25  Legal
    26  Motion preferences
   ========================================================================== */


/* ── 1 · Reset & scope ─────────────────────────────────────────────────── */

/* The Builder template owns the document, so the user-agent body margin is
   cleared here. Without it every full-bleed band sits 8px off-centre and every
   measured width is 16px short of the Figma. */
body.ddb-hosted { margin: 0; }

/* How far down the viewport anything the page scrolls to has to start, so it
   arrives below the sticky masthead rather than under it. Three terms:
   the WordPress toolbar (0 for every visitor, a real height only while an
   editor is logged in and the bar is genuinely pinned), the stuck header's own
   81px box, and a little air beneath it.

   Declared here on .ddb rather than on :root deliberately. A custom property
   that references another resolves in the scope it is *declared* in, and
   --ddb-admin-bar is set on <body>; declared on an ancestor of <body> this
   would never see it. .ddb is a descendant, so it inherits the real value. */
.ddb { --ddb-sticky-offset: calc(var(--ddb-admin-bar, 0px) + 81px + 24px); }

/* The same clearance for the browser's own scrolling, plus smooth travel, so a
   contents link lands its section under the header instead of behind it. Both
   belong on the scrolling element, which is the document — hence the :has(),
   which keeps this off every page the Builder does not compose. The document
   cannot read the property above for the same scoping reason, so
   --ddb-admin-bar-doc carries the toolbar's height on <html> as well; it is
   0px for every visitor. */
html:has(body.ddb-hosted) {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--ddb-admin-bar-doc, 0px) + 105px);
}
@media (prefers-reduced-motion: reduce) {
  html:has(body.ddb-hosted) { scroll-behavior: auto; }
}

.ddb {
  font-family: var(--ddb-font);
  font-weight: var(--ddb-w-regular);
  font-size: var(--ddb-t-body);
  line-height: var(--ddb-lh-body);
  color: var(--ddb-ink);
  background: var(--ddb-ground);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

.ddb :where(*, *::before, *::after) { box-sizing: border-box; }

.ddb :where(h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, ol, ul) {
  margin: 0;
  padding: 0;
}

.ddb :where(ul, ol) { list-style: none; }

.ddb :where(img, picture, video, iframe) {
  display: block;
  max-width: 100%;
}

.ddb :where(img) { height: auto; }

/* Links are undecorated by default; where the design does underline one — the
   footer credit, copy inside a legal page — it is a hairline sitting close to
   the baseline. Declared for the same reason as the wrapping rule above: the
   previous theme was supplying it, and the signed-off pages were measured with
   it in place. */
.ddb :where(a) {
  color: inherit;
  text-decoration: none;
  text-decoration-thickness: 1px;
  text-underline-offset: .1em;
}

.ddb :where(button) {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

.ddb :where(address) { font-style: normal; }

.ddb :where(table) { border-collapse: collapse; width: 100%; }

.ddb .screen-reader-text {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* One focus treatment for the whole build. */
.ddb :where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--ddb-primary);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Outer safety cap.
   The design is drawn on a 1728 frame. Past --ddb-cap the major visual sections
   stop growing and centre instead, so a very wide monitor gets margin rather
   than a stretched composition. This sits *outside* the measured layout: every
   gutter, grid and content width inside a section is untouched, and at 1728 the
   cap is inert.

   The scrolling type strips are deliberately exempt. The design treats them as
   continuous edge-to-edge devices that run off both sides of the viewport, so
   capping them would break the effect the composition depends on — which is
   also why the cap is applied per section rather than by wrapping the page. */
.ddb :where(.ddb-main > *, .ddb-footer) {
  width: 100%;
  max-width: var(--ddb-cap);
  margin-inline: auto;
}
.ddb :where(.ddb-marquee) { max-width: none; }

/* Section spacing.
   The design does not use one rhythm, so neither does this. Every gap below is
   the measured distance between two specific sections on the UI Design Home
   frame, expressed as its own rule. The fallback only applies to an adjacency
   the design has not yet been measured for. */
.ddb-main > * + * { margin-top: clamp(32px, 3.4vw, 58px); }

/* Treatment areas — frame 119:2189 (Dental); Aesthetics and Wellness share the
   same composition and the same gaps, differing only by identity colour. */
.ddb-page--division .ddb-pintro  { margin-top: clamp(32px, 3.356vw, 58px); }   /* header 610 → intro 668 */
.ddb-page--division .ddb-zig     { margin-top: clamp(68px, 7.523vw, 130px); }  /* intro 863 → rows 993 */
.ddb-page--division .ddb-vtesti  { margin-top: clamp(54px, 5.961vw, 103px); }  /* rows 3460 → testimonials 3563 */
.ddb-page--division .ddb-faq     { margin-top: clamp(54px, 5.903vw, 102px); }  /* testimonials 4230 → FAQs 4332 */
.ddb-page--division .ddb-process { margin-top: clamp(72px, 8.044vw, 139px); }  /* FAQs 4832 → how-it-works 4971 */
.ddb-page--division .ddb-intro   { margin-top: clamp(82px, 9.201vw, 159px); }  /* process 5946 → intro 6105 */
.ddb-page--division .ddb-cats    { margin-top: clamp(24px, 2.315vw, 40px); }   /* intro copy 6266 → tiles 6306 */
.ddb-page--division .ddb-reviews { margin-top: clamp(50px, 5.440vw, 94px); }   /* tiles 6872 → reviews 6966 */
.ddb-page--division .ddb-band    { margin-top: clamp(60px, 6.597vw, 114px); }  /* reviews 7705 → band 7819 */
.ddb-page--division .ddb-footer  { margin-top: clamp(40px, 4.398vw, 76px); }   /* band 8541 → footer 8617 */

/* The band sits at x 121 on these frames (node 119:2203), not the 101 it uses
   on Home or the 106 on About. */
.ddb-page--division .ddb-band__panel {
  width: min(100% - clamp(20px, 7.002vw, 121px) - clamp(20px, 5.266vw, 91px), 1516px);
  margin-left: calc(clamp(20px, 7.002vw, 121px) + max(0px, (100% - 1728px) / 2));
}

/* About — frame 119:2164. Its own measured gaps and its own band/split offsets;
   the sections are shared with Home but their spacing here is not. */
.ddb-page--about .ddb-clinic,
.ddb-page--about .ddb-bento   { margin-top: clamp(48px, 5.093vw, 88px); }   /* header 610 → bento 698 */
.ddb-page--about .ddb-strip   { margin-top: clamp(48px, 5.093vw, 88px); }   /* bento 1509 → strip 1597 */
.ddb-page--about .ddb-marquee { margin-top: clamp(48px, 5.093vw, 88px); }   /* strip 2143 → marquee 2231 */
.ddb-page--about .ddb-split   { margin-top: clamp(58px, 6.424vw, 111px); }  /* marquee 2366 → split head 2477 */
.ddb-page--about .ddb-intro   { margin-top: clamp(54px, 5.903vw, 102px); }  /* split 3378 → intro heading 3480 */
.ddb-page--about .ddb-cats    { margin-top: clamp(24px, 2.315vw, 40px); }   /* intro copy 3641 → tiles 3681 */
.ddb-page--about .ddb-band    { margin-top: clamp(58px, 6.424vw, 111px); }  /* tiles 4247 → band 4358 */
.ddb-page--about .ddb-reviews { margin-top: clamp(58px, 6.366vw, 110px); }  /* band 5080 → reviews 5190 */
.ddb-page--about .ddb-res     { margin-top: clamp(50px, 5.498vw, 95px); }   /* reviews 5929 → news eyebrow 6024 */
.ddb-page--about .ddb-footer  { margin-top: clamp(54px, 5.903vw, 102px); }  /* news 6646 → footer 6748 */

/* About places the band and the cross-area panels a few pixels differently from
   Home (nodes 119:2178 at x 106 and 119:2180 at x 118), so each carries its own
   offset rather than being normalised to one value. */
.ddb-page--about .ddb-band__panel {
  width: min(100% - clamp(20px, 6.134vw, 106px) - clamp(20px, 6.134vw, 106px), 1516px);
  margin-left: calc(clamp(20px, 6.134vw, 106px) + max(0px, (100% - 1728px) / 2));
}
.ddb-page--about .ddb-split__inner {
  max-width: calc(1466px + clamp(20px, 6.829vw, 118px) + clamp(20px, 8.218vw, 142px));
  padding-inline: clamp(20px, 6.829vw, 118px) clamp(20px, 8.218vw, 142px);
}

/* Practice — frame 119:2641. It shares its components with About and the area
   pages but not their spacing, so every gap is measured on its own frame. */
.ddb-page--practice .ddb-pintro  { margin-top: clamp(32px, 3.356vw, 58px); }   /* header 610 → intro 668 */
.ddb-page--practice .ddb-strip   { margin-top: clamp(44px, 4.572vw, 79px); }   /* intro 863 → strip 942 */
.ddb-page--practice .ddb-marquee { margin-top: clamp(44px, 4.572vw, 79px); }   /* strip 1488 → marquee 1567 */
.ddb-page--practice .ddb-band    { margin-top: clamp(58px, 6.250vw, 108px); }  /* marquee 1702 → band 1810 */
.ddb-page--practice .ddb-reviews { margin-top: clamp(36px, 3.819vw, 66px); }   /* band 2532 → reviews 2598 */
.ddb-page--practice .ddb-intro   { margin-top: clamp(58px, 6.192vw, 107px); }  /* reviews 3337 → intro heading 3444 */
.ddb-page--practice .ddb-cats    { margin-top: clamp(24px, 2.315vw, 40px); }   /* intro copy 3605 → tiles 3645 */
.ddb-page--practice .ddb-footer  { margin-top: clamp(56px, 5.961vw, 103px); }  /* tiles 4211 → footer 4314 */

/* The band sits at x 121 here (node 119:2644), as on the area pages. */
.ddb-page--practice .ddb-band__panel {
  width: min(100% - clamp(20px, 7.002vw, 121px) - clamp(20px, 5.266vw, 91px), 1516px);
  margin-left: calc(clamp(20px, 7.002vw, 121px) + max(0px, (100% - 1728px) / 2));
}

/* Meet The Team — frame 119:2704. */
.ddb-page--team .ddb-pintro  { margin-top: clamp(32px, 3.356vw, 58px); }   /* header 610 → intro 668 */
.ddb-page--team .ddb-team    { margin-top: clamp(38px, 3.935vw, 68px); }   /* intro 863 → grid 931 */
.ddb-page--team .ddb-strip   { margin-top: clamp(70px, 7.350vw, 127px); }  /* grid 1811 → strip 1938 */
.ddb-page--team .ddb-marquee { margin-top: clamp(50px, 5.266vw, 91px); }   /* strip 2484 → marquee 2575 */
.ddb-page--team .ddb-band    { margin-top: clamp(78px, 7.986vw, 138px); }  /* marquee 2710 → band 2848 */
.ddb-page--team .ddb-reviews { margin-top: clamp(42px, 4.398vw, 76px); }   /* band 3570 → reviews 3646 */
.ddb-page--team .ddb-intro   { margin-top: clamp(56px, 5.729vw, 99px); }   /* reviews 4385 → intro heading 4484 */
.ddb-page--team .ddb-cats    { margin-top: clamp(24px, 2.315vw, 40px); }   /* intro copy 4645 → tiles 4685 */
.ddb-page--team .ddb-footer  { margin-top: clamp(58px, 5.961vw, 103px); }  /* tiles 5251 → footer 5354 */

.ddb-page--team .ddb-band__panel {
  width: min(100% - clamp(20px, 7.002vw, 121px) - clamp(20px, 5.266vw, 91px), 1516px);
  margin-left: calc(clamp(20px, 7.002vw, 121px) + max(0px, (100% - 1728px) / 2));
}

/* Our Locations — frame 119:2677. */
.ddb-page--locations .ddb-locs    { margin-top: clamp(38px, 3.935vw, 68px); }   /* header 610 → cards 678 */
.ddb-page--locations .ddb-marquee { margin-top: clamp(48px, 4.919vw, 85px); }   /* cards 1452 → marquee 1537 */
.ddb-page--locations .ddb-faq     { margin-top: clamp(50px, 5.035vw, 87px); }   /* marquee 1672 → FAQs 1759 */
.ddb-page--locations .ddb-reviews { margin-top: clamp(56px, 5.671vw, 98px); }   /* FAQs 2259 → reviews 2357 */
.ddb-page--locations .ddb-band    { margin-top: clamp(52px, 5.382vw, 93px); }   /* reviews 3096 → band 3189 */
.ddb-page--locations .ddb-footer  { margin-top: clamp(52px, 5.266vw, 91px); }   /* band 3911 → footer 4002 */

.ddb-page--locations .ddb-band__panel {
  width: min(100% - clamp(20px, 7.002vw, 121px) - clamp(20px, 5.266vw, 91px), 1516px);
  margin-left: calc(clamp(20px, 7.002vw, 121px) + max(0px, (100% - 1728px) / 2));
}

/* Location detail — frame 119:2653. */
.ddb-page--location_detail .ddb-pintro  { margin-top: clamp(32px, 3.356vw, 58px); }   /* header 610 → intro 668 */
.ddb-page--location_detail .ddb-strip   { margin-top: clamp(44px, 4.572vw, 79px); }   /* intro 863 → strip 942 */
.ddb-page--location_detail .ddb-marquee { margin-top: clamp(44px, 4.572vw, 79px); }   /* strip 1488 → marquee 1567 */
.ddb-page--location_detail .ddb-tcar    { margin-top: clamp(54px, 5.613vw, 97px); }   /* marquee 1702 → carousel 1799 */
.ddb-page--location_detail .ddb-band    { margin-top: clamp(58px, 6.019vw, 104px); } /* carousel 2285 → band 2389 */
.ddb-page--location_detail .ddb-reviews { margin-top: clamp(36px, 3.819vw, 66px); }   /* band 3111 → reviews 3177 */
.ddb-page--location_detail .ddb-footer  { margin-top: clamp(36px, 3.819vw, 66px); }   /* reviews 3916 → footer 3982 */

/* This page's carousel starts at x 90 rather than the 121 the home frame uses
   (node 119:2660), and it has no cream ground behind it. */
.ddb-page--location_detail .ddb-tcar__inner {
  max-width: calc(1466px + clamp(20px, 5.208vw, 90px) + clamp(20px, 10.185vw, 176px));
  padding-inline: clamp(20px, 5.208vw, 90px) clamp(20px, 10.185vw, 176px);
}
.ddb-page--location_detail .ddb-tcar__panel { margin-right: calc(-1 * clamp(20px, 10.185vw, 176px)); }

.ddb-page--location_detail .ddb-band__panel {
  width: min(100% - clamp(20px, 7.002vw, 121px) - clamp(20px, 5.266vw, 91px), 1516px);
  margin-left: calc(clamp(20px, 7.002vw, 121px) + max(0px, (100% - 1728px) / 2));
}

/* Resources — frame 119:2522. */
.ddb-page--resources .ddb-pintro { margin-top: clamp(32px, 3.356vw, 58px); }   /* header 610 → intro 668 */
.ddb-page--resources .ddb-rindex { margin-top: clamp(34px, 3.356vw, 58px); }   /* intro 863 → tiles 921 */
.ddb-page--resources .ddb-footer { margin-top: clamp(74px, 8.391vw, 145px); }  /* tiles 2448 → footer 2593 */

/* Article — frame 119:2544. */
.ddb-page--post .ddb-article { margin-top: clamp(36px, 3.530vw, 61px); }   /* header 610 → title 671 */
.ddb-page--post .ddb-promo   { margin-top: clamp(36px, 3.588vw, 62px); }   /* words 2402 → card 2464 */
.ddb-page--post .ddb-rindex  { margin-top: clamp(52px, 5.556vw, 96px); }   /* card 2662 → "Read more" 2758 */
.ddb-page--post .ddb-footer  { margin-top: clamp(46px, 5.266vw, 91px); }   /* tiles 3306 → footer 3397 */
/* The listing beneath an article carries a heading rather than a page intro. */
.ddb-page--post .ddb-rindex .ddb-h2 {
  font-size: clamp(22px, 1.736vw, 30px);                                   /* node 119:2552 */
  font-weight: var(--ddb-w-medium);
  margin-bottom: 38px;                                                     /* 2790 → 2828 */
}

/* Legal — frame 119:2635. */
.ddb-page--legal .ddb-legal  { margin-top: clamp(34px, 3.356vw, 58px); }   /* header 610 → eyebrow 668 */
.ddb-page--legal .ddb-footer { margin-top: clamp(90px, 10.359vw, 179px); } /* words 2110 → footer 2289 */

/* Referrals — frame 119:2341. */
.ddb-page--referrals .ddb-referral { margin-top: clamp(42px, 4.225vw, 73px); }   /* header 610 → heading 683 */
.ddb-page--referrals .ddb-tcar     { margin-top: clamp(90px, 9.375vw, 162px); }  /* submit 1901 → carousel 2063 */
.ddb-page--referrals .ddb-process  { margin-top: clamp(54px, 5.556vw, 96px); }   /* carousel 2549 → process 2645 */
.ddb-page--referrals .ddb-footer   { margin-top: clamp(90px, 9.491vw, 164px); }  /* process 3620 → footer 3784 */
/* This page places the carousel at x 121 and the process block at 198. */
.ddb-page--referrals .ddb-process__inner {
  width: min(100% - (2 * clamp(20px, 11.458vw, 198px)), 1354px);
}

/* Contact — frame 119:2563. Its FAQ block is 940 wide and its rows 118 tall,
   where the Locations frame draws the same component at 1140 and 82. Both are in
   the design; both are kept. */
.ddb.ddb-page--contact .ddb-faq__inner {
  width: min(100% - (2 * clamp(20px, 22.801vw, 394px)), 940px);
}
.ddb.ddb-page--contact .ddb-faq__head { margin-bottom: 60px; }         /* heading 2496 → rows 2556 */
.ddb.ddb-page--contact .ddb-faq__head .ddb-eyebrow { min-height: 0; margin-bottom: 9px; }   /* node 119:2621 — a 23 box, not the 33 the FAQ component uses */
.ddb.ddb-page--contact .ddb-faq__list { gap: 11px; }
.ddb.ddb-page--contact .ddb-faq__item:first-child { margin-bottom: 5px; }   /* the design's own wider first gap */
.ddb.ddb-page--contact .ddb-faq__item { width: 100%; }
/* The Contact frame draws this component at 118 tall with 61px of inset — the
   Locations frame draws the same component at 82 with 32. Both were in the
   design and both were kept, but 118 is a very tall box for a single line of
   question, and 61px of inset makes each row read as a card rather than as a
   row. Brought down to 80 and 28/24: still comfortably above the 44px minimum
   tap target, still centred on the question and its mark, and long questions
   still wrap inside it because the height is a minimum, not a fixed size.
   The answer's own inset follows, so the copy stays aligned under its
   question. */
.ddb.ddb-page--contact .ddb-faq__trigger { min-height: 80px; padding-inline: 28px 24px; }
.ddb.ddb-page--contact .ddb-faq__a-inner { padding-inline: 28px 24px; }

/* Contact — frame 119:2563. */
.ddb-page--contact .ddb-contact { margin-top: clamp(32px, 3.183vw, 55px); }   /* header 610 → cards 665 */
.ddb-page--contact .ddb-map     { margin-top: clamp(56px, 5.787vw, 100px); }  /* form card 1452 → map eyebrow 1552 */
.ddb-page--contact .ddb-faq     { margin-top: clamp(58px, 5.903vw, 102px); }  /* map 2314 → FAQ eyebrow 2416 */
.ddb-page--contact .ddb-footer  { margin-top: clamp(58px, 5.903vw, 102px); }  /* FAQs 3066 → footer 3168 */

/* Home — every gap measured between the two elements it actually separates on
   frame 119:1956, not between component bounding boxes. */
.ddb-page--home .ddb-hero    { margin-top: clamp(14px, 1.447vw, 25px); }   /* menu 78 → hero 103 */
.ddb-page--home .ddb-intro   { margin-top: clamp(42px, 4.456vw, 77px); }   /* hero 1004 → heading 1081 */
.ddb-page--home .ddb-cats    { margin-top: clamp(24px, 2.315vw, 40px); }   /* intro copy 1242 → tiles 1282 */
.ddb-page--home .ddb-marquee { margin-top: clamp(36px, 3.819vw, 66px); }   /* tiles 1848 → strip 1914 */
.ddb-page--home .ddb-bento   { margin-top: clamp(36px, 3.877vw, 67px); }   /* strip 2049 → bento 2116 */
.ddb-page--home .ddb-band    { margin-top: clamp(42px, 4.572vw, 79px); }   /* bento 2927 → band 3006 */
.ddb-page--home .ddb-split   { margin-top: clamp(46px, 5.035vw, 87px); }   /* cream ground 4396 → split head 4483 */
.ddb-page--home .ddb-reviews { margin-top: clamp(42px, 4.456vw, 77px); }   /* split content 5384 → reviews 5461 */
.ddb-page--home .ddb-res     { margin-top: clamp(52px, 5.729vw, 99px); }   /* reviews 6200 → news eyebrow 6299 */
.ddb-page--home .ddb-footer  { margin-top: clamp(40px, 4.282vw, 74px); }   /* news 6921 → footer 6995 */


/* Media frames (§22).
   Every frame occupies the same grid cell, so a set of images is stacked without
   absolute positioning — the container keeps its own size and nothing can escape
   it if a caller forgets to establish a positioning context. Cycling only
   changes opacity, so nothing ever reflows. */
.ddb :where(.ddb-media) {
  position: relative;
  display: grid;
  height: 100%;
  overflow: hidden;
}
.ddb :where(.ddb-media__frame) {
  grid-area: 1 / 1;
  min-width: 0;
  overflow: hidden;
}
.ddb :where(.ddb-media__img) {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.ddb .ddb-media--cycle .ddb-media__frame { transition: opacity .9s var(--ddb-ease); }
.ddb .ddb-media--cycle .ddb-media__frame:not(.is-active) { opacity: 0; }



/* ── 2 · Typography ────────────────────────────────────────────────────── */

/* Headings.
   These classes carry only what every heading in the design genuinely shares —
   tracking, leading, colour, balanced wrapping. Size and weight are deliberately
   NOT set here: the design varies both per section (hero 55 Light, intro 45
   Light, bento 35 Medium, split 40 Medium, panel 38 Medium, news 45 Medium,
   reviews 45 Light), so each section sets its own from its own node. */
/* Wrapping.
   -----------------------------------------------------------------------------
   Deliberately `pretty`, not `balance`. The two are not the same choice:

     balance  evens the line lengths out, which rewrites where a heading breaks
              into something the frame does not draw. Not used.
     pretty   keeps greedy line breaking and only refuses to leave a single word
              stranded on the last line. It is what the signed-off pages were
              measured and approved with.

   This rule is here because it was previously arriving from the site's
   off-the-shelf theme, which set `text-wrap: pretty` on every heading and
   paragraph on the page — Durley's included. That dependency was found when the
   custom theme replaced it and four page headers re-wrapped: "Dental Treatments
   / at Durley" became "Dental Treatments at / Durley". The behaviour is correct
   and signed off, so it is declared here, owned by the Builder, rather than
   inherited by accident from whichever theme happens to be active. */
.ddb :where(h1, h2, h3, h4, h5, h6, p, blockquote, caption, figcaption) {
  text-wrap: pretty;
}

.ddb :where(.ddb-h1, .ddb-h2, .ddb-h3) {
  letter-spacing: var(--ddb-track-display);
  line-height: var(--ddb-lh-heading);
  color: var(--ddb-primary);
}
.ddb :where(.ddb-hero, .ddb-pagehead, .ddb-band, .ddb-footer, .ddb-lhero, .ddb-cat, .ddb-tcard) :where(.ddb-h1, .ddb-h2, .ddb-h3) { color: var(--ddb-ink-invert); }

/* Accent words step up to SemiBold from whatever weight their heading is set in.
   Emphasis is weight only — the design never recolours an accent, and the accent
   is not always mid-sentence (node 119:2206 emphasises the first word). */
.ddb .ddb-accent { font-weight: var(--ddb-w-bold); }

/* Heading variants — one rule per heading the design actually draws, at the size
   and weight its own node specifies. Nothing is rounded to a shared ramp. */
.ddb .ddb-hero    .ddb-h1 { font-size: var(--ddb-t-hero);    font-weight: var(--ddb-w-light);  line-height: var(--ddb-lh-display); }  /* 119:1970 — 55 Light, solid */
.ddb .ddb-intro   .ddb-h2 { font-size: var(--ddb-t-intro);   font-weight: var(--ddb-w-light);  }   /* 119:1993 — 45 Light  */
.ddb .ddb-bento   .ddb-h2 { font-size: var(--ddb-t-bento);   font-weight: var(--ddb-w-medium); line-height: var(--ddb-lh-h35); }   /* 119:2020 — 35 Medium */
.ddb .ddb-band    .ddb-h2 { font-size: var(--ddb-t-intro);   font-weight: var(--ddb-w-light);  }
.ddb .ddb-split   .ddb-h2 { font-size: var(--ddb-t-split);   font-weight: var(--ddb-w-medium); line-height: var(--ddb-lh-h40); }   /* 119:2123 — 40 Medium */
.ddb .ddb-reviews .ddb-h2 { font-size: var(--ddb-t-reviews); font-weight: var(--ddb-w-light);  }   /* 119:2206 — 45 Light  */
.ddb .ddb-res     .ddb-h2 { font-size: var(--ddb-t-news);    font-weight: var(--ddb-w-medium); }   /* 119:2147 — 45 Medium */

/* Sections whose own frames have not been measured yet default to the news
   heading treatment; each is corrected as its page is built. */
.ddb :where(.ddb-tcar, .ddb-tgrid, .ddb-team, .ddb-locs, .ddb-faq, .ddb-testi,
            .ddb-process, .ddb-prices, .ddb-contact, .ddb-referral, .ddb-map,
            .ddb-gallery, .ddb-rindex, .ddb-ldet) .ddb-h2 {
  font-size: var(--ddb-t-news);
  font-weight: var(--ddb-w-medium);
}

.ddb .ddb-eyebrow {
  font-weight: var(--ddb-w-regular);
  font-size: var(--ddb-t-meta);
  letter-spacing: var(--ddb-track-ui);
  line-height: var(--ddb-lh-meta);            /* 15 → the 23 line box the frame lays out against */
  color: var(--ddb-muted);
}
.ddb :where(.ddb-hero, .ddb-pagehead, .ddb-band, .ddb-lhero) .ddb-eyebrow { color: rgb(255 255 255 / .8); }

/* Body copy: Poppins Regular 16/24 (node 119:1994). Never scaled below 16. */

.ddb :where(.ddb-hero__body, .ddb-intro__body, .ddb-bento__body,
            .ddb-band__body, .ddb-split__body) p + p {
  margin-top: .75em;
}


/* ── 3 · Buttons & links ───────────────────────────────────────────────── */

/* 191 × 56, radius 12, a 16px Medium label (nodes 119:1986 / 119:1999).
   min-width rather than a fixed width, so a longer label grows instead of
   truncating. */
.ddb .ddb-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--ddb-btn-h);
  min-width: var(--ddb-btn-minw);
  padding: 0 var(--ddb-btn-px);
  border-radius: var(--ddb-r-btn);
  font-weight: var(--ddb-w-medium);
  font-size: var(--ddb-t-ui);
  letter-spacing: var(--ddb-track-ui);
  line-height: 1;
  text-align: center;
  border: 1px solid transparent;
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease),
              color var(--ddb-dur-fast) var(--ddb-ease),
              border-color var(--ddb-dur-fast) var(--ddb-ease);
}

/* Primary is the gold fill; secondary is an outline in the identity colour. */
.ddb .ddb-btn--primary {
  background: var(--ddb-gold);
  color: var(--ddb-gold-ink);
  border-color: var(--ddb-gold);
}

.ddb .ddb-btn--dark {
  background: var(--ddb-primary);
  color: #f5f5f5;                             /* node 123:5436 */
  border-color: var(--ddb-primary);
}

.ddb .ddb-btn--secondary {
  background: transparent;
  color: var(--ddb-primary);
  border-color: var(--ddb-primary);
}

/* ── The button hierarchy ──────────────────────────────────────────────────
   One rule for the whole site, in both directions:

     PRIMARY    is always the FILLED treatment.
     SECONDARY  is always the OUTLINED treatment.
     HOVER      always ends FILLED. A filled button changes its fill to another
                approved colour; an outlined button gains one.

   Nothing inverts a fill into an outline on contact, and no section reverses
   which of the pair is the filled one. The colours change with the ground the
   pair sits on — identity green, Durley gold, or white over a photograph — but
   the hierarchy does not.

   Every rule below pairs :hover with :focus-visible, so a keyboard reaches the
   same state a pointer does rather than only the focus ring. */

.ddb .ddb-btn--primary:hover,
.ddb .ddb-btn--primary:focus-visible {
  background: var(--ddb-primary);            /* gold fill → identity fill */
  color: var(--ddb-ink-invert);
  border-color: var(--ddb-primary);
}
.ddb .ddb-btn--dark:hover,
.ddb .ddb-btn--dark:focus-visible {
  background: var(--ddb-gold);               /* identity fill → Durley gold */
  color: var(--ddb-gold-ink);
  border-color: var(--ddb-gold);
}
.ddb .ddb-btn--secondary:hover,
.ddb .ddb-btn--secondary:focus-visible {
  background: var(--ddb-primary);            /* outline → identity fill */
  color: var(--ddb-ink-invert);
  border-color: var(--ddb-primary);
}

/* On the full-bleed dark panels the pair is drawn in white rather than gold —
   the gold fill is the light-ground treatment and is not used over a
   photograph (hero nodes 119:1987 / 119:1990, band nodes 119:2094 / 119:2097).
   The hierarchy is the site's: the primary is the solid white fill and the
   secondary the white outline beside it.

   Hover keeps both filled, and moves between the two light approved colours
   the design already uses over a photograph — white and Durley gold. The
   identity green is deliberately not used for a fill here: on a #1f1f1f ground
   under a darkened photograph a green button barely separates from the panel
   behind it, however legible its own label is.

   The page header keeps its own pairing — node 119:2170 draws gold there
   against a 1.5px white outline — so it trades the same two colours the other
   way round, below in §8b. */
.ddb :where(.ddb-hero, .ddb-band, .ddb-lhero, .ddb-loc) .ddb-btn--primary {
  background: var(--ddb-white);
  color: var(--ddb-ink-deep);
  border-color: var(--ddb-white);
}
.ddb :where(.ddb-hero, .ddb-band, .ddb-lhero, .ddb-loc) .ddb-btn--primary:hover,
.ddb :where(.ddb-hero, .ddb-band, .ddb-lhero, .ddb-loc) .ddb-btn--primary:focus-visible {
  background: var(--ddb-gold);
  color: var(--ddb-gold-ink);
  border-color: var(--ddb-gold);
}
.ddb :where(.ddb-hero, .ddb-band, .ddb-lhero, .ddb-loc) .ddb-btn--secondary {
  background: transparent;
  color: var(--ddb-ink-invert);
  border-color: var(--ddb-ink-invert);
}
.ddb :where(.ddb-hero, .ddb-band, .ddb-lhero, .ddb-loc) .ddb-btn--secondary:hover,
.ddb :where(.ddb-hero, .ddb-band, .ddb-lhero, .ddb-loc) .ddb-btn--secondary:focus-visible {
  background: var(--ddb-white);
  color: var(--ddb-ink-deep);
  border-color: var(--ddb-white);
}
/* The footer keeps the plain white outline it is drawn with. Its ground is
   already the identity green, so the shared outline hover — which fills with
   that same green — would make the button vanish into the panel; it fills
   white instead. */
.ddb .ddb-footer .ddb-btn--secondary {
  background: transparent;
  color: var(--ddb-ink-invert);
  border-color: var(--ddb-ink-invert);
}
.ddb .ddb-footer .ddb-btn--secondary:hover,
.ddb .ddb-footer .ddb-btn--secondary:focus-visible {
  background: var(--ddb-white);
  color: var(--ddb-primary);
  border-color: var(--ddb-white);
}
/* Node 119:2173 — the page header's outline is 1.5px, not the 1px used elsewhere. */
.ddb .ddb-pagehead .ddb-btn--secondary { border-width: 1.5px; }

.ddb .ddb-textlink {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  font-weight: var(--ddb-w-medium);
  font-size: var(--ddb-t-ui);
  letter-spacing: var(--ddb-track-ui);
  color: var(--ddb-primary);
}
.ddb .ddb-textlink__icon { transition: transform var(--ddb-dur-fast) var(--ddb-ease); }
.ddb .ddb-textlink:hover .ddb-textlink__icon { transform: translateX(.25em); }

/* Every CTA pair is a flex row. The gutter below is the hero's (nodes 119:1986
   → 119:1989 — 16.3); sections whose own components draw a different gutter
   override it beside their other measurements rather than sharing one value.

   `min-width` is the button's *desktop* measurement, and several sections draw
   their own — 185, 191, 194.88, 195, 211. A minimum is an instruction to
   overflow rather than shrink, so in a column narrower than the pair those
   buttons pushed straight out of their track: the split section's actions ran
   44px past the column at 390.

   Capping each one as `min(191px, 100%)` looks like the fix and is a trap. A
   percentage minimum inside a shrink-to-fit or `auto`-sized track has nothing
   definite to resolve against while that track is being measured, so it counts
   as zero — the track then sizes to the button *labels* rather than to 191, and
   the pair wraps. It did exactly that to the home intro at 1728, which is a
   desktop regression to fix a mobile one.

   So the minimums stay as drawn, and the two things that actually stop them
   overflowing are structural: every column that carries a CTA pair now holds a
   floor wider than the pair (400–440px, set per component below), and beneath
   600 the pair gives up inline layout altogether and takes the measure. */
.ddb .ddb-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16.3px;
  margin-top: clamp(20px, 2vw, 34px);
  min-width: 0;
}
.ddb :where(.ddb-intro__actions) { gap: 9px; }   /* nodes 119:1998 → 123:3916 */
.ddb .ddb-actions > .ddb-btn { max-width: 100%; }

/* Below the width at which a pair stops fitting side by side, a wrapped button
   sitting at its desktop minimum reads as a stray tile rather than as a CTA.
   Once they have wrapped they take the column (§21 of the amendments). */
@media (max-width: 600px) {
  .ddb .ddb-actions { width: 100%; }
  .ddb .ddb-actions > .ddb-btn { flex: 1 1 100%; min-width: 0; }
}

/* Circular carousel arrows (nodes 119:2149 / 119:2155 and 119:2104 / 119:2110).
   The design draws one control in two interaction states — a sand disc with the
   identity arrow at rest, and the identity disc with a white arrow on contact.
   It is NOT one style for previous and another for next: both controls sit in
   the default state until the pointer or keyboard reaches that particular one. */
.ddb .ddb-arrow {
  display: inline-grid;
  place-items: center;
  width: 63px;
  height: 63px;
  border-radius: 50%;
  border: 0;
  background: var(--ddb-sand);
  color: var(--ddb-primary);
  font-size: 18px;
  cursor: pointer;
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease),
              color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-arrow:hover,
.ddb .ddb-arrow:focus-visible {
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
}
.ddb .ddb-arrow[disabled] { opacity: .25; cursor: default; }


/* ── 4 · Interactive cards ─────────────────────────────────────────────── */

/* The highlight treatment for a genuinely clickable card, read off the one
   place the UI Design draws it: node 192:5143, the card behind the second
   treatment column. That card sits 4px outside the image on the left, top and
   right, is filled #fefbf4, and is rounded 52 at the head and 30 at the foot.
   The copy inside it keeps its own 21px indent from the image edge, so it
   never crowds the card's sides. No shadow, no lift, no gradient. */

/* `display` is only a sensible default here, so it is kept at the lowest
   specificity — a section that lays its own card out as a grid or a flex row
   must not have to fight this rule to do so. */
.ddb :where(.ddb-card-link) { display: block; }
.ddb .ddb-card-link { position: relative; }

/* Stacked cards (photograph above, copy beneath) take the highlight as a
   pseudo-element drawn *behind* the card and 4px outside it. Because nothing
   in the card's own box model changes, hovering can never shift a carousel,
   resize a tile or reflow a row.

   The card owns its own stacking context, so a negative z-index stays behind
   the card's content rather than escaping to the root and vanishing behind the
   page's background. */
.ddb :where(.ddb-rcard, .ddb-split__panel).ddb-card-link { isolation: isolate; }
.ddb :where(.ddb-rcard, .ddb-split__panel).ddb-card-link::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: calc(-1 * var(--ddb-card-inset)) calc(-1 * var(--ddb-card-inset)) 0;
  border-radius: var(--ddb-r-hover-top) var(--ddb-r-hover-top) var(--ddb-r-hover-bot) var(--ddb-r-hover-bot);
  background: var(--ddb-card-hi);
  opacity: 0;
  transition: opacity var(--ddb-dur) var(--ddb-ease);
  pointer-events: none;
}
.ddb :where(.ddb-rcard, .ddb-split__panel).ddb-card-link:hover::before,
.ddb :where(.ddb-rcard, .ddb-split__panel).ddb-card-link:focus-visible::before { opacity: 1; }

/* Image-filled tiles — the category tiles and the treatment cards — used to
   take the same treatment: the photograph drew back 4px on hover and the tile's
   coloured ground showed through as a frame around it. It is dropped. Whatever
   it does on the one card the design draws it on, on a photographic tile it
   reads as the picture shrinking away from the reader at the moment they reach
   for it, and the inset frame it leaves looks like a rendering fault.

   In its place, the restrained treatment: the picture takes a small step
   toward the reader and brightens slightly, and the scrim over it lightens to
   match. The tile's own box never changes — the transform is on the image layer
   inside an `overflow: hidden` tile — so there is no layout shift, nothing
   moves in a carousel row, and the title seated over the photograph stays
   exactly where it was. */
/* The transform is on the picture itself, not on the layer holding it: the
   layer keeps the tile's radius and its `overflow: hidden`, so the enlarged
   photograph is cropped by the tile's own corners, and the scrim painted on
   that layer stays exactly where it is instead of scaling with the image. */
.ddb .ddb-cat__img,
.ddb .ddb-tcard__media .ddb-media__img {
  transition: transform var(--ddb-dur) var(--ddb-ease),
              filter var(--ddb-dur) var(--ddb-ease);
}
.ddb .ddb-cat.ddb-card-link:hover .ddb-cat__img,
.ddb .ddb-cat.ddb-card-link:focus-visible .ddb-cat__img,
.ddb .ddb-tcard.ddb-card-link:hover .ddb-tcard__media .ddb-media__img,
.ddb .ddb-tcard.ddb-card-link:focus-visible .ddb-tcard__media .ddb-media__img {
  transform: scale(1.03);
  filter: brightness(1.06);
}
/* Easing the scrim back is what lets the brightening be seen at all through a
   50% black. */
.ddb :where(.ddb-cat, .ddb-tcard) :where(.ddb-cat__media, .ddb-tcard__media)::after {
  transition: background-color var(--ddb-dur) var(--ddb-ease);
}
.ddb .ddb-cat.ddb-card-link:hover .ddb-cat__media::after,
.ddb .ddb-cat.ddb-card-link:focus-visible .ddb-cat__media::after { background: rgb(0 0 0 / .42); }
.ddb .ddb-tcard.ddb-card-link:hover .ddb-tcard__media::after,
.ddb .ddb-tcard.ddb-card-link:focus-visible .ddb-tcard__media::after { background: rgb(0 0 0 / .45); }

/* The stacked cards keep their highlight card — it is the one interactive
   treatment the UI Design actually draws, it moves nothing, and the resource
   card's "Read More" pill depends on it to be legible at all. They gain the
   same image step, so every clickable image card on the site now reacts the
   same way. */
.ddb :where(.ddb-rcard__media, .ddb-split__media) { overflow: hidden; }
.ddb :where(.ddb-rcard__img, .ddb-split__img) {
  transition: transform var(--ddb-dur) var(--ddb-ease),
              filter var(--ddb-dur) var(--ddb-ease);
}
.ddb :where(.ddb-rcard, .ddb-split__panel).ddb-card-link:hover :where(.ddb-rcard__img, .ddb-split__img),
.ddb :where(.ddb-rcard, .ddb-split__panel).ddb-card-link:focus-visible :where(.ddb-rcard__img, .ddb-split__img) {
  transform: scale(1.03);
  filter: brightness(1.04);
}

@media (prefers-reduced-motion: reduce) {
  .ddb .ddb-cat__img,
  .ddb .ddb-tcard__media .ddb-media__img,
  .ddb :where(.ddb-cat, .ddb-tcard) :where(.ddb-cat__media, .ddb-tcard__media)::after,
  .ddb :where(.ddb-rcard__img, .ddb-split__img),
  .ddb :where(.ddb-rcard, .ddb-split__panel).ddb-card-link::before { transition: none; }
}


/* ── 5 · Header (node 2:286) ───────────────────────────────────────────── */

.ddb-header {
  position: relative;
  z-index: 20;
  padding: 21px 0 0;               /* bar sits at y 21 and ends at 78 */
  background: var(--ddb-ground);
  color: var(--ddb-ink-deep);
}

/* Inner pages: the navigation sits over the page-header panel in white, with
   the gold booking button (node 119:1973, placed at x 47 / y 41). It occupies
   no vertical space, so the panel still starts at the top of the document
   exactly as the frame draws it — but it stays *in* flow so it can be sticky
   without the page jumping when the state changes. */
/* The document shell.
   A short page — a policy before its content is written, the 404 — left the
   footer partway up the screen with the page's background below it. The page
   fills the viewport instead, and the main region takes whatever height is
   spare, so the footer sits on the bottom edge when there is not enough content
   to push it there and follows the content when there is. Never `fixed`.

   `svh` is the small viewport, the height with the mobile browser's chrome
   *showing*, so the page can never be taller than the screen and start the
   document scrolling by itself. The admin bar is subtracted because WordPress
   moves the document down by its height, which would otherwise put exactly that
   much of the page below the fold; it is 0 for every visitor, so nothing about
   the logged-out page changes.

   `flex: 1 0 auto` rather than `flex: 1`: the shorthand's 0% basis would let the
   main region be measured as though it had no content, and on a long page the
   footer is meant to follow that content, not float over it.

   The main region growing is the whole mechanism — there is deliberately no
   `margin-top: auto` on the footer, which would push it down just as well but
   would also override the measured gap the design leaves above it on every
   long page, where `auto` resolves to zero. */
.ddb-site {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: calc(100vh - var(--ddb-admin-bar, 0px));
}
@supports (min-height: 100svh) {
  .ddb-site { min-height: calc(100svh - var(--ddb-admin-bar, 0px)); }
}
.ddb .ddb-main { flex: 1 0 auto; }
.ddb-header--overlay {
  padding-top: 35px;               /* node 119:2175 — menu at y 35 */
  margin-bottom: -92px;            /* 35 + 57: the bar overlays rather than stacks */
  background: transparent;
  color: var(--ddb-ink-invert);
}
.ddb-header--overlay .ddb-header__inner {
  max-width: var(--ddb-cap);
  padding-inline: clamp(20px, 2.72vw, 47px);
}
/* The area frames place their own menu 6px lower than the shared Page-Header
   component does — nodes 164:5307 / 164:5255 / 164:5358 at y 41 against node
   119:2175 at y 35. Both values are in the design, so both are kept. */
.ddb-page--division .ddb-header--overlay { padding-top: 41px; margin-bottom: -98px; }

/* Sticky is `sticky`, never `fixed`: the bar keeps its place in the document,
   so nothing below it moves when it pins.

   `top` is the WordPress admin bar's height, which is 0 for every visitor —
   --ddb-admin-bar is only ever set to anything else while an editor is logged
   in and the toolbar is genuinely pinned to the viewport. Nothing about the
   public page changes. */
.ddb-header--sticky {
  position: sticky;
  top: var(--ddb-admin-bar, 0px);
}

.ddb-header__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: clamp(16px, 2vw, 40px);
  /* The header keeps its own gutter: node 123:5437 spans x 46 → 1681 on the
     1728 frame, so 46 either side rather than the page's 117. */
  width: 100%;
  /* The navigation stops widening at the same cap the page's sections do, so on
     a very wide monitor the bar and the content below it centre on one another
     rather than the bar sitting inside the composition. At 1728 and below the
     cap is inert and the frame's own 46px gutter is what applies. */
  max-width: var(--ddb-cap);
  padding-inline: clamp(20px, 2.662vw, 46px);
  margin-inline: auto;
  height: 57px;
}
/* The lockup is 71 tall and bleeds 7 above and below the 57 bar rather than
   stretching it (node 123:5388 at y −6.99, node 164:5216 at y −7). Its width is
   whatever the artwork is: 170.37 for the Implants lockup, 180.80 for
   Wellbeing — so the height is what is set and the width follows the SVG's own
   ratio. The box is held at 57 so the taller artwork cannot stretch the bar. */
.ddb-header__brand {
  position: relative;
  height: 57px;
  display: grid;
  place-items: center;
}
.ddb-header .ddb-brand {
  display: grid;
  place-items: center;
  line-height: 0;
}
/* Both grounds' artwork is stacked in one cell so the sticky container can
   cross-fade between them; only one is ever visible or hit-testable. */
.ddb-header .ddb-brand__img { grid-area: 1 / 1; }
.ddb-header .ddb-brand__img--light { opacity: 1; }
.ddb-header .ddb-brand__img--dark  { opacity: 0; }
.ddb-header--overlay .ddb-brand__img--light { opacity: 0; }
.ddb-header--overlay .ddb-brand__img--dark  { opacity: 1; }
.ddb-header .ddb-brand__img { transition: opacity var(--ddb-dur) var(--ddb-ease); }

.ddb .ddb-nav {
  display: flex;
  align-items: center;
  gap: clamp(14px, 1.85vw, 32px);
}
.ddb .ddb-nav a {
  font-weight: var(--ddb-w-light);
  font-size: var(--ddb-t-ui);
  letter-spacing: var(--ddb-track-ui);
  line-height: var(--ddb-lh-ui);
}
/* The underline belongs to the bar's own links and nothing else. Declared on
   the link class rather than on every `a` inside the navigation, because the
   dropdown card, its booking button and the phone panel's rows all live
   inside the same <nav>, and a rule on `a` reached all of them: a dark rule
   appeared under a hovered button and under a cream row. */
.ddb .ddb-nav__link {
  padding-block: 4px;
  border-bottom: 1px solid transparent;
  transition: border-color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-nav__link:hover,
.ddb .ddb-nav__link[aria-current="page"] { border-bottom-color: currentColor; }

.ddb-header__nav--right ul { justify-content: flex-end; }

.ddb-header__brand { justify-self: center; }
.ddb .ddb-brand__img { height: auto; }
/* Sized by height so the aspect ratio is the SVG's own and never CSS's guess. */
.ddb-header .ddb-brand__img {
  height: clamp(48px, 4.109vw, 71px);   /* nodes 123:5388 / 164:5216 — 71 tall */
  width: auto;
  max-width: none;
}
.ddb-footer .ddb-brand__img { width: clamp(200px, 17.34vw, 300px); }   /* node 123:5592 */
.ddb .ddb-brand__text {
  font-size: clamp(18px, 1.4vw, 24px);
  letter-spacing: var(--ddb-track-display);
}

.ddb-header__end {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: clamp(14px, 1.85vw, 32px);
}
.ddb .ddb-header__cta { flex: none; }


/* ── 5a · The scrolled header ──────────────────────────────────────────── */

/* At rest both variants are exactly what the UI Design draws. Once the page
   scrolls past the bar it becomes a plain full-width navigation: the background
   spans the viewport edge to edge, while the navigation inside keeps its own
   measure and centres. No rounded container, no gutter, no shadow. */
.ddb-header--sticky .ddb-header__inner,
.ddb-header--sticky {
  transition: background-color var(--ddb-dur) var(--ddb-ease),
              box-shadow var(--ddb-dur) var(--ddb-ease),
              padding var(--ddb-dur) var(--ddb-ease),
              margin var(--ddb-dur) var(--ddb-ease);
}
/* The lockup shrinks with the bar rather than snapping to its stuck size. */
.ddb-header__brand .ddb-brand__img { transition: height var(--ddb-dur) var(--ddb-ease); }

/* The scrolled bar is solid white, edge to edge.
   It was translucent glass, and the blur behind it was costing the lockup its
   legibility: the artwork is a fine-weight wordmark, and whatever photograph
   happened to be travelling under the bar showed through it. So the ground is
   now opaque — no translucency, no backdrop-filter, no fallback to guess at,
   and nothing behind the navigation to read it against.

   Everything else about the bar is what it already was, and is what the brief
   asks for: the background is painted by the header element itself, which is a
   full-width block, so the bar already spans the viewport with no rounded
   corners, no outer gutter and no floating-card inset. The navigation inside it
   keeps its own measure and centres.

   The hairline is an *inset* shadow rather than a border so separating the bar
   from the page beneath it costs no height — a real border would grow the box
   and nudge the whole document down at the moment it pins. It is a 7%-opacity
   rule, not a drop shadow: with a white bar over white page content there has
   to be some edge, and this is the lightest one that provides it. The negative
   bottom margin does the same job for the padding change, so the flow height at
   rest (21 + 57) and stuck (12 + 57 + 12) is identical and the page never
   jumps. */
.ddb-header--sticky.is-stuck {
  padding-block: 12px;             /* the 57 bar plus 12 either side */
  margin-bottom: -3px;             /* 81 back to the 78 the bar occupies at rest */
  background: var(--ddb-white);
  box-shadow: inset 0 -1px 0 rgb(31 31 31 / .07);
  color: var(--ddb-ink-deep);
}
/* The lockup is drawn at 71 tall, which is 7px taller than the 57 bar it sits
   in and reaches within 5px of the stuck bar's painted edge — 2px of the
   flow edge the content below it starts at. At rest that bleed is the design
   (nodes 123:5388 / 164:5216) and there is white page above and below it to
   bleed into; pinned there is not, and the mark read as though it were resting
   on the bottom of the bar.

   The bar's height is untouched — the whole navigation would have had to grow
   to give a 71px mark room, and the brief asks for it to stay compact. What
   changes is the artwork inside the 57px brand box, which is held clear of both
   edges: 46 tall in an 81 tall bar leaves 17.5px above and below the painted
   edge, and 14.5 to the flow edge. The nav links and the booking button beside
   it do not move at all — they are laid out by the bar, not by the lockup. */
.ddb-header--sticky.is-stuck .ddb-header__brand .ddb-brand__img { height: 46px; }

/* Above the cap the navigation stops widening and centres; the white ground
   carries on to the viewport edges behind it. Same cap pinned as at rest, so
   nothing about the bar's width changes when it detaches. */
.ddb-header--sticky.is-stuck .ddb-header__inner {
  max-width: var(--ddb-cap);
}

/* Over a dark panel the bar is white once it detaches, so the ink, the lockup
   and the booking button all return to their light-ground treatment. */
/* The overlay bar occupies no space at rest (35 + 57 cancelled by −92) and must
   still occupy none once it pins, so its own negative margin follows the stuck
   box: 12 + 57 + 12. */
.ddb-header--overlay.is-stuck { padding-top: 12px; margin-bottom: -81px; }
.ddb-header--overlay.is-stuck .ddb-brand__img--light { opacity: 1; }
.ddb-header--overlay.is-stuck .ddb-brand__img--dark  { opacity: 0; }
.ddb-header--overlay.is-stuck .ddb-header__cta {
  background: var(--ddb-primary);
  border-color: var(--ddb-primary);
  color: var(--ddb-ink-invert);
}
/* Pinned, the booking button is the identity solid — which is also what the
   shared gold-primary hover resolves to, so without this the button would have
   no hover state at all once the bar detached. It takes the same filled → gold
   step every other identity-filled button on the site takes. */
.ddb-header--overlay.is-stuck .ddb-header__cta:hover,
.ddb-header--overlay.is-stuck .ddb-header__cta:focus-visible {
  background: var(--ddb-gold);
  border-color: var(--ddb-gold);
  color: var(--ddb-gold-ink);
}

@media (prefers-reduced-motion: reduce) {
  .ddb-header--sticky,
  .ddb-header--sticky .ddb-header__inner,
  .ddb-header__brand .ddb-brand__img { transition: none; }
}


/* ── 5b · The header on a narrow screen ─────────────────────────────────────
   The UI Design is drawn at 1728 only, so there is no signed-off mobile
   masthead. What there is, is a rule the rest of the site follows: present the
   same things, in the same identity, in the shape the width allows. So the bar
   keeps its lockup and its booking button — the two things a visitor arrives
   wanting — and the eight navigation items, which will not fit beside them,
   move into a panel behind a single control.

   The composition is the one the brief asks for and the one a masthead is
   normally read in: the lockup pinned hard left, the booking button and the
   burger grouped together hard right, and genuinely flexible space between
   them. Nothing is independently centred — the button is a member of the
   right-hand group, not a third column of its own.
   ────────────────────────────────────────────────────────────────────────── */

.ddb-header__burger {
  display: none;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-right: -10px;                /* optical: the bars align with the bar's own gutter */
  color: inherit;
  flex: none;
}
/* Three bars rather than two, and 2.5px rather than 2. Beside a filled booking
   button a two-bar mark at a hairline weight read as the lighter of the two
   controls; this is the weight that balances it. 24 wide × 18 tall overall. */
.ddb-burger {
  display: grid;
  gap: 5px;
  width: 24px;
}
.ddb-burger span {
  display: block;
  height: 2.5px;
  border-radius: 2px;
  background: currentColor;
}

/* ── The mobile navigation panel ──────────────────────────────────────────
   Not a dropdown under the bar: a full-width panel that arrives from the top of
   the viewport and covers the masthead it came from, carrying its own lockup
   and its own close control in the places the closed bar puts them. So there is
   never a second header competing above or below it while it is open.

   It is height-fluid rather than a forced full screen — eight items, a lockup
   and a booking button do not fill a tablet, and a panel padded out to do so
   would be emptier than the composition deserves. It will scroll inside itself
   if the viewport is short enough to need it. */
/* Two layers, no extra markup: the outer element is the full-viewport backdrop
   and the inner one is the panel that travels. Splitting them this way is what
   lets the page behind be dimmed — a scrim cannot be a child of a transformed
   element, because a transform makes that element the containing block for
   anything fixed inside it, and the scrim would then slide up with the panel
   instead of covering the viewport.

   Dimming matters here: without it the panel reads as a card dropped on top of
   the page, and the hero carries on competing underneath it. With it, the menu
   is the only thing on screen, which is what the brief is asking for. */
.ddb-header__panel {
  position: fixed;
  inset: var(--ddb-admin-bar, 0px) 0 0 0;
  z-index: 60;
  /* A soft blue-slate rather than a plain black dim, with a light blur pulling
     the page out of focus behind it — enough character to read as the
     practice's own scrim, never a solid block. The colour carries the tint;
     the blur is what keeps it feeling like glass rather than paint. */
  background: rgb(31 51 72 / .45);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity var(--ddb-dur) var(--ddb-ease);
}
.ddb-header__panel.is-open { opacity: 1; }
.ddb-header__panel[hidden] { display: none; }

/* The panel's contents keep the same measure and the same gutter as the bar
   they replaced, so the lockup inside the open menu sits exactly where the
   lockup in the closed bar did and the two do not appear to jump.

   It is height-fluid rather than a forced full screen — eight items, a lockup
   and a booking button do not fill a tablet, and a panel padded out to do so
   would be emptier than the composition deserves. It scrolls inside itself when
   the viewport is genuinely too short, and `overscroll-behavior` keeps that
   scroll from chaining to the page underneath. */
.ddb-header__panel-inner {
  width: 100%;
  max-width: var(--ddb-cap);
  margin-inline: auto;
  max-height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 0 clamp(20px, 2.662vw, 46px) clamp(24px, 4vw, 36px);
  background: var(--ddb-white);
  color: var(--ddb-ink-deep);
  /* The foot of the panel is a drawn edge over the dimmed page, so it takes
     the site's rounded language; the top stays square where it meets the
     viewport edge it arrived from. */
  border-radius: 0 0 28px 28px;
  box-shadow: 0 20px 50px rgb(0 0 0 / .18);
  /* The resting state is fully retracted, so the panel travels down from behind
     the top edge of the viewport rather than fading in place. */
  transform: translateY(-100%);
  transition: transform var(--ddb-dur) var(--ddb-ease);
}
.ddb-header__panel.is-open .ddb-header__panel-inner { transform: translateY(0); }

/* The panel's own masthead — lockup left, close right, on the bar's own
   21 + 57 rhythm so it lands on the closed bar's geometry. */
.ddb-header__panel-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 52px;                   /* the closed bar's rhythm; the enlarged
                                         lockup may deepen it a few pixels */
  margin-top: 21px;
  margin-bottom: clamp(16px, 3vw, 28px);
}
.ddb-header__panel-brand { display: flex; align-items: center; }
.ddb-header__panel .ddb-brand { display: block; line-height: 0; }
.ddb-header__panel .ddb-brand__img {
  /* A step up from the closed bar's 54px cap, so the lockup leads the open
     menu rather than merely persisting from the bar. The vw term brings it
     back through the close control's clearance on a small phone. */
  height: clamp(48px, 15vw, 60px);
  width: auto;
  max-width: none;
  opacity: 1;                         /* never the bar's cross-fade pair */
}

/* The close control is the burger's counterpart and sits on its footprint, so
   the mark a reader pressed to open is where the mark to close it appears. */
.ddb-header__close {
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  margin-right: -10px;
  color: inherit;
}
.ddb-close { position: relative; display: block; width: 22px; height: 22px; }
.ddb-close::before,
.ddb-close::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 2.5px;
  border-radius: 2px;
  background: currentColor;
}
.ddb-close::before { transform: rotate(45deg); }
.ddb-close::after  { transform: rotate(-45deg); }

/* ── The navigation itself ──
   Editorial rather than a plugin menu: each item is a full-width row set at the
   scale of a section heading, with the whole row — not the words in it — the
   thing that is clicked. The hairlines that used to separate the rows are
   gone: each row is now its own rounded rectangle, radiused in the buttons'
   language (--ddb-r-btn), and the cream interaction ground appears inside that
   shape. Deliberately not a full CTA treatment — no fill at rest, no minimum
   height, type still at heading scale — so the rows read as navigation that
   happens to be pressable, not as a stack of buttons. */
.ddb .ddb-nav--stacked {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.ddb .ddb-nav--stacked li { margin: 0; }
.ddb .ddb-nav--stacked a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: clamp(13px, 2.4vw, 18px) clamp(14px, 2.4vw, 20px);
  border-radius: var(--ddb-r-btn);
  font-weight: var(--ddb-w-light);
  font-size: clamp(23px, 5.6vw, 32px);
  letter-spacing: var(--ddb-track-display);
  line-height: var(--ddb-lh-display);
  color: var(--ddb-ink-deep);
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease),
              color var(--ddb-dur-fast) var(--ddb-ease),
              padding-left var(--ddb-dur-fast) var(--ddb-ease);
}
/* The chevron is drawn rather than set in the icon font, so a row costs no
   extra request and the mark scales with the label it belongs to. */
.ddb .ddb-nav--stacked a::after {
  content: "";
  flex: none;
  width: .34em;
  height: .34em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  opacity: .35;
  transition: opacity var(--ddb-dur-fast) var(--ddb-ease),
              transform var(--ddb-dur-fast) var(--ddb-ease);
}
/* The interaction: the cream the rest of the site uses for a hovered card, the
   identity colour on the words, and the row's content stepping a little to the
   right. Restrained on purpose — the row is large enough that anything more
   would be noise. */
.ddb .ddb-nav--stacked a:hover,
.ddb .ddb-nav--stacked a:focus-visible {
  background: var(--ddb-card-hi);
  color: var(--ddb-primary);
  padding-left: clamp(20px, 3.4vw, 28px);
}
.ddb .ddb-nav--stacked a:hover::after,
.ddb .ddb-nav--stacked a:focus-visible::after { opacity: 1; transform: rotate(-45deg) translate(2px, 2px); }
/* The current page holds the same cream inside its rounded row, so "where am
   I" and "what am I pressing" are one treatment. */
.ddb .ddb-nav--stacked a[aria-current="page"] {
  background: var(--ddb-card-hi);
  color: var(--ddb-primary);
  font-weight: var(--ddb-w-regular);
}

/* The booking CTA keeps the standardised primary treatment — filled, full
   width, and the most prominent thing left in the panel once the rows above it
   have been read. */
.ddb-header__panel-cta { margin-top: clamp(20px, 3.6vw, 30px); }
.ddb-header__panel-cta .ddb-btn { width: 100%; min-height: 60px; }

/* While the panel is open the document behind it must not scroll. The
   scrollbar's width is handed back as padding at the same moment, so locking
   cannot shift the page sideways under the panel. */
body.ddb-menu-open { overflow: hidden; }
html:has(body.ddb-menu-open) { padding-right: var(--ddb-scrollbar, 0px); }
/* The header is the panel's stacking context, and the logged-in editing pencils
   sit at 40 in the same context the header's 20 does — so while the panel is
   open the header has to outrank them, or an editor sees a pencil floating over
   the menu. Only while it is open: nothing about the resting page changes. */
body.ddb-menu-open .ddb-header { z-index: 100; }

/* 1220, measured rather than chosen. The space between the lockup and the
   right-hand navigation is 229px at the frame width and closes steadily as the
   bar narrows: 122 at 1440, 56 at 1260, 34 at 1200, 15 at 1150. Below about 40
   the "Resources" link is touching the mark, and the bar reads as compressed
   for a good 120px before the trigger used to appear at 1100. It now hands over
   while the desktop bar still looks like a desktop bar (§29 of the brief). */
@media (max-width: 1220px) {
  .ddb-header__nav--left,
  .ddb-header__nav--right { display: none; }
  .ddb-header__burger { display: grid; }

  /* Logo left, actions right, real space between them — as a flex row rather
     than the desktop's `1fr auto 1fr` grid, whose centre column is what was
     holding the lockup in the middle of the bar.

     Flex rather than a two-track grid because of what happens when the bar runs
     out of room. In a grid the actions sit in a `1fr` track, and an `fr` track
     never *demands* its content: it takes what is left after the lockup has had
     its natural width, and anything that does not fit simply hangs out of the
     track. Here the priority is explicit — the actions do not shrink, the
     lockup does — so a booking label a couple of words longer than the one in
     place narrows the mark instead of pushing the button through the side of
     the bar. The artwork keeps its own ratio while it does (`height: auto`
     under a max-height), so nothing is ever stretched. */
  .ddb-header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
  .ddb-header__brand { justify-self: start; flex: 0 1 auto; min-width: 0; }
  .ddb-header__brand .ddb-brand { min-width: 0; max-width: 100%; }
  .ddb-header__end { flex: 0 0 auto; gap: 14px; }

  /* Larger than the 48px floor the desktop clamp bottoms out at: at this width
     the lockup was the smallest thing in the bar and read as an afterthought
     beside the booking button. The bar's own height is unchanged. */
  .ddb-header__brand .ddb-brand__img { height: auto; max-height: 54px; max-width: 100%; }
  .ddb-header--sticky.is-stuck .ddb-header__brand .ddb-brand__img { height: auto; max-height: 46px; }
}

@media (max-width: 620px) {
  /* The bar tightens, but the composition does not change: the booking button
     stays in the right-hand group beside the burger, because it is the reason
     most people open the site on a phone. It gives up its minimum width and
     some of its padding rather than its place. */
  .ddb-header__inner { height: 52px; }
  .ddb-header__brand { height: 52px; }
  .ddb-header__brand .ddb-brand__img { height: auto; max-height: 46px; max-width: 100%; }
  .ddb-header--sticky.is-stuck .ddb-header__brand .ddb-brand__img { height: auto; max-height: 42px; }
  .ddb-header__end { gap: 8px; }
  .ddb .ddb-header__cta {
    min-width: 0;
    min-height: 42px;
    padding-inline: 14px;
    font-size: 14px;
  }
  .ddb-header__burger { width: 40px; margin-right: -8px; }
}

@media (max-width: 400px) {
  /* Below this the label and the burger genuinely collide, so the button
     shortens rather than wraps or overlaps. */
  .ddb .ddb-header__cta { font-size: 13px; padding-inline: 11px; }
  .ddb-burger { width: 22px; }
}

@media (prefers-reduced-motion: reduce) {
  .ddb-header__panel,
  .ddb-header__panel-inner { transition: none; }
  .ddb .ddb-nav--stacked a,
  .ddb .ddb-nav--stacked a::after { transition: none; }
}

/* ── 6 · Footer (node 1:96) ────────────────────────────────────────────── */

.ddb-footer { margin-top: clamp(40px, 4.282vw, 74px); }

.ddb-footer__panel {
  position: relative;
  overflow: hidden;
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
  border-radius: var(--ddb-r-panel) var(--ddb-r-panel) 0 0;   /* node 119:1958 */
  padding-block: clamp(24px, 2.4vw, 42px) clamp(24px, 2.4vw, 40px);
  min-height: clamp(360px, 29.3vw, 506px);                    /* 506 tall */
  display: grid;
  align-content: start;
}

/* Beneath the typographic strip: the lockup on the left with the four link
   columns beside it, then a bottom line carrying the copyright and the social
   marks. The top padding is what keeps the lockup at y 241 of the frame's
   506, clear of the strip, and is unchanged. */
.ddb-footer__inner {
  width: min(100% - (2 * var(--ddb-gutter)), var(--ddb-content));
  margin-inline: auto;
  padding-top: clamp(60px, 8vw, 138px);      /* logo sits at y 241.5 of 464 */
}
.ddb-footer__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: clamp(32px, 4.5vw, 80px);
}
.ddb-footer__brand { flex: 0 0 auto; }
.ddb-footer .ddb-brand { display: block; line-height: 0; }

/* Four columns, each as wide as its longest link and no wider, with an even
   gutter between them. `auto` tracks rather than `1fr`: the columns are read
   as a set of short lists, not as four quarters of the measure. */
.ddb-footer__groups {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, auto));
  column-gap: clamp(28px, 3.6vw, 64px);
  row-gap: 28px;
  flex: 0 1 auto;
  min-width: 0;
}
.ddb-footer__group { min-width: 0; }
.ddb .ddb-footer__group-title {
  margin: 0 0 14px;
  font-weight: var(--ddb-w-medium);
  font-size: var(--ddb-t-meta);
  letter-spacing: var(--ddb-track-ui);
  line-height: var(--ddb-lh-meta);
  color: rgb(255 255 255 / .62);
}
/* The heading is a button so that on a phone it can fold its list. On a wide
   screen it is inert: no expanded state, out of the tab order, the pointer
   passes through it, and it is drawn exactly as the heading it is. */
.ddb .ddb-footer__toggle {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 0;
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
  text-align: left;
  pointer-events: none;
  cursor: default;
}
.ddb .ddb-footer__toggle .ddb-mark { display: none; }
.ddb-footer__list ul { display: grid; gap: 10px; }
.ddb-footer__list a {
  display: inline-block;
  font-weight: var(--ddb-w-light);
  font-size: var(--ddb-t-link);              /* 17 (node 119:1959) */
  letter-spacing: var(--ddb-track-ui);
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: border-color var(--ddb-dur-fast) var(--ddb-ease);
}
/* The Figma shows a rule beneath the current page's link (node 1:91). */
.ddb-footer__list a:hover,
.ddb-footer__list a[aria-current="page"] { border-bottom-color: currentColor; }

.ddb-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 24px;
  margin-top: clamp(32px, 3.4vw, 56px);
  padding-top: clamp(20px, 2vw, 28px);
  border-top: 1px solid rgb(255 255 255 / .14);
}
.ddb-footer__copyright {
  font-weight: var(--ddb-w-light);
  font-size: var(--ddb-t-meta);              /* 15 (node 119:1965) */
  letter-spacing: var(--ddb-track-ui);
  color: var(--ddb-muted-invert);
}
.ddb .ddb-footer__credit { text-decoration: underline; }

.ddb-footer__social {
  display: flex;
  gap: 14px;
}
.ddb-footer__social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px; height: 40px;
  border: 1px solid var(--ddb-line-invert);
  border-radius: 50%;
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease), color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb-footer__social a:hover { background: var(--ddb-white); color: var(--ddb-primary); }

/* Content-driven steps, measured rather than chosen. The lockup and four
   columns need about 1080px of measure between the gutters; below it the
   lockup takes a line of its own above the columns. Four columns need about
   640px; below it they pair up. And a phone folds each column away behind
   its heading. */
@media (max-width: 1180px) {
  .ddb-footer__top { flex-direction: column; gap: clamp(28px, 4.5vw, 44px); }
  .ddb-footer__groups { width: 100%; justify-content: space-between; }
}
@media (max-width: 860px) {
  .ddb-footer__groups { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 32px; }
}
@media (max-width: 620px) {
  .ddb-footer__inner { padding-top: clamp(48px, 12vw, 80px); }
  .ddb-footer__groups { grid-template-columns: minmax(0, 1fr); row-gap: 0; }
  .ddb-footer__group { border-top: 1px solid rgb(255 255 255 / .14); }
  .ddb-footer__group:last-child { border-bottom: 1px solid rgb(255 255 255 / .14); }
  .ddb .ddb-footer__group-title { margin: 0; color: var(--ddb-ink-invert); }
  .ddb .ddb-footer__toggle {
    display: flex;
    width: 100%;
    justify-content: space-between;
    min-height: 58px;
    padding: 14px 4px;
    pointer-events: auto;
    cursor: pointer;
    font-weight: var(--ddb-w-regular);
    font-size: var(--ddb-t-link);
  }
  .ddb .ddb-footer__toggle .ddb-mark { display: block; width: 12px; height: 12px; opacity: .75; }
  .ddb .ddb-footer__toggle[aria-expanded="true"] .ddb-mark { opacity: 1; }
  .ddb .ddb-footer__list { overflow: hidden; transition: height var(--ddb-dur) var(--ddb-ease); }
  .ddb .ddb-footer__list[hidden] { display: none; }
  .ddb-footer__list ul { gap: 2px; padding: 0 4px 16px; }
  .ddb-footer__list a { display: block; padding: 10px 0; border-bottom: 0; color: rgb(255 255 255 / .86); }   /* a 44px row to tap */
  .ddb-footer__list a:hover,
  .ddb-footer__list a[aria-current="page"] { border-bottom: 0; color: var(--ddb-ink-invert); }
  .ddb-footer__bottom {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 18px;
    margin-top: 28px;
    padding-top: 0;
    border-top: 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  .ddb .ddb-footer__list { transition: none; }
}


/* ── 7 · Marquee (nodes 2:557 & 1:95) ──────────────────────────────────── */

.ddb-marquee,
.ddb-footer__marquee {
  overflow: hidden;
  user-select: none;
  pointer-events: none;
}

/* The strip is exactly its own type height (node 119:2015 — 135); the space
   above and below it belongs to the neighbouring sections. */
.ddb-marquee { padding-block: 0; }

.ddb-footer__marquee {
  position: absolute;
  inset-block-start: clamp(28px, 3.6vw, 63px);
  inset-inline: 0;
}

.ddb .ddb-marquee__track {
  display: flex;
  width: max-content;
  will-change: transform;
}

.ddb .ddb-marquee__run {
  display: block;
  white-space: pre;
  font-weight: var(--ddb-w-light);
  font-size: var(--ddb-t-marquee);      /* 135 in both places */
  letter-spacing: var(--ddb-track-display);
  line-height: 1;
}

/* In-page strip: a pale green on white (node 119:2015). */
.ddb-marquee .ddb-marquee__run { color: var(--ddb-marquee-ink); }

/* Footer strip: white at 20% over the identity green (node 119:1967). */
.ddb-footer__marquee .ddb-marquee__run { color: rgb(255 255 255 / .20); }


/* ── 8 · Hero (node 1:266) ─────────────────────────────────────────────── */

.ddb-hero { padding-top: 0; }

.ddb-hero__panel {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  margin-inline: var(--ddb-bleed-inset);          /* inset 19 from each edge */
  border-radius: var(--ddb-r-panel);
  background: var(--ddb-hero-ground);
  color: var(--ddb-ink-invert);
  min-height: clamp(520px, 52.14vw, 901px);       /* 901 tall (node 123:3909) */
  display: grid;
  align-items: end;
}

.ddb-hero__media {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  /* The darkening is the image's own opacity over the panel ground, exactly as
     the Figma builds it — not an overlay layer of our own invention. */
  opacity: .63;
}
/* Node 123:3907 draws the source at 2506 × 1671 with the panel's 1690 × 901
   window opening 57 across and 748 down it — a closer, lower crop than
   object-fit: cover would choose on its own.

   That crop *was* built by placing the image at a percentage of the panel's own
   width and height with `height: auto`, and that is what broke the hero on a
   narrow viewport. Both terms are proportions of the panel, but the panel stops
   being proportional: below ~1000px its `min-height` clamp bottoms out at 520
   while its width keeps shrinking, so the natural-ratio height fell far short of
   the panel and the −83% top offset lifted what was left clean out of the frame.
   At 390px the photograph covered the top few pixels and the #1f1f1f ground
   showed through the rest — which is exactly the reported fault, and it got
   worse the narrower the screen.

   Rebuilt so the image can never be smaller than its container. The picture is
   `object-fit: cover` over the full frame — so coverage is guaranteed at every
   ratio, whatever the panel does — and the design's closer framing is put back
   on top of it as a scale about the crop's own anchor point. Scaling up about a
   point inside a box that is already covered keeps it covered, so the design
   crop and the guarantee are not in tension.

   The anchor is the design's crop expressed as a position within the overflow:
   57 of the 816px horizontal overhang (6.98%) and 748 of the 770px vertical
   (97.18%). With the scale below, that reproduces node 123:3907 exactly at
   1728 — the picture lands at (−57, −748) at 2506 × 1671, to within a pixel.

   `--ddb-hero-zoom` is the extra magnification over cover: 2506 ÷ 1690 ÷ the
   0.674 cover scale = 1.48284. It is held at the design value on desktop and
   eased back as the panel turns portrait, because a 1.48× crop of a landscape
   photograph on a phone is a face and an elbow. Coverage holds at any value
   from 1 up.

   Those values describe the Figma placeholder photograph and nothing else.
   The practice's own hero (2026-10-13) is supplied as a derivative already cut
   to the panel's 1690 × 901 proportion, so the framing is in the file: no
   magnification over cover, and a focal point on the subjects so that the
   narrower, taller panels crop around them rather than around a corner of the
   picture. The mechanism stays for the next photograph that needs it. */
.ddb-hero__media {
  --ddb-hero-zoom: 1;
  --ddb-hero-focus-x: 42%;
  --ddb-hero-focus-y: 50%;
}
.ddb .ddb-hero__media .ddb-media__frame { position: relative; }
.ddb .ddb-hero__media .ddb-media__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: var(--ddb-hero-focus-x) var(--ddb-hero-focus-y);
  transform-origin: var(--ddb-hero-focus-x) var(--ddb-hero-focus-y);
  transform: scale(var(--ddb-hero-zoom));
}
/* The panel narrows and deepens from here down, so the crop opens out with it:
   less magnification, and the focal point walking back toward the middle of the
   frame as the window turns from a 1690 × 901 landscape into a portrait. */
/* On a phone the panel is a portrait window onto a landscape photograph, wide
   enough for one of the two people; it keeps the one on the left whole rather
   than half of each. */
@media (max-width: 500px)  { .ddb-hero__media { --ddb-hero-focus-x: 30%; } }

.ddb-hero__inner {
  position: relative;
  /* Copy sits 99px inside the panel; the feature card stops 43px from its right
     edge (node 119:1970 at x=118 and node 119:2008 ending at 1666, panel 19 → 1709). */
  width: 100%;
  padding-block: clamp(40px, 5vw, 86px);
  padding-inline: clamp(18px, 5.729vw, 99px) clamp(18px, 2.49vw, 43px);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: clamp(24px, 3vw, 56px);
}

/* ── The hero on a narrower viewport ──────────────────────────────────────
   The panel's height is a proportion of the frame's width (52.14vw = 901 ÷
   1728), which is right while the viewport is a landscape of roughly the
   frame's shape and wrong as soon as it is not: at 768 that proportion asks for
   a 400px band, and the hero — the most considered composition on the page —
   arrives as a short horizontal strip with the photograph cropped to a sliver.

   So below the frame the panel stops following the width down and takes its
   height from the viewport instead, deepening toward portrait as the screen
   narrows, and the copy inside it gains matching room at the top. The three
   steps below run alongside the crop steps in §8 above, which open the
   photograph's framing out over the same range.

   Nothing here reaches the desktop composition: the first query starts below
   1200, and at 1728 every value is the signed-off one. */
@media (max-width: 1200px) {
  .ddb-hero__panel { min-height: max(clamp(520px, 52.14vw, 901px), 60svh); }
  .ddb-hero__inner { padding-top: clamp(56px, 7vw, 86px); }
}
@media (max-width: 1024px) {
  .ddb-hero__panel { min-height: max(560px, 66svh); }
  .ddb-hero__inner { padding-top: clamp(64px, 9vw, 96px); }
}
@media (max-width: 768px) {
  .ddb-hero__panel { min-height: max(600px, 72svh); }
  .ddb-hero__inner { padding-top: clamp(72px, 13vw, 104px); }
}
@media (max-width: 500px) {
  .ddb-hero__panel { min-height: max(620px, 76svh); }
  .ddb-hero__inner { padding-top: clamp(76px, 19vw, 96px); }
}

/* The gap the home page leaves above the hero opens with it. The desktop value
   is the frame's own (menu 78 → hero 103); these are the same gap read as a
   proportion of a narrower screen, so the panel is not pressed against the
   masthead once it has become the tall thing on the page. */
@media (max-width: 1024px) { .ddb-page--home .ddb-hero { margin-top: 26px; } }
@media (max-width: 768px)  { .ddb-page--home .ddb-hero { margin-top: 30px; } }
@media (max-width: 500px)  { .ddb-page--home .ddb-hero { margin-top: 34px; } }

/* The heading measures 799 and the copy beneath it 459 on the frame
   (nodes 119:1970 and 119:1972) — the wrap is part of the composition. */
.ddb-hero__copy { max-width: 799px; }
.ddb .ddb-hero__copy .ddb-eyebrow { margin-bottom: clamp(10px, 1vw, 19px); }
.ddb .ddb-hero__body { margin-top: clamp(14px, 1.4vw, 24px); max-width: 459px; }

/* Feature card, bottom-right (node 2:549 — 380 × 194, inner tile 125 × 147).

   At rest this is exactly what the design draws: white glass at 30% over the
   photograph, a white hairline, and the copy in white. What it did not do was
   say it was a link — a translucent panel over a hero reads as part of the
   composition, and the "Explore Now" line beneath the title was set at half
   strength, which reads as a caption rather than as a way in.

   So the whole card resolves to solid white on contact, taking its type down to
   the deep ink with it, and the CTA line becomes a filled pill. Only colour
   changes: the card's box, its position, its size and its image are all
   identical in both states, so nothing in the hero moves. No shadow. */
.ddb-hero__card {
  display: grid;
  grid-template-columns: clamp(92px, 8.275vw, 143px) minmax(0, 168px);
  align-items: center;
  justify-content: start;
  gap: 15px;                                  /* image ends 1443, text at 1458 */
  width: clamp(280px, 21.99vw, 380px);
  min-height: clamp(150px, 11.23vw, 194px);
  padding: 13px 14px;                         /* card 1286, image 1300 */
  border-radius: var(--ddb-r-card);
  border: 1px solid var(--ddb-white);
  background: rgb(255 255 255 / .3);
  backdrop-filter: blur(7.8px);
  -webkit-backdrop-filter: blur(7.8px);
  color: var(--ddb-ink-invert);
  transition: background-color var(--ddb-dur) var(--ddb-ease),
              color var(--ddb-dur) var(--ddb-ease),
              border-color var(--ddb-dur) var(--ddb-ease);
}
.ddb .ddb-hero__card:hover,
.ddb .ddb-hero__card:focus-visible {
  background: var(--ddb-white);
  border-color: var(--ddb-white);
  color: var(--ddb-ink-deep);
}
.ddb-hero__card-media {
  display: block;
  width: 100%;                                /* 143 × 168 (node 123:3912) */
  aspect-ratio: 143 / 168;
  overflow: hidden;
  border-radius: 20px;
  background: rgb(255 255 255 / .2);
}
.ddb .ddb-hero__card-img { width: 100%; height: 100%; object-fit: cover; }
.ddb-hero__card-body { display: grid; gap: 4px; }
.ddb .ddb-hero__card-title {
  font-weight: var(--ddb-w-medium);
  font-size: var(--ddb-t-feature);                /* 28 (node 119:2009) */
  letter-spacing: var(--ddb-track-display);
  line-height: var(--ddb-lh-h28);
}
/* The pill is carried at rest and only filled on contact, in the same way the
   resource card's "Read More" is (§22): the box, its padding and its place in
   the layout never change, and the negative inline margin cancels the padding
   so the words stay flush with the title above them in both states. That is
   what lets a pill appear around the label without moving it, or the card, a
   pixel — which is the whole point of the treatment. */
.ddb .ddb-hero__card-cta {
  display: inline-flex;
  align-items: center;
  justify-self: start;
  padding: 5px 12px;
  margin-left: -12px;
  border-radius: var(--ddb-r-pill);
  background: transparent;
  font-size: var(--ddb-t-lead);              /* 18 (node 119:2010) */
  font-weight: var(--ddb-w-medium);
  letter-spacing: var(--ddb-track-ui);
  line-height: 1.2;
  opacity: .5;
  transition: background-color var(--ddb-dur) var(--ddb-ease),
              color var(--ddb-dur) var(--ddb-ease),
              opacity var(--ddb-dur) var(--ddb-ease),
              margin-left var(--ddb-dur) var(--ddb-ease);
}
/* On contact the negative margin eases to zero, so the pill that appears
   starts on the title's left edge and the words step 12px to the right inside
   it — the pill aligns with the heading, and the step is the same easing as
   the fill rather than a jump. The card itself still does not move. */
.ddb .ddb-hero__card:hover .ddb-hero__card-cta,
.ddb .ddb-hero__card:focus-visible .ddb-hero__card-cta {
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
  opacity: 1;
  margin-left: 0;
}

@media (prefers-reduced-motion: reduce) {
  .ddb-hero__card,
  .ddb .ddb-hero__card-cta { transition: none; }
}

/* Once the card can no longer sit beside the copy it is dropped rather than
   stacked beneath it (§16 of the amendments). Stacked, it stopped being part of
   the hero composition and became a fourth block under the buttons, pushing the
   panel taller for no gain. `display: none` rather than a collapsed width, so
   the grid is a single column with no residual gap where the card was, and the
   small-screen hero is a clean portrait: eyebrow, heading, copy, buttons. */
@media (max-width: 900px) {
  .ddb-hero__inner { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .ddb-hero__card { display: none; }
}


/* ── 8b · Inner-page header (node 119:2165) ───────────────────────────── */

/* 1728 × 610: a #1f1f1f ground carrying the image at 49%, rounded 50 at the
   foot only. The navigation overlays it rather than sitting above it. */
.ddb-pagehead__panel {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-radius: 0 0 var(--ddb-r-panel) var(--ddb-r-panel);
  background: var(--ddb-hero-ground);
  color: var(--ddb-ink-invert);
  min-height: clamp(400px, 35.3vw, 610px);
  display: grid;
  align-items: end;
}
.ddb-pagehead__media { position: absolute; inset: 0; z-index: -1; opacity: .49; }

.ddb-pagehead__inner {
  width: 100%;
  max-width: calc(1435px + clamp(20px, 8.333vw, 144px) + clamp(20px, 8.623vw, 149px));
  padding-inline: clamp(20px, 8.333vw, 144px) clamp(20px, 8.623vw, 149px);
  padding-bottom: clamp(40px, 5.961vw, 103px);   /* buttons end 507 of 610 */
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  column-gap: clamp(24px, 3vw, 52px);
}
.ddb-pagehead__copy { max-width: 655px; }        /* node 119:2167 */
.ddb .ddb-pagehead .ddb-h1 {
  font-size: var(--ddb-t-hero);                  /* 65 Light (node 119:2167) */
  font-weight: var(--ddb-w-light);
  line-height: var(--ddb-lh-display);
}
.ddb .ddb-pagehead__body { margin-top: 24px; max-width: 459px; }   /* 435 → 459 */
.ddb .ddb-pagehead__actions { margin-top: 0; gap: 11px; }          /* 1373 → 1384 */
.ddb .ddb-pagehead__actions .ddb-btn { min-width: 195px; }         /* node 119:2170 */
/* Over this panel the outline button is drawn at 1.5 (node 119:2173). The
   panel's own pairing is the gold fill against a white outline, so it trades
   the same two light colours the hero does, in the other direction: the gold
   primary fills white, and the white outline fills gold. Both stay filled. */
.ddb .ddb-pagehead .ddb-btn--secondary {
  background: transparent;
  border-width: 1.5px;
  border-color: var(--ddb-white);
  color: var(--ddb-white);
}
.ddb .ddb-pagehead .ddb-btn--secondary:hover,
.ddb .ddb-pagehead .ddb-btn--secondary:focus-visible {
  background: var(--ddb-gold);
  color: var(--ddb-gold-ink);
  border-color: var(--ddb-gold);
}
.ddb .ddb-pagehead .ddb-btn--primary:hover,
.ddb .ddb-pagehead .ddb-btn--primary:focus-visible {
  background: var(--ddb-white);
  color: var(--ddb-primary);
  border-color: var(--ddb-white);
}

/* The same correction the hero gets above, for the panel that opens every inner
   page: 35.3vw is 610 ÷ 1728, which asks for a 271px band at 768 and leaves the
   page's heading and buttons crowded into a strip. Below the frame it takes its
   depth from the viewport instead. */
@media (max-width: 1200px) {
  .ddb-pagehead__panel { min-height: max(clamp(400px, 35.3vw, 610px), 48svh); }
}
@media (max-width: 1024px) {
  .ddb-pagehead__panel { min-height: max(440px, 54svh); }
  .ddb-pagehead__inner { padding-top: clamp(56px, 8vw, 80px); }
}
@media (max-width: 768px) {
  .ddb-pagehead__panel { min-height: max(480px, 60svh); }
  .ddb-pagehead__inner { padding-top: clamp(64px, 11vw, 88px); }
}
@media (max-width: 500px) {
  .ddb-pagehead__panel { min-height: max(500px, 64svh); }
}

@media (max-width: 900px) {
  .ddb-pagehead__inner { grid-template-columns: minmax(0, 1fr); row-gap: 28px; align-items: start; }
}

/* ── 8c · Bleeding image strip (node 119:2184) ────────────────────────── */

/* Four 490 × 546 tiles with a 26 gutter measure 2038 — 155 wider than the
   frame on each side, which is exactly how the design runs it off the page.

   The rail moves: it is driven by the reader's own scrolling, in the opposite
   direction to the typographic strip, from the same shared scroll state. Its
   width is deliberately more than the viewport can hold and the section clips
   it; the page itself never gains a horizontal scrollbar.

   The track carries the transform. Until the script has run there is exactly
   one run, centred, which is the resting composition the design draws — and it
   is also what a reader who prefers reduced motion keeps. */
/* The section centres the rail on the page. An auto margin cannot do it: the
   rail is wider than the viewport, and auto margins resolve to zero rather than
   going negative, which would leave the run pinned to the left edge instead of
   overhanging both. Centring a flex item does overflow symmetrically, which is
   how the design runs the strip 155 past each side of the frame. */
.ddb-strip {
  overflow: hidden;
  display: flex;
  justify-content: center;
}
/* Once the script is driving the rail it places the track itself, from the left. */
.ddb-strip.is-driven { justify-content: flex-start; }
.ddb .ddb-strip__track {
  display: flex;
  gap: 26px;
  width: max-content;
  max-width: none;
}
.ddb .ddb-strip__rail {
  display: flex;
  gap: 26px;
  width: max-content;
  margin: 0;
  padding: 0;
  list-style: none;
  max-width: none;
}
.ddb .ddb-strip__track.is-driven { will-change: transform; }
.ddb-strip__item {
  flex: none;
  width: clamp(220px, 28.356vw, 490px);
  aspect-ratio: 490 / 546;
  overflow: hidden;
  border-radius: var(--ddb-r-panel);
  background: var(--ddb-cream);
}
.ddb .ddb-strip__img { width: 100%; height: 100%; object-fit: cover; }

/* Narrow viewports clip the rail exactly as wide ones do — the tiles keep their
   490 × 546 proportion and give up width together rather than being squeezed
   until the whole gallery fits. A hand-scrollable strip would fight the
   scroll-driven motion, so the strip is never a second scroll container. */



/* ── 9 · Intro ─────────────────────────────────────────────────────────── */

/* Node 2:554: the heading occupies the left half (746 of 1494) on its own row;
   beneath it the copy sits left (459 wide) with the buttons pushed right. */
.ddb-intro__inner {
  width: min(100% - (2 * var(--ddb-gutter)), var(--ddb-content));
  margin-inline: auto;
  display: grid;
  gap: 9px;                                     /* heading 115 → row 124 */
}
.ddb-intro__lead { max-width: 746px; }
.ddb-intro__aside {
  display: grid;
  grid-template-columns: minmax(0, 459px) auto;
  justify-content: space-between;
  align-items: center;                          /* copy centres against the buttons */
  gap: clamp(20px, 2.4vw, 44px);
}
.ddb .ddb-intro__body { max-width: 459px; }
.ddb .ddb-intro__actions { margin-top: 0; justify-content: flex-end; }

/* 1040, not 900. This row is a 459px paragraph with a 191px button pair pushed
   to the far end of it — 459 + 44 + 391 = 894 before anything can give, and the
   content wrapper only has that much at about 1040. Between 900 and 1040 the
   paragraph was being squeezed under its measure to keep the buttons on the
   same line as it. */
@media (max-width: 1040px) {
  .ddb-intro__aside {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(18px, 2.6vw, 26px);
  }
  .ddb .ddb-intro__actions { justify-content: flex-start; }
}


/* ── 10 · Category tiles (nodes 2:505 / 2:506 / 2:508) ─────────────────── */

/* Three 472 tiles with a 35 gutter measure 1486, not the full 1494 content
   width (nodes 2:505 / 2:506 / 2:508). */
.ddb-cats__grid {
  width: min(100% - (2 * var(--ddb-gutter)), 1486px);
  margin-inline: auto;
  display: grid;
  /* 472-wide tiles with a 35px gutter — intrinsic, so a fourth area wraps
     cleanly instead of squeezing the row. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: 35px;
}

.ddb .ddb-cat {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  aspect-ratio: 472 / 566;
  padding: 45px;                    /* title seated 45 in, 48 up */
  padding-bottom: 48px;
  border-radius: var(--ddb-r-panel);
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
}

/* The photograph is its own positioned layer beneath the title, clipped to the
   tile's radius — which is what lets the picture inside it move on hover (§4)
   without the tile's box or the title seated over it changing at all. */
.ddb-cat__media {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  border-radius: var(--ddb-r-panel);
}
/* A 50% black scrim over the image so the title stays legible on any photograph. */
.ddb-cat__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--ddb-scrim);
}
.ddb .ddb-cat__img { width: 100%; height: 100%; object-fit: cover; }

.ddb .ddb-cat__title {
  font-weight: var(--ddb-w-light);
  font-size: var(--ddb-t-tile);      /* 45 (node 119:2006) */
  letter-spacing: var(--ddb-track-display);
  line-height: var(--ddb-lh-display);
}

/* The hover treatment for this tile is the shared one in §4 — a small step
   toward the reader and a lighter scrim. It used to draw the photograph back
   4px into an inset frame; that is gone (§20 of the amendments). */


/* ── 11 · Bento overview (node 2:693) ──────────────────────────────────── */

/* Node 119:2016 — the component sits at x 101 and its content measures
   764 (media) + 90 (gap) + 562 (copy) = 1416, so the copy column stops well
   short of the right frame edge. That slack is in the design. */
.ddb-bento__inner {
  padding-bottom: 14px;                       /* component 811 vs content 797 */
  width: min(100% - clamp(20px, 5.845vw, 101px) - clamp(20px, 12.211vw, 211px), 1416px);
  margin-left: calc(clamp(20px, 5.845vw, 101px) + max(0px, (100% - 1728px) / 2));
  margin-right: auto;
  display: grid;
  /* The copy track carries a floor as well as its share. At the frame width the
     562fr share is 562; by 1200 the same share is 390, which is not a column a
     35px heading and a 52px icon row can live in. Between the two the copy
     holds 430 and the media gives up the difference. */
  grid-template-columns: minmax(0, 764fr) minmax(min(100%, 430px), 562fr);
  column-gap: clamp(24px, 5.208vw, 90px);
  /* `stretch`, not `start`: the media column has to be able to grow to the row's
     height. The copy column keeps its own `align-self: start` below, so it is
     unaffected and still begins 52 down from the component top. */
  align-items: stretch;
  /* The query container for the media column's minimum height, below. */
  container-type: inline-size;
  container-name: ddb-bento;
}
/* The frame hangs this composition off the left margin — 101 in, 211 out. Held
   as a proportion down to a phone it becomes a 23/48 split, which reads as a
   mistake rather than as a composition. Below 900 it centres on the page
   gutter like every other section. */
@media (max-width: 900px) {
  .ddb-bento__inner {
    width: min(100% - (2 * var(--ddb-gutter)), 1416px);
    margin-inline: auto;
  }
}

.ddb-bento__inner--nomedia { grid-template-columns: minmax(0, 1fr); }

/* The media column: an upper row of 372 × 291 tiles and a 764 × 486 tile
   beneath, both separated by 20 (nodes 119:2017 / 119:2018 / 119:2019). Rows
   collapse when their content isn't there, driven by the server-set counts.

   Every one of those numbers is a ratio of the column's own width, and the copy
   column's height is a function of how many lines its text takes, so off the
   frame the two diverge: the text wraps and grows while the media shrinks with
   the width. The column therefore takes the grid row's height whenever the copy
   beside it is taller, its two rows divide that height in the design's own
   291 : 486 ratio, and each tile fills its row rather than setting it. The
   arrangement never changes — two tiles above, one wide tile below, the same
   20px gutters, all still `object-fit: cover`; only the containers grow more
   portrait.

   **The `aspect-ratio` that used to express the column's minimum height was the
   bug behind the collision in the brief's screenshot, and it was mine.**
   `aspect-ratio: 764/797` alongside `min-height: 100%` reads in both
   directions: once the copy grew taller than the media's natural height — which
   happens from about 1440 down — the min-height forced the height up and the
   ratio computed a *width* back from it. At 1200 the column rendered 795px wide
   inside a 530px track and painted straight across the copy beside it. At 1728
   the copy is shorter than 797, the min-height was inert, and nothing showed,
   which is why it survived the last pass's desktop check.

   The minimum is now a length rather than a ratio, so it cannot feed back into
   width: 56.286cqw is 797 ÷ 1416 — the drawn height as a proportion of the
   component's own inline size, measured against the component rather than the
   viewport, so it stays true whatever the page gutters do. At 1728 it resolves
   to 797 and the column is the 764 × 797 the frame draws, to the pixel. */
/* The two rows are stated as percentages of the column's own height rather than
   in `fr`, and that is load-bearing rather than stylistic. An `fr` track inside
   a grid whose *own* height is still being decided is resolved against its
   content and then scaled back up by the flex factors, so the column reported a
   taller intrinsic height than the design's — 835 against 797 — and, because
   `min-height` is a floor and not a cap, nothing below could bring it back
   down. That is 38px the whole home and About pages inherited.

   A percentage row resolves to `auto` while the height is indefinite and to the
   real proportion once it is definite, so the column contributes only its 20px
   gutter to the row sizing, takes its height from `min-height` or from the copy
   beside it, and only then divides that height 291 : 486. Both ends behave:
   797 at the frame width, and the same proportion at any height above it. */
.ddb-bento__media {
  display: grid;
  gap: 20px;
  grid-template-rows:
    calc((291 / 777) * (100% - 20px))
    calc((486 / 777) * (100% - 20px));
  min-width: 0;
  min-height: min(797px, 46.123vw);            /* fallback: 797 ÷ 1728 */
}
@supports (min-height: 1cqw) {
  .ddb-bento__media { min-height: 56.286cqw; } /* 797 ÷ 1416 of the component */
}
.ddb-bento__media[data-upper="0"],
.ddb-bento__media[data-main="0"] { grid-template-rows: 100%; }

.ddb-bento__upper {
  display: grid;
  gap: 20px;                                  /* 392 − 372 (node 119:2018) */
  /* Written out rather than repeat(): the playing state below swaps one track
     to 0fr, and two explicit interpolable lists are what lets the swap run as
     a grid-track transition instead of a jump. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  transition: grid-template-columns .45s var(--ddb-ease), column-gap .45s var(--ddb-ease);
}
/* One upper tile spans the full width rather than leaving a hole beside it. */
.ddb-bento__upper[data-count="1"] { grid-template-columns: minmax(0, 1fr); }

/* The tiles take the height their row is given rather than setting it from
   their width, so they turn more portrait as the column grows. `min-height: 0`
   lets a grid item be shorter than its content's minimum, which is what stops
   the photograph inside from propping the row open. */
.ddb-bento__upper { min-height: 0; }
.ddb-bento__tile {
  position: relative;
  overflow: hidden;
  min-height: 0;
  height: 100%;
  border-radius: var(--ddb-r-panel);
  background: var(--ddb-cream);
}

.ddb-bento__tile-media { position: absolute; inset: 0; }
.ddb .ddb-bento__tile-img { width: 100%; height: 100%; object-fit: cover; }

.ddb-bento__main {
  border-radius: var(--ddb-r-panel);
  overflow: hidden;
  min-height: 0;
  height: 100%;
  background: var(--ddb-cream);
}

/* Play control + expanded player (§21). */
.ddb .ddb-play {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgb(0 0 0 / .15);
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease),
              opacity .35s var(--ddb-ease);
}
.ddb .ddb-play:hover { background: rgb(0 0 0 / .3); }
.ddb .ddb-play__glyph {
  display: grid;
  place-items: center;
  width: 64px; height: 64px;
  border-radius: 50%;
  background: var(--ddb-white);
  color: var(--ddb-primary);
  font-size: 18px;
}

/* The player arrives as a fade under the geometry's own motion — the script
   unhides it a frame before the playing class lands, so this opacity really
   transitions rather than appearing mid-value. The slight delay lets the tile
   start moving first, which is what makes the arrival read as an expansion
   rather than a swap. */
.ddb-bento__player {
  position: absolute;
  inset: 0;
  background: var(--ddb-primary);
  opacity: 0;
  transition: opacity .35s var(--ddb-ease) .08s;
}
.ddb-bento__tile.is-playing .ddb-bento__player { opacity: 1; }
.ddb-bento__player[hidden] { display: none; }
.ddb .ddb-bento__player :where(iframe, video) { width: 100%; height: 100%; border: 0; }
/* A quietened Vimeo frame (§21) draws no UI of its own, so it takes no pointer
   either: hovering a playing tile can never surface the provider's controls
   over the Builder's, and the close control remains the one way to pause. */
.ddb .ddb-bento__player--quiet iframe { pointer-events: none; }

.ddb .ddb-play__close {
  position: absolute;
  top: 12px; right: 12px;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgb(0 0 0 / .55);
  color: var(--ddb-white);
}

/* Playing state: the tile becomes a proper 16:9 frame and the poster steps back.
   The column has to let go of its own proportion for that — while a video is
   playing the media is no longer the balancing column, it is a player, and it
   sizes itself. Both are released together so the 16:9 frame is honoured
   instead of being stretched to a row that was measured for photographs.

   The move between the two states is animated rather than switched. Three
   things carry it, and each uses the mechanism suited to it: the sibling
   tile's column collapses to 0fr through a grid-track transition (fr values
   interpolate; display: none does not), the poster and play control cross-fade
   with the arriving player, and the tile's own height is driven between its
   two measured values by the script — a percentage row and an auto row cannot
   interpolate, so the height would otherwise snap however the tracks animate.
   `.is-closing` is the script's holding state on the way back: it keeps this
   layout while the height comes down, so the shrinking player can never paint
   over the tile beneath it, and the sibling only returns once the row is back
   at its rest height. */
.ddb-bento__media:has(.is-playing, .is-closing) {
  aspect-ratio: auto;
  min-height: 0;
  grid-template-rows: auto auto;
}
.ddb-bento__tile { transition: opacity .3s var(--ddb-ease), height .45s var(--ddb-ease); }
/* The playing frame takes the film's own proportion (set on the tile by the
   renderer from the pasted snippet); 16:9 only when the snippet says nothing. */
.ddb-bento__tile.is-playing { height: auto; aspect-ratio: var(--ddb-video-ratio, 16 / 9); }
.ddb-bento__tile-media { transition: opacity .35s var(--ddb-ease); }
.ddb-bento__tile.is-playing .ddb-bento__tile-media,
.ddb-bento__tile.is-playing .ddb-play { opacity: 0; pointer-events: none; }
/* A tile that has expanded takes the whole upper row so the player isn't
   squeezed into half the width; its neighbour's track closes to nothing and
   the gap goes with it. */
.ddb-bento__upper:has(.is-playing, .is-closing) { column-gap: 0px; }
.ddb-bento__upper:has(> .ddb-bento__tile:first-child:is(.is-playing, .is-closing)) {
  grid-template-columns: minmax(0, 1fr) minmax(0, 0fr);
}
.ddb-bento__upper:has(> .ddb-bento__tile:last-child:is(.is-playing, .is-closing)) {
  grid-template-columns: minmax(0, 0fr) minmax(0, 1fr);
}
.ddb-bento__upper:has(.is-playing, .is-closing) .ddb-bento__tile:not(.is-playing, .is-closing) {
  opacity: 0;
  pointer-events: none;
}

/* Under reduced motion the two states simply switch, as they always did. */
@media (prefers-reduced-motion: reduce) {
  .ddb-bento__upper,
  .ddb-bento__tile,
  .ddb-bento__tile-media,
  .ddb .ddb-play,
  .ddb-bento__player { transition: none; }
}

/* The copy column starts 52 down from the component top (node 119:2022). */
.ddb-bento__copy { align-self: start; padding-top: clamp(20px, 3.009vw, 52px); }
.ddb .ddb-bento__copy .ddb-eyebrow { margin-bottom: 19px; }   /* 52 + 23 → 94 */
.ddb .ddb-bento__body { margin-top: 19px; max-width: 556px; } /* 205 → 224 (node 119:2021) */

/* Feature rows: 109 tall with a 29 gap, the first sitting 50 below the copy
   (nodes 119:2023 / 123:3937 / 123:3979). */
.ddb .ddb-features {
  display: grid;
  gap: 29px;
  margin-top: 50px;
}
.ddb-features__item { display: block; }
.ddb .ddb-features__link { display: block; }
/* The icon sits in a 52 × 52 gold tile with a 10 radius, holding a 32 glyph
   (nodes 119:2027 / 119:2028). The title sits beside it, 23 to its right; the
   body drops below both and aligns back to the icon's left edge. */
.ddb .ddb-features__item {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr);
  column-gap: 23px;
  align-items: start;
}
.ddb .ddb-features__icon {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: var(--ddb-r-icon);
  background: var(--ddb-gold);
  color: var(--ddb-primary);
  font-size: 26px;                            /* the 32 glyph box, optically */
}
.ddb .ddb-features__title { grid-column: 2; }
.ddb .ddb-features__body  { grid-column: 1 / -1; margin-top: 9px; max-width: 449px; }
.ddb .ddb-features__text { display: grid; gap: 6px; }
.ddb .ddb-features__title {
  font-weight: var(--ddb-w-medium);
  font-size: var(--ddb-t-feature);            /* 28 (node 119:2025) */
  line-height: var(--ddb-lh-h28);
  letter-spacing: var(--ddb-track-display);
  color: var(--ddb-primary);
  padding-top: 10px;                          /* title 356 vs icon 346 */
}
.ddb .ddb-features__body { color: var(--ddb-muted); }

/* ── The stacked bento ────────────────────────────────────────────────────
   1080 rather than 900, and the number comes from the component. The wrapper is
   about 0.819 of the viewport through this range, so at 1080 it measures ~885;
   the copy takes its 430 floor and the ~55 gutter leaves the media 400 — which
   is two 190px tiles, the least the upper row can be and still be two pictures
   rather than two stamps. Below that the media was still shrinking while the
   copy stood still, and by 1024 the section was a tall column of text beside a
   short stack of thumbnails.

   Stacked, the composition is kept but re-proportioned: the media leads, its
   two rows relax from the frame's 291 : 486 toward something a phone can hold,
   and the copy takes a reading measure rather than the full track. */
@media (max-width: 1080px) {
  .ddb-bento__inner {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(28px, 4vw, 44px);
    container-type: normal;              /* nothing left inside it to query */
  }
  .ddb-bento__media { min-height: 0; }
  .ddb-bento__media,
  .ddb-bento__upper { gap: clamp(12px, 2vw, 20px); }
  /* Stacked, the column has no copy beside it to match, so it takes a ratio of
     its own rather than a height borrowed from a column that is no longer
     there. */
  .ddb-bento__media { aspect-ratio: 764 / 640; }
  .ddb-bento__copy { padding-top: 0; }
  .ddb .ddb-bento__body { max-width: 62ch; }
  .ddb .ddb-features { margin-top: clamp(28px, 4vw, 40px); gap: clamp(20px, 3vw, 29px); }
}
@media (max-width: 600px) {
  /* Two tiles above a wide one stops being legible as three pictures; the upper
     row keeps its pair but the whole column becomes squarer so none of them
     drops below about 150px. */
  .ddb-bento__media { aspect-ratio: 764 / 780; }
}


/* ── 12 · Image band ───────────────────────────────────────────────────── */

/* Node 119:2089 — 1516 wide, sitting 101 from the left and 111 from the right.
   The asymmetry is in the design, so it is reproduced rather than centred: the
   panel is placed by its own margins instead of `auto` on both sides. */
/* The band's height, held as a property on .ddb because two components depend
   on the same value: the panel takes it as its min-height, and the home page's
   carousel measures its cream-ground overlap against it (§13) — the two must
   never drift apart.

   The first term is the drawn geometry: 722 at the 1728 frame, scaling with
   the viewport. On its own it bottoms out at 360 while the panel keeps
   narrowing, which is what left the section a shallow letterbox by tablet. The
   second term runs the other way — it grows as the viewport shrinks — so from
   about 960px down the band turns steadily more portrait instead, reaching its
   600px ceiling by about 550. Above ~965 the drawn term always wins, so
   desktop is untouched to the pixel. */
.ddb { --ddb-band-h: max(clamp(360px, 41.782vw, 722px), min(calc(940px - 62vw), 600px)); }
.ddb-band__panel {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  width: min(100% - clamp(20px, 5.845vw, 101px) - clamp(20px, 6.424vw, 111px), 1516px);
  /* Above the 1728 frame the whole composition centres, and the 101 offset is
     measured from the frame edge rather than the viewport edge. */
  margin-left: calc(clamp(20px, 5.845vw, 101px) + max(0px, (100% - 1728px) / 2));
  margin-right: auto;
  border-radius: var(--ddb-r-panel);
  background: var(--ddb-band-ground);         /* node 123:4192 */
  color: var(--ddb-ink-invert);
  min-height: var(--ddb-band-h);              /* node 119:2089 — 1516 × 722 */
  display: grid;
  /* The composition is seated on the panel's foot, not centred in it: the
     buttons finish 104 above the bottom edge (node 119:2093 ends at 618 of
     722) while the heading's top floats with however many lines it takes. */
  align-items: end;
}
/* Node 123:4181 — the source at 1737 × 1158 placed at (−9, −418) in the
   1516 × 722 panel, and mirrored (Figma applies a 180° rotation together with a
   vertical flip, which resolves to a horizontal mirror). */
/* The photograph sits at 63% over the panel's own ground — the design's own
   darkening, not an overlay of our invention. */
/* The crop *was* the natural-size source offset by percentages of the panel —
   the same construction that broke the hero (§8), and it failed the same way:
   the offsets are proportions of the panel, but below ~1000px the panel's
   height clamp bottoms out while its width keeps shrinking, so the
   natural-ratio image fell short of the panel and the black ground showed
   through more the narrower the screen got.

   Rebuilt on the hero's pattern, so the image can never be smaller than its
   frame. The picture is `object-fit: cover` over the full panel — coverage is
   guaranteed at every ratio — and the design's closer framing is put back on
   top as a scale about the crop's own anchor. The mirror moves to the media
   layer (a panel-sized box, flipped about its own centre) so the anchor
   arithmetic on the image stays in unmirrored coordinates.

   The anchor is the drawn crop expressed as a position within the overflow at
   the design scale: the window opens 212 of the 221px horizontal overhang
   (95.928%) and 418 of the 436px vertical (95.872%). The zoom is the design's
   natural-size placement over the 0.87277 cover scale — 1.14578. At 1728 this
   reproduces node 123:4181 to within a pixel; below the frame the zoom eases
   off and the focus walks toward the frame's middle as the panel turns
   portrait, keeping the subject rather than a corner of it. */
.ddb-band__media {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  border-radius: inherit;
  opacity: .63;
  /* The mirror and the magnification described above reproduced the Figma
     placeholder (node 123:4181). The practice's photographs carry signage and
     faces, so they sit unmirrored at cover with a centred focus (2026-10-13);
     the variables remain for any photograph that needs framing. */
  --ddb-band-zoom: 1;
  --ddb-band-focus-x: 50%;
  --ddb-band-focus-y: 50%;
}
.ddb .ddb-band__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: var(--ddb-band-focus-x) var(--ddb-band-focus-y);
  transform-origin: var(--ddb-band-focus-x) var(--ddb-band-focus-y);
  transform: scale(var(--ddb-band-zoom));
}
/* Node 119:2091 — the copy starts 132.62 in from the panel's left edge (8.75%
   of 1516) and the heading measures 591.71 across, which is what gives it its
   three lines. The paragraph is set narrower again at 468.27 (node 119:2092).
   These are three separate measured widths, not one shared content column. */
.ddb-band__inner {
  padding-left: clamp(24px, 7.675vw, 132.62px);
  padding-right: clamp(24px, 4vw, 70px);
  padding-bottom: clamp(40px, 6.019vw, 104px);
  max-width: none;
}
.ddb .ddb-band__inner .ddb-h2,
.ddb .ddb-band__title { max-width: 591.71px; }          /* node 119:2091 */
.ddb .ddb-band__body  { margin-top: 20px; max-width: 468.27px; }   /* node 119:2092 — 444.62 → 465 */
/* The band's own pair: 194.88 × 57.11 with a 16.61 gutter (nodes 119:2093 and
   119:2096), a little wider than the 191 × 56 the light sections use. */
.ddb .ddb-band__actions { margin-top: 47px; gap: 16.61px; }   /* node 119:2093 — 513.95 → 560.88 */
.ddb .ddb-band__actions .ddb-btn { min-width: 194.88px; min-height: 57.11px; }
/* Once the band is running on its portrait-term height the copy sits on the
   foot of a taller panel, and the padding-top is the floor under the breathing
   room above it: however many lines the heading takes, the image keeps a
   substantial presence above the words. Inert on desktop, where the panel's
   min-height leaves far more than this above the copy anyway. */
@media (max-width: 1000px) {
  .ddb-band__inner { padding-top: clamp(56px, 14vw, 120px); }
}


/* ── 13 · Treatment cards, carousel & grid (node 3:697) ────────────────── */

.ddb .ddb-tcard {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  aspect-ratio: 472 / 328;
  padding: 45px;                     /* 45 in (node I119:2100;119:2163) */
  padding-bottom: 51px;              /* the 45 line box ends 51 up from the foot */
  border-radius: var(--ddb-r-panel);
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
}
.ddb .ddb-tcard__media {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  border-radius: var(--ddb-r-panel);
}
/* This tile's scrim is 53%, not the 50 the area tiles use (node I119:2100;119:2162
   against node 119:2001). Both values are in the design; both are kept. */
.ddb .ddb-tcard__media::after { content: ""; position: absolute; inset: 0; z-index: 1; background: rgb(0 0 0 / .53); }
/* Hover is the shared card treatment in §4; the 4px inset frame this card used
   to draw on hover is gone (§20 of the amendments). */

.ddb-tcard__body { display: grid; gap: 8px; }
.ddb .ddb-tcard__eyebrow { font-size: var(--ddb-t-meta); opacity: .8; }
/* 35 Light in a 45 line box (node I119:2100;119:2163) — smaller than the 45 the
   area tiles are set in, and not set solid. */
.ddb .ddb-tcard__title {
  font-weight: var(--ddb-w-light);
  font-size: clamp(24px, 2.025vw, 35px);
  letter-spacing: var(--ddb-track-display);
  line-height: calc(45 / 35);
}
.ddb .ddb-tcard__summary { max-width: 34ch; }

/* The card at tablet and phone sizes. Three drawn desktop values stop scaling
   well once the card is nearer 280px than 472: the 472 × 328 landscape ratio
   turns the tile short and wide, the 45px inset becomes a third of the card,
   and the 50px panel radius on a small box reads as a pill. Each steps down
   with the card — the ratio toward square so the tile stays image-led, the
   inset so the title keeps its seat near the foot without a moat around it,
   and the radius so the corners read as a rounded rectangle, not a capsule.
   Applied to the card itself, so the carousel and the treatment grid stay one
   component. */
@media (max-width: 1080px) {
  .ddb .ddb-tcard {
    aspect-ratio: 472 / 400;
    padding: clamp(24px, 3.3vw, 34px);
    padding-bottom: clamp(28px, 3.8vw, 40px);
  }
  .ddb .ddb-tcard,
  .ddb .ddb-tcard__media { border-radius: 36px; }
}
@media (max-width: 700px) {
  .ddb .ddb-tcard {
    aspect-ratio: 472 / 440;
    padding: 20px;
    padding-bottom: 24px;
  }
  .ddb .ddb-tcard,
  .ddb .ddb-tcard__media { border-radius: 28px; }
}


/* The cream ground behind the band's lower half and the carousel
   (node 123:4203 — 3295 → 4396). It belongs to neither section on its own, so
   it is carried by the carousel and pulled up behind the band.

   Both the pull and the padding that cancels it were fixed pixel values while
   the band they are measured against is not: the band's height is
   clamp(360px, 41.782vw, 722px), so it stops at 722 and keeps shrinking to a
   floor of 360, while the carousel went on being dragged 433px upward whatever
   the band did. Below about 1035px viewport the pull was longer than the band
   was tall, so the cream slab started *above* the band's top edge and covered
   the foot of the image strip above it — the reported overlap. On desktop it
   was only ever hidden by paint order: the band's panel is positioned and the
   carousel's background is not, so the panel happened to draw on top.

   Two corrections, so the effect works rather than being concealed:

   1. The overlap is now the same *proportion* of the band it was measured as —
      433 of 722, 59.97% — so it scales with the band and can never be deeper
      than the band is tall. The section above therefore stays fully visible at
      every width. At 1728 it resolves to 433 and 536 exactly, so the desktop
      composition is untouched.

   2. The band panel is given an explicit z-index rather than relying on paint
      order to keep it above the ground that rises behind it. Nothing is hidden
      with `overflow` and nothing is clipped: the cream simply passes behind an
      opaque panel, which is what the design draws.

   The overlap is deliberate — node 123:4203 starts the cream ground at 3295
   while the band runs to 3728 — so it is kept and made to work, not removed. */
.ddb-page--home .ddb-tcar {
  /* --ddb-band-h is the band's own min-height, inherited from .ddb (§12), so
     the two can never drift apart — including on a phone, where the band now
     runs on its portrait term. */
  --ddb-band-overlap: calc(var(--ddb-band-h) * .59972);   /* 433 ÷ 722 */

  background: var(--ddb-cream);
  padding-top: calc(var(--ddb-band-overlap) + 103px);     /* 3295 → 3831 at 1728 */
  padding-bottom: 79px;                                   /* 4317 → 4396 */
  margin-top: calc(-1 * var(--ddb-band-overlap));         /* band ends 3728; ground starts 3295 */
}
/* The panel is already `position: relative` and already isolates; this is only
   the rank it needs so a later sibling's background cannot paint over it. */
.ddb-band__panel { z-index: 1; }

/* Node 119:2099 — the component starts at x 121 and runs 1963 wide, so it
   overruns the frame's right edge by 356 and a fourth tile is caught by it. The
   head keeps the 141 gutter; only the rail is let out to the edge. */
.ddb-tcar__panel { margin-right: calc(-1 * clamp(20px, 8.160vw, 141px)); }

.ddb-tcar__inner,
.ddb-tgrid__inner {
  width: 100%;
  max-width: calc(1466px + clamp(20px, 7.002vw, 121px) + clamp(20px, 8.160vw, 141px));
  padding-inline: clamp(20px, 7.002vw, 121px) clamp(20px, 8.160vw, 141px);
  margin-inline: auto;
}

/* The tab bar is 562 × 104 at the component's top-left and the arrows sit at
   its right; the cards begin 158 down (nodes 119:2116 / 119:2100). */
.ddb-tcar__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(16px, 2vw, 32px);
  min-height: 104px;
  margin-bottom: 54px;                        /* 104 → 158 */
}
.ddb-tcar__nav,
.ddb-testi__nav,
.ddb-res__nav { display: flex; gap: 12px; margin-left: auto; }

/* Tab bar — 562 × 104 with an 11 inset and a 177 × 82 active pill
   (nodes 119:2117 / 119:2118). */
/* The area switch: a 562 × 104 shell in a 4% warm grey at radius 20, holding
   177 × 82 tabs at radius 10 (nodes 119:2117 / 119:2118). Nothing here is a
   pill — the two radii are 20 and 10, not the panels' 50. */
.ddb .ddb-tabs-ui {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 11px 13px;
  min-height: 104px;
  background: rgb(81 78 74 / .04);            /* node 119:2117 */
  border-radius: 20px;
}
.ddb .ddb-tabs-ui__tab {
  min-width: 177px;
  min-height: 82px;
  padding: 0 22px;
  border-radius: 10px;                        /* node 119:2118 */
  font-weight: var(--ddb-w-light);            /* nodes 119:2119–119:2121 — Light 22 */
  font-size: clamp(17px, 1.273vw, 22px);
  letter-spacing: var(--ddb-track-ui);
  color: var(--ddb-ink);
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease), color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-tabs-ui__tab.is-active { background: var(--ddb-white); }

/* Three tabs at their drawn 177px minimum, plus the shell's 26px of inset, need
   565px. The carousel head has about 0.848 of the viewport to give them, so
   below roughly 700 they stopped fitting and pushed straight out of the
   component — 232px past it at 390, which is the widest single overflow the
   audit found anywhere on the site.

   Below that width the three tabs share the row instead of each demanding a
   desktop measurement: the shell goes full width, the tabs become equal
   fractions of it, and the whole control shortens because a 104px switch above
   a phone-width carousel is a lot of furniture. Nothing scrolls and nothing is
   clipped — the three areas are all still visible and all still reachable. */
@media (max-width: 700px) {
  .ddb-tcar__head { min-height: 0; margin-bottom: clamp(24px, 5vw, 40px); gap: 16px; }
  .ddb .ddb-tabs-ui {
    display: flex;
    width: 100%;
    min-height: 0;
    padding: 5px;
    border-radius: 14px;
  }
  .ddb .ddb-tabs-ui__tab {
    flex: 1 1 0;
    min-width: 0;
    min-height: 52px;
    padding: 0 6px;
    font-size: clamp(13px, 3.6vw, 16px);
    border-radius: 9px;
  }
  .ddb-tcar__nav { margin-left: 0; }
}

/* The rail: a scroll-snapping row that works with touch, wheel and the arrows,
   rather than a JS-transformed track. */
.ddb .ddb-tcar__rail,
.ddb .ddb-testi__rail,
.ddb .ddb-res__rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min(100%, clamp(280px, 27.315vw, 472px));
  gap: 25px;                                  /* 497 − 472 (node 119:2101) */
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
/* A scroll rail clips at its own edges, which would shave the 4px the highlight
   card bleeds past the leading and trailing slides. The highlight bleeds up and
   out but never down (its inset is 0 at the foot), so the rail only needs room
   on three sides — and the matching negative margin puts the slides back where
   they were, leaving the rail's contribution to the page's vertical rhythm
   exactly the height of the slides.
   scroll-padding has to match: snapping aligns a slide to the scrollport's
   *padding* box, so without it the rail would settle 4px off and take every
   slide with it. */
.ddb :where(.ddb-tcar__rail, .ddb-testi__rail, .ddb-res__rail) {
  padding: var(--ddb-card-inset) var(--ddb-card-inset) 0;
  margin: calc(-1 * var(--ddb-card-inset)) calc(-1 * var(--ddb-card-inset)) 0;
  scroll-padding: var(--ddb-card-inset);
}
.ddb :where(.ddb-tcar__rail, .ddb-testi__rail, .ddb-res__rail)::-webkit-scrollbar { display: none; }
.ddb :where(.ddb-tcar__slide, .ddb-testi__item, .ddb-res__slide) { scroll-snap-align: start; }

.ddb-tcar__panel[hidden] { display: none; }

.ddb-tgrid__head { margin-bottom: clamp(24px, 2.6vw, 44px); }
.ddb .ddb-tgrid__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  gap: 35px;
}


/* ── 14 · Cross-area panels ────────────────────────────────────────────── */

/* Node 119:2122 — x 121, width 1466. */
.ddb-split__inner {
  width: 100%;
  max-width: calc(1466px + clamp(20px, 7.002vw, 121px) + clamp(20px, 8.160vw, 141px));
  padding-inline: clamp(20px, 7.002vw, 121px) clamp(20px, 8.160vw, 141px);
  margin-inline: auto;
}
/* The header is two columns: heading left (638 wide from x 21), copy and
   buttons right (from x 806) — nodes 119:2123 / 119:2124 / 123:4204. */
.ddb-split__head {
  display: grid;
  grid-template-columns: minmax(0, 638fr) minmax(0, 660fr);
  column-gap: clamp(24px, 8.516vw, 147px);
  align-items: start;
  margin-bottom: 64px;                        /* buttons 203 → panels 267 */
  /* the section box starts at the head, i.e. 23 into the component */
  padding-left: 21px;
  max-width: none;
}
.ddb-split__head-l, .ddb-split__head-r { min-width: 0; }
.ddb-split__head-l .ddb-eyebrow { margin-bottom: 19px; }   /* 46 → 65 */
.ddb-split__head-r { padding-top: 17px; }                  /* col 1 at 23, col 2 at 40 */

/* This header had no stacked state at all — it held its two tracks the whole
   way down, so at 390 it was a 40px heading in a 136px column beside a
   141px column of body copy and two buttons, and the heading overflowed its own
   box by 23px. It stacks at 900: the pair is a heading against a paragraph, and
   below roughly 380 each neither has a measure worth keeping. */
@media (max-width: 900px) {
  .ddb-split__head {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(18px, 3vw, 28px);
    margin-bottom: clamp(32px, 5vw, 48px);
    padding-left: 0;
  }
  .ddb-split__head-r { padding-top: 0; }
  .ddb .ddb-split__body { max-width: 62ch; }
}
.ddb .ddb-split__body    { max-width: 562px; }
.ddb .ddb-split__actions { margin-top: 35px; gap: 9px; }   /* 112 → 147; 991 → 1000 */
.ddb .ddb-split__actions .ddb-btn { min-width: 185px; }                   /* node 123:4204 */

/* Two 700-wide columns with a 66 gap — 700 + 66 + 700 = 1466 exactly. */
.ddb .ddb-split__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  gap: 66px;
}
/* The column itself carries no inset: node 119:2129 draws the image at the full
   700 of the column. The 45 below the copy is the foot of the highlight card
   (node 192:5143 ends at 924, the copy at 879), so it is kept on the panel to
   hold that height whether the card is showing or not. */
.ddb .ddb-split__panel {
  display: grid;
  gap: 0;
  padding: 0 0 45px;
  background: transparent;
}
.ddb-split__media {
  display: block;
  overflow: hidden;
  border-radius: var(--ddb-r-panel);          /* node 119:2134 — 50 */
  aspect-ratio: 700 / 410;
  background: var(--ddb-cream);
}
.ddb .ddb-split__img { width: 100%; height: 100%; object-fit: cover; }
/* The copy is indented 21 from the image edge in both states (node 119:2133 at
   787 against an image starting at 766), which is what keeps it clear of the
   highlight card's sides — the card only adds 4 beyond the image. */
.ddb .ddb-split__text { display: grid; gap: 0; padding-top: 34px; padding-inline: var(--ddb-card-text-px); }  /* image 677 → eyebrow 711 */
.ddb .ddb-split__text .ddb-eyebrow { margin-bottom: 9px; }           /* 734 → 743 */
.ddb .ddb-split__title {
  font-weight: var(--ddb-w-medium);
  font-size: var(--ddb-t-panel);              /* 38 (node 119:2132) */
  letter-spacing: var(--ddb-track-display);
  line-height: var(--ddb-lh-h38);
  color: var(--ddb-primary);
}
.ddb .ddb-split__copy { margin-top: 24px; max-width: 558px; }        /* 783 → 807 */

/* The interactive state is the shared highlight card — see section 4. */


/* ── 15 · Process ──────────────────────────────────────────────────────── */

/* The content block runs 157 → 975 of the component (818), while the cards and
   the image inside it run 164 → 975 (811): the 7 above them is the head of the
   vertical rule that tracks the steps (node 119:2377 starts at 157, node
   119:2365 at 164). Reproducing it is what makes the section 975 rather than
   968 — it is carried by the gap under the heading, not by padding above it,
   so the kicker still starts at the component's own top edge. */
.ddb-process__inner {
  width: min(100% - (2 * clamp(20px, 10.822vw, 187px)), 1354px);
  margin-inline: auto;
  display: grid;
  /* The steps column carries a floor: a step card is an icon, a number and two
     lines of copy, and below about 420 the copy stops wrapping into sentences
     and starts wrapping into words. */
  grid-template-columns:
    minmax(0, 35fr) minmax(min(100%, 420px), 645fr) minmax(0, 29fr) minmax(0, 645fr);
  /* `stretch`, so the photograph beside the steps is as tall as they are. The
     steps column re-declares `start` below and is unaffected. */
  align-items: stretch;
  container-type: inline-size;
  container-name: ddb-process;
}
.ddb-process__copy  { grid-column: 2; align-self: start; }
.ddb-process__media { grid-column: 4; }
.ddb-process__inner--nomedia { grid-template-columns: minmax(0, 1fr); }
.ddb-process__inner--nomedia .ddb-process__copy { grid-column: 1; }

/* The heading spans the full width and is centred (nodes 119:2380 / 119:2381).
   This section's kicker is not the 15px meta label the rest of the page uses —
   node 119:2381 sets it at 22/33 in the practice's near-black, so it is set from
   its own node rather than inheriting the shared eyebrow. */
.ddb-process__head { grid-column: 1 / -1; text-align: center; margin-bottom: 68px; }  /* 96 → 164, with the rule's 7 inside it */
.ddb .ddb-process__head .ddb-eyebrow {
  font-size: clamp(17px, 1.273vw, 22px);      /* node 119:2381 */
  line-height: calc(33 / 22);
  color: var(--ddb-ink);
  margin-bottom: 15px;                        /* 33 → 48 */
}
.ddb .ddb-process .ddb-h2 { font-size: var(--ddb-t-intro); font-weight: var(--ddb-w-medium); }

.ddb .ddb-process__body { margin-top: clamp(14px, 1.4vw, 24px); max-width: 46ch; }

/* Steps are 645 × 190 cards with a 17 gutter, drawn in the identity green with
   white type (nodes 119:2365–119:2368). Their radius is the 30 the cards use,
   not the 50 the panels do. */
.ddb .ddb-steps { display: grid; gap: 17px; margin-top: 0; }
.ddb-steps__item {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  min-height: 190px;
  padding: 32px 48px 28px;                                       /* text at 83 of a card at 35 */
  border-radius: var(--ddb-r-card);
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
  border-top: 0;
}
.ddb .ddb-steps__n { display: none; }
.ddb .ddb-steps__n {
  font-size: clamp(16px, 1.16vw, 20px);
  letter-spacing: var(--ddb-track-display);
  color: var(--ddb-primary);
}
.ddb .ddb-steps__text { display: grid; gap: 0; }   /* the body carries its own 17 */
.ddb .ddb-steps__title {
  font-weight: var(--ddb-w-medium);
  font-size: clamp(22px, 1.736vw, 30px);                         /* node 119:2369 — 30/32 */
  line-height: 1.06;
  letter-spacing: var(--ddb-track-display);
  color: var(--ddb-ink-invert);
}
/* Node 119:2370 — 18px Regular at the font's own leading, which is what puts
   the design's three lines inside 548 and the card at exactly 190. */
.ddb .ddb-steps__body {
  margin-top: 17px;                                              /* title 228 → body 245 */
  max-width: 548px;
  font-size: clamp(16px, 1.042vw, 18px);
  color: var(--ddb-ink-invert);
}
.ddb .ddb-steps__n { color: var(--ddb-ink-invert); }

/* The rule that runs beside the steps: 4px wide in the pale green the strips
   use, from the content block's top to its foot, with the step the reader is on
   picked out in the identity green (nodes 119:2377 / 119:2378). */
.ddb-process__copy { position: relative; }
.ddb-process__copy::before {
  content: "";
  position: absolute;
  left: calc((-35 / 645) * 100%);                                /* the 35 column outside the cards */
  top: -7px;                                                     /* the rule starts 7 above the cards */
  bottom: 0;
  width: 4px;
  border-radius: 2px;
  background: var(--ddb-marquee-ink);
}
.ddb-steps__item { position: relative; }
.ddb-steps__item::before {
  content: "";
  position: absolute;
  left: calc((-35 / 645) * 100%);
  top: 0;
  bottom: 0;
  width: 4px;
  border-radius: 2px;
  background: var(--ddb-primary);
  opacity: 0;
  transition: opacity var(--ddb-dur) var(--ddb-ease);
}
.ddb-steps__item.is-current::before { opacity: 1; }

/* The photograph runs the full height of the steps beside it — 164 → 975 on the
   frame, the same 811 the cards occupy. It is stated as a stretched grid item
   with a minimum rather than as a fixed 645 : 811 ratio, because the steps are
   content-led: an extra step, or a step whose copy takes a third line, makes
   that column taller, and a ratio-locked image would then end part-way down it
   with a run of white beneath — which is exactly what §25 of the brief
   describes. `aspect-ratio` is deliberately not used together with the stretch:
   a ratio on an item whose height has been forced computes a *width* back from
   that height, which is what broke the bento. */
.ddb-process__media {
  border-radius: 60px;                                           /* node 119:2364 — not the panels' 50 */
  overflow: hidden;
  min-height: min(811px, 46.933vw);                              /* fallback: 811 ÷ 1728 */
  background: var(--ddb-cream);
}
@supports (min-height: 1cqw) {
  .ddb-process__media { min-height: 59.897cqw; }                 /* 811 ÷ 1354 */
}
.ddb .ddb-process__img { width: 100%; height: 100%; object-fit: cover; }

/* ── The stacked process ──────────────────────────────────────────────────
   1080, from the component: the wrapper is about 0.784 of the viewport, so at
   1080 it measures ~846; the steps take their 420 floor, the two spacer tracks
   take ~40, and the photograph is left with ~386 — the least a portrait image
   can be beside nothing. Below that the image was still narrowing while the
   steps column stood still.

   Stacked, the photograph stops being a column and becomes a band: a portrait
   crop the full width of the page would be enormous, so it takes a landscape
   ratio and a real height instead of the column's. */
@media (max-width: 1080px) {
  .ddb-process__inner {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(28px, 4vw, 40px);
    container-type: normal;
  }
  .ddb-process__copy, .ddb-process__media { grid-column: 1; }
  .ddb-process__media { min-height: 0; aspect-ratio: 16 / 10; }
  .ddb-process__head { margin-bottom: clamp(32px, 5vw, 68px); }
  /* The 35 column the rule lives in is gone at this width, so it moves inside. */
  .ddb-process__copy::before,
  .ddb-steps__item::before { left: -14px; }
}
@media (max-width: 600px) {
  .ddb-process__media { aspect-ratio: 4 / 3; }
}
@media (prefers-reduced-motion: reduce) {
  .ddb-steps__item::before { transition: none; }
}


/* ── 16 · Testimonials ─────────────────────────────────────────────────── */

.ddb-testi__inner {
  width: min(100% - (2 * var(--ddb-gutter)), var(--ddb-content));
  margin-inline: auto;
}
.ddb-testi__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  margin-bottom: clamp(24px, 2.6vw, 44px);
}
.ddb .ddb-testi__item {
  display: grid;
  gap: clamp(14px, 1.4vw, 24px);
  padding: clamp(20px, 2vw, 34px);
  border-radius: var(--ddb-r-panel);
  background: var(--ddb-ground-alt);
}
.ddb-testi__media { border-radius: 25px; overflow: hidden; }
.ddb .ddb-testi__quote { font-size: clamp(17px, 1.16vw, 20px); }
.ddb .ddb-testi__by { display: grid; gap: 2px; }
.ddb .ddb-testi__name { letter-spacing: var(--ddb-track-display); }
.ddb .ddb-testi__label { color: var(--ddb-muted); font-size: var(--ddb-t-meta); }
/* A single testimonial is a static quote, not a one-slide carousel. */
.ddb-testi--single .ddb-testi__rail { display: block; overflow: visible; }


/* ── 17 · Reviews (node 3:1656) ────────────────────────────────────────── */

/* Reviews — a full-bleed cream band whose top corners are rounded 150
   (node 119:2205). Total height 739 on the frame. */
.ddb-reviews {
  background: var(--ddb-cream);
  border-radius: var(--ddb-r-band) var(--ddb-r-band) 0 0;
  padding-block: 85px 97px;                    /* pill at 85; button ends 642 of 739 */
  overflow: hidden;
}
.ddb-reviews__inner {
  width: min(100% - (2 * clamp(20px, 5.556vw, 96px)), 1536px);
  margin-inline: auto;
}

/* The head is the pill + heading on the left with the rating block right. */
.ddb-reviews__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  column-gap: clamp(24px, 3vw, 52px);
  padding-inline: 6px;                         /* text at 102, cards at 96 */
  margin-bottom: 49px;                         /* heading 197 → cards 246 */
}

/* Eyebrow pill (node 119:2208): 256 × 44, a 10% grey, fully rounded. */
.ddb .ddb-reviews .ddb-eyebrow {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: 28px;
  border-radius: var(--ddb-r-pill);
  background: rgb(168 168 168 / .1);
  color: var(--ddb-ink);
  font-weight: var(--ddb-w-medium);
  font-size: var(--ddb-t-meta);
  margin-bottom: 20px;                          /* pill 129 → heading 149 */
}

.ddb-reviews__embed > * { max-width: 100%; }
/* The footer row (2026-10-13): the button bottom-left and the carousel's
   controls bottom-right — the News & Resources head's arrangement, turned over
   to close the band. The controls are the site's own arrows driving the Google
   widget's carousel (initReviews); they are hidden until the widget has
   rendered, and the widget's own small arrows and header are hidden in turn. */
.ddb-reviews__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px 24px;
  margin-top: 40px;
  padding-inline: 6px;                         /* in line with the head's text */
}
.ddb-reviews__actions { display: flex; justify-content: flex-start; }
.ddb .ddb-reviews__actions .ddb-btn { min-width: 176px; min-height: 55px; }  /* node 119:2218 */
.ddb-reviews__nav { display: flex; gap: 12px; margin-left: auto; }
.ddb-reviews__nav[hidden] { display: none; }
/* On a phone the two stop sharing a line: the button takes the measure and the
   controls sit beneath it, left, as the other rails' controls do. */
@media (max-width: 480px) {
  .ddb-reviews__foot { flex-direction: column; align-items: stretch; }
  .ddb .ddb-reviews__actions .ddb-btn { width: 100%; }
  .ddb-reviews__nav { margin-left: 0; }
}

/* ── Review cards (node 154:5014) ────────────────────────────────────────
   492 × 301, white, radius 30, three across with a 30 gutter. */
.ddb .ddb-reviews__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 30px;                                    /* 588 → 618 */
  margin: 0;
  padding: 0;
  list-style: none;
}
.ddb .ddb-review {
  position: relative;
  min-height: 301px;
  padding: 26px 32px 42px;                      /* avatar at 32/26; quote ends 259 of 301 */
  border-radius: var(--ddb-r-card);             /* node 154:5015 — 30 */
  background: var(--ddb-white);
  color: #000;
  margin: 0;
}
.ddb-review__by {
  display: grid;
  grid-template-columns: 71px minmax(0, 1fr) 38px;
  align-items: center;
  column-gap: 22px;                             /* avatar ends 103, name at 125 */
}
.ddb-review__avatar {
  width: 71px;
  height: 71px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--ddb-ground-alt);
}
.ddb .ddb-review__photo { width: 100%; height: 100%; object-fit: cover; }
.ddb-review__who { display: grid; gap: 0; min-width: 0; }
/* Node 154:5017 — SemiBold 22 in black, with the date beneath at half strength. */
.ddb .ddb-review__name {
  font-weight: var(--ddb-w-bold);
  font-size: clamp(18px, 1.273vw, 22px);
  line-height: 1.5;
  color: #000;
}
.ddb .ddb-review__when {
  font-weight: var(--ddb-w-medium);
  font-size: 15px;
  line-height: 1.5;
  color: rgb(0 0 0 / .5);
}
.ddb .ddb-review__mark { width: 38px; height: 38px; object-fit: contain; }   /* node 154:5021 */

/* Stars, in the design's own gold. The box is 118 × 30 (node 154:5020). */
.ddb .ddb-stars {
  display: inline-flex;
  gap: 3px;
  color: #f1be42;                               /* the design's own gold */
  font-size: 21px;                              /* five glyphs and four gaps → the drawn 118 */
  line-height: calc(30 / 21);
}
.ddb .ddb-review__stars { margin-top: 16px; }   /* avatar 97 → stars 113 */
/* Node 154:5019 — Medium 15/22, six lines of measure inside 388. */
.ddb .ddb-review__quote {
  margin-top: 14px;                             /* stars 143 → quote 149 minus the glyph box */
  max-width: 388px;
  font-weight: var(--ddb-w-medium);
  font-size: 15px;
  line-height: calc(22 / 15);
  color: #000;
}

/* The overall-rating badge, 204 × 86 (nodes 119:2213–119:2216). */
.ddb-reviews__badge {
  display: inline-grid;
  grid-template-columns: 47px auto;
  align-items: center;
  gap: 0;                                       /* the stars begin where the mark ends */
  min-width: 204px;
  min-height: 86px;
  padding: 19px 18px 19px 21px;                 /* 1423 → mark 1444; stars end 1609 → 1627 */
  border-radius: var(--ddb-r-card);
  background: var(--ddb-white);
}
.ddb .ddb-reviews__badge-mark { width: 47px; height: 47px; object-fit: contain; }
.ddb-reviews__badge-body { display: grid; gap: 4px; }
.ddb-reviews__badge-body { padding-left: 0; }
.ddb .ddb-reviews__badge-label {
  font-weight: var(--ddb-w-medium);
  font-size: clamp(16px, 1.273vw, 22px);
  line-height: 1.5;
  color: #000;
}
/* In production the badge is not drawn: the practice asked for the widget's
   rating header to be left out of the band (2026-10-13; initReviews hides it),
   so the head is the pill and the heading alone. */

@media (max-width: 700px) {
  .ddb .ddb-reviews__grid { grid-template-columns: minmax(0, 1fr); }
}

/* ── 18 · FAQs ─────────────────────────────────────────────────────────── */

.ddb-faq__inner {
  width: min(100% - (2 * clamp(20px, 17.014vw, 294px)), 1140px);
  margin-inline: auto;
}
/* The frame's 294px gutters are a proportion of a 1728 frame; kept as one on a
   phone they would leave the questions in a 258px column. Below the width the
   page changes shape at, the block falls back to the page's own gutter. */
@media (max-width: 900px) {
  .ddb-faq__inner { width: min(100% - (2 * var(--ddb-gutter)), 1140px); }
  .ddb.ddb-page--contact .ddb-faq__inner { width: min(100% - (2 * var(--ddb-gutter)), 940px); }
}

.ddb-faq__head { text-align: center; margin-bottom: 31px; }      /* heading 96 → rows 127 */
/* The centred section eyebrows sit in a 33 line box (nodes 119:2267 and
   119:2381), not the 23 the in-page eyebrows use. */
.ddb-faq__head .ddb-eyebrow { min-height: 33px; margin-bottom: 15px; }   /* 33 → 48 */
.ddb .ddb-faq .ddb-h2 { font-size: var(--ddb-t-intro); font-weight: var(--ddb-w-medium); }

/* Each question is a card rather than a ruled row (node 119:2269). */
.ddb-faq__list { display: grid; gap: 15px; }                     /* 209 → 224 */
.ddb-faq__item {
  width: min(100%, 1021px);
  margin-inline: auto;
  border-radius: var(--ddb-r-card);
  background: var(--ddb-cream);
}

.ddb .ddb-faq__q { margin: 0; }
.ddb .ddb-faq__trigger {
  display: flex;
  align-items: center;
  gap: 24px;
  width: 100%;
  min-height: 82px;
  padding: 12px 35px 12px 32px;                                  /* text at 92 of a row at 60 */
  text-align: left;
}
.ddb .ddb-faq__label {
  flex: 1;
  font-weight: var(--ddb-w-medium);
  font-size: var(--ddb-t-lead);                                  /* node 119:2270 */
  letter-spacing: var(--ddb-track-ui);
  color: var(--ddb-primary);
}

/* The approved + / − mark: two rules, the vertical one folding away on open.
   No icon font, no extra container (§29). */
.ddb .ddb-faq__mark {
  position: relative;
  flex: none;
  width: 20px; height: 20px;
}
.ddb .ddb-faq__mark::before,
.ddb .ddb-faq__mark::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transition: transform var(--ddb-dur) var(--ddb-ease);
}
.ddb .ddb-faq__mark::after { transform: rotate(90deg); }
.ddb .ddb-faq__trigger[aria-expanded="true"] .ddb-faq__mark::after { transform: rotate(0deg); }

.ddb .ddb-faq__a {
  overflow: hidden;
  transition: height var(--ddb-dur) var(--ddb-ease);
}
.ddb .ddb-faq__a[hidden] { display: none; }
.ddb .ddb-faq__a-inner { padding: 0 35px 26px 32px; max-width: 76ch; }


/* ── 19 · Team (node 147:5025) ─────────────────────────────────────────── */

/* The grid runs 138 → 1575 of the 1728 frame: four 348 cards with a 15 gutter,
   and 16 between the rows. */
.ddb-team__inner {
  width: 100%;
  max-width: calc(1437px + clamp(20px, 7.986vw, 138px) + clamp(20px, 8.854vw, 153px));
  padding-inline: clamp(20px, 7.986vw, 138px) clamp(20px, 8.854vw, 153px);
  margin-inline: auto;
}
.ddb-team__head { margin-bottom: clamp(24px, 2.6vw, 44px); }
.ddb .ddb-team__grid {
  display: grid;
  /* 300 is the track floor that gives four 348 columns inside the drawn 1437 and
     steps down a column at a time as the page narrows. */
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  column-gap: 15px;
  row-gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
}
/* The card is the photograph. The plate sits over its foot rather than beneath
   it, so the card's height is the image's and nothing below it moves when a
   role runs to two words or ten. */
.ddb-team__item {
  position: relative;
  aspect-ratio: 348 / 432;
  border-radius: var(--ddb-r-panel);            /* node 147:5022 — 50 */
  overflow: hidden;
  background: var(--ddb-ground-alt);
  margin: 0;
}
.ddb-team__photo { position: absolute; inset: 0; }
.ddb .ddb-team__img { width: 100%; height: 100%; object-fit: cover; }

/* The name plate (node 147:5019): white at 57% over a 16.25px blur, radius 15,
   inset 7 from the card's sides and foot. This glass is in the design. */
.ddb-team__plate {
  position: absolute;
  left: calc((7 / 348) * 100%);
  right: calc((6 / 348) * 100%);
  bottom: calc((7 / 432) * 100%);
  min-height: calc((79 / 432) * 100%);
  display: grid;
  align-content: center;
  gap: 0;
  padding: 8px calc((18 / 348) * 100%);
  border-radius: 15px;
  background: rgb(255 255 255 / .57);
  -webkit-backdrop-filter: blur(16.25px);
  backdrop-filter: blur(16.25px);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .ddb-team__plate { background: rgb(255 255 255 / .86); }
}
.ddb .ddb-team__name {
  font-weight: var(--ddb-w-bold);                /* node 147:5020 — SemiBold 18/24 */
  font-size: clamp(16px, 1.042vw, 18px);
  line-height: calc(24 / 18);
  letter-spacing: 0;
  color: var(--ddb-primary);
  margin: 0;
}
.ddb .ddb-team__role {
  font-weight: var(--ddb-w-medium);              /* node 147:5021 — Medium 13/24 */
  font-size: clamp(12px, 0.752vw, 13px);
  line-height: calc(24 / 13);
  color: var(--ddb-ink);
  margin: 0;
}
.ddb-team__actions { display: flex; justify-content: center; margin-top: clamp(24px, 2.6vw, 44px); }


/* ── 20 · Locations ────────────────────────────────────────────────────── */

.ddb-locs__inner,
.ddb-ldet__inner {
  width: min(100% - (2 * var(--ddb-gutter)), var(--ddb-content));
  margin-inline: auto;
}
/* The grid runs 107 → 1600: two 736 cards with a 21 gutter. */
.ddb-locs__inner {
  width: 100%;
  max-width: calc(1493px + clamp(20px, 6.192vw, 107px) + clamp(20px, 7.407vw, 128px));
  padding-inline: clamp(20px, 6.192vw, 107px) clamp(20px, 7.407vw, 128px);
  margin-inline: auto;
}
.ddb-locs__head { margin-bottom: clamp(24px, 2.6vw, 44px); }
.ddb .ddb-locs__grid {
  display: grid;
  /* Two across, as drawn. A third practice starts a second row rather than
     squeezing three into one — the card's proportions are the design's. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 21px;
  margin: 0;
  padding: 0;
  list-style: none;
}
/* The card is the photograph (node 119:2682): radius 40 under a 40% scrim, with
   the copy seated in its lower half. */
.ddb .ddb-loc {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  aspect-ratio: 736 / 774;
  display: grid;
  align-content: end;
  padding: 0 clamp(20px, 3.53vw, 61px) clamp(28px, 3.25vw, 56px);
  border-radius: 40px;
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
  margin: 0;
}
.ddb-loc__media { position: absolute; inset: 0; z-index: -1; overflow: hidden; border-radius: 40px; }
.ddb-loc__media::after { content: ""; position: absolute; inset: 0; background: rgb(0 0 0 / .4); }
.ddb .ddb-loc__img { width: 100%; height: 100%; object-fit: cover; }
.ddb .ddb-loc__body { display: grid; gap: 0; }
/* Node 119:2685 — 45 Light in a 324 measure, so the practice's name breaks
   exactly where the design breaks it. */
.ddb .ddb-loc__name {
  font-weight: var(--ddb-w-light);
  font-size: clamp(30px, 2.604vw, 45px);
  line-height: 1.06;
  letter-spacing: var(--ddb-track-display);
  color: var(--ddb-ink-invert);
  text-decoration: none;
  max-width: 324px;
}
.ddb .ddb-loc__strap {
  margin-top: 9px;                                /* name 572 → copy 581 */
  max-width: 459px;
  color: var(--ddb-ink-invert);
}
/* Node 119:2687 — 223 × 56 with a 19 gutter, both set Light. */
.ddb .ddb-loc__actions { margin-top: 34px; gap: 19px; }
.ddb .ddb-loc__actions .ddb-btn {
  min-width: 223px;
  min-height: 56px;
  font-weight: var(--ddb-w-light);
}

.ddb-lhero__panel {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  margin-inline: var(--ddb-bleed-inset);
  border-radius: var(--ddb-r-panel);
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
  min-height: clamp(420px, 44vw, 760px);
  display: grid;
  align-items: end;
}
.ddb .ddb-lhero__img { position: absolute; inset: 0; z-index: -1; width: 100%; height: 100%; object-fit: cover; }
.ddb-lhero__inner {
  width: min(100% - (2 * var(--ddb-gutter)), var(--ddb-content));
  margin-inline: auto;
  padding-block: clamp(40px, 5vw, 86px);
  max-width: 46ch;
}
.ddb .ddb-lhero__logo-img { width: clamp(160px, 14vw, 240px); margin-bottom: 24px; }

.ddb-ldet__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: clamp(24px, 3vw, 60px);
  align-items: start;
}
.ddb .ddb-ldet__facts { display: grid; gap: clamp(18px, 1.8vw, 28px); }
.ddb-fact { padding-top: 16px; border-top: 1px solid var(--ddb-line); }
.ddb .ddb-fact__label {
  font-size: var(--ddb-t-meta);
  letter-spacing: var(--ddb-track-display);
  color: var(--ddb-muted);
  margin-bottom: 4px;
}
@media (max-width: 900px) { .ddb-ldet__inner { grid-template-columns: minmax(0, 1fr); } }


/* ── 21 · Gallery ──────────────────────────────────────────────────────── */

.ddb-gallery__inner {
  width: min(100% - (2 * var(--ddb-gutter)), var(--ddb-content));
  margin-inline: auto;
}
.ddb .ddb-gallery__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: 20px;
  margin-top: clamp(24px, 2.6vw, 44px);
}
.ddb-gallery__item { overflow: hidden; border-radius: 25px; aspect-ratio: 4 / 3; background: var(--ddb-ground-alt); }
.ddb .ddb-gallery__img { width: 100%; height: 100%; object-fit: cover; }


/* ── 22 · Resources ────────────────────────────────────────────────────── */

/* Node 119:2143 — x 131, width 1452. */
.ddb-res__inner,
.ddb-rindex__inner {
  width: 100%;
  max-width: calc(1452px + clamp(20px, 7.581vw, 131px) + clamp(20px, 8.391vw, 145px));
  padding-inline: clamp(20px, 7.581vw, 131px) clamp(20px, 8.391vw, 145px);
  margin-inline: auto;
}
.ddb-res__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 16px;
  margin-bottom: 55px;                         /* heading 97 → cards 152 */
}
.ddb-res__head .ddb-eyebrow { margin-bottom: 19px; }   /* eyebrow 30 → heading 49 */
.ddb .ddb-res__rail { grid-auto-columns: min(100%, clamp(260px, 26.273vw, 454px)); gap: 45px; }  /* node 119:2145 */
/* The desktop slide is a share of the viewport with a 260px floor, and by
   tablet that floor is what shows: at 800px the rail held two-and-a-bit 260px
   cards, each too slight to carry its image and copy. From here down the slide
   is a share of the rail itself instead, so the cards stay substantial at
   every width between the checkpoints: two full cards and a sliver of the
   next through the tablet range, then one full card with a clear peek of the
   following one once the rail is phone-width. The peek is deliberate — it is
   what says "this scrolls" without an arrow being pressed. */
@media (max-width: 1080px) {
  .ddb .ddb-res__rail { grid-auto-columns: min(100%, calc(46% - 14px)); gap: clamp(24px, 3.2vw, 36px); }
}
@media (max-width: 820px) {
  .ddb .ddb-res__rail { grid-auto-columns: min(100%, 72%); }
}
@media (max-width: 480px) {
  .ddb .ddb-res__rail { grid-auto-columns: 84%; gap: 20px; }
}

.ddb .ddb-rcard { display: grid; gap: 0; align-content: start; padding-bottom: 9px; }   /* pill 468 → tile 477 */
/* Node 119:2527 — 451 wide inside a 454 tile, set 3 in from the left edge and
   flush with the right. The asymmetry is the drawn geometry and is reproduced. */
.ddb-rcard__media {
  display: block;
  overflow: hidden;
  border-radius: 40px;                        /* node 119:2527 */
  aspect-ratio: 451 / 291;
  width: calc(100% - 3px);
  margin-left: 3px;
  background: var(--ddb-cream);
  margin-bottom: 17px;                        /* image 291 → title 308 */
}
.ddb .ddb-rcard__img { width: 100%; height: 100%; object-fit: cover; }
/* Title 22 in from the tile edge, copy and link 24 (nodes 119:2528 / 119:2529
   / 119:2531 — 4.85% and 5.29% of 454). With the highlight card's 4px frame
   outside that, nothing sits nearer than 26 to the coloured edge. */
.ddb .ddb-rcard__body { display: grid; gap: 0; padding-inline: 22px 18px; }
/* Node 119:2528 — Poppins Medium 24/28 in the practice's near-black, not the
   identity green the section heading above it is set in. */
.ddb .ddb-rcard__title {
  font-weight: var(--ddb-w-medium);
  font-size: clamp(19px, 1.389vw, 24px);
  letter-spacing: var(--ddb-track-display);
  line-height: calc(28 / 24);                 /* 414 × 56 → two lines */
  color: var(--ddb-ink);
}
/* The highlight card's head follows this tile's own image radius (40, node
   119:2527) plus the 4 inset, rather than the 52 the treatment column uses for
   its 50 image — the two curves have to stay concentric on each card. */
.ddb .ddb-rcard.ddb-card-link::before { border-radius: 44px 44px var(--ddb-r-hover-bot) var(--ddb-r-hover-bot); }
/* Node 119:2529 — 15/24 Regular at half strength, which is what keeps the
   ninety characters the design sets on two lines inside 392. */
.ddb .ddb-rcard__excerpt {
  margin-top: 7px;
  margin-left: 2px;
  max-width: 392px;                           /* 364 → 371 */
  font-size: 15px;
  line-height: calc(24 / 15);                 /* 15/24, not the body ratio */
  color: rgb(32 31 34 / .5);
}
.ddb .ddb-rcard__meta { display: flex; gap: 14px; font-size: var(--ddb-t-meta); color: var(--ddb-muted); margin-top: 6px; }
/* Read More sits in its own 33-tall pill (node 192:5122 — 132 × 33, radius
   100, white). On white it is invisible; over the highlight card it is what
   keeps the link legible. */
.ddb .ddb-rcard__more {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  margin-top: 16px;                           /* excerpt 419 → pill 435 */
  margin-left: 2px;
  justify-self: start;                        /* the pill is its own width, not the column's */
  min-width: 132px;                           /* node 192:5122 — 132 × 33 */
  padding-block: 4px 5px;                     /* a 33 line box around the 24 text */
  border-radius: var(--ddb-r-pill);
  font-weight: var(--ddb-w-regular);          /* node 119:2531 — Regular 16/24 */
  color: var(--ddb-ink);
  transition: background-color var(--ddb-dur) var(--ddb-ease);
}
/* The pill is flush left with the link text and runs to the right of it, so it
   appears around the words without moving them a pixel. */
.ddb .ddb-rcard.ddb-card-link:hover .ddb-rcard__more,
.ddb .ddb-rcard.ddb-card-link:focus-visible .ddb-rcard__more { background: var(--ddb-white); }
.ddb .ddb-rcard__more i { transition: transform var(--ddb-dur-fast) var(--ddb-ease); }
.ddb .ddb-rcard:hover .ddb-rcard__more i { transform: translateX(.25em); }

/* Three 454 tiles across with a 45 gutter and 48 between the rows — the same
   tile the home page's carousel uses, laid out as a grid (nodes 119:2526 ff). */
.ddb .ddb-rindex__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 380px), 1fr));
  column-gap: 45px;
  row-gap: 48px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.ddb-rindex__grid > li { margin: 0; }
.ddb-res__actions { display: flex; justify-content: center; margin-top: clamp(24px, 2.6vw, 44px); }


/* ── 23 · Pricing (frame 119:2383) ─────────────────────────────────────── */

/* The tables and the booking card share the top of the page: tables at x 121
   width 1010, card at x 1185 width 468, so 121 / 54 / 75 across the frame. */
.ddb-pricing {
  width: 100%;
  max-width: calc(1532px + 121px + 75px);
  padding-inline: clamp(20px, 7vw, 121px) clamp(20px, 4.34vw, 75px);
  margin-inline: auto;
}
.ddb-pricing__cols {
  display: grid;
  grid-template-columns: minmax(0, 1010fr) minmax(0, 468fr);
  gap: clamp(24px, 3.125vw, 54px);
  align-items: start;
}
.ddb-page--pricing .ddb-pricing { margin-top: clamp(48px, 4.977vw, 86px); }  /* header 610 → tabs 696 */
.ddb-page--pricing .ddb-process { margin-top: clamp(50px, 5.208vw, 90px); }  /* tables 2717 → how-it-works 2807 */
.ddb-page--pricing .ddb-footer  { margin-top: clamp(36px, 3.588vw, 62px); }  /* how-it-works 3782 → footer 3844 */

/* One column when there is no card, and always below the breakpoint where a
   468 column would squeeze the price rows. */
.ddb-pricing--nocard .ddb-pricing__cols { grid-template-columns: minmax(0, 1fr); }
@media (max-width: 1100px) {
  .ddb-pricing__cols { grid-template-columns: minmax(0, 1fr); }
}

.ddb-prices__inner { width: 100%; }
.ddb-prices__head { margin-bottom: clamp(24px, 2.6vw, 44px); }

/* Tab strip, node 119:2386 — a 562 × 104 sand shell with the active tab as a
   white pill inset 13 / 11 inside it. */
/* The signed-off strip is 562 × 104 (nodes 119:2386 and 119:2116). Browser text
   metrics set the three drawn labels a little narrower than Figma measures
   them, so the strip is held at its drawn width and the tabs share the slack;
   a longer set of labels still grows it rather than truncating. */
.ddb-ptabs {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  padding: 11px 13px;
  min-width: min(562px, 100%);
  border-radius: 20px;                      /* node 119:2387 */
  background: var(--ddb-sand);
  margin-bottom: 44px;                      /* strip 800 → first table 844 */
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}
.ddb-ptabs::-webkit-scrollbar { display: none; }
.ddb .ddb-ptabs__tab {
  display: inline-flex;
  align-items: center;
  min-height: 82px;                         /* node 119:2388 — 177 × 82 */
  padding-inline: 45px 38px;                /* label 179 in a pill 134 → 311 */
  border-radius: 10px;
  white-space: nowrap;
  font-weight: var(--ddb-w-light);
  font-size: 22px;                          /* node 119:2389 */
  letter-spacing: -0.22px;
  color: var(--ddb-ink-deep);
  background: transparent;
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-ptabs__tab.is-active { background: var(--ddb-white); }

/* Price table, node 119:2392 — 1010 wide, a 72 sand head row, then 72-pitch
   rows each closing on a hairline. */
.ddb .ddb-ptable {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
  text-align: left;
}
/* The frame's own gaps between stacked tables are 55, then 45, then 45
   (1276→1331, 1763→1808, 2240→2285) — reproduced rather than levelled. */
.ddb .ddb-ptable + .ddb-ptable { margin-top: 55px; }
.ddb .ddb-ptable + .ddb-ptable + .ddb-ptable { margin-top: 45px; }
.ddb .ddb-ptable__col {
  padding: 26px 0 19px 36px;                /* head 844 → text 870, row 72 tall */
  background: var(--ddb-sand);
  font-weight: var(--ddb-w-light);
  font-size: 18px;                          /* node 119:2394 */
  letter-spacing: -0.18px;
  color: var(--ddb-ink-deep);
}
.ddb .ddb-ptable__col--price { padding-left: 0; }
.ddb .ddb-ptable :where(.ddb-ptable__name, .ddb-ptable__price) {
  /* 21 above the text, 33 of text, 17 below, and the hairline itself: 72 to
     the row beneath, with the rule landing exactly on 988 of the frame. */
  padding: 21px 0 17px;
  border-bottom: 1px solid var(--ddb-line);
  font-weight: var(--ddb-w-light);
  font-size: 22px;                          /* nodes 119:2398 / 119:2399 */
  letter-spacing: -0.22px;
  color: var(--ddb-ink-deep);
}
.ddb .ddb-ptable__name { padding-left: 36px; }           /* 121 → 157 */
/* The price column starts at 802 of the 1010, so the name column is given that
   width outright rather than being left to the table's own distribution. */
.ddb .ddb-ptable :where(.ddb-ptable__name, .ddb-ptable__col):first-child { width: 79.406%; }
.ddb .ddb-ptable__note {
  display: block;
  margin-top: 4px;
  font-size: var(--ddb-t-meta);
  color: var(--ddb-muted);
}
.ddb-prices__panel[hidden] { display: none; }
.ddb-prices__footnote { margin-top: 24px; font-size: var(--ddb-t-meta); color: var(--ddb-muted); }

/* Booking / finance card, node 119:2509 — 468 × 435, sand, radius 30, every
   line centred. */
.ddb-booking { margin-top: 22px; }          /* tabs 696 → card 718 */
.ddb-booking__card {
  padding: 45px 33px 33px;                  /* heading 763, buttons 402 wide */
  border-radius: 30px;                      /* node 119:2510 */
  background: var(--ddb-sand);
  text-align: center;
}
.ddb .ddb-booking__title {
  font-weight: var(--ddb-w-light);
  font-size: 24px;                          /* node 119:2515 */
  letter-spacing: -0.24px;
  line-height: 1.5;
  color: var(--ddb-ink-deep);
}
.ddb .ddb-booking__copy {
  margin: 13px auto 0;                      /* heading 799 → copy 812 */
  max-width: 359px;                         /* node 119:2514 */
  font-weight: var(--ddb-w-light);
  letter-spacing: -0.16px;
}
/* Node 119:2512 — a white pill that sizes to its own wording. */
.ddb .ddb-booking__finance {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-top: 21px;                         /* copy 884 → pill 905 */
  min-height: 45.19px;
  padding-inline: 24px;
  border-radius: var(--ddb-r-pill);
  background: var(--ddb-white);
  font-weight: var(--ddb-w-light);
  font-size: 15.641px;                      /* node 119:2513 */
  letter-spacing: -0.156px;
  color: var(--ddb-ink-deep);
}
/* This card's buttons are its own: 402 × 65 at radius 20 in 18px Light, stacked
   full width, not the 191 × 56 pair the rest of the site uses. */
.ddb .ddb-booking__actions {
  display: grid;
  gap: 9px;                                 /* button 1 ends 1046 → button 2 1055 */
  margin-top: 30px;                         /* pill 951 → button 981 */
}
.ddb .ddb-booking__actions .ddb-btn {
  width: 100%;
  min-width: 0;
  min-height: 65px;
  border-radius: 20px;
  font-weight: var(--ddb-w-light);
  font-size: 18px;
  letter-spacing: -0.18px;
}
/* Node 119:2520 — the second button is outlined in ink on the card's own
   ground, not in the identity colour. */
.ddb .ddb-booking__actions .ddb-btn--secondary {
  background: var(--ddb-sand);
  border-color: var(--ddb-ink-deep);
  color: var(--ddb-ink-deep);
}
.ddb .ddb-booking__actions .ddb-btn--secondary:hover {
  background: var(--ddb-ink-deep);
  color: var(--ddb-white);
}
/* The wireframe-era price table and booking card were replaced by the
   measured Pricing composition in section 23 above. */


/* ── 24 · Contact, forms & map ─────────────────────────────────────────── */

/* ── Referral form (frame 119:2341) ──────────────────────────────────────
   985 wide from x 332, centred: a heading and introduction over a two-column
   field grid with a 23 gutter. */
/* 985 wide from x 332 — the composition sits a little left of the frame's own
   centre line, which is where the design puts it. */
.ddb-referral__inner {
  width: 100%;
  max-width: calc(985px + clamp(20px, 19.213vw, 332px) + clamp(20px, 23.785vw, 411px));
  padding-inline: clamp(20px, 19.213vw, 332px) clamp(20px, 23.785vw, 411px);
  margin-inline: auto;
}
/* The frame's gutters are asymmetric — 332 left, 411 right — and expressed in
   vw they keep that proportion all the way down, which on a phone leaves the
   form 222px wide inside a 390px screen, off-centre. Below the width the rest
   of the page changes shape at, the composition falls back to the page's own
   gutter: same form, centred, at the measure every other section uses. */
@media (max-width: 900px) {
  .ddb-referral__inner {
    max-width: none;
    padding-inline: var(--ddb-gutter);
  }
}

.ddb-referral__head { text-align: center; }
.ddb .ddb-referral .ddb-h1 {
  font-size: var(--ddb-t-intro);                 /* node 119:2359 — 45 */
  font-weight: var(--ddb-w-medium);
  line-height: var(--ddb-lh-heading);
}
.ddb .ddb-referral__body {
  max-width: 459px;
  margin: 20px auto 0;                           /* heading 731 → copy 751 */
  color: var(--ddb-muted);
}
.ddb .ddb-form--referral { margin-top: 49px; padding: 0; background: none; }   /* copy 799 → legend 848 */
.ddb .ddb-form--referral .ddb-form__skeleton { gap: 19px; }
.ddb .ddb-form--referral .ddb-form__pair { margin-top: 0; }
.ddb .ddb-form--referral .ddb-form__field--area { margin-top: 0; }
.ddb-form__legend {
  display: block;
  text-align: center;
  font-weight: var(--ddb-w-medium);
  font-size: clamp(16px, 1.157vw, 20px);         /* node 154:5697 */
  line-height: calc(25 / 20);
  color: var(--ddb-primary);
  margin-block: 26px 21px;                       /* 1262 → 1307, and 873 → 913 */
}
.ddb-form__legend:first-child { margin-top: 0; }
.ddb-form__row { display: block; }
.ddb .ddb-form--referral .ddb-form__pair { grid-template-columns: repeat(2, minmax(0, 481fr)); gap: 23px; }
.ddb .ddb-form--referral .ddb-form__field { height: 73px; border-radius: 15px; background: var(--ddb-sand); position: relative; }
.ddb .ddb-form--referral .ddb-form__field--area { height: 164px; }
.ddb-form__hint {
  position: absolute;
  top: 25px;
  left: 24px;
  font-size: 16px;
  color: var(--ddb-muted);
}
.ddb .ddb-form--referral .ddb-form__submit { min-height: 69px; margin-top: 1px; border-radius: 15px; }
/* The real form gets the same field treatment as the skeleton. */
.ddb .ddb-form--referral :where(input[type="text"], input[type="email"], input[type="tel"],
                                input[type="url"], input[type="number"], input[type="date"],
                                select, textarea) {
  min-height: 73px;
  border-radius: 15px;
  background: var(--ddb-sand);
}
.ddb .ddb-form--referral :where(textarea) { min-height: 164px; }
@media (max-width: 700px) {
  .ddb .ddb-form--referral .ddb-form__pair { grid-template-columns: minmax(0, 1fr); }
}

/* "Where to find us" (node 119:2622) — 1390 wide from x 149, the heading and
   its buttons above a 1390 × 622 map. */
.ddb-map__inner {
  width: 100%;
  max-width: calc(1398px + clamp(20px, 8.623vw, 149px) + clamp(20px, 10.475vw, 181px));
  padding-inline: clamp(20px, 8.623vw, 149px) clamp(20px, 10.475vw, 181px);
  margin-inline: auto;
}
.ddb-map__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 24px;
  margin-bottom: 50px;                           /* heading 1642 → map 1692 */
}
.ddb-map__head .ddb-eyebrow { margin-bottom: 19px; }   /* 1575 → 1594 */
.ddb .ddb-map__actions { gap: 11px; }                  /* 1360 → 1371 */
.ddb .ddb-map__actions .ddb-btn { min-width: 176px; min-height: 56px; }
.ddb-map__frame {
  position: relative;
  overflow: hidden;
  border-radius: 30px;
  aspect-ratio: 1390 / 622;
  max-width: 1390px;
  background: var(--ddb-ground-alt);
}
.ddb .ddb-map__frame :where(iframe, img) { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.ddb-map__frame--pending { border: 1px dashed rgb(0 0 0 / .18); }



/* ── 24a · Contact (frame 119:2563) ──────────────────────────────────────
   Two 675 columns from x 149 to 1539, each a sand card at radius 30. */
.ddb-contact__inner {
  width: 100%;
  max-width: calc(1390px + clamp(20px, 8.623vw, 149px) + clamp(20px, 10.938vw, 189px));
  padding-inline: clamp(20px, 8.623vw, 149px) clamp(20px, 10.938vw, 189px);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 675fr) minmax(0, 40fr) minmax(0, 675fr);
  align-items: start;
}
.ddb-contact__col:first-child { grid-column: 1; }
.ddb-contact__col:last-child  { grid-column: 3; }
.ddb-contact__card {
  border-radius: 30px;
  background: var(--ddb-sand);
  padding: 32px 26px;                            /* card 665 → first row 697 */
}
.ddb .ddb-contact__rows { display: grid; gap: 16px; margin: 0; padding: 0; list-style: none; }
/* Each row is 616 × 128 in white at radius 20, with a 78 green tile inside it. */
.ddb-contact__row {
  display: grid;
  grid-template-columns: 78px minmax(0, 1fr);
  align-items: center;
  gap: 28px;                                     /* tile ends 278, label at 306 */
  min-height: 128px;
  padding: 0 25px;                               /* row 175 → tile 200 */
  border-radius: 20px;
  background: var(--ddb-white);
  margin: 0;
}
.ddb-contact__icon {
  width: 78px;
  height: 78px;
  display: grid;
  place-items: center;
  border-radius: 16px;
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
  font-size: 30px;
}
.ddb-contact__text { display: grid; gap: 2px; min-width: 0; }
.ddb .ddb-contact__label {
  font-size: clamp(15px, 1.042vw, 18px);
  line-height: calc(27 / 18);
  color: var(--ddb-muted);
}
.ddb .ddb-contact__value {
  font-weight: var(--ddb-w-medium);
  font-size: clamp(18px, 1.389vw, 24px);
  line-height: calc(27 / 24);
  color: var(--ddb-ink);
  text-decoration: none;
}
.ddb .ddb-contact__value:hover { color: var(--ddb-primary); }

/* Social row: three 47 discs on the left, the label on the right. */
/* The discs sit at one end of this row and the label at the other. Three discs,
   a 20px gap and the label need about 365px inside a card that is 330 wide on a
   phone, so the row wraps rather than pushing the label out of the card — and
   when it wraps the label leads, because a line of type reading "Connect on
   Social" above its own icons is the composition, where a stray label under
   them is not. */
.ddb-contact__social {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 20px;
  min-height: 47px;                              /* the discs' own height, kept
                                                    whether or not any are set */
  margin-top: 27px;                              /* rows end 1113 → discs 1140 */
  padding-inline: 17px;
}
@media (max-width: 480px) {
  .ddb-contact__social { justify-content: flex-start; }
  .ddb .ddb-contact__social-label { order: -1; width: 100%; }
}
.ddb .ddb-contact__socials { display: flex; gap: 5px; margin: 0; padding: 0; list-style: none; }
.ddb .ddb-contact__socials a {
  width: 47px;
  height: 47px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--ddb-white);
  color: var(--ddb-ink);
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease), color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-contact__socials a:hover { background: var(--ddb-primary); color: var(--ddb-ink-invert); }
.ddb .ddb-contact__social-label {
  font-weight: var(--ddb-w-medium);
  font-size: clamp(17px, 1.273vw, 22px);
  color: var(--ddb-ink);
}

/* The Google row sits beneath the card, not inside it (nodes 119:2589 / 119:2599). */
.ddb-contact__google {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  margin-top: 38px;                              /* card 1220 → label 1258 */
  padding-inline: 26px;
}
/* Where the practice has a reviews listing, the whole row is the way to it. The
   anchor is transparent to layout, so the label and the badge stay the flex
   children the row was measured with. */
.ddb .ddb-contact__google-link { display: contents; }
.ddb .ddb-contact__google-label {
  font-weight: var(--ddb-w-medium);
  font-size: clamp(17px, 1.273vw, 22px);
  color: var(--ddb-ink);
}
.ddb .ddb-contact__google-link:hover .ddb-contact__google-label,
.ddb .ddb-contact__google-link:focus-visible .ddb-contact__google-label {
  text-decoration: underline;
}
/* Google's own mark, at the size the badge draws it (node 119:2214). It sits
   where the badge does, so the row reads the same way with or without a rating
   beside it. */
.ddb .ddb-contact__google-mark { width: 34px; height: auto; flex: none; }

/* The form card carries the same sand ground and its own heading. */
.ddb .ddb-contact__card--form { padding: 35px 36px 53px; }   /* submit ends 1399 → card 1452 */
.ddb .ddb-contact__card--form .ddb-eyebrow { margin-bottom: 3px; }
.ddb .ddb-form__title {
  font-weight: var(--ddb-w-bold);
  font-size: clamp(22px, 1.62vw, 28px);          /* node 119:2590 */
  line-height: calc(32 / 28);
  letter-spacing: var(--ddb-track-display);
  color: var(--ddb-primary);
  margin: 0 0 40px;                              /* heading 758 → first field 798 */
}
.ddb .ddb-form__pending { color: var(--ddb-muted); }

/* WPForms' own output, restyled to the drawn field: white, radius 12, 69 tall. */
.ddb .ddb-form :where(input[type="text"], input[type="email"], input[type="tel"],
                      input[type="url"], input[type="number"], input[type="date"],
                      select, textarea) {
  width: 100%;
  min-height: 69px;
  padding: 18px 22px;
  border: 0;
  border-radius: 12px;
  background: var(--ddb-white);
  color: var(--ddb-ink);
  font-family: inherit;
  font-size: 16px;
}
.ddb .ddb-form :where(textarea) { min-height: 143px; resize: vertical; }
.ddb .ddb-form :where(input, select, textarea):focus-visible {
  outline: 2px solid var(--ddb-primary);
  outline-offset: 2px;
}
.ddb .ddb-form :where(button, input[type="submit"], .wpforms-submit) {
  width: 100%;
  min-height: 55px;
  border: 0;
  border-radius: 12px;
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
  font-family: inherit;
  font-weight: var(--ddb-w-medium);
  font-size: 16px;
  cursor: pointer;
}
.ddb .ddb-form :where(button:hover, input[type="submit"]:hover, .wpforms-submit:hover) { background: var(--ddb-ink-deep); }

/* Development-only footprint for the form the practice has not connected yet.
   Every gap here is the one the frame draws between those two fields, so the
   card's height — and everything below it on the page — is the design's. */
.ddb-form__skeleton { display: grid; gap: 14px; }
.ddb-form__pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-top: 7px; }
.ddb-form__field { display: block; height: 69px; border-radius: 12px; background: var(--ddb-white); }
.ddb-form__field--area { height: 143px; margin-top: 3px; }
.ddb-form__consent { display: flex; align-items: center; gap: 11px; margin-top: 3px; }
.ddb-form__box { width: 17px; height: 17px; border-radius: 4px; background: var(--ddb-white); flex: none; }
.ddb-form__consent-text { font-size: 14px; color: var(--ddb-muted); }
.ddb-form__submit {
  display: grid;
  place-items: center;
  min-height: 55px;
  margin-top: 2px;
  border-radius: 12px;
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
  font-weight: var(--ddb-w-medium);
}


/* ── 24a · WPForms output, mapped onto the drawn form ────────────────────────
   WPForms owns the fields, the validation and the submission; the design owns
   how it looks. Its own full stylesheet is switched off (Settings → WPForms →
   Include Form Styling: None) and only its small base sheet remains, for the
   utilities that are behaviour rather than appearance — hiding the honeypot,
   hiding a field switched off by conditional logic, the screen-reader class.

   Every rule below is scoped through .wpforms-container as well as .ddb-form.
   That is not decoration: WPForms' base sheet loads after this one, so an
   equally specific rule of ours would lose to it. Scoping one level deeper
   settles the cascade by specificity rather than by load order, which no
   plugin update can reorder.

   Layout is taken back from WPForms entirely: the field container is a two
   column grid, every field spans both columns, and a field marked one-half
   takes one. One rule, instead of tracking WPForms' float behaviour across
   versions — and it is what puts the pairs on the Figma's own column edges.

   The vertical gaps are the frame's, and the frame's are not uniform: the
   Contact form runs 14, 21, 21, 17, 17, 20 between its rows (node 119:2563).
   The base row-gap carries the 14 and the differences are added where they
   occur, so the field stack measures the 601px the card is drawn to and the
   card lands on its 787. */

.ddb .ddb-form .wpforms-container { margin: 0; }
.ddb .ddb-form .wpforms-container .wpforms-form { margin: 0; }

.ddb .ddb-form .wpforms-container .wpforms-field-container {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 16px;                                  /* node 119:2593 → 119:2594 */
  row-gap: 14px;                                     /* 867 → 881 */
}

.ddb .ddb-form .wpforms-container .wpforms-field {
  grid-column: 1 / -1;
  /* WPForms sizes a half-width field with a percentage meant for a float
     layout. Inside the grid that percentage is taken of the column rather than
     the row, and a pair comes out a quarter of the measure; the left margin it
     adds to the second of a pair then pushes it out of its own column. */
  width: 100%;
  max-width: none;
  float: none;
  margin: 0;
  padding: 0;
  border: 0;
}
.ddb .ddb-form .wpforms-container .wpforms-one-half { grid-column: span 1; }

/* Labels are drawn inside the field as placeholder text, so the label element
   leaves the flow — but not the accessibility tree, which is what a screen
   reader and an autofill heuristic both read. */
.ddb .ddb-form .wpforms-container .wpforms-field-label.wpforms-label-hide,
.ddb .ddb-form .wpforms-container .wpforms-field-sublabel.wpforms-sublabel-hide {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.ddb .ddb-form .wpforms-container .wpforms-field-label {
  display: block;
  margin: 0 0 6px;
  font-size: 15px;
  font-weight: var(--ddb-w-medium);
  color: var(--ddb-ink);
}
.ddb .ddb-form .wpforms-container .wpforms-required-label { color: var(--ddb-primary); border: 0; }

/* The gaps the frame actually draws, on top of the base row-gap. */
.ddb .ddb-form .wpforms-container .wpforms-one-half.wpforms-first,
.ddb .ddb-form .wpforms-container .wpforms-one-half.wpforms-first + .wpforms-one-half { margin-top: 7px; }
.ddb .ddb-form .wpforms-container .wpforms-field-textarea { margin-top: 3px; }
.ddb .ddb-form .wpforms-container .wpforms-field-checkbox { margin-top: 3px; }

/* The submit sits outside the field grid, so its separation is its own margin
   rather than the grid's row-gap: consent ends 1327, button starts 1344. */
.ddb .ddb-form .wpforms-container .wpforms-submit-container { margin-top: 16px; padding: 0; }

/* The consent line (node 119:2600): a 17px box, 11px from its wording. */
.ddb .ddb-form .wpforms-container :where(.wpforms-field-checkbox, .wpforms-field-radio) ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 8px;
}
.ddb .ddb-form .wpforms-container :where(.wpforms-field-checkbox, .wpforms-field-radio) li {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  margin: 0;
}
.ddb .ddb-form .wpforms-container :where(.wpforms-field-checkbox, .wpforms-field-radio) input {
  width: 17px;
  height: 17px;
  min-height: 0;
  margin: 3px 0 0;
  flex: none;
  accent-color: var(--ddb-primary);
}
.ddb .ddb-form .wpforms-container :where(.wpforms-field-checkbox, .wpforms-field-radio) label {
  font-size: 14px;
  line-height: calc(20 / 14);
  color: var(--ddb-muted);
  font-weight: var(--ddb-w-regular);
  margin: 0;
}

/* A section divider becomes the centred legend the Referral form draws
   (node 154:5697). */
.ddb .ddb-form .wpforms-container .wpforms-field-divider { border: 0; }
.ddb .ddb-form .wpforms-container .wpforms-field-divider :where(h1, h2, h3, h4, h5, h6) {
  text-align: center;
  font-weight: var(--ddb-w-medium);
  font-size: clamp(16px, 1.157vw, 20px);
  line-height: calc(25 / 20);
  color: var(--ddb-primary);
  margin-block: 26px 21px;
}
.ddb .ddb-form .wpforms-container .wpforms-field-divider:first-child :where(h1, h2, h3, h4, h5, h6) { margin-top: 0; }
.ddb .ddb-form .wpforms-container .wpforms-field-divider .wpforms-field-description {
  text-align: center;
  color: var(--ddb-muted);
}

/* Validation. Restrained and legible rather than the boxed alert the design
   does not draw — but never hidden: an error a visitor cannot see is a form
   they cannot complete. */
.ddb .ddb-form .wpforms-container :where(label.wpforms-error, em.wpforms-error, .wpforms-error-container) {
  display: block;
  margin-top: 7px;
  padding: 0;
  font-size: 14px;
  font-weight: var(--ddb-w-regular);
  line-height: calc(20 / 14);
  color: #a32020;
}
.ddb .ddb-form .wpforms-container .wpforms-error-container { margin: 0 0 14px; }
.ddb .ddb-form .wpforms-container :where(input, select, textarea).wpforms-error {
  box-shadow: inset 0 0 0 1px #a32020;
}

/* Confirmation: the practice's own wording, on the page's own ground. */
.ddb .ddb-form .wpforms-container :where(.wpforms-confirmation-container, .wpforms-confirmation-container-full) {
  margin: 0;
  padding: 24px 26px;
  border: 0;
  border-radius: var(--ddb-r-btn);
  background: var(--ddb-white);
  color: var(--ddb-ink);
}
.ddb .ddb-form .wpforms-container .wpforms-confirmation-container p:last-child { margin-bottom: 0; }
.ddb .ddb-form .wpforms-container .wpforms-submit-spinner { margin-left: 10px; }

/* ── The Referral form ──
   The same system on a wider measure: 985 across, two 481 columns, 73-tall
   fields on the sand ground, 19px between rows (node 119:2341). Scoped through
   .wpforms-container like everything above, so it outranks the generic block
   rather than losing to it. */

.ddb .ddb-form--referral .wpforms-container .wpforms-field-container {
  grid-template-columns: repeat(2, minmax(0, 481fr));
  column-gap: 23px;                                  /* 813 → 836 */
  row-gap: 19px;                                     /* 986 → 1005 */
}
.ddb .ddb-form--referral .wpforms-container .wpforms-one-half.wpforms-first,
.ddb .ddb-form--referral .wpforms-container .wpforms-one-half.wpforms-first + .wpforms-one-half,
.ddb .ddb-form--referral .wpforms-container .wpforms-field-textarea,
.ddb .ddb-form--referral .wpforms-container .wpforms-field-checkbox { margin-top: 0; }

.ddb .ddb-form--referral .wpforms-container :where(input[type="text"], input[type="email"],
  input[type="tel"], input[type="url"], input[type="number"], input[type="date"],
  select, textarea) {
  min-height: 73px;                                  /* node 119:2344 */
  border-radius: 15px;
  background: var(--ddb-sand);
  padding: 22px 24px;
}
.ddb .ddb-form--referral .wpforms-container :where(textarea) {
  min-height: 164px;                                 /* node 119:2346 */
  height: 164px;
}
.ddb .ddb-form--referral .wpforms-container .wpforms-field-divider :where(h1, h2, h3, h4, h5, h6) {
  margin-block: 26px 21px;                           /* 1262 → 1307, 873 → 913 */
}
.ddb .ddb-form--referral .wpforms-container .wpforms-submit-container { margin-top: 20px; }   /* 1812 → 1832 */
.ddb .ddb-form--referral .wpforms-container :where(button, input[type="submit"], .wpforms-submit) {
  min-height: 69px;                                  /* node 119:2357 */
  border-radius: 15px;
}

/* Below the point where two fields side by side stop being usable, every field
   takes the whole measure — the fluid behaviour the rest of the site uses,
   rather than a squeeze that ends in unusable inputs.

   The viewport is the wrong thing to measure that against, because the same
   form is a full-width block on Referrals and one column of a two-up on
   Contact. At a 1024 viewport the Contact form is 400px wide, so its "half"
   fields were 156px — narrower than the placeholder text inside them — while
   the page was still 300px above this breakpoint. The form is now its own query
   container and answers to its own width, so it behaves correctly in both
   placements without either one knowing about the other. The media query is
   kept underneath as the fallback. */
.ddb .ddb-form { container-type: inline-size; container-name: ddb-form; }

@container ddb-form (max-width: 560px) {
  .ddb .ddb-form .wpforms-container .wpforms-field-container,
  .ddb .ddb-form--referral .wpforms-container .wpforms-field-container { grid-template-columns: minmax(0, 1fr); }
  .ddb .ddb-form .wpforms-container .wpforms-one-half { grid-column: 1 / -1; }
  .ddb .ddb-form .wpforms-container .wpforms-one-half.wpforms-first,
  .ddb .ddb-form .wpforms-container .wpforms-one-half.wpforms-first + .wpforms-one-half { margin-top: 0; }
  .ddb .ddb-form .ddb-form__pair { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 700px) {
  .ddb .ddb-form .wpforms-container .wpforms-field-container { grid-template-columns: minmax(0, 1fr); }
  .ddb .ddb-form .wpforms-container .wpforms-one-half { grid-column: 1 / -1; }
  .ddb .ddb-form .wpforms-container .wpforms-one-half.wpforms-first,
  .ddb .ddb-form .wpforms-container .wpforms-one-half.wpforms-first + .wpforms-one-half { margin-top: 0; }
}

/* The Contact composition stacks before the two cards get too narrow to hold
   their contents: the details card's rows lose their generous padding, and the
   form card takes the whole measure rather than half of it. Restored here after
   it was lost when this section was rewritten — without it the form card was
   152px wide on a phone. */
/* 1080, not the 1000 it was (and not the 900 before that): the wrapper is
   about 0.81 of the viewport here, so at the old 1000 trigger each 675fr
   column was ~380 — and the right-hand column is an enquiry form whose
   name/email pairs are themselves two-up, which made them 180px fields for
   80px of viewport before the stack arrived. At 1080 the columns are ~420 and
   the pairs ~190; that is the point at which the form stops being comfortable,
   so that is where it stacks. */
@media (max-width: 1080px) {
  .ddb-contact__inner {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(20px, 3vw, 28px);
    /* Stacked, the frame's measured gutters (8.6vw and 10.9vw of asymmetry)
       stop earning their keep — they were the two-column composition's
       placement, and on one column they only starve the cards. A steady ~30px
       a side instead, easing to 20 on a small phone. */
    padding-inline: clamp(20px, 3.75vw, 30px);
  }
  .ddb-contact__col:first-child,
  .ddb-contact__col:last-child { grid-column: 1; }
  /* The form is the page's primary action, so once the columns stack it
     leads and the details card follows — ordering, not markup. */
  .ddb-contact__col:last-child { order: -1; }
  .ddb-contact__row { grid-template-columns: 56px minmax(0, 1fr); gap: 16px; padding: 20px; min-height: 0; }
  .ddb-contact__icon { width: 56px; height: 56px; font-size: 22px; }
}

/* Below the phone breakpoint the card's own inset comes down too, so the
   fields keep a usable measure instead of paying for 36px of padding twice. */
@media (max-width: 560px) {
  .ddb .ddb-contact__card--form { padding: 24px 20px 32px; }
  .ddb .ddb-contact__card { padding: 20px; }
}

/* ── 24b · Article & treatment promotion (frame 119:2544) ────────────────
   The article column starts at 449 of the 1728 frame — indented, not centred —
   and each element inside it keeps its own measure: 780 for the heading, 845
   for the words, 932 for a picture. */
/* ── A measured gutter that gives way before the measure does ─────────────
   The frame's indent is 449 left and 347 right — 46% of the page — and held as
   a proportion it keeps taking 46% all the way down: at 390 it left the article
   a 210px column, which is a 32px heading breaking every two words. The same is
   true of the policy pages' 239px gutters.

   Rather than dropping to the shared gutter at a breakpoint — which works, and
   is what the Referral section does below, but steps the indent by 200px as you
   cross it — each gutter is capped by the room left over once the text has been
   given a readable measure. Three terms, and whichever is smallest wins: the
   frame's own maximum, the frame's proportion, and half of whatever is left
   after the measure floor, split in the design's own left/right ratio. A 20px
   floor keeps a gutter at the very bottom.

   At 1728 the first two terms decide it and the gutters are exactly 449 and
   347 — the signed-off composition. Below about 1290 the third term takes over
   and the indent closes smoothly rather than at a step, holding the measure at
   560px all the way to the phone. */
.ddb-article__inner {
  --ddb-measure-min: 560px;
  width: 100%;
  max-width: calc(932px + clamp(20px, 25.984vw, 449px) + clamp(20px, 20.081vw, 347px));
  padding-inline:
    max(20px, min(449px, 25.984vw, calc(.5641 * (100% - var(--ddb-measure-min)))))
    max(20px, min(347px, 20.081vw, calc(.4359 * (100% - var(--ddb-measure-min)))));
  margin-inline: auto;
}
/* Node 119:2547 — 50 Medium in a 780 measure. Larger than the page headings
   this design uses elsewhere, and set from its own node. */
.ddb .ddb-article__title {
  max-width: 780px;
  font-weight: var(--ddb-w-medium);
  font-size: clamp(32px, 2.894vw, 50px);
  line-height: 1.06;
  letter-spacing: var(--ddb-track-display);
  color: var(--ddb-primary);
  margin: 0 0 35px;                              /* 777 → 812 */
}
/* Each element inside the article keeps its own measure: 845 for the words, 918
   for a sub-heading, 932 for a picture. */
.ddb .ddb-article__body { max-width: 932px; color: var(--ddb-muted); }
.ddb .ddb-article__body > * { max-width: 845px; }
.ddb .ddb-article__body > * + * { margin-top: 1.5em; }
.ddb .ddb-article__body :where(h2, h3) {
  max-width: 918px;
  color: var(--ddb-primary);
  font-weight: var(--ddb-w-medium);
  font-size: var(--ddb-t-bento);                 /* node 119:2549 — 35/37 */
  line-height: var(--ddb-lh-h35);
  letter-spacing: var(--ddb-track-display);
  margin-top: 55px;                              /* picture 1741 → heading 1796 */
}
.ddb .ddb-article__body :where(h2, h3) + * { margin-top: 63px; }   /* 1907 → 1970 */
/* A picture is cropped to the drawn 932 × 442 rather than taking whatever
   proportion the file happens to have — wpautop wraps it in a paragraph, so the
   paragraph is what carries the measure. */
.ddb .ddb-article__body :where(p:has(> img:only-child)) { max-width: 932px; }
.ddb .ddb-article__body :where(img) {
  display: block;
  width: 100%;
  max-width: 932px;
  aspect-ratio: 932 / 442;                       /* node 119:2551 */
  height: auto;
  object-fit: cover;
  border-radius: 30px;
  margin-block: 55px;
}
/* The paragraph around a lone picture must not add its own gap on top of the
   picture's. */
.ddb .ddb-article__body :where(p:has(> img:only-child)) { margin-top: 0; }
.ddb .ddb-article__body :where(a) { color: var(--ddb-primary); text-decoration: underline; }

/* The promotion card (node 119:2556): 890 × 198 in the warm sand, its image
   202 × 168 inset 15, and a 73 control at the right. */
.ddb-promo { display: flex; justify-content: center; }
.ddb .ddb-promo__card {
  display: grid;
  grid-template-columns: 202px minmax(0, 1fr) 73px;
  align-items: center;
  gap: 29px;                                     /* image ends 651, title at 680 */
  width: min(100% - (2 * var(--ddb-gutter)), 890px);
  min-height: 198px;
  padding: 15px 50px 15px 15px;                  /* 2464 → image 2479; arrow ends 1274 of 1324 */
  border-radius: 30px;
  background: var(--ddb-sand);
  color: var(--ddb-ink);
  text-decoration: none;
}
.ddb-promo__media {
  width: 202px;
  height: 168px;
  overflow: hidden;
  border-radius: 20px;
  background: var(--ddb-ground-alt);
}
.ddb .ddb-promo__img { width: 100%; height: 100%; object-fit: cover; }
.ddb .ddb-promo__body { display: grid; gap: 11px; min-width: 0; }
.ddb .ddb-promo__title {
  font-weight: var(--ddb-w-medium);
  font-size: clamp(22px, 1.736vw, 30px);         /* node 119:2557 */
  line-height: calc(35 / 30);
  letter-spacing: var(--ddb-track-display);
  color: var(--ddb-primary);
  max-width: 179px;
}
.ddb .ddb-promo__price { font-size: clamp(15px, 1.042vw, 18px); color: var(--ddb-ink); }
.ddb .ddb-promo__go {
  width: 73px;
  height: 73px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--ddb-white);
  color: var(--ddb-primary);
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease), color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-promo__card:hover .ddb-promo__go,
.ddb .ddb-promo__card:focus-visible .ddb-promo__go {
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
}
@media (max-width: 700px) {
  .ddb .ddb-promo__card { grid-template-columns: minmax(0, 1fr); justify-items: start; padding: 15px; }
  .ddb-promo__media { width: 100%; height: auto; aspect-ratio: 202 / 168; }
}


/* ── 24b · Page not found ──────────────────────────────────────────────── */

/* The message sits in the middle of whatever room is left between the masthead
   and the footer, rather than at a fixed distance from the top.

   Two steps, because the page shell only gets the height as far as <main>: §1
   makes <main> the flex child that absorbs the spare height, and this makes
   <main> a column of its own so the section inside it can absorb that height in
   turn. `place-content: center` then centres the block within it. On a viewport
   too short to centre in, `padding-block` is what keeps the copy off the bar
   above and the footer below.

   No panel, no photograph, no ground: this is a white page with three things
   on it. */
.ddb-page--not_found .ddb-main { display: flex; flex-direction: column; }
.ddb-nf {
  flex: 1 0 auto;
  display: grid;
  place-content: center;
  padding-block: clamp(72px, 12vh, 160px);
  text-align: center;
}
.ddb-nf__inner {
  width: min(100% - (2 * var(--ddb-gutter)), 640px);
  margin-inline: auto;
}
.ddb .ddb-nf .ddb-eyebrow { margin-bottom: 14px; }
.ddb .ddb-nf .ddb-h1 {
  font-size: var(--ddb-t-intro);                  /* the 45 Light the intro uses */
  font-weight: var(--ddb-w-light);
  line-height: var(--ddb-lh-heading);
  color: var(--ddb-primary);
}
.ddb .ddb-nf__body {
  margin-top: 18px;
  color: var(--ddb-muted);
}
.ddb .ddb-nf__actions {
  display: flex;
  justify-content: center;
  margin-top: clamp(28px, 3vw, 40px);
}


/* ── 25 · Legal ────────────────────────────────────────────────────────── */

/* Frame 119:2635 — a 1250 measure from x 239. */
/* Same treatment as the article wrapper above: the frame's 239px gutters are
   kept while there is room for them, and capped by the room left after the
   policy has its measure. At 390 they were taking 108px of a 390px screen. */
.ddb-legal__inner {
  --ddb-measure-min: 560px;
  width: 100%;
  max-width: calc(1250px + (2 * clamp(20px, 13.831vw, 239px)));
  padding-inline: max(20px, min(239px, 13.831vw, calc(.5 * (100% - var(--ddb-measure-min)))));
  margin-inline: auto;
}
.ddb-legal__head { margin-bottom: 41px; }                   /* heading 750 → body 791 */
.ddb-legal__head .ddb-eyebrow { margin-bottom: 11px; }      /* 691 → 702 */
.ddb .ddb-legal .ddb-h1 {
  font-size: var(--ddb-t-intro);                            /* node 119:2639 — 45 */
  font-weight: var(--ddb-w-medium);
  line-height: var(--ddb-lh-heading);
}
.ddb .ddb-legal__updated { color: var(--ddb-muted); font-size: var(--ddb-t-meta); margin-bottom: 24px; }

/* ── The policy layout ──
   The prose in the wide column with the Contents rail beside it. The rail is a
   short column against a long one, so it is sticky and `align-self: start` —
   a stretched grid item is as tall as the row and could never travel.

   The prose column is capped well inside the track it sits in: the frame's
   measure is 1250 and long-form policy text is not comfortable at anything like
   that, so it is held to a readable line and the slack falls between the two
   columns. */
.ddb-legal__layout {
  display: grid;
  /* The rail holds its drawn 340 while the page is wide and narrows with it
     after that, so the policy keeps the measure rather than paying for a panel
     that has stopped needing all of its width. At 1728 the 22vw term is 380 and
     the 340 cap decides it, so the desktop composition is the drawn one. */
  grid-template-columns: minmax(0, 1fr) minmax(0, clamp(250px, 22vw, 340px));
  gap: clamp(36px, 4.6vw, 80px);
  align-items: start;
}
.ddb-legal__layout--solo { grid-template-columns: minmax(0, 1fr); }
.ddb .ddb-legal__body { max-width: 760px; }
.ddb-legal__layout--solo .ddb-legal__body { max-width: none; }

.ddb-legal__rail {
  position: sticky;
  top: var(--ddb-sticky-offset);
  align-self: start;
}

.ddb .ddb-legal__section + .ddb-legal__section { margin-top: 48px; }
/* The section's own scroll clearance. The header's height is already carried
   once, globally, by `scroll-padding-top` on the document (§1); what belongs
   here is only the breathing space beneath the bar, not a second copy of it. */
.ddb .ddb-legal__section { scroll-margin-top: 12px; }
.ddb .ddb-legal__section-title {
  font-weight: var(--ddb-w-light);
  font-size: var(--ddb-t-feature);
  letter-spacing: var(--ddb-track-display);
  line-height: var(--ddb-lh-display);
  margin: 0 0 16px;
}
/* A sub-heading the client writes inside a section has to sit *under* that
   section's own title. The body h2 rule below is the same step as the title, so
   headings written inside the prose each drop one. */
.ddb .ddb-legal__section :where(h2) { font-size: clamp(18px, 1.45vw, 25px); margin-top: 32px; }

/* ── Contents rail ── */
.ddb .ddb-toc {
  padding: clamp(20px, 1.8vw, 30px) clamp(18px, 1.5vw, 26px);
  border-radius: var(--ddb-r-card);
  background: var(--ddb-ground-alt);
}
.ddb .ddb-toc__title { margin: 0 0 14px; }
.ddb .ddb-toc__list {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: ddb-toc;
}
.ddb .ddb-toc__item + .ddb-toc__item { border-top: 1px solid var(--ddb-line); }
/* The whole row is the link, so a reader can press anywhere along it rather
   than having to find the words. */
.ddb .ddb-toc__link {
  display: flex;
  gap: 12px;
  padding-block: 11px;
  font-size: var(--ddb-t-meta);
  line-height: 1.5;
  color: var(--ddb-ink);
  transition: color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-toc__link::before {
  counter-increment: ddb-toc;
  content: counter(ddb-toc, decimal-leading-zero);
  flex: none;
  color: var(--ddb-primary);
  font-variant-numeric: tabular-nums;
  opacity: .5;
  transition: opacity var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-toc__link:hover,
.ddb .ddb-toc__link:focus-visible { color: var(--ddb-primary); }
.ddb .ddb-toc__link:hover::before,
.ddb .ddb-toc__link:focus-visible::before { opacity: 1; }

/* Below the width a policy stops sharing its line with a panel, the rail
   becomes an ordinary block *above* the policy. It is navigation: the reader
   should meet it on the way in, not find it stranded under a long document.
   Sticky is dropped with it — a panel stacked above the content has nothing to
   travel alongside. */
@media (max-width: 1100px) {
  .ddb-legal__layout { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .ddb-legal__rail { position: static; order: -1; }
  .ddb .ddb-legal__body { max-width: none; }
  .ddb .ddb-toc { max-width: 520px; }
}

.ddb .ddb-legal__body :where(h2) {
  font-weight: var(--ddb-w-light);
  font-size: var(--ddb-t-feature);
  letter-spacing: var(--ddb-track-display);
  line-height: var(--ddb-lh-display);
  margin-top: 48px;
  margin-bottom: 16px;
  scroll-margin-top: 100px;
}
.ddb .ddb-legal__body :where(h3) {
  font-size: clamp(18px, 1.45vw, 25px);
  letter-spacing: var(--ddb-track-display);
  margin-top: 32px;
  margin-bottom: 12px;
}
.ddb .ddb-legal__body :where(p, ul, ol) { margin-bottom: 16px; }
.ddb .ddb-legal__body :where(ul, ol) { padding-left: 1.25em; list-style: revert; }
.ddb .ddb-legal__body :where(a) { text-decoration: underline; text-underline-offset: 3px; }


/* ── 26 · Motion preferences ───────────────────────────────────────────── */


/* ── Section heads that carry their own controls ──────────────────────────
   Four sections put a heading in a 1fr track with its controls — carousel
   arrows, a "View all" button, a reviews badge — in an `auto` track beside it.
   An `auto` track takes what it needs before the 1fr gets anything, so as the
   page narrows the controls hold their size and the heading pays for all of it:
   on a 390 phone the Latest Resources heading was down to a 174px box for 30px
   type, breaking "Latest News & Resources" over four lines beside a pair of
   63px discs.

   Below the width where the heading falls under about seven of its own ems, the
   two stop sharing a line. The controls keep their size and move under the
   heading, which is the readable order — you read what the row is before you
   reach for the control that moves it. */
@media (max-width: 720px) {
  .ddb-reviews__head,
  .ddb-res__head,
  .ddb-map__head,
  .ddb-tgrid__head {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(16px, 3vw, 24px);
    align-items: start;
  }
  .ddb-reviews__head > *,
  .ddb-res__head > *,
  .ddb-map__head > * { grid-column: 1; }
  .ddb-res__nav,
  .ddb-testi__nav { margin-left: 0; justify-content: flex-start; }
}

/* Subtle section stacking (§25). Applied only where a page composition opts in,
   never as a blanket rule, and it never changes the resting layout. */
.ddb [data-ddb-stack] {
  position: sticky;
  top: 0;
}

@media (prefers-reduced-motion: reduce) {
  .ddb *,
  .ddb *::before,
  .ddb *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .ddb .ddb-media--cycle .ddb-media__frame:not(.is-active) { opacity: 0; }
  .ddb [data-ddb-stack] { position: static; }
}


/* ── Skip link ─────────────────────────────────────────────────────────── */

.ddb-skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 999;
  padding: 12px 20px;
  background: #000;
  color: #fff;
}
.ddb-skip:focus { left: 8px; top: 8px; }


/* ==========================================================================
   27 · Treatment-area page components
   Measured from the Dental frame (119:2189). Aesthetics (119:2305) and
   Wellness (119:2323) share this composition and differ only by identity.
   ========================================================================== */

/* ── Page intro (node 119:2192) ─────────────────────────────────────────
   1466 wide at x 131: heading 771 on the left, copy 557 from x 872 with the
   buttons beneath it. */
.ddb-pintro__inner {
  width: 100%;
  max-width: calc(1466px + clamp(20px, 7.581vw, 131px) + clamp(20px, 7.581vw, 131px));
  padding-inline: clamp(20px, 7.581vw, 131px);
  margin-inline: auto;
  display: grid;
  /* The aside holds the copy and a 191px button pair; below about 400 the pair
     wraps and the paragraph drops to a six-word measure, so it takes a floor
     and the heading column gives up the difference. */
  grid-template-columns:
    minmax(0, 771fr) minmax(0, 101fr) minmax(min(100%, 400px), 557fr);
  align-items: start;
}
.ddb-pintro__lead  { grid-column: 1; }
.ddb-pintro__aside { grid-column: 3; }
.ddb-pintro__lead .ddb-eyebrow { margin-bottom: 19px; }        /* 23 → 42 */
.ddb .ddb-pintro .ddb-h2 {
  font-size: var(--ddb-t-intro);                                /* 45 Medium (node 119:2193) */
  font-weight: var(--ddb-w-medium);
}
.ddb .ddb-pintro__aside  { padding-top: 42px; }                 /* copy starts at 42 */
.ddb .ddb-pintro__actions { margin-top: 25px; gap: 12px; }      /* 114 → 139 */
/* This pair is set Light, unlike the Medium the intro's buttons use — nodes
   119:2198 / 119:2201 against node 119:2000. */
.ddb .ddb-pintro__actions .ddb-btn { min-width: 191px; font-weight: var(--ddb-w-light); }
.ddb .ddb-pintro__actions .ddb-btn--secondary { border-width: 1.5px; }   /* node 119:2197 */

@media (max-width: 760px) {
  .ddb .ddb-locs__grid { grid-template-columns: minmax(0, 1fr); }
}

/* 960: with the aside holding its 400 floor, that is where the heading column
   beside it falls below ~360 and a 45px treatment-area title starts breaking
   across three and four lines. */
@media (max-width: 960px) {
  .ddb-pintro__inner { grid-template-columns: minmax(0, 1fr); row-gap: clamp(18px, 3vw, 28px); }
  .ddb-pintro__lead, .ddb-pintro__aside { grid-column: 1; }
  .ddb .ddb-pintro__aside { padding-top: 0; }
  .ddb .ddb-pintro__body { max-width: 62ch; }
}

/* ── Alternating treatment rows (nodes 119:2234 / 119:2221) ─────────────
   The carousel and the copy do not sit on one shared pair of columns: the
   design insets them differently depending on which side they are, so each
   row declares explicit tracks rather than being normalised to one grid. */
.ddb-zig__inner {
  width: 100%;
  max-width: calc(1483px + clamp(20px, 6.25vw, 108px) + clamp(20px, 7.928vw, 137px));
  padding-inline: clamp(20px, 6.25vw, 108px) clamp(20px, 7.928vw, 137px);
  margin-inline: auto;
  display: grid;
  row-gap: 85px;                                                /* 1543 → 1628 */
}
/* The design's own last gap is wider than the three above it: the rows sit at
   993 / 1628 / 2263 / 2910, so the run-in to the final row is 647 where the
   others are 635. Reproduced rather than levelled out. */
.ddb-zig__row:last-child:not(:first-child) { margin-top: 12px; }
/* The row's four tracks are media / gutter / copy / trailing slack, and the
   copy track carries a floor as well as its share: a 45px treatment name and a
   211px button pair need about 440px, and below that the column stops being a
   column and becomes a squeeze. Between the frame width and the stack point the
   copy holds that 440 and the media gives up the difference — which is the
   right way round, because a photograph reads at 380 and a heading does not. */
.ddb-zig__row {
  display: grid;
  grid-template-columns:
    minmax(0, 756fr) minmax(0, 139fr) minmax(min(100%, 440px), 562fr) minmax(0, 26fr);
  align-items: center;
}
/* Both items share row 1 explicitly. Without this the flipped rows place the
   media in column 4 first and auto-placement pushes the copy onto a second row,
   doubling the row's height. */
.ddb-zig__row .ddb-zig__media { grid-column: 1; grid-row: 1; }
.ddb-zig__row .ddb-zig__copy  { grid-column: 3; grid-row: 1; }
/* Flipped rows: copy 45 in on the left, carousel starting at 727. */
.ddb-zig__row--flip {
  grid-template-columns:
    minmax(0, 45fr) minmax(min(100%, 440px), 562fr) minmax(0, 120fr) minmax(0, 756fr);
}
.ddb-zig__row--flip .ddb-zig__copy  { grid-column: 2; grid-row: 1; }
.ddb-zig__row--flip .ddb-zig__media { grid-column: 4; grid-row: 1; }

.ddb .ddb-zig__kicker {
  font-size: var(--ddb-t-meta);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ddb-muted);
  margin-bottom: 6px;
}
.ddb .ddb-zig__title {
  font-weight: var(--ddb-w-medium);
  font-size: clamp(30px, 2.604vw, 45px);                        /* node 119:2222 */
  line-height: var(--ddb-lh-heading);
  letter-spacing: var(--ddb-track-display);
  color: var(--ddb-primary);
}
.ddb .ddb-zig__body { margin-top: 24px; max-width: 550px; }     /* 74 → 98 */
.ddb .ddb-zig__actions { margin-top: 41px; gap: 13px; }         /* 278 → 319 */
.ddb .ddb-zig__actions .ddb-btn { min-width: 211px; }           /* node 119:2225 */

/* ── Stacked treatment rows ───────────────────────────────────────────────
   1080 rather than 900. The wrapper is about 0.858 of the viewport here, so at
   1080 it measures ~927: the copy takes its 440 floor and the media is left
   with ~385, which is the least a 756 × 550 carousel can be and still read.
   Below that the media was being squeezed while the copy stood still, which is
   the imbalance the brief describes.

   **The row previously drew the copy directly on top of the photograph at every
   width below the stack point.** Both items are placed with `grid-column` *and*
   `grid-row: 1`, and the old stacked rule reset only the column — so the two
   landed in the same single cell and painted over each other, at 900 and all
   the way down to 390, on all three treatment-area pages. `grid-row: auto` is
   the fix; `order` then gives every row the same reading sequence rather than
   letting the flipped rows arrive image-last (§10 of the amendments).

   The alternation is a wide-screen device. Stacked, keeping it would only mean
   some rows opened with a picture and others with a heading, which reads as a
   mistake rather than as rhythm — so every stacked row runs image, eyebrow,
   heading, copy, buttons. */
@media (max-width: 1080px) {
  .ddb-zig__row,
  .ddb-zig__row--flip {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(20px, 3vw, 32px);
  }
  .ddb-zig__row .ddb-zig__media,
  .ddb-zig__row .ddb-zig__copy,
  .ddb-zig__row--flip .ddb-zig__media,
  .ddb-zig__row--flip .ddb-zig__copy { grid-column: 1; grid-row: auto; }
  .ddb-zig__row .ddb-zig__media,
  .ddb-zig__row--flip .ddb-zig__media { order: 1; }
  .ddb-zig__row .ddb-zig__copy,
  .ddb-zig__row--flip .ddb-zig__copy { order: 2; }

  /* Stacked, the row is no longer competing with a column beside it, so the
     copy takes a reading measure rather than the track's full width and the
     gaps come in from the desktop rhythm. */
  .ddb-zig__inner { row-gap: clamp(44px, 6vw, 72px); }
  .ddb-zig__row:last-child:not(:first-child) { margin-top: 0; }
  .ddb .ddb-zig__body { max-width: 62ch; }
  .ddb .ddb-zig__actions { margin-top: clamp(20px, 3vw, 30px); }
}

/* ── Treatment image carousel (node 119:2234) — 756 × 550 ──────────────── */
.ddb-ttile {
  position: relative;
  aspect-ratio: 756 / 550;
  border-radius: var(--ddb-r-panel);
  overflow: hidden;
  background: var(--ddb-cream);
}
/* A 756 × 550 crop is a wide-screen proportion drawn for a row that has a
   column of copy beside it. Once the row stacks there is nothing beside it, and
   the same ratio makes a very wide, very shallow band; it steps to a card
   instead. Declared here rather than up with the stacked rules because the base
   rule above is the same specificity and would otherwise win on source order. */
@media (max-width: 1080px) { .ddb-ttile { aspect-ratio: 3 / 2; } }
@media (max-width: 600px)  { .ddb-ttile { aspect-ratio: 4 / 3; } }
/* The rail scrolls horizontally and only horizontally: the slides are exactly
   the viewport's height, so nothing can push it into a vertical scroll, and
   overflow-y is pinned closed in case a slide is ever taller than it should be.

   Containment is on the horizontal axis ONLY. `overscroll-behavior: contain`
   applied to both axes made this element a scroll trap: because its vertical
   overflow is clipped it still counts as a scroll container, so a wheel or a
   swipe over the photograph was swallowed instead of chaining to the page and
   the reader could not scroll past the treatment imagery. Horizontal
   containment is kept — it is what stops a sideways flick at the end of the
   rail from triggering a back-navigation gesture — while vertical intent is
   handed straight back to the document.

   touch-action is left at its default so the browser itself decides: a
   predominantly horizontal drag pans the rail, a predominantly vertical one
   scrolls the page. Nothing here calls preventDefault on a wheel or a touch. */
.ddb .ddb-ttile__rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
  height: 100%;
  max-height: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  overscroll-behavior-y: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.ddb .ddb-ttile__rail::-webkit-scrollbar { display: none; }
.ddb-ttile__slide { scroll-snap-align: center; height: 100%; min-height: 0; overflow: hidden; }
/* The source photograph is the full uncropped asset; the 756 × 550 viewport is
   what crops it, so the crop can change per breakpoint without a new file. */
.ddb .ddb-ttile__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Badge, 281 × 52 at 29/26 (node 119:2251). */
.ddb .ddb-ttile__badge {
  position: absolute;
  top: 26px;
  left: 29px;
  min-height: 52px;
  display: inline-flex;
  align-items: center;
  padding-inline: 26px;
  border-radius: var(--ddb-r-btn);
  background: var(--ddb-white);
  color: var(--ddb-primary);
  font-weight: var(--ddb-w-medium);
  font-size: var(--ddb-t-lead);
}

/* Arrows, 44 × 44 (nodes 119:2236 and 119:2242). The pair is deliberately
   asymmetric — 23 in from the left edge against 32 from the right — and sits
   7px below the container's centre line, which is reproduced rather than
   squared up. Figma reports a rotated layer's box before its rotation, so the
   previous control's drawn position is its reported origin less its diameter. */
.ddb .ddb-ttile__arrow {
  position: absolute;
  top: 260px;                       /* 44-tall control in a 550 viewport */
  top: calc((260 / 550) * 100%);
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 0;
  background: var(--ddb-sand);
  color: var(--ddb-primary);
  font-size: 14px;
  cursor: pointer;
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease),
              color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-ttile__arrow:hover,
.ddb .ddb-ttile__arrow:focus-visible {
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
}
.ddb .ddb-ttile__arrow--prev { left: 23px; }    /* node 119:2242 */
.ddb .ddb-ttile__arrow--next { right: 32px; }   /* node 119:2236 */
.ddb .ddb-ttile__arrow[hidden] { display: none; }

/* Dots, 13px with a 7 gutter (nodes 119:2248–119:2250). */
.ddb-ttile__dots {
  position: absolute;
  left: 50%;
  bottom: 31px;
  transform: translateX(-50%);
  display: flex;
  gap: 7px;
}
.ddb-ttile__dot {
  position: relative;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: rgb(255 255 255 / .5);
}
/* The dot the design draws is 13px, which is smaller than a fingertip can
   reliably hit. The mark stays exactly as drawn and an invisible target is
   extended around it instead, so the control is usable on a phone without the
   pagination looking any different. */
.ddb-ttile__dot::after {
  content: "";
  position: absolute;
  inset: -8px -4px;                     /* 29 tall, and half the 7px gap either side */
}
.ddb-ttile__dot.is-active { background: var(--ddb-white); }

/* ── Video testimonial carousel (node 119:2284) ─────────────────────────
   The active slide is 892 × 538 in the centre with its neighbours showing
   either side, so the rail is padded rather than clipped to the content width. */
.ddb-vtesti { overflow: hidden; }
.ddb-vtesti__stage { --ddb-vt-card: min(892px, 76vw); }
.ddb-vtesti__head { text-align: center; margin-bottom: 43px; }   /* heading 86 → stage 129 */
.ddb-vtesti__head .ddb-eyebrow { margin-bottom: 18px; }          /* 23 → 41 */
.ddb .ddb-vtesti .ddb-h2 {
  font-size: var(--ddb-t-intro);                                 /* 45 (node 119:2303) */
  font-weight: var(--ddb-w-medium);
  line-height: var(--ddb-lh-display);                            /* set solid here, not 45/48 */
}
/* Three complete cards is the widest composition the design draws, so past
   3 × 892 + 2 × 35 the stage stops growing and a fourth can never creep in at
   the edges. Below that the neighbours simply reveal more of themselves as room
   appears — one continuous carousel, no breakpoint switch. */
.ddb-vtesti__stage {
  position: relative;
  max-width: calc((3 * 892px) + (2 * 35px));
  margin-inline: auto;
}
.ddb .ddb-vtesti__rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: var(--ddb-vt-card);
  gap: 35px;                                                     /* 369 → 404 */
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  padding-inline: max(0px, calc((100% - var(--ddb-vt-card)) / 2));
}
.ddb .ddb-vtesti__rail::-webkit-scrollbar { display: none; }
.ddb-vtesti__slide { scroll-snap-align: center; margin: 0; position: relative; }
.ddb-vtesti__slide .ddb-bento__tile {
  aspect-ratio: 892 / 538;                                       /* node 119:2285 */
  border-radius: 20px;                                           /* not the 50 the panels use */
}
/* The active card carries a 53% black scrim over its photograph, which is what
   the name and role sit legibly on (node 119:2285). */
.ddb-vtesti__slide .ddb-bento__tile-media::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: rgb(0 0 0 / .53);
  transition: opacity var(--ddb-dur) var(--ddb-ease);
  pointer-events: none;
}
/* Its neighbours are drawn at a tenth of their strength and without the scrim
   (nodes 119:2293 / 119:2294 — opacity .1), so the centre card is unmistakably
   the one being read. The dimming only starts once the script is marking which
   slide is centred; before then every slide is simply itself. */
.ddb-vtesti__stage.is-marked .ddb-vtesti__slide { opacity: .1; }
.ddb-vtesti__stage.is-marked .ddb-vtesti__slide.is-active { opacity: 1; }
.ddb-vtesti__slide { transition: opacity var(--ddb-dur) var(--ddb-ease); }
.ddb-vtesti__stage.is-marked .ddb-vtesti__slide:not(.is-active) .ddb-bento__tile-media::after { opacity: 0; }
.ddb-vtesti__by {
  position: absolute;
  left: 49px;                                                    /* 453 − 404 */
  bottom: 43px;
  display: grid;
  padding-left: 69px;                                            /* the 55 play control + gap */
  color: var(--ddb-ink-invert);
  pointer-events: none;                 /* the card beneath is the play control */
  transition: opacity var(--ddb-dur) var(--ddb-ease);
}
/* The play control here is drawn at the foot of the card beside the name
   (node 119:2284): a 55px white disc seated 49px in and 43px up, not the bento
   tile's centred 64px one. The control still covers the whole card as the
   click target; only its glyph moves, and the card's own scrim does the
   darkening so the control adds none of its own. */
.ddb-vtesti__slide .ddb-play { place-items: end start; padding: 0 0 43px 49px; background: transparent; }
.ddb-vtesti__slide .ddb-play:hover,
.ddb-vtesti__slide .ddb-play:focus-visible { background: rgb(0 0 0 / .12); }
.ddb-vtesti__slide .ddb-play__glyph { width: 55px; height: 55px; font-size: 16px; }
/* While a testimonial plays its tile takes the player's 16:9 — the bento rule
   that does this is overridden by the 892 × 538 above, so it is restated at
   this specificity — and the caption steps aside rather than being drawn
   across the patient's video. */
.ddb-vtesti__slide .ddb-bento__tile.is-playing { aspect-ratio: var(--ddb-video-ratio, 16 / 9); }
.ddb-vtesti__slide:has(.is-playing) .ddb-vtesti__by { opacity: 0; }
.ddb .ddb-vtesti__name  { font-weight: var(--ddb-w-medium); font-size: var(--ddb-t-lead); }
.ddb .ddb-vtesti__label { font-size: var(--ddb-t-meta); opacity: .8; }
/* 55 × 55 controls seated 7px below the stage's centre line (nodes 119:2295 and
   119:2299). This carousel's controls are drawn *both* as a green disc with a
   white arrow — the reverse of the sand controls on the section carousels — so
   green is this control's resting state and the sand disc is what it becomes
   under the pointer. Measured per carousel, as the design intends.

   They are placed against the card rather than the frame, so they hold their
   drawn distance from its edges — 73 clear of the left edge, 62 clear of the
   right — at every width instead of only at 1728. The pair is asymmetric in the
   design and stays that way. */
.ddb .ddb-vtesti__arrow {
  position: absolute;
  top: calc((249 / 538) * 100%);
  width: 55px;
  height: 55px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 0;
  background: var(--ddb-primary);
  color: var(--ddb-ink-invert);
  cursor: pointer;
  z-index: 2;
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease),
              color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-vtesti__arrow:hover,
.ddb .ddb-vtesti__arrow:focus-visible {
  background: var(--ddb-sand);
  color: var(--ddb-primary);
}
.ddb .ddb-vtesti__arrow--prev {
  right: calc(50% + (var(--ddb-vt-card) / 2) + 73px);            /* node 119:2299 */
  left: auto;
}
.ddb .ddb-vtesti__arrow--next {
  left: calc(50% + (var(--ddb-vt-card) / 2) + 62px);             /* node 119:2295 */
}
.ddb .ddb-vtesti__arrow[hidden] { display: none; }
.ddb-vtesti__stage--single .ddb-vtesti__rail { grid-auto-flow: row; }

/* As the viewport narrows the side cards give up their space gradually rather
   than the layout switching: the centre card keeps 76vw until the arrows would
   no longer clear it, then they move inside its edges and it takes the width. */
@media (max-width: 1320px) {
  .ddb .ddb-vtesti__arrow--prev { right: auto; left: 16px; }
  .ddb .ddb-vtesti__arrow--next { left: auto; right: 16px; }
}
@media (max-width: 700px) {
  .ddb-vtesti__stage { --ddb-vt-card: min(892px, 88vw); }
  .ddb .ddb-vtesti__rail { gap: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .ddb-vtesti__slide,
  .ddb-vtesti__slide .ddb-bento__tile-media::after { transition: none; }
}


/* ── 27 · Administrator chrome ─────────────────────────────────────────────
   The only part of this stylesheet that is not the signed-off design. None of
   it is ever rendered for a visitor: the markup is not emitted without the
   capability, and every rule below is gated on the body class that goes with it.

   The rules are written so that they cannot move anything. The control is taken
   out of flow, and the only thing added to the section is `position: relative`,
   which shifts nothing by itself. A screenshot taken logged out and one taken
   logged in have the same section coordinates and the same page height. */

.ddb-editing .ddb-main > * { position: relative; }
.ddb-editing .ddb-footer   { position: relative; }

.ddb .ddb-edit {
  position: absolute;
  z-index: 40;
  top: 14px;
  right: 16px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px 5px 9px;
  border-radius: 4px;
  /* WordPress admin ink, not Durley's — this is a utility, not part of the
     public design. The shadow is here for legibility over photography, which is
     the one place in this stylesheet a shadow is not decoration. */
  background: #1d2327;
  color: #fff;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0;
  text-decoration: none;
  box-shadow: 0 1px 3px rgb(0 0 0 / .3);
  opacity: 0;
  visibility: hidden;
  transition: opacity .12s ease, visibility .12s ease, background-color .12s ease;
}
.ddb .ddb-edit i { font-size: 11px; }
.ddb .ddb-edit:hover,
.ddb .ddb-edit:focus-visible { background: #2271b1; color: #fff; }
.ddb .ddb-edit:focus-visible { outline: 2px solid #fff; outline-offset: 1px; }

/* Revealed by the section, so an administrator sees one control at a time and
   keyboard users reach it the same way a pointer does. */
.ddb-editing .ddb-main > *:hover > .ddb-edit,
.ddb-editing .ddb-main > *:focus-within > .ddb-edit {
  opacity: 1;
  visibility: visible;
}

/* The overlay is a hover affordance. Where there is no hover there is no way to
   reveal it without leaving it permanently on top of the design, so it is not
   shown at all — the same edit is a tap away from the toolbar. */
@media (hover: none) {
  .ddb .ddb-edit { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .ddb .ddb-edit { transition: none; }
}


/* ── 28 · Completion pass (2026-09-29): dropdowns, footer columns, team drawer ──
   Three additions the signed-off frames do not draw and the brief asked for,
   each built from values already in this file rather than from new ones: the
   FAQ's approved + / − mark, the 30 card radius, the cream interaction ground,
   the sand surface, the phone menu's scrim, and the 50 panel radius.
   ────────────────────────────────────────────────────────────────────────── */

/* The + / − mark, at whatever size its parent gives it. The vertical rule
   folds away when the control it belongs to is expanded — the same behaviour
   the FAQ mark has, on a control the FAQ does not own. */
.ddb .ddb-mark {
  position: relative;
  display: block;
  width: 10px;
  height: 10px;
}
.ddb .ddb-mark::before,
.ddb .ddb-mark::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 1.5px;
  margin-top: -.75px;
  border-radius: 1px;
  background: currentColor;
  transition: transform var(--ddb-dur) var(--ddb-ease);
}
.ddb .ddb-mark::after { transform: rotate(90deg); }
.ddb [aria-expanded="true"] > .ddb-mark::after { transform: rotate(0deg); }

/* ── 28a · A bar item with pages beneath it ─────────────────────────────── */

.ddb .ddb-nav__item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 7px;
}
/* The mark beside the label is its own 22px control, so a keyboard or a finger
   has something to press that is not the link. Quiet at rest; full strength
   when the item is hovered, open, or the control itself is focused. */
.ddb .ddb-nav__more {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  margin-left: -2px;
  border-radius: 6px;
  color: inherit;
  opacity: .62;
  transition: opacity var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-nav__item--parent:hover > .ddb-nav__more,
.ddb .ddb-nav__item--parent.is-open > .ddb-nav__more,
.ddb .ddb-nav__more:focus-visible { opacity: 1; }
/* The label underlines with the whole item, not only when the pointer is on
   the words: the label, the mark and the open dropdown are one thing. A page
   beneath the item keeps its parent underlined, as the current page does. */
.ddb .ddb-nav__item--parent:hover > .ddb-nav__link,
.ddb .ddb-nav__item--parent.is-open > .ddb-nav__link,
.ddb .ddb-nav__item--parent.is-branch > .ddb-nav__link { border-bottom-color: currentColor; }

/* The dropdown. A descendant of the item — so hovering it is hovering the
   item — positioned beneath the bar. Its top padding is the bridge: the gap
   between the bar and the card belongs to the hover region, so the pointer can
   travel straight down into the panel without the item ever seeing it leave. */
.ddb .ddb-mega {
  position: absolute;
  top: 100%;
  left: -14px;
  z-index: 30;
  padding-top: 22px;
  color: var(--ddb-ink-deep);
  opacity: 0;
  transform: translateY(6px);
  pointer-events: none;
  transition: opacity var(--ddb-dur-fast) var(--ddb-ease),
              transform var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-mega[hidden] { display: none; }
.ddb .ddb-nav__item.is-open > .ddb-mega {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
/* Three parts, deliberately weighted: the two link columns keep a generous
   inset of their own, while the card's outer padding is tight, so the practice
   card sits close to the white edge and the panel is no taller than its
   tallest column. */
.ddb .ddb-mega__card {
  display: flex;
  align-items: stretch;
  gap: clamp(20px, 2vw, 32px);
  width: max-content;
  max-width: min(calc(100vw - 40px), 900px);
  padding: 16px 16px 16px 20px;
  border-radius: var(--ddb-r-card);                    /* the glass card's 30 */
  background: var(--ddb-white);
  box-shadow: 0 24px 64px rgb(0 30 15 / .16), 0 0 0 1px rgb(0 67 34 / .06);
}
.ddb .ddb-mega__cols {
  display: flex;
  gap: clamp(20px, 2vw, 36px);
  padding: 8px 6px 4px 6px;
}
.ddb .ddb-mega__col { min-width: 176px; }
/* Column headings are headings, not links: a step up in weight, the deep ink
   rather than the muted grey, and a hairline beneath — the same rule the
   price tables and the profile drawer draw — so the eye reads a labelled
   group before it reads the links inside it. Still 15px, still sentence
   case; nothing about it invites a click. */
.ddb .ddb-mega__title {
  margin: 0 12px 10px;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--ddb-line);
  font-weight: var(--ddb-w-medium);
  font-size: var(--ddb-t-meta);
  letter-spacing: var(--ddb-track-ui);
  line-height: var(--ddb-lh-meta);
  color: var(--ddb-ink-deep);
}
.ddb .ddb-mega__list { display: grid; gap: 2px; }
.ddb .ddb-nav .ddb-mega__list a {
  display: flex;
  align-items: center;
  padding: 9px 12px;
  border-radius: 10px;
  border-bottom: 0;
  white-space: nowrap;
  font-weight: var(--ddb-w-light);
  font-size: var(--ddb-t-ui);
  letter-spacing: var(--ddb-track-ui);
  line-height: 1.3;
  color: var(--ddb-ink-deep);
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease),
              color var(--ddb-dur-fast) var(--ddb-ease),
              padding-left var(--ddb-dur-fast) var(--ddb-ease);
}
/* The interaction is the phone menu's, at this scale: the cream the cards use,
   the identity colour on the words, a small step to the right. */
.ddb .ddb-nav .ddb-mega__list a:hover,
.ddb .ddb-nav .ddb-mega__list a:focus-visible {
  background: var(--ddb-card-hi);
  color: var(--ddb-primary);
  padding-left: 16px;
  border-bottom: 0;
}
.ddb .ddb-nav .ddb-mega__list a[aria-current="page"] {
  background: var(--ddb-card-hi);
  color: var(--ddb-primary);
  font-weight: var(--ddb-w-regular);
  border-bottom: 0;
}

/* The practice card beside the columns: the Pricing composition's sand
   surface at the same 20 radius as its tab shell. */
.ddb .ddb-mega__aside {
  flex: none;
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 246px;
  padding: 20px 20px 20px;
  border-radius: 20px;
  background: var(--ddb-sand);
}
.ddb .ddb-mega__aside-title {
  margin: 0 0 4px;
  font-weight: var(--ddb-w-medium);
  font-size: var(--ddb-t-ui);
  letter-spacing: var(--ddb-track-ui);
  line-height: 1.35;
  color: var(--ddb-primary);
}
.ddb .ddb-nav .ddb-mega__phone {
  display: inline-block;
  padding: 0;
  font-weight: var(--ddb-w-light);
  font-size: 24px;
  letter-spacing: var(--ddb-track-display);
  line-height: 1.2;
  color: var(--ddb-ink-deep);
  border-bottom: 1px solid transparent;
  transition: border-color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-nav .ddb-mega__phone:hover,
.ddb .ddb-nav .ddb-mega__phone:focus-visible { border-bottom-color: currentColor; }
.ddb .ddb-mega__actions { margin-top: 16px; }
/* The booking button is the site's own filled button and takes the site's
   own hover — identity fill to gold — and nothing else. */
.ddb .ddb-nav .ddb-mega__actions .ddb-btn {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 12px;
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .ddb .ddb-mega,
  .ddb .ddb-mark::before,
  .ddb .ddb-mark::after,
  .ddb .ddb-nav__more,
  .ddb .ddb-nav .ddb-mega__list a { transition: none; }
}

/* ── 28b · The same pages inside the phone panel ────────────────────────── */

/* A parent row is drawn as every other row — same type, same chevron, same
   rounded cream on contact — but the whole row is the control that unfolds
   its pages. Open, the row and the list beneath it share one cream ground,
   the row's words take the identity colour, and its chevron turns to point
   down: one group, not a second component set into the menu. */
.ddb .ddb-nav--stacked .ddb-nav__parent {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  width: 100%;
  padding: clamp(13px, 2.4vw, 18px) clamp(14px, 2.4vw, 20px);
  border-radius: var(--ddb-r-btn);
  font-weight: var(--ddb-w-light);
  font-size: clamp(23px, 5.6vw, 32px);
  letter-spacing: var(--ddb-track-display);
  line-height: var(--ddb-lh-display);
  color: var(--ddb-ink-deep);
  text-align: left;
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease),
              color var(--ddb-dur-fast) var(--ddb-ease),
              padding-left var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-nav--stacked .ddb-nav__parent::after {
  content: "";
  flex: none;
  width: .34em;
  height: .34em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  opacity: .35;
  transition: opacity var(--ddb-dur-fast) var(--ddb-ease),
              transform var(--ddb-dur) var(--ddb-ease);
}
.ddb .ddb-nav--stacked .ddb-nav__parent:hover,
.ddb .ddb-nav--stacked .ddb-nav__parent:focus-visible {
  background: var(--ddb-card-hi);
  color: var(--ddb-primary);
  padding-left: clamp(20px, 3.4vw, 28px);
}
.ddb .ddb-nav--stacked .ddb-nav__parent:hover::after,
.ddb .ddb-nav--stacked .ddb-nav__parent:focus-visible::after { opacity: 1; transform: rotate(-45deg) translate(2px, 2px); }

.ddb .ddb-nav__row--parent.is-open {
  background: var(--ddb-card-hi);
  border-radius: var(--ddb-r-btn);
}
.ddb .ddb-nav--stacked .ddb-nav__row--parent.is-open > .ddb-nav__parent {
  background: transparent;
  color: var(--ddb-primary);
  font-weight: var(--ddb-w-regular);
  padding-left: clamp(14px, 2.4vw, 20px);
}
.ddb .ddb-nav--stacked .ddb-nav__row--parent.is-open > .ddb-nav__parent::after {
  opacity: 1;
  transform: rotate(45deg) translate(-1px, -1px);
}

.ddb .ddb-nav__sub {
  overflow: hidden;
  transition: height var(--ddb-dur) var(--ddb-ease);
}
.ddb .ddb-nav__sub[hidden] { display: none; }
/* The children: one step in, a size down, and plainly rows of the group
   rather than cards of their own. Contact tints the cream a shade deeper
   with the identity colour, since the group is already cream. */
.ddb .ddb-nav--stacked .ddb-nav__sublist {
  display: grid;
  gap: 0;
  padding: 0 clamp(10px, 2vw, 14px) 10px;
}
.ddb .ddb-nav--stacked .ddb-nav__sublist a {
  min-height: 46px;
  padding: 8px clamp(10px, 2vw, 14px) 8px clamp(14px, 3vw, 22px);
  border-radius: 10px;
  font-size: clamp(18px, 4.2vw, 22px);
  font-weight: var(--ddb-w-light);
  color: var(--ddb-ink-deep);
}
.ddb .ddb-nav--stacked .ddb-nav__sublist a::after { width: .3em; height: .3em; }
.ddb .ddb-nav--stacked .ddb-nav__sublist a:hover,
.ddb .ddb-nav--stacked .ddb-nav__sublist a:focus-visible {
  background: rgb(var(--ddb-primary-rgb) / .06);
  color: var(--ddb-primary);
  padding-left: clamp(18px, 3.6vw, 26px);
}
.ddb .ddb-nav--stacked .ddb-nav__sublist a[aria-current="page"] {
  background: rgb(var(--ddb-primary-rgb) / .08);
  color: var(--ddb-primary);
  font-weight: var(--ddb-w-regular);
}
@media (prefers-reduced-motion: reduce) {
  .ddb .ddb-nav__sub,
  .ddb .ddb-nav--stacked .ddb-nav__parent,
  .ddb .ddb-nav--stacked .ddb-nav__parent::after { transition: none; }
}

/* ── 28c · (footer columns now live in section 6) ───────────────────── */

/* ── 28d · Team cards that open, and the profile drawer ─────────────────── */

/* The control is a transparent overlay across the whole card, so the card's
   markup, crop and plate are byte-for-byte what the frame measures. */
.ddb .ddb-team__open {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  cursor: pointer;
}
.ddb .ddb-team__open:focus-visible { outline-offset: -4px; border-radius: inherit; }
.ddb .ddb-team__img {
  transition: transform var(--ddb-dur) var(--ddb-ease),
              filter var(--ddb-dur) var(--ddb-ease);
}
/* The photographic-tile treatment every other clickable image card has: a
   small step toward the reader, a touch brighter, the box itself unchanged. */
.ddb .ddb-team__item:has(.ddb-team__open:hover) .ddb-team__img,
.ddb .ddb-team__item:has(.ddb-team__open:focus-visible) .ddb-team__img {
  transform: scale(1.03);
  filter: brightness(1.04);
}
/* The one visible sign the card opens: the mark in a small disc at the right
   of the plate, in the identity colour at a tenth, filling on contact. */
.ddb .ddb-team__item--link .ddb-team__plate { padding-right: calc((18 / 348) * 100% + 40px); }
.ddb .ddb-team__hint {
  position: absolute;
  right: calc((14 / 348) * 100%);
  top: 50%;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgb(var(--ddb-primary-rgb) / .1);
  color: var(--ddb-primary);
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease),
              color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-team__item:has(.ddb-team__open:hover) .ddb-team__hint,
.ddb .ddb-team__item:has(.ddb-team__open:focus-visible) .ddb-team__hint {
  background: var(--ddb-primary);
  color: var(--ddb-white);
}

/* The drawer: the phone menu's scrim, and a white panel arriving from the
   right edge with the 50 panel radius on the two corners that meet the page. */
.ddb .ddb-drawer {
  position: fixed;
  inset: var(--ddb-admin-bar, 0px) 0 0 0;
  z-index: 80;
}
.ddb .ddb-drawer[hidden] { display: none; }
.ddb .ddb-drawer__scrim {
  position: absolute;
  inset: 0;
  background: rgb(31 51 72 / .45);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity var(--ddb-dur) var(--ddb-ease);
}
.ddb .ddb-drawer.is-open .ddb-drawer__scrim { opacity: 1; }
.ddb .ddb-drawer__panel {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(600px, 100%);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--ddb-white);
  color: var(--ddb-ink);
  border-radius: var(--ddb-r-panel) 0 0 var(--ddb-r-panel);
  box-shadow: -20px 0 60px rgb(0 0 0 / .18);
  transform: translateX(100%);
  transition: transform var(--ddb-dur) var(--ddb-ease);
}
.ddb .ddb-drawer.is-open .ddb-drawer__panel { transform: none; }
.ddb .ddb-drawer__panel:focus { outline: none; }
.ddb .ddb-drawer__close {
  position: absolute;
  top: 22px;
  right: 22px;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--ddb-sand);
  color: var(--ddb-ink-deep);
  transition: background-color var(--ddb-dur-fast) var(--ddb-ease),
              color var(--ddb-dur-fast) var(--ddb-ease);
}
.ddb .ddb-drawer__close:hover,
.ddb .ddb-drawer__close:focus-visible { background: var(--ddb-primary); color: var(--ddb-white); }
.ddb .ddb-drawer__close .ddb-close { width: 16px; height: 16px; }
.ddb .ddb-drawer__close .ddb-close::before,
.ddb .ddb-drawer__close .ddb-close::after { height: 2px; }
.ddb .ddb-drawer__scroll {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: clamp(28px, 4vw, 52px) clamp(24px, 4vw, 52px) clamp(32px, 4vw, 52px);
}
.ddb .ddb-drawer__member[hidden] { display: none; }
.ddb .ddb-drawer__photo {
  aspect-ratio: 16 / 11;
  margin-bottom: 26px;
  border-radius: var(--ddb-r-card);
  overflow: hidden;
  background: var(--ddb-ground-alt);
}
.ddb .ddb-drawer__img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 18%; }
.ddb .ddb-drawer__role { margin-bottom: 8px; }
.ddb .ddb-team .ddb-drawer__name {
  font-size: clamp(28px, 2.315vw, 36px);
  font-weight: var(--ddb-w-medium);
  line-height: 1.1;
}
.ddb .ddb-drawer__meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px 24px;
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--ddb-line);
}
.ddb .ddb-drawer__meta dt { font-size: 13px; letter-spacing: var(--ddb-track-ui); color: var(--ddb-muted); }
.ddb .ddb-drawer__meta dd { margin: 2px 0 0; font-size: var(--ddb-t-meta); color: var(--ddb-ink-deep); }
.ddb .ddb-drawer__bio { margin-top: 22px; font-weight: var(--ddb-w-light); }
.ddb .ddb-drawer__bio p + p { margin-top: .85em; }
.ddb .ddb-drawer__actions { margin-top: 28px; }
.ddb .ddb-drawer__actions .ddb-btn { width: 100%; }

body.ddb-drawer-open { overflow: hidden; }
html:has(body.ddb-drawer-open) { padding-right: var(--ddb-scrollbar, 0px); }

@media (max-width: 640px) {
  .ddb .ddb-drawer__panel { width: 100%; border-radius: 0; }
  .ddb .ddb-drawer__close { top: 14px; right: 14px; }
  .ddb .ddb-drawer__photo { aspect-ratio: 4 / 3; }
}
@media (prefers-reduced-motion: reduce) {
  .ddb .ddb-drawer__scrim,
  .ddb .ddb-drawer__panel,
  .ddb .ddb-team__img,
  .ddb .ddb-team__hint,
  .ddb .ddb-drawer__close { transition: none; }
}

/* ── 28e · Price table on a phone ───────────────────────────────────────── */
/* The name column's 79.4% is the frame's proportion of a 1010px table; kept
   on a 350px table it leaves the price 70px and "From £2,500" breaks across
   two lines. Below the width where the tables stack above the booking card
   the name column gives the price the room a whole figure needs, and the
   figure itself never wraps. */
@media (max-width: 600px) {
  .ddb .ddb-ptable :where(.ddb-ptable__name, .ddb-ptable__col):first-child { width: 58%; }
  .ddb .ddb-ptable__price,
  .ddb .ddb-ptable__col--price { white-space: nowrap; padding-right: 16px; }
  .ddb .ddb-ptable__name,
  .ddb .ddb-ptable__col { padding-left: 20px; }
  .ddb .ddb-ptable__col--price { padding-left: 0; }
  .ddb .ddb-ptable :where(.ddb-ptable__name, .ddb-ptable__price) { font-size: 19px; }
}
