/**
 * 3MW Core Child Theme - Frontend Styles
 *
 * Client-specific customizations and style overrides
 * This file loads after the parent theme's frontend.min.css
 *
 * @package 3MW_Core_Child
 * @since 1.0.0
 */

/* ==========================================================================
   COMPONENT IMPORTS
   ========================================================================== */

@import url('components/navigation.css');
@import url('components/footer.css');
@import url('components/buttons.css');

/* ==========================================
   TABLE OF CONTENTS
   ========================================== */

/*
 * COMPONENT IMPORTS (at top of file):
 *   - components/navigation.css (header & nav styles)
 *   - components/footer.css (footer styles)
 *   - components/buttons.css (anchor button down-arrow)
 *
 * SECTIONS IN THIS FILE:
 *   - Variables
 *   - Mega Menus
 *   - Typography Overrides
 *   - Component Overrides
 *   - Block Customizations (various blocks)
 *   - Two-Column Alternating Block
 *   - Template-Specific Overrides
 *   - Prefooter CTA Block
 *   - Client-Specific Features
 *   - Responsive Overrides
 *   - Utility Classes
 *   - Hero Block Layouts
 *   - Tabbed Content Block
 *   - CTA Banner Block
 *   - Video Embeds (responsive iframe fallback)
 *
 * SEPARATE FILES:
 *   - Gravity Form form styles: frontend-gravity-forms.css
 *   - Block-specific styles: /blocks/[block-name]/style.css
 */

/* ==========================================
   VARIABLES
   ========================================== */

:root {
    /* Grid System Override */
    --row-gap: 20px;

    /* Colors & Gradients - Managed via Full Site Editor (FSE) */

    /* Use FSE > Site Editor > Colors/Gradients to add custom colors and gradients */

    /* No need to define color/gradient variables here - FSE handles all color management */

    /* WordPress FSE Color Mapping - Simple names → WordPress preset format */
    --color-primary: var(--wp--preset--color--blue);
    --color-primary-transparent: color-mix(in srgb, var(--color-primary) 25%, transparent);
    --color-secondary: var(--wp--preset--gradient--gradient-primary);
    --color-tertiary: var(--wp--preset--color--blue-navy);
    --color-bg: var(--wp--preset--color--gray-light);
    --color-bg-gradient: var(--wp--preset--gradient--gradient-blue-white);
    --color-accent: var(--wp--preset--color--blue-light);
    --color-input: var(--wp--preset--color--gray);
    --color-text-primary: var(--wp--preset--color--gray);
    --color-text-secondary: var(--wp--preset--color--gray-light);
    --color-text-light: var(--color-white);
    --color-text-light-muted: color-mix(in srgb, var(--color-text-light) 80%, transparent);

    /* muted text on dark */
    --color-link: var(--wp--preset--color--blue);
    --color-link-hover: var(--wp--preset--color--blue-navy);
    --color-border: var(--wp--preset--color--blue-light);
    --color-border-light: var(--wp--preset--color--gray-light);
    --color-border-dark: rgb(91 103 112 / 40%);
    --input-placeholder: var(--wp--preset--color--gray);
    --color-heading: var(--wp--preset--color--blue);
    --line-height-heading: 1.15em;
    --font-weight-normal: 500;
    --font-weight-heading: 400;

    /* Font families are now managed via Theme Settings > Typography */


    /* Client-Specific Custom Variables */
    --radius-xl: 40px;
    --radius-sm: 8px;

    /* Hero Subtitle - Larger lead font size for hero blocks & CTAs */
    --font-size-hero-subtitle: var(--wp--preset--font-size--hero-subtitle);
    --gradient-overlay: var(--wp--preset--color--gradient-overlay-2);

    /* Brand gradient — SITE-AWARE. Use this, not --gradient-primary.
       ------------------------------------------------------------------
       Cingal is a multisite network whose two sites use different brand
       gradients: the patient site's green-to-cyan ramp, and an all-blue
       variant on the HCP subsite. Anything that paints the brand gradient
       (gradient text, bullets, badges, underlines) must reference
       --brand-gradient so it re-themes automatically from the body class.

       Referencing --gradient-primary directly is a bug: it hardcodes the
       patient gradient, so the element renders green on HCP. That was the
       cause of the green-on-HCP blockquote and step-number defects.

       The override lives on .cingal-hcp below (the class
       tmw_child_hcp_body_class() puts on <body> for blog ID 2). */
    --brand-gradient: var(--wp--preset--gradient--gradient-primary);

    /* Individual stops of the brand gradient, for INLINE SVG only.
       SVG <stop stop-color> takes a single color and cannot read a CSS
       gradient, so --brand-gradient is unusable inside an inline SVG. These
       two tokens expose the same ramp as discrete colors so inline SVG
       gradients re-theme from the same body class instead of hardcoding hex.

       Keep these in sync with the gradient-primary / gradient-primary-hcp
       definitions in theme.json — they are the same colors, restated because
       theme.json only exposes the composed gradient, not its stops.

       For SVGs referenced as background-image (url(...)), do NOT use these —
       CSS cannot reach inside an external SVG file. Ship a per-site variant
       and swap the URL under .cingal-hcp, as the checkmark bullets do. */
    --brand-gradient-start: #64A234;
    --brand-gradient-end: #1EA0CA;

    /* Comparison status colors — shared by the Comparison Table and
       Head-to-Head Cards blocks.

       These are status indicators, not brand colors: a red "x" must stay red
       on both subsites, so unlike the check/plus icons (which paint with
       --brand-gradient-start/-end) they are NOT re-themed under .cingal-hcp.
       They are defined once here rather than in each block's style.css so the
       two blocks cannot drift apart.

       The "qualified" state is the palette grey rather than an amber. The
       palette is all blues and neutrals with no warm color, so the amber this
       replaced (#E07A20) read as foreign — and it measured 3.01:1 on white and
       2.7:1 on the highlighted column, failing WCAG AA for the small text it
       was used on. Grey is 5.8:1 and semantically better suited: a value like
       "Partial" is a qualified yes, not a warning, and with the gradient
       carrying positive and red carrying negative, a muted neutral reads as
       "less emphatic" without introducing an off-brand hue. */
    --comparison-icon-negative: #A82222;
    --comparison-icon-qualified: var(--wp--preset--color--gray);
}

/* HCP subsite: swap the brand gradient to the all-blue variant. Scoped to the
   body class, so every --brand-gradient consumer re-themes with no per-element
   override needed. */
.cingal-hcp {
    --brand-gradient: var(--wp--preset--gradient--gradient-primary-hcp);
    --brand-gradient-start: #1A559A;
    --brand-gradient-end: #1D96BF;
}

body {
    color: var(--color-text-primary);
}

.flexible-content-wrapper .text-lead,
.flexible-content-wrapper .lead-text {
    margin-bottom: revert;
}

:focus-visible {
    outline: 1px dashed var(--wp--preset--color--blue);
    outline-offset: 2px;
}

.section-header {
    margin-bottom: var(--space-xl);
}

.wp-block-image img {
    border-radius: var(--radius-card);
}

.announcement-bar .announcement-bar-cta:hover::before {
    opacity: 0.4;
}

.breadcrumbs-list,
.breadcrumbs-list a {
    color: var(--color-primary);
}

.breadcrumbs-list span.current {
    padding: 3px 0;
}

/* Breadcrumbs container padding - match main container padding at each breakpoint
   1200px-1280px: matches base .container (--space-xl)
   <= 1200px: matches responsive.css .container override (--space-md) */
@media (1200px < width < 1280px) {
    .breadcrumbs .container {
        padding-left: var(--space-xl);
        padding-right: var(--space-xl);
    }
}

@media (width <=1200px) {
    .breadcrumbs .container {
        padding-left: var(--space-md);
        padding-right: var(--space-md);
    }
}

.wp-block-separator {
    background-color: var(--color-border) !important;
}

/* ==========================================
   TABLE STYLING - Modern & Accessible
   ========================================== */

/* Base table structure - scoped to block editor tables and post content only */
:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    overflow: hidden;
    background: var(--color-white);
}

:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table:not(.comparison-table__table) thead th {
    /* color: var(--color-white); */
    font-weight: var(--font-weight-semibold);
    padding: var(--space-md) var(--space-lg);
    border: none;
    border-bottom: 2px solid var(--color-primary);
}

:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table thead th:first-child {
    border-top-left-radius: var(--radius-card);
}

:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table thead th:last-child {
    border-top-right-radius: var(--radius-card);
}

/* Table body */
:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table:not(.comparison-table__table) tbody td {
    padding: var(--space-md) var(--space-lg);
    border: none;
    border-bottom: 1px solid var(--color-border-light);
    color: var(--color-text-primary);
    vertical-align: top;
}

/* Zebra striping */
:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table:not(.comparison-table__table) tbody tr:nth-child(even) {
    background-color: var(--wp--preset--color--gray-light);
}

/* Last row rounded corners */
:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table tbody tr:last-child td {
    border-bottom: none;
}

:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table tbody tr:last-child td:first-child {
    border-bottom-left-radius: var(--radius-card);
}

:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table tbody tr:last-child td:last-child {
    border-bottom-right-radius: var(--radius-card);
}

/* Table footer */
:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table tfoot {
    background-color: var(--wp--preset--color--gray-light);
    font-weight: var(--font-weight-semibold);
}

:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table tfoot td {
    padding: var(--space-md) var(--space-lg);
    border-top: 2px solid var(--color-border);
}

/* Caption */
.wp-block-table figcaption,
.entry-content:not(.gform_confirmation_message) table caption {
    caption-side: bottom;
    padding: var(--space-sm) var(--space-md);
    font-size: var(--font-size-small);
    font-style: italic;
}

/* Links in tables */
:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table td a {
    color: var(--color-primary);
    text-decoration: underline;
    text-underline-offset: 2px;
}

:is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table td a:hover {
    color: var(--color-bg);
    text-decoration: none;
}

