/*
 * factory-base baseline chrome + layout.
 *
 * theme-core.css is the SHARED (cross-lane) design language and deliberately
 * stays lane-agnostic; it does not know about this WordPress theme's markup
 * (df-site-header / df-site-nav / df-site-footer) or the structural helpers the
 * seeded content uses (df-section, df-flow, df-list, the inquiry form, the blog).
 * This stylesheet supplies that WordPress baseline so every tenant renders as a
 * navigable, laid-out site out of the box. It is written ENTIRELY against the
 * --df-* tokens, so a client's skin still drives all color/type - never hardcode
 * a brand value here, and never style one client. Enqueued after the skin in
 * functions.php so the tokens are resolved.
 */

/* ---- Layout helpers ---------------------------------------------------- */
/* In-page jumps (the anchor bar, any "back to top") glide instead of teleporting,
   so a visitor keeps their bearings and sees what they scrolled past. Gated on
   prefers-reduced-motion: for anyone who asks the OS for less animation this
   stays an instant jump. Pairs with the scroll-margin-top on anchored sections,
   which keeps the sticky header from covering the heading on arrival. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
.df-flow > * + * { margin-block-start: var(--df-space-4); }
/* Section rhythm is its own knob (defaults to space.12, the previous literal),
   because the vertical beat of a site is a brand decision independent of the
   general spacing scale. */
.df-section { padding-block: var(--df-space-section); }
.df-section--muted { background: var(--df-color-surface-subtle); }
.df-section__title { font-size: var(--df-font-size-2xl); margin-block-end: var(--df-space-6); }
.df-main { display: block; }

/* ---- Site header + primary nav ---------------------------------------- */
.df-site-header {
  border-block-end: 1px solid var(--df-color-line);
  background: var(--df-color-surface-default);
  position: sticky;
  top: 0;
  z-index: 50;
}
.df-site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--df-space-6);
  padding-block: var(--df-space-4);
}
.df-site-header__brand {
  font-family: var(--df-font-family-serif);
  font-size: var(--df-font-size-xl);
  font-weight: var(--df-font-weight-bold);
  color: var(--df-color-brand-secondary);
  text-decoration: none;
  white-space: nowrap;
}
.df-site-header__brand { display: inline-flex; align-items: center; flex: none; }
.df-site-header__brand .df-brand__logo { display: block; width: auto; height: 2.75rem; }
@media (max-width: 40rem) {
  .df-site-header__brand .df-brand__logo { height: 2.25rem; }
}
.df-site-nav__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--df-space-2);
}
.df-site-nav__list li { position: relative; margin: 0; }
.df-site-nav__list a {
  display: block;
  padding: var(--df-space-2) var(--df-space-3);
  color: var(--df-color-text-default);
  text-decoration: none;
  font-weight: var(--df-font-weight-medium);
  font-size: var(--df-font-size-sm);
  border-radius: var(--df-radius-sm);
  white-space: nowrap;
}
.df-site-nav__list a:hover,
.df-site-nav__list a:focus,
.df-site-nav__list .sub-menu .current-menu-item > a,
.df-site-nav__list .sub-menu [aria-current="page"] {
  color: var(--df-color-brand-primary);
  background: var(--df-color-surface-subtle);
}
/* "You are here" on the bar itself is a thin rule under the section's name, never
   the hover pill: a pill on a resting item reads as a stuck dropdown, and the
   bar would look different on every page of a section. The ancestor counts
   too, so a service page marks its family exactly like the family's catalog. */
.df-site-nav__list > li:is(.current-menu-item, .current-menu-ancestor) > a {
  color: var(--df-color-brand-primary);
}
@media (min-width: 75rem) {
  .df-site-nav__list > li:is(.current-menu-item, .current-menu-ancestor) > a:not(:hover):not(:focus) {
    background: linear-gradient(currentColor, currentColor) no-repeat
      left var(--df-space-3) bottom 0.3rem / calc(100% - 2 * var(--df-space-3)) 2px;
  }
}
/* Dropdown submenus (family -> service). */
.df-site-nav__list .sub-menu {
  list-style: none;
  margin: 0;
  padding: var(--df-space-2);
  position: absolute;
  inset-inline-start: 0;
  top: 100%;
  min-width: 20rem;
  background: var(--df-color-surface-default);
  border: 1px solid var(--df-color-line);
  border-radius: var(--df-radius-md);
  box-shadow: var(--df-shadow-md);
  display: none;
  z-index: 60;
}
.df-site-nav__list .sub-menu .sub-menu { top: 0; inset-inline-start: 100%; }
/* Service names are sentences, not nav points: they wrap inside a dropdown
   rather than stretching it to the width of the longest one. */
.df-site-nav__list .sub-menu a { white-space: normal; }

/* Mega panel: a dropdown whose OWN items have children is not a cascade of
   fly-outs but one wide panel, a column per child - the "Other Services" shape,
   where three families and their services have to be scannable at once. The
   :has() test is structural, so a menu earns the layout by being three levels
   deep; browsers without :has() keep the plain fly-out cascade. */
@media (min-width: 75rem) {
  /* The panel spans the header's container, not the one nav item it hangs off:
     the item goes position:static so the panel resolves against the container
     instead, which is what keeps a wide panel from running off the page edge on
     the last nav point. */
  .df-site-header__inner { position: relative; }
  .df-site-nav__list > li:has(> .sub-menu > li > .sub-menu) { position: static; }
  /* Hover bridge. The panel hangs off the header container, so a strip of header
     padding sits between the nav item and the panel's top edge; crossing it with
     the pointer would leave both, drop :hover and close the panel before it can
     be reached. The panel carries a transparent extension of itself over that
     strip - part of the panel, so hovering it keeps the item hovered, and it
     exists only while the panel is open. */
  .df-site-nav__list > li > .sub-menu:has(> li > .sub-menu)::before {
    content: "";
    position: absolute;
    inset-inline: 0;
    bottom: 100%;
    height: var(--df-space-6);
  }
  .df-site-nav__list > li > .sub-menu:has(> li > .sub-menu) {
    inset-inline: 0;
    padding: var(--df-space-6);
    gap: var(--df-space-6);
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    background: var(--df-color-surface-subtle);
  }
  .df-site-nav__list > li:hover > .sub-menu:has(> li > .sub-menu),
  .df-site-nav__list > li:focus-within > .sub-menu:has(> li > .sub-menu) { display: grid; }
  /* Inside the panel the columns are laid out by the grid, so their own
     submenus stop being absolute fly-outs and just flow under the heading. */
  .df-site-nav__list .sub-menu:has(> li > .sub-menu) > li > .sub-menu {
    display: block;
    position: static;
    min-width: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    background: none;
  }
  /* The child is the column heading: a quiet label above its own services, and
     no disclosure caret - nothing expands, the column is already open. */
  .df-site-nav__list .sub-menu:has(> li > .sub-menu) > li.menu-item-has-children > a::after { content: none; }
  .df-site-nav__list .sub-menu:has(> li > .sub-menu) > li > a {
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: var(--df-font-weight-bold);
    color: var(--df-color-text-muted);
    margin-block-end: var(--df-space-2);
  }
}
/* The row that opens a list: that family's inquiry form, as the outlined CTA
   the approved nav mock puts at the top of every dropdown. */
.df-site-nav__list .df-nav-inquiry { margin-block-end: var(--df-space-2); }
.df-site-nav__list .df-nav-inquiry > a {
  text-align: center;
  color: var(--df-color-brand-primary);
  font-weight: var(--df-font-weight-bold);
  border: 1px solid color-mix(in srgb, var(--df-color-brand-primary) 35%, transparent);
  border-radius: var(--df-radius-md);
}
.df-site-nav__list .df-nav-inquiry > a:hover,
.df-site-nav__list .df-nav-inquiry > a:focus {
  background: var(--df-color-brand-primary);
  border-color: var(--df-color-brand-primary);
  color: var(--df-color-text-inverse);
}

/* The row that closes a column: the family's own catalog landing. */
.df-site-nav__list .df-nav-seeall > a {
  color: var(--df-color-brand-primary);
  font-weight: var(--df-font-weight-bold);
}
.df-site-nav__list .df-nav-seeall > a::after { content: " \2192"; }
@media (min-width: 75rem) {
  .df-site-nav__list .df-nav-seeall {
    margin-block-start: var(--df-space-2);
    padding-block-start: var(--df-space-2);
    border-block-start: 1px solid var(--df-color-line);
  }
}

/* Header actions: the global chrome CTAs (Contact / Quote), beside the nav.
   Which item is the filled button is a content decision - a menus.json item
   marks itself with "class": "df-nav-cta" - not a position this theme guesses. */
.df-site-actions__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--df-space-2);
}
.df-site-actions__list li { margin: 0; }
.df-site-actions__list a {
  display: block;
  padding: var(--df-space-2) var(--df-space-3);
  color: var(--df-color-text-default);
  text-decoration: none;
  font-weight: var(--df-font-weight-medium);
  font-size: var(--df-font-size-sm);
  border-radius: var(--df-radius-sm);
  white-space: nowrap;
}
.df-site-actions__list a:hover,
.df-site-actions__list a:focus { color: var(--df-color-brand-primary); }
.df-site-actions__list .df-nav-cta > a {
  background: var(--df-color-brand-primary);
  color: var(--df-color-text-inverse);
  border-radius: var(--df-radius-md);
  padding-inline: var(--df-space-4);
}
.df-site-actions__list .df-nav-cta > a:hover,
.df-site-actions__list .df-nav-cta > a:focus {
  color: var(--df-color-text-inverse);
  opacity: 0.9;
}

/* Toggles. The hamburger and the per-family disclosure buttons only exist below
   the nav breakpoint; each media query below hides the pair it does not use. */
