/**
 * Dream Tails Promotion Manager — front-end.
 *
 * Built on the theme's own tokens. Unlike a flat two-colour brand, the Dream
 * Tails palette is a range of low-saturation tints — sage, peach, blush and
 * butter over cream, anchored by deep teal and navy — so every surface below
 * carries its own measured text colour and scrim floor rather than inheriting
 * one pair. Feature tokens are declared on the placement roots, never :root,
 * which is the convention every other Dream Tails feature follows
 * (.dt-fb in financing-banner.css, .dt-page in pages.css, --pg- in
 * pet-gallery.css).
 *
 * Layering, against the ladder already in the theme:
 *   1090  .dt-pin-modal            (deposit PIN)
 *   1080  #warranty
 *   1070  .modal-backdrop
 *   1045  .dream-tails-offcanvas   (mobile menu)
 *   1040  .dt-floating-cta         (booking pill — bottom RIGHT, every page)
 *   1035  .dt-promo-badge          <- here, deliberately
 *   1030  .dt-sticky-cta           (mobile pet CTA bar)
 *   1001  .dt-promo-bar--sticky-above
 *   1000  .pet-mobile-sticky-bar
 *    999  .dt-promo-bar--sticky-below
 *
 * The badge sits above the utility chrome it may share a corner with, and below
 * the booking pill: a promotion must never cover the site's own conversion
 * path. Note the header is NOT sticky in this theme, so a sticky bar needs no
 * header-height offset — it simply sticks to the top of the viewport itself.
 *
 * Everything from a closed enum is a class. Only continuous or per-asset values
 * arrive as inline custom properties, all clamped server-side in
 * DT_Promo_Render::style_attr().
 */

/* =========================================================================
   Tokens

   Declared on the placement roots, not :root — the convention every other
   Dream Tails feature follows (.dt-fb in financing-banner.css, .dt-page in
   pages.css, --pg- in pet-gallery.css). Two namespaces, deliberately:

     --dtpr-*  brand layer. Hard-coded here. Restyle here.
     --dtpx-*   runtime layer, written as an inline style attribute by
               DT_Promo_Render::style_attr(). Never rename one of these.

   Chrome measurements (--dt-header-h, --dt-promo-bar-h, --dt-promo-badge-h,
   --dt-floating-cta-h, --dt-sticky-cta-h, --dt-adminbar-h) are deliberately
   NOT declared here: promo.js writes them on :root, and a declaration in this
   scoped block would shadow the measured value. They appear only as var()
   fallbacks at their use sites, seeded by wp_add_inline_style().
   ========================================================================= */

.dt-promo-hero,
.dt-promo-bar,
.dt-promo-badge,
.dt-promo-popup,
.dt-promo-countdown {

	/* ---- brand ---- */
	--dtpr-teal:        #3D5155;
	--dtpr-teal-deep:   #2a3a3d;
	--dtpr-teal-light:  #4a6367;
	--dtpr-blush:       #d9b2af;
	--dtpr-blush-soft:  #eabfbd;
	--dtpr-blush-deep:  #efc4c1;
	--dtpr-peach:       #EECCAA;
	--dtpr-peach-soft:  #f4d4b1;
	--dtpr-butter:      #F1E6B2;
	--dtpr-sage:        #BCC9C5;
	--dtpr-navy:        #2E334E;
	--dtpr-maroon:      #503B3D;
	--dtpr-ivory:       #FAFAFA;
	--dtpr-cream:       #fffaf5;
	--dtpr-cream-soft:  #fef6ed;
	--dtpr-cream-deep:  #fef0e2;
	--dtpr-ink:         #2a3a3d;
	--dtpr-ink-soft:    #6a7a7e;
	--dtpr-line:        rgba(61, 81, 85, .12);
	--dtpr-line-soft:   rgba(61, 81, 85, .06);

	/* Glass, for anything sitting on a photograph. Mirrors the chips on
	   .dt-hero so a promotion standing in for it is indistinguishable. */
	--dtpr-glass:       rgba(255, 255, 255, .16);
	--dtpr-glass-hover: rgba(255, 255, 255, .28);
	--dtpr-glass-line:  rgba(255, 255, 255, .28);
	--dtpr-white-line:  rgba(255, 255, 255, .55);

	/* ---- shape: pills at 999px, cards at 12/14/18/24 ---- */
	--dtpr-r-pill:  999px;
	--dtpr-r-chip:  14px;
	--dtpr-r-md:    18px;
	--dtpr-r-badge: 18px;
	--dtpr-r-block: 24px;

	/* ---- depth: teal- or blush-tinted, never neutral black ---- */
	--dtpr-shadow-sm:    0 6px 20px -10px rgba(61, 81, 85, .15);
	--dtpr-shadow-md:    0 12px 30px -16px rgba(61, 81, 85, .25);
	--dtpr-shadow-lg:    0 24px 60px -20px rgba(61, 81, 85, .25);
	--dtpr-shadow-blush: 0 8px 24px rgba(217, 178, 175, .35);
	/* The badge floats over warm cream, which is most of this site, and a
	   spread-only shadow lets it dissolve into it. Hairline plus a tight
	   contact shadow instead. */
	--dtpr-shadow-badge:       0 1px 2px rgba(61, 81, 85, .10),
	                           0 14px 34px -10px rgba(61, 81, 85, .30),
	                           inset 0 0 0 1px rgba(61, 81, 85, .07);
	--dtpr-shadow-badge-hover: 0 2px 4px rgba(61, 81, 85, .12),
	                           0 20px 42px -12px rgba(61, 81, 85, .36),
	                           inset 0 0 0 1px rgba(61, 81, 85, .10);

	/* ---- motion ---- */
	--dtpr-ease:   cubic-bezier(.4, 0, .2, 1);
	--dtpr-t-fast: 220ms;
	--dtpr-t-slow: 350ms;

	/* ---- type ---- */
	--dtpr-font-display: 'Mollie Glaston', 'Playfair Display', serif;
	--dtpr-font-serif:   'Playfair Display', Georgia, serif;
	--dtpr-font-ui:      'Lato', sans-serif;

	/* --h-lg is .dt-page__hero-title verbatim; --h-xl is .dt-hero__title
	   verbatim, so a promotion replacing the homepage hero lands on exactly
	   the same size. Both small ends sit above the sizes this system shipped
	   with: Mollie Glaston is a script face and reads smaller at equal px. */
	--dtpr-h-sm: clamp(1.9rem, 3.4vw, 2.6rem);
	--dtpr-h-md: clamp(2.1rem, 4.4vw, 3.3rem);
	--dtpr-h-lg: clamp(2.4rem, 5.5vw, 3.8rem);
	--dtpr-h-xl: clamp(2.75rem, 6vw, 5rem);

	/* One opacity for quiet supporting labels. .9 is the highest value at
	   which all six surfaces still clear 4.5:1 against their own ground. */
	--dtpr-quiet: .9;
}

/* =========================================================================
   Shared
   ========================================================================= */


/* Applied before first paint by the wp_head dismiss guard, so a returning
   visitor never sees a flash of something they closed. */
html.dt-promo-bar-off .dt-promo-bar,
html.dt-promo-badge-off .dt-promo-badge,
html.dt-promo-popup-off .dt-promo-popup { display: none !important; }

/* Minimised earlier this visit: the bubble stays, the dialog does not. */
html.dt-promo-popup-min .dt-promo-popup__dialog { display: none !important; }

/* Scroll lock while the dialog is open. scrollbar-gutter keeps the page from
   jumping sideways as the scrollbar disappears. */
html.dt-promo-popup-open { overflow: hidden; scrollbar-gutter: stable; }

/* The theme's focus convention is a 2px teal ring at 2px offset. That is what
   these use on every light surface. Over a photograph or on the two dark
   surfaces teal cannot be seen, so those invert to white with a teal halo —
   one of the two always clears 3:1 against anything underneath. */
.dt-promo-cta:focus-visible,
.dt-promo-bar__cta:focus-visible,
.dt-promo-bar__close:focus-visible,
.dt-promo-badge__link:focus-visible,
.dt-promo-badge__close:focus-visible {
	outline: 2px solid var(--dtpr-teal);
	outline-offset: 2px;
	box-shadow: none;
}
.dt-promo-hero--pal-teal .dt-promo-cta:focus-visible,
.dt-promo-hero--pal-navy .dt-promo-cta:focus-visible,
.dt-promo-bar--image .dt-promo-bar__cta:focus-visible,
.dt-promo-bar--image .dt-promo-bar__close:focus-visible,
/* The bar is a dark surface at every colour setting now, so the white ring is
   unconditional here. A teal ring on teal is an invisible focus indicator. */
.dt-promo-bar .dt-promo-bar__cta:focus-visible,
.dt-promo-bar .dt-promo-bar__close:focus-visible,
/* The badge is a dark surface at every colour setting now, so the white ring
   is unconditional — a teal ring on teal cannot be seen. */
.dt-promo-badge .dt-promo-badge__link:focus-visible,
.dt-promo-badge .dt-promo-badge__close:focus-visible {
	outline: 3px solid #fff;
	outline-offset: 3px;
	box-shadow: 0 0 0 6px rgb(61 81 85 / .55);
}

/* Teal on blush measures 4.36:1 — below AA for normal text, fine at the WCAG
   large-text threshold. 1.18rem at 700 is 18.88px bold, which clears it. */
.dt-promo-cta--primary {
	font-size: 1.18rem;
	font-weight: 700;
	padding: 1.05em 2rem;
}
.dt-promo-cta--secondary { font-weight: 600; }

/* =========================================================================
   Utilities the promo markup carries its own copies of

   The eyebrow pill, the buttons and the trust chips were theme utilities where
   this system came from. Rather than add a site-wide utility layer this theme
   has never had, promotions ship their own — rebuilt on the Dream Tails
   components they should look like:

     .dt-promo-eyebrow      -> .dt-page__hero-eyebrow, and the glass chip on
                               .dt-hero when it sits over a photograph
     .dt-promo-btn          -> the blush / teal / peach gradient button family
     .dt-promo-trust__item  -> .dt-trust-pill
   ========================================================================= */

/* ---- the eyebrow pill ---- */
.dt-promo-eyebrow {
	display: inline-flex;
	align-items: center;
	gap: .45rem;
	padding: .4rem 1.05rem;
	border-radius: var(--dtpr-r-pill);
	background: linear-gradient(135deg, var(--dtpr-blush-soft) 0%, var(--dtpr-peach) 100%);
	border: 1px solid var(--dtpr-white-line);
	color: var(--dtpr-teal-deep);
	font-family: var(--dtpr-font-ui);
	font-size: .72rem;
	font-weight: 700;
	letter-spacing: .14em;
	text-transform: uppercase;
	line-height: 1.2;
	box-shadow: 0 8px 20px -10px rgba(217, 178, 175, .55);
}
.dt-promo-eyebrow i { font-size: .82rem; color: var(--dtpr-blush); }

/* Over a photograph the gradient pill fights the picture, so it becomes the
   glass chip the site's own photo hero uses. That is what makes a promotion
   standing in for .dt-hero indistinguishable from it. */
.dt-promo-hero--photo.dt-promo-hero--pal-teal .dt-promo-eyebrow,
.dt-promo-hero--photo.dt-promo-hero--pal-navy .dt-promo-eyebrow {
	background: var(--dtpr-glass);
	backdrop-filter: blur(8px);
	-webkit-backdrop-filter: blur(8px);
	border-color: rgba(255, 255, 255, .22);
	color: #fff;
	letter-spacing: .16em;
	box-shadow: none;
}
.dt-promo-hero--photo.dt-promo-hero--pal-teal .dt-promo-eyebrow i,
.dt-promo-hero--photo.dt-promo-hero--pal-navy .dt-promo-eyebrow i { color: var(--dtpr-peach); }

/* ---- buttons ---- */
.dt-promo-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: .55rem;
	padding: .95rem 1.6rem;
	border: 1px solid transparent;
	border-radius: var(--dtpr-r-pill);
	font-family: var(--dtpr-font-ui);
	font-weight: 700;
	font-size: .95rem;
	line-height: 1.15;
	letter-spacing: .02em;
	text-decoration: none;
	white-space: nowrap;
	cursor: pointer;
	transition: transform var(--dtpr-t-fast) var(--dtpr-ease),
	            box-shadow var(--dtpr-t-fast) var(--dtpr-ease),
	            background var(--dtpr-t-fast) var(--dtpr-ease),
	            color var(--dtpr-t-fast) var(--dtpr-ease);
}
.dt-promo-btn--lg { font-size: 1.08rem; padding: 1.12rem 2.1rem; }
.dt-promo-btn:hover,
.dt-promo-btn:focus-visible { transform: translateY(-2px); text-decoration: none; }