/* Mobile responsive */
@media (width <=768px) {
    figure.wp-block-table {
        width: 100%;
        margin: 0 0 var(--space-lg) 0;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    :is(figure.wp-block-table, .wp-block-table, .entry-content:not(.gform_confirmation_message)) table {
        width: 100% !important;
        min-width: 100%;
    }

    figure.wp-block-table table.has-fixed-layout {
        table-layout: auto;
    }

    /* `word-break: break-word` splits words mid-character whenever the auto
       table layout offers a cell a narrow column, so a single header word can
       lose its last letter to a second line ("Characteristi/c"). Breaking at
       word boundaries instead lets the column claim the width it needs, and
       only splits a word when it genuinely cannot fit its cell. */
    :is(.wp-block-table, .entry-content:not(.gform_confirmation_message)) table :is(th, td),
    table:not(.wp-calendar-table, .gfield_list) :is(th, td) {
        padding: var(--space-sm) var(--space-md);
        white-space: normal;
        word-break: normal;
        overflow-wrap: break-word;
    }
}

.section-subtitle {
    max-width: var(--max-width-content-lg);
    font-size: var(--font-size-lead);
}

.section-subtitle,
.section-subtitle p {
    color: inherit;
}

/* Utility Menu - Override parent theme's color: inherit */
.utility-menu a {
    color: var(--color-primary);
}

.nav-menu--mobile {
    background: var(--color-white);
    color: var(--color-heading);
}

.cingal-hcp .nav-menu--mobile {
    background: var(--wp--preset--color--blue-navy) !important;
}

.mobile-menu__link,
.mobile-menu__toggle {
    font-size: var(--font-size-lead);
    color: var(--color-heading);
    padding: var(--space-lg) var(--space-md);
}

/* Set constant padding to prevent shift during expand/collapse animation */
.mobile-submenu {
    padding: 0 0 var(--space-lg) var(--space-md);
}

.nav-menu--mobile .mobile-submenu .mobile-menu__link {
    padding-left: 0;
}

.nav-menu--mobile .mobile-submenu__link.mobile-submenu__link--parent {
    text-transform: uppercase;
    font-weight: var(--font-weight-semibold);
}

.nav-menu--mobile .mobile-submenu__item.column-title a,
.mobile-footer-menu__list .sub-menu .column-title a {
    text-transform: uppercase;
    font-size: var(--font-size-body);
}

.nav-menu--mobile .mobile-submenu__item.column-title a {
    font-weight: var(--font-weight-semibold);
    border-bottom: 1px solid var(--color-border);
}

.mobile-footer-menu__list .sub-menu .column-title a {
    margin-bottom: var(--space-sm);
    border-bottom: 1px solid rgb(255 255 255 / 15%);
}

.nav-menu--mobile .has-submenu .mobile-submenu__item.column-title:not(:first-of-type) {
    margin-top: 1em;
}

/* ==========================================
   MEGA MENUS
   ========================================== */

/* Mobile Column Title Links */
.mobile-submenu__link--column-title {
    min-height: fit-content;
    color: var(--color-primary);
    padding-bottom: 0;
    margin-top: var(--space-md);
    margin-bottom: var(--space-xs);
}

/* Column Title Links */
.mega-menu__column-title-link {
    text-decoration: none;
    color: inherit;
    transition: color var(--transition-base);
}

.mobile-submenu__item--column-title:first-child {
    margin-top: 0;
}

.mobile-submenu__link--column-title:hover {
    color: var(--color-primary);
}

/* ==========================================
   TYPOGRAPHY OVERRIDES
   ========================================== */

/* Uses --brand-gradient, so the HCP subsite gets the all-blue variant with no
   per-element override. This replaced a `.cingal-hcp blockquote:not(…)` rule
   that had to re-declare the gradient AND carry a :not() guard to stay behind
   the dark-background reset below — the token needs neither, because it resolves
   per-site before the cascade and the dark reset still wins on source order.

   The gradient paint is applied to the TEXT-BEARING element, not to the
   blockquote itself. `background-clip: text` clips an element's background to
   that element's *own* text, and a core-editor blockquote holds no direct text
   nodes — its copy lives in child `<p>`s (`<blockquote><p>…</p></blockquote>`).
   Declaring the gradient on the blockquote therefore clips it to an empty text
   area; that the quote is visible at all in most builds relies on Chrome
   painting a parent's clipped background across descendant text, which is not
   guaranteed. Some Chrome builds (reported on Android/Chrome mobile) clip to
   the letter — the gradient paints nothing while the inherited
   `-webkit-text-fill-color: transparent` still hides the glyphs, so the quote
   renders as blank space. Painting on the child makes the text its own clip
   target, which is what the property is specified to do.

   `color` is set alongside every `-webkit-text-fill-color: transparent` so the
   text degrades to a solid brand color instead of vanishing if the gradient
   ever fails to paint (unsupported `background-clip: text`, or the token
   resolving to `none`). */
blockquote {
    border-left: 4px solid transparent;
    border-image-source: var(--brand-gradient);
    border-image-slice: 1;
    font-style: normal;
    font-size: var(--font-size-h6);
    font-family: var(--font-family-heading);
    font-weight: var(--font-weight-medium);
    margin-left: 0;
    padding-left: var(--space-md);
}

/* Paint the gradient on whatever actually carries the text: the child <p>s of a
   core-editor blockquote, or the blockquote itself when it holds direct text
   (`:not(:has(p))` covers hand-authored or legacy markup). */
blockquote p,
blockquote:not(:has(p)) {
    color: var(--color-primary);
    background: var(--brand-gradient);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

/* Eyebrow labels inside a blockquote (e.g. "Finding 1:") should read as a
   solid Navy Blue label, not the bright gradient quote treatment above —
   breaks up the gradient visually when multiple findings/quotes stack.
   Must come after the base gradient rule (same specificity) so it wins here,
   but before the dark-background override below so dark mode still applies
   correctly (equal specificity resolved by source order). */
blockquote p.eyebrow-text {
    background: none;
    color: var(--color-tertiary);
    -webkit-text-fill-color: var(--color-tertiary);
}

/* Dark background overrides - reset gradient text to white. Targets the same
   text-bearing elements as the rule above so it can undo the transparent fill. */
:is([data-dark-bg="true"], [data-section-dark-bg="true"], .hero-text-light) blockquote {
    border-image-source: none;
    border-left-color: var(--color-text-light);
    border-left-width: 2px;
}

:is([data-dark-bg="true"], [data-section-dark-bg="true"], .hero-text-light) blockquote p,
:is([data-dark-bg="true"], [data-section-dark-bg="true"], .hero-text-light) blockquote:not(:has(p)) {
    background: none;
    color: var(--color-text-light);
    -webkit-text-fill-color: var(--color-text-light);
}

/* Keep the eyebrow label legible on dark backgrounds too - same light color
   as the rest of the dark-background blockquote text. */
:is([data-dark-bg="true"], [data-section-dark-bg="true"], .hero-text-light) blockquote p.eyebrow-text {
    color: var(--color-text-light);
    -webkit-text-fill-color: var(--color-text-light);
}

/* Uses --brand-gradient, so HCP gets the all-blue variant automatically. */
h1 b,
h2 b,
h3 b,
h4 b,
h5 b,
h6 b,
h1 strong,
h2 strong,
h3 strong,
h4 strong,
h5 strong,
h6 strong {
    background: var(--brand-gradient);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    font-weight: var(--font-weight-normal);
    line-height: normal;
}

/* HCP subsite: bolded gradient text runs one weight heavier.
   The gradient itself is NOT re-declared here — --brand-gradient already
   resolves to the blue variant under .cingal-hcp. Only the weight differs,
   which is a genuine per-site difference rather than a gradient override. */
.cingal-hcp :is(h1, h2, h3, h4, h5, h6) :is(b, strong) {
    font-weight: var(--font-weight-medium);
}

:is([data-dark-bg="true"], [data-section-dark-bg="true"], .hero-text-light) :is(h1, h2, h3, h4, h5, h6) :is(strong, b) {
    background: none;
    -webkit-background-clip: none;
    -webkit-text-fill-color: var(--color-text-light);
}

/* Text Wrap - Improved line breaking for better typography
   Avoids orphans and creates more balanced paragraph endings.
   Excludes elements with .balance or .text-balance classes. */
.entry-content div:not(.balance, .text-balance),
.wysiwyg-editor-content p:not(.balance, .text-balance) {
    text-wrap: pretty;
}

/* When the WYSIWYG Editor block carries the .text-balance class (Advanced →
   Additional CSS class), balance its paragraphs instead of the pretty default. */
.text-balance .wysiwyg-editor-content p {
    text-wrap: balance;
}

/* ==========================================================================
   Eyebrow Text - Global Utility Class
   Small uppercase label displayed above a heading.
   ========================================================================== */

.eyebrow-text {
    display: block;
    font-size: var(--font-size-small);
    font-weight: var(--font-weight-medium);
    text-transform: uppercase;
    margin-block-end: 0;
}

.eyebrow-text+* {
    margin-block-start: var(--space-xs);
}

/* When eyebrow-text is inside a flex column (e.g. flexible-content-wrapper),
   gap overrides margins. Use negative margin to pull the next sibling closer. */
.flexible-content-wrapper>.eyebrow-text+* {
    margin-block-start: calc(var(--block-spacing, var(--space-xl)) * -1 + var(--space-xs));
}

.cingal-hcp .eyebrow-text {
    color: var(--color-tertiary);
    font-size: var(--font-size-body);
}

.cingal-hcp .eyebrow-text.default-case {
    text-transform: none;
}

/* ==========================================================================
   Post Navigation (Previous / Next) - Single Post Template
   `core/post-navigation-link` ships no color of its own and neither the parent
   theme nor this child theme styled it, so the links fell through to the
   browser default (#0000EE, underlined) on single posts. Pinned to the design
   system here rather than in the block template so both links and all their
   states are covered in one place.
   ========================================================================== */

.wp-block-post-navigation-link a {
    color: var(--color-primary);
    font-weight: var(--font-weight-semibold);
    text-decoration: none;
    transition: color 0.2s ease;
}

.wp-block-post-navigation-link a:hover,
.wp-block-post-navigation-link a:focus-visible {
    color: var(--color-primary-dark);
    text-decoration: underline;
}

/* The chevron arrows are rendered as spans *outside* the anchor, so they do not
   inherit the link color - match them to it explicitly, and keep them clear of
   the underline the anchor picks up on hover. */
.wp-block-post-navigation-link__arrow-previous,
.wp-block-post-navigation-link__arrow-next {
    color: var(--color-primary);
    display: inline-block;
    text-decoration: none;
}

.wp-block-post-navigation-link:hover .wp-block-post-navigation-link__arrow-previous,
.wp-block-post-navigation-link:hover .wp-block-post-navigation-link__arrow-next {
    color: var(--color-primary-dark);
}

/* On dark sections, inherit the adapted text color instead of the fixed dark one. */
[data-section-dark-bg="true"] .wp-block-post-navigation-link a {
    color: var(--adapt-text-color, var(--color-white));
}

/* The post-nav row is the last element in the single-post content section, and
   the References Dropdown that would follow it renders only on posts that have
   references. When the accordion IS present its own `section-padding-lg` top
   padding supplies the gap; when it is absent the nav row butts up against the
   next section. So add the spacing to the content section only when it is NOT
   followed by the references block - `:has(+ ...)` keeps this conditional in CSS
   rather than requiring a body class or template change.

   Scoped by `section` + a descendant post-nav row so it matches only the single
   post content section. `parts/footer.html` also uses `.wp-block-group.container`
   (on a `div`, with no nav row) and must not pick this up. */
section.wp-block-group.container:has(.wp-block-post-navigation-link):not(:has(+ .references-dropdown)) {
    padding-bottom: var(--space-2xl);
}

/* ==========================================================================
   Link Font Weigit - On-Page Content Links Only
   Only links within paragraphs and list items should be bold.
   Navigation, header, footer, and card links remain normal weight.
   ========================================================================== */

/* Content links - bold for in-paragraph/in-list links */
.entry-content p a:not(.btn),
.entry-content li a,
.flexible-content-wrapper p a,
.flexible-content-wrapper li a,
#main-content p a:not(.btn),
#main-content li a,
.wysiwyg-content p a,
.wysiwyg-content li a,
.box-description p a,
.box-description li a {
    font-weight: var(--font-weight-semibold);
}

/* Content links - remove underline on hover */
.entry-content p a:hover,
.entry-content li a:hover,
.flexible-content-wrapper p a:hover,
.flexible-content-wrapper li a:hover,
#main-content p a:hover,
#main-content li a:hover,
.wysiwyg-content p a:hover,
.wysiwyg-content li a:hover,
.box-description p a:hover,
.box-description li a:hover {
    text-decoration: none;
}

/* Ensure navigation, header, footer, and card links stay normal weight */
header a,
footer a,
nav a,
.site-header a,
.site-footer a,
.card a,
.card-title a,
.box-title a,
.btn,
.button,
.breadcrumbs a,
.breadcrumbs-list a,
.mega-menu a,
.mobile-menu a,
.utility-menu a,
.post-meta a,
.archive-meta a,
.pagination a,
sup a,
a sup {
    font-weight: var(--font-weight-normal);
}

/* Default heading styles */
h1,
h2,
h3,
h4,
h5,
h6 {
    font-weight: var(--font-weight-heading);
}

h5,
.h5 {
    font-weight: var(--font-weight-medium);
    line-height: var(--line-height-relaxed);
}

.cingal-hcp h2,
.cingal-hcp h3,
.cingal-hcp h4,
.cingal-hcp h5,
.cingal-hcp h6 {
    font-weight: var(--font-weight-medium);
}

.cingal-hcp h5,
.cingal-hcp .h5 {
    font-weight: var(--font-weight-normal);
}

/* Headings inherit text color in dark background sections */
[class*="bg-dark"] :is(h1, h2, h3, h4, h5, h6),
.dark-bg :is(h1, h2, h3, h4, h5, h6),
.has-text-color :is(h1, h2, h3, h4, h5, h6) {
    color: inherit;
}

/* List Styles - Gradient bullets via ::before (::marker doesn't support gradients)
   .context-caveats is a custom class used in some two-column-content WYSIWYG
   blocks (e.g. clinical-evidence/real-world-data); included here so it gets
   the same gradient dots as unclassed/wp-block-list lists instead of
   falling back to the browser's default disc bullet. */
ul:not([class]),
ul.wp-block-list,
ul.context-caveats {
    margin-left: 0;
    padding-left: 0;
}

ul:not([class]) li,
ul.wp-block-list li,
ul.context-caveats li {
    list-style: none;
    padding-left: var(--space-lg);
    position: relative;
}

ul:not([class]) li::before,
ul.wp-block-list li::before,
ul.context-caveats li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.55em;
    width: 8px;
    height: 8px;
    border-radius: var(--radius-full);
    background: var(--brand-gradient);
    flex-shrink: 0;
}

/* Context-caveat lists match the lead/subtitle size of the section copy
   around them (e.g. real-world-data) rather than the default body size. */
ul.context-caveats {
    font-size: var(--font-size-lead);
}

/* Ordered Lists - Bold numbers, indentation matched to gradient bullets above.
   CSS counters replace ::marker so the number can be bolded and absolutely
   positioned at the same left offset the bullets use. */
ol:not([class]),
ol.wp-block-list {
    counter-reset: ordered-list;
    margin-left: 0;
    padding-left: 0;
}

ol:not([class]) li,
ol.wp-block-list li {
    counter-increment: ordered-list;
    list-style: none;
    padding-left: var(--space-lg);
    position: relative;
}

/* The number is right-aligned inside an 8px box — the same width as the gradient
   bullet — so its right edge lands where a bullet's does. Without this the wider
   number glyphs grow rightward toward the text and read as over-indented.

   `white-space: nowrap` is load-bearing, not cosmetic: "N." is wider than the
   8px box by design, and overflowing an absolutely-positioned box is harmless
   *until* an ancestor sets `overflow-wrap: anywhere` / `word-break: break-word`.
   Both inherit into ::before, and given permission to break anywhere inside 8px
   the browser drops the period onto a second line under every number. Any
   container that wraps long URLs — citation lists, footnotes, narrow columns —
   sets those properties, so the guard belongs here on the counter rather than
   being re-fixed per block. First seen in the References block on HCP. */
ol:not([class]) li::before,
ol.wp-block-list li::before {
    content: counter(ordered-list) '.';
    position: absolute;
    left: 0;
    top: 0;
    width: 8px;
    white-space: nowrap;
    text-align: right;
    font-weight: var(--font-weight-bold);
}


/* ==========================================================================
   Checkmarks List - Custom WYSIWYG Formats
   Applied via Formats dropdown in TinyMCE editor
   Two variants: filled (default) and outlined
   ========================================================================== */

/* Shared styles for both checkmarks list variants.
   Raw `.checkmarks-list` classes come from the classic TinyMCE Formats dropdown.
   `.is-style-checkmarks-list` classes come from the Gutenberg List block Styles panel. */
.checkmarks-list,
.checkmarks-list-outlined,
.is-style-checkmarks-list,
.is-style-checkmarks-list-outlined {
    list-style: none;
    padding-left: 0;
    margin-left: 0;
}

/* `ul` qualifier raises specificity to override the generic gradient-bullet
   rule (`ul.wp-block-list li::before`), which would otherwise win because the
   list block carries the `wp-block-list` class. */
ul.checkmarks-list li,
ul.checkmarks-list-outlined li,
ul.is-style-checkmarks-list li,
ul.is-style-checkmarks-list-outlined li {
    position: relative;
    padding-left: 1.75em;
    margin-bottom: var(--space-sm);
}

ul.checkmarks-list li::before,
ul.checkmarks-list-outlined li::before,
ul.is-style-checkmarks-list li::before,
ul.is-style-checkmarks-list-outlined li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.275em;
    width: 18px;
    height: 18px;
    border-radius: 0;
    background-color: transparent;
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
}

/* Filled checkmark (default) */
ul.checkmarks-list li::before,
ul.is-style-checkmarks-list li::before {
    background-image: url('/wp-content/themes/3mw-core-child/assets/images/icon-checkmark.svg');
}

/* HCP subsite only: blue gradient checkmark (matches gradient-primary-hcp).
   The gradient lives in the SVG itself, so we swap to a blue variant rather
   than recolor via CSS. Scoped to .cingal-hcp so the main site is unaffected. */
.cingal-hcp ul.checkmarks-list li::before,
.cingal-hcp ul.is-style-checkmarks-list li::before,
.cingal-hcp ul.checkmarks-list ul li::before,
.cingal-hcp ul.is-style-checkmarks-list ul li::before {
    background-image: url('/wp-content/themes/3mw-core-child/assets/images/icon-checkmark-hcp.svg');
}

/* Outlined checkmark variant */
ul.checkmarks-list-outlined li::before,
ul.is-style-checkmarks-list-outlined li::before {
    background-image: url('/wp-content/themes/3mw-core-child/assets/images/icon-checkmark-outline.svg');
}

/* HCP subsite: same blue swap for the outlined variant. Without this, an
   outlined WYSIWYG list rendered green on HCP while the filled variant above
   and the Comparison Table's own outlined check icon
   (blocks/comparison-table/style.css) both went blue — the two check styles
   on one HCP page disagreed. The x-list variants below are deliberately NOT
   given an HCP override: that red is a fixed status color on both subsites
   (see --comparison-icon-negative). */
.cingal-hcp ul.checkmarks-list-outlined li::before,
.cingal-hcp ul.is-style-checkmarks-list-outlined li::before,
.cingal-hcp ul.checkmarks-list-outlined ul li::before,
.cingal-hcp ul.is-style-checkmarks-list-outlined ul li::before {
    background-image: url('/wp-content/themes/3mw-core-child/assets/images/icon-checkmark-outline-hcp.svg');
}

/* Nested lists within checkmarks lists inherit their parent's style */
ul.checkmarks-list ul,
ul.checkmarks-list-outlined ul,
ul.is-style-checkmarks-list ul,
ul.is-style-checkmarks-list-outlined ul {
    list-style: none;
    padding-left: 0;
    margin-top: var(--space-sm);
}

ul.checkmarks-list ul li::before,
ul.is-style-checkmarks-list ul li::before {
    background-image: url('/wp-content/themes/3mw-core-child/assets/images/icon-checkmark.svg');
}

ul.checkmarks-list-outlined ul li::before,
ul.is-style-checkmarks-list-outlined ul li::before {
    background-image: url('/wp-content/themes/3mw-core-child/assets/images/icon-checkmark-outline.svg');
}

/* ==========================================================================
   X / Cross List Styles
   Two variants: filled (default) and outlined
   ========================================================================== */

/* Shared styles for both x-list variants */
.x-list,
.x-list-outlined {
    list-style: none;
    padding-left: 0;
    margin-left: 0;
}

.x-list li,
.x-list-outlined li {
    position: relative;
    padding-left: 1.75em;
    margin-bottom: var(--space-sm);
}

.x-list li::before,
.x-list-outlined li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.275em;
    width: 18px;
    height: 18px;
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
}

/* Filled x (default) */
.x-list li::before {
    background-image: url('/wp-content/themes/3mw-core-child/assets/images/icon-x.svg');
}

/* Outlined x variant */
.x-list-outlined li::before {
    background-image: url('/wp-content/themes/3mw-core-child/assets/images/icon-x-outline.svg');
}

/* Nested lists within x-lists inherit their parent's style */
.x-list ul,
.x-list-outlined ul {
    list-style: none;
    padding-left: 0;
    margin-top: var(--space-sm);
}

.x-list ul li::before {
    background-image: url('/wp-content/themes/3mw-core-child/assets/images/icon-x.svg');
}

.x-list-outlined ul li::before {
    background-image: url('/wp-content/themes/3mw-core-child/assets/images/icon-x-outline.svg');
}

/* ==========================================================================
   White check / cross lists — white-circle bullets (for dark backgrounds).
   `checkmarks-list-white` uses white-check.svg; `x-list-white` uses
   white-cross.svg. `ul` qualifier raises specificity above the generic
   gradient-bullet rule (`ul.wp-block-list li::before`).
   ========================================================================== */

.checkmarks-list-white,
.x-list-white,
.is-style-checkmarks-list-white,
.is-style-x-list-white {
    list-style: none;
    padding-left: 0;
    margin-left: 0;
}

ul.checkmarks-list-white li,
ul.x-list-white li,
ul.is-style-checkmarks-list-white li,
ul.is-style-x-list-white li {
    position: relative;
    padding-left: 1.75em;
    margin-bottom: var(--space-sm);
}

ul.checkmarks-list-white li::before,
ul.x-list-white li::before,
ul.is-style-checkmarks-list-white li::before,
ul.is-style-x-list-white li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.275em;
    width: 18px;
    height: 18px;
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
}

ul.checkmarks-list-white li::before,
ul.is-style-checkmarks-list-white li::before,
ul.checkmarks-list-white ul li::before,
ul.is-style-checkmarks-list-white ul li::before {
    background-image: url('/wp-content/themes/3mw-core-child/assets/images/white-check.svg');
}

ul.x-list-white li::before,
ul.is-style-x-list-white li::before,
ul.x-list-white ul li::before,
ul.is-style-x-list-white ul li::before {
    background-image: url('/wp-content/themes/3mw-core-child/assets/images/white-cross.svg');
}