.df-nav-toggle {
  display: none;
  align-items: center;
  gap: var(--df-space-2);
  font: inherit;
  font-size: var(--df-font-size-sm);
  font-weight: var(--df-font-weight-medium);
  cursor: pointer;
  padding: var(--df-space-2) var(--df-space-3);
  border: 1px solid var(--df-color-line);
  border-radius: var(--df-radius-md);
  background: var(--df-color-surface-default);
  color: var(--df-color-text-default);
}
.df-nav-toggle__bars,
.df-nav-toggle__bars::before,
.df-nav-toggle__bars::after {
  display: block;
  width: 1.125rem;
  height: 2px;
  background: currentColor;
  content: "";
}
.df-nav-toggle__bars { position: relative; }
.df-nav-toggle__bars::before { position: absolute; top: -6px; }
.df-nav-toggle__bars::after { position: absolute; top: 6px; }
.df-subnav-toggle {
  display: none;
  font: inherit;
  cursor: pointer;
  background: none;
  border: 0;
  padding: var(--df-space-2) var(--df-space-3);
  color: inherit;
}
.df-subnav-toggle > span {
  display: block;
  width: 0.5rem;
  height: 0.5rem;
  border-inline-end: 2px solid currentColor;
  border-block-end: 2px solid currentColor;
  transform: rotate(45deg);
  transform-origin: 65% 65%;
}
.is-open > .df-subnav-toggle > span { transform: rotate(225deg); }

/* ---- Desktop nav (>= 75rem) -------------------------------------------
   75rem is where the families plus the chrome CTAs stop fitting on one
   line at this type scale; it is a layout threshold, not a device. */
@media (min-width: 75rem) {
  /* Nav and chrome CTAs share one row; the panel is only a stacking container
     below the breakpoint. Without this they wrap to a second line as soon as a
     site has more than a handful of families. */
  .df-site-header__panel {
    display: flex;
    align-items: center;
    gap: var(--df-space-4);
  }
  .df-site-nav__list li:hover > .sub-menu,
  .df-site-nav__list li:focus-within > .sub-menu { display: block; }
  .df-site-nav__list .menu-item-has-children > a::after { content: " \25be"; opacity: 0.6; }
}
/* Just above the breakpoint the row is at its tightest: close up the spacing
   between items so it stays on one line instead of wrapping to two. */
@media (min-width: 75rem) and (max-width: 84.999rem) {
  .df-site-header__inner { gap: var(--df-space-4); }
  .df-site-header__panel { gap: var(--df-space-3); }
  .df-site-nav__list { gap: var(--df-space-1); }
  .df-site-nav__list > li > a { padding-inline: var(--df-space-2); }
}

/* ---- Collapsed nav (< 75rem) ------------------------------------------
   Guarded by .js-nav (set by js/nav.js): without the script there is no toggle
   to reopen the panel, so it must stay visible rather than lock the site down. */
@media (max-width: 74.999rem) {
  .df-site-header__inner { flex-wrap: wrap; row-gap: var(--df-space-3); }
  .df-nav-toggle { display: inline-flex; }
  .df-subnav-toggle { display: block; }

  .df-site-header__panel { width: 100%; }
  .js-nav .df-site-header__panel { display: none; }
  .js-nav .df-site-header.is-nav-open .df-site-header__panel {
    display: block;
    max-height: calc(100vh - 5rem);
    overflow-y: auto;
    padding-block-end: var(--df-space-4);
  }

  .df-site-nav__list,
  .df-site-actions__list { flex-direction: column; align-items: stretch; gap: 0; }
  .df-site-nav__list > li { border-block-start: 1px solid var(--df-color-line); }
  .df-site-nav__list a,
  .df-site-actions__list a { padding-block: var(--df-space-3); white-space: normal; }

  /* Parent row: link on the left, disclosure button on the right. The button is
     what opens the children - tapping the parent still follows its own link. */
  .df-site-nav__list .menu-item-has-children > a { display: inline-block; }
  .df-site-nav__list .menu-item-has-children {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
  }
  .df-site-nav__list .menu-item-has-children > .sub-menu { grid-column: 1 / -1; }

  .df-site-nav__list .sub-menu {
    position: static;
    min-width: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 0 0 var(--df-space-2) var(--df-space-4);
  }
  .df-site-nav__list li.is-open > .sub-menu { display: block; }

  .df-site-actions {
    margin-block-start: var(--df-space-4);
    padding-block-start: var(--df-space-4);
    border-block-start: 1px solid var(--df-color-line);
  }
  .df-site-actions__list .df-nav-cta > a { text-align: center; }
}

/* ---- Footer ------------------------------------------------------------ */
/* Closing band: an optional closing row (headline + the ways to reach the
   business), the brand column (logo, tagline, credential badges) plus one
   column per top-level footer menu item (heading + its children), then the
   copyright beside the service area. Near-black by design - it is the end of
   the page, not another section - with the column headings in the brand's
   accent and the badges outlined in its second accent. */
.df-site-footer {
  position: relative;
  padding-block: clamp(48px, 6vw, 72px) 32px;
  background: #101010;
  color: rgba(255,255,255,0.8);
  font-size: 14.5px;
}
.df-site-footer > .df-container { position: relative; z-index: 1; }

.df-site-footer__cta {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  align-items: end;
  gap: var(--df-space-8);
  padding-block-end: var(--df-space-12);
  margin-block-end: var(--df-space-12);
  border-block-end: 1px solid rgba(255,255,255,0.12);
}
.df-site-footer__title {
  margin: 0;
  color: var(--df-color-text-inverse);
  font-size: clamp(2rem, 1.2rem + 3vw, var(--df-font-size-4xl));
  line-height: 1.08;
  letter-spacing: -0.02em;
  font-weight: var(--df-font-weight-bold);
  max-width: 16ch;
}
.df-site-footer__text {
  margin: var(--df-space-4) 0 0;
  max-width: 44ch;
  font-size: var(--df-font-size-base);
  color: rgba(255,255,255,0.72);
}
.df-site-footer__reach {
  display: grid;
  justify-items: start;
  gap: var(--df-space-4);
}
.df-site-footer__reach .df-btn { margin-block-end: var(--df-space-2); }
.df-site-footer__line {
  display: grid;
  gap: 0.15rem;
  color: var(--df-color-text-inverse);
  font-size: var(--df-font-size-lg);
  font-weight: var(--df-font-weight-semibold);
  text-decoration: none;
  background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat;
  transition: background-size 0.35s ease, color 0.2s ease;
}
.df-site-footer__line:hover { color: var(--df-color-brand-accent); background-size: 100% 1px; }
.df-site-footer__line-label {
  font-size: var(--df-font-size-xs);
  font-weight: var(--df-font-weight-semibold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.5);
}

.df-site-footer__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: 48px;
}
.df-site-footer__name {
  color: var(--df-color-text-inverse);
  font-family: var(--df-font-family-serif);
  font-size: var(--df-font-size-lg);
  font-weight: var(--df-font-weight-bold);
  margin: 0;
}
.df-site-footer__name a { color: inherit; text-decoration: none; }
.df-site-footer__name .df-brand__logo { display: block; width: auto; height: 3rem; }
.df-site-footer__blurb {
  margin: 16px 0 20px;
  max-width: 34ch;
  font-size: 14.5px;
  line-height: 1.5;
  color: rgba(255,255,255,0.78);
}
/* The menu is itself the column set, so a tenant adds a column by adding a
   parent item - the theme never names the columns. Its items take their
   place in the outer grid beside the brand column. */
.df-site-footer__nav { display: contents; list-style: none; }
.df-site-footer__nav > li { margin: 0; }
.df-site-footer__nav > li > a,
.df-site-footer__nav > li > .df-menu-text__label {
  display: block;
  margin-block-end: 16px;
  color: var(--df-color-brand-accent);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
}
.df-site-footer__nav .sub-menu {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
}
.df-site-footer__nav .sub-menu li { margin: 0; }
.df-site-footer__nav .sub-menu a,
.df-site-footer__nav .sub-menu .df-menu-text__label {
  display: inline-block;
  color: rgba(255,255,255,0.8);
  text-decoration: none;
  transition: color 0.2s ease, transform 0.25s ease;
}
.df-site-footer__nav .sub-menu a:hover { color: #FFFFFF; transform: translateX(3px); }
/* Credentials as outlined pills under the tagline. */
.df-site-footer__meta {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.df-site-footer__meta > li {
  margin: 0;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--df-color-brand-accent2, var(--df-color-brand-accent)) 50%, transparent);
  color: color-mix(in srgb, var(--df-color-brand-accent2, var(--df-color-brand-accent)) 55%, #FFFFFF);
  font-size: 13px;
  font-weight: 600;
}
.df-site-footer__meta a { color: inherit; text-decoration: none; }
.df-site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-block-start: 64px;
  padding-block-start: 22px;
  border-block-start: 1px solid rgba(255,255,255,0.15);
  font-size: 13px;
  color: rgba(255,255,255,0.6);
}
.df-site-footer__copy,
.df-site-footer__area { margin: 0; color: inherit; }
@media (max-width: 74.999rem) {
  .df-site-footer__cta { grid-template-columns: 1fr; align-items: start; }
}

/* ---- Typographic helpers ---------------------------------------------- */
.df-eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: var(--df-font-size-sm);
  font-weight: var(--df-font-weight-bold);
  color: var(--df-color-brand-primary);
  margin-block-end: var(--df-space-2);
}
/* An eyebrow can be the page's h1 (a hero whose keyword heading sits in the
   small line above a decorative tagline). Drop the heading face and margin so it
   still reads as an eyebrow. */
h1.df-eyebrow {
  font-family: inherit;
  line-height: inherit;
  margin-block-start: 0;
}
.df-title { font-size: var(--df-font-size-3xl); }
.df-page-title { font-size: var(--df-font-size-3xl); margin-block-end: var(--df-space-6); }
.df-lead { font-size: var(--df-font-size-lg); color: var(--df-color-text-muted); }
.df-link { color: var(--df-color-brand-primary); font-weight: var(--df-font-weight-medium); }
.df-list { padding-inline-start: var(--df-space-4); }
.df-list li { margin-block: var(--df-space-2); }

/* Homepage hero (front-page.php). df-hero exists in theme-core; add the copy
   variants used by the seeded homepage. */
.df-hero { padding-block: var(--df-space-24) var(--df-space-16); background: var(--df-color-surface-warm); }
.df-hero__tagline { font-size: var(--df-font-size-xl); font-weight: var(--df-font-weight-bold); color: var(--df-color-brand-secondary); }
.df-hero__title { font-size: var(--df-font-size-4xl); }
.df-hero__lede { font-size: var(--df-font-size-lg); color: var(--df-color-text-muted); max-width: var(--df-container-narrow); }
.df-hero__actions { display: flex; flex-wrap: wrap; gap: var(--df-space-3); margin-block-start: var(--df-space-6); }

