/* Duck Mark Phase M: unified site shell. */
body.dm-site-shell-enabled {
  --dm-shell-container: var(--dm-container, 1140px);
  --dm-shell-gutter: clamp(16px, 3vw, 36px);
  --dm-shell-section-space: var(--dm-section-gap, 72px);
  --dm-shell-heading-size: clamp(1.65rem, 2.5vw, 2.5rem);
  --dm-shell-heading-line: 1.16;
  --dm-shell-copy-width: 68ch;
  --dm-shell-card-radius: var(--dm-radius-lg, 22px);
  --dm-shell-card-border: var(--dm-border-w, 1px) solid var(--dm-border, #e5e7eb);
  --dm-shell-card-shadow: var(--dm-shadow-card, 0 4px 14px rgba(17,17,17,.06));
}

body.dm-site-shell-rhythm--compact { --dm-shell-section-space: clamp(36px, 5vw, 56px); }
body.dm-site-shell-rhythm--standard { --dm-shell-section-space: clamp(52px, 7vw, 82px); }
body.dm-site-shell-rhythm--generous { --dm-shell-section-space: clamp(72px, 10vw, 124px); }

body.dm-site-shell-align-chrome {
  --dm-header-max-width: var(--dm-shell-container);
  --dm-footer-max-width: var(--dm-shell-container);
}

.dm-page-assembly--shell {
  position: relative;
  width: 100%;
  max-width: none;
  margin-inline: 0;
  overflow-x: clip;
  background: var(--dm-bg, #fff);
  color: var(--dm-text, #111);
  font-family: var(--dm-font-body, inherit);
}

body.dm-site-shell-full-bleed .dm-page-assembly--shell {
  width: auto;
  margin-inline: calc(50% - 50vw);
}

.dm-site-section {
  position: relative;
  width: 100%;
  min-width: 0;
  padding-block: var(--dm-shell-section-space);
  color: var(--dm-text, #111);
  font-family: var(--dm-font-body, inherit);
  isolation: isolate;
}

.dm-site-section--width-full { padding-block: 0; }
.dm-site-section--tone-base { background: var(--dm-bg, #fff); }
.dm-site-section--tone-surface { background: var(--dm-surface, #f6f5f2); }
.dm-site-section--tone-surface-2 { background: var(--dm-surface-2, #eeece7); }

.dm-site-section__inner {
  width: min(calc(100% - (var(--dm-shell-gutter) * 2)), var(--dm-shell-container));
  max-width: none;
  margin-inline: auto;
  min-width: 0;
}

.dm-site-section--width-full > .dm-site-section__inner {
  width: 100%;
  max-width: none;
}

.dm-site-section__content,
.dm-site-section__content > * {
  min-width: 0;
}

/* Let the shell own the outer width and rhythm. Internal layouts remain module-owned. */
.dm-site-section__content > :where(
  .dm-cat,
  .dm-phl,
  .dm-guide,
  .duck-mark-review,
  .dm-news,
  .dm-mood,
  .dm-gp__rail,
  .dm-visual,
  .cls-slider
) {
  width: 100% !important;
  max-width: none !important;
  margin: 0 !important;
  /*
   * Several of these modules escape their container on their own, with
   * `left: 50%` plus a negative margin and a viewport width. Neutralising only
   * the width and the margin left the offset behind, which pushed the module
   * half a container to the right where the shell's overflow clip hid it. The
   * positional half has to go too, so the shell is the single owner of how wide
   * a section is and where it starts.
   */
  position: relative !important;
  inset-inline: auto !important;
  transform: none !important;
}

/* A shared heading system across independent modules. */
.dm-site-section :where(
  .dm-cat__heading,
  .dm-phl__heading,
  .dm-guide__heading,
  .duck-mark-review__heading,
  .dm-news__heading,
  .dm-mood__heading,
  .dm-gp__rail h2,
  .dm-visual-heading
) {
  margin-top: 0;
  color: var(--dm-text, #111);
  font-family: var(--dm-font-display, inherit);
  font-size: var(--dm-shell-heading-size);
  font-weight: var(--dm-display-weight, 800);
  line-height: var(--dm-shell-heading-line);
  letter-spacing: var(--dm-display-track, -.02em);
}

.dm-site-section :where(
  .dm-cat__subtitle,
  .dm-phl__subtitle,
  .dm-guide__subtitle,
  .duck-mark-review__subtitle,
  .dm-news__subtitle,
  .dm-mood__subtitle,
  .dm-gp__rail p,
  .dm-visual-subtitle
) {
  color: var(--dm-muted, #6b7280);
  line-height: 1.75;
}

/* Shared action language. */
.dm-site-section :where(
  .dm-cat__all,
  .dm-phl__all,
  .dm-guide__all,
  .duck-mark-review__all,
  .dm-news__all,
  .dm-mood__all,
  .dm-visual-button,
  .dm-gp__rail a[class*="button"]
) {
  border-radius: var(--dm-btn-radius, var(--dm-radius-sm, 8px));
  font-weight: var(--dm-btn-weight, 700);
}

/* Shared card finish, enabled as a safe outer visual normalization. */
body.dm-site-shell-normalize-cards .dm-site-section :where(
  .dm-cat__card,
  .dm-phl__card,
  .dm-guide__card,
  .duck-mark-review__card,
  .dm-news__card,
  .dm-mood__card,
  .dm-visual-thumb,
  .dm-visual-social-item
) {
  border-radius: var(--dm-shell-card-radius) !important;
  border-color: var(--dm-border, #e5e7eb) !important;
}

body.dm-site-shell--balanced.dm-site-shell-normalize-cards .dm-site-section :where(
  .dm-cat__card,
  .dm-phl__card,
  .dm-guide__card,
  .duck-mark-review__card,
  .dm-news__card,
  .dm-mood__card
) {
  box-shadow: var(--dm-shell-card-shadow);
}

body.dm-site-shell--catalog {
  --dm-shell-heading-size: clamp(1.45rem, 2vw, 2rem);
}
body.dm-site-shell--catalog .dm-site-section { --dm-shell-section-space: clamp(40px, 6vw, 68px); }
body.dm-site-shell--catalog.dm-site-shell-normalize-cards .dm-site-section :where(.dm-cat__card,.dm-phl__card,.dm-guide__card) {
  box-shadow: none;
}

body.dm-site-shell--editorial {
  --dm-shell-heading-size: clamp(2rem, 4vw, 3.6rem);
  --dm-shell-copy-width: 60ch;
}
body.dm-site-shell--editorial .dm-site-section:not(.dm-site-section--width-full) {
  --dm-shell-section-space: clamp(72px, 10vw, 132px);
}

/* The shell must not expose raw module diagnostics in the public composition. */
.dm-page-assembly--shell :where(.dm-phl-debug,.dm-cat-debug,.dm-guide-debug,.dm-mood-debug,.dm-visual-empty) {
  display: none !important;
}

@media (max-width: 782px) {
  body.dm-site-shell-enabled {
    --dm-shell-gutter: 16px;
    --dm-shell-heading-size: clamp(1.45rem, 7vw, 2.1rem);
  }
  .dm-site-section {
    padding-block: clamp(40px, 12vw, 64px);
  }
  .dm-site-section--width-full { padding-block: 0; }
}

/* ==================================================================
 * v3.7.4 — frontend shell stabilization
 *
 * Selectors below were taken from the shipped Astra templates, not from memory:
 * page.php renders #primary, template-parts/content-page.php renders
 * article.page, the title lives in header.entry-header and the body in
 * .entry-content.clear inside .ast-container.
 * ================================================================== */

/* One canonical container and gutter for every Duck Mark surface. */
body.dm-site-shell-enabled {
  --dm-shell-gutter: clamp(16px, 3vw, 36px);
  --dm-header-gutter: var(--dm-shell-gutter);
  --dm-footer-gutter: var(--dm-shell-gutter);
}

/* ---- 4.4 composed front page: remove the theme's competing chrome ---- */
body.dm-composed-front-page header.entry-header,
body.dm-composed-front-page .ast-single-entry-banner {
  display: none;
}

body.dm-composed-front-page #primary,
body.dm-composed-front-page .site-content > .ast-container,
body.dm-composed-front-page article.page,
body.dm-composed-front-page .entry-content.clear {
  max-width: none;
  width: 100%;
  margin-inline: 0;
  padding-inline: 0;
}

body.dm-composed-front-page .entry-content.clear > :first-child { margin-block-start: 0; }
body.dm-composed-front-page .entry-content.clear > :last-child { margin-block-end: 0; }
body.dm-composed-front-page #content.site-content { padding-block: 0; }
/*
 * Astra's own "Content Bottom Spacing" customizer setting puts a 60px
 * margin-bottom on .content-area.primary regardless of page type — on an
 * ordinary post that is normal breathing room before the footer; on a
 * composed page it is 60px of nothing between the last section and the
 * footer with no background painted in it, so body's own colour (this
 * skin's paper tone, or any other skin's) shows straight through as a solid
 * band. Structural, not a brand choice — every composed page needs this
 * regardless of Pack, so it stays on the generic class (found via GREEN
 * BADGER DETAIL CORRECTION DIRECTIVE v2, reviewer correction #2 — the
 * "thick beige band right above the footer" — 2026-08-21).
 */
/*
 * !important matches the codebase's own established precedent for this
 * exact fight: slider.css already carries `body.home #primary { margin-top:
 * 0 !important; }` for the same element's top margin, because main.min.css's
 * `#primary { margin: 4em 0px; }` shorthand re-sets both margin-top AND
 * margin-bottom even where a more specific rule already set one of them
 * individually to 0 (shorthand-vs-longhand at the same or lower specificity
 * still wins on the properties it touches). Same fight, same fix, bottom side.
 */
body.dm-composed-front-page .content-area.primary { margin-bottom: 0 !important; }

/* ---- a composed band is not an article ---- */

/*
 * Astra's dynamic CSS ships this, from its "underline content links" setting:
 *
 *   .ast-single-post .entry-content a { text-decoration: underline; }
 *
 * That is a sound choice for prose — an underline is how a reader finds a link
 * in a paragraph. Our bands are not prose. They are cards, category names and
 * buttons that happen to be rendered into the page's content area, and the theme
 * has no way to tell the two apart: from where it stands, everything inside
 * .entry-content is article body.
 *
 * So the correction belongs here rather than in the theme. Turning the setting
 * off would strip the underline from real articles too, which is the shop's
 * decision about its own writing and not a pack's to make. Both reference
 * mockups draw every one of these links without an underline: the LUXERA card
 * titles and prices, and GREEN BANGER's HERB / LIQUID / EDIBLES and VIEW ALL.
 *
 * Specificity, counted rather than guessed: Astra's rule is (0,2,1) and this one
 * is (0,3,1), so it wins on the cascade itself and not on which stylesheet the
 * enqueue order happens to put last. Every link a section draws sits inside
 * .dm-section__inner, so one rule reaches all of them.
 */
.entry-content .dm-section .dm-section__inner a {
  text-decoration: none;
}

/* The admin bar and the Coming Soon notice belong to WordPress. They are left
   alone; only the sticky offset accounts for them. */
body.admin-bar.dm-site-shell-enabled { --dm-admin-bar-offset: 32px; }
@media (max-width: 782px) {
  body.admin-bar.dm-site-shell-enabled { --dm-admin-bar-offset: 46px; }
}

/* ---- 4.5 module outer geometry is neutralised only inside a section ---- */
.dm-site-section__content > *,
.dm-site-section__content > * > .dm-phl,
.dm-site-section__content > * > .duck-phl {
  max-width: none;
  margin-inline: 0;
}
.dm-site-section__content > :first-child { margin-block-start: 0; }
.dm-site-section__content > :last-child { margin-block-end: 0; }

/* Carousel controls and focus rings must survive the clip. */
.dm-page-assembly--shell { overflow-x: clip; }
.dm-site-section { overflow: visible; }
.dm-site-section__inner { overflow: visible; }
:where(.dm-site-section) :focus-visible { outline-offset: 2px; }

/* ---- 4.9 / 4.10 footer and commerce align to the same container ---- */
body.dm-site-shell-align-chrome .dm-footer__inner,
body.dm-site-shell-align-chrome .dm-header__inner {
  width: min(calc(100% - (var(--dm-shell-gutter) * 2)), var(--dm-shell-container));
  margin-inline: auto;
  min-width: 0;
}

body.dm-site-shell-enabled.woocommerce #primary,
body.dm-site-shell-enabled.woocommerce-page #primary {
  width: min(calc(100% - (var(--dm-shell-gutter) * 2)), var(--dm-shell-container));
  margin-inline: auto;
  max-width: none;
}
body.dm-site-shell-enabled.woocommerce .site-content > .ast-container,
body.dm-site-shell-enabled.woocommerce-page .site-content > .ast-container {
  max-width: none;
  padding-inline: 0;
}

/* No Duck Mark surface may create horizontal page scrolling. */
body.dm-site-shell-enabled { overflow-x: hidden; }
body.dm-site-shell-enabled img,
body.dm-site-shell-enabled video { max-width: 100%; height: auto; }


/* ------------------------------------------------------------------
 * Vertical rhythm, owned here and nowhere else.
 *
 * The section space was applied above and below every section, so two
 * neighbours produced twice the gap - 264px between them at desktop width.
 * Half on each side means the space between two sections is the space that was
 * asked for, and the first and last sit flush against the header and footer.
 * ------------------------------------------------------------------ */

.dm-page-assembly--shell .dm-site-section {
  padding-block: calc(var(--dm-shell-section-space) / 2);
}

.dm-page-assembly--shell > .dm-site-section:first-child { padding-block-start: 0; }
.dm-page-assembly--shell > .dm-site-section:last-child { padding-block-end: 0; }

/* ------------------------------------------------------------------
 * Full bleed, owned here and nowhere else.
 *
 * The earlier rule widened the assembly with a negative inline margin, but the
 * assembly stylesheet loads later and pins the width back to 100%, so the block
 * moved left without growing. Viewport units are avoided as well, because
 * 100vw counts the scrollbar and produces a horizontal scroll.
 *
 * The theme container is widened instead. Nothing is stretched past the
 * viewport, so there is no overflow to clip.
 * ------------------------------------------------------------------ */

body.dm-site-shell-full-bleed .site-content > .ast-container {
  max-width: none;
  margin-inline: 0;
  padding-inline: 0;
}

body.dm-site-shell-full-bleed .dm-page-assembly.dm-page-assembly--shell {
  width: 100%;
  max-width: none;
  margin-inline: 0;
}

/* ---------------------------------------------------------------------------
 * The edge: a band that stands beside the stack instead of in it.
 *
 * One description of a left rail, for any pack that declares one. Nothing here
 * names a pack, a band or a colour: the width arrives as --dm-edge-width from
 * the skeleton, and the band that stands aside is the one the skeleton marked.
 *
 * The rail is the first row of the grid and spans as many rows as the bands it
 * stands beside, so a page reads as a rail plus a column of bands rather than a
 * band that happens to be narrow.
 * ------------------------------------------------------------------------- */
.dm-page-assembly[data-dm-edge="left-rail"] {
  display: grid;
  grid-template-columns: var(--dm-edge-width, 0) minmax(0, 1fr);
  align-items: start;
}

.dm-page-assembly[data-dm-edge="left-rail"] > .dm-slot {
  grid-column: 2;
}

/*
 * The rail stays put while the bands beside it scroll.
 *
 * `grid-row: 1 / -1` is the obvious way to make it stand the whole height and
 * it does nothing here: the rows are implicit, so -1 resolves to the end of the
 * explicit grid, which has none, and the rail occupies row 1 alone. Rather than
 * leave a rule that says one thing and does another, the rail is sticky, which
 * is what the reference does anyway — a rail that is always to hand, not one
 * drawn the full length of a very long page.
 */
.dm-page-assembly[data-dm-edge="left-rail"] > .dm-slot[data-dm-in-edge="yes"] {
  grid-column: 1;
  grid-row: 1;
  position: sticky;
  top: 0;
  min-width: 0;
}

/*
 * Below the skeleton's own breakpoint the rail stops being a rail. It is not
 * hidden — a category list is how this kind of shop is navigated, and dropping
 * it on a phone would lose the thing the pack is for — so it returns to the
 * stack as an ordinary first band.
 */
@media (max-width: 781px) {
  .dm-page-assembly[data-dm-edge="left-rail"] {
    display: block;
  }
  .dm-page-assembly[data-dm-edge="left-rail"] > .dm-slot[data-dm-in-edge="yes"] {
    position: static;
  }
}