ul.checkmarks-list-white ul,
ul.x-list-white ul,
ul.is-style-checkmarks-list-white ul,
ul.is-style-x-list-white ul {
    list-style: none;
    padding-left: 0;
    margin-top: var(--space-sm);
}

/* Trademark and Registered Symbols - Readable inline styling */

/* Visible but subtle superscript styling */
sup {
    font-size: 0.65em;

    /* readable but not dominant */
    vertical-align: super;

    /* Standard superscript positioning */
    line-height: 0;

    /* Prevent affecting line height */
    font-weight: normal;

    /* Always use normal weight */
    font-style: normal;

    /* Never italic */
}

/* Links with superscripts - no underline, consistent styling */
sup a,
a sup {
    font-weight: inherit;
    text-decoration: none;
}

/* Links that wrap superscripts (e.g., reference citations) - remove underline */
a:has(sup) {
    text-decoration: none;
}

/* Superscripts in headings - slightly smaller relative to large text */
:is(h1, h2, h3, h4, h5, h6) sup {
    font-weight: normal;
    font-size: 60%;
    vertical-align: super;
}

/* Helper class for manual application to unwrapped symbols */
.tm-symbol {
    font-size: 0.65em;
    vertical-align: super;
    line-height: 0;
    font-weight: normal;
    font-style: normal;
}

/* No Wrap - Prevents line breaking between words
   Apply via Formats dropdown in TinyMCE editor to keep words together.
   More reliable than &nbsp; which can be stripped by editor processing. */
.nowrap {
    white-space: nowrap;
}

/* ==========================================
   COMPONENT OVERRIDES
   ========================================== */

.btn,
input[type="submit"],
button[type="submit"],
.wp-element-button,
.wp-block-button__link {
    padding: 12px 24px;
    font-weight: var(--font-weight-normal);
}

.btn-arrow svg.icon-chevron-right {
    top: 1px;
    position: relative;
}

.btn-arrow:is(:hover, :focus, :active) svg {
    transform: translate(15%, 0);
}

.card-image,
.card-media img {
    object-position: top;
}

/* ==========================================================================
   404 Page Search Button - Match Search Results Page Styling
   ========================================================================== */

/* Global search input styling */
.wp-block-search__input {
    border-radius: var(--radius-card);
    flex: 1;
    padding: var(--space-sm) var(--space-md);
    font-size: var(--font-size-body);
    background: var(--color-white);
    line-height: var(--line-height-normal);
    box-shadow: var(--shadow-sm);
    outline: none;
    border: 1px solid var(--color-border);
    transition: box-shadow var(--transition-base);
}

.btn-arrow::before {
    background: var(--color-primary);
    height: 1px;
}

.card-action {
    font-weight: var(--font-weight-semibold);
}

.card-action::before {
    display: none;
}

/* Hide arrow icon on card action links (for featured posts, dynamic archives, etc.) */
.card-action svg,
.card-action .btn-icon {
    display: none;
}

.badge[data-badge-variant="primary"] {
    background: var(--color-primary);
    color: var(--color-white);
    text-transform: uppercase;
    font-size: var(--font-size-small);
    border-radius: var(--radius-sm);
    padding-left: var(--space-sm);
    padding-right: var(--space-sm);
}

/* Taxonomy tags (archive-meta-tags) styled as primary badges */
.archive-meta-tags .badge.badge-pill {
    background: var(--color-primary);
}

.archive-meta-tags .badge.badge-pill:hover,
.archive-meta-tags .badge.badge-pill:focus {
    background: var(--color-secondary);
}

/* Light Badges */
.badge.badge-pill.pill-light {
    background: var(--color-white);
    color: var(--color-primary);
}

.badge.badge-pill.pill-light:hover,
.badge.badge-pill.pill-light:focus {
    background: var(--color-secondary);
}


/* ==========================================
   PLATFORM BLOCK CUSTOMIZATIONS
   ========================================== */

section:not(.has-text-color) .platform-description {
    color: var(--color-text-primary);
}

/* ==========================================
   FEATURED/MOST RECENT POSTS CUSTOMIZATIONS
   ========================================== */

.badge:not(.badge-pill) {
    background: transparent;
}

.card {
    border-color: var(--color-border);
    background: var(--color-bg);
}

.card-date-banner {
    flex-wrap: wrap;
}

.card-date-banner::before,
.card-date-banner::after {
    background-color: var(--color-primary);
    height: 0;
}

.card-date-banner .date-icon {
    color: var(--color-primary);
}

/* Stack location below date instead of inline with separator */
.card-date-banner .date-separator {
    flex-basis: 100%;
    height: 0;
    overflow: hidden;
    margin: 0;
    padding: 0;
}

/* Blog post date - dark text, no icon (cards + single post) */
.card--post .card__date,
.post-date.wp-block-post-date {
    color: var(--color-text-primary);
}

/* Card date uses the eyebrow-text treatment to match the single post template,
   where the date already carries the `eyebrow-text` class via single.html.
   The card template comes from 3mw-base and cannot add that class without
   overriding the whole block, so the properties are applied to the existing
   selector instead - deliberately mirroring the `.eyebrow-text` rule above
   (small, medium weight, uppercase) rather than restating arbitrary values.
   Color is intentionally left to the rule above so the per-site override
   (`.cingal-hcp .eyebrow-text`) and dark-background adaptation still apply. */
.card--post .card__date {
    display: block;
    font-size: var(--font-size-small);
    font-weight: var(--font-weight-medium);
    text-transform: uppercase;
}

.card-excerpt,
.has-text-color .card .card-excerpt {
    color: var(--color-text-primary);
}

/* Card title links - remove default link styling for consistency across all post types */
.card-title a {
    color: inherit;
    text-decoration: none;
    transition: color var(--transition-base);
}

.card:hover .card-title,
.card:hover .card-title a,
.card-wrapper:hover .post-title,
.post-card:hover .post-title {
    text-decoration: underline;
    text-decoration: none;
}

.layout-masonry .post-card {
    border: 1px solid var(--color-border);
    background: var(--color-bg);
}

.featured-recent-posts-wrapper .card {
    border-color: var(--color-border);
    background: var(--color-bg);
}

.layout-masonry .eyebrow-text {
    display: none;
}

/* ==========================================
   CORE VIDEO BLOCK CUSTOMIZATIONS
   ========================================== */

/* Gutenberg writes inline margin-left/margin-right (spacing block support)
   on the figure even when centered. Those inline values override the
   parent theme's auto margins for .aligncenter, pinning the video to the
   left when its max-width is narrower than the flexible-content-wrapper. */
.wp-block-video.aligncenter {
    margin-left: auto !important;
    margin-right: auto !important;
}

/* Parent theme sets display:block on img but not video, leaving video at
   its UA-default display:inline. That reserves a few px below the element
   for text descenders, exposing the section background as a thin line —
   Windows Chrome renders this gap more visibly than macOS Chrome. */
.wp-block-video video {
    display: block;
}

/* ==========================================
   DROPDOWN ACCORDION ROWS CUSTOMIZATIONS
   ========================================== */
.dropdown-accordion-rows__accordions {
    row-gap: var(--space-sm);
}

.dropdown-accordion-rows__grid {
    --row-gap: var(--space-xl);
}

.dropdown-accordion-rows__header {
    gap: var(--space-sm);
}

/* Question text sits one clear step above the answer copy. At
   --font-size-hero-subtitle (22px) against the 18px answer body the 4px gap
   read as too subtle, so this steps up to --font-size-h5 (28px) rather than
   shrinking the answer below a comfortable reading size. */
.dropdown-accordion-rows__header-title {
    font-size: var(--font-size-h5);
    font-family: var(--font-family-heading);
    line-height: var(--line-height-heading);
    font-weight: var(--font-weight-normal);
}

.dropdown-accordion-rows__item ul li::before {
    background: var(--wp--preset--color--blue-mid);
}

/* Side-by-side layout's heading column defaults to col-4 (33%, ~288px at
   ~1280px viewport). At the title's fluid H1/H2 size a long word (e.g.
   "Osteoarthritis") needs ~362px — more than the column has even on its own
   line — so it overflows (overflow-wrap defaults to normal) past the column
   boundary and visually bleeds into the accordion column next to it.
   overflow-wrap: break-word would "fix" this by hyphen-splitting the word
   mid-letter, which is worse than the overlap it replaces. The 12-column
   grid only offers whole-span steps: span 5 (~374px) leaves just ~12px of
   clearance — too fragile against a slightly longer word or a translated
   string — while span 6 (50/50, ~460px) clears it comfortably but reads
   oversized next to the accordion column. Overriding this block's own grid
   template with an explicit minmax() gets a size between those two steps
   (~400px, ~38px clearance) without being locked to /12 increments; span: 1
   on the columns targets that single custom track instead of the (now
   irrelevant) 12-column span they'd otherwise consume. Scoped to this block
   so other col-4/col-8/.row users are untouched.

   Gated to width >= 1025px: the plugin's own @media (width <= 991px) rule
   switches this layout to stacked (position: static, centered), but relies
   on col-md-12 (grid-column: span 12, firing at <= 1024px) to make each
   column full-width first. Our 2-track override would leave col-md-12
   spanning a 12-track grid that no longer exists between 992px and 1024px,
   so the override must not be active in that range either. */
@media (width >=1025px) {
    .dropdown-accordion-rows--layout-side-by-side .dropdown-accordion-rows__grid {
        grid-template-columns: minmax(400px, 38%) 1fr;
    }

    .dropdown-accordion-rows--layout-side-by-side .dropdown-accordion-rows__heading-col,
    .dropdown-accordion-rows--layout-side-by-side .dropdown-accordion-rows__accordion-col {
        grid-column: span 1;
    }
}

/* Sticky heading offset (side-by-side layout only).
   The plugin pins the heading at `top: var(--space-xl)` (~58px), which sits
   behind the sticky site header (~80px) and, where present, the fixed
   sub-navigation below it — so at ~1280px the title slid up underneath them.
   Use the same offset formula as the anchor-link scroll-margin rules below so
   the heading pins clear of whichever sticky chrome is actually on the page. */
@media (width >=992px) {
    /* The grid uses align-items: flex-start, so the heading column shrink-wraps
       to the heading and sticky gets zero travel — it just scrolls away instead
       of pinning. Stretching the column to the row height gives sticky room to
       work within. */
    .dropdown-accordion-rows--layout-side-by-side .dropdown-accordion-rows__heading-col {
        align-self: stretch;
    }

    .dropdown-accordion-rows--layout-side-by-side .dropdown-accordion-rows__heading {
        top: calc(var(--header-height, 0px) + var(--announcement-bar-height, 0px) + var(--sticky-sub-nav-height, 0px) + var(--sticky-element-top-offset, 20px));
    }
}

/* ==========================================
   VERTICAL SCROLLING CARDS CUSTOMIZATIONS
   ========================================== */

.icon-text-card,
.icon-text-card .highlighted-statistic {
    border-color: var(--wp--preset--color--blue);
}

/* ==========================================
   TESTIMONIAL CUSTOMIZATIONS
   ========================================== */

.testimonial-intro {
    text-wrap: balance;
}

/* ==========================================
   TEAM MEMBER GRID CUSTOMIZATIONS
   ========================================== */


/* ==========================================
   TEMPLATE-SPECIFIC OVERRIDES
   ========================================== */

.dynamic-archive-grid-wrapper article .card-body {
    background: var(--color-bg);
    padding: var(--space-md);
}

/* 4-column grid: reduce gap to half for tighter spacing */
.dynamic-archive-grid-wrapper .row:has(.col-3) {
    row-gap: calc(var(--row-gap) / 2);
}

/* 4-column grid: use aspect-ratio instead of fixed height to prevent tall images on narrow cards */
.dynamic-archive-grid-wrapper .row:has(.col-3) .card-media {
    height: auto;
    aspect-ratio: 16 / 9;
}

.dynamic-archive-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
}

.dynamic-archive-filters .filter-buttons {
    justify-content: center;
}

.dynamic-archive-filters .filter-buttons button.filter-button {
    border: 2px solid var(--color-border);
    background: var(--color-white);
}

/* Active/Pressed state */
.dynamic-archive-filters .filter-button:hover,
.dynamic-archive-filters .filter-button:focus,
.dynamic-archive-filters .filter-button:hover:not([aria-pressed="true"], .active),
.dynamic-archive-filters .filter-buttons .filter-button[aria-pressed="true"],
.dynamic-archive-filters .filter-buttons .filter-button.active {
    background-color: var(--wp--preset--color--blue-navy);
    color: var(--color-white);
    border-color: var(--wp--preset--color--blue-navy);
}

/* Match the Gravity Forms select dropdown arrow (frontend-gravity-forms.css)
 * so filter dropdowns and form selects use the same chevron site-wide, instead
 * of 3mw-base's solid-triangle default (submodule — overridden here, not edited
 * in place). */
.archive-filters__select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M6 8.825L1.175 4 2.238 2.938 6 6.7l3.763-3.762L10.825 4z'/%3E%3C/svg%3E");
}

/* Disabled parent terms as non-clickable category headers in filter dropdowns
 * These serve as visual group labels (e.g., "Regenerative Solutions", "OA Pain Management")
 * Must look distinctly different from clickable options to avoid confusion */
.filter-dropdown-wrapper .archive-filters__select option:disabled {
    color: var(--wp--preset--color--gray);
    font-weight: var(--font-weight-semibold);
    font-size: 0.85em;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    background-color: var(--wp--preset--color--gray-light);
}

/* ==========================================
   PREFOOTER CTA BLOCK CUSTOMIZATIONS
   ========================================== */

/* ==========================================
   UTILITY CLASSES
   ========================================== */

h1.alt {
    font-size: var(--wp--preset--font-size--h-1-alt);
}

.balance {
    text-wrap: balance;
}

/* ==========================================================================
   HEADING SIZE STEP-DOWN
   Apply to any container to make all headings render one size smaller.
   Useful when semantic heading levels need different visual treatment.
   Example: h2 renders as h3 size/color, h3 as h4 size/color, etc.
   ========================================================================== */

.headings-step-down h1 {
    font-size: var(--font-size-h2);
}

.headings-step-down h2 {
    font-size: var(--font-size-h3);
    color: var(--color-primary);
}

.headings-step-down h3 {
    font-size: var(--font-size-h4);
}

.headings-step-down h4 {
    font-size: var(--font-size-h5);
}

.headings-step-down h5 {
    font-size: var(--font-size-h6);
}

.headings-step-down h6 {
    font-size: var(--font-size-small);
}

/* ==========================================
   TABBED CONTENT BLOCK
   ========================================== */

.tabbed-content .section-header .section-title,
.tabbed-content .section-header .section-subtitle {
    text-align: left;
    margin-left: 0;
}

/* Reduce the tab strip to a single rule beneath the tabs. Drops the
   container's top/left/right border, its rounded corners and its white fill
   so the tabs read as plain labels sitting on the page. The rule matches the
   active underline's 3px so the two form one continuous line. */
.tabbed-content .tab-navigation {
    border-width: 0 0 3px;
    border-color: var(--color-border-light);
    border-radius: 0;
    background: transparent;
    justify-content: flex-start;
    overflow: visible;
}

/* Tabs share the strip equally and sit flush on the rule with no fill or
   dividers. flex-basis: 0 makes the distribution independent of label
   length so the set spans the full width evenly.

   margin-bottom: -3px pulls each button down by its own border width so the
   active underline lands directly ON the container's grey rule and replaces
   it, rather than stacking above it as a second visible line. */
.tabbed-content .tab-button {
    flex: 1 1 0;
    min-width: 0;
    padding: 0 var(--space-md) var(--space-sm);
    margin-bottom: -3px;
    background: transparent;
    border: 0;
    border-bottom: 3px solid transparent;
    color: var(--color-text-primary);
    font-weight: var(--font-weight-medium);

    /* The plugin block sets `transition: all`, and the active tab changes
       font-weight — which is an animatable property, so the label visibly
       tweens through fractional weights (measured 500 → 500.5 → 587 → 700 over
       ~150ms) and appears to thicken a beat after the tab is selected.
       Weight should switch instantly; only colour and the underline animate. */
    transition:
        color var(--transition-base),
        background-color var(--transition-base),
        border-color var(--transition-base);
    text-align: center;
    white-space: normal;
}

/* Hover hints at the active treatment without shifting layout. */
.tabbed-content .tab-button:hover {
    background: transparent;
    color: var(--color-primary);
}

/* Active tab: primary-colored label over a primary underline that, via the
   negative margin above, sits in place of the container's grey rule. */
.tabbed-content .tab-button.active {
    background: transparent;
    color: var(--color-primary);
    font-weight: var(--font-weight-semibold);
    border-bottom: 3px solid var(--color-primary);
}