/* ---- Cards / related --------------------------------------------------- */
/* Content grids read one shared set of knobs instead of each inventing its own
   gap and column floor. Defaults are the literals these rules used before, so
   nothing moves; the point is that the rhythm is now changeable in ONE place.
   NOTE: the live reference has no grid system to copy - measured gaps there run
   170/156/96/54/52/40/1/0px with no cluster - so these values are a factory
   default awaiting a design decision, not an extracted one. See
   lanes/wordpress/clients/blinktexas/reference/style-extract.json. */
.df-card-grid {
  display: grid;
  gap: var(--df-grid-gap);
  grid-template-columns: repeat(auto-fit, minmax(var(--df-grid-min-column), 1fr));
}
/* Card shape comes from the card.* knobs (defaults reproduce the literals this
   rule used before: space.6 padding, a 1px line border, radius.lg, shadow.sm),
   so a brand can have flat borderless cards without touching the radius scale. */
.df-card {
  padding: var(--df-card-padding);
  border: var(--df-card-border-width) solid var(--df-color-line);
  border-radius: var(--df-card-radius);
  box-shadow: var(--df-card-shadow);
  background: var(--df-color-surface-default);
}
.df-card__title { font-size: var(--df-font-size-lg); margin-block-end: var(--df-space-2); }
.df-card__title a { text-decoration: none; color: var(--df-color-brand-secondary); }
.df-card__meta { color: var(--df-color-text-muted); font-size: var(--df-font-size-sm); }
/* A featured card: a top service drawn out of the grid. It takes two columns
   once the grid has room for them (spanning two in a one-column grid would add
   a phantom column), so two featured cards fill a four-column row. */