/* Primary — the blush gradient. */
.dt-promo-cta--primary {
	background: linear-gradient(135deg, var(--dtpr-blush) 0%, var(--dtpr-blush-deep) 100%);
	color: var(--dtpr-teal);
	box-shadow: var(--dtpr-shadow-blush);
}
.dt-promo-cta--primary:hover,
.dt-promo-cta--primary:focus-visible {
	background: linear-gradient(135deg, #d8aaa8 0%, #e9bdba 100%);
	color: var(--dtpr-teal);
	box-shadow: 0 14px 30px rgba(217, 178, 175, .5);
}
/* A blush button on a blush ground disappears, and on the two dark surfaces it
   is the wrong weight — so the primary is palette-aware. */
.dt-promo-hero--pal-blush .dt-promo-cta--primary {
	background: linear-gradient(135deg, var(--dtpr-teal) 0%, var(--dtpr-teal-light) 100%);
	color: #fff;
	box-shadow: 0 8px 24px rgba(61, 81, 85, .28);
}
.dt-promo-hero--pal-teal .dt-promo-cta--primary,
.dt-promo-hero--pal-navy .dt-promo-cta--primary {
	background: linear-gradient(135deg, var(--dtpr-peach) 0%, var(--dtpr-peach-soft) 100%);
	color: var(--dtpr-teal-deep);
	box-shadow: 0 8px 24px rgba(238, 204, 170, .32);
}

/* Secondary — a soft white pill on light ground … */
.dt-promo-btn--ghost,
.dt-promo-cta--secondary {
	background: rgba(255, 255, 255, .9);
	border-color: var(--dtpr-line);
	color: var(--dtpr-teal);
	box-shadow: var(--dtpr-shadow-sm);
	font-weight: 700;
}
.dt-promo-btn--ghost:hover,
.dt-promo-cta--secondary:hover,
.dt-promo-cta--secondary:focus-visible {
	background: #fff;
	color: var(--dtpr-teal);
	box-shadow: var(--dtpr-shadow-md);
}
/* … and glass on anything dark or photographic. */
.dt-promo-hero--pal-teal .dt-promo-cta--secondary,
.dt-promo-hero--pal-navy .dt-promo-cta--secondary {
	background: var(--dtpr-glass);
	backdrop-filter: blur(10px);
	-webkit-backdrop-filter: blur(10px);
	border-color: var(--dtpr-glass-line);
	color: #fff;
	box-shadow: 0 4px 18px rgba(61, 81, 85, .12);
}
.dt-promo-hero--pal-teal .dt-promo-cta--secondary:hover,
.dt-promo-hero--pal-navy .dt-promo-cta--secondary:hover {
	background: var(--dtpr-glass-hover);
	color: #fff;
}

/* ---- trust chips ---- */
.dt-promo-trust__item {
	display: inline-flex;
	align-items: center;
	gap: .45rem;
	padding: .45rem 1rem;
	background: rgba(255, 255, 255, .9);
	border: 1px solid var(--dtpr-line);
	border-radius: var(--dtpr-r-pill);
	color: var(--dtpr-teal-deep);
	font-family: var(--dtpr-font-ui);
	font-size: .8rem;
	font-weight: 700;
	letter-spacing: .04em;
	box-shadow: var(--dtpr-shadow-sm);
}
.dt-promo-trust__item i { color: var(--dtpr-blush); font-size: .9rem; }

.dt-promo-hero--pal-teal .dt-promo-trust__item,
.dt-promo-hero--pal-navy .dt-promo-trust__item {
	background: var(--dtpr-glass);
	backdrop-filter: blur(10px);
	-webkit-backdrop-filter: blur(10px);
	border-color: var(--dtpr-glass-line);
	color: #fff;
	box-shadow: 0 4px 18px rgba(61, 81, 85, .12);
}
.dt-promo-hero--pal-teal .dt-promo-trust__item i,
.dt-promo-hero--pal-navy .dt-promo-trust__item i { color: var(--dtpr-peach); }

/* =========================================================================
   "Photo behind the text" is a PHONE composition — so is its palette

   --m-overlay rides on the hero root at every width, but the layout it names
   only happens under 991.98px; above that the photograph is still framed
   beside the words and the panel is still cream. These rules used to sit
   unconditionally beside the --photo ones, which put glass chips and white
   text on a cream panel on every desktop: the eyebrow, the second button,
   the focus ring and all three trust chips were invisible.

   They belong to the breakpoint, not to the modifier. Anything added here
   later must go inside the query for the same reason.

   767.98px, matching the layout block that actually promotes the photo to
   the background. It was 991.98px first, which re-created the very bug this
   block exists to fix in the 768–991px band: photo-over colours while the
   photo was still framed beside the words.
   ========================================================================= */

@media (max-width: 767.98px) {
	.dt-promo-hero--m-overlay .dt-promo-cta:focus-visible {
		outline: 3px solid #fff;
		outline-offset: 3px;
		box-shadow: 0 0 0 6px rgb(61 81 85 / .55);
	}

	/*
	 * The same reasoning as the chips above: opaque, because the picture
	 * underneath is unknown. A glass pill measured 1.06:1 over a pale photo.
	 * The gradient is the theme's own eyebrow, so this reads as the signature
	 * pill rather than as a fallback.
	 */
	.dt-promo-hero--m-overlay .dt-promo-eyebrow {
		background: linear-gradient(135deg, var(--dtpr-blush-soft) 0%, var(--dtpr-peach) 100%);
		border-color: rgba(255, 255, 255, .55);
		color: var(--dtpr-ink);
		letter-spacing: .16em;
		box-shadow: 0 8px 20px -10px rgba(61, 81, 85, .45);
	}
	.dt-promo-hero--m-overlay .dt-promo-eyebrow i { color: var(--dtpr-teal); }

	/*
	 * Glass is for chrome sitting over a DARK photograph. These two sit over
	 * whatever picture the marketer uploaded, and over a pale one — a cream
	 * puppy on a white blanket, which is most of this boutique's library —
	 * white-on-translucent-white cannot be read at any scrim strength. Worse,
	 * the glass veil RAISES the local background luminance, so turning the
	 * scrim up makes the headline darker and the chips no better.
	 *
	 * So both carry opaque grounds here. An opaque chip's contrast is a fixed
	 * number rather than a function of the photo behind it, which is the only
	 * way to promise legibility over a picture nobody has seen yet.
	 */
	.dt-promo-hero--m-overlay .dt-promo-trust__item {
		/* 11.4:1, and it holds over black and white alike. */
		background: rgba(255, 255, 255, .94);
		backdrop-filter: blur(10px);
		-webkit-backdrop-filter: blur(10px);
		border-color: var(--dtpr-white-line);
		color: var(--dtpr-teal-deep);
		box-shadow: 0 4px 18px rgba(61, 81, 85, .22);
	}
	.dt-promo-hero--m-overlay .dt-promo-trust__item i { color: var(--dtpr-blush); }
}

/* =========================================================================
   Hero
   ========================================================================= */

.dt-promo-hero {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	background: var(--dtpx-bg, var(--dtpr-ivory));
	color: var(--dtpx-fg, var(--dtpr-ink));
}

/* ---- palettes: measured pairs only ---- */
/*
 * The six surfaces. --dtpx-quiet is the ink small supporting text uses; it
 * differs from --dtpx-fg only on blush, where the heading pairing is the brand's
 * teal-on-blush accent (4.36:1, large text only) and anything smaller has to
 * fall back to navy.
 */
.dt-promo-hero--pal-ivory { --dtpx-bg: var(--dtpr-ivory); --dtpx-fg: var(--dtpr-ink);  --dtpx-head: var(--dtpr-teal);  --dtpx-quiet: var(--dtpr-teal); --dtpx-scrim-rgb: 250 250 250; }
.dt-promo-hero--pal-sage  { --dtpx-bg: var(--dtpr-sage);  --dtpx-fg: var(--dtpr-navy); --dtpx-head: var(--dtpr-navy);  --dtpx-quiet: var(--dtpr-navy); --dtpx-scrim-rgb: 188 201 197; }
.dt-promo-hero--pal-peach { --dtpx-bg: var(--dtpr-peach); --dtpx-fg: var(--dtpr-ink);  --dtpx-head: var(--dtpr-teal);  --dtpx-quiet: var(--dtpr-teal); --dtpx-scrim-rgb: 238 204 170; }
.dt-promo-hero--pal-blush { --dtpx-bg: var(--dtpr-blush); --dtpx-fg: var(--dtpr-ink);  --dtpx-head: var(--dtpr-teal);  --dtpx-quiet: var(--dtpr-navy); --dtpx-scrim-rgb: 217 178 175; }
.dt-promo-hero--pal-teal  { --dtpx-bg: var(--dtpr-teal);  --dtpx-fg: #fff;             --dtpx-head: #fff;             --dtpx-quiet: #fff;             --dtpx-scrim-rgb: 61 81 85; }
.dt-promo-hero--pal-navy  { --dtpx-bg: var(--dtpr-navy);  --dtpx-fg: #fff;             --dtpx-head: #fff;             --dtpx-quiet: #fff;             --dtpx-scrim-rgb: 46 51 78; }

/*
 * Over a photograph the small supporting ink gets its own value.
 *
 * --dtpx-quiet is chosen per surface against that surface's own flat colour,
 * which is right everywhere the ground IS that colour. In the photo layout the
 * ground is the picture behind a scrim, and a mid-weight teal on a dark
 * photograph measured 2.82:1. The scrim guarantees the HEADLINE, not this.
 * White here is legible against anything the scrim allows through.
 */
.dt-promo-hero--photo .dt-promo-countdown__label,
.dt-promo-hero--photo .dt-promo-countdown__unitlabel {
	color: #fff;
	text-shadow: 0 1px 3px rgb(0 0 0 / .45);
}

/*
 * Ivory is the one surface that would read as un-designed as a flat panel, so
 * off a photograph it takes the ambient cream wash and two soft blush/peach
 * blobs the theme uses on its own sections. isolation:isolate on the root plus
 * z-index on the panel already keep the words above these.
 */
.dt-promo-hero--pal-ivory:not(.dt-promo-hero--photo) {
	background: linear-gradient(145deg, #fffaf5 0%, #fef6ed 50%, #fef0e2 100%);
}
.dt-promo-hero--pal-ivory:not(.dt-promo-hero--photo)::before,
.dt-promo-hero--pal-ivory:not(.dt-promo-hero--photo)::after {
	content: ''; position: absolute; pointer-events: none; z-index: 0;
}
.dt-promo-hero--pal-ivory:not(.dt-promo-hero--photo)::before {
	top: -10%; left: -8%; inline-size: 45%; block-size: 70%;
	background: radial-gradient(circle, rgba(234, 191, 189, .35), transparent 65%);
}
.dt-promo-hero--pal-ivory:not(.dt-promo-hero--photo)::after {
	bottom: -10%; right: -10%; inline-size: 50%; block-size: 70%;
	background: radial-gradient(circle, rgba(238, 204, 170, .32), transparent 65%);
}

/* ---- spacing and type presets ---- */
.dt-promo-hero--space-tight { --dtpx-pad: clamp(2.25rem, 5vw, 3.5rem); --dtpx-gap: clamp(1rem, 2.5vw, 2rem); }
.dt-promo-hero--space-cozy  { --dtpx-pad: clamp(3rem, 7vw, 5rem);      --dtpx-gap: clamp(1.5rem, 4vw, 3rem); }
.dt-promo-hero--space-roomy { --dtpx-pad: clamp(4rem, 9vw, 7rem);      --dtpx-gap: clamp(2rem, 5vw, 4rem); }

.dt-promo-hero--h-sm { --dtpx-h1: clamp(1.7rem, 3.2vw, 2.6rem); }
.dt-promo-hero--h-md { --dtpx-h1: clamp(1.9rem, 4.2vw, 3.4rem); }
.dt-promo-hero--h-lg { --dtpx-h1: clamp(2.2rem, 5vw, 4.2rem); }
.dt-promo-hero--h-xl { --dtpx-h1: var(--dtpr-h-xl); }

.dt-promo-hero--txt-center { --dtpx-align: center; --dtpx-measure-mi: auto; }
/* margin-inline takes start then end, so "auto 0" pushes the block right. */
.dt-promo-hero--txt-end    { --dtpx-align: end;    --dtpx-measure-mi: auto 0; }
.dt-promo-hero--align-start  { --dtpx-valign: start; }
.dt-promo-hero--align-center { --dtpx-valign: center; }
.dt-promo-hero--align-end    { --dtpx-valign: end; }

/* ---- the text panel ---- */
.dt-promo-hero__panel { grid-area: panel; position: relative; z-index: 2; }

/* The width limit is on the PROSE, not the panel.
   A max-inline-size on a wrapper constrains everything inside it, so putting the
   measure on the panel would squeeze the button row and the trust chips into a
   34ch column too. The theme's own hero makes the same distinction: it caps
   .dt-hero__lede at 32ch and leaves .dt-hero__cta alone. */
.dt-promo-hero__panel {
	text-align: var(--dtpx-align, start);
	margin-inline: var(--dtpx-measure-mi, 0);
	max-inline-size: min(52ch, 100%);
}

.dt-promo-hero__eyebrow { margin-bottom: .25rem; }

.dt-promo-hero__title {
	font-family: var(--dtpr-font-display);
	font-size: var(--dtpx-h1, var(--dtpr-h-lg));
	font-weight: 400;              /* Mollie Glaston ships one weight */
	line-height: 1.04;             /* == .dt-hero__title */
	letter-spacing: -.005em;       /* == .dt-hero__title / .dt-page__hero-title */
	color: var(--dtpx-head, var(--dtpr-teal-deep));
	margin: 1rem 0 1.1rem;
	text-wrap: balance;
	max-inline-size: var(--dtpx-measure, 34ch);
	margin-inline: var(--dtpx-measure-mi, 0);
}

.dt-promo-hero__lede {
	font-family: var(--dtpr-font-serif);
	font-style: italic;            /* the theme's editorial lede voice */
	font-size: clamp(1.05rem, 1.5vw, 1.25rem);
	line-height: 1.55;
	color: var(--dtpx-fg, var(--dtpr-ink-soft));
	margin: 0;
	text-wrap: pretty;
	max-inline-size: var(--dtpx-measure, 34ch);
	margin-inline: var(--dtpx-measure-mi, 0);
}

.dt-promo-hero__cta {
	display: flex;
	flex-wrap: wrap;
	gap: .9rem;
	margin-top: 1.8rem;
	justify-content: var(--dtpx-align, start);
}

/* The trust chips deliberately break out of the text measure. Constrained to
   34ch they stack one per line, which turns three short reassurances into a
   column of pills taller than the headline. They are a row, not prose. */
.dt-promo-hero__trust {
	display: flex;
	flex-wrap: wrap;
	gap: .45rem;
	margin: 1.5rem 0 0;
	padding: 0;
	list-style: none;
	justify-content: var(--dtpx-align, start);
}
.dt-promo-hero__trust .dt-promo-trust__item {
	font-size: .82rem;
	padding: .4em .85em;
	gap: .4em;
}


/* ---- media ---- */
.dt-promo-hero__media { grid-area: media; position: relative; }
.dt-promo-hero__pic   { display: block; block-size: 100%; }

.dt-promo-hero__img {
	inline-size: 100%;
	block-size: 100%;
	display: block;
	object-fit: var(--dtpx-fit, cover);
	/* The focal point. With object-fit:cover and object-position p%, the source
	   point at p% renders at exactly p% of the box — which is what makes the
	   admin's "is the subject under the headline?" check provable. */
	object-position: var(--dtpx-focal, 50% 50%);
}
@media (max-width: 767.98px) {
	.dt-promo-hero__img { object-position: var(--dtpx-focal-sm, var(--dtpx-focal, 50% 50%)); }
}

.dt-promo-hero__figure {
	aspect-ratio: var(--dtpx-ratio, 4/3);
	/* Overridden for split and panel below — see the note there. */
	/* Same ceiling, same reason: the framed photo in the split and panel
	   layouts is half the width, so a tall shape still runs past the fold. */
	max-block-size: min(72vh, 620px);
	overflow: hidden;
	border-radius: var(--dtpr-r-block);
	/* The white hairline is what makes a framed photo read as Dream Tails
	   rather than as a stock block — the theme's own .dt-page__hero-image
	   carries the same one. */
	border: 1.5px solid var(--dtpr-white-line);
	box-shadow: var(--dtpr-shadow-lg);
	margin: 0;
}
@media (max-width: 767.98px) {
	.dt-promo-hero__figure { aspect-ratio: var(--dtpx-ratio-sm, var(--dtpx-ratio, 4/3)); }
}

/* ---- layout 1: photo overlay ---- */
.dt-promo-hero--photo .dt-promo-hero__stack {
	display: grid;
	grid-template-areas: "stack";
	/* minmax(0, 1fr), not the implicit auto column: the media below carries an
	   aspect-ratio AND a min-block-size, so an auto column would size itself
	   from the image's max-content width (640px tall at 16/9 = 1138px wide) and
	   overflow every viewport narrower than that. */
	grid-template-columns: minmax(0, 1fr);
	align-items: var(--dtpx-valign, center);
}
.dt-promo-hero--photo .dt-promo-hero__media,
.dt-promo-hero--photo .dt-promo-hero__inner { grid-area: stack; min-inline-size: 0; }

.dt-promo-hero--photo .dt-promo-hero__media {
	/* The media box does the sizing: width first, then height from the ratio.
	   min-block-size is a FLOOR on the height only — long copy or 200% text
	   grows the row instead of clipping, and it never feeds back into width.

	   position: static is deliberate here, and only in this layout. It hands
	   the containing block for the picture and the scrim below to the hero
	   ROOT, so the photograph fills the whole section — including the padding
	   the copy sits in. Left relative, the box caps itself against a tall
	   ratio while the copy's own padding grows the row past it, and the hero
	   paints bands of flat palette above and below the photo. The theme's own
	   .dt-hero is full-bleed; a promotion standing in for it has to be too.
	   The hero root already carries overflow:hidden, so nothing escapes. */
	position: static;
	inline-size: 100%;
	min-block-size: min(72vh, 640px);
	/* A CEILING as well as a floor.
	   aspect-ratio alone let the chosen Desktop shape set the height with
	   nothing to stop it: a 1/1 shape on a 1568px-wide screen produced a
	   1568px-tall band, twice the viewport, with the page's own content pushed
	   entirely below the fold. Capping the box crops the photograph top and
	   bottom instead — object-fit:cover and the focal point decide what
	   survives — so every shape stays usable on a wide screen. Phones keep
	   their own 62vh cap further down and are untouched. */
	max-block-size: min(80vh, 720px);
	aspect-ratio: var(--dtpx-ratio, 16/9);
}
/* The photograph and its scrim FILL THE HERO absolutely (see the note above
   about the media box being static in this layout).
   They cannot be grid items with height:100%: a percentage height inside an
   auto-sized grid row is indefinite, so the picture falls back to the image's
   own intrinsic ratio, overflows the box, and drags the scrim with it — which
   painted the whole hero flat teal. Only the backdrop is positioned this way;
   the text stays in normal flow so it can never be clipped. */
.dt-promo-hero--photo .dt-promo-hero__pic,
.dt-promo-hero--photo .dt-promo-hero__scrim {
	position: absolute;
	inset: 0;
	inline-size: 100%;
	block-size: 100%;
}

.dt-promo-hero--photo .dt-promo-hero__inner {
	position: relative;
	z-index: 2;
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	padding-block: var(--dtpx-pad);
}
.dt-promo-hero--photo.dt-promo-hero--side-left  .dt-promo-hero__panel { grid-column: 1; }
.dt-promo-hero--photo.dt-promo-hero--side-right .dt-promo-hero__panel { grid-column: 2; }

/* ---- layout 2: editorial split ---- */
.dt-promo-hero--split .dt-promo-hero__inner,
.dt-promo-hero--panel .dt-promo-hero__inner {
	/*
	 * Positioned, and above the ambient blooms the hero paints on its own
	 * ::before/::after. Those are absolutely positioned at z-index 0, and a
	 * positioned element beats a static one at the same level — so left
	 * static, this row's photograph renders UNDER the wash and disappears.
	 */
	position: relative;
	z-index: 1;
	display: grid;
	gap: var(--dtpx-gap);
	padding-block: var(--dtpx-pad);
	align-items: var(--dtpx-valign, center);
	grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
	grid-template-areas: "panel media";
}
/* Reversal is expressed ONLY in the named areas, the scrim direction and the
   text alignment — never as a transform, a row-reverse or direction:rtl. The
   photograph is therefore never mirrored. */
.dt-promo-hero--split.dt-promo-hero--side-right .dt-promo-hero__inner,
.dt-promo-hero--panel.dt-promo-hero--side-right .dt-promo-hero__inner {
	grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr);
	grid-template-areas: "media panel";
}

/* ---- layout 3: brand panel ---- */
.dt-promo-hero--panel .dt-promo-hero__inner {
	grid-template-columns: minmax(0, 1fr) minmax(0, .8fr);
}
.dt-promo-hero--panel.dt-promo-hero--side-right .dt-promo-hero__inner {
	grid-template-columns: minmax(0, .8fr) minmax(0, 1fr);
}
.dt-promo-hero--panel .dt-promo-hero__figure {
	max-inline-size: min(520px, 100%);
	margin-inline: auto;
}

/* These two layouts carry a scrim element only so the phone overlay can use
   it. On every other screen the photograph is framed beside the words and has
   nothing over it — without this the shared --scrim-linear rule would start
   painting a gradient across their picture. */
.dt-promo-hero--split .dt-promo-hero__scrim,
.dt-promo-hero--panel .dt-promo-hero__scrim { display: none; }
.dt-promo-hero--cutout .dt-promo-hero__figure {
	aspect-ratio: auto;
	overflow: visible;
	border-radius: 0;
	box-shadow: none;
	/* drop-shadow follows the alpha edge; box-shadow would draw a rectangle
	   around a transparent cut-out. */
	filter: drop-shadow(0 14px 32px rgb(61 81 85 / .18));
}
.dt-promo-hero--cutout .dt-promo-hero__img { block-size: auto; object-fit: contain; }

/* =========================================================================
   The editorial panel

   The split and panel layouts follow the boutique's own concierge popup: a
   hairline rule and a small caps label instead of a filled pill, a confident
   serif headline carrying one accent word in italic blush, a quiet sans lede,
   and a squared block button rather than a rounded one.

   The PHOTO layout deliberately does not follow it. That layout stands in for
   .dt-hero on the homepage, and the swap only stays invisible if it keeps the
   site's own display face and glass chips. This treatment is for the layouts
   that read as an editorial panel, not as the page's photograph.
   ========================================================================= */

/* ---- eyebrow: a rule, an icon, and small caps ---- */
.dt-promo-hero--split .dt-promo-hero__eyebrow,
.dt-promo-hero--panel .dt-promo-hero__eyebrow {
	background: none;
	border: 0;
	box-shadow: none;
	padding: 0;
	border-radius: 0;
	gap: .6rem;
	color: var(--dtpx-quiet, var(--dtpr-teal));
	letter-spacing: .16em;
	font-size: .72rem;
}
.dt-promo-hero--split .dt-promo-hero__eyebrow::before,
.dt-promo-hero--panel .dt-promo-hero__eyebrow::before {
	content: '';
	inline-size: 28px;
	block-size: 2px;
	border-radius: 2px;
	background: var(--dtpr-blush);
	flex: 0 0 auto;
}
.dt-promo-hero--split .dt-promo-hero__eyebrow i,
.dt-promo-hero--panel .dt-promo-hero__eyebrow i { color: var(--dtpr-blush); font-size: .9rem; }

/* ---- headline: a confident serif, one word in blush italic ---- */
.dt-promo-hero--split .dt-promo-hero__title,
.dt-promo-hero--panel .dt-promo-hero__title {
	/*
	 * Mollie Glaston, like every other heading on this site.
	 *
	 * This briefly used Playfair to match the concierge popup, which carries a
	 * heavier serif. That was the wrong reference to follow: the popup is one
	 * component, while "Three ways to begin" and "Featured dream pets" — the
	 * sections this hero sits directly above — are the site's actual voice. A
	 * hero in a different face than the section under it reads as a bolted-on
	 * banner, which is exactly what it must never look like.
	 */
	font-family: var(--dtpr-font-display);
	/*
	 * 600 against a family that ships ONE cut at 400, so the browser
	 * synthesises it — the glyphs are smeared outward rather than redrawn.
	 * Asked for deliberately: it thickens the script a touch, which is the
	 * intent. If it ever reads furry at large sizes, the honest heavier
	 * headline is Playfair 600 (a real cut, already loaded) — not a larger
	 * number here, which only smears harder.
	 */
	font-weight: 600;
	line-height: 1.06;
	letter-spacing: -.005em;
}
/*
 * Two accents, and they are not the same thing.
 *
 * <em> is the author writing *their own* stress with asterisks, mid-sentence:
 * "the *tail* you are dreaming of". A slant is exactly right for that — it is
 * a change in tone of voice, not a change in volume.
 *
 * <strong> is the offer word the system picks out by itself — the OFF in
 * "XX% OFF", a standalone "FREE". That one is volume, so it is upright and
 * heavy. Italic made it look like an aside, which is the opposite of the job.
 */
.dt-promo-hero__title em {
	font-style: italic;
	color: #8f5f5b;
}

.dt-promo-hero__title strong,
.dt-promo-popup__title strong {
	/*
	 * Playfair, deliberately, and this is the whole reason the rule exists.
	 * Mollie Glaston is a single-weight 400 script with no bold cut, so
	 * `font-weight: 700` on it only asks the rasteriser to smear the stems —
	 * fake bold, and on a script face it reads as a rendering fault rather
	 * than as emphasis. Playfair ships a real 700 (functions.php:508 loads
	 * 0,400;0,600;0,700), so the word is drawn bold rather than thickened.
	 *
	 * Two faces in one headline works here only because the accent is a
	 * single short word — it reads as a stamp set into the line.
	 *
	 * The .98em is MEASURED, not taste. Both faces are 1000 units/em, and
	 * their cap heights are 700 (Mollie Glaston) against 708 (Playfair 700).
	 * The accent sits on the same baseline as the caps either side of it, so
	 * cap height is the thing that has to agree: 700/708 = .989, taken to
	 * .98 to let the bold weight — which always reads a size larger than the
	 * light script around it — settle level instead of looming.
	 *
	 * If this ever looks wrong, re-measure both faces rather than nudging
	 * the number; a font swap is what would break it.
	 */
	font-family: var(--dtpr-font-serif);
	font-style: normal;
	font-weight: 700;
	font-size: .98em;
	/* Uppercase bold serif sets tight; a hair of tracking keeps OFF open. */
	letter-spacing: .02em;
	/* A deeper dusty rose than the surface blush, so the offer reads as the
	   loudest thing in the headline. Measured against the 3:1 display floor:
	   cream 5.12, ivory 5.09, peach 3.50, sage 3.11 — all clear. Blush is the
	   exception and is handled just below. */
	color: #8f5f5b;
}

/*
 * On the blush surface this rose is the ground's own hue one step darker,
 * and it measures 2.76:1 — under the 3:1 display floor. It was survivable
 * while the accent was a quiet italic; now that it is the loudest word in
 * the headline it is not. A deeper cut of the same rose takes it to 3.53:1
 * without leaving the family.
 */
.dt-promo-hero--pal-blush .dt-promo-hero__title strong,
.dt-promo-popup--pal-blush .dt-promo-popup__title strong,
.dt-promo-hero--pal-blush .dt-promo-hero__title em { color: #7d4f4c; }

/* Over a photo or a dark surface the rose goes muddy; peach is the light-on-
   dark counterpart and is already the accent those variants use elsewhere. */
/*
 * Keyed to the PALETTE, not the layout. --photo used to be in this list on
 * the assumption that a photo hero is dark — but the scrim over the picture
 * is painted in the palette's own colour (--dtpx-scrim-rgb above), so a photo
 * hero on ivory or peach has a LIGHT ground and peach on it measures about
 * 1.2:1. The offer word, which is the loudest thing in the headline, vanished
 * on exactly the palettes most campaigns use. Dark grounds take peach; light
 * ones keep the rose, whatever the layout.
 */
.dt-promo-hero--pal-teal .dt-promo-hero__title em,
.dt-promo-hero--pal-navy .dt-promo-hero__title em,
.dt-promo-hero--pal-teal .dt-promo-hero__title strong,
.dt-promo-hero--pal-navy .dt-promo-hero__title strong { color: var(--dtpr-peach); }

.dt-promo-popup--pal-teal .dt-promo-popup__title strong,
.dt-promo-popup--pal-navy .dt-promo-popup__title strong { color: var(--dtpr-peach); }

/* ---- lede: quiet sans, roomier line ---- */
.dt-promo-hero--split .dt-promo-hero__lede,
.dt-promo-hero--panel .dt-promo-hero__lede {
	font-family: var(--dtpr-font-ui);
	font-style: normal;
	font-size: 1.02rem;
	line-height: 1.65;
	/*
	 * Palette-aware, not a fixed grey. In these two layouts the band behind
	 * the words IS the palette colour, so a hard-coded --dtpr-ink-soft
	 * (#6a7a7e) measured 2.33:1 on blush and 2.62:1 on sage. --dtpx-fg is the
	 * body colour each surface was measured with.
	 */
	color: var(--dtpx-fg, var(--dtpr-ink-soft));
	max-inline-size: 46ch;
}
.dt-promo-hero--pal-teal .dt-promo-hero__lede,
.dt-promo-hero--pal-navy .dt-promo-hero__lede { color: rgba(255, 255, 255, .88); }

/* ---- the primary button becomes a block ---- */
.dt-promo-hero--split .dt-promo-cta--primary,
.dt-promo-hero--panel .dt-promo-cta--primary {
	background: var(--dtpr-teal);
	color: #fff;
	border-radius: 6px;
	padding: 1.05rem 1.9rem;
	font-size: .82rem;
	font-weight: 700;
	letter-spacing: .1em;
	text-transform: uppercase;
	box-shadow: 0 10px 26px -14px rgba(61, 81, 85, .55);
}
.dt-promo-hero--split .dt-promo-cta--primary:hover,
.dt-promo-hero--panel .dt-promo-cta--primary:hover {
	background: var(--dtpr-teal-deep);
	color: #fff;
	box-shadow: 0 14px 30px -14px rgba(61, 81, 85, .6);
}
/* On the dark surfaces a teal block vanishes; peach carries it instead. */
.dt-promo-hero--split.dt-promo-hero--pal-teal .dt-promo-cta--primary,
.dt-promo-hero--panel.dt-promo-hero--pal-teal .dt-promo-cta--primary,
.dt-promo-hero--split.dt-promo-hero--pal-navy .dt-promo-cta--primary,
.dt-promo-hero--panel.dt-promo-hero--pal-navy .dt-promo-cta--primary {
	background: var(--dtpr-peach);
	color: var(--dtpr-teal-deep);
}
/*
 * The secondary is a colour of its own, not an outline.
 *
 * It used to be a hairline box beside the teal block, on the usual reasoning
 * that a second filled button competes with the first. That reasoning holds
 * when both buttons want the same click; here they do not. The teal one is
 * the offer and the blush one is "show me everything" — two different errands,
 * and an outline made the second read as a cancel button.
 *
 * Blush against teal is the brand's own pairing, and it stays clearly the
 * quieter of the two: lighter ground, ink rather than white, and a softer
 * shadow. Ink on blush measures 6.18:1.
 */
.dt-promo-hero--split .dt-promo-cta--secondary,
.dt-promo-hero--panel .dt-promo-cta--secondary {
	border-radius: 6px;
	padding: 1.05rem 1.6rem;
	font-size: .82rem;
	font-weight: 700;
	letter-spacing: .1em;
	text-transform: uppercase;
	background: linear-gradient(135deg, var(--dtpr-blush) 0%, var(--dtpr-blush-deep) 100%);
	border-color: rgba(255, 255, 255, .55);
	color: var(--dtpr-ink);
	box-shadow: 0 8px 22px -12px rgba(217, 178, 175, .85);
}
.dt-promo-hero--split .dt-promo-cta--secondary:hover,
.dt-promo-hero--panel .dt-promo-cta--secondary:hover,
.dt-promo-hero--split .dt-promo-cta--secondary:focus-visible,
.dt-promo-hero--panel .dt-promo-cta--secondary:focus-visible {
	background: linear-gradient(135deg, var(--dtpr-blush-soft) 0%, var(--dtpr-peach-soft) 100%);
	color: var(--dtpr-ink);
	box-shadow: 0 12px 26px -12px rgba(217, 178, 175, .95);
}
/*
 * On the dark surfaces blush loses its footing — white text on it is 1.92:1
 * and ink on it against a navy ground reads as a smudge. The glass chip the
 * rest of the dark-surface furniture uses is the right answer there, and is
 * restated rather than inherited because this block would otherwise win on
 * document order.
 */
/*
 * On the blush surface the blush button IS the ground — same hue, a shade
 * apart — so the second button dissolved into the band it sits on. Cream with
 * teal lettering keeps it a button, and keeps the pair reading as teal block
 * plus lighter companion rather than as two blush shapes.
 */
.dt-promo-hero--split.dt-promo-hero--pal-blush .dt-promo-cta--secondary,
.dt-promo-hero--panel.dt-promo-hero--pal-blush .dt-promo-cta--secondary {
	background: linear-gradient(135deg, #fffaf5 0%, #fef0e2 100%);
	border-color: rgba(255, 255, 255, .8);
	color: var(--dtpr-teal-deep);
	box-shadow: 0 8px 22px -12px rgba(61, 81, 85, .4);
}
.dt-promo-hero--split.dt-promo-hero--pal-blush .dt-promo-cta--secondary:hover,
.dt-promo-hero--panel.dt-promo-hero--pal-blush .dt-promo-cta--secondary:hover {
	background: #fff;
	color: var(--dtpr-teal-deep);
}

.dt-promo-hero--split.dt-promo-hero--pal-teal .dt-promo-cta--secondary,
.dt-promo-hero--panel.dt-promo-hero--pal-teal .dt-promo-cta--secondary,
.dt-promo-hero--split.dt-promo-hero--pal-navy .dt-promo-cta--secondary,
.dt-promo-hero--panel.dt-promo-hero--pal-navy .dt-promo-cta--secondary {
	background: var(--dtpr-glass);
	backdrop-filter: blur(10px);
	-webkit-backdrop-filter: blur(10px);
	border-color: rgba(255, 255, 255, .28);
	color: #fff;
	box-shadow: none;
}

/* =========================================================================
   A framed photograph is shown whole

   The Desktop shape and Crop-or-fit were written for the PHOTO layout, where
   the picture IS the background and something has to decide how tall the band
   is and what survives. Beside the words it is a portrait in a frame, and
   applying the same 16/9 default there crops a square photograph by 44% for a
   reason that belongs to a different layout. Someone who chose that picture
   chose all of it.

   So the frame takes the picture's own shape, and those two controls govern
   the layout they were written for. The cap is what stops a tall photograph
   running past the fold.
   ========================================================================= */

.dt-promo-hero--split .dt-promo-hero__figure,
.dt-promo-hero--panel .dt-promo-hero__figure {
	aspect-ratio: auto;
	max-block-size: min(76vh, 660px);
	display: grid;
	place-items: center;
	/* The frame hugs the picture rather than boxing it: a square photo gets a
	   square frame, a tall one a tall frame. */
	inline-size: fit-content;
	margin-inline: auto;
}
.dt-promo-hero--split .dt-promo-hero__img,
.dt-promo-hero--panel .dt-promo-hero__img {
	inline-size: auto;
	max-inline-size: 100%;
	block-size: auto;
	max-block-size: min(76vh, 660px);
	object-fit: contain;
}

/* =========================================================================
   Boutique detail

   This theme's idea of ornament is restraint: warm washes layered over each
   other, hairlines, small caps, and a single blush accent — never a pattern
   or a border that announces itself. Everything here is built from the same
   three gestures the site already uses on its own sections.
   ========================================================================= */

/* ---- the ground gains a third bloom and an edge ---- */
.dt-promo-hero:not(.dt-promo-hero--photo) {
	position: relative;
	/* A warm floor under the wash, so the band has a bottom rather than
	   fading into whatever section follows it. */
	box-shadow: inset 0 -1px 0 rgba(61, 81, 85, .06);
}
.dt-promo-hero__stack { position: relative; z-index: 1; }

/* A third, softer bloom low and centre — the site's sections carry two or
   three, never one, which is what stops a large area reading as flat paint. */
.dt-promo-hero:not(.dt-promo-hero--photo) .dt-promo-hero__inner::before {
	content: '';
	position: absolute;
	inset-block-end: -30%;
	inset-inline-start: 34%;
	inline-size: 46%;
	block-size: 80%;
	border-radius: 50%;
	pointer-events: none;
	z-index: -1;
	background: radial-gradient(circle, var(--dtpx-bloom-c, rgba(241, 230, 178, .30)), transparent 68%);
}
.dt-promo-hero--pal-sage  { --dtpx-bloom-c: rgba(255, 255, 255, .34); }
.dt-promo-hero--pal-peach { --dtpx-bloom-c: rgba(217, 178, 175, .26); }
.dt-promo-hero--pal-blush { --dtpx-bloom-c: rgba(241, 230, 178, .26); }
.dt-promo-hero--pal-teal  { --dtpx-bloom-c: rgba(241, 230, 178, .07); }
.dt-promo-hero--pal-navy  { --dtpx-bloom-c: rgba(238, 204, 170, .07); }

/* ---- the framed photograph gets a second, offset frame ---- */
.dt-promo-hero--split .dt-promo-hero__media,
.dt-promo-hero--panel .dt-promo-hero__media { position: relative; }
.dt-promo-hero--split .dt-promo-hero__media::after,
.dt-promo-hero--panel .dt-promo-hero__media::after {
	content: '';
	position: absolute;
	inset: 14px -14px -14px 14px;
	border: 1px solid var(--dtpr-blush);
	border-radius: var(--dtpr-r-block);
	opacity: .5;
	z-index: -1;
	pointer-events: none;
}
.dt-promo-hero--pal-teal .dt-promo-hero__media::after,
.dt-promo-hero--pal-navy .dt-promo-hero__media::after { border-color: rgba(238, 204, 170, .5); }

/* =========================================================================
   The two-tone ground

   The split and panel layouts are a composition of two halves, and on a
   single flat ground the eye has nothing telling it where one stops. Laying
   the picture half on a warmer tint and dividing the two with a hairline is
   the whole of it — a quiet change of paper rather than a panel dropped on
   top, which is why the tint runs to the edge of the band and not to the
   edge of a box.

   All of it rides on ONE pseudo-element carrying three background layers —
   the rule, a wash, and the tile beneath them. Separate elements for the
   tint and the pattern would each have needed this same bleed geometry
   written twice and kept in step.
   ========================================================================= */

.dt-promo-hero--tinted .dt-promo-hero__media::before {
	content: '';
	position: absolute;
	/*
	 * Deliberately far past the band on three sides, because the hero root
	 * carries overflow:hidden and clips it. Sizing this to the band instead
	 * would mean tracking the grid row height and the block padding from
	 * here, and it would come apart the moment the copy side grew taller
	 * than the picture.
	 */
	inset-block: -100vh;
	inset-inline-end: -50vw;
	/* Meets the gap at its middle, so the rule sits centred between the two
	   halves rather than tight against the photograph. */
	inset-inline-start: calc(var(--dtpx-gap) / -2);
	z-index: -1;
	pointer-events: none;

	background-color: var(--dtpx-split-tint, #eabfbd);
	background-image:
		/* 1. the divider, faded out at both ends so it reads as a rule and
		      not as the edge of a box */
		linear-gradient(to bottom,
			transparent 0,
			var(--dtpx-split-rule, rgba(61, 81, 85, .18)) 12%,
			var(--dtpx-split-rule, rgba(61, 81, 85, .18)) 88%,
			transparent 100%),
		/* 2. the wash that holds the tile at a whisper. This is what makes
		      "very faint" a single number instead of a re-exported image. */
		linear-gradient(var(--dtpx-split-wash, rgba(234, 191, 189, .92)),
		                var(--dtpx-split-wash, rgba(234, 191, 189, .92))),
		/* 3. the tile itself, from the Media Library. Absent, this is `none`
		      and the two layers above it simply paint on the tint. */
		var(--dtpx-pattern, none);
	background-repeat: no-repeat, repeat, repeat;
	background-size: 1px 100%, auto, var(--dtpx-pattern-size, 380px);
	background-position: left top, 0 0, center top;

	/*
	 * The "tad of shadow", and it is meant to be found rather than seen:
	 * thrown off the rule onto the copy side only, so the picture half reads
	 * a hair proud of the words. Tinted teal like every other shadow in the
	 * theme — a neutral grey here turns the cream dirty.
	 */
	box-shadow: -8px 0 16px -14px rgb(61 81 85 / .18);
}

/* Reversed composition: the picture sits left, so the bleed, the rule and
   the shadow all change hands. */
.dt-promo-hero--tinted.dt-promo-hero--side-right .dt-promo-hero__media::before {
	inset-inline-start: -50vw;
	inset-inline-end: calc(var(--dtpx-gap) / -2);
	background-position: right top, 0 0, center top;
	box-shadow: 8px 0 16px -14px rgb(61 81 85 / .18);
}

/* ---- the companion tint ----
   Blush-soft on every light surface. It was a warm tan at first, which put a
   third warm neutral next to cream and peach and read as a paper mismatch
   rather than a deliberate pairing; the brand's own soft blush is the tint
   that looks chosen. The wash repeats it with an alpha, and THAT alpha is the
   pattern's faintness — take it to 1 and the tile stops showing at all. */
.dt-promo-hero--tinted.dt-promo-hero--pal-ivory .dt-promo-hero__media::before,
.dt-promo-hero--tinted.dt-promo-hero--pal-blush .dt-promo-hero__media::before,
.dt-promo-hero--tinted.dt-promo-hero--pal-peach .dt-promo-hero__media::before,
.dt-promo-hero--tinted.dt-promo-hero--pal-sage  .dt-promo-hero__media::before,
.dt-promo-hero--tinted.dt-promo-hero--photo     .dt-promo-hero__media::before {
	--dtpx-split-tint: var(--dtpr-blush-soft);
	--dtpx-split-wash: rgb(234 191 189 / .92);
}
.dt-promo-hero--tinted.dt-promo-hero--pal-teal .dt-promo-hero__media::before {
	--dtpx-split-tint: #476065;
	--dtpx-split-wash: rgb(71 96 101 / .9);
	--dtpx-split-rule: rgb(255 255 255 / .22);
	box-shadow: -8px 0 16px -14px rgb(0 0 0 / .26);
}
.dt-promo-hero--tinted.dt-promo-hero--pal-navy .dt-promo-hero__media::before {
	--dtpx-split-tint: #393f61;
	--dtpx-split-wash: rgb(57 63 97 / .9);
	--dtpx-split-rule: rgb(255 255 255 / .22);
	box-shadow: -8px 0 16px -14px rgb(0 0 0 / .26);
}

@media (max-width: 991.98px) {
	/*
	 * Stacked, the two halves are above and below rather than side by side,
	 * so a vertical rule would run along nothing. The tint stays — it still
	 * separates the picture from the words — but it becomes a full-width
	 * band with a horizontal rule along its top edge.
	 */
	/*
	 * Which way the band grows depends on which half is on top, and getting
	 * that backwards floods the copy instead of backing the picture.
	 *
	 * The default stack is mediafirst — photo above the words — so the band
	 * runs UP past the top of the hero and stops half a gap BELOW the photo,
	 * with its rule along the bottom edge. Written the other way round first,
	 * it ran -100vh downward from the top of the photo and washed the whole
	 * text area in blush on every phone using the default.
	 */
	.dt-promo-hero--tinted .dt-promo-hero__media::before,
	.dt-promo-hero--tinted.dt-promo-hero--side-right .dt-promo-hero__media::before {
		inset-block: -100vh calc(var(--dtpx-gap) / -2);
		inset-inline: -50vw;
		background-image:
			linear-gradient(to right,
				transparent 0,
				var(--dtpx-split-rule, rgba(61, 81, 85, .18)) 12%,
				var(--dtpx-split-rule, rgba(61, 81, 85, .18)) 88%,
				transparent 100%),
			linear-gradient(var(--dtpx-split-wash, rgba(234, 191, 189, .92)),
			                var(--dtpx-split-wash, rgba(234, 191, 189, .92))),
			var(--dtpx-pattern, none);
		background-size: 100% 1px, auto, var(--dtpx-pattern-size, 380px);
		background-position: left bottom, 0 0, center top;
		box-shadow: 0 8px 16px -14px rgb(61 81 85 / .18);
	}
	/* Words first, photo underneath: the band grows the other way and the
	   rule moves to its top edge. */
	.dt-promo-hero--tinted.dt-promo-hero--m-textfirst .dt-promo-hero__media::before,
	.dt-promo-hero--tinted.dt-promo-hero--m-textfirst.dt-promo-hero--side-right .dt-promo-hero__media::before {
		inset-block: calc(var(--dtpx-gap) / -2) -100vh;
		background-position: left top, 0 0, center top;
		box-shadow: 0 -8px 16px -14px rgb(61 81 85 / .18);
	}
}

/* ---- the countdown chips read as cards, like the site's own ---- */
.dt-promo-hero .dt-promo-countdown__unit {
	background: rgba(255, 255, 255, .82);
	border-color: var(--dtpr-white-line);
	box-shadow: var(--dtpr-shadow-sm);
}
.dt-promo-hero--pal-teal .dt-promo-countdown__unit,
.dt-promo-hero--pal-navy .dt-promo-countdown__unit {
	background: rgba(255, 255, 255, .12);
	border-color: rgba(255, 255, 255, .22);
	box-shadow: none;
}

@media (max-width: 767.98px) {
	/* The offset frame is a desktop nicety; on a phone it only steals width. */
	.dt-promo-hero--split .dt-promo-hero__media::after,
	.dt-promo-hero--panel .dt-promo-hero__media::after { display: none; }
}

/* =========================================================================
   Damask

   Thin filigree, drawn as inline SVG so it costs no request and no build
   step, and kept deliberately faint. On this site ornament works by being
   noticed second: the eye should land on the offer, then find the flourish.
   Anything bold enough to read at a glance would fight the photograph.
   ========================================================================= */

/* ---- a damask rule between the words and the button ---- */
/* The anchor. Without it the rule positions against the hero itself and lands
   at the top of the band instead of above the button. */
.dt-promo-hero--split .dt-promo-hero__cta,
.dt-promo-hero--panel .dt-promo-hero__cta { position: relative; }

.dt-promo-hero--split .dt-promo-hero__cta::before,
.dt-promo-hero--panel .dt-promo-hero__cta::before {
	content: '';
	position: absolute;
	inset-block-start: calc(var(--dtpx-gap, 2rem) * -.5);
	inset-inline-start: 0;
	inline-size: 200px;
	block-size: 18px;
	background: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20200%2018%22%20fill%3D%22none%22%20stroke%3D%22%23c99b96%22%20stroke-width%3D%221%22%20stroke-linecap%3D%22round%22%3E%3Cpath%20d%3D%22M2%209h56%22%2F%3E%3Cpath%20d%3D%22M58%209c6%200%207-5%2013-5s7%205%2013%205%22%2F%3E%3Cpath%20d%3D%22M116%209c6%200%207%205%2013%205s7-5%2013-5%22%2F%3E%3Cpath%20d%3D%22M142%209h56%22%2F%3E%3Cpath%20d%3D%22M100%203.5%20106.5%209%20100%2014.5%2093.5%209Z%22%2F%3E%3Cpath%20d%3D%22M84%209h9M107%209h9%22%2F%3E%3C%2Fsvg%3E") center left / 200px 18px no-repeat;
	opacity: .65;
}
.dt-promo-hero--txt-center .dt-promo-hero__cta::before {
	inset-inline: 0;
	margin-inline: auto;
	background-position: center;
}
/* The stroke is drawn in blush; on the dark surfaces it disappears, so the
   whole ornament is lifted with a filter rather than shipped twice. */
.dt-promo-hero--pal-teal .dt-promo-hero__cta::before,
.dt-promo-hero--pal-navy .dt-promo-hero__cta::before {
	filter: brightness(0) saturate(100%) invert(86%) sepia(18%) saturate(480%) hue-rotate(324deg) brightness(101%) contrast(94%);
	opacity: .55;
}

/* ---- a ruled foot, the way a boutique card is finished ----
   The corner arabesque that used to live here was the wrong instinct: large
   enough to be noticed first, and it collided with the framed photograph. A
   long hairline with one small centred flourish reads as finishing rather
   than decoration, and it gives the band a bottom edge. */
.dt-promo-hero:not(.dt-promo-hero--photo) .dt-promo-hero__inner::after {
	content: '';
	position: absolute;
	inset-block-end: calc(var(--dtpx-pad, 3rem) * -.42);
	inset-inline: 0;
	margin-inline: auto;
	inline-size: min(440px, 62%);
	block-size: 20px;
	background: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20440%2020%22%20fill%3D%22none%22%20stroke%3D%22%23c99b96%22%20stroke-width%3D%221%22%20stroke-linecap%3D%22round%22%3E%3Cpath%20d%3D%22M0%2010h150%22%2F%3E%3Cpath%20d%3D%22M290%2010h150%22%2F%3E%3Cpath%20d%3D%22M150%2010c8%200%2010-6%2018-6s10%206%2018%206%22%2F%3E%3Cpath%20d%3D%22M254%2010c8%200%2010%206%2018%206s10-6%2018-6%22%2F%3E%3Cpath%20d%3D%22M220%204.5%20226.5%2010%20220%2015.5%20213.5%2010Z%22%2F%3E%3Cpath%20d%3D%22M186%2010h27M227%2010h27%22%2F%3E%3Cpath%20d%3D%22M204%2010c0-3%203-5%206-5M236%2010c0%203-3%205-6%205%22%2F%3E%3C%2Fsvg%3E") center / contain no-repeat;
	opacity: .5;
	pointer-events: none;
}
.dt-promo-hero--pal-teal .dt-promo-hero__inner::after,
.dt-promo-hero--pal-navy .dt-promo-hero__inner::after {
	filter: brightness(0) saturate(100%) invert(86%) sepia(18%) saturate(480%) hue-rotate(324deg) brightness(101%) contrast(94%);
	opacity: .45;
}

@media (max-width: 767.98px) {
	/* Ornament is the first thing to go when width is scarce. */
	.dt-promo-hero .dt-promo-hero__inner::after { display: none; }
	.dt-promo-hero--split .dt-promo-hero__cta::before,
	.dt-promo-hero--panel .dt-promo-hero__cta::before { inline-size: 150px; background-size: 150px 14px; }
}

/* =========================================================================
   Directional scrim
   ========================================================================= */

.dt-promo-hero__scrim {
	z-index: 1;
	pointer-events: none;
}

.dt-promo-hero--side-left  { --dtpx-scrim-dir: to right; --dtpx-scrim-origin: 18% 50%; }
.dt-promo-hero--side-right { --dtpx-scrim-dir: to left;  --dtpx-scrim-origin: 82% 50%; }

/* The alpha HOLDS through the first 42% — the band the text actually occupies —
   then falls away fast, so the subject at the far side keeps its saturation.
   --dtpx-scrim-a is floored per palette server-side at the value where the text
   still passes over ANY photograph. */
.dt-promo-hero--scrim-linear .dt-promo-hero__scrim {
	/* Hold the full alpha across the band the words occupy, then fall away
	   quickly and reach ZERO well before the edge. Trailing tint all the way to
	   100% is what makes a photo hero read as a flat colour panel — the point of
	   a directional scrim is that the far side keeps its photograph. */
	background: linear-gradient(
		var(--dtpx-scrim-dir, to right),
		rgb(var(--dtpx-scrim-rgb) / var(--dtpx-scrim-a))              0%,
		rgb(var(--dtpx-scrim-rgb) / var(--dtpx-scrim-a))             var(--dtpx-scrim-hold, 40%),
		rgb(var(--dtpx-scrim-rgb) / calc(var(--dtpx-scrim-a) * .18)) 66%,
		rgb(var(--dtpx-scrim-rgb) / 0)                              82%
	);
}

.dt-promo-hero--scrim-radial .dt-promo-hero__scrim {
	background: radial-gradient(
		120% 130% at var(--dtpx-scrim-origin, 18% 50%),
		rgb(var(--dtpx-scrim-rgb) / var(--dtpx-scrim-a))              0%,
		rgb(var(--dtpx-scrim-rgb) / calc(var(--dtpx-scrim-a) * .55)) 46%,
		rgb(var(--dtpx-scrim-rgb) / 0)                              78%
	);
}

.dt-promo-hero--scrim-panel .dt-promo-hero__scrim { background: none; }
.dt-promo-hero--scrim-panel .dt-promo-hero__panel {
	background: rgb(var(--dtpx-scrim-rgb) / .94);
	padding: clamp(1.5rem, 3vw, 2.5rem);
	border-radius: var(--dtpr-r-block);
	box-shadow: var(--dtpr-shadow-lg);
}

.dt-promo-hero--scrim-none .dt-promo-hero__scrim { display: none; }

/* =========================================================================
   Hero — responsive
   ========================================================================= */

@media (max-width: 991.98px) {
	/*
	 * The --side-right selectors are carried explicitly, and they have to be.
	 * "Text side = Right" sets grid-template-columns in an UNCONDITIONAL rule
	 * of specificity (0,3,0); this one is (0,2,0), and a media query adds no
	 * specificity — so a right-side hero kept its two desktop columns all the
	 * way down to 320px and crushed the whole promotion into half the screen.
	 * Matching (0,3,0) here wins on source order instead.
	 */
	.dt-promo-hero--split .dt-promo-hero__inner,
	.dt-promo-hero--panel .dt-promo-hero__inner,
	.dt-promo-hero--split.dt-promo-hero--side-right .dt-promo-hero__inner,
	.dt-promo-hero--panel.dt-promo-hero--side-right .dt-promo-hero__inner {
		grid-template-columns: minmax(0, 1fr);
		grid-template-areas: "panel" "media";
	}
	/* The photo overlay stays an overlay down to 768px, but its two-column split
	   would leave the text in a ~340px column on a tablet — narrow enough that
	   three short trust chips stack into a tower. Give the words the full width
	   and let the scrim cover more of the frame. */
	.dt-promo-hero--photo .dt-promo-hero__inner {
		grid-template-columns: minmax(0, 1fr);
	}
	.dt-promo-hero--photo .dt-promo-hero__panel { grid-column: 1; }
	.dt-promo-hero--photo .dt-promo-hero__scrim { --dtpx-scrim-hold: 58%; }
	.dt-promo-hero--split.dt-promo-hero--m-mediafirst .dt-promo-hero__inner,
	.dt-promo-hero--panel.dt-promo-hero--m-mediafirst .dt-promo-hero__inner,
	.dt-promo-hero--split.dt-promo-hero--side-right.dt-promo-hero--m-mediafirst .dt-promo-hero__inner,
	.dt-promo-hero--panel.dt-promo-hero--side-right.dt-promo-hero--m-mediafirst .dt-promo-hero__inner {
		grid-template-areas: "media" "panel";
	}
	.dt-promo-hero__title,
	.dt-promo-hero__lede { max-inline-size: min(var(--dtpx-measure, 34ch), 60ch); }
}

@media (max-width: 767.98px) {
	/* A mobile composition, not a shrunken desktop one: by default the photo and
	   the words un-stack, so nothing overlaps and the scrim is unnecessary. */
	.dt-promo-hero--photo:not(.dt-promo-hero--m-overlay) .dt-promo-hero__stack {
		grid-template-areas: "media" "panel";
		grid-template-columns: minmax(0, 1fr);
	}
	.dt-promo-hero--photo:not(.dt-promo-hero--m-overlay) .dt-promo-hero__media { grid-area: media; }
	.dt-promo-hero--photo:not(.dt-promo-hero--m-overlay) .dt-promo-hero__inner { grid-area: panel; }
	.dt-promo-hero--photo:not(.dt-promo-hero--m-overlay) .dt-promo-hero__scrim { display: none; }
	.dt-promo-hero--photo:not(.dt-promo-hero--m-overlay) .dt-promo-hero__media {
		min-block-size: 0;
		aspect-ratio: var(--dtpx-ratio-sm, 4/5);
		max-block-size: 62vh;
		/*
		 * Load-bearing, and its absence was invisible in the CSS.
		 *
		 * The photo layout sets this box to position:static for the desktop
		 * composition, where the picture is meant to fill the hero. Once this
		 * branch un-stacks the grid into a picture row and a text row, static
		 * leaves .dt-promo-hero__pic (absolute, inset:0) parented to the
		 * STACK — which spans both rows — so the photograph ran straight down
		 * through the copy while the line above switches the scrim off on the
		 * grounds that "nothing overlaps". Headline and lede printed onto the
		 * picture with nothing behind them on every phone.
		 */
		position: relative;
	}
	.dt-promo-hero--photo:not(.dt-promo-hero--m-overlay).dt-promo-hero--m-textfirst .dt-promo-hero__stack {
		grid-template-areas: "panel" "media";
	}
	.dt-promo-hero--photo:not(.dt-promo-hero--m-overlay) .dt-promo-hero__inner {
		grid-template-columns: minmax(0, 1fr);
	}
	/* ---------------------------------------------------------------------
	   "Photo behind the text" on a phone.
	   ---------------------------------------------------------------------
	   Available on ALL three layouts, not just the photo one. It used to be
	   wired only for --photo, so choosing it on a split or panel hero did
	   nothing at all: the picture went on stacking under the words.

	   The alpha comes from --dtpx-scrim-sm-a, computed server-side and floored
	   per palette at the value where the text still passes over ANY photograph.
	   The old rule here said `--dtpx-scrim-a: calc(var(--dtpx-scrim-a) + .06)`,
	   which is a custom property defined in terms of itself — a dependency
	   cycle, so it silently evaluated to nothing and lifted the fade by zero. */
	.dt-promo-hero--m-overlay { --dtpx-scrim-a: var(--dtpx-scrim-sm-a, .7); }

	/* Split and panel: the framed photo becomes the background of the whole
	   hero, and the words sit on top of it. */
	.dt-promo-hero--m-overlay.dt-promo-hero--split .dt-promo-hero__inner,
	.dt-promo-hero--m-overlay.dt-promo-hero--panel .dt-promo-hero__inner {
		grid-template-columns: minmax(0, 1fr);
		grid-template-areas: "panel";
		min-block-size: min(80vh, 620px);
		align-content: center;
	}

	/*
	 * The words get the margin; the photograph does not.
	 *
	 * Padding the wrap was wrong: the wrap is .dt-promo-hero__inner, which is
	 * position:relative, which makes it the containing block for the
	 * absolutely-placed photo below — so every pixel of gutter pushed the
	 * picture in from the screen edge as well as the text. The panel is the
	 * text column and nothing else, so it is the honest place for it.
	 *
	 * It also has to out-rank header.css, which pins `main .container` to
	 * 0.25rem !important at this breakpoint. The promo hero renders inside
	 * <main>, so that rule reaches the wrap — another reason the padding does
	 * not belong there.
	 */
	.dt-promo-hero--m-overlay.dt-promo-hero--split .dt-promo-hero__panel,
	.dt-promo-hero--m-overlay.dt-promo-hero--panel .dt-promo-hero__panel {
		padding-inline: clamp(1.15rem, 5.5vw, 2.5rem);
		padding-block: clamp(.5rem, 3vw, 1.5rem);
	}

	/*
	 * No two-tone ground in this composition. The picture is promoted to the
	 * hero's background and the media box is stretched over the whole band,
	 * so the tint would either hide behind the photograph or, if the stacking
	 * ever shifted, paint straight across it. There is no second half left to
	 * distinguish, which is the only thing the tint was for.
	 */
	.dt-promo-hero--tinted.dt-promo-hero--m-overlay .dt-promo-hero__media::before {
		content: none;
	}
	/* Absolute against the HERO, not the wrap, so the picture reaches the
	   screen edges instead of being inset by the wrap's gutter. */
	.dt-promo-hero--m-overlay.dt-promo-hero--split .dt-promo-hero__media,
	.dt-promo-hero--m-overlay.dt-promo-hero--panel .dt-promo-hero__media {
		position: absolute;
		z-index: 0;
		margin: 0;
		max-inline-size: none;
		/*
		 * Edge to edge, whatever gutter the wrap is carrying.
		 *
		 * `inset: 0` was meant to reach the screen edges, on the belief that
		 * this box was positioned against the hero. It is not — the wrap is
		 * position:relative, so `inset: 0` stops at the wrap's padding box and
		 * the picture inherits the gutter. 50% is half the wrap and 50vw is
		 * half the screen, so this is exactly the distance out to the edge on
		 * each side, and the hero's overflow:hidden trims the remainder.
		 */
		inset-block: 0;
		inset-inline: calc(50% - 50vw);
	}
	.dt-promo-hero--m-overlay.dt-promo-hero--split .dt-promo-hero__figure,
	.dt-promo-hero--m-overlay.dt-promo-hero--panel .dt-promo-hero__figure {
		block-size: 100%;
		inline-size: 100%;
		max-inline-size: none;
		margin: 0;
		aspect-ratio: auto;
		border-radius: 0;
		box-shadow: none;
	}
	.dt-promo-hero--m-overlay.dt-promo-hero--split .dt-promo-hero__figure :is(picture, img),
	.dt-promo-hero--m-overlay.dt-promo-hero--panel .dt-promo-hero__figure :is(picture, img) {
		inline-size: 100%;
		block-size: 100%;
		object-fit: cover;
		object-position: var(--dtpx-focal-sm, var(--dtpx-focal, 50% 50%));
	}
	.dt-promo-hero--m-overlay.dt-promo-hero--split .dt-promo-hero__panel,
	.dt-promo-hero--m-overlay.dt-promo-hero--panel .dt-promo-hero__panel {
		position: relative;
		z-index: 2;
	}

	/* The scrim is unconditional here and covers the whole frame at full alpha.
	   A directional fade protects "the far side keeping its photograph", but
	   when the words cover the entire picture there is no far side to protect —
	   and a gradient would leave the bottom of the text sitting on bare photo.
	   This is also why it paints even when the desktop fade is set to None. */
	.dt-promo-hero--m-overlay .dt-promo-hero__scrim {
		display: block;
		position: absolute;
		inset: 0;
		z-index: 1;
		background: rgb(var(--dtpx-scrim-rgb) / var(--dtpx-scrim-sm-a, .7));
	}

	.dt-promo-hero__title,
	.dt-promo-hero__lede { max-inline-size: none; }
	.dt-promo-hero__cta { flex-direction: column; align-items: stretch; }
	.dt-promo-hero__title { text-wrap: pretty; }
}

@media (max-width: 575.98px) {
	.dt-promo-hero--h-xl { --dtpx-h1: clamp(2.2rem, 5vw, 4.2rem); }
	.dt-promo-hero__trust li:nth-child(n+3) { display: none; }
}

/* =========================================================================
   Countdown

   Deliberately quiet: no flip animation, no pulsing, no colour that shouts.
   It is a fact about the offer, sized like supporting copy — the headline and
   the button stay the loudest things in the hero.

   Tabular figures matter more than they sound: without them the seconds digit
   changes width every tick and the whole row jitters.
   ========================================================================= */

.dt-promo-countdown {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: .55rem .8rem;
	margin-block-start: 1.5rem;
	/* Follow the hero's alignment, exactly like the button row and the trust
	   chips do. Without this the countdown stays left-packed inside a centred
	   or right-aligned panel — the row visibly out of step with everything
	   above and below it. */
	justify-content: var(--dtpx-align, start);
}

.dt-promo-countdown__label {
	font-family: var(--dtpr-font-ui);
	font-size: .84rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .14em;                       /* == the eyebrow */
	color: var(--dtpx-quiet, var(--dtpr-teal));
	opacity: var(--dtpr-quiet);
}

/*
 * The label gets its own line in the hero, always.
 *
 * It used to be an ordinary flex item, so whether it sat beside the numbers or
 * above them depended on whether the whole row happened to fit — and the row's
 * width changes as the clock runs: "1 day" is narrower than "11 days", and
 * "SECOND" is narrower than "SECONDS". At 390px the numbers measure 337px in
 * 354px of space, so those few pixels flipped the layout back and forth every
 * time a unit rolled over, and the label visibly jumped above and below the
 * numbers while you watched it.
 *
 * Giving it a full-width basis makes the position a fact instead of a
 * coincidence: nothing the clock does can move it. The bar keeps the label
 * inline — it is one short strip that wraps as a whole, and its numbers are
 * small enough never to come near the limit.
 */
.dt-promo-hero .dt-promo-countdown__label { flex: 0 0 100%; }

/* Same reasoning anywhere else once the screen is narrow enough to be tight. */
@media (max-width: 767.98px) {
	.dt-promo-countdown__label { flex: 0 0 100%; }
	.dt-promo-bar .dt-promo-countdown__label { flex: 0 1 auto; }
}

/*
 * Reserve width for the widest each unit will ever be, so a roll-over cannot
 * change the row's width at all. Two tabular digits plus the longest label.
 */
.dt-promo-countdown--inline .dt-promo-countdown__unit { min-inline-size: 4.6rem; }
.dt-promo-countdown--inline .dt-promo-countdown__unit { justify-items: start; }

.dt-promo-countdown__static {
	font-size: .9rem;
	opacity: .9;
}

.dt-promo-countdown__units {
	display: flex;
	flex-wrap: wrap;
	align-items: stretch;
	gap: .4rem;
}
.dt-promo-countdown__units[hidden] { display: none; }

.dt-promo-countdown__unit {
	display: grid;
	justify-items: center;
	gap: .1rem;
	min-inline-size: clamp(4.4rem, 3.5rem + 2.4vw, 6rem);
	padding: .6rem .7rem .5rem;
	border-radius: var(--dtpr-r-chip);
	background: rgb(255 255 255 / .14);
	border: 1px solid rgb(255 255 255 / .22);
	box-shadow: none;
}

.dt-promo-countdown__num {
	/*
	 * Deliberately NOT the display face. Mollie Glaston is a single-weight
	 * script OTF with no tabular figures, so "tnum" would be a no-op on it and
	 * the row would twitch on every tick — which is the exact bug the
	 * min-inline-size above exists to prevent. Playfair has tnum and lnum.
	 */
	font-family: var(--dtpr-font-serif);
	font-size: clamp(2rem, 1.3rem + 2.4vw, 3.1rem);
	line-height: 1;
	font-weight: 600;
	color: var(--dtpx-head, var(--dtpr-teal-deep));
	font-variant-numeric: tabular-nums lining-nums;
	font-feature-settings: "tnum" 1, "lnum" 1;
}

.dt-promo-countdown__unitlabel {
	font-family: var(--dtpr-font-ui);
	font-style: normal;
	font-size: .72rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .12em;
	color: var(--dtpx-quiet, var(--dtpr-teal));
	opacity: var(--dtpr-quiet);
}

/* On a light surface the translucent-white chip disappears; use a tinted one. */
.dt-promo-hero--pal-ivory .dt-promo-countdown__unit,
.dt-promo-hero--pal-sage .dt-promo-countdown__unit,
.dt-promo-hero--pal-peach .dt-promo-countdown__unit,
.dt-promo-hero--pal-blush .dt-promo-countdown__unit {
	background: rgb(255 255 255 / .72);
	border-color: var(--dtpr-white-line);
	box-shadow: var(--dtpr-shadow-sm);
}

/* ---- size, so "bigger" is a choice rather than a fixed guess ----
   Each step scales the numbers and the chip together; the labels grow more
   gently so they stay subordinate to the digits at every size. */
.dt-promo-countdown--size-sm {
	--dtpx-cd-num: clamp(1.5rem, 1.1rem + 1.3vw, 2.1rem);
	--dtpx-cd-min: clamp(3.4rem, 2.9rem + 1.4vw, 4.4rem);
	--dtpx-cd-lab: .64rem;
	--dtpx-cd-pad: .45rem .55rem .4rem;
}
.dt-promo-countdown--size-md {
	--dtpx-cd-num: clamp(1.75rem, 1.2rem + 1.9vw, 2.6rem);
	--dtpx-cd-min: clamp(3.9rem, 3.2rem + 1.9vw, 5.2rem);
	--dtpx-cd-lab: .68rem;
	--dtpx-cd-pad: .55rem .62rem .45rem;
}
.dt-promo-countdown--size-lg {
	--dtpx-cd-num: clamp(2rem, 1.3rem + 2.4vw, 3.1rem);
	--dtpx-cd-min: clamp(4.4rem, 3.5rem + 2.4vw, 6rem);
	--dtpx-cd-lab: .72rem;
	--dtpx-cd-pad: .6rem .7rem .5rem;
}

.dt-promo-countdown__num { font-size: var(--dtpx-cd-num, clamp(2rem, 1.3rem + 2.4vw, 3.1rem)); }
.dt-promo-countdown__unit {
	min-inline-size: var(--dtpx-cd-min, clamp(4.4rem, 3.5rem + 2.4vw, 6rem));
	padding: var(--dtpx-cd-pad, .6rem .7rem .5rem);
}
.dt-promo-countdown__unitlabel { font-size: var(--dtpx-cd-lab, .72rem); }

/* ---- inline variant: a sentence, not a scoreboard ---- */
.dt-promo-countdown--inline .dt-promo-countdown__unit {
	background: none;
	box-shadow: none;
	padding: 0;
	/* Not 0: a fixed floor is what stops the row resizing as the clock runs.
	   See the note on __label above. */
	min-inline-size: 4.6rem;
	grid-auto-flow: column;
	align-items: baseline;
	gap: .2rem;
}
.dt-promo-countdown--inline { gap: .5rem 1.1rem; }
.dt-promo-countdown--inline .dt-promo-countdown__num { font-size: var(--dtpx-cd-num, clamp(1.7rem, 1.15rem + 1.7vw, 2.5rem)); }
.dt-promo-countdown--inline .dt-promo-countdown__unitlabel { font-size: .74rem; letter-spacing: .08em; }

/* ---- inside the announcement bar it is always compact ---- */
.dt-promo-bar .dt-promo-countdown {
	margin-block-start: 0;
	gap: .35rem .5rem;
	color: var(--dtpx-bar-fg, var(--dtpr-teal));
}
.dt-promo-bar .dt-promo-countdown__label { font-size: .68rem; letter-spacing: .08em; }
.dt-promo-bar .dt-promo-countdown__unit {
	background: none;
	box-shadow: none;
	/*
	 * The border goes too. In the hero the unit is a chip — ground, padding
	 * and a hairline together. The bar strips the ground and the padding but
	 * used to keep the hairline, which then had nothing to enclose and drew a
	 * thin rule tight under each number: at a glance the unit labels looked
	 * underlined.
	 */
	border: 0;
	border-radius: 0;
	padding: 0;
	min-inline-size: 0;
	grid-auto-flow: column;
	align-items: baseline;
	gap: .15rem;
}
.dt-promo-bar .dt-promo-countdown__num { font-family: var(--dtpr-font-ui); font-size: .95rem; font-weight: 700; }
.dt-promo-bar .dt-promo-countdown__unitlabel { font-size: .64rem; }
.dt-promo-bar .dt-promo-countdown__label { font-size: .68rem; }
.dt-promo-bar .dt-promo-countdown__static { font-size: .82rem; }

/* ---- the moment it reaches zero ---- */
.dt-promo-countdown.is-expired .dt-promo-countdown__units,
.dt-promo-countdown.is-expired .dt-promo-countdown__label { display: none; }
.dt-promo-countdown.is-expired .dt-promo-countdown__static { font-weight: 600; }

@media (max-width: 575.98px) {
	.dt-promo-countdown { gap: .4rem .5rem; }
	.dt-promo-countdown__unit { min-inline-size: 3.6rem; padding: .45rem .5rem .4rem; }
	.dt-promo-countdown__num { font-size: 1.75rem; }
	.dt-promo-countdown--inline .dt-promo-countdown__num { font-size: 1.5rem; }
}

/* No animation here at all, so there is nothing to disable under reduced
   motion — the tick itself is a text change, which is the point. */

/* =========================================================================
   Announcement bar
   ========================================================================= */

.dt-promo-bar { position: relative; isolation: isolate; }

.dt-promo-bar--flow          { position: static; }
.dt-promo-bar--sticky-above  { position: sticky; top: 0; z-index: 1001; }
.dt-promo-bar--sticky-below  { position: sticky; top: var(--dt-header-h, 0px); z-index: 999; }
body:has(.dt-promo-bar--sticky-above) .dt-header { top: var(--dt-promo-bar-h, 0px); }

/* Sticky is opt-in on desktop and forced off on phones: a sticky bar plus the
   theme's two-row sticky header would eat a quarter of a 667px viewport. */
@media (max-width: 767.98px) {
	.dt-promo-bar--sticky-above,
	.dt-promo-bar--sticky-below { position: static; }
}

.dt-promo-bar__inner {
	display: flex;
	flex-wrap: wrap;          /* wrapping IS the growth mechanism */
	align-items: center;
	justify-content: center;
	column-gap: .9rem;
	row-gap: .35rem;
	padding-block: .25rem;
	/* Symmetric room for the absolutely-placed close button, so the centred
	   content is centred on the bar and never slides under the control. */
	padding-inline: 44px;
	min-block-size: 44px;     /* a floor, never a cap */
	position: relative;
	z-index: 1;
}
/* Deliberately no height, no max-height, no overflow:hidden, no nowrap. */

.dt-promo-bar__msg {
	margin: 0;
	/* Always centred, at every width. */
	text-align: center;
	/* A shade larger and heavier than before: the bar is one line competing with
	   a busy header, and at the old weight it read as chrome rather than as the
	   offer. */
	font-size: clamp(.92rem, .6rem + .55vw, 1.05rem);
	font-weight: 600;
	line-height: 1.35;
	color: var(--dtpx-bar-fg, var(--dtpr-teal));
	text-wrap: pretty;
	overflow-wrap: anywhere;  /* a pasted URL can never overflow the viewport */
	max-inline-size: 68ch;
}

.dt-promo-bar__thumb {
	inline-size: 32px;
	block-size: 32px;
	flex: 0 0 auto;
	border-radius: 50%;
	object-fit: cover;
}

/*
 * A text link, not a button.
 *
 * The bar is a one-line strip; a filled pill in it competes with the hero's
 * own buttons a few hundred pixels below and turns a quiet announcement into
 * a second call to action. It stays underlined type — but in the SECONDARY
 * accent rather than the bar's own foreground, so it reads as the lighter of
 * the campaign's two links rather than as its main one.
 */
.dt-promo-bar__cta {
	display: inline-flex;
	align-items: center;
	gap: .4em;
	min-block-size: 44px;
	padding-inline: .2rem;
	font-weight: 600;
	font-size: .9rem;
	text-decoration: underline;
	text-underline-offset: .22em;
	text-decoration-thickness: .08em;
}
.dt-promo-bar__cta:hover { text-decoration-thickness: .12em; }

/*
 * On the dark bars the accent is blush-soft, not blush.
 *
 * Plain --dtpr-blush measures 4.12:1 on #3f5559 — under AA for text this
 * size, and the one thing in the bar a visitor is meant to click. blush-soft
 * is 4.78:1 and is the same hex the hero's tinted side uses, so the two
 * placements share one accent.
 */
.dt-promo-bar__cta { color: var(--dtpr-blush-soft); }

.dt-promo-bar__close {
	/*
	 * Out of flow, deliberately.
	 *
	 * It used to sit in the flex row with margin-inline-start:auto, which
	 * consumed every pixel of free space on its side — so "centred" content
	 * was really centred in whatever was left over, sitting visibly left of
	 * the bar's true middle. Absolute here means the message, the countdown
	 * and the link centre against the BAR, and the close stays pinned right.
	 */
	position: absolute;
	inset-inline-end: 0;
	inset-block-start: 50%;
	transform: translateY(-50%);
	inline-size: 44px;
	block-size: 44px;
	display: grid;
	place-items: center;
	border: 0;
	background: none;
	cursor: pointer;
	color: var(--dtpx-bar-fg, var(--dtpr-teal));
	font-size: .8rem;
	border-radius: 50%;
}
.dt-promo-bar__close:hover { background: rgb(0 0 0 / .08); }

/* ---- one surface, and it is the pet card's Call Us button ----
 *
 * Lifted verbatim from .pet-card .dt-pet__btn--call (header.css:2722): the
 * same 135deg deep-teal sweep, the same white lettering, the same peach icon.
 * A visitor scrolling from the bar to the pet grid sees one colour used twice
 * rather than two teals that nearly agree.
 *
 * This is UNCONDITIONAL — it ignores the "Bar colour" picker, by request. The
 * six per-palette surfaces that used to live here (blush, sage, peach, ivory,
 * navy) are gone, so choosing any of them now yields this same bar. The field
 * is left in the schema so nothing stored is lost and restoring per-campaign
 * colour is only this block coming back.
 */
.dt-promo-bar--solid {
	background: linear-gradient(135deg, #3D5155 0%, #4a6367 100%);
	--dtpx-bar-fg: #fff;
}

/*
 * Every piece of ink in the bar is white, set as TOKENS rather than as a list
 * of element selectors.
 *
 * --dtpx-quiet and --dtpx-head are declared by the hero's palette blocks and
 * by nothing else, so inside a bar they fell through to their defaults —
 * --dtpr-teal on a teal bar, the same colour twice. "Offer ends in" and every
 * DAYS / HOURS / MINUTES / SECONDS label were invisible; only the digits,
 * which had their own white rule, came through. Tokens fix the parts that
 * exist today and any countdown part added later.
 */
.dt-promo-bar {
	--dtpx-quiet: #fff;
	--dtpx-head: #fff;
}
.dt-promo-bar .dt-promo-countdown,
.dt-promo-bar .dt-promo-countdown__num,
.dt-promo-bar .dt-promo-bar__close { color: #fff; }
.dt-promo-bar .dt-promo-bar__close:hover { background: rgb(255 255 255 / .16); }

/* ---- custom background image, with an enforced legibility tint ---- */
.dt-promo-bar--image {
	background-image: var(--dtpx-bar-img);
	background-size: cover;
	background-position: var(--dtpx-bar-focal, 50% 50%);
	background-repeat: no-repeat;
}
/* A separate tint element rather than background-blend-mode, so colour and
   strength stay independent tokens and the minimum alpha can be enforced on
   the server. */
.dt-promo-bar--image::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	background: rgb(var(--dtpx-bar-tint-rgb, 61 81 85) / var(--dtpx-bar-tint-a, .86));
}
.dt-promo-bar--image.dt-promo-bar--tint-teal  { --dtpx-bar-tint-rgb: 61 81 85;    --dtpx-bar-fg: #fff; }
.dt-promo-bar--image.dt-promo-bar--tint-navy  { --dtpx-bar-tint-rgb: 46 51 78;    --dtpx-bar-fg: #fff; }
.dt-promo-bar--image.dt-promo-bar--tint-ivory { --dtpx-bar-tint-rgb: 250 250 250; --dtpx-bar-fg: var(--dtpr-ink); }

@media (max-width: 575.98px) {
	.dt-promo-bar--image { --dtpx-bar-tint-a: calc(var(--dtpx-bar-tint-a, .86) + .04); }
}

/*
 * The phone bar.
 *
 * Left to itself it stacked into three full-width rows — message, countdown,
 * then a link marooned on the left with the close button 170px away on the
 * right — and stood 151px tall, about a fifth of the screen, above a hero that
 * was already carrying the same offer and a much bigger countdown.
 *
 * The close button comes out of the flow (it is chrome, not content, and it was
 * claiming a whole row for a 44px target), the link centres under the message,
 * and the type comes down a step. Nothing is hidden and nothing is clipped —
 * the bar still grows freely if the message is long or the text is zoomed.
 */
@media (max-width: 767.98px) {
	.dt-promo-bar__inner {
		padding-inline-end: 2.6rem;   /* room for the absolutely-placed close */
		row-gap: .3rem;
		padding-block: .45rem;
	}
	.dt-promo-bar__close {
		position: absolute;
		inset-block-start: 50%;
		inset-inline-end: .1rem;
		transform: translateY(-50%);
		inline-size: 40px;
		block-size: 40px;
	}
	.dt-promo-bar__msg {
		font-size: .88rem;
		line-height: 1.3;
		text-align: center;
	}
	.dt-promo-bar__cta {
		min-block-size: 36px;
		font-size: .86rem;
	}
	/*
	 * The countdown stays, but as one quiet centred line rather than a 48px
	 * band hugging the left edge while the message and the link are centred
	 * above and below it.
	 */
	.dt-promo-bar .dt-promo-countdown {
		gap: .15rem .4rem;
		justify-content: center;
		inline-size: 100%;
	}
	.dt-promo-bar .dt-promo-countdown__units { justify-content: center; }
	.dt-promo-bar .dt-promo-countdown__label { flex: 0 0 100%; text-align: center; }
	.dt-promo-bar .dt-promo-countdown__unit { min-inline-size: 0; }
	.dt-promo-bar .dt-promo-countdown__num { font-size: .86rem; }
	.dt-promo-bar .dt-promo-countdown__unitlabel { font-size: .58rem; }
	.dt-promo-bar .dt-promo-countdown__label { font-size: .6rem; }
}

/* =========================================================================
   Corner badge
   ========================================================================= */

.dt-promo-badge {
	position: fixed;
	z-index: 1035;
	display: grid;
	grid-template-columns: 1fr auto;
	align-items: start;
	gap: .1rem;
	inline-size: max-content;
	max-inline-size: min(21rem, calc(100vw - 2 * var(--dtpx-inline, 1.1rem) - 1rem));
	padding: .5rem .5rem .5rem .95rem;
	border-radius: var(--dtpr-r-badge);
	background: var(--dtpx-badge-bg, #fff);
	color: var(--dtpx-badge-fg, var(--dtpr-ink));
	/*
	 * A deeper, tighter shadow plus a hairline: a spread-only shadow let it
	 * dissolve into a cream page, which is most of this site. The inset
	 * highlight is the same one the bar carries, and it is what keeps a dark
	 * block from reading as a hole punched in the page.
	 */
	box-shadow: var(--dtpr-shadow-badge),
	            inset 0 1px 0 rgba(255, 255, 255, .14);
	overflow: hidden;
	transition: opacity var(--dtpr-t-fast) var(--dtpr-ease),
	            transform var(--dtpr-t-fast) var(--dtpr-ease),
	            box-shadow var(--dtpr-t-fast) var(--dtpr-ease);

	/*
	 * The booking pill sits on clamp(1rem, 2.5vw, 1.75rem) (header.css:2936).
	 * The badge joins that baseline rather than inventing its own offset, so
	 * the corner reads as one row instead of a stack.
	 */
	--dtpx-base:   clamp(1rem, 2.5vw, 1.75rem);
	--dtpx-inline: calc(var(--dtpx-badge-x, var(--dtpx-base)) + var(--dtpx-safe-i, 0px));
	--dtpx-block:  calc(var(--dtpx-badge-y, var(--dtpx-base)) + var(--dtpx-safe-b, 0px) + var(--dtpx-stack, 0px));
}

/* ---- one surface, matching the announcement bar ----
 *
 * The same 135deg deep-teal sweep as .pet-card .dt-pet__btn--call and the
 * promo bar. On a cream page a white badge is the one thing that CANNOT stand
 * out — it is the page's own colour with a shadow — which is why this reads
 * as furniture until it goes dark.
 *
 * UNCONDITIONAL, like the bar: the "Badge colour" picker no longer changes it.
 * The per-palette surfaces that used to sit here are gone; the field stays in
 * the schema so nothing stored is lost and restoring them is this block
 * coming back.
 */
.dt-promo-badge {
	--dtpx-badge-bg:    linear-gradient(135deg, #3D5155 0%, #4a6367 100%);
	--dtpx-badge-fg:    #fff;
	--dtpx-badge-quiet: #fff;
}
.dt-promo-badge__title { color: #fff; }

.dt-promo-badge--bl { left: var(--dtpx-inline);  bottom: var(--dtpx-block);
	--dtpx-safe-i: env(safe-area-inset-left, 0px);  --dtpx-safe-b: env(safe-area-inset-bottom, 0px); }
.dt-promo-badge--br { right: var(--dtpx-inline); bottom: var(--dtpx-block);
	--dtpx-safe-i: env(safe-area-inset-right, 0px); --dtpx-safe-b: env(safe-area-inset-bottom, 0px); }
.dt-promo-badge--tl { left: var(--dtpx-inline);  top: var(--dtpx-block);
	--dtpx-safe-i: env(safe-area-inset-left, 0px);
	--dtpx-safe-b: calc(env(safe-area-inset-top, 0px) + var(--dt-adminbar-h, 0px) + var(--dtpx-header-clear, 0px)); }
.dt-promo-badge--tr { right: var(--dtpx-inline); top: var(--dtpx-block);
	--dtpx-safe-i: env(safe-area-inset-right, 0px);
	--dtpx-safe-b: calc(env(safe-area-inset-top, 0px) + var(--dt-adminbar-h, 0px) + var(--dtpx-header-clear, 0px)); }

/* The header is sticky at top:0, so a top-corner badge has to clear it. */
.dt-promo-badge--tl, .dt-promo-badge--tr {
	--dtpx-header-clear: calc(var(--dt-header-h, 0px) + var(--dt-promo-bar-h, 0px));
}

/* Defensive only: the theme disables the admin bar site-wide (functions.php:42). */
body.admin-bar { --dt-adminbar-h: 32px; }
@media (max-width: 782px) { body.admin-bar { --dt-adminbar-h: 46px; } }

.dt-promo-badge__link {
	display: grid;
	grid-template-columns: auto 1fr auto;
	align-items: center;
	gap: .6rem;
	min-block-size: 44px;
	padding: .45rem .3rem .45rem 0;
	text-decoration: none;
	color: inherit;
	border-radius: var(--dtpr-r-md);
}
.dt-promo-badge:not(.dt-promo-badge--with-thumb) .dt-promo-badge__link {
	grid-template-columns: 1fr auto;
}
.dt-promo-badge__thumb { inline-size: 48px; block-size: 48px; border-radius: 50%; object-fit: cover; }
.dt-promo-badge__text  { display: grid; gap: .1rem; min-inline-size: 0; }
/*
 * The badge is an OFFER, so it should read like one: the number is the thing
 * worth seeing from the corner of your eye, and the occasion is the supporting
 * line. It used to set both at nearly the same size, which made it look like a
 * notification rather than a promotion.
 */
.dt-promo-badge__title {
	font-family: var(--dtpr-font-display);
	font-size: 1.45rem;
	font-weight: 400;
	line-height: 1.05;
	letter-spacing: -.005em;
	color: var(--dtpx-badge-fg, var(--dtpr-teal));
	text-wrap: balance;
}
.dt-promo-badge__sub {
	font-family: var(--dtpr-font-ui);
	font-size: .74rem;
	line-height: 1.25;
	font-weight: 700;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--dtpx-badge-quiet, var(--dtpr-teal));
	opacity: var(--dtpr-quiet);
}
.dt-promo-badge__go {
	/* Teal on blush, not white: white on blush measures 1.92:1. */
	color: var(--dtpr-teal);
	background: linear-gradient(135deg, var(--dtpr-blush) 0%, var(--dtpr-blush-deep) 100%);
	inline-size: 2rem;
	block-size: 2rem;
	border-radius: 50%;
	display: grid;
	place-items: center;
	font-size: .8rem;
	flex: 0 0 auto;
	transition: transform var(--dtpr-t-fast) var(--dtpr-ease),
	            background var(--dtpr-t-fast) var(--dtpr-ease);
}
/* A blush chip on a blush or peach badge disappears; on the dark surfaces it
   is the wrong weight. Flip to the complementary gradient in both cases. */
/* Peach on the teal ground — the warm chip is what catches the eye in the
   corner, and teal-deep on peach is 7.82:1. */
.dt-promo-badge__go {
	background: linear-gradient(135deg, var(--dtpr-peach) 0%, var(--dtpr-peach-soft) 100%);
	color: var(--dtpr-teal-deep);
}
.dt-promo-badge__link:hover .dt-promo-badge__go {
	transform: translateX(2px);
	background: linear-gradient(135deg, var(--dtpr-butter) 0%, var(--dtpr-peach-soft) 100%);
	color: var(--dtpr-teal-deep);
}

/* A left accent bar ties it to the offer without adding a starburst. */
.dt-promo-badge::before {
	content: "";
	position: absolute;
	/* Full height, not inset: the pill clips to a large radius, so an inset bar
	   was cut down to a sliver at both ends and read as a rendering fault. */
	inset-block: 0;
	inset-inline-start: 0;
	inline-size: 5px;
	background: var(--dtpr-blush);
}
.dt-promo-badge::before { background: linear-gradient(180deg, var(--dtpr-peach) 0%, var(--dtpr-butter) 100%); }

.dt-promo-badge:hover {
	transform: translateY(-3px);          /* the theme lifts floating chrome by 3 */
	box-shadow: var(--dtpr-shadow-badge-hover);
}
@media (prefers-reduced-motion: reduce) {
	.dt-promo-badge, .dt-promo-badge:hover { transform: none; transition: opacity .18s ease; }
	.dt-promo-badge__link:hover .dt-promo-badge__go { transform: none; }
	.dt-promo-popup__card { animation: none !important; }
	.dt-promo-popup__bubble,
	.dt-promo-popup__bubble:hover { transform: none !important; }

	/* Every flourish added in the Character section above. */
	.dt-promo-bar--solid::after,
	.dt-promo-cta--primary::after,
	.dt-promo-popup__bubble::after,
	.dt-promo-popup__confetti { animation: none !important; }
	.dt-promo-popup__confetti { opacity: .85 !important; transform: none !important; }
	.dt-promo-badge { animation: none !important; }
}

.dt-promo-badge__close {
	inline-size: 44px;
	block-size: 44px;
	display: grid;
	place-items: center;
	border: 0;
	border-radius: 50%;
	background: none;
	cursor: pointer;
	color: inherit;
	font-size: .72rem;
}
/* The badge is dark now; a black wash on it is invisible. */
.dt-promo-badge__close:hover { background: rgb(255 255 255 / .16); }

/* ---- collisions with UI that actually exists in this theme ---- */

/*
 * .dt-floating-cta is fixed bottom-RIGHT on every page at every width
 * (header.css:2934), which is why the badge defaults to the LEFT corner here.
 * A marketer can still choose the right corner, so it has to survive that:
 * lift it clear of the pill rather than letting the two overlap.
 */
body.dt-has-floating-cta .dt-promo-badge--br {
	--dtpx-stack: calc(var(--dt-floating-cta-h, 62px) + .6rem);
}

/* The mobile pet CTA bar owns the full width of the bottom edge on pet pages. */
body.has-sticky-bar .dt-promo-badge--bl,
body.has-sticky-bar .dt-promo-badge--br {
	--dtpx-stack: calc(var(--dt-sticky-cta-h, 72px) + .6rem);
}

@media (max-width: 991.98px) {
	/*
	 * .dt-sticky-cta only exists below this breakpoint (single-product.css:1879)
	 * and spans the whole bottom edge, so BOTH corners have to clear it — there
	 * is no gutter to sit in the way there is beside the booking pill.
	 */
	body:has(.dt-sticky-cta.is-visible) .dt-promo-badge--bl,
	body:has(.dt-sticky-cta.is-visible) .dt-promo-badge--br {
		--dtpx-stack: calc(var(--dt-sticky-cta-h, 72px) + .6rem);
	}
}

/*
 * Under ~360px the badge and the booking pill genuinely do not fit on one line
 * — the arithmetic runs out, and squeezing the badge further would leave an
 * ellipsis where the offer should be. It steps up a line instead, which is the
 * honest outcome rather than a chip nobody can read.
 */
@media (max-width: 359.98px) {
	body.dt-has-floating-cta .dt-promo-badge--bl {
		--dtpx-stack: calc(var(--dt-floating-cta-h, 62px) + .6rem);
	}
}

/*
 * Get out of the way of anything the visitor deliberately opened. :has() keeps
 * this in CSS rather than depending on a body class some other script has to
 * remember to set — Bootstrap's offcanvas and modal add no such class.
 */
body:has(.offcanvas.show) .dt-promo-badge,
body:has(.modal.show) .dt-promo-badge,
body:has(.offcanvas.show) .dt-promo-bar {
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
}

/* ---- genuinely compact on a phone, not a shrunken card ---- */
@media (max-width: 767.98px) {
	.dt-promo-badge--m-bl { left: var(--dtpx-inline); right: auto; bottom: var(--dtpx-block); top: auto; }
	.dt-promo-badge--m-br { right: var(--dtpx-inline); left: auto; bottom: var(--dtpx-block); top: auto; }
	.dt-promo-badge--m-tl { left: var(--dtpx-inline); right: auto; top: var(--dtpx-block); bottom: auto; }
	.dt-promo-badge--m-tr { right: var(--dtpx-inline); left: auto; top: var(--dtpx-block); bottom: auto; }
}

@media (max-width: 767.98px) {
	.dt-promo-badge { max-inline-size: calc(100vw - 2 * var(--dtpx-inline)); }

	/*
	 * Compact is the phone default, and on a phone it has one job: sit in the
	 * bottom row next to the booking pill without pushing it off centre. That
	 * caps it at roughly the left gutter, so the arrow goes, the occasion goes
	 * under the title as a single small line, and the type comes down.
	 */
	/*
	 * The budget is the left gutter beside the centred booking pill — about
	 * 82px on a 390px screen. Three items on one row only works if this one is
	 * a chip. The occasion drops out here rather than the offer: on a phone the
	 * announcement bar is already carrying "Columbus Day event — 30% off select
	 * puppies", so repeating it in the corner spends the width twice.
	 */
	.dt-promo-badge--compact {
		padding: .25rem .15rem .25rem .4rem;
		gap: 0;
		border-radius: var(--dtpr-r-pill, 999px);
		/*
		 * Sized to the actual gutter, not to a guess. The booking pill is
		 * centred and about 190px wide, so the space to its left is
		 * (100vw - 190px)/2, less this badge's own inset and a breathing gap —
		 * i.e. 50vw - 124px. Below that the row cannot hold three things and
		 * the badge steps up a line instead (see the query below).
		 */
		max-inline-size: max(60px, calc(50vw - 124px));
	}
	.dt-promo-badge--compact::before { inline-size: 3px; }
	.dt-promo-badge--compact .dt-promo-badge__link { gap: .15rem; padding: .15rem 0; min-block-size: 38px; }
	.dt-promo-badge--compact .dt-promo-badge__title {
		/* Scales with the gutter it has to live in, so the offer shrinks to fit
		   rather than being cut to "30% O…". The ellipsis stays as a backstop
		   for a label far longer than "30% Off". */
		font-size: clamp(.54rem, 2.7vw, .84rem);
		line-height: 1.05;
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}
	.dt-promo-badge--compact .dt-promo-badge__sub   { display: none; }
	.dt-promo-badge--compact .dt-promo-badge__go    { display: none; }
	.dt-promo-badge--compact .dt-promo-badge__thumb { inline-size: 26px; block-size: 26px; }
	.dt-promo-badge--compact .dt-promo-badge__close { inline-size: 20px; block-size: 38px; font-size: .52rem; }

	/* Not compact: keep the roomier pill, and it gets lifted instead (above). */
	.dt-promo-badge:not(.dt-promo-badge--compact) .dt-promo-badge__title { font-size: 1.2rem; }
	.dt-promo-badge:not(.dt-promo-badge--compact) .dt-promo-badge__go { inline-size: 1.75rem; block-size: 1.75rem; font-size: .72rem; }
	.dt-promo-badge__thumb { inline-size: 40px; block-size: 40px; }
}

/* An explicit, admin-chosen hide. Never an automatic "the layout broke". */
.dt-promo-badge--m-hidden { display: none; }
@media (min-width: 768px) { .dt-promo-badge--m-hidden { display: grid; } }

/* =========================================================================
   Popup

   A centred card over the page, and the little pill it minimises to. One root
   element holds both: the client replaces a placement by swapping the node
   carrying data-dt-promo, so a bubble living outside it would be orphaned by
   the first revalidation.
   ========================================================================= */

.dt-promo-popup {
	/* Stacked (no picture, or a narrow screen) and side-by-side are different
	   shapes and need different budgets — a two-up card at 34rem gives each
	   half 17rem, which is narrower than the text wants. */
	--dtpx-popup-max: 34rem;
	--dtpx-popup-max-wide: 54rem;
}
.dt-promo-popup--sm { --dtpx-popup-max: 27rem; --dtpx-popup-max-wide: 46rem; }
.dt-promo-popup--lg { --dtpx-popup-max: 41rem; --dtpx-popup-max-wide: 62rem; }

.dt-promo-popup__dialog {
	position: fixed;
	inset: 0;
	z-index: 1060;               /* over the mobile menu (1045), under the
	                                deposit-PIN and warranty modals (1080+) */
	display: grid;
	place-items: center;
	padding: clamp(1rem, 4vw, 2.5rem);
}
.dt-promo-popup__dialog[hidden] { display: none; }

.dt-promo-popup__backdrop {
	position: absolute;
	inset: 0;
	background: rgb(42 58 61 / .55);
	backdrop-filter: blur(3px);
	-webkit-backdrop-filter: blur(3px);
}

.dt-promo-popup__card {
	position: relative;
	inline-size: min(100%, var(--dtpx-popup-max));

	/*
	 * Fitting the screen is a property of the CARD, not something the content
	 * is trusted to respect.
	 *
	 * The card used to be the scroller: max-block-size plus overflow-y on the
	 * whole thing. That does keep it inside the viewport, but the picture is
	 * the first child, so on a laptop the photograph filled the frame and the
	 * headline, the countdown and the button were all below the fold of a box
	 * most people never think to scroll. The offer was there and invisible.
	 *
	 * Now the card is a grid that owns its height, the BODY is the only
	 * scroller, and the button is pinned to the bottom of it — so whatever
	 * else has to give, the thing you are meant to press is on screen.
	 */
	display: grid;
	grid-template-rows: auto minmax(0, 1fr);
	max-block-size: calc(100dvh - 2rem);
	border-radius: 20px;
	background: var(--dtpx-popup-bg, var(--dtpr-cream));
	color: var(--dtpx-popup-fg, var(--dtpr-ink));
	border: 1.5px solid var(--dtpr-white-line);
	box-shadow: var(--dtpr-shadow-lg);
	/* Clips the accent bar and the picture to the rounded corners. */
	overflow: hidden;
	animation: dt-promo-popup-in .45s var(--dtpr-ease) var(--dtpx-popup-delay, 0s) both;
}

@keyframes dt-promo-popup-in {
	from { opacity: 0; transform: translateY(14px) scale(.985); }
	to   { opacity: 1; transform: none; }
}

.dt-promo-popup__close {
	position: absolute;
	inset-block-start: .55rem;
	inset-inline-end: .55rem;
	z-index: 2;
	inline-size: 44px;
	block-size: 44px;
	display: grid;
	place-items: center;
	border: 0;
	border-radius: 50%;
	background: rgb(255 255 255 / .82);
	color: var(--dtpr-teal);
	cursor: pointer;
	font-size: .8rem;
	box-shadow: var(--dtpr-shadow-sm);
	transition: background var(--dtpr-t-fast) var(--dtpr-ease);
}
.dt-promo-popup__close:hover { background: #fff; }

/*
 * A gradient hairline across the top of the card.
 *
 * This is the theme's own tell — the page-title band closes with a blush rule,
 * the corner badge carries a gradient edge — and it is the cheapest signal that
 * a surface was designed rather than defaulted. Without it a cream card on a
 * cream page is just a rectangle.
 */
.dt-promo-popup__card::before {
	content: '';
	position: absolute;
	inset-block-start: 0;
	inset-inline: 0;
	block-size: 4px;
	z-index: 3;
	background: linear-gradient(90deg,
		var(--dtpr-blush) 0%, var(--dtpr-blush-deep) 34%,
		var(--dtpr-peach) 68%, var(--dtpr-butter) 100%);
}
/* On the dark surfaces the same bar in peach reads as a warm filament. */
.dt-promo-popup--pal-teal .dt-promo-popup__card::before,
.dt-promo-popup--pal-navy .dt-promo-popup__card::before {
	background: linear-gradient(90deg,
		var(--dtpr-peach) 0%, var(--dtpr-butter) 50%, var(--dtpr-blush) 100%);
}

/* The ground is a wash, not a flat fill — the same move every section on the
   site makes. Only on the light surfaces; the dark two stay solid so white
   text keeps the contrast its floor guarantees. */
.dt-promo-popup--pal-ivory .dt-promo-popup__card {
	background: linear-gradient(160deg, #fffaf5 0%, #fef6ed 55%, #fef0e2 100%);
}

.dt-promo-popup__media {
	/*
	 * Stacked, the picture is capped in VIEWPORT units, not given a ratio.
	 * 8/5 of a 34rem card is 340px of photograph before a single word — on a
	 * 700px-tall laptop that is half the screen spent on the least important
	 * half of the offer. A vh cap means the picture yields as the screen gets
	 * shorter, which is exactly the right thing to give up.
	 */
	position: relative;
	overflow: hidden;
	min-block-size: 0;
	block-size: clamp(120px, 24vh, 260px);
}
.dt-promo-popup__img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	object-position: var(--dtpx-popup-focal, 50% 50%);
	display: block;
}

.dt-promo-popup__body {
	/* A frame, not a scroller: a growable row and a fixed foot. */
	display: grid;
	grid-template-rows: minmax(0, 1fr) auto;
	min-block-size: 0;
}
.dt-promo-popup__scroll {
	display: grid;
	justify-items: center;
	align-content: start;
	text-align: center;
	gap: .8rem;
	padding: clamp(1.25rem, 3.5vw, 2rem) clamp(1.25rem, 3.5vw, 2rem) .9rem;
	min-block-size: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
}
.dt-promo-popup__foot {
	display: grid;
	justify-items: center;
	gap: .5rem;
	padding: .2rem clamp(1.25rem, 3.5vw, 2rem) clamp(1.1rem, 3vw, 1.6rem);
	/* The card's own ground, so copy scrolling up behind the foot dissolves
	   into it rather than stopping at a hard edge. */
	background: var(--dtpx-popup-bg, var(--dtpr-cream));
	position: relative;
}
.dt-promo-popup__foot::before {
	content: '';
	position: absolute;
	inset-inline: 0;
	inset-block-start: -1.4rem;
	block-size: 1.4rem;
	pointer-events: none;
	background: linear-gradient(to top, var(--dtpx-popup-bg, var(--dtpr-cream)), transparent);
}
.dt-promo-popup--pal-ivory .dt-promo-popup__foot,
.dt-promo-popup--pal-ivory .dt-promo-popup__foot::before {
	/* The ivory card is a gradient, and its foot sits at the warm end of it. */
	background: #fef0e2;
}
.dt-promo-popup--pal-ivory .dt-promo-popup__foot::before {
	background: linear-gradient(to top, #fef0e2, rgb(254 240 226 / 0));
}

/*
 * The countdown, sized for a popup column rather than a hero band.
 *
 * The shared unit is clamp(4.4rem … 6rem) wide, which is right under a
 * full-bleed headline and too wide for the ~26rem text column of a two-up
 * card: four units broke to three-plus-one, and a lone "24 SECONDS" on its
 * own row reads as a layout fault rather than as a clock.
 */
.dt-promo-popup .dt-promo-countdown__unit {
	min-inline-size: clamp(3.3rem, 2.6rem + 1.6vw, 4.3rem);
	padding: .45rem .45rem .4rem;
}
.dt-promo-popup .dt-promo-countdown__num   { font-size: clamp(1.35rem, 3.4vw, 1.85rem); }
.dt-promo-popup .dt-promo-countdown__units { gap: .4rem; }
.dt-promo-popup .dt-promo-countdown        { gap: .45rem .5rem; }

/* =========================================================================
   The popup, side by side

   With a picture and room for it, the card turns into two columns. This is
   the single biggest thing keeping the popup on screen: the same content in
   one narrow column is roughly twice as tall, which is what pushed the button
   under the fold on every laptop.

   :has() rather than a class from PHP — the template already renders the
   media div only when a picture exists, so the DOM is the honest source and
   there is no second flag to keep in step.
   ========================================================================= */

@media (min-width: 48em) {
	.dt-promo-popup__card:has(.dt-promo-popup__media) {
		inline-size: min(100%, var(--dtpx-popup-max-wide));
		grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
		grid-template-rows: minmax(0, 1fr);
	}
	/* Full-height column: no ratio, no cap — it simply matches whatever the
	   words next to it need, so there is never a letterboxed gap. */
	.dt-promo-popup__card:has(.dt-promo-popup__media) .dt-promo-popup__media {
		block-size: auto;
		max-block-size: none;
	}
	.dt-promo-popup__card:has(.dt-promo-popup__media) .dt-promo-popup__scroll {
		text-align: start;
		justify-items: start;
		padding: clamp(1.5rem, 2.6vw, 2.4rem) clamp(1.5rem, 2.6vw, 2.4rem) .9rem;
	}
	.dt-promo-popup__card:has(.dt-promo-popup__media) .dt-promo-popup__foot {
		justify-items: stretch;
		padding-inline: clamp(1.5rem, 2.6vw, 2.4rem);
	}
	/* A hairline between the halves, the same rule the split hero uses. */
	.dt-promo-popup__card:has(.dt-promo-popup__media) .dt-promo-popup__media::after {
		content: '';
		position: absolute;
		inset-block: 0;
		inset-inline-end: 0;
		inline-size: 1px;
		background: linear-gradient(to bottom, transparent, rgb(61 81 85 / .16) 12%,
		                                       rgb(61 81 85 / .16) 88%, transparent);
	}
}

/* =========================================================================
   Short screens

   A laptop at 1440x780, and every phone held sideways. Height is the scarce
   axis here, not width, so the picture and the padding give way first and the
   type follows — rather than the button sliding off the bottom.
   ========================================================================= */

@media (max-height: 44em) {
	.dt-promo-popup__media { block-size: clamp(90px, 16vh, 170px); }
	.dt-promo-popup__scroll { gap: .6rem; padding: 1.1rem 1.25rem .7rem; }
	.dt-promo-popup__foot   { padding: .2rem 1.25rem 1rem; }
	.dt-promo-popup__title { font-size: clamp(1.35rem, 3.2vw, 1.75rem); }
	.dt-promo-popup__stamp { font-size: clamp(1.9rem, 6vw, 2.6rem); }
	.dt-promo-popup__lede  { font-size: .95rem; }
}
@media (max-height: 34em) {
	/* Below this the picture is costing more than it gives. */
	.dt-promo-popup__card:not(:has(.dt-promo-popup__media)) { grid-template-rows: minmax(0, 1fr); }
	.dt-promo-popup__media { display: none; }
	.dt-promo-popup__card  { grid-template-rows: minmax(0, 1fr); }
	.dt-promo-popup__text  { display: none; }
}

/* The big claim. Display face, because this is the one line meant to be read
   from across the room. */
.dt-promo-popup__stamp {
	font-family: var(--dtpr-font-display);
	font-size: clamp(2.4rem, 8vw, 3.6rem);
	font-weight: 400;
	line-height: 1;
	letter-spacing: -.01em;
	color: var(--dtpx-popup-head, var(--dtpr-teal));
}

.dt-promo-popup__title {
	font-family: var(--dtpr-font-display);
	font-size: clamp(1.6rem, 4vw, 2.2rem);
	font-weight: 400;
	line-height: 1.08;
	letter-spacing: -.005em;
	margin: 0;
	color: var(--dtpx-popup-head, var(--dtpr-teal));
	text-wrap: balance;
}

.dt-promo-popup__lede {
	font-family: var(--dtpr-font-serif);
	font-style: italic;
	font-size: 1.02rem;
	line-height: 1.5;
	margin: 0;
	color: var(--dtpx-popup-fg, var(--dtpr-ink));
	text-wrap: pretty;
}

.dt-promo-popup__text {
	font-family: var(--dtpr-font-ui);
	font-size: .95rem;
	line-height: 1.6;
	color: var(--dtpx-popup-fg, var(--dtpr-ink));
	max-inline-size: 42ch;
}
.dt-promo-popup__text p { margin: 0 0 .6rem; }
.dt-promo-popup__text p:last-child { margin-block-end: 0; }

/*
 * The button is pinned to the foot of the scroller.
 *
 * Sticky, not fixed, and inside the body rather than outside it: long copy
 * then scrolls UNDER it instead of pushing it away, so there is no state in
 * which the offer is readable and unclickable. The fade is what stops a line
 * of text ending flush against the button's edge as it passes behind.
 */
.dt-promo-popup__cta {
	justify-self: stretch;
	text-align: center;

	/* Teal, the same gradient as the pet-card Call Us button, the promo bar
	   and the corner badge. White on it is 8.38:1. The blush fill this used
	   to carry is the site's *secondary* weight and read as the lighter of
	   two actions when it is the only one. */
	background: linear-gradient(135deg, #3D5155 0%, #4a6367 100%);
	border-color: transparent;
	color: #fff;
	box-shadow: 0 8px 22px -10px rgba(61, 81, 85, .55);
}
.dt-promo-popup__cta:hover,
.dt-promo-popup__cta:focus-visible {
	background: linear-gradient(135deg, #2f4044 0%, #3d5155 100%);
	color: #fff;
	box-shadow: 0 12px 26px -10px rgba(61, 81, 85, .65);
}
/* On the dark popup surfaces a teal button on a teal card is one shape; the
   warm fill is the one that separates. */
.dt-promo-popup--pal-teal .dt-promo-popup__cta,
.dt-promo-popup--pal-navy .dt-promo-popup__cta {
	background: linear-gradient(135deg, var(--dtpr-peach) 0%, var(--dtpr-peach-soft) 100%);
	color: var(--dtpr-teal-deep);
}
.dt-promo-popup--pal-teal .dt-promo-popup__cta:hover,
.dt-promo-popup--pal-navy .dt-promo-popup__cta:hover {
	background: linear-gradient(135deg, var(--dtpr-butter) 0%, var(--dtpr-peach-soft) 100%);
	color: var(--dtpr-teal-deep);
}

.dt-promo-popup__fine {
	font-family: var(--dtpr-font-ui);
	font-size: .74rem;
	line-height: 1.4;
	margin: 0;
	max-inline-size: 46ch;
	color: var(--dtpx-popup-quiet, var(--dtpr-ink-soft));
	opacity: var(--dtpr-quiet);
}

/* ---- surfaces ---- */
/* Teal, not ink-soft: the fine print carries --dtpr-quiet (.9) on top of its
   colour, and ink-soft on cream is 4.31:1 BEFORE that multiplier — already
   under AA, and 3.1:1 after it. Teal is what the hero's own ivory surface
   uses for the same role, so this also brings the two into line. */
.dt-promo-popup--pal-ivory { --dtpx-popup-bg: var(--dtpr-cream); --dtpx-popup-fg: var(--dtpr-ink);  --dtpx-popup-head: var(--dtpr-teal);  --dtpx-popup-quiet: var(--dtpr-teal); }
.dt-promo-popup--pal-sage  { --dtpx-popup-bg: var(--dtpr-sage);  --dtpx-popup-fg: var(--dtpr-navy); --dtpx-popup-head: var(--dtpr-navy);  --dtpx-popup-quiet: var(--dtpr-navy); }
.dt-promo-popup--pal-peach { --dtpx-popup-bg: var(--dtpr-peach); --dtpx-popup-fg: var(--dtpr-ink);  --dtpx-popup-head: var(--dtpr-teal);  --dtpx-popup-quiet: var(--dtpr-teal); }
/* Blush takes ink for body copy: teal on blush is 4.36:1, fine for the stamp
   and the title, below AA for anything smaller. */
.dt-promo-popup--pal-blush { --dtpx-popup-bg: var(--dtpr-blush); --dtpx-popup-fg: var(--dtpr-ink);  --dtpx-popup-head: var(--dtpr-teal);  --dtpx-popup-quiet: var(--dtpr-navy); }
.dt-promo-popup--pal-teal  { --dtpx-popup-bg: var(--dtpr-teal);  --dtpx-popup-fg: #fff;             --dtpx-popup-head: #fff;              --dtpx-popup-quiet: #fff; }
.dt-promo-popup--pal-navy  { --dtpx-popup-bg: var(--dtpr-navy);  --dtpx-popup-fg: #fff;             --dtpx-popup-head: #fff;              --dtpx-popup-quiet: #fff; }

.dt-promo-popup--pal-teal .dt-promo-popup__close,
.dt-promo-popup--pal-navy .dt-promo-popup__close {
	background: rgb(255 255 255 / .16);
	color: #fff;
}
.dt-promo-popup--pal-teal .dt-promo-popup__close:hover,
.dt-promo-popup--pal-navy .dt-promo-popup__close:hover { background: rgb(255 255 255 / .3); }

/* The popup's primary button follows the same palette-aware logic the hero's
   does, for the same reason: blush on blush disappears. */
.dt-promo-popup--pal-blush .dt-promo-cta--primary {
	background: linear-gradient(135deg, var(--dtpr-teal) 0%, var(--dtpr-teal-light) 100%);
	color: #fff;
	box-shadow: 0 8px 24px rgba(61, 81, 85, .28);
}
.dt-promo-popup--pal-teal .dt-promo-cta--primary,
.dt-promo-popup--pal-navy .dt-promo-cta--primary {
	background: linear-gradient(135deg, var(--dtpr-peach) 0%, var(--dtpr-peach-soft) 100%);
	color: var(--dtpr-teal-deep);
	box-shadow: 0 8px 24px rgba(238, 204, 170, .32);
}

/* ---- the reminder bubble ---- */
.dt-promo-popup__bubble-wrap {
	position: fixed;
	z-index: 1036;               /* just above the badge, below the booking pill */
	display: inline-flex;
	align-items: center;
	gap: .15rem;
	inset-block-end: calc(clamp(1rem, 2.5vw, 1.75rem) + env(safe-area-inset-bottom, 0px) + var(--dtpx-bubble-stack, 0px));
}
.dt-promo-popup--bub-bl .dt-promo-popup__bubble-wrap { inset-inline-start: calc(clamp(1rem, 2.5vw, 1.75rem) + env(safe-area-inset-left, 0px)); }

/*
 * A badge and a reminder bubble in the same corner. Both default to the left,
 * because the booking pill owns the right on every page — so rather than
 * forbidding the combination, the bubble steps up over the badge. promo.js
 * measures the badge and publishes --dt-promo-badge-h; the body class tells us
 * which corner it landed in.
 */
body.dt-promo-badge-bl .dt-promo-popup--bub-bl .dt-promo-popup__bubble-wrap {
	--dtpx-bubble-stack: calc(var(--dt-promo-badge-h, 0px) + .6rem);
}
.dt-promo-popup--bub-br .dt-promo-popup__bubble-wrap { inset-inline-end: calc(clamp(1rem, 2.5vw, 1.75rem) + env(safe-area-inset-right, 0px)); }

/* While the dialog is open the bubble is redundant and would sit under the
   backdrop anyway. */
.dt-promo-popup.is-open .dt-promo-popup__bubble-wrap { display: none; }

.dt-promo-popup__bubble {
	display: inline-flex;
	align-items: center;
	gap: .5rem;
	padding: .6rem 1.1rem;
	border: 1px solid var(--dtpr-white-line);
	border-radius: var(--dtpr-r-pill);
	background: linear-gradient(135deg, var(--dtpr-blush) 0%, var(--dtpr-blush-deep) 100%);
	color: var(--dtpr-teal);
	font-family: var(--dtpr-font-ui);
	font-size: .82rem;
	font-weight: 700;
	letter-spacing: .04em;
	cursor: pointer;
	box-shadow: var(--dtpr-shadow-blush);
	transition: transform var(--dtpr-t-fast) var(--dtpr-ease),
	            box-shadow var(--dtpr-t-fast) var(--dtpr-ease);
}
.dt-promo-popup__bubble:hover { transform: translateY(-3px); box-shadow: 0 14px 30px rgba(217, 178, 175, .5); }
.dt-promo-popup__bubble-icon { font-size: .95rem; }

.dt-promo-popup__bubble-close {
	inline-size: 44px;
	block-size: 44px;
	display: grid;
	place-items: center;
	border: 0;
	border-radius: 50%;
	background: none;
	color: var(--dtpr-teal);
	cursor: pointer;
	font-size: .7rem;
}
.dt-promo-popup__bubble-close:hover { background: rgba(61, 81, 85, .08); }

/* An explicit, admin-chosen hide. Never an automatic "the layout broke". */
@media (max-width: 767.98px) {
	.dt-promo-popup--m-hidden { display: none !important; }
}

/*
 * The editor preview frame drops a fragment into a static stage with the
 * production stylesheet and no JavaScript, so a dialog that starts hidden
 * would preview as an empty box. This is the only placement that needs such an
 * override — the other three are in-flow or already painted.
 */
.dt-promo-popup.is-promo-preview .dt-promo-popup__dialog,
.dt-promo-popup.is-promo-preview .dt-promo-popup__dialog[hidden] {
	position: static;
	/* !important is load-bearing here, not laziness: Bootstrap's reboot ships
	   [hidden] { display: none !important } and the preview frame loads
	   Bootstrap, so without it the popup previews as an empty box. */
	display: grid !important;
	padding: 0;
}
.dt-promo-popup.is-promo-preview .dt-promo-popup__backdrop,
.dt-promo-popup.is-promo-preview .dt-promo-popup__bubble-wrap { display: none; }
.dt-promo-popup.is-promo-preview .dt-promo-popup__card { animation: none; }

/* =========================================================================
   Character

   The theme's own flourish grammar, borrowed rather than reinvented: one long
   loop that stays completely still for roughly four fifths of it, then a brief
   coordinated moment — a sheen crossing, a sparkle, a small wiggle — and back
   to still. That is what .dt-fb does, and it is why the site feels alive
   without ever nagging. Loops that animate continuously read as a banner ad.

   Everything here is decoration on ::before/::after or aria-hidden spans, so a
   screen reader encounters none of it, and all of it is switched off under
   prefers-reduced-motion at the bottom of this file.
   ========================================================================= */

@keyframes dt-promo-sheen {
	0%, 78%, 100% { transform: translateX(-115%); opacity: 0; }
	82%           { opacity: 1; }
	92%           { transform: translateX(115%); opacity: 0; }
}
@keyframes dt-promo-glint {
	0%, 82%, 100% { opacity: 0; transform: scale(0) translate(0, 0); }
	86%           { opacity: 1; transform: scale(1) translate(2px, -3px); }
	92%           { opacity: 0; transform: scale(.4) translate(9px, -13px); }
}
@keyframes dt-promo-bob {
	0%, 100% { transform: translateY(0); }
	50%      { transform: translateY(-4px); }
}
@keyframes dt-promo-ring {
	0%   { box-shadow: 0 0 0 0 rgba(217, 178, 175, .55); }
	70%  { box-shadow: 0 0 0 18px rgba(217, 178, 175, 0); }
	100% { box-shadow: 0 0 0 0 rgba(217, 178, 175, 0); }
}
@keyframes dt-promo-confetti {
	0%   { opacity: 0; transform: scale(0); }
	60%  { opacity: 1; transform: scale(1.3); }
	100% { opacity: .85; transform: scale(1); }
}

/* ---- the hero's ground is never a flat field ----------------------------
   A single solid colour across a full-bleed band is the one thing that reads
   as un-designed on this site; every section the theme ships lays a warm wash
   and two soft blooms over its base. Light surfaces get blush and peach,
   the two dark ones get a warmer, much weaker glow so the words stay first. */
.dt-promo-hero:not(.dt-promo-hero--photo)::before,
.dt-promo-hero:not(.dt-promo-hero--photo)::after {
	content: '';
	position: absolute;
	pointer-events: none;
	z-index: 0;
	border-radius: 50%;
}
.dt-promo-hero:not(.dt-promo-hero--photo)::before {
	inset-block-start: -18%;
	inset-inline-start: -10%;
	inline-size: 48%;
	block-size: 82%;
	background: radial-gradient(circle, var(--dtpx-bloom-a, rgba(234, 191, 189, .35)), transparent 66%);
}
.dt-promo-hero:not(.dt-promo-hero--photo)::after {
	inset-block-end: -20%;
	inset-inline-end: -12%;
	inline-size: 52%;
	block-size: 84%;
	background: radial-gradient(circle, var(--dtpx-bloom-b, rgba(238, 204, 170, .32)), transparent 66%);
}

.dt-promo-hero--pal-sage  { --dtpx-bloom-a: rgba(255, 255, 255, .42); --dtpx-bloom-b: rgba(238, 204, 170, .30); }
.dt-promo-hero--pal-peach { --dtpx-bloom-a: rgba(255, 255, 255, .45); --dtpx-bloom-b: rgba(217, 178, 175, .32); }
.dt-promo-hero--pal-blush { --dtpx-bloom-a: rgba(255, 250, 245, .40); --dtpx-bloom-b: rgba(238, 204, 170, .34); }
/* Weaker on the dark surfaces: a bloom strong enough to see here would lift
   the ground under white text and eat the contrast the floors guarantee. */
.dt-promo-hero--pal-teal  { --dtpx-bloom-a: rgba(238, 204, 170, .12); --dtpx-bloom-b: rgba(188, 201, 197, .10); }
.dt-promo-hero--pal-navy  { --dtpx-bloom-a: rgba(217, 178, 175, .12); --dtpx-bloom-b: rgba(241, 230, 178, .09); }

/* ---- the announcement bar earns a gradient and one slow sheen ---------- */
.dt-promo-bar { position: relative; overflow: hidden; }
.dt-promo-bar__inner { position: relative; z-index: 1; }
.dt-promo-bar--solid::after {
	content: '';
	position: absolute;
	inset: 0;
	pointer-events: none;
	z-index: 0;
	background: linear-gradient(110deg, transparent 35%, rgba(255, 255, 255, .38) 50%, transparent 65%);
	animation: dt-promo-sheen 9s ease-in-out infinite;
	will-change: transform, opacity;
}
/* A hairline of light along the top edge, so the strip reads as a surface
   rather than a block of colour sitting on the page. */
.dt-promo-bar--solid { box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14); }

/* ---- the badge breathes, very slightly ---- */
.dt-promo-badge { animation: dt-promo-bob 6s ease-in-out infinite; }
.dt-promo-badge:hover { animation-play-state: paused; }

/* ---- the popup keeps the character the retired module had --------------- */
.dt-promo-popup__card { position: relative; }

/* A sunburst behind the discount stamp. Low opacity on purpose: it should
   read as warmth behind the number, never as a starburst sticker. */
.dt-promo-popup--with-stamp .dt-promo-popup__stamp { position: relative; }
.dt-promo-popup--with-stamp .dt-promo-popup__stamp::before {
	content: '';
	position: absolute;
	inset-block-start: 50%;
	inset-inline-start: 50%;
	inline-size: 190px;
	block-size: 190px;
	transform: translate(-50%, -50%);
	z-index: -1;
	pointer-events: none;
	opacity: .32;
	background: conic-gradient(from 0deg,
		var(--dtpr-butter) 0deg 16deg, transparent 16deg 36deg,
		var(--dtpr-butter) 36deg 52deg, transparent 52deg 72deg,
		var(--dtpr-butter) 72deg 88deg, transparent 88deg 108deg,
		var(--dtpr-butter) 108deg 124deg, transparent 124deg 144deg,
		var(--dtpr-butter) 144deg 160deg, transparent 160deg 180deg,
		var(--dtpr-butter) 180deg 196deg, transparent 196deg 216deg,
		var(--dtpr-butter) 216deg 232deg, transparent 232deg 252deg,
		var(--dtpr-butter) 252deg 268deg, transparent 268deg 288deg,
		var(--dtpr-butter) 288deg 304deg, transparent 304deg 324deg,
		var(--dtpr-butter) 324deg 340deg, transparent 340deg 360deg);
	mask-image: radial-gradient(circle, #000 30%, transparent 70%);
	-webkit-mask-image: radial-gradient(circle, #000 30%, transparent 70%);
}
/* On the two dark surfaces the butter rays glare. Warm them down. */
.dt-promo-popup--pal-teal .dt-promo-popup__stamp::before,
.dt-promo-popup--pal-navy .dt-promo-popup__stamp::before { opacity: .16; }

.dt-promo-popup__confetti {
	position: absolute;
	inline-size: 10px;
	block-size: 10px;
	border-radius: 50%;
	z-index: 4;
	pointer-events: none;
	opacity: 0;
	animation: dt-promo-confetti 1.4s ease-out forwards;
}
.dt-promo-popup__confetti--1 { inset-block-start: -6px;  inset-inline-start: 18%;  background: var(--dtpr-blush);  animation-delay: .40s; }
.dt-promo-popup__confetti--2 { inset-block-start: 12%;   inset-inline-end: -6px;   background: var(--dtpr-butter); inline-size: 14px; block-size: 14px; animation-delay: .55s; }
.dt-promo-popup__confetti--3 { inset-block-end: 22%;     inset-inline-start: -6px; background: var(--dtpr-peach);  animation-delay: .70s; }
.dt-promo-popup__confetti--4 { inset-block-end: -6px;    inset-inline-end: 24%;    background: var(--dtpr-maroon); inline-size: 8px; block-size: 8px; animation-delay: .85s; }

/* The reminder bubble pulses a soft blush ring, the way the theme's own
   floating chrome does, so a minimised offer stays findable. */
.dt-promo-popup__bubble { position: relative; }
.dt-promo-popup__bubble::after {
	content: '';
	position: absolute;
	inset: 0;
	border-radius: inherit;
	pointer-events: none;
	animation: dt-promo-ring 2.6s ease-out infinite;
}

/* ---- a glint on the primary button, once per loop ---- */
.dt-promo-cta--primary { position: relative; overflow: hidden; }
.dt-promo-cta--primary::after {
	content: '';
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: linear-gradient(110deg, transparent 38%, rgba(255, 255, 255, .45) 50%, transparent 62%);
	animation: dt-promo-sheen 7s ease-in-out infinite;
	will-change: transform, opacity;
}
.dt-promo-cta--primary > * { position: relative; z-index: 1; }

/* =========================================================================
   Reduced motion
   Every animation and transform here needs an explicit opt-out; the theme's
   own reduced-motion blocks are per-feature, not global.
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
	.dt-promo-hero *,
	.dt-promo-bar,
	.dt-promo-badge { animation: none !important; }
	.dt-promo-badge { transition: none !important; }
}

/* =========================================================================
   Shop archives
   Those templates have no hero of their own — they render the global page-title
   band. When a promotion takes that band's place we keep the breadcrumb trail
   beneath it, without the band's own background or padding.
   ========================================================================= */

.header-title--promo {
	background: none;
	padding-block: .75rem 0;
}
.header-title--promo .breadcrumbs { margin: 0; }