.tab-panel-content {
    border: 0;
    box-shadow: none;
    padding-inline: 0;
}

.tab-button.h5 {
    font-size: var(--font-size-body);
}

/* Position the image to the right of the text content on desktop.
   The grid keeps image (.col-4) first in the DOM; order swaps the
   visual placement so text sits left and the image sits right. */
.tabbed-content .tab-text {
    order: 1;
}

.tabbed-content .tab-image {
    order: 2;
}

/* On mobile the panel stacks; keep text above the image as before. */
@media (width <=768px) {
    .tabbed-content .tab-text {
        order: -1;
    }

    /* Client request: mobile should read as four continuously scrollable
       sections (HA Biology, Cross-Linking, TH Profile, Chondrocyte Response)
       instead of tab-switched content — the tab click UI hid 3 of the 4
       sections behind a tap with no scroll affordance between them.

       The tab strip is no longer needed for navigation on mobile, so it's
       hidden outright rather than restyled — this also retires the prior
       stacked-row tab treatment (bordered card, active row filled solid
       primary), since a hidden nav renders none of it. Every panel renders
       open, in document order, and each one already carries its own
       .tab-heading (e.g. "Biological Considerations of Hyaluronic Acid (HA)"),
       so losing the short button labels ("HA Biology") loses no information.

       JS (script.js) only calls switchTab() from a tab-button click, and with
       the nav hidden nothing invokes it — the plugin's click-driven
       hidden/active state on .tab-panel is left exactly as PHP rendered it
       (panel 0 active, 1-3 [hidden]), so it must be overridden here rather
       than relying on JS to re-run. */
    .tabbed-content .tab-navigation {
        display: none;
    }

    .tabbed-content .tab-panels {
        min-height: auto;
    }

    .tabbed-content .tab-panel {
        position: relative;
        opacity: 1;
        pointer-events: auto;
    }

    .tabbed-content .tab-panel[hidden] {
        display: block;
    }

    .tab-panel-content {
        border: 0;
        margin-top: 0;
        padding-inline: 0;
    }

    .tabbed-content .tab-panel+.tab-panel .tab-panel-content {
        margin-top: var(--space-xl);
        border-top: 1px solid var(--color-border);
        padding-top: var(--space-xl);
    }
}

/* ==========================================
   TIMELINE / OUR HISTORY BLOCK
   ========================================== */
.timeline-card {
    border-color: var(--color-border);
    background: var(--wp--preset--color--gray-light);
}

.timeline-description p strong {
    color: var(--color-primary);
}

/* ==========================================
   PAGINATION CUSTOMIZATIONS
   ========================================== */

/* Override parent theme pagination colors with gradient styling */

/* All page number links - apply gradient */

/* .pagination a.page-numbers {
    border: 2px solid transparent;
    background: var(--color-white);
    color: transparent;
    background-image: var(--gradient-primary);
    -webkit-background-clip: text;
    background-clip: text;
}

.pagination a.page-numbers,
.pagination span.page-numbers {
    border-radius: 6px;
} */

/* Gradient border using pseudo-element */

/* .pagination a.page-numbers::before {
    background: var(--gradient-primary);
    -webkit-mask:
        linear-gradient(#ffffff 0 0) content-box,
        linear-gradient(#ffffff 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
    border-radius: 6px;
} */

/* Hover state for ALL links - gradient background with white text */

/* .pagination a.page-numbers:hover,
.pagination a.page-numbers:focus {
    background: var(--gradient-primary);
    color: var(--color-white);
    border-color: transparent;
    -webkit-background-clip: padding-box;
    background-clip: padding-box;
} */

/* Current page - gradient background with white text */

/* .pagination a.page-numbers:hover,
.pagination a.page-numbers:focus,
.pagination .page-numbers.current {
    background: var(--gradient-primary);
    color: var(--color-white);
    border: 2px solid var(--color-white);
    border-color: var(--color-white);
}

.pagination .page-numbers.current {
    border-radius: 6px;
} */

/* ==========================================
   SINGLE POST TEMPLATE - CONSTRAINED WIDTH
   ========================================== */

/* Mobile padding for single post header section */
@media (width < 768px) {
    .single section.container.wp-block-group.is-layout-constrained {
        padding-left: var(--space-md);
        padding-right: var(--space-md);
    }
}

/* Allow blocks to break out to full/wide widths when explicitly set */
.single .wp-block-post-content .alignwide {
    max-width: var(--container-lg);
    margin-left: auto;
    margin-right: auto;
}

.single .wp-block-post-content .alignfull {
    max-width: 100%;
}

.single .post-meta {
    /* max-width: 1064px; */
    margin-left: auto;
    margin-right: auto;
    overflow: visible;
}

.single .entry-content h1,
.single .entry-content h2,
.single .entry-content h3,
.single .entry-content h4,
.single .entry-content h5 {
    text-wrap: unset;
}

/* White Papers - Allow post title to wrap normally instead of balancing */
.tmw-tl-single--white-papers .post-meta__title {
    text-wrap: wrap;
}

/* Single posts use headings-step-down at desktop to maintain visual hierarchy
   while allowing proper semantic heading structure (h1 title, h2-h6 in content) */
@media (width >=991px) {
    .single h1.post-meta__title {
        font-size: var(--font-size-h2);
    }

    .single .entry-content h2 {
        font-size: var(--font-size-h4);
    }

    .single .entry-content h3 {
        font-size: var(--font-size-h5);
    }

    .single .entry-content h4 {
        font-size: var(--font-size-h6);
    }

    .single .entry-content h5 {
        font-size: var(--font-size-h6);
    }
}

.single .post-meta__excerpt {
    font-weight: var(--font-weight-bold);
    line-height: 1.4em;
}

/* Featured image within constrained container - break out to regular container width */
.single .post-meta__featured-image {
    /* Calculate the negative margin needed to expand from container-content (1064px) to container (1280px) Difference is 216px total, so 108px on each side */
    margin-left: -108px;
    margin-right: -108px;
    width: calc(100% + 216px);
    max-width: var(--max-width-content-2xl);
    border-radius: var(--radius-card);
    border: 1px solid var(--color-border-light);
}

.single .post-meta__featured-image img {
    margin-top: 0;
}

@media (width <=480px) {
    .single .post-meta {
        margin-bottom: 0;
    }
}

/* ==========================================
   FLEXIBLE CONTENT - COLUMNS BLOCK SPACING
   ========================================== */

/* ==========================================
   FLEXIBLE CONTENT - BADGE WIDTH FIX
   Override plugin's width: 100% rule on direct children
   to allow badges to display at their natural inline-block width.
   ========================================== */

.flexible-content-wrapper>.badge,
.flexible-content-wrapper>p.badge {
    width: auto;
    max-width: fit-content;
}

/* ==========================================================================
   FLEXIBLE CONTENT - NESTED BLOCKS WITH BACKGROUNDS
   Card styling for the "Clinical outcome charts" section (#outcome-data) on
   the HCP Clinical Trials & Studies page: rounded corners/shadow on each
   white-background wp:group card, plus a column-count override so the
   3-column layout doesn't render illegibly narrow on tablet/small-desktop
   widths. Scoped to #outcome-data rather than a global
   .flexible-content-area-block rule because other pages use plain
   white-background groups inside flexible-content-area without wanting the
   card treatment.

   #outcome-data is the ACF Flexible Content Area block's Anchor field value,
   not a hardcoded template ID - if an editor renames that anchor in
   wp-admin, this styling silently stops applying. That's an accepted,
   documented trade-off, not something to code around.
   ========================================================================== */

#outcome-data .wp-block-group.has-white-background-color {
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-sm);
}

/* Each card is a single dense portrait infographic image (1152x1692) with
   its title/subtitle/data baked in. All three cards must share ONE row at
   desktop (client requirement) - an earlier 2-per-row tier at 992-1600px
   left the odd third card wrapping alone at full row width, which read as
   broken, and was removed in favor of core's default 3-up layout.

   The theme's fluid --wp--style--block-gap default (clamp(2rem, 3dvw +
   1.25rem, 4rem), ~80-130px at these widths) would eat a large share of a
   3-up row, so the tighter --space-lg gap is kept to give the cards the
   width back.

   Below 992px the cards stack 1-per-row: WP core only stacks columns below
   782px, but three-up (and even the 782-991px in-between) renders these
   image cards too small to read, so this file's existing 991/992px
   breakpoint governs instead. flex-wrap needs !important to beat core's
   own `.wp-block-columns { flex-wrap: nowrap !important; }` (applied from
   min-width:782px up). */
@media (width <=991px) {
    #outcome-data .wp-block-columns {
        flex-wrap: wrap !important;
    }

    #outcome-data .wp-block-column {
        flex-basis: 100%;
    }
}

@media (width >=992px) {
    #outcome-data .wp-block-columns {
        gap: var(--space-lg);
    }
}

/* ==========================================
   EVENTS - HIDE EMPTY CONTENT SECTIONS
   ========================================== */

/* Hide "Event Overview" heading when it's the only content in its wrapper
   When post content and dynamic-event-content are both empty, they don't render at all,
   leaving only the h2 heading. This hides the heading when it's the sole child. */
.single-events .flexible-content-wrapper.width-medium>h2.wp-block-heading:only-child {
    display: none;
}

/* Hide flexible content area when it contains only empty wrapper
   Prevents empty purple section from showing when event has no speakers, agenda, etc.
   The dynamic-event-content block doesn't render at all when empty, leaving just the wrapper
   Scoped to single events only to avoid affecting other pages */
.single-events .flexible-content-area-block.has-light-purple-background-color:has(.flexible-content-wrapper:empty) {
    display: none;
}

/* =======================================================
   MULTI-COLUMN BOXED CONTENT BLOCK CUSTOMIZATIONS
   ======================================================= */

.multi-column-boxed-content .column-title {
    font-size: var(--font-size-h5);
    font-weight: var(--font-weight-normal);
}

/* ==========================================
   TWO-COLUMN ALTERNATING BLOCK CUSTOMIZATIONS
   ========================================== */


/* ==========================================
   TIMELINE BLOCKS CUSTOMIZATION
   ========================================== */

.timeline-h-year-badge {
    border-radius: 4px;
}

.timeline-h-dot {
    background: var(--color-primary);
}

.timeline-h-line {
    background: var(--wp--preset--color--blue-light);
}

/* Larger scrollbar on hover without layout shift */
.timeline-h-progress-container {
    height: 10px;
    margin-bottom: 6px;

    /* Reserve space for growth */
}

.timeline-h-progress-container:hover,
.timeline-h-progress-container.is-dragging {
    height: 16px;
    margin-bottom: 0;

    /* Consume reserved space */
}


/* ==========================================
   SOCIAL SHARE BUTTONS
   ========================================== */

.social-share-buttons {
    padding-top: var(--space-xl);
    border-top: 1px solid var(--color-border);
    gap: var(--space-md);
    align-items: center;
}

.social-share-buttons p {
    margin: 0;
    font-size: var(--font-size-small);
}

/* The share list renders with no space between icons. Two compounding causes:
   the block's own spacing comes from `--wp--style--block-gap`, which resolves to
   `0` here (the template sets no blockGap), and `.wp-social-link { margin: 0 }`
   below removes the margin-based fallback the block ships for older markup.
   The previous `--row-gap` custom property was never read by anything - the
   social links block does not consume it - so it had no effect.
   Setting `gap` directly on the flex container fixes both axes, and follows the
   same explicit-selector approach already needed for the footer social links
   (see components/footer.css). */
.social-share-links {
    gap: var(--space-sm);
}

.social-share-links .wp-social-link {
    margin: 0;
}

.social-share-links .wp-social-link a {
    transition: transform var(--transition-fast), opacity var(--transition-fast);
}

.social-share-links .wp-social-link a:hover {
    transform: scale(1.1);
    opacity: 0.9;
}

/* Responsive adjustments */
@media (width <=640px) {
    .social-share-buttons {
        flex-wrap: wrap;
        justify-content: flex-start;
    }

    .social-share-buttons p {
        width: 100%;
        margin-bottom: var(--space-xs);
    }
}

/* ==========================================
   MOBILE UPDATES
   Responsive fixes and mobile-specific overrides
   ========================================== */

@media (width <=768px) {
    :root {
        --row-gap: var(--space-md);
    }
}

/* ==========================================
   WOOCOMMERCE CHECKOUT - PLACE ORDER BUTTON
   Match primary button style for consistency
   ========================================== */

/* WooCommerce Block Checkout - Place Order Button */
.wc-block-checkout__actions .wc-block-components-checkout-place-order-button,
.wc-block-checkout__actions button.wc-block-components-button,
.wp-block-woocommerce-checkout .wc-block-components-checkout-place-order-button {
    background: var(--btn-primary-bg);
    color: var(--btn-primary-text-color) !important;
    border-color: var(--btn-primary-border-color);
    border-width: var(--btn-primary-border-width);
    border-style: var(--btn-primary-border-style);
    border-radius: var(--radius-button);
    font-weight: var(--font-weight-normal);
    padding: 10px 24px;
    transition: all var(--transition-base);
}

/* Hover state */
.wc-block-checkout__actions .wc-block-components-checkout-place-order-button:hover,
.wc-block-checkout__actions .wc-block-components-checkout-place-order-button:focus,
.wc-block-checkout__actions button.wc-block-components-button:hover,
.wc-block-checkout__actions button.wc-block-components-button:focus,
.wp-block-woocommerce-checkout .wc-block-components-checkout-place-order-button:hover,
.wp-block-woocommerce-checkout .wc-block-components-checkout-place-order-button:focus {
    background: var(--btn-primary-hover-bg);
    color: var(--btn-primary-hover-text-color) !important;
    border-color: var(--btn-primary-hover-border-color);
}

/* Classic WooCommerce Checkout (fallback) */
.woocommerce-checkout #place_order,
.woocommerce #payment #place_order {
    background: var(--btn-primary-bg);
    color: var(--btn-primary-text-color) !important;
    border-color: var(--btn-primary-border-color);
    border-width: var(--btn-primary-border-width);
    border-style: var(--btn-primary-border-style);
    border-radius: var(--radius-button);
    font-weight: var(--font-weight-normal);
    padding: 10px 24px;
    transition: all var(--transition-base);
}

.woocommerce-checkout #place_order:hover,
.woocommerce-checkout #place_order:focus,
.woocommerce #payment #place_order:hover,
.woocommerce #payment #place_order:focus {
    background: var(--btn-primary-hover-bg);
    color: var(--btn-primary-hover-text-color) !important;
    border-color: var(--btn-primary-hover-border-color);
}

/* ==========================================
   COOKIE NOTICE
   ========================================== */

.cky-consent-bar {
    border-color: var(--wp--preset--color--blue-dark) !important;
}

.cky-consent-container,
.cky-consent-container .cky-consent-bar,
.cky-preference-wrapper,
.cky-accordion-body,
.cky-empty-cookies-text {
    background: var(--wp--preset--color--blue-dark) !important;
}

.cky-consent-container *,
.cky-consent-container .cky-consent-bar *,
.cky-consent-container .cky-consent-bar .cky-title {
    color: var(--color-white) !important;
}

/* CookieYes' own stylesheet sets its own font stack inline on every element;
   restate the site's body/heading fonts here (scoped to the widget, not a
   bare `*`) so the popup matches the rest of the site instead of CookieYes'
   default. */
.cky-consent-container * {
    font-family: var(--font-family-body) !important;
}

.cky-preference-title {
    font-family: var(--font-family-heading) !important;
}

.cky-footer-shadow {
    display: none !important;
}

/* Audit table (expanded accordion cookie list) keeps a light background —
   it sits inside the dark preference modal, and the CookieYes-managed
   dashboard CSS (see cky-style, generated per subsite) already renders it as
   white with dark text. Excluding it from the dark-background rule above and
   restating white + dark text here directly makes this correct even when a
   subsite falls back to the local, unbranded CookieYes renderer instead of
   the connected cloud script — see CookieYes multisite connection notes in
   this theme's CLAUDE.md. */
.cky-audit-table {
    background: #ffffff !important;
}

.cky-audit-table,
.cky-audit-table * {
    color: var(--wp--preset--color--black) !important;
}

/* Accordion "Always Active" label and the cookie-details toggle read as
   white/light text against the dark accordion header — restated here for
   the same cross-subsite-fallback reason as .cky-audit-table above. */
.cky-accordion-header .cky-always-active {
    color: #ceeace !important;
}

.cky-show-desc-btn {
    color: var(--color-white) !important;
}

/* Accordion item divider — barely-visible white so it reads against the
   dark preference modal background instead of CookieYes' default dark
   border, which was invisible on the same dark background. */