.df-card--featured {
  border-color: var(--df-color-brand-primary);
  background: color-mix(in srgb, var(--df-color-brand-primary) 4%, var(--df-color-surface-default));
}
.df-card--featured .df-card__title { font-size: var(--df-font-size-xl); }
@media (min-width: 48rem) {
  .df-card-grid > .df-card--featured { grid-column: span 2; }
}
.df-card__badge {
  display: inline-block;
  margin: 0;
  padding: 0.25rem 0.75rem;
  border-radius: 999px;
  background: var(--df-color-brand-primary);
  color: var(--df-color-text-inverse);
  font-size: var(--df-font-size-xs);
  font-weight: var(--df-font-weight-bold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.df-related {
  margin-block-start: var(--df-space-12);
  padding-block-start: var(--df-space-6);
  border-block-start: 1px solid var(--df-color-line);
}

/* Primary button = theme-core .df-btn with the brand fill (alias of the base). */
.df-btn--primary { background: var(--df-color-brand-primary); color: var(--df-color-text-inverse); }

/* ---- Inquiry form ------------------------------------------------------
   Shape mirrors the panel a visitor already knows from the client's live
   contact page: one elevated card, placeholder-only fields (labels stay in the
   DOM for screen readers), two per row, message full width. Every value is a
   --df-form-* / --df-field-* knob, so a skin sets its own card and field chrome
   without the theme growing a per-client branch. */
.df-inquiry {
  margin-block-start: var(--df-space-8);
  padding: var(--df-form-padding);
  border: var(--df-form-border-width) solid var(--df-color-line);
  border-radius: var(--df-form-radius);
  box-shadow: var(--df-form-shadow);
  background: var(--df-color-surface-default);
  max-width: var(--df-form-max-width);
}
.df-inquiry__title { font-size: var(--df-font-size-2xl); margin-block-end: var(--df-space-8); }
/* Two per row, as on the live form: an auto-fit track would slip to three on a
   wide card and break the pairing. */
.df-inquiry__grid {
  display: grid;
  gap: var(--df-form-gap);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.df-field { display: flex; flex-direction: column; gap: var(--df-space-2); }
/* Grid children are spaced by the grid gap; the full-width fields that sit
   directly in the form need that same rhythm as a margin. */
.df-inquiry > .df-field { margin-block-start: var(--df-form-gap); }
.df-field--full { grid-column: 1 / -1; }
/* The placeholder carries the label on screen (as on the live form), so the
   real label is available to assistive tech only. Never display:none - that
   would take it out of the accessibility tree too. */
.df-field__label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
/* Input chrome is token-driven (--df-field-*), so a skin sets the shape of its
   own form controls - radius, breathing room, shadow - without the theme
   growing a per-client branch. */
.df-field__input {
  font: inherit;
  padding: var(--df-field-padding-y) var(--df-field-padding-x);
  border: 1px solid var(--df-color-line);
  border-radius: var(--df-field-radius);
  box-shadow: var(--df-field-shadow);
  background: var(--df-color-surface-default);
  color: var(--df-color-text-default);
  width: 100%;
}
.df-field__input::placeholder { color: var(--df-color-text-muted); opacity: 1; }
.df-field__input:focus {
  border-color: var(--df-color-brand-primary);
  outline: 2px solid var(--df-color-brand-primary);
  outline-offset: 1px;
}
.df-field__input--textarea { min-height: 9.375rem; resize: vertical; }
/* Service picker: same chrome as a text input, with our own chevron so the
   native control does not break the row. */
.df-field__input--select {
  appearance: none;
  -webkit-appearance: none;
  padding-inline-end: calc(var(--df-field-padding-x) + 1.25rem);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%236d6d6d' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--df-field-padding-x) center;
  background-size: 0.75rem auto;
}
/* An unchosen Service reads as a placeholder, not as an answer. */
.df-field__input--select:has(option[value=""]:checked) { color: var(--df-color-text-muted); }
.df-inquiry .df-btn { margin-block-start: var(--df-form-gap); }
/* Copy that follows the card (the phone/email fallback) clears the card, rather
   than picking up the tighter .df-flow rhythm. */
.df-inquiry + * { margin-block-start: var(--df-space-8); }
.df-inquiry__errors {
  border: 1px solid var(--df-color-feedback-danger);
  color: var(--df-color-feedback-danger);
  border-radius: var(--df-radius-md);
  padding: var(--df-space-3) var(--df-space-4);
  margin-block-end: var(--df-space-4);
}
.df-inquiry__success {
  border: 1px solid var(--df-color-feedback-success);
  color: var(--df-color-feedback-success);
  border-radius: var(--df-radius-md);
  padding: var(--df-space-4);
}
/* The card sheds its desktop padding before the fields stack, so --df-form-padding
   stays a desktop knob and no skin has to describe a phone. */
@media (max-width: 61.9375rem) {
  .df-inquiry { padding: var(--df-space-12); }
}
@media (max-width: 47.9375rem) {
  .df-inquiry { padding: var(--df-space-8) var(--df-space-6); }
}
@media (max-width: 29.9375rem) {
  .df-inquiry__grid { grid-template-columns: 1fr; }
}

/* ---- Contact details panel ---------------------------------------------
   The "how to reach a human" band that sits under a contact form: a dark panel
   of ways to get in touch, flush against a photo that shares its rounding. Both
   halves are token-driven (--df-panel-*, --df-color-surface-deep), and below the
   phone breakpoint the photo goes on top and each half spans the row. */
.df-contact-info { padding-block: var(--df-space-section); }
/* Straight after the inquiry card the band would double the section rhythm; the
   card's own section already holds the gap. */
.df-section--overlap + .df-contact-info { padding-block-start: 0; }
.df-contact-info .df-section__title { max-width: 66.875rem; margin-inline: auto; }
.df-contact-info__row { display: flex; flex-wrap: wrap; align-items: center; }
.df-contact-info__panel {
  flex: 0 1 43.5%;
  /* Without this a flex item never shrinks below its content, and an icon plus a
     long email address pushed the panel past the screen edge on a phone. */
  min-width: 0;
  box-sizing: border-box;
  padding: var(--df-panel-padding);
  border-radius: var(--df-panel-radius);
  background: var(--df-color-surface-deep);
  color: var(--df-color-text-inverse);
}
/* The photo butts against the panel, so only its outer corners are rounded. */
.df-contact-info__media {
  flex: 0 1 56.5%;
  min-width: 0;
  align-self: center;
  overflow: hidden;
  border-start-end-radius: var(--df-panel-radius);
  border-end-end-radius: var(--df-panel-radius);
}
.df-contact-info__media img { display: block; width: 100%; height: auto; }
.df-contact-info__item {
  display: flex;
  align-items: center;
  gap: var(--df-space-6);
  padding-block: var(--df-space-8);
  border-block-end: 1px solid rgba(255,255,255,0.18);
}
.df-contact-info__item:last-child { border-block-end: 0; }
.df-contact-info__icon { flex: 0 0 3rem; width: 3rem; }
.df-contact-info__icon img { display: block; width: 100%; height: auto; }
.df-contact-info__text { min-width: 0; }
.df-contact-info__label { color: rgba(255,255,255,0.85); margin: 0; }
.df-contact-info__value {
  /* Explicit both ways: the base p rule ships a bottom margin, which would sit
     between the value and the row's divider and open the row up. */
  margin-block: var(--df-space-2) 0;
  font-weight: var(--df-font-weight-bold);
  color: var(--df-color-text-inverse);
  overflow-wrap: anywhere;
}
.df-contact-info__value a { color: inherit; text-decoration: none; }
.df-contact-info__value a:hover { text-decoration: underline; }
@media (max-width: 47.9375rem) {
  /* Photo first, then the panel - the live order on a phone. */
  .df-contact-info__row { flex-wrap: wrap-reverse; gap: var(--df-space-2); }
  .df-contact-info__panel,
  .df-contact-info__media { flex-basis: 100%; }
  /* Same idea as .df-inquiry above: --df-panel-padding stays a desktop knob, and
     on a phone the panel keeps its rows the width they need. */
  .df-contact-info__panel { padding-inline: var(--df-space-6); }
  .df-contact-info__media { border-radius: var(--df-panel-radius); }
  .df-contact-info__item { padding-block: var(--df-space-4); }
}

/* ---- Blog -------------------------------------------------------------- */
.df-blog-filter {
  display: flex;
  flex-wrap: wrap;
  gap: var(--df-space-2);
  margin-block: var(--df-space-4) var(--df-space-8);
}
.df-blog-filter__item {
  padding: var(--df-space-1) var(--df-space-3);
  border: 1px solid var(--df-color-line);
  border-radius: var(--df-radius-full);
  text-decoration: none;
  color: var(--df-color-text-default);
  font-size: var(--df-font-size-sm);
}
.df-blog-filter__item.is-active,
.df-blog-filter__item:hover { background: var(--df-color-brand-primary); color: var(--df-color-text-inverse); }
.df-blog .df-blog-filter { margin-block-start: 0; }
/* auto-fill, not auto-fit: a lone post keeps a card's width instead of
   stretching across the page. */
.df-post-grid {
  display: grid;
  gap: var(--df-grid-post-gap);
  grid-template-columns: repeat(auto-fill, minmax(var(--df-grid-post-min-column), 1fr));
}
.df-post-card { display: flex; flex-direction: column; }
.df-post-card__body { display: flex; flex: 1; flex-direction: column; }
.df-post-card__body > :last-child { margin-block-start: auto; padding-block-start: var(--df-space-2); }
.df-post-card .df-card__media img { aspect-ratio: 16 / 9; }
.df-post-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--df-space-1) var(--df-space-3);
  margin: 0;
  color: var(--df-color-text-muted);
  font-size: var(--df-font-size-sm);
}
.df-post-card__cat {
  color: var(--df-color-brand-primary);
  font-weight: var(--df-font-weight-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.df-blog .nav-links { display: flex; flex-wrap: wrap; gap: var(--df-space-2); margin-block-start: var(--df-space-12); }
.df-blog .page-numbers {
  min-width: 2.5rem;
  padding: var(--df-space-2) var(--df-space-3);
  border: 1px solid var(--df-color-line);
  border-radius: var(--df-radius-full);
  text-align: center;
  text-decoration: none;
  color: var(--df-color-text-default);
}
.df-blog .page-numbers.current,
.df-blog a.page-numbers:hover { border-color: var(--df-color-brand-primary); background: var(--df-color-brand-primary); color: var(--df-color-text-inverse); }
.df-blog .page-numbers.dots { border-color: transparent; }
.df-blog-empty { max-width: 36rem; }
.df-blog-empty h2 { font-size: var(--df-font-size-xl); }

/* A post body in a comfortable reading measure. */
.df-post-section { padding-block-start: var(--df-space-12); }
.df-post__back { max-width: 44rem; margin-block-start: var(--df-space-12); }
.df-prose { max-width: 44rem; font-size: 1.0625rem; line-height: var(--df-font-line-height-relaxed); }
.df-prose > * + * { margin-block-start: 1.25em; }
.df-prose :is(h2, h3, h4) { margin-block: 2em 0.5em; line-height: var(--df-font-line-height-tight); }
.df-prose h2 { font-size: var(--df-font-size-xl); }
.df-prose h3 { font-size: var(--df-font-size-lg); }
.df-prose :is(h2, h3, h4) + * { margin-block-start: 0; }
.df-prose a { color: var(--df-color-brand-primary); text-decoration: underline; text-underline-offset: 0.15em; }
.df-prose :is(ul, ol) { padding-inline-start: 1.25em; }
.df-prose li + li { margin-block-start: 0.4em; }
.df-prose blockquote {
  margin-inline: 0;
  padding-inline-start: var(--df-space-6);
  border-inline-start: 3px solid var(--df-color-brand-primary);
  font-size: var(--df-font-size-lg);
}
.df-prose :is(img, figure) { max-width: 100%; height: auto; border-radius: var(--df-card-radius); }
.df-prose figure { margin-inline: 0; }
.df-prose figcaption { margin-block-start: var(--df-space-2); color: var(--df-color-text-muted); font-size: var(--df-font-size-sm); }
.df-post-related__title { font-size: var(--df-font-size-2xl); }

/* ---- Homepage sections -------------------------------------------------- */
/* The components an editorial front page is built from: an image hero, an
   in-page anchor bar, numbered service cards, a dark audience mosaic, a service
   -area map and a split closing CTA. All generic and token-driven - a tenant
   supplies the imagery through --df-hero-image / --df-audience-image and the
   colours come from its skin. */

/* Image hero: the photo rides on a custom property so the page body sets it
   without the theme knowing any tenant's asset URLs. */
.df-hero--image {
  position: relative;
  padding-block: var(--df-space-16);
  min-height: 35rem; /* 560px */
  display: flex;
  align-items: center;
  color: var(--df-color-text-inverse);
  /* The scrim is its own custom property so a hero variant can re-aim the
     darkening (a form hero needs the copy side much denser) without restating
     the whole background shorthand and the tenant's image URL with it. */
  background:
    var(--df-hero-scrim, linear-gradient(105deg, rgba(0,0,0,0.72) 0%, rgba(0,0,0,0.45) 55%, rgba(0,0,0,0.35) 100%)),
    var(--df-hero-image, linear-gradient(120deg, #1b1b1b, #3a3a3a)) center / cover no-repeat;
}
/* The hero centres its content vertically with flex, which makes the container
   a flex item - and a flex item shrinks to its content, so the container's own
   margin-inline:auto then centred the whole column instead of holding the page
   grid. Force it to span the row so the copy sits on the grid's left edge. */
.df-hero--image > .df-container { width: 100%; }
.df-hero--image .df-eyebrow { color: var(--df-color-brand-accent); }
/* On the image hero the tagline is the visual headline and the h1 carries the
   descriptive, keyword-bearing sentence - the split the Phase 1 SEO pass asked
   for, where the decorative line is NOT the h1. */
/* An emphasised word inside the tagline takes the second brand accent - the
   two-tone headline the brand uses on dark, photographic bands. Same <em>
   contract as .df-split-cta__tagline. */
.df-hero--image .df-hero__tagline em {
  font-style: normal;
  color: var(--df-color-brand-accent2, var(--df-color-brand-accent));
}
.df-hero--image .df-hero__tagline {
  font-size: var(--df-font-size-4xl);
  line-height: var(--df-font-line-height-tight);
  color: var(--df-color-text-inverse);
}
/* .df-hero__summary: the same descriptive line as a plain paragraph, for a hero
   whose h1 moved into the eyebrow slot (h1.df-eyebrow). */
.df-hero--image .df-hero__title,
.df-hero--image .df-hero__summary {
  font-size: var(--df-font-size-base);
  font-weight: var(--df-font-weight-regular);
  line-height: var(--df-font-line-height-normal);
  letter-spacing: var(--df-font-letter-spacing-body);
  color: rgba(255,255,255,0.9);
  max-width: var(--df-container-narrow);
  margin-block: var(--df-space-4) var(--df-space-6);
}
.df-hero__content { max-width: 48rem; }
.df-hero--image .df-hero__lede { color: rgba(255,255,255,0.9); }

/* Interior-page hero (a catalog or landing page): the same photo band, but the
   h1 IS the headline - there is no separate brand tagline above it - so it
   takes the display treatment the homepage gives its tagline. */
.df-hero--page .df-hero__title {
  font-size: var(--df-font-size-4xl);
  font-weight: var(--df-font-weight-bold);
  line-height: var(--df-font-line-height-tight);
  letter-spacing: var(--df-font-letter-spacing-heading);
  color: var(--df-color-text-inverse);
  max-width: none;
  margin-block: 0;
}
.df-hero--page .df-hero__lede { max-width: 36rem; margin-block-start: var(--df-space-6); }
.df-hero--page .df-hero__actions { margin-block-start: var(--df-space-8); }
@media (max-width: 47.9375rem) {
  .df-hero--page { min-height: 0; }
  .df-hero--page .df-hero__title { font-size: var(--df-font-size-3xl); }
  /* On a phone the copy takes the full width, but the desktop scrim is a
     105deg gradient that thins as it runs right (alpha 0.72 -> 0.35). The
     right-hand copy therefore lands on the thinnest part of the mask: on a
     photo with bright light trails the background behind a line measured
     luminance 0.49-0.55, i.e. white text at ~1.8:1, well under the 4.5:1 AA
     floor, while the left-hand lines measured ~6:1. Nothing looked broken,
     lines just looked faded. Swap the diagonal for a top-to-bottom mask that
     stays dense across the full width - 0.55 is the floor that keeps the
     brightest photo pixel under 4.5:1 against white - so every line, left or
     right, still reads. */
  .df-hero--image {
    --df-hero-scrim: linear-gradient(
      180deg,
      rgba(0, 0, 0, 0.55) 0%,
      rgba(0, 0, 0, 0.68) 45%,
      rgba(0, 0, 0, 0.8) 100%
    );
  }
}

/* Breadcrumb trail. Muted text on a plain page; on a photo hero it drops to a
   quiet white so it reads as a label above the eyebrow, not as a link row. */
.df-breadcrumb {
  font-size: var(--df-font-size-sm);
  color: var(--df-color-text-muted);
  margin-block-end: var(--df-space-6);
}
.df-breadcrumb__list { display: flex; flex-wrap: wrap; list-style: none; margin: 0; padding: 0; }
.df-breadcrumb__list li + li::before { content: "/"; margin-inline: var(--df-space-2); opacity: 0.6; }
.df-breadcrumb a { color: inherit; text-decoration: none; }
.df-breadcrumb a:hover { text-decoration: underline; }
.df-hero--image .df-breadcrumb { color: rgba(255,255,255,0.85); }
.df-hero--image .df-breadcrumb [aria-current] { color: rgba(255,255,255,0.6); }
/* A two-tone accent word in a page hero's h1 (same <em> contract as the
   homepage tagline). */
.df-hero--page .df-hero__title em { font-style: normal; color: var(--df-color-brand-accent2, var(--df-color-brand-accent)); }

/* ---- Content components ------------------------------------------------ */
/* What an interior page is built from, all token-driven: a two-column split, an
   icon list, a point list, steps, an FAQ accordion (native <details>, no
   script), tags, image cards and a photo CTA band. Introduced for the Webflow
   migration, where each live section maps onto one of these; nothing here
   names a tenant. */
.df-section--dark { background: var(--df-color-surface-dark); color: var(--df-color-text-inverse); }
.df-section--dark :is(h2, h3, .df-section__title) { color: var(--df-color-text-inverse); }
.df-section--dark .df-eyebrow { color: var(--df-color-brand-accent); }
.df-section--dark :is(p, li, .df-lead) { color: rgba(255,255,255,0.82); }
/* Cards stay light on a dark band: they are panels, not text on the band. */
.df-section--dark .df-card { color: var(--df-color-text-default); }
.df-section--dark .df-card :is(p, li) { color: var(--df-color-text-muted); }
.df-section--dark .df-card :is(h2, h3, .df-card__title) { color: var(--df-color-text-default); }
.df-section--image {
  background:
    linear-gradient(rgba(0,0,0,0.74), rgba(0,0,0,0.74)),
    var(--df-section-image) center / cover no-repeat,
    var(--df-color-surface-dark);
}
.df-actions { display: flex; flex-wrap: wrap; gap: var(--df-space-3); }
.df-figure { margin: 0; }
.df-figure img,
.df-split__media img { display: block; width: 100%; height: auto; border-radius: var(--df-radius-md); }

.df-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--df-space-12);
  align-items: center;
}
.df-split--media-first .df-split__media { order: -1; }
@media (max-width: 60rem) {
  .df-split { grid-template-columns: minmax(0, 1fr); gap: var(--df-space-8); }
  /* One column reads text first, whichever side the photo sat on. */
  .df-split--media-first .df-split__media { order: 0; }
}

.df-icon-list, .df-point-list, .df-steps, .df-tags { list-style: none; margin: 0; padding: 0; }
.df-icon-list { display: grid; gap: var(--df-space-4); }
.df-icon-list--grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); gap: var(--df-space-6); }
.df-icon-list__item { display: flex; gap: var(--df-space-4); align-items: flex-start; }
.df-icon-list__icon { flex: 0 0 auto; width: 2.5rem; height: 2.5rem; }
.df-icon-list__icon img { width: 100%; height: 100%; object-fit: contain; }
.df-icon-list__body > * { margin: 0; }
.df-icon-list__body > * + * { margin-block-start: var(--df-space-1); }
.df-icon-list__title, .df-point-list__title, .df-steps__title { font-weight: var(--df-font-weight-semibold); }

.df-point-list { display: grid; gap: var(--df-space-4); }
.df-point-list > li { padding-inline-start: var(--df-space-4); border-inline-start: 3px solid var(--df-color-brand-primary); }
.df-point-list > li > * { margin: 0; }
.df-point-list > li > * + * { margin-block-start: var(--df-space-1); }

.df-steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr)); gap: var(--df-space-3); }
.df-steps__item {
  padding: var(--df-space-4);
  border: 1px solid var(--df-color-line);
  border-block-start: 3px solid var(--df-color-brand-primary);
  border-radius: var(--df-radius-md);
  background: var(--df-color-surface-default);
  color: var(--df-color-text-default);
}
.df-steps__item > * { margin: 0; }
.df-steps__item > * + * { margin-block-start: var(--df-space-1); }