.cky-accordion {
    border-color: rgb(255 255 255 / 16%) !important;
}

/* CookieYes ships this class misspelled ("prefrence") in its own markup —
   matched here as-is, not a typo. */
.cky-prefrence-btn-wrapper .cky-btn {
    border-radius: 12px !important;
}

.cky-prefrence-btn-wrapper .cky-btn:hover,
.cky-prefrence-btn-wrapper .cky-btn:active,
.cky-prefrence-btn-wrapper .cky-btn:focus {
    background: var(--color-white) !important;
    color: var(--wp--preset--color--blue-dark) !important;
}

/* CookieYes buttons - Light Secondary style (outline button for dark backgrounds) */
.cky-consent-container .cky-btn {
    background: var(--btn-light_secondary-bg) !important;
    border: var(--btn-light_secondary-border-width) var(--btn-light_secondary-border-style) var(--btn-light_secondary-border-color) !important;
    border-radius: var(--radius-button) !important;
    color: var(--btn-light_secondary-text-color) !important;
    font-family: var(--font-family-body) !important;
    font-size: var(--font-size-button) !important;
    font-weight: var(--font-weight-medium) !important;
    padding: 10px 24px !important;
    transition: background var(--transition-base), color var(--transition-base), border-color var(--transition-base) !important;
}

.cky-consent-container .cky-btn:hover,
.cky-consent-container .cky-btn:focus {
    background: var(--btn-light_secondary-hover-bg) !important;
    border-color: var(--btn-light_secondary-hover-border-color) !important;
    color: var(--btn-light_secondary-hover-text-color) !important;
}

/* Customize button - extra right padding to visually center text with arrow */
.cky-consent-container .cky-btn-customize {
    padding-right: 32px !important;

    /* Extra right padding to balance the arrow */
}

/* CookieYes revisit button (floating icon) - Add white border for visibility against dark footer */
.cky-btn-revisit-wrapper {
    border: 2px solid var(--color-white) !important;
    box-shadow: 0 4px 12px rgb(0 0 0 / 20%) !important;
    border-radius: 100%;
}

/* Hide CookieYes button when modals are open to prevent overlap */
body.lightbox-open .cky-btn-revisit-wrapper,
body.team-member-modal-open .cky-btn-revisit-wrapper {
    display: none !important;
}

/* CookieYes preferences modal - Mobile viewport fix
   Ensures modal header with close button is visible on mobile browsers
   Accounts for iOS safe area insets (notch/home indicator) */
@media (width <=767px) {
    .cky-modal {
        padding-top: env(safe-area-inset-top, 0) !important;
    }

    .cky-preference-center {
        max-height: calc(100vh - env(safe-area-inset-top, 0) - env(safe-area-inset-bottom, 0)) !important;
        max-height: calc(100dvh - env(safe-area-inset-top, 0) - env(safe-area-inset-bottom, 0)) !important;
        height: 100% !important;
        top: 0 !important;
        margin: 0 !important;
        border-radius: 0 !important;
    }

    /* Ensure the modal content is scrollable and header stays fixed */
    .cky-preference-header {
        position: sticky !important;
        top: 0 !important;
        z-index: 10 !important;
        background: var(--wp--preset--color--blue-dark) !important;
        padding-top: max(var(--space-md), env(safe-area-inset-top, 16px)) !important;
    }

    .cky-preference-body-wrapper {
        overflow-y: auto !important;
        -webkit-overflow-scrolling: touch !important;
        flex: 1 !important;
        max-height: none !important;
    }

    /* Ensure footer buttons stay visible */
    .cky-preference-footer {
        position: sticky !important;
        bottom: 0 !important;
        z-index: 10 !important;
        background: var(--wp--preset--color--blue-dark) !important;
        padding-bottom: max(var(--space-md), env(safe-area-inset-bottom, 16px)) !important;
    }
}

/* ==========================================
   ARCHIVES
   ========================================== */

.dynamic-archive-grid-wrapper .card-link-wrapper {
    border: 1px solid var(--color-border-light);
}

.dynamic-archive-filters.display-style-dropdowns input,
.dynamic-archive-filters.display-style-dropdowns select {
    border: 1px solid rgb(91 103 112 / 40%);
}

/* ==========================================
   ARCHIVE FILTER SEARCH ALIGNMENT
   ========================================== */

/* Match search input height and corner radius to the filter dropdowns.
   The 3mw-base plugin styles the search as a pill (--radius-full) to match its
   own pill-shaped filter buttons, but this site uses dropdown selects
   (--radius-button), so the pill read as an odd one out in the row. */
.filter-dropdown-wrapper .inline-search-input,
.dynamic-archive-filters .inline-search-input {
    min-height: 46px;
    line-height: var(--line-height-normal);
    box-sizing: border-box;
    border-radius: var(--radius-button);
}

/* Tighten the search field's inner padding to match the filter dropdowns.
   The plugin uses `--space-lg` on the sides plus `--space-2xl` on the right to
   clear its floating clear-button — but this site renders the search with
   `hide_clear_button`, so that ~83px right inset reserved room for a button
   that never appears and left the placeholder floating well inside the field.
   Matching the selects' `--space-md` inset lines the placeholder up with the
   dropdown labels. */
.dynamic-archive-filters .inline-search-input {
    padding-inline: var(--space-md);
}

.dynamic-archive-filters.display-style-dropdowns .filter-dropdowns {
    row-gap: 0;
    margin-top: 0;
}

/* Hide a taxonomy dropdown that offers no real choice.
   The parent theme's `tmw_core_render_dropdown_filters()` only skips a taxonomy
   when `get_terms()` returns nothing, so a taxonomy with a single term still
   renders a full dropdown whose only options are "All <Taxonomy>" and that one
   term — selecting either shows the same posts. The HCP site currently has one
   Resource Category ("Download Centre") and hits exactly this case.
   Matching on option count keeps this self-correcting per site and per
   environment: `option:nth-child(2):last-child` is true only when the select
   holds the "all" option plus exactly one term, so the dropdown reappears on
   its own as soon as a second term has posts (the Patients site, with two
   categories, is unaffected). Terms are filtered by `hide_empty => true`, so
   this tracks terms that actually have content, not terms that merely exist.
   The inline search and reset link are separate children of `.filter-dropdowns`
   and are untouched, so the filter row stays useful. */
.dynamic-archive-filters .filter-dropdown-wrapper:has(.archive-filters__select option:nth-child(2):last-child) {
    display: none;
}

.dynamic-archive-filters.display-style-dropdowns .filter-dropdowns .filter-reset-button,
.dynamic-archive-filters.display-style-dropdowns .filter-dropdowns .filter-reset-button:hover,
.dynamic-archive-filters.display-style-dropdowns .filter-dropdowns .filter-reset-button:focus,
.dynamic-archive-filters.display-style-dropdowns .filter-dropdowns .filter-reset-button:focus-visible,
.dynamic-archive-filters.display-style-dropdowns .filter-dropdowns .filter-reset-button:active {
    border: none;
    outline: none;
    box-shadow: none;
    padding: var(--space-2xs);
}

/* Filter block/section padding is NOT set here — it lives in
   `3mw-resources/assets/css/src/frontend.css`, next to the
   `archive-resources.html` markup whose `#resource-filters` anchor those rules
   target, so selector and markup can't drift apart. That file also zeroes this
   block's horizontal padding so its edges meet the cards grid.
   The "Reset Filters" link keeps 3mw-base's stock behaviour: always present,
   dimmed and `disabled` until a filter or search is active. Hiding it while
   inactive was tried and reverted at the client's request — don't re-add it. */

/* Right-align the search within the filter row, with the reset link on its own
   line beneath it.
   The plugin explicitly zeroes the search's auto margin in dropdown mode
   (`.dynamic-archive-filters.display-style-dropdowns .inline-search-wrapper`),
   and its stylesheet loads after this file, so we need the extra
   `.filter-dropdowns` class to win on specificity rather than order.
   Scoped to >768px: the plugin stacks the search full-width with `order: -1`
   on mobile, which should keep winning. */

/* `.dynamic-archive-filters` is itself a flex container and the plugin leaves
   `.archive-filters` at `flex: 0 1 auto`, so the filter bar only shrink-wraps
   its content instead of spanning the block's full inner width. Nothing inside
   it could reach the right edge while the bar itself stopped short, so let it
   grow to fill the block. Its edges then line up with the cards grid below.
   Applies at every width: on mobile the shrink-wrap left the search and Type
   dropdown ~43px short of the cards' right edge. The plugin's mobile rule on
   this same element (`flex-direction: column; align-items: stretch`) governs
   the bar's internal stacking, not its own width, so the two don't conflict. */
.dynamic-archive-filters.display-style-dropdowns .archive-filters {
    flex: 1 1 auto;
}

@media (width >=769px) {
    /* The plugin sets the dropdown wrappers to `flex: 1 1 0%`, so they absorb
       every spare pixel in the row and `margin-left: auto` has no free space to
       distribute. Stop them growing so the auto margin can actually push the
       search to the right. */
    .dynamic-archive-filters.display-style-dropdowns .filter-dropdowns .filter-dropdown-wrapper {
        flex-grow: 0;
    }

    /* Move the reset link onto its own line below the search, right-aligned.
       The row already wraps, so a full-width basis forces a new line. Without
       this the reset wrapper sits inline at the far right and reserves ~110px
       even when inactive (the plugin's `.is-hidden` only dims the button with
       opacity/pointer-events, it doesn't remove it from layout), which stopped
       the search from reaching the right edge. */
    .dynamic-archive-filters.display-style-dropdowns .filter-dropdowns .filter-reset-wrapper {
        flex: 0 0 100%;
        justify-content: flex-end;
    }

    .dynamic-archive-filters.display-style-dropdowns .filter-dropdowns .inline-search-wrapper {
        margin-left: auto;
    }
}

/* Fix clear button vertical alignment - base plugin missing top: 50% */
.inline-search-clear {
    top: 50%;
}

/* Mobile: transform doesn't apply, so use inset centering instead */
@media (width <=991px) {
    .inline-search-clear {
        top: 0;
        bottom: 0;
        margin-block: auto;
        height: fit-content;
        transform: none;
    }
}

/* Increase dropdown min-width to prevent text truncation for longer labels like "All Career Locations".
   Raised again to 320px (from 260px) for the Resources archive's French "Tous les Resource
   Categories" placeholder: measured via canvas against the select's actual computed font, the
   option text plus the select's 28px left / 64px right padding needs 279px. The wrapper is a flex
   item with `flex: 0 1 0%` (no grow), so it sits at its `min-width` floor rather than expanding
   toward 3mw-base's own 300px `max-width` ceiling — raising only `max-width` would have changed
   nothing, since the box never grows past its floor on its own. `min-width: 320px` clears the
   measured 279px with headroom for future terms/locales; `max-width` is raised to match so the
   new floor isn't immediately clamped back down by the plugin's tighter 300px ceiling. */
.filter-dropdown-wrapper {
    min-width: 320px;
    max-width: 320px;
}

/* ==========================================
   Search Results
   ========================================== */

.card-media--default-image img {
    object-fit: cover;
}

/* Mobile: constrain Page card images to match other post types */
@media (width <=768px) {
    .card--page .card-media {
        max-height: 160px;
    }
}

/* ==========================================
   ANCHOR LINK SCROLL OFFSET - Sticky Sub-Navigation
   Override parent theme scroll-margin-top to include
   sticky sub-navigation height when present.
   ========================================== */

/*
 * When the sub-navigation block becomes sticky, JavaScript sets
 * --sticky-sub-nav-height on :root. This ensures anchor links
 * scroll to the correct position below the sticky sub-nav.
 */
section[id],
div[id]:not(.wp-site-blocks, .is-layout-flow, .entry-content) {
    scroll-margin-top: calc(var(--header-height, 0px) + var(--announcement-bar-height, 0px) + var(--sticky-sub-nav-height, 0px) + var(--sticky-element-top-offset, 20px));
}

/* Admin bar adjustment - desktop (32px) */
@media screen and (width >=783px) {
    body.admin-bar section[id],
    body.admin-bar div[id]:not(.wp-site-blocks, .is-layout-flow, .entry-content) {
        scroll-margin-top: calc(var(--header-height, 0px) + var(--announcement-bar-height, 0px) + var(--sticky-sub-nav-height, 0px) + var(--sticky-element-top-offset, 20px) + 32px);
    }
}

/* Admin bar adjustment - mobile (46px) */
@media screen and (width <=782px) {
    body.admin-bar section[id],
    body.admin-bar div[id]:not(.wp-site-blocks, .is-layout-flow, .entry-content) {
        scroll-margin-top: calc(var(--header-height, 0px) + var(--announcement-bar-height, 0px) + var(--sticky-sub-nav-height, 0px) + var(--sticky-element-top-offset, 20px) + 46px);
    }
}

/* ==========================================================================
   HORIZONTAL ACCORDION SLIDES CUSTOMIZATIONS
   ========================================================================== */

/* Reduce font size of rotated tab titles and prevent wrapping.
   The plugin sets width:100px which Chrome uses as the wrap constraint
   before rotation; nowrap + smaller text resolves it. */
.horizontal-accordion-slides .panel-title-vertical {
    font-size: var(--font-size-h6);

    /* .h5 heading styles set text-wrap (from FSE), which resets white-space's
       wrap mode; force nowrap so long labels (e.g. "First-Step Treatments")
       stay on a single rotated line instead of breaking. */
    white-space: nowrap;
    text-wrap: nowrap !important;
}

/* White panels on a bordered white card. The plugin defaults collapsed panels to
   light-gray (--color-light-gray #eeeff0) and the container border to the
   near-invisible blue --color-border, so both vanish against the gray section. */
.horizontal-accordion-slides .accordion-panel {
    border: 1px solid var(--color-border);

    /* --Light-Blue #E8F5F9 */
    background: var(--color-white);
}

.horizontal-accordion-container {
    border: 1px solid var(--color-border);
}

.horizontal-accordion-slides .horizontal-accordion-container {
    border: none;
}

/* Left-align the band's section header (title + subtitle) and constrain it to
   content-xl, overriding the block's default centered (.text-center) header. */
.horizontal-accordion-slides .section-header {
    max-width: var(--max-width-content-xl);
    margin-inline: 0;
    text-align: left;
}

.horizontal-accordion-slides .section-subtitle {
    max-width: var(--max-width-content-xl);
    margin-inline: 0;
    font-size: var(--font-size-body);

    /* 18px, scoped to this block only */
    text-wrap: wrap;

    /* override the parent's text-wrap: balance */
}

/* Collapsing: hide content instantly, no lingering fade-out. */
.horizontal-accordion-slides .panel-content {
    transition: none;
    transform: none;
}

/* Expanding: hold content hidden until the panel's own 0.7s width transition
   finishes, then reveal it instantly (no fade/slide) at its final width. The
   plugin's own 0.4s delay revealed content ~300ms before the width settled,
   which visibly reflowed the text as the column kept resizing. */
.horizontal-accordion-slides .accordion-panel.is-active .panel-content {
    transition: opacity 0.7s step-end, visibility 0.7s step-end, transform 0.7s step-end;
    transform: none;
}

.accordion-panel .panel-content {
    display: block;
}

.accordion-panel.is-active::before {
    border-right: 2px solid var(--color-border);
}

.accordion-panel.is-active .panel-content .panel-title {
    font-size: var(--font-size-h4);
}

@media (width <=768px) {
    .accordion-panel:not(.is-active) .panel-icon-collapsed {
        width: 30px;
        padding: var(--space-2xs);
    }
}

/* Sync icon/title repositioning with the panel's own width transition instead of
   the plugin's undelayed 0.6s move, which finishes well before the 0.7s panel
   expansion and reads as the icon "flying out" ahead of everything else. */
.horizontal-accordion-slides .panel-icon-collapsed,
.horizontal-accordion-slides .panel-title-vertical {
    transition: opacity 0.3s ease-in-out, left 0.7s cubic-bezier(0.87, 0, 0.13, 1);
}

/* Reduce size of ® and ™ symbols when inside headings */
h1 .reg-mark,
h2 .reg-mark,
h3 .reg-mark,
h4 .reg-mark,
h5 .reg-mark,
h6 .reg-mark,
h1 .tm-mark,
h2 .tm-mark,
h3 .tm-mark,
h4 .tm-mark,
h5 .tm-mark,
h6 .tm-mark {
    font-size: 0.6em;
    vertical-align: super;
}

/* ==========================================================================
   TWO-COLUMN CONTENT BLOCK CUSTOMIZATIONS
   ========================================================================== */