.df-faq { display: grid; gap: var(--df-space-3); }
.df-faq__item {
  border: 1px solid var(--df-color-line);
  border-radius: var(--df-radius-md);
  background: var(--df-color-surface-default);
  color: var(--df-color-text-default);
}
.df-faq__q {
  display: flex; justify-content: space-between; gap: var(--df-space-4);
  padding: var(--df-space-4) var(--df-space-6);
  font-weight: var(--df-font-weight-semibold);
  cursor: pointer;
  list-style: none;
}
.df-faq__q::-webkit-details-marker { display: none; }
.df-faq__q::after { content: "+"; color: var(--df-color-brand-primary); font-weight: var(--df-font-weight-bold); }
.df-faq__item[open] > .df-faq__q::after { content: "\2212"; }
.df-faq__a { padding: 0 var(--df-space-6) var(--df-space-4); }
.df-section--dark .df-faq__a :is(p, li), .df-faq__a :is(p, li) { color: var(--df-color-text-muted); }
.df-faq__a > * { margin: 0; }
.df-faq__a > * + * { margin-block-start: var(--df-space-2); }

.df-tags { display: flex; flex-wrap: wrap; gap: var(--df-space-2); }
.df-tags > li {
  padding: var(--df-space-2) var(--df-space-4);
  border: 1px solid currentColor;
  border-radius: var(--df-radius-full);
  font-size: var(--df-font-size-sm);
}

/* Image card: the photo runs to the card's edges above its copy. */
.df-card__media {
  margin: calc(-1 * var(--df-card-padding)) calc(-1 * var(--df-card-padding)) var(--df-space-4);
  border-radius: var(--df-card-radius) var(--df-card-radius) 0 0;
  overflow: hidden;
}
.df-card__media img { display: block; width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }

/* Photo CTA band: the closing "next step" of an interior page. */
.df-cta-band {
  padding-block: var(--df-space-16);
  color: var(--df-color-text-inverse);
  background:
    linear-gradient(90deg, rgba(0,0,0,0.86) 20%, rgba(0,0,0,0.5) 100%),
    var(--df-cta-image, none) center / cover no-repeat,
    var(--df-color-surface-dark);
}
.df-cta-band__inner { max-width: 40rem; }
.df-cta-band :is(h2, .df-section__title) { color: var(--df-color-text-inverse); }
.df-cta-band .df-eyebrow { color: var(--df-color-brand-accent); }
.df-cta-band p { color: rgba(255,255,255,0.86); }

/* Form-page hero: the banner a contact page opens with, sized so the inquiry
   card can ride up onto it (.df-section--overlap below). It keeps the image
   hero's split - the tagline is the brand line, the h1 underneath names THIS
   page - and only re-aims the scrim, dense on the copy side and clearing to the
   photo on the right. */
.df-hero--form {
  --df-hero-scrim: linear-gradient(90deg, rgba(0,0,0,0.88) 15%, rgba(0,0,0,0.44) 55%, rgba(0,0,0,0) 80%);
  min-height: 41.25rem; /* 660px */
  align-items: flex-start;
  padding-block: 7.75rem 13.5rem;
}
.df-hero--form .df-hero__content { max-width: 46.875rem; /* 750px */ }
/* White, not the brand accent: on this banner the eyebrow is a quiet label
   above the h1, and the card below it carries the brand colour. */
.df-hero--form .df-eyebrow { color: rgba(255,255,255,0.85); }
.df-hero--form .df-hero__title { margin-block: var(--df-space-4) 0; }
.df-hero--form .df-hero__lede { margin-block-start: var(--df-space-4); }
/* The band that lifts the following section onto the hero above it. The lift is
   larger than the hero's bottom padding, so the card overlaps the photo rather
   than just filling the gap. */
.df-section--overlap {
  position: relative;
  z-index: 1;
  margin-block-start: -17.75rem; /* 284px */
  padding-block-start: 0;
}
/* The card is the column here: it centres in the page grid and the copy that
   follows it lines up with its edges instead of the wider page container. */
.df-section--overlap > .df-container {
  max-width: calc(var(--df-form-max-width) + 2 * var(--df-container-padding));
}
.df-section--overlap .df-inquiry { margin-block-start: 0; margin-inline: auto; }
/* The display line steps down with the viewport (the live banner does the same),
   otherwise a long service name eats the whole banner and runs under the card. */
@media (max-width: 61.9375rem) {
  .df-hero--form .df-hero__tagline { font-size: var(--df-font-size-2xl); }
}
@media (max-width: 47.9375rem) {
  .df-hero--form {
    min-height: 32rem; /* 512px */
    padding-block: var(--df-space-16) 11rem;
  }
  .df-hero--form .df-hero__tagline { font-size: var(--df-font-size-xl); }
  .df-section--overlap { margin-block-start: -9.5rem; }
}

/* In-page anchor bar under the hero. js/subnav.js marks the section in view. */
.df-subnav {
  border-block-end: 1px solid var(--df-color-line);
  background: var(--df-color-surface-default);
}
.df-subnav__list {
  display: flex;
  justify-content: center;
  gap: var(--df-space-1);
  list-style: none;
  margin: 0;
  padding-block: var(--df-space-3);
  overflow-x: auto;
  scrollbar-width: none;
}
.df-subnav__list::-webkit-scrollbar { display: none; }
.df-subnav__link {
  flex: 0 0 auto;
  display: block;
  padding: var(--df-space-2) var(--df-space-4);
  border-radius: var(--df-radius-full);
  text-decoration: none;
  white-space: nowrap;
  font-size: var(--df-font-size-sm);
  color: var(--df-color-text-muted);
}
.df-subnav__link:hover { background: var(--df-color-surface-subtle); color: var(--df-color-text-default); }
.df-subnav__link.is-active {
  background: var(--df-color-brand-secondary);
  color: var(--df-color-text-inverse);
}
/* Anchored sections must clear the sticky header when jumped to. */
.df-section[id], .df-audiences[id], .df-split-cta[id] { scroll-margin-top: 5.5rem; }

/* Section heading block, centred by default. */
.df-section-head { text-align: center; margin-block-end: var(--df-space-8); }
/* Emphasised word in a section title takes the brand colour - same <em>
   contract as the hero tagline, one step up the palette. */
.df-section__title em { font-style: normal; color: var(--df-color-brand-primary); }
.df-section-head--left { text-align: left; }
.df-section-head .df-lead { margin-inline: auto; }
.df-section-head--left .df-lead { margin-inline: 0; }

/* Numbered service card + a two-up grid for shorter card sets. */
.df-card__num {
  display: block;
  font-size: var(--df-font-size-sm);
  font-weight: var(--df-font-weight-semibold);
  color: var(--df-color-brand-primary);
  letter-spacing: 0.04em;
  margin-block-end: var(--df-space-2);
}
/* Fixed column counts: these grids are compositions, not "fit as many as fit".
   A pair stays a pair on a wide screen instead of fanning out to four. */
.df-card-grid--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.df-card-grid--trio { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 60rem) {
  .df-card-grid--pair { grid-template-columns: minmax(0, 1fr); }
  .df-card-grid--trio { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 45rem) {
  .df-card-grid--trio { grid-template-columns: minmax(0, 1fr); }
}

/* Dark audience mosaic. Each tile's photo comes in on --df-audience-image. */
.df-audiences {
  background: var(--df-color-surface-dark);
  color: var(--df-color-text-inverse);
  padding-block-start: var(--df-space-section);
}
.df-audiences__head {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: var(--df-space-6);
  align-items: end;
  margin-block-end: var(--df-space-8);
}
.df-audiences__head .df-eyebrow { color: rgba(255,255,255,0.8); }
.df-audiences__head h2 { color: var(--df-color-text-inverse); margin: 0; }
.df-audiences__head p { color: rgba(255,255,255,0.78); margin: 0; }
/* Two tiles per row - the mosaic is a 2x2 block, and it stays two-up further
   down than the card grids because each tile is a photo that needs the width. */
.df-audience-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: rgba(255,255,255,0.22);
}
@media (max-width: 45rem) {
  .df-audience-grid { grid-template-columns: minmax(0, 1fr); }
}
.df-audience {
  position: relative;
  min-height: 23.75rem; /* 380px: the prototype's tile height */
  padding: var(--df-space-6);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: var(--df-space-2);
  overflow: hidden;
  background: #111 center / cover no-repeat;
  background-image: var(--df-audience-image, none);
}
.df-audience::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0.12) 25%, rgba(0,0,0,0.82) 100%);
}
.df-audience > * { position: relative; z-index: 1; margin: 0; }
.df-audience h3 { color: var(--df-color-text-inverse); font-size: var(--df-font-size-lg); }
.df-audience p { color: rgba(255,255,255,0.82); font-size: var(--df-font-size-sm); max-width: 36ch; }
.df-link--light { color: var(--df-color-brand-accent); }
.df-link--light:hover { color: var(--df-color-text-inverse); }

/* Service-area map. */
.df-map { display: grid; justify-items: center; gap: var(--df-space-6); margin-block-start: var(--df-space-8); }
.df-map svg { width: min(100%, 32rem); height: auto; display: block; overflow: visible; }
.df-map__shape { fill: var(--df-color-brand-secondary); }
.df-map__radius { fill: var(--df-color-brand-primary); opacity: 0.18; }
.df-map__pin { fill: var(--df-color-brand-primary); stroke: #fff; stroke-width: 2; }
.df-map__pin-core { fill: #fff; }
.df-map__label { font-family: var(--df-font-family-sans); font-size: 13px; font-weight: 700; fill: #fff; }
.df-map__sub { font-family: var(--df-font-family-sans); font-size: 10px; font-weight: 500; fill: rgba(255,255,255,0.7); }
.df-map__legend {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--df-space-2) var(--df-space-6);
  list-style: none; margin: 0; padding: 0;
  font-size: var(--df-font-size-sm); font-weight: var(--df-font-weight-semibold);
}
.df-map__legend li { display: inline-flex; align-items: center; gap: var(--df-space-2); }
.df-map__legend li::before {
  content: ""; width: 9px; height: 9px; border-radius: 50%;
  background: var(--df-color-brand-primary);
}

/* Split closing CTA: brand panel + a dark "talk to a person" panel. */
.df-split-cta { display: grid; grid-template-columns: repeat(auto-fit, minmax(24rem, 1fr)); }
.df-split-cta__panel {
  padding: var(--df-space-16) var(--df-space-8);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--df-space-4);
}
.df-split-cta__panel--brand { background: var(--df-color-brand-primary); color: var(--df-color-text-inverse); }
.df-split-cta__panel--brand .df-eyebrow { color: rgba(255,255,255,0.85); }
.df-split-cta__panel--dark { background: var(--df-color-surface-dark); color: var(--df-color-text-inverse); }
.df-split-cta__panel--dark .df-eyebrow { color: var(--df-color-brand-accent); }
.df-split-cta__panel h2 { color: var(--df-color-text-inverse); margin: 0; }
.df-split-cta__panel p { margin: 0; max-width: 36ch; }
.df-split-cta__panel--dark p { color: rgba(255,255,255,0.75); }
.df-split-cta__tagline {
  font-size: var(--df-font-size-2xl);
  font-weight: var(--df-font-weight-heading);
  line-height: var(--df-font-line-height-tight);
  max-width: 16ch;
  margin: 0;
}
.df-split-cta__tagline em { font-style: normal; color: var(--df-color-brand-accent); }
.df-btn--on-brand { background: var(--df-color-surface-default); color: var(--df-color-brand-primary); align-self: flex-start; }
.df-btn--on-brand:hover { background: var(--df-color-brand-secondary); color: var(--df-color-text-inverse); }
.df-people { display: grid; gap: var(--df-space-3); margin: 0; padding: 0; list-style: none; }
.df-person {
  display: block;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: var(--df-card-radius);
  padding: var(--df-space-4);
  text-decoration: none;
  color: var(--df-color-text-inverse);
}
.df-person:hover { border-color: var(--df-color-brand-accent); background: rgba(255,255,255,0.04); }
.df-person__name { display: block; font-weight: var(--df-font-weight-semibold); }
.df-person__role { display: block; font-size: var(--df-font-size-sm); color: rgba(255,255,255,0.6); }
.df-person__go { display: block; margin-block-start: var(--df-space-2); color: var(--df-color-brand-accent); font-size: var(--df-font-size-sm); font-weight: var(--df-font-weight-semibold); }

/* ---- Guided front page -------------------------------------------------
   Shared by the homepage sections (css/home.css) and any page that borrows
   their parts: keyword colour, the hero rule, and the trailing arrow. */

/* Keyword emphasis: one word or phrase of a headline in a brand colour, the
   way the brand's earlier site set them. On a dark or photographic band it
   takes the accent (--alt: the second accent); on a light surface the accents
   fail contrast as text, so it takes the primary. */
.df-mark, .df-mark-alt { color: var(--df-color-brand-primary); }
:is(.df-hero--image, .df-section--dark, .df-audiences, .df-cta-band, .df-tabs--dark) .df-mark {
  color: var(--df-color-brand-accent);
}
:is(.df-hero--image, .df-section--dark, .df-audiences, .df-cta-band, .df-tabs--dark) .df-mark-alt {
  color: var(--df-color-brand-accent2, var(--df-color-brand-accent));
}

/* A short rule in the primary colour under a display headline. */
.df-hero__rule {
  width: 100%;
  max-width: 49rem;
  height: 1px;
  margin: var(--df-space-6) 0;
  border: 0;
  background: var(--df-color-brand-primary);
}

/* A trailing arrow inside a button or link. */
.df-btn--arrow { display: inline-flex; align-items: center; gap: var(--df-space-3); }
.df-btn__arrow { flex: none; transition: transform 0.18s ease; }
.df-btn--arrow:hover .df-btn__arrow,
.df-btn--arrow:focus-visible .df-btn__arrow { transform: translateX(3px); }
.df-link--arrow { text-decoration: none; }
.df-link--arrow::after { content: " \2192"; }
.df-link--arrow:hover { text-decoration: underline; }

/* The homepage's own sections (display hero, intro, tab block, expanding
   cards, photo cards, audience picker, coverage map, closing band) are styled
   in css/home.css, loaded on the front page and in the editor. */

/* ---- Floating CTA dock + guided drawer ---------------------------------
   One persistent cluster of calls to action, never a scattering of separate
   floating widgets: a stack of pills in the bottom corner on a wide screen, the
   same list as a full-width bar across the bottom edge on a phone.

   The cluster is FIXED, so the only part of the document it would otherwise
   sit on for good is the very end of it - the footer. Rather than pad the
   footer out with an empty band to clear it, the cluster steps aside while the
   footer is on screen (js/cta-dock.js puts .df-dock-at-end on <html>): the
   footer carries the same calls to action, so nothing is lost.
   --df-dock-reserve is only what an anchor jump keeps clear of the cluster.

   Everything is token-driven, as everywhere else in this file: the pills are
   .df-btn, so a skin's button radius, colour and hover apply unchanged. */
.df-has-cta-dock { --df-dock-reserve: 14rem; }
.df-dock-collapsed .df-has-cta-dock { --df-dock-reserve: 3rem; }
/* Anchor jumps must not land under a bottom bar either. */
.df-has-cta-dock { scroll-padding-block-end: var(--df-dock-reserve); }

.df-cta-dock {
  transition: opacity 0.3s ease, transform 0.4s cubic-bezier(.2,.7,.2,1), visibility 0s linear 0s;
  position: fixed;
  inset-block-end: max(var(--df-space-6), env(safe-area-inset-bottom));
  inset-inline-end: var(--df-space-6);
  z-index: 45;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}
html.df-dock-at-end .df-cta-dock {
  opacity: 0;
  visibility: hidden;
  transform: translateY(1.5rem);
  transition: opacity 0.3s ease, transform 0.4s cubic-bezier(.2,.7,.2,1), visibility 0s linear 0.4s;
}
/* The mobile nav panel drops down over the page; two competing overlays at once
   is exactly the "too much persistent chrome" this cluster was warned about. */
.df-site-header.is-nav-open ~ .df-cta-dock { display: none; }

.df-cta-dock__cluster {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--df-space-2);
}
.df-dock-collapsed .df-cta-dock__cluster { display: none; }

.df-cta-dock__list {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--df-space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}
.df-cta-dock__item { display: block; }

/* .df-btn supplies the skin's fill, radius and hover; the dock only resets the
   generous page-button padding, which would make a stack of three pills tower. */
.df-cta-dock__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
  padding: var(--df-space-3) var(--df-space-6);
  font-size: var(--df-font-size-sm);
  line-height: var(--df-font-line-height-tight);
  text-align: center;
  box-shadow: var(--df-shadow-md);
}
.df-cta-dock__label--short { display: none; }

/* The control that hides the cluster, and the tab it leaves behind. Exactly one
   of the two is ever on screen. */
.df-cta-dock__hide {
  align-self: flex-end;
  width: 1.75rem;
  height: 1.75rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--df-color-line);
  border-radius: var(--df-radius-full);
  background: var(--df-color-surface-default);
  color: var(--df-color-text-default);
  font-size: var(--df-font-size-base);
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--df-shadow-sm);
}
.df-cta-dock__hide:hover { border-color: var(--df-color-text-default); }
.df-cta-dock__reopen {
  display: none;
  writing-mode: vertical-rl;
  border: 0;
  border-start-start-radius: var(--df-radius-md);
  border-end-start-radius: var(--df-radius-md);
  background: var(--df-color-brand-primary);
  color: var(--df-color-text-inverse);
  font-family: inherit;
  font-size: var(--df-font-size-xs);
  font-weight: var(--df-font-weight-semibold);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: var(--df-space-4) var(--df-space-2);
  cursor: pointer;
}
.df-dock-collapsed .df-cta-dock__reopen { display: block; }
.df-dock-collapsed .df-cta-dock {
  /* The tab hugs the corner; the cluster it replaced stood off it. */
  inset-inline-end: 0;
  inset-block-end: 0;
}