/* Left-align the section heading & subtitle (block markup uses .text-center).
   The subtitle is centered globally via auto side margins — reset to anchor left.
   Note: the title must not carry its own `text-align` in the block's style.css —
   an element-level rule there beats this container rule and re-centers the title
   above the left-aligned subtitle. */
.two-column-content .section-header {
    text-align: left;
}

.two-column-content .section-header .section-subtitle {
    margin-left: 0;
    margin-right: 0;
}

/* ==========================================================================
   IMAGELINKS MAP ZOOM (both sites)
   ==========================================================================
   Buttons-only zoom + drag-to-pan for the ImageLinks "Cingal World Map".
   The wrapper clips the scaled map; the transform is applied to .imgl-map
   itself by assets/js/src/imagelinks-zoom.js so markers scale in lockstep.

   Deliberately NOT scoped to .cingal-hcp / .cingal-main. This section was
   originally HCP-only on the assumption that only that subsite embedded the
   map; the map is in fact on both sites, so every rule here silently did
   nothing on Patients (body gets .cingal-main — see tmw_child_hcp_body_class()
   in functions.php). The .imgl-* classes are generated by the ImageLinks
   plugin and only exist where a map has actually rendered, so unscoped
   selectors are already self-limiting — a per-site prefix buys nothing and
   is what broke Patients in the first place. Keep new map rules unscoped
   unless a difference between the two sites is genuinely intended. */

/* Loading skeleton
   --------------------------------------------------------------------------
   ImageLinks renders the map via async AJAX (loader.min.js fetches config.json,
   then builds the DOM). Until that finishes the container is literally
   `width: 0; height: 0` — measured on production — so the page showed nothing
   at all where the map belongs, with no indication anything was coming.
   Measured cost of that gap: ~850ms on a warm cache, but ~6.6-7.0s on a cold
   cache with mobile throttling (1.6Mbps / 4x CPU), and the map claims ~210px of
   document height when it finally lands.

   Two problems, both handled here:
   1. No feedback during the wait  -> animated shimmer below.
   2. No reserved space            -> aspect-ratio, which also removes the
                                      layout shift as a side effect.

   `aspect-ratio` rather than a min-height per breakpoint: the map fills its
   parent's width and holds a constant 1.8224 ratio at every viewport measured
   (390 / 768 / 1280 / 1440px all returned 1.8224), so one declaration reserves
   the correct box everywhere with no media queries to drift out of sync.

   Keyed off `:not(.imgl-ready)` — the same class the plugin adds when it
   finishes, and the same signal imagelinks-zoom.js waits on — so the skeleton
   removes itself with no JS, no cleanup and no possibility of being left
   behind. Listing `.imgl-failed` in the same `:not()` is what stops it
   shimmering forever; see the failure state below. */
.imgl-map:not(.imgl-ready) {
    position: relative;
    width: 100%;
    aspect-ratio: 1.8224;
    overflow: hidden;
    background-color: var(--color-bg-secondary);
    border-radius: var(--radius-card);
}

.imgl-map:not(.imgl-ready, .imgl-failed)::after {
    position: absolute;
    inset: 0;
    background-image: linear-gradient(90deg,
            transparent 0%,
            rgb(255 255 255 / 60%) 50%,
            transparent 100%);
    animation: imgl-skeleton-shimmer 1.4s ease-in-out infinite;
    content: "";
}

@keyframes imgl-skeleton-shimmer {
    from {
        transform: translateX(-100%);
    }

    to {
        transform: translateX(100%);
    }
}

/* Failure state: imagelinks-zoom.js adds .imgl-failed once its ~10s poll has
   given up, meaning the map is never going to arrive. Swap the shimmer (killed
   by the :not(.imgl-failed) guard above) for a static message, so the component
   fails honestly instead of implying it is still working. Collapses the
   reserved box to something message-sized rather than holding a 1.82 ratio of
   empty grey. */
.imgl-map.imgl-failed {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: auto;
    min-height: var(--space-3xl);
    padding: var(--space-md);
}

.imgl-map.imgl-failed::after {
    font-size: var(--font-size-small);
    color: var(--color-text-primary);
    text-align: center;
    content: "Map unavailable — please refresh to try again.";
}

/* Respect a reduced-motion preference: keep the reserved space and the grey
   placeholder (both are layout/affordance, not motion) but drop the sweeping
   animation, which is the part that causes problems for motion-sensitive
   users. */
@media (prefers-reduced-motion: reduce) {
    .imgl-map:not(.imgl-ready, .imgl-failed)::after {
        animation: none;
    }
}

/* Marker pulse.

   NOTE: the actual flicker fix does NOT live here. The plugin ships a malformed
   @keyframes imgl-shadow-pulse whose opening selector is `0 {` (a bare zero,
   invalid — it must be `0%`/`from`), so browsers drop that block and the
   animation keeps only its 100% stop, snapping back each loop. It cannot be
   corrected from this file: the plugin's loader appends imagelinks.min.css to
   <head> at DOM-ready, i.e. AFTER this stylesheet, and for identically-named
   @keyframes the last definition wins outright (specificity does not apply).
   The corrected keyframes therefore live in the map's own custom.css, which the
   same loader appends last — see the `customCSS` block in the ImageLinks item
   (exported in _TEMP/imagelinks_config_worldmap_fixed.json).

   What remains here is the stagger. The plugin runs the animation identically
   and un-staggered on every marker, so with ~50 markers they all pulse in
   lockstep every 2s, reading as one global strobe rather than individual pins.
   ease-in-out (instead of ease-out) softens each cycle's start and end.
   :nth-child works here because ImageLinks renders markers as plain <li>
   siblings under .imgl-markers. The modulo cycle below spreads markers
   across a 2s window so at any moment only a few are pulsing at once. */
.imgl-markers .imgl-marker-wrap.imgl-shadow-pulse .imgl-pin-data {
    animation-timing-function: ease-in-out;
}

.imgl-markers .imgl-marker-wrap:nth-child(5n + 1).imgl-shadow-pulse .imgl-pin-data {
    animation-delay: 0s;
}

.imgl-markers .imgl-marker-wrap:nth-child(5n + 2).imgl-shadow-pulse .imgl-pin-data {
    animation-delay: 0.4s;
}

.imgl-markers .imgl-marker-wrap:nth-child(5n + 3).imgl-shadow-pulse .imgl-pin-data {
    animation-delay: 0.8s;
}

.imgl-markers .imgl-marker-wrap:nth-child(5n + 4).imgl-shadow-pulse .imgl-pin-data {
    animation-delay: 1.2s;
}

.imgl-markers .imgl-marker-wrap:nth-child(5n + 5).imgl-shadow-pulse .imgl-pin-data {
    animation-delay: 1.6s;
}

/* The prefers-reduced-motion opt-out for these pins lives in the map's
   custom.css alongside the keyframe fix, so the whole pulse behaviour is
   described in one place rather than split across two files. The delay/timing
   rules above stay here because they are ordinary declarations whose selectors
   out-specify the plugin's, so load order does not affect them. */

.imgl-zoom-wrap {
    position: relative;
    overflow: hidden;
}

/* Touch: details render in a card BELOW the map, not in a floating tooltip.

   The floating tooltip cannot work at this size. `.imgl-zoom-wrap` must keep
   `overflow: hidden` to clip the scaled/panned map, and at 390px the map is only
   311x170.6px — while the 55 tooltips on this map are 79-251px tall (141px
   median). Six exceed the clip box outright, so part of them is always cut off;
   the reported bug was Canada losing 64% of its height off the top and Mexico
   46%. Full reasoning, and the four in-place fixes that were measured and
   rejected, is in initDetailPanel() in imagelinks-zoom.js.

   `.has-detail-panel` is set by that function, and only on coarse pointers, so
   desktop keeps its hover tooltips untouched. */
.imgl-zoom-wrap.has-detail-panel .imgl-tooltips {
    /* `visibility` rather than `display: none`: the plugin measures these nodes
       when positioning, and removing them from layout makes those measurements
       zero, which throws errors in its own code. Hidden-but-laid-out keeps the
       plugin working while the card does the presenting. Also cleared from the
       a11y tree, so the card is not read out twice. */
    visibility: hidden;
}

.imgl-detail-panel {
    position: relative;
    margin-block-start: var(--space-md);
    padding: var(--space-md);
    padding-inline-end: var(--space-xl);
    border-radius: var(--radius-card);
    background-color: var(--color-bg-primary);
    box-shadow: var(--shadow-md);
}

.imgl-detail-panel[hidden] {
    display: none;
}

.imgl-detail-panel__close {
    position: absolute;
    inset-block-start: var(--space-2xs);
    inset-inline-end: var(--space-2xs);

    /* 44px WCAG 2.5.5 target, same floor the marker halo uses. */
    display: flex;
    align-items: center;
    justify-content: center;
    inline-size: 44px;
    block-size: 44px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--color-text-secondary);
    font-size: var(--font-size-lead);
    line-height: 1;
    cursor: pointer;
}

.imgl-detail-panel__close:hover {
    color: var(--color-text-primary);
}

/* Neutralise the tooltip's own sizing on the clone.

   The plugin writes a FIXED inline `width` on `.imgl-tooltip` (and the theme
   sets `width: max-content` on it for the floating case), sized for a tooltip
   floating over the map — measured at 99px. Cloned into a 267px-wide card that
   width comes along, so every link inside wraps as if it had 99px to work with:
   `office@haemo-pharma.at` broke onto two lines needing 165px of an available
   267px, and the "Contact" button wrapped to nearly four lines. Overriding to
   `auto`/`none` lets the content use the card's real width.

   `!important` on the width beats the plugin's inline declaration, which no
   selector can otherwise outrank. */
.imgl-detail-panel .imgl-tooltip,
.imgl-detail-panel .imgl-tt {
    inline-size: auto !important;
    max-inline-size: none !important;
}

/* The card's typography and contact icons are NOT restated here.

   The card renders a clone of the tooltip's own markup, so it wants exactly the
   tooltip's appearance — title styling, link colours, and the phone/email/globe
   mask icons. Those rules live further down this file, scoped to `.imgl-map`,
   and `.imgl-detail-panel` has been added as a second selector to each of them
   rather than copied here. Duplicating ~60 lines of mask data URIs would
   guarantee the two copies drift; sharing the selector means the card and the
   desktop tooltip cannot diverge.

   The one thing the card must override is the width, above: everything else it
   inherits by matching the same rules. */

/* Buttons keep their label on one line and size to it, rather than inheriting
   the aggressive wrapping the long email/URL links need. */
.imgl-detail-panel .btn {
    inline-size: auto;
    white-space: nowrap;
}

/* Selected marker: this replaces the tooltip arrow's job of showing which dot
   the details belong to, since the card sits away from the map.

   Two signals, because either alone is weak on this map: the pin turns brand
   blue (against the default green, and distinct from the pale blue territory
   fill behind it), and it gains a ring. Colour alone would fail WCAG 1.4.1
   "use of colour", and a ring alone was easy to miss among 55 dots.

   The colour goes on `.imgl-pin-data` — that is the element that actually
   paints the dot (green rgb(96,162,60) with a 3px white border). `.imgl-marker`
   is fully transparent and exists as the geometry/hit box, which is also why
   the ring is drawn here rather than there: a ring on the transparent parent
   floated away from the visible pin.

   The ring is the default marker green, NOT brand blue: with the dot itself
   now blue, a blue ring on a blue dot collapsed back to one signal (the
   ring nearly disappeared against its own pin). Green keeps the ring visible
   against the blue dot and ties it back to every other (unselected) dot on
   the map, which are also that green — there is no theme.json token for it,
   as this green is the ImageLinks plugin's own default pin colour, defined
   in its config JSON rather than the design system.

   `.is-selected` is set by initDetailPanel(), which only runs on touch/narrow
   screens, so desktop is unaffected without needing a media query. */
.imgl-markers .imgl-marker-wrap.is-selected .imgl-pin-data {
    background-color: var(--color-primary);

    /* --imgl-ring-width is written inline by syncHitSize() in
       imagelinks-zoom.js, pre-divided by the dot's measured scale. The pin is
       scaled ~3.8x at mobile size, and an outline scales with its element, so a
       literal `3px` here paints under 0.8px on screen — applied but invisible,
       which is exactly what it did before this was counter-scaled. */
    outline: var(--imgl-ring-width) solid rgb(96 162 60);
    outline-offset: var(--imgl-ring-width);
}

/* Invisible tap target around each marker dot on touch/small screens.

   WHY. The plugin scales every `responsive` marker by
   renderedImageWidth / naturalImageWidth (_updateSize() in
   jquery.imagelinks.min.js). The map SVG is 1693px wide, so on a 390px viewport
   the configured 20x20px dot renders at roughly 4px — about a tenth of the
   44x44px WCAG 2.5.5 minimum. imagelinks-zoom.js floors the dot itself to
   MIN_DOT_PX, and this supplies the rest of the target without enlarging the dot
   any further: growing the visible dot to a full 44px would merge the dense
   European cluster into a single blob.

   It is a pseudo-element, NOT padding or a bigger box on .imgl-marker, because
   that element's real dimensions are load-bearing elsewhere — the plugin writes
   explicit width/height to it, and markerRadius() in imagelinks-zoom.js measures
   it to place each tooltip arrow. Inflating its box would drag every arrow off
   its pin.

   --imgl-hit-size is set inline by imagelinks-zoom.js so the JS size floor and
   this hit area are driven by one decision rather than two thresholds that can
   drift apart. `.is-touch` is added by the same code.

   The halo is inside .imgl-marker, so it inherits the counter-scale transform and
   therefore holds a constant on-screen size across every zoom level — the same
   reason the dot itself does. */
.imgl-zoom-wrap.is-touch .imgl-markers .imgl-marker::after {
    position: absolute;
    top: 50%;
    left: 50%;
    width: var(--imgl-hit-size);
    height: var(--imgl-hit-size);
    content: "";
    background-color: transparent;
    border-radius: var(--radius-full);
    transform: translate(-50%, -50%);
}

.imgl-zoom-wrap .imgl-map {
    transform-origin: center center;
    transition: transform 0.15s ease-out;
}

.imgl-zoom-wrap.is-zoomed .imgl-map {
    cursor: grab;
}

/* `will-change: transform` is applied ONLY while dragging, never at rest.

   It used to sit on .imgl-map unconditionally, which was the main cause of the
   blurry zoomed map and tooltip text. The property promotes the element to its
   own compositor layer, and that layer is rasterized once at its 1x size — the
   GPU then stretches those cached pixels for every scale value, so at 3x the
   view is a 1x-resolution bitmap blown up 300%. The map background is an SVG
   and could render sharply at any zoom; layer caching discarded that resolution
   before it was ever used. Text suffered most, being the least forgiving of
   resampling.

   Declaring it permanently also tells the browser "more transforms are coming",
   which suppresses the re-rasterization at the new scale that would otherwise
   happen once a transform settles.

   Panning is the one case that genuinely wants the hint: it retransforms on
   every pointermove, where re-rasterizing each frame would stutter. Scoping it
   to .is-dragging (already toggled by pointerDown/pointerUp in
   imagelinks-zoom.js) keeps the pan smooth and lets the browser re-rasterize
   crisply the moment the drag ends. */
.imgl-zoom-wrap.is-dragging .imgl-map {
    /* No transition mid-drag so panning tracks the pointer 1:1. */
    transition: none;
    cursor: grabbing;
    will-change: transform;
}

/* Same hint, for the same reason, on the two zoom paths that were still missing
   it: pinch and the +/- buttons. Both call zoomTo()/apply() in
   imagelinks-zoom.js without ever touching .is-dragging, so before this they
   re-rasterized the SVG with no compositor promotion at all — pinch on every
   touchmove of the gesture, buttons across the 0.15s transition below. That
   matches the reported "blurry until it comes into focus" symptom: a plain,
   uncomposited transform change on this element forces a synchronous
   re-rasterize, and on a mid-range phone GPU that lags visibly behind the
   scale change until the browser catches up.

   `.is-scaling` is added by pinchStart/zoomTo in imagelinks-zoom.js and
   removed on pinch end / at the transitionend of a button zoom, so — like
   .is-dragging — the promotion never sits on the element at rest and the
   final frame of any zoom still re-rasterizes at full SVG sharpness. */
.imgl-zoom-wrap.is-scaling .imgl-map {
    will-change: transform;
}

.imgl-zoom-controls {
    position: absolute;
    top: var(--space-sm);
    right: var(--space-sm);
    z-index: 5;
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
}

.imgl-zoom-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--space-xl);
    height: var(--space-xl);
    padding: 0;
    font-size: var(--font-size-lead);
    line-height: 1;
    color: var(--color-text-primary);
    background-color: var(--color-bg-primary);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-button);
    box-shadow: var(--shadow-md);
    cursor: pointer;
}

.imgl-zoom-btn:hover {
    background-color: var(--color-bg-secondary);
}

.imgl-zoom-btn:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   ImageLinks map typography & tooltips

   All of the rules below were migrated out of the ImageLinks item's own
   "Custom CSS" field (persisted in config.json in the DB) so they are
   version-controlled, linted and built with the rest of the theme rather than
   living in a blob a client edit can silently overwrite.

   The original CSS flagged nearly every declaration `!important`. Most of those
   flags are genuinely redundant — these selectors out-specify the plugin's — and
   were dropped during the move. But NOT all of them: the plugin's own theme
   stylesheet is enqueued well after the theme (measured on production: theme is
   stylesheet index 26, light.min.css is 35), so wherever it sets the same
   property on the same element, source order decides and the flag is load-
   bearing. Each surviving `!important` is individually justified in a comment
   at its rule; don't remove one without re-testing on production with the map's
   Custom CSS field EMPTY.

   That caveat is not hypothetical: the first pass tested these rules while the
   Custom CSS field still contained an `!important` copy of them, which masked
   the plugin defaults and made the flags look unnecessary. Clearing that field
   on deploy is what exposed the regression (tooltip padding/radius reverted to
   the plugin's 10px 5px / 5px on desktop).
   -------------------------------------------------------------------------- */

/* Base map typography. Scoped to .imgl-map so the universal selector can never
   leak into the surrounding page. */
.imgl-map *,
.imgl-detail-panel * {
    font-family: var(--font-family-body);
    font-size: var(--font-size-body);
    color: inherit;
}

.imgl-map p,
.imgl-detail-panel p {
    margin-bottom: var(--space-3xs);
    font-family: var(--font-family-body);
    line-height: var(--line-height-body);
    color: inherit;
}

.imgl-map p a:not(.btn),
.imgl-detail-panel p a:not(.btn) {
    color: var(--color-link);
}

.imgl-map p.imgl-tooltip-title,
.imgl-detail-panel p.imgl-tooltip-title {
    /* padding-right reserves room for the injected close button, which is
       absolutely positioned in the popup's top-right corner, so a long
       distributor name cannot run underneath it. */
    padding-right: var(--space-lg);
    font-family: var(--font-family-heading);
    font-size: var(--font-size-h6);
    font-weight: var(--font-weight-bold);
    color: var(--color-heading);
}

/* `!important` IS required on these two. The plugin's own theme stylesheet
   sets `.imgl-tooltip-form { padding: 10px 5px; border-radius: 5px }` in
   assets/themes/light.min.css, which WordPress enqueues nine sheets after the
   theme (measured: theme is stylesheet index 26, light.min.css is 35). Dropping
   the flags here was a regression — it was tested while the map's Custom CSS
   field still held an `!important` copy of these same rules, so the plugin
   default was being masked and the flags looked redundant. Once that field was
   cleared on deploy the plugin default surfaced and the tooltip reverted to
   10px 5px / 5px on desktop. Verified the values themselves are sound: the
   tokens resolve on this element (--space-md -> 22.4px, --radius-card -> 20px)
   and applying them directly produces the intended box. */
.imgl-tooltips .imgl-tooltip-form {
    padding: var(--space-md) !important;
    border-radius: var(--radius-card) !important;
}

/* Tooltip width: size to content, capped so long emails stop wrapping.

   The plugin writes a FIXED inline `width` on `.imgl-tooltip`. A fixed width can
   only be capped by `max-width`, never grown by it — which is why raising the
   form's max-width alone never fixed the wrapped emails. `width: max-content`
   replaces it, so each tooltip is as wide as its longest unbreakable run and no
   wider (measured across all 50: 169-418px over 44 distinct widths).

   Must be `max-content`, NOT `auto`: `.imgl-tooltip-offset` is absolute inside a
   zero-width containing block, so `auto` shrink-to-fits to nothing and collapses
   every tooltip — making every email wrap.

   418px is the widest email's requirement at the 18px this actually renders at;
   the inner cap is that less the 48.4px horizontal padding. `!important` is
   required on both to beat the plugin's inline width. The `min()` keeps the
   viewport clamp: at 390px the widest tooltip is 333px of a 366px budget. */
.imgl-tooltip-form {
    max-width: min(418px, calc(100vw - 24px)) !important;
}

.imgl-tooltip-form .imgl-tooltip {
    box-sizing: border-box;
    width: max-content !important;
    max-width: min(369.6px, 100%) !important;
}

/* Arrow inset vs corner radius.

   The plugin seats the arrow 10px from the panel corner on the `-top`/`-bottom`
   placement variants, which suits its own 5px default radius. This theme
   overrides the panel to `--radius-card` (20px), so at 10px the arrow meets the
   edge while it is still curving away — leaving a visible notch between the
   triangle and the panel. Seating it past the radius puts it on the straight
   part of the edge, where it reads as one shape with the panel.

   Targeted by exact placement class, not a substring match. `[class*="-top"]`
   would also catch the centred `imgl-tooltip-top` and shove its mid-edge arrow
   into a corner; `[class$=…]` is worse still, because the plugin appends
   `imgl-show`/`imgl-hide` AFTER the placement class on some state changes, so
   an ends-with match would apply only half the time. Only the eight corner
   variants have the 10px inset; the four centred ones are mid-edge and fine.

   `!important` is required on all four rules: the plugin's own selector carries
   four classes (`.imgl-theme-default .imgl-tooltips .imgl-tooltip-wrap.imgl-
   tooltip-top-left .imgl-tooltip-arrow`) against three here, so a plain
   declaration loses on specificity and the arrow silently keeps its 10px inset. */
.imgl-map .imgl-tooltip-left-top .imgl-tooltip-arrow,
.imgl-map .imgl-tooltip-right-top .imgl-tooltip-arrow {
    top: 24px !important;
}

.imgl-map .imgl-tooltip-left-bottom .imgl-tooltip-arrow,
.imgl-map .imgl-tooltip-right-bottom .imgl-tooltip-arrow {
    bottom: 24px !important;
}

.imgl-map .imgl-tooltip-top-left .imgl-tooltip-arrow,
.imgl-map .imgl-tooltip-bottom-left .imgl-tooltip-arrow {
    left: 24px !important;
}

.imgl-map .imgl-tooltip-top-right .imgl-tooltip-arrow,
.imgl-map .imgl-tooltip-bottom-right .imgl-tooltip-arrow {
    right: 24px !important;
}

/* Hover bridge: the popup's hoverable "safe zone" hugs the arrow at a single
   point. Moving the cursor off that point (instead of tracing the arrow exactly)
   exits the safe zone and the tooltip closes before the cursor reaches the popup
   content. This pseudo-element extends the tooltip's actual hoverable hit-area
   back toward the marker across the popup's full edge (not just the arrow tip),
   so any approach angle stays "inside" a hoverable element the whole way from
   marker to popup.

   The bridge must sit on the side facing the marker, which is the OPPOSITE side
   to the placement name: a `right`-placed tooltip opens to the right of its
   marker, so the marker is off its left edge. Most markers here are `right`, so
   that is the default below; the handful using other placements get a matching
   override, keyed off the `imgl-tooltip-*` class the plugin puts on the wrap.
   Without these, a left/top/bottom tooltip's bridge points away into empty space
   and that tooltip becomes the hard-to-reach kind this rule exists to fix.

   The 60px reach is sized for ZOOM, not for the 1x layout. This pseudo-element
   lives inside .imgl-tooltip-form, which imagelinks-zoom.js counter-scales by
   1/scale — so its on-screen reach is 60/scale and shrinks exactly as the map
   zooms in. At the old 20px it covered only 6.7px at 3x and 5px at 4x, which
   was less than the gap the arrow now holds off the marker, leaving dead space
   the cursor had to cross and making zoomed tooltips impossible to click into.
   60px keeps the bridge ahead of that gap at every zoom level. */
.imgl-map .imgl-tooltip-form {
    position: relative;
}

.imgl-map .imgl-tooltip-form::after {
    position: absolute;
    top: 0;
    right: 100%;
    bottom: 0;
    left: -60px;
    content: "";
}

/* Tooltip opens to the LEFT of its marker -> bridge on the right edge. */
.imgl-tooltip-wrap[class*="imgl-tooltip-left"] .imgl-tooltip-form::after {
    top: 0;
    right: -60px;
    bottom: 0;
    left: 100%;
}

/* Opens ABOVE its marker -> bridge along the bottom edge. */
.imgl-tooltip-wrap[class*="imgl-tooltip-top"] .imgl-tooltip-form::after {
    top: 100%;
    right: 0;
    bottom: -60px;
    left: 0;
}

/* Opens BELOW its marker -> bridge along the top edge. */
.imgl-tooltip-wrap[class*="imgl-tooltip-bottom"] .imgl-tooltip-form::after {
    top: -60px;
    right: 0;
    bottom: 100%;
    left: 0;
}

/* Close (X) button, top-right corner of the popup.

   Added at the client's request: with hover-triggered interactive tooltips in
   the dense European cluster, moving the pointer toward a neighbouring dot
   usually crosses the open panel, which keeps it alive and leaves it covering
   the dots you were aiming for. This is the explicit way out.

   Injected by imagelinks-zoom.js as the form's last child. The form already has
   `position: relative` (set above for the hover bridge), so absolute
   positioning here anchors to the popup box. z-index clears the ::after bridge,
   which is a later-painted sibling and would otherwise swallow the clicks. */
.imgl-map .imgl-tooltip-close {
    position: absolute;
    z-index: 3;
    top: var(--space-2xs);
    right: var(--space-2xs);
    display: flex;
    width: 26px;
    height: 26px;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: var(--radius-full);
    margin: 0;
    background: transparent;

    /* The glyph is a decorative "×" sized independently of the popup's body
       copy, so a literal value is correct here rather than a --font-size-* token
       (those are content scales, and the smallest still renders this too large
       for a 26px control). line-height: 1 centres the glyph in the circle. */
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
}

.imgl-map .imgl-tooltip-close:hover,
.imgl-map .imgl-tooltip-close:focus-visible {
    background: var(--color-bg-secondary);
    color: var(--color-heading);
}


/* Tablet and below — steps the base 16px down, as the original Custom CSS did.
   Kept at the same 991px breakpoint so behaviour is unchanged by the move. */
@media (width <=991px) {
    .imgl-map *,
    .imgl-detail-panel * {
        font-size: var(--font-size-small);
    }
}

/* Narrow screens: the tooltip is a small floating panel on an already-cramped
   viewport, so tighten the type and the spacing both around and between the
   text, and let long emails/URLs break rather than force the panel wider than
   the clamp above. */
@media (width <=480px) {
    /* Body text keeps the --font-size-small set by the 991px query above; only
       the title needs stepping down, from --font-size-h6 to body copy, so it
       stops dominating a panel this narrow. The `p.imgl-tooltip-title` compound
       already out-specifies the `.imgl-map *` rule above, so no flag needed. */
    .imgl-map p.imgl-tooltip-title,
    .imgl-detail-panel p.imgl-tooltip-title {
        font-size: var(--font-size-body);
    }

    .imgl-tooltip {
        overflow-wrap: anywhere;
    }

    /* Space AROUND the text — the 1em inset is a large share of the panel's
       width on a 390px screen. Carries `!important` to match the base rule
       above; without it this loses to that rule's flagged declaration and the
       mobile inset silently reverts to the desktop value. */
    .imgl-tooltips .imgl-tooltip-form {
        padding: var(--space-sm) var(--space-md) !important;
    }

    /* Space BETWEEN text blocks; the last <p> otherwise leaves trailing dead
       space inside the panel. */
    .imgl-map p:last-child,
    .imgl-detail-panel p:last-child {
        margin-bottom: 0;
    }

    /* Stacked contact rows sit closer together on a short screen. */
    .imgl-map .contact-info a {
        padding-top: var(--space-3xs);
        padding-bottom: var(--space-3xs);
    }
}

/* Contact icons (phone / email / website) — prepended to each .contact-info
   link inside a marker tooltip.

   Moved here from the map's own customCSS (stored in config.json in the DB)
   so the rules are version-controlled, linted and built like the rest of the
   theme, instead of living in a blob a client edit can silently overwrite.
   Remove the corresponding block from the ImageLinks item's Custom CSS when
   deploying this, or the DB copy will keep shadowing these rules.

   The data URIs are fully percent-encoded (%3C, %3E, %23). The previous
   version used `;utf8,` with raw `<` and unescaped quotes — valid enough for
   Chrome/Safari to render, but invalid per spec and fragile: any CSS
   minifier, CDN "optimize CSS" pass or WAF that rewrites the stylesheet can
   corrupt the value. A corrupted mask still leaves a 1em box painted with
   `background-color`, which is exactly the "squares instead of icons" the
   client reported.

   The icon is an inline-block ::before followed by raw text (no wrapping
   span available without editing all 50 markers' HTML), so a hanging
   indent is used instead of flex: padding-left reserves the icon's column
   width and text-indent pulls the FIRST line back to sit next to the icon.
   Any wrapped second/third line is NOT re-indented (no equivalent of
   text-indent for wrapped lines), so it naturally aligns under the text —
   i.e. NOT under the icon — keeping icon and text visually grouped as one
   entry regardless of how many lines the entry wraps to. 5px top/bottom
   padding gives a tight, consistent gap between stacked entries without
   paragraph-style spacing.

   min-width below fixes a `max-content`/text-indent measurement gap: the
   parent `.imgl-tooltip` sizes itself via `width: max-content` (see the
   "Tooltip width" rule further down), and the browser's intrinsic-width pass
   under-measures a block with negative text-indent by a few pixels versus
   what the same box actually needs once laid out. For most entries the gap
   is invisible (padding elsewhere in the tooltip absorbs it), but on
   Thailand's tooltip — where the email's own text width sits within ~4px of
   the computed tooltip width — the shortfall was enough to push the ENTIRE
   first line (icon + text) down to a phantom empty first line, leaving the
   mail icon alone above the email instead of beside it. Reproduced and
   bisected live: forcing this element even 4px wider than its natural
   max-content fixes the wrap; anything narrower reproduces the bug exactly.
   8px is a safety margin, not a tuned minimum. */
.imgl-map .contact-info a,
.imgl-detail-panel .contact-info a {
    display: block;
    padding: 5px 0 5px calc(1em + var(--space-2xs));
    overflow-wrap: anywhere;
    text-indent: calc(-1em - var(--space-2xs));
    word-break: break-word;
    min-width: calc(100% + 8px);
}

/* Base box only — deliberately no `background-color` here. The fill is applied
   only alongside a resolved mask below, so a pseudo-element that never matches
   an icon rule stays invisible instead of painting a solid currentcolor square.

   Note the @supports guard is NOT sufficient on its own: it tests whether the
   BROWSER supports masking, not whether a mask actually resolved for this
   element. LaunchPad's client-review.js rewrites every href to "#", which made
   the [href^="tel:"] / [href^="mailto:"] rules stop matching while
   `background-color` still applied from the shared rule — repainting exactly
   the squares this block set out to prevent. Each icon rule therefore now
   carries its own `background-color`, so fill and mask always arrive together. */
.imgl-map .contact-info a::before,
.imgl-detail-panel .contact-info a::before {
    display: inline-block;
    width: 1em;
    height: 1em;
    margin-right: var(--space-2xs);
    content: "";
    vertical-align: -0.125em;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
}

/* Each rule below matches BOTH `href` and `data-original-href`. In LaunchPad
   Review Mode the real URL is moved to data-original-href and href becomes "#",
   so an href-only selector silently stops matching on review URLs. Matching
   both keeps the icons correct in review mode and on the live site alike. */
@supports (mask-image: url("")) or (-webkit-mask-image: url("")) {
    /* Fill applied only to elements that also receive a mask below, so an
       unmatched link can never paint a bare square. */
    .imgl-map .contact-info a[href^="tel:"]::before,
    .imgl-detail-panel .contact-info a[href^="tel:"]::before,
    .imgl-map .contact-info a[data-original-href^="tel:"]::before,
    .imgl-detail-panel .contact-info a[data-original-href^="tel:"]::before,
    .imgl-map .contact-info a[href^="mailto:"]::before,
    .imgl-detail-panel .contact-info a[href^="mailto:"]::before,
    .imgl-map .contact-info a[data-original-href^="mailto:"]::before,
    .imgl-detail-panel .contact-info a[data-original-href^="mailto:"]::before,
    .imgl-map .contact-info a.in-cell-link::before,
    .imgl-detail-panel .contact-info a.in-cell-link::before {
        background-color: currentcolor;
    }

    .imgl-map .contact-info a[href^="tel:"]::before,
    .imgl-detail-panel .contact-info a[href^="tel:"]::before,
    .imgl-map .contact-info a[data-original-href^="tel:"]::before,
    .imgl-detail-panel .contact-info a[data-original-href^="tel:"]::before {
        -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.362 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.338 1.85.573 2.81.7A2 2 0 0 1 22 16.92z'/%3E%3C/svg%3E");
        mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.362 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.338 1.85.573 2.81.7A2 2 0 0 1 22 16.92z'/%3E%3C/svg%3E");
    }

    .imgl-map .contact-info a[href^="mailto:"]::before,
    .imgl-detail-panel .contact-info a[href^="mailto:"]::before,
    .imgl-map .contact-info a[data-original-href^="mailto:"]::before,
    .imgl-detail-panel .contact-info a[data-original-href^="mailto:"]::before {
        -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z'/%3E%3Cpath d='m22 6-10 7L2 6'/%3E%3C/svg%3E");
        mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z'/%3E%3Cpath d='m22 6-10 7L2 6'/%3E%3C/svg%3E");
    }

    .imgl-map .contact-info a.in-cell-link::before,
    .imgl-detail-panel .contact-info a.in-cell-link::before {
        -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M2 12h20'/%3E%3Cpath d='M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z'/%3E%3C/svg%3E");
        mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M2 12h20'/%3E%3Cpath d='M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z'/%3E%3C/svg%3E");
    }
}

/* ==========================================================================
   TranslatePress Language Switcher
   Layout/spacing for the switcher within the header (flush against the CTA
   button, hamburger positioning) is handled in components/navigation.css under
   "LANGUAGE SWITCHER (TranslatePress) + HEADER CTA GROUP".
   ========================================================================== */

/* Desktop — match the "Treatment Options Compared" reference: show the active
   panel's icon in the left rail, stack the content as text over a full-width
   image, and give the collapsed-tab dividers a visible gray. Tablet/mobile keep
   the plugin's own responsive layout. */
@media (width >=1025px) {
    .horizontal-accordion-slides .accordion-panel:not(:last-child)::after {
        background-color: color-mix(in srgb, var(--wp--preset--color--gray) 20%, transparent);
    }

    /* Fixed, consistent band height across all panels. Content that exceeds it
       is absorbed by shrinking the image (below), not by growing the panel — so
       every slide is the same height and the text is always fully shown. */
    .horizontal-accordion-slides .horizontal-accordion-container {
        height: clamp(600px, 65vh, 800px);
    }

    /* Flex column: text takes its natural height; the image column takes the
       remainder and is allowed to shrink (min-height:0) so nothing overflows. */
    .horizontal-accordion-slides .panel-content-inner {
        flex-direction: column;
        align-items: flex-start;
        justify-content: flex-start;
        padding-top: var(--space-lg);
        padding-right: var(--space-lg);
        padding-bottom: var(--space-lg);
        padding-left: var(--space-lg);
        row-gap: var(--space-sm);
        height: 100%;
        min-height: 0;
    }

    .panel-icon-collapsed {
        top: var(--space-lg);
    }

    .panel-title-vertical {
        bottom: var(--space-lg);
    }

    /* Text: fixed size, always fully visible (never shrinks or clips). */
    .horizontal-accordion-slides .panel-content-left {
        flex: 0 0 auto;
        width: 100%;
    }

    /* Image column: takes the space left after the text and shrinks to fit the
       fixed panel height (min-height:0 lets it go below the image's natural
       size). This is the element that absorbs tall content. */
    .horizontal-accordion-slides .panel-content-right {
        flex: 1 1 auto;
        width: 100%;
        min-height: 0;
        display: flex;
        flex-direction: column;
        overflow: hidden;
    }

    /* Align the image to the top-left so it lines up with the text above it.
       (The wrap is a flex box; without this it centers the image.) */
    .horizontal-accordion-slides .panel-slide-image {
        flex: 1 1 auto;
        min-height: 0;
        height: auto;
        align-items: flex-start;
        justify-content: flex-start;
    }

    /* Natural size scaled DOWN to fit within the column on both axes: auto
       width/height + max-width/max-height:100% means the whole image always
       shows (bottom rounded corners included) and it's never clipped, whether
       width or height is the limiting dimension. Left-aligned to match the text. */
    .horizontal-accordion-slides .panel-slide-image img {
        width: auto;
        height: auto;
        max-width: 100%;
        max-height: 100%;
        min-height: 0;
        object-fit: contain;
        object-position: left top;
    }
}

/* Wider viewports: taller fixed band so more content fits before the image has
   to shrink. Still a fixed (consistent) height across all panels — the image
   absorbs any overflow rather than the panel growing. */
@media (width >=1440px) {
    .horizontal-accordion-slides .horizontal-accordion-container {
        height: clamp(600px, 72vh, 900px);
    }
}

/* ==========================================================================
   ADJACENT ACF BLOCK SPACING (GLOBAL)
   ==========================================================================
   When two ACF blocks with no visible section background sit next to each
   other, the stacked section paddings (e.g. 3XL bottom + 3XL top) read as an
   oversized empty band. This rule collapses that seam by reducing the TOP
   padding of the following block to var(--space-lg) whenever the block above
   it also has no visible background — so consecutive plain-content sections
   sit tighter together.

   "No visible background" means the section wrapper has no solid/gradient
   color fill and no image: it carries none of .has-background (Gutenberg
   native color), .has-background-color (custom solid-color class used by some
   3MW blocks, e.g. content-panels-bg-graph), .has-background-image (image bg,
   as on an overlay hero — which also carries .has-overlay),
   .has-gradient-background (Gutenberg native gradient), .has-default-bg (a
   block's own fallback fill, e.g. the hero's solid Anika Blue), .has-overlay,
   or data-has-bg-image="true" (multi-column-boxed-content). Explicitly white
   (.has-white-background-color) and explicitly transparent
   (.has-transparent-background-color) still count as no visible background and
   collapse. Blocks with a chosen color/gradient/image background keep their
   full section padding, so the visual seam is preserved where it matters.

   This generalizes the previous per-block rules (sub-navigation's
   following-block rule and cta-banner's preceding-block :has() rule), which
   have been removed in favor of this single global rule.

   Sticky sub-navigation injects a zero-height placeholder div
   (.sub-navigation-block--sticky-placeholder) immediately after itself, which
   becomes the true adjacent sibling; it is treated as a no-background lead-in
   so the block after a sticky subnav collapses the same way.

   Specificity note: these selectors are (0,3,0)+, beating the single-class
   .section-padding-* utilities (0,1,0) without !important, while Gutenberg's
   inline per-block padding still wins — so any manual top padding an editor
   sets on the following block is always respected.
   ========================================================================== */

/* Two classes were missing from these exclusions and both produced the same
   defect — a block with a visible fill had its top padding collapsed like a
   plain one, so the fill read as cropped against the block above:

   - .has-gradient-background: the class WordPress emits for a gradient
     background (alongside a slug-specific .has-{slug}-gradient-background).
     Matching the generic class covers every gradient, theme.json or custom.
   - .has-default-bg: a block's own fallback fill, applied when the editor has
     chosen neither a background image nor a Gutenberg colour/gradient — e.g.
     hero.php pairs it with .has-dark-bg and paints solid --color-primary.
     Self-applied rather than Gutenberg-native, but visually a background in
     exactly the sense this rule cares about.

   Both were already covered by the intent stated above, which names
   colour/gradient/image backgrounds as worth preserving padding for; only the
   selector had not kept up. */
.acf-block:not(.has-background, .has-background-color, .has-background-image, .has-gradient-background, .has-default-bg, .has-overlay, [data-has-bg-image="true"])+.acf-block:not(.has-background, .has-background-color, .has-background-image, .has-gradient-background, .has-default-bg, .has-overlay, [data-has-bg-image="true"]) {
    padding-top: var(--space-lg);
}

/* ==========================================================================
   ACF BLOCK SPACING NEXT TO PROSE (WYSIWYG-EMBEDDED BLOCKS)
   ==========================================================================
   When an ACF block (video-showcase, two-column-content, statistics-row,
   testimonial, cta-banner, etc.) is inserted directly into the block editor
   content area, next to real prose (paragraphs, headings, quotes, lists) —
   as opposed to a page built entirely from stacked ACF blocks, e.g. the
   homepage, where entry-content's children are ALL <section> blocks and no
   plain-content-vs-page-section distinction exists — two spacing systems
   stack on top of each other:

   1. WordPress's global block gap (theme.json blockGap) adds a flat
      margin-top to every direct child of the content's flow/constrained
      layout, including ACF blocks.
   2. The ACF block itself carries its own section-padding-* utility class
      (via tmw_core_get_default_padding_class()), which ranges from
      section-padding-xl up to the sitewide default of section-padding-3xl
      depending on the block and any per-instance Gutenberg overrides.

   The result: a paragraph-to-paragraph gap is the ~20px block gap alone,
   but a paragraph-to-ACF-block gap becomes block-gap + full section padding
   (56-100px+), and that total varies further between block types because
   each was configured with a different padding scale. This reads as
   inconsistent, uncontrolled spacing throughout an article.

   Fix: an entry-content is only treated as "article prose with embedded
   blocks" if at least one of its direct children is a prose element
   (paragraph, heading, quote, list) — detected via
   :has(> :is(p, h1, ...)). Only inside such a container do ACF blocks lose
   the compounding block-gap margin and get their top/bottom padding capped
   at section-padding-lg, a scale appropriate for a block embedded between
   paragraphs rather than a standalone full-page section. A page built
   entirely from stacked ACF blocks (e.g. the homepage, where entry-content's
   children are ALL <section> and none are prose) never matches the :has()
   condition, so every block there keeps its configured padding (e.g.
   section-padding-3xl) exactly as authored.

   This intentionally applies to every ACF block in a mixed container, not
   just ones directly touching a prose sibling — an article often has runs
   of several ACF blocks in a row (e.g. video, then two-column, then a
   stats row, all before the next paragraph), and all of them should read
   as "inside the article" at a consistent scale, not just the first/last
   one touching text.

   Selector targets [class*="section-padding-"] rather than .acf-block:
   most block templates apply .acf-block via tmw_core_get_default_padding_class(),
   but at least one (testimonial-block, 3mw-blocks plugin) hardcodes its
   section-padding-* class directly without going through that helper and so
   never gets .acf-block. Matching on the padding class itself catches every
   block regardless of which path it took to get its padding.

   Specificity note: like the adjacent-block rule above, this uses a
   multi-part selector (0,2,0)+ so it beats the single-class
   .section-padding-* utilities (0,1,0) without !important. Gutenberg's
   inline per-block padding (set via the block's own padding controls in the
   editor) still wins, since inline styles always beat classes.

   SINGLE POSTS NEED AN EXPLICIT BRANCH — the :has() test cannot detect them.
   On the single-post template, post content is authored entirely as ACF
   blocks: every direct child of .wp-block-post-content is a <section>,
   <nav>, <hr> or <div>, and the prose lives *inside* those blocks rather
   than as a direct child. The :has(> prose) condition is therefore false,
   so a single post is classified as an all-blocks page (like the homepage)
   and keeps the full section-padding-3xl — 104px top and bottom, which
   compounds to 160-215px of measured ink-to-ink space between sections.

   This used to be masked: the template wrapped post content in an extra
   constrained wp-block-group, which changed the child structure enough for
   the :has() test to pass. That wrapper was removed so separators between
   ACF blocks could be spaced properly, which flattened every child to a
   bare <section> and silently switched off the padding cap here. The
   regression looked like a spacing bug in the template but was really this
   detection heuristic losing its signal.

   Matching .single .wp-block-post-content by class instead of by content
   shape is deliberate: a single post is *always* an article, regardless of
   whether its author happened to leave a paragraph at the top level, so
   structural detection is the wrong tool for it. Page-builder pages still
   go through the :has() test unchanged.
   ========================================================================== */

.entry-content:has(> :is(p, h1, h2, h3, h4, h5, h6, blockquote, ul, ol))>[class*="section-padding-"],
.single .wp-block-post-content>[class*="section-padding-"] {
    margin-top: 0;
    padding-top: var(--space-lg);
    padding-bottom: var(--space-lg);
}

/* ==========================================================================
   SEPARATOR BETWEEN ACF BLOCKS (SINGLE POST CONTENT)
   ==========================================================================
   Once the padding cap above applies, a separator's two neighbours are no
   longer symmetric around it. The block ABOVE ends with its capped
   padding-bottom of --space-lg (~31px); the block BELOW contributes nothing,
   because the flexible-content-area plugin forces padding-top: 0 with
   !important via its `> :first-child .acf-block` descendant selector, and
   the cap zeroes its margin-top. Left alone, the line sits ~31px below the
   preceding section and flush against the following one.

   Matching margin-bottom to the neighbour's capped padding restores a
   symmetric ~31px on both sides. Referencing the same --space-lg token the
   cap uses keeps the two in step: change the cap and this follows, instead
   of drifting into a hardcoded offset.

   Scoped to .wp-block-post-content so it only affects editor-authored post
   content and cannot reach separators inside page-builder sections, where
   the wrapper's flex gap already handles spacing correctly.

   Specificity note: (0,2,0) via the child combinator, so it beats the
   (0,1,0) .wp-block-separator utility without !important. The plugin's
   !important rules target padding only and never margins, so no !important
   is needed here.
   ========================================================================== */

.wp-block-post-content>.wp-block-separator {
    margin-top: 0;
    margin-bottom: var(--space-lg);
}

/* Slightly reduce blog post title size on single post pages */
.single-post h1.wp-block-post-title {
    font-size: var(--font-size-h3);
    text-wrap: normal;
}

/* Resources single template (single-resources.html) uses the same
   wp:post-title block markup as the blog's single.html, so it needs the
   same desktop size reduction — otherwise titles like "Dr. Deakon
   Administration Video" render at the full --font-size-h1 (36-72px). */
.single-resources h1.wp-block-post-title {
    font-size: var(--font-size-h3);
    text-wrap: normal;
}

/* Mobile: blog headings run large enough to wrap awkwardly (e.g. "Understanding"
   breaking onto its own line). Step both the post title and in-content headings
   down one size below 768px, matching the existing desktop headings-step-down
   approach used elsewhere in single posts. */
@media (width < 768px) {
    .single-post h1.wp-block-post-title,
    .single-resources h1.wp-block-post-title {
        font-size: var(--font-size-h4);
    }

    .single .entry-content h2 {
        font-size: var(--font-size-h5);
    }

    .single .entry-content h3 {
        font-size: var(--font-size-h6);
    }

    .single .entry-content h4 {
        font-size: var(--font-size-h6);
    }

    /* Related Posts / Related Resources / other dynamic-archive-grid section
       titles below the post content also run large on mobile. */
    .single-post .section-title,
    .single-resources .section-title {
        font-size: var(--font-size-h4);
    }
}

/* Video embeds fall back to the iframe's literal width/height attributes
   (e.g. width="500") when no rule constrains them, so they render at a fixed
   pixel width — overflowing the container rather than filling the content
   column. Two distinct cases need this, both outside core's coverage:

   1. Embeds pasted or hand-edited as raw HTML, which lose the
      `wp-has-aspect-ratio` + `wp-embed-aspect-*` classes core requires before
      it will stretch the iframe itself.
   2. The resource Video Link (`inc/video-resource-presentation.php`), which
      *does* carry those classes but still gets no core styling: WordPress only
      enqueues the `core/embed` stylesheet when an embed block is found while
      parsing content, and that markup is injected by a `render_block` filter on
      the featured-image block — after parsing. Core never sees an embed block,
      so `blocks/embed` is never enqueued and its classes match nothing.

   Deliberately not scoped to `.entry-content`: case 2 renders in the
   featured-image slot, which sits outside it. Owning the sizing here rather
   than force-enqueueing core's stylesheet keeps it independent of whether that
   conditional stylesheet happens to load. */
.wp-block-embed__wrapper iframe {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
}

/* The figure and wrapper need constraining too, not just the iframe: an
   unstyled `<figure>` is as wide as its content, so the iframe's literal
   `width="1200"` attribute stretches the figure past the container before the
   rule above ever applies. Core's embed stylesheet normally supplies these —
   see the note above for why it is absent on the Video Link path. */
.tmw-resource-video,
.tmw-resource-video .wp-block-embed__wrapper {
    width: 100%;
    max-width: 100%;
    margin-inline: 0;
}

/* ==========================================================================
   CookieYes
   ========================================================================== */
.cky-notice-btn-wrapper {
    gap: var(--space-sm);
}

.cky-notice-btn-wrapper .cky-btn {
    margin: 0;
}