/* ---- Small viewports: the same cluster as one bottom bar ----------------
   Three pills stacked in a corner eat a third of a small screen and sit over
   the content beside them. On a narrow screen - and on ANY short one, which is
   what a phone in landscape is - the dock spans the bottom edge with no surface
   of its own, and its buttons stack against the right side at the width of
   their labels, so a long label is never squeezed or truncated.

   The width breakpoint is the theme's OWN nav breakpoint (75rem): below it the
   header has already collapsed to a toggle and the container runs edge to edge,
   so a corner cluster would land on top of the body copy rather than in a
   gutter. Above it the float is the approved desktop design. */
@media (max-width: 74.999rem), (max-height: 34rem) {
  .df-has-cta-dock { --df-dock-reserve: 8.5rem; }
  .df-dock-collapsed .df-has-cta-dock { --df-dock-reserve: 3rem; }

  .df-cta-dock {
    inset-inline: 0;
    inset-block-end: 0;
    align-items: stretch;
  }
  /* No surface of its own: the buttons float over the page, so the empty part of
     the row must let taps through to the content underneath. */
  .df-cta-dock__cluster {
    position: relative;
    align-items: stretch;
    pointer-events: none;
    padding: var(--df-space-3) var(--df-space-4);
    padding-block-end: calc(var(--df-space-3) + env(safe-area-inset-bottom));
  }
  .df-cta-dock__cluster > * { pointer-events: auto; }
  /* The list keeps its desktop shape - one button per row, each the width of its
     label, right-aligned - so the bar and the corner stack read as one design. */
  /* The hide control rides on the bar's own edge rather than adding a row. */
  .df-cta-dock__hide {
    position: absolute;
    inset-block-start: 0;
    inset-inline-end: var(--df-space-2);
    transform: translateY(-60%);
  }
  .df-dock-collapsed .df-cta-dock { inset-inline: auto 0; }
}

/* Landscape phones and other short viewports: two rows of chrome plus the
   header leaves almost no page. Keyed on height alone - a phone on its side is
   844px wide and 390px tall, so a width breakpoint misses exactly the case that
   needs this most. One row, and the compact labels the tenant declared (each a shortening of the full label, which stays the accessible
   name, so the button a screen reader announces does not change with the
   viewport). */
@media (max-height: 34rem) {
  .df-has-cta-dock { --df-dock-reserve: 5.5rem; }
  .df-cta-dock__list { flex-direction: row; justify-content: flex-end; }
  .df-cta-dock__btn { font-size: var(--df-font-size-xs); padding-inline: var(--df-space-2); }
  .df-cta-dock__label { display: none; }
  .df-cta-dock__label--short { display: inline; }
  /* A tenant that declared no short label keeps the full one rather than
     rendering an empty button. */
  .df-cta-dock__btn > .df-cta-dock__label:only-child { display: inline; }
}

/* ---- Guided drawer ------------------------------------------------------
   Opened by the dock action that declares "opens". JS-only: it stays
   visibility:hidden (so out of the tab order AND the accessibility tree) until
   js/cta-dock.js opens it, which is why such an action should also carry an
   href as its no-JS destination. */
.df-cta-drawer__scrim {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(0, 0, 0, 0.45);
  opacity: 0;
  visibility: hidden;
  /* visibility flips INSTANTLY on the way in and only after the slide on the way
     out. Transitioning it in both directions leaves the panel visibility:hidden
     for the first frame, and nothing inside a visibility:hidden subtree can take
     focus - the drawer would open with focus still on the page behind it. */
  transition: opacity 0.25s ease, visibility 0s linear 0.25s;
}
.df-cta-drawer {
  position: fixed;
  inset-block: 0;
  inset-inline-end: 0;
  z-index: 81;
  width: min(100% - var(--df-space-6), 28.75rem);
  display: flex;
  flex-direction: column;
  background: var(--df-color-surface-default);
  box-shadow: var(--df-shadow-lg);
  transform: translateX(100%);
  visibility: hidden;
  transition: transform 0.3s ease, visibility 0s linear 0.3s;
}
.df-drawer-open { overflow: hidden; }
.df-drawer-open .df-cta-drawer__scrim {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.25s ease, visibility 0s;
}
.df-drawer-open .df-cta-drawer {
  transform: none;
  visibility: visible;
  transition: transform 0.3s ease, visibility 0s;
}
@media (prefers-reduced-motion: reduce) {
  .df-cta-drawer,
  .df-cta-drawer__scrim { transition: none; }
}
/* While the drawer is open the dock underneath it is noise, and on a phone the
   bar would sit on top of the drawer's own content. */
.df-drawer-open .df-cta-dock { visibility: hidden; }

.df-cta-drawer__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--df-space-4);
  padding: var(--df-space-6) var(--df-space-6) var(--df-space-4);
  border-block-end: 1px solid var(--df-color-line);
}
.df-cta-drawer__title { font-size: var(--df-font-size-h5); margin: 0; }
.df-cta-drawer__close {
  flex: 0 0 auto;
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--df-color-line);
  border-radius: var(--df-radius-sm);
  background: var(--df-color-surface-default);
  color: var(--df-color-text-default);
  font-size: var(--df-font-size-lg);
  line-height: 1;
  cursor: pointer;
}
.df-cta-drawer__close:hover { border-color: var(--df-color-text-default); }
.df-cta-drawer__body {
  flex: 1 1 auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: var(--df-space-6);
  padding-block-end: calc(var(--df-space-8) + env(safe-area-inset-bottom));
}
.df-cta-step__back {
  display: inline-flex;
  align-items: center;
  gap: var(--df-space-1);
  border: 0;
  background: none;
  padding: 0;
  margin-block-end: var(--df-space-3);
  font: inherit;
  font-size: var(--df-font-size-sm);
  font-weight: var(--df-font-weight-semibold);
  color: var(--df-color-brand-primary);
  cursor: pointer;
}
.df-cta-step__back:hover { color: var(--df-color-text-default); }
.df-cta-step__lede { color: var(--df-color-text-muted); margin: 0 0 var(--df-space-4); }
.df-cta-cards {
  display: grid;
  gap: var(--df-space-3);
  list-style: none;
  margin: 0;
  padding: 0;
}
.df-cta-card {
  display: block;
  width: 100%;
  text-align: start;
  font: inherit;
  color: inherit;
  text-decoration: none;
  background: var(--df-color-surface-default);
  border: var(--df-card-border-width) solid var(--df-color-line);
  border-radius: var(--df-card-radius);
  padding: var(--df-space-4);
  cursor: pointer;
}
.df-cta-card:hover { border-color: var(--df-color-brand-primary); }
.df-cta-card__title {
  display: block;
  font-weight: var(--df-font-weight-semibold);
  font-size: var(--df-font-size-h6);
  line-height: var(--df-font-line-height-h6);
}
.df-cta-card__body {
  display: block;
  margin-block-start: var(--df-space-2);
  color: var(--df-color-text-muted);
  font-size: var(--df-font-size-sm);
}
.df-cta-card__go {
  display: block;
  margin-block-start: var(--df-space-3);
  color: var(--df-color-brand-primary);
  font-size: var(--df-font-size-sm);
  font-weight: var(--df-font-weight-semibold);
}

/* ---- Site search --------------------------------------------------------
   One piece of markup, two shapes. What ships in the HTML is a plain GET form,
   which is what a visitor without JavaScript uses. js/search.js puts .js-search
   on <body>, and only then does the form collapse to an icon at the far right
   of the header and reopen as a modal panel over the page. Nothing is
   duplicated between the states, so they cannot drift apart.

   There is no submit control: Enter on the field goes to the results page, and
   a suggestion is taken by clicking it or pressing Enter on it. */
.df-search { position: relative; display: flex; align-items: center; }
/* The visually-hidden utility for this component: it names the icon-only button
   with real text rather than an aria-label, and labels the field. */
.df-search__label {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.df-search__icon { display: inline-flex; flex: 0 0 auto; color: var(--df-color-text-muted); }
.df-search__icon svg { width: 1.125rem; height: 1.125rem; }

/* Unenhanced: a real form sitting in the header. */
.df-search__form {
  display: flex;
  align-items: center;
  gap: var(--df-space-2);
  border: 1px solid var(--df-color-line);
  border-radius: var(--df-field-radius);
  background: var(--df-color-surface-default);
  padding-inline: var(--df-space-3);
  max-width: 18rem;
}
.df-search__input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  outline-offset: 2px;
  background: transparent;
  font: inherit;
  font-size: var(--df-font-size-sm);
  padding-block: var(--df-space-2);
  color: var(--df-color-text-default);
}
/* The browser's own clear button would sit next to our close control. */
.df-search__input::-webkit-search-cancel-button { display: none; }
/* Both belong to the enhanced panel only; without JS the form IS the UI. */
.df-search__toggle,
.df-search__close { display: none; }
.df-search__scrim { display: none; }
.df-search__results { display: none; }

/* ---- Enhanced: icon button + modal panel ------------------------------- */
.js-search .df-search__toggle {
  display: inline-grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border: 1px solid var(--df-color-line);
  border-radius: var(--df-field-radius);
  background: var(--df-color-surface-default);
  color: var(--df-color-text-default);
  cursor: pointer;
  padding: 0;
}
.js-search .df-search__toggle:hover { border-color: var(--df-color-text-default); }
.js-search .df-search__toggle .df-search__icon { color: inherit; }

.js-search .df-search__scrim {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgba(0, 0, 0, 0.45);
}
/* [hidden] must win over the display above, or the scrim never goes away. */
.js-search .df-search__scrim[hidden] { display: none; }

.js-search .df-search__panel {
  display: none;
  position: fixed;
  z-index: 91;
  inset-block-start: 10vh;
  inset-inline: 0;
  width: min(100% - var(--df-space-8), 40rem);
  margin-inline: auto;
  background: var(--df-color-surface-default);
  border-radius: var(--df-radius-md);
  box-shadow: var(--df-shadow-lg);
  overflow: hidden;
  /* Its own text colour: the panel sits inside the header, and a header over
     a hero photo (--over on a front page) is white text, which made every
     result title white on this white panel. */
  color: var(--df-color-text-default);
}
.js-search .df-search.is-open .df-search__panel { display: block; }
/* Inside the panel the form is a header row, not a bordered field of its own. */
.js-search .df-search__form {
  max-width: none;
  border: 0;
  border-radius: 0;
  border-block-end: 1px solid var(--df-color-line);
  padding: var(--df-space-3) var(--df-space-4);
}
.js-search .df-search__input { font-size: var(--df-font-size-base); padding-block: var(--df-space-3); }
.js-search .df-search__close {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  border: 1px solid var(--df-color-line);
  border-radius: var(--df-radius-sm);
  background: var(--df-color-surface-default);
  color: var(--df-color-text-muted);
  font-size: var(--df-font-size-lg);
  line-height: 1;
  cursor: pointer;
}
.js-search .df-search__close:hover { border-color: var(--df-color-text-default); color: var(--df-color-text-default); }

/* The list is open from the moment the panel is: an empty field shows the main
   sections, so the panel is never a blank box asking what you want. */
.js-search .df-search__results { display: block; }
.df-search__list {
  list-style: none;
  margin: 0;
  padding: var(--df-space-2);
  max-height: min(24rem, 60vh);
  overflow-y: auto;
}
.df-search__link {
  display: block;
  padding: var(--df-space-3);
  border-radius: var(--df-radius-sm);
  text-decoration: none;
  color: inherit;
}
/* Hover and keyboard highlight look identical: the arrow keys move
   aria-activedescendant, not focus, so there is no :focus to style. */
.df-search__item.is-active .df-search__link,
.df-search__link:hover {
  background: var(--df-color-surface-subtle);
}
.df-search__item-title {
  display: block;
  font-weight: var(--df-font-weight-semibold);
  font-size: var(--df-font-size-base);
}
.df-search__item-excerpt,
.df-search__item-why {
  display: block;
  font-size: var(--df-font-size-sm);
  color: var(--df-color-text-muted);
  margin-block-start: 2px;
}
/* The line that explains a page with none of the typed words in its title. */
.df-search__item-why { color: var(--df-color-brand-primary); }
.df-search__empty {
  margin: 0;
  padding: var(--df-space-6) var(--df-space-4);
  text-align: center;
  color: var(--df-color-text-muted);
  font-size: var(--df-font-size-sm);
}
/*
 * "Showing results for ..." - the line that says a typo was forgiven. Muted and
 * small: it explains the results, it is not one of them.
 */
.df-search__spelling {
  margin: 0;
  padding: var(--df-space-3) var(--df-space-4) 0;
  color: var(--df-color-text-muted);
  font-size: var(--df-font-size-sm);
}
.df-search-page .df-search__spelling {
  padding-inline: 0;
}
.df-search__all {
  display: block;
  width: 100%;
  padding: var(--df-space-3) var(--df-space-4);
  border: 0;
  border-block-start: 1px solid var(--df-color-line);
  background: transparent;
  font: inherit;
  font-size: var(--df-font-size-sm);
  font-weight: var(--df-font-weight-semibold);
  color: var(--df-color-brand-primary);
  text-align: start;
  cursor: pointer;
}
.df-search__all:hover { color: var(--df-color-text-default); }

@media (max-width: 47.999rem) {
  .js-search .df-search__panel { inset-block-start: var(--df-space-3); width: min(100% - var(--df-space-4), 40rem); }
}

/* ---- Results page ------------------------------------------------------ */
.df-search-results { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--df-space-8); }
.df-search-result__title { font-size: var(--df-font-size-h6); margin: 0; }
.df-search-result__title a { text-decoration: none; color: var(--df-color-text-default); }
.df-search-result__title a:hover { color: var(--df-color-brand-primary); }
.df-search-result__url {
  margin: var(--df-space-1) 0 0;
  font-size: var(--df-font-size-xs);
  color: var(--df-color-text-muted);
}
.df-search-result__why {
  margin: var(--df-space-2) 0 0;
  font-size: var(--df-font-size-sm);
  color: var(--df-color-brand-primary);
}
.df-search-result__body { margin-block-start: var(--df-space-2); color: var(--df-color-text-muted); }

/* ---- Motion ---------------------------------------------------------------
   One motion language for every page, keyed off the classes the blocks render,
   so a page an editor assembles in wp-admin moves exactly like a seeded one.
   Everything sits under html.df-motion, which the head script sets unless the
   visitor asks for reduced motion (functions.php): without it every element
   renders in place, and nothing here can leave content hidden.

   1. Hero entrance, pure CSS so it starts on first paint: the eyebrow, each
      headline line rising out of its own mask, the red rule drawing across,
      then the copy and buttons. The photo settles from a slow zoom.
   2. Hero depth on scroll (js/motion.js sets --df-hero-shift, 0 to 1): the
      photo drifts at a slower rate than the page and the copy lifts away.
   3. Scroll reveals (js/motion.js adds .df-reveal, then .is-in on entry).
   4. Header condenses once the page leaves the top.
   5. Cards: a lift on hover and a soft light that follows the pointer. */
:root { --df-ease-out: cubic-bezier(0.22, 1, 0.36, 1); }

.df-line { display: block; }

@keyframes df-rise { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }
@keyframes df-line-up { from { transform: translateY(110%); } to { transform: none; } }
@keyframes df-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes df-settle { from { scale: 1.14; } to { scale: 1.04; } }
@keyframes df-fade { from { opacity: 0; } to { opacity: 1; } }

/* 1. Hero entrance */
.df-motion .df-hero__content > * {
  animation: df-rise 0.9s var(--df-ease-out) backwards;
  animation-delay: 0.15s;
}
.df-motion .df-hero__content > :nth-child(2) { animation-delay: 0.3s; }
.df-motion .df-hero__content > :nth-child(3) { animation-delay: 0.75s; }
.df-motion .df-hero__content > :nth-child(4) { animation-delay: 0.9s; }
.df-motion .df-hero__content > :nth-child(n+5) { animation-delay: 1.05s; }
.df-motion .df-hero__content > :is(.df-hero__tagline, .df-hero__title):has(.df-line) { animation: none; }
.df-motion .df-hero :is(.df-hero__tagline, .df-hero__title) .df-line {
  overflow: hidden;
  padding-block-end: 0.12em;
  margin-block-end: -0.12em;
}
.df-motion .df-hero .df-line__in {
  display: block;
  animation: df-line-up 1.05s var(--df-ease-out) backwards;
  animation-delay: calc(0.3s + var(--df-line, 0) * 0.14s);
}
.df-motion .df-hero__rule {
  transform-origin: left center;
  animation: df-draw 1.1s var(--df-ease-out) 0.7s backwards;
}

/* The photo moves to its own layer so it can zoom and drift without moving the
   copy; the section keeps a dark fill so there is never a white flash. */
.df-motion .df-hero--image {
  isolation: isolate;
  overflow: hidden;
  background: var(--df-color-surface-dark);
}
.df-motion .df-hero--image::before {
  content: "";
  position: absolute;
  inset: -4% 0;
  z-index: -1;
  background:
    var(--df-hero-scrim, linear-gradient(105deg, rgba(0,0,0,0.72) 0%, rgba(0,0,0,0.45) 55%, rgba(0,0,0,0.35) 100%)),
    var(--df-hero-image, linear-gradient(120deg, #1b1b1b, #3a3a3a)) center / cover no-repeat;
  scale: 1.04;
  translate: 0 calc(var(--df-hero-shift, 0) * 8%);
  animation: df-settle 2.6s var(--df-ease-out) backwards;
  will-change: translate;
}
/* 2. Hero depth: the copy lifts and fades as the hero leaves. */
.df-motion .df-hero--image .df-hero__content {
  translate: 0 calc(var(--df-hero-shift, 0) * -3rem);
  opacity: calc(1 - var(--df-hero-shift, 0) * 1.1);
}
/* Phones keep the lift but drop the fade. There the hero is taller than the
   screen and its button sits below the fold, so the copy was already at about
   half opacity by the time the visitor scrolled down to read it. */
@media (max-width: 47.9375rem) {
  .df-motion .df-hero--image .df-hero__content { opacity: 1; }
}

/* 3. Scroll reveals */
.df-motion .df-reveal {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 0.6s ease var(--df-reveal-delay, 0ms),
    transform 0.8s var(--df-ease-out) var(--df-reveal-delay, 0ms);
}
.df-motion .df-reveal.is-in { opacity: 1; transform: none; }
.df-motion .df-reveal--clip { transform: none; transition: opacity 0.9s ease var(--df-reveal-delay, 0ms); }
.df-motion .df-reveal--clip img {
  scale: 1.04;
  transition: scale 1.4s var(--df-ease-out) var(--df-reveal-delay, 0ms);
}
.df-motion .df-reveal--clip.is-in img { scale: 1; }

/* 4. Header */
.df-site-header { transition: box-shadow 0.3s ease, background-color 0.3s ease, border-color 0.3s ease; }
.df-site-header__inner { transition: padding 0.3s var(--df-ease-out); }
.df-site-header.is-scrolled {
  border-block-end-color: transparent;
  background: color-mix(in srgb, var(--df-color-surface-default) 88%, transparent);
  -webkit-backdrop-filter: saturate(1.6) blur(14px);
  backdrop-filter: saturate(1.6) blur(14px);
  box-shadow: 0 10px 30px -18px rgba(0,0,0,0.35);
}
.df-site-header.is-scrolled .df-site-header__inner { padding-block: var(--df-space-3); }

/* 5. Cards */
.df-card, .df-steps__item, .df-icon-list--grid .df-icon-list__item, .df-contact-info__row {
  transition: transform 0.45s var(--df-ease-out), box-shadow 0.45s ease, border-color 0.3s ease;
}
.df-card:hover, .df-steps__item:hover, .df-icon-list--grid .df-icon-list__item:hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 32px -14px rgba(0,0,0,0.16);
}
.df-card:hover { border-color: var(--df-color-brand-accent2, var(--df-color-brand-primary)); }
.df-card__media { overflow: hidden; }
.df-card__media img { transition: transform 0.9s var(--df-ease-out); }
.df-card:hover .df-card__media img { transform: scale(1.03); }
.df-steps__item { transition: transform 0.45s var(--df-ease-out), box-shadow 0.45s ease, border-top-color 0.3s ease; }
.df-steps__item:hover { border-block-start-color: var(--df-color-brand-accent); }

@media (hover: hover) and (pointer: fine) {
  .df-motion :is(.df-card, .df-steps__item, .df-icon-list--grid .df-icon-list__item):hover {
    background-image: radial-gradient(
      circle 16rem at var(--df-spot-x, 50%) var(--df-spot-y, 50%),
      color-mix(in srgb, var(--df-color-brand-accent2, var(--df-color-brand-primary)) 12%, transparent),
      transparent 70%
    );
  }
}
