/* =============================================================================
 * WordJS UI — a token-driven, Bootstrap-like CSS framework for themes
 * -----------------------------------------------------------------------------
 * ONE static stylesheet that every theme shares. It (1) auto-styles ALL standard
 * HTML elements, (2) ships opt-in components (.btn/.card/.alert/.badge/.table/
 * .nav/...), and (3) ships a utility layer (spacing/display/flex/text/color/...).
 *
 * EVERYTHING is driven by `--wjs-*` design tokens with sensible fallbacks, so a
 * theme customizes the whole framework just by declaring tokens in its own
 * `:root` (in themes/<slug>/style.css). Tokens declared here are DEFAULTS; the
 * theme stylesheet loads AFTER this file, so a theme's `:root` overrides these,
 * and a theme's own rules override component styles at equal specificity.
 *
 * SCOPING: selectors are intentionally low-specificity (bare elements / single
 * classes) and this file is loaded ONLY on public pages + the editor preview
 * (never the admin UI). Themed chrome that uses utility/Tailwind classes keeps
 * winning over the bare-element rules here, so in practice this styles raw
 * content HTML and provides opt-in classes everywhere it's loaded.
 *
 * BLOCK CLASSES COME IN PAIRS: `.wjs-block-x, .wp-block-x { … }`. The first is
 * WordJS's own name and the SOURCE — write new rules against it. The second is a
 * DEPRECATED WordPress-compatible alias, listed in the same grouped selector so
 * that themes written before the change, content already saved in a database and
 * anything a WXR import brings over from WordPress keep their styling. The markup
 * emits both classes on every element (frontend components/blocks/blockVars.ts,
 * `bc()`), so the two alternatives always match the same elements. When you add a
 * block rule here, list BOTH — and when the alias is removed in the next major
 * version, delete the `.wp-block-*` alternative from each group.
 *
 * Token reference + class reference: documentation/theming.md
 * Block-class contract + removal plan: documentation/block-class-identity.md
 * ========================================================================== */

/* ------------------------------------------------------------------ TOKENS - */
:root {
  /* Brand / semantic colors (themes override) */
  --wjs-color-primary: #2563eb;
  --wjs-color-primary-dark: #1e40af;
  --wjs-color-secondary: #6b7280;
  --wjs-color-secondary-dark: #4b5563;
  --wjs-color-accent: #7c3aed;
  --wjs-color-success: #16a34a;
  --wjs-color-danger: #dc2626;
  --wjs-color-warning: #f59e0b;
  --wjs-color-info: #0ea5e9;
  --wjs-color-light: #f8f9fa;
  --wjs-color-dark: #1f2937;
  /* --- WordJS UI on-color tokens (auto: max-contrast text on each solid color) --- */
  --wjs-color-on-primary: #ffffff;
  --wjs-color-on-secondary: #ffffff;
  --wjs-color-on-success: #161616;
  --wjs-color-on-danger: #ffffff;
  --wjs-color-on-warning: #161616;
  --wjs-color-on-info: #161616;
  --wjs-color-on-light: #161616;
  --wjs-color-on-dark: #ffffff;

  /* Surfaces + text + borders */
  --wjs-bg-canvas: #ffffff;
  --wjs-bg-surface: #ffffff;
  --wjs-bg-muted: #f8f9fa;
  --wjs-color-text-main: #1f2937;
  --wjs-color-text-muted: #6b7280;
  --wjs-color-heading: var(--wjs-color-text-main);
  --wjs-color-link: var(--wjs-color-primary);
  --wjs-color-link-hover: var(--wjs-color-primary-dark);
  --wjs-border-subtle: #e5e7eb;
  --wjs-border-width: 1px;
  --wjs-focus-ring: rgba(37, 99, 235, 0.35);

  /* Native UI color scheme. This is the one thing a dark theme could NOT say: it can paint every
   * surface it owns, but the parts the BROWSER draws — the scrollbar, the select/date/checkbox
   * widgets, the autofill background, the spellcheck underline, `Highlight` — stay in the light
   * palette and come out as bright chrome bolted to a dark page. `color-scheme` is the only
   * property that moves them, it must sit on the ROOT element to affect the canvas and the
   * viewport scrollbar, and a theme has no way to reach the root except through this contract.
   * Declared here as the token DEFAULT (`normal` = today's behaviour, so nothing changes for an
   * unaware theme) and consumed by the `html` rule in the REBOOT section below; a dark theme opts
   * in with `"tokens": { "--wjs-color-scheme": "dark" }` in its theme.json. */
  --wjs-color-scheme: normal;

  /* Typography */
  /* var(--font-inter, Inter): next/font registers --font-inter on the public tree; the inner
   * `Inter` fallback is load-bearing — an undefined var() WITHOUT fallback makes the whole
   * font-family invalid at computed-value time (UA font), e.g. inside the editor preview iframe. */
  --wjs-font-family-base: var(--font-inter, Inter), system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --wjs-font-family-heading: var(--wjs-font-family-base);
  --wjs-font-family-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --wjs-font-size-base: 1rem;        /* 16px */
  --wjs-line-height-base: 1.6;
  --wjs-heading-weight: 700;
  --wjs-heading-line-height: 1.2;
  --wjs-h1: 2.5rem;
  --wjs-h2: 2rem;
  --wjs-h3: 1.75rem;
  --wjs-h4: 1.5rem;
  --wjs-h5: 1.25rem;
  --wjs-h6: 1rem;

  /* Spacing scale (Bootstrap-style: 0, .25, .5, 1, 1.5, 3 × spacer) */
  --wjs-spacer: 1rem;

  /* Radius */
  --wjs-radius-sm: 0.25rem;
  --wjs-radius: 0.5rem;
  --wjs-radius-md: 0.5rem;
  --wjs-radius-lg: 0.75rem;
  --wjs-radius-pill: 50rem;

  /* Elevation */
  --wjs-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.08);
  --wjs-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
  --wjs-shadow-md: var(--wjs-shadow);
  --wjs-shadow-lg: 0 10px 20px -3px rgba(0, 0, 0, 0.15), 0 4px 8px -4px rgba(0, 0, 0, 0.1);

  /* Layout */
  --wjs-container-max: 1140px;
  --wjs-transition: 0.15s ease-in-out;

  /* Chrome (public header/footer/sidebar) — consumed by the React chrome via Tailwind
   * arbitrary values / inline style; every default = the value the chrome rendered before
   * these tokens existed. The var(--wjs-footer-*) indirection is DELIBERATE: themes declare
   * the documented --wjs-footer-* convention, and this bridge is what makes it apply. */
  --wjs-bg-footer: var(--wjs-footer-bg, rgb(17, 24, 39));
  --wjs-color-text-footer-main: var(--wjs-footer-text-body, white);
  --wjs-color-text-footer-dim: var(--wjs-footer-text-body, gray);
  --wjs-color-text-footer-heading: var(--wjs-footer-text-heading, #ffffff);
  /* (--wjs-bg-surface-glass already has its default in the derived-tokens :root below) */
  --wjs-header-offset: 6rem;   /* main padding-top under the fixed header (was pt-24) */
  --wjs-sidebar-width: 20rem;  /* was lg:w-80 */
  --wjs-sidebar-gap: 2.5rem;   /* was gap-10 */

  /* Display headings / lead / blockquote / mark (defaults = previous fixed values) */
  --wjs-display-1: 5rem;
  --wjs-display-2: 4.5rem;
  --wjs-display-3: 4rem;
  --wjs-display-4: 3.5rem;
  --wjs-display-weight: 300;
  --wjs-display-line-height: 1.1;
  --wjs-lead-size: 1.25rem;
  --wjs-lead-weight: 300;
  --wjs-blockquote-padding: 0.5rem 1.25rem;
  --wjs-blockquote-border-width: 4px;
  --wjs-blockquote-border-color: var(--wjs-color-primary);
  --wjs-blockquote-color: var(--wjs-color-text-muted);
  --wjs-blockquote-size: 1.125rem;
  --wjs-mark-bg: #fcf8c3;

  /* --- Visual-editor (Puck) block aliases ------------------------------------------------
   * The Puck block renderer references these token NAMES, but the canonical framework/theme
   * tokens are named differently (e.g. heading size is `--wjs-h1`, not `--wjs-h1-size`). With
   * no matching token AND no fallback, a heading's `font-size: var(--wjs-h1-size)` collapsed to
   * the inherited 16px — Puck headings rendered tiny and text ignored the theme. Map the block
   * names to the canonical tokens here as DEFAULTS; because custom properties resolve at use
   * time, a theme that overrides the canonical token (e.g. `--wjs-h1`) still flows through. */
  --wjs-h1-size: var(--wjs-h1);
  --wjs-h2-size: var(--wjs-h2);
  --wjs-h3-size: var(--wjs-h3);
  --wjs-h4-size: var(--wjs-h4);
  --wjs-h5-size: var(--wjs-h5);
  --wjs-h6-size: var(--wjs-h6);
  --wjs-h1-weight: var(--wjs-heading-weight);
  --wjs-h2-weight: var(--wjs-heading-weight);
  --wjs-h3-weight: var(--wjs-heading-weight);
  --wjs-h4-weight: var(--wjs-heading-weight);
  --wjs-h5-weight: var(--wjs-heading-weight);
  --wjs-h6-weight: var(--wjs-heading-weight);
  --wjs-font-family: var(--wjs-font-family-base);
  --wjs-color-text-heading: var(--wjs-color-heading);
  --wjs-color-text-dim: var(--wjs-color-text-muted);
  --wjs-color-primary-text: var(--wjs-color-on-primary);
  --wjs-foreground: var(--wjs-color-text-main);
  --wjs-bg-surface-hover: var(--wjs-bg-surface);
  --wjs-border-radius: var(--wjs-radius);
  --wjs-space-md: var(--wjs-spacer);
  --wjs-space-sm: calc(var(--wjs-spacer) * 0.5);

  /* --- RTL renames -----------------------------------------------------------------------
   * Same mechanism, different reason: the RTL pass turned a physical declaration into a LOGICAL
   * one, which left the token's name saying the opposite of what it now sets. The manifest is the
   * contract a theme author reads, so the canonical name follows the property
   * (`--wjs-cta-button-margin-start` → `margin-inline-start`) and the old physical name stays here
   * as an alias: a theme that already declares `--wjs-cta-button-ml` keeps working unchanged, and
   * the doctor's ALIAS_OVERRIDE points its author at the canonical name.
   * The `, 0` is NOT redundant — without it this declaration is invalid-at-computed-value-time
   * whenever no theme sets the canonical, and the alias would resolve to the guaranteed-invalid
   * value rather than to a real length. */
  --wjs-cta-button-ml: var(--wjs-cta-button-margin-start, 0);
}

/* ------------------------------------------------------------------ REBOOT - */

/* The token's single consumer. On `html` and not `:root` on purpose: same element, lower
 * specificity (0,0,1 vs 0,1,0), so a theme's own `:root` block always wins the TOKEN and nothing
 * here ever out-specifies it. The property must be on the root element — set on `body` it styles
 * that box's descendants but leaves the canvas and the viewport scrollbar alone. */
html { color-scheme: var(--wjs-color-scheme); }

*,
*::before,
*::after { box-sizing: border-box; }

[hidden] { display: none !important; }

img, svg, video, canvas, audio, iframe, embed, object { vertical-align: middle; }
img, video { max-width: 100%; height: auto; }

/* Base typography on the document where this framework is active. The public
 * site loads this only on its own pages, so styling `body` here themes the page
 * without touching the admin UI (which never loads this file). */
body {
  margin: 0;
  font-family: var(--wjs-font-family-base);
  font-size: var(--wjs-font-size-base);
  line-height: var(--wjs-line-height-base);
  color: var(--wjs-color-text-main);
  background-color: var(--wjs-bg-canvas);
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* --------------------------------------------------------------- HEADINGS - */
h1, h2, h3, h4, h5, h6 {
  margin: 0 0 0.5em;
  font-family: var(--wjs-font-family-heading);
  font-weight: var(--wjs-heading-weight);
  line-height: var(--wjs-heading-line-height);
  color: var(--wjs-color-heading);
}
h1 { font-size: var(--wjs-h1); }
h2 { font-size: var(--wjs-h2); }
h3 { font-size: var(--wjs-h3); }
h4 { font-size: var(--wjs-h4); }
h5 { font-size: var(--wjs-h5); }
h6 { font-size: var(--wjs-h6); }

.h1 { font-size: var(--wjs-h1) !important; }
.h2 { font-size: var(--wjs-h2) !important; }
.h3 { font-size: var(--wjs-h3) !important; }
.h4 { font-size: var(--wjs-h4) !important; }
.h5 { font-size: var(--wjs-h5) !important; }
.h6 { font-size: var(--wjs-h6) !important; }

/* Chrome footer headings: the h1-h6 rule above paints --wjs-color-heading (dark), which is
 * dark-on-dark over the dark footer chrome. Higher specificity remaps them to the footer
 * heading token (themes reach it through the --wjs-footer-text-heading bridge in :root). */
footer h3, footer h4 { color: var(--wjs-color-text-footer-heading, #ffffff); }

.display-1 { font-size: var(--wjs-display-1, 5rem); font-weight: var(--wjs-display-weight, 300); line-height: var(--wjs-display-line-height, 1.1); }
.display-2 { font-size: var(--wjs-display-2, 4.5rem); font-weight: var(--wjs-display-weight, 300); line-height: var(--wjs-display-line-height, 1.1); }
.display-3 { font-size: var(--wjs-display-3, 4rem); font-weight: var(--wjs-display-weight, 300); line-height: var(--wjs-display-line-height, 1.1); }
.display-4 { font-size: var(--wjs-display-4, 3.5rem); font-weight: var(--wjs-display-weight, 300); line-height: var(--wjs-display-line-height, 1.1); }
.lead { font-size: var(--wjs-lead-size, 1.25rem); font-weight: var(--wjs-lead-weight, 300); }

/* ------------------------------------------------------- TEXT-LEVEL CONTENT - */
p { margin: 0 0 1rem; }

a {
  color: var(--wjs-color-link);
  text-decoration: underline;
  text-underline-offset: 0.15em;
  transition: color var(--wjs-transition);
}
a:hover { color: var(--wjs-color-link-hover); }
a:not([href]):not([class]) { color: inherit; text-decoration: none; }

/* ------------------------------------------------------------------ PUBLIC CHROME -
 *
 * Everything in the public header and footer is an <a>, so the two rules above owned it: every nav
 * item, logo, footer link, social icon and CTA pill was painted --wjs-color-link, hovered to
 * --wjs-color-link-hover, and underlined.
 *
 * The React chrome does ask for the right thing — `text-[var(--wjs-color-text-main)]`,
 * `hover:text-[var(--wjs-color-primary)]`, footer links in --wjs-color-text-footer-dim, buttons in
 * --wjs-color-on-primary. None of it ever applied: those are Tailwind utilities, Tailwind puts them
 * in `@layer utilities`, and an UNLAYERED rule (this file) beats a layered one regardless of
 * specificity. The utility never had a chance, in any theme, since the day the chrome was written.
 *
 * What it looked like: a filled CTA whose label is the same colour as its own fill (invisible
 * whenever link == primary, which is most palettes), a dark-rust footer link list on a dark footer,
 * a permanently underlined menu, and a hover that jumps to an unrelated accent everywhere at once.
 *
 * Fixed here, next to the rules that were winning, through the --wjs-nav-* / --wjs-footer-text-*
 * families the default theme already uses — so a theme keeps full control and no longer needs
 * !important to get it, and :hover keeps working (an inline style would win but would freeze it).
 * The fallbacks are the components' own stated intent, not the accident they were getting. */
.wjs-header-nav a,
.wjs-chrome-nav a,
.wjs-header-mobile-panel a,
.wjs-header-logo,
.wjs-footer-logo,
.wjs-footer-grid a,
.wjs-footer-minimal a,
.wjs-chrome-button { text-decoration: none; }
.wjs-header-nav a:hover,
.wjs-chrome-nav a:hover,
.wjs-footer-grid a:hover,
.wjs-footer-minimal a:hover { text-decoration: var(--wjs-nav-hover-decoration, none); }

/* A menu item is one unit: the ROW may wrap between items (the nav containers are flex-wrap), never
 * a label down its middle — "PORTAL PARA CLIENTES" was coming out as three stacked lines in any
 * header that also carries a search field or two buttons. */
.wjs-header-nav a,
.wjs-chrome-nav a { white-space: nowrap; }

/* The mobile panel is the SAME menu and loses the same way — it is a separate <nav> in both chromes
 * (Header.tsx's own panel and ChromeNavMobile), sharing only the .wjs-header-mobile-panel wrapper,
 * so it needs naming here or the burger menu keeps painting itself --wjs-color-link. */
/* Scoped by LOCATION, not by "is it chrome": .wjs-chrome-nav is emitted by a composed nav in BOTH
 * the header and the footer, so colouring it here painted footer navigation with the masthead's
 * colour — dark-on-dark on any theme whose footer inverts the page. The header hook, the footer hook
 * and the mobile panel are three different surfaces with three different backgrounds. */
.wjs-header-nav a,
.wjs-header-mobile-panel a { color: var(--wjs-nav-color, var(--wjs-color-text-main)); }
.wjs-header-nav a:hover,
.wjs-header-mobile-panel a:hover { color: var(--wjs-nav-color-hover, var(--wjs-color-primary)); }
.wjs-header-logo { color: var(--wjs-logo-color, var(--wjs-color-text-main)); }
.wjs-header-logo:hover { color: var(--wjs-logo-color-hover, var(--wjs-color-primary)); }

.wjs-footer-grid a,
.wjs-footer-minimal a,
.wjs-footer-nav a,
.wjs-footer-logo { color: var(--wjs-footer-text-body, var(--wjs-color-text-footer-dim, #94a3b8)); }
.wjs-footer-grid a:hover,
.wjs-footer-minimal a:hover,
.wjs-footer-nav a:hover,
.wjs-footer-logo:hover { color: var(--wjs-footer-text-hover, var(--wjs-color-text-footer-main, #ffffff)); }
/* The composed footer's brand is the heading of that band, not one of its links. */
.wjs-footer-logo { color: var(--wjs-footer-text-heading, var(--wjs-color-text-footer-heading, #ffffff)); }
/* Social chips. Their background came from --wjs-bg-surface-hover, a token that lives in the
 * Puck-ALIAS zone (themes are told not to declare it) and resolves to the page's card surface — so
 * on a light theme the chip was a pale circle with a near-white glyph. --wjs-footer-icon-* is what
 * the default theme and four catalogue themes were already using for exactly this, through
 * `footer .w-10` !important rules targeting a Tailwind utility class; the compiler rejected those
 * tokens as UNKNOWN because nothing in the framework read them. Now it does, and the themes can
 * drop the !important. */
.wjs-footer-social a,
.wjs-chrome-socials a {
  background-color: var(--wjs-footer-icon-bg, var(--wjs-bg-surface-hover, rgba(255, 255, 255, 0.06)));
  color: var(--wjs-footer-icon-color, var(--wjs-color-text-footer-main, #ffffff));
  text-decoration: none;
}
.wjs-footer-social a:hover,
.wjs-chrome-socials a:hover {
  background-color: var(--wjs-footer-icon-hover-bg, var(--wjs-color-primary));
  color: var(--wjs-social-hover-color, var(--wjs-color-on-primary, #ffffff));
}

/* Nav typography, promoted from "something the default theme did with !important" into the contract.
 * Four catalogue themes were setting --wjs-nav-font-family and friends and getting UNKNOWN_TOKEN
 * from the compiler, because no framework rule read them — tokens that demonstrably worked and that
 * the contract denied. They are declared on the CONTAINER, never on the link: `styles.nav` compiles
 * to `.wjs-header-nav`, so a link-level declaration here would out-specify the theme's own rule and
 * make styles.nav.font-weight inert. The links then inherit, which is also what neutralises the
 * Tailwind `font-medium` that was winning over the theme. */
.wjs-header-nav,
.wjs-chrome-nav,
.wjs-footer-nav {
  font-family: var(--wjs-nav-font-family, inherit);
  font-size: var(--wjs-nav-font-size, inherit);
  font-weight: var(--wjs-nav-font-weight, 500);
  text-transform: var(--wjs-nav-text-transform, none);
  letter-spacing: var(--wjs-nav-letter-spacing, normal);
}
.wjs-header-nav a,
.wjs-chrome-nav a,
.wjs-footer-nav a {
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  transition: var(--wjs-nav-transition, color var(--wjs-transition));
}

/* NavMenu block — the ChromeNav vocabulary placed in PAGE CONTENT (not the header/footer band). It
 * emits the same .wjs-chrome-nav* hooks a composed chrome nav does, so the submenu / spacing /
 * typography rules above already apply; this only supplies the content-context surface the band hooks
 * would otherwise carry. Scoped under .wjs-block-nav-menu (specificity 0,2,1) so it out-ranks the band
 * `a` rules (0,1,1): a VERTICAL content menu emits the .wjs-footer-nav hook, whose footer-dim colour is
 * wrong on a light in-content background — here the link takes the page's own main text colour, and a
 * theme keeps full control through --wjs-nav-color / --wjs-nav-color-hover.
 *
 * The MegaMenu block shares the same in-content surface: its structure emits the same .wjs-chrome-nav
 * vocabulary (plus the .wjs-mega-menu / .wjs-mega-menu__panel hooks), so the same scoped link colour
 * applies under .wjs-block-mega-menu. The panel surface itself is tokenized in the block's own markup
 * (--wjs-bg-surface / --wjs-border-subtle), exactly like the NavMenu submenu panel. */
.wjs-block-nav-menu .wjs-chrome-nav a,
.wjs-block-mega-menu .wjs-chrome-nav a {
  color: var(--wjs-nav-color, var(--wjs-color-text-main, inherit));
  text-decoration: none;
}
.wjs-block-nav-menu .wjs-chrome-nav a:hover,
.wjs-block-mega-menu .wjs-chrome-nav a:hover {
  color: var(--wjs-nav-color-hover, var(--wjs-color-primary));
}

/* NavMenu submenu — the disclosure, moved HERE from Tailwind visible/invisible utilities for the same
 * reason as the MegaMenu flyout below: the unlayered `.invisible { !important }` utility out-cascades
 * any LAYERED utility toggle, so the old group-hover/group-focus-within reveal could NEVER open on the
 * public surface. Scoped to the HORIZONTAL nav (the vertical/footer submenu is a static, always-visible
 * indented list — it must stay untouched) and to the flyout position
 * (`.wjs-has-submenu > .wjs-chrome-submenu`, nested levels included).
 *
 * Two trigger modes, keyed on the block's rendered data-trigger attr (like MegaMenu):
 *  - hover: :hover and :focus-within open (keyboard-reachable — the trigger is a real link; Tab-out
 *    closes). CSS-only, no JS.
 *  - click: the caret is a real <button> and the NavClickSubmenus island flips [data-open] (Escape /
 *    outside-click close). :focus-within must NOT open in this mode — the toggled-closed panel would
 *    re-open (stick open) while the just-clicked button keeps focus.
 * A theme restyles the panel surface via --wjs-bg-surface / --wjs-border-subtle and may retime the
 * reveal via --wjs-transition. */
.wjs-block-nav-menu .wjs-chrome-nav-horizontal .wjs-has-submenu > .wjs-chrome-submenu {
  visibility: hidden;
  opacity: 0;
  translate: 0 4px;
  transition: opacity var(--wjs-transition, 0.15s ease), translate var(--wjs-transition, 0.15s ease), visibility 0.15s;
}
.wjs-block-nav-menu[data-trigger="hover"] .wjs-chrome-nav-horizontal .wjs-has-submenu:hover > .wjs-chrome-submenu,
.wjs-block-nav-menu[data-trigger="hover"] .wjs-chrome-nav-horizontal .wjs-has-submenu:focus-within > .wjs-chrome-submenu,
.wjs-block-nav-menu .wjs-chrome-nav-horizontal .wjs-has-submenu[data-open="true"] > .wjs-chrome-submenu {
  visibility: visible;
  opacity: 1;
  translate: 0 0;
}

/* MegaMenu flyout — the CSS-only disclosure lives HERE, on the block's own hooks, and deliberately
 * NOT in utility classes: this sheet ships an unlayered `.invisible { visibility: hidden !important }`
 * (utility set, above) that out-cascades any LAYERED utility toggle, so a Tailwind
 * visible/invisible reveal can never open on the public surface. Scoped to the flyout position
 * (`.wjs-has-submenu > .wjs-mega-menu__panel`) so the editor's flat authoring panels are untouched.
 * Keyboard: :focus-within opens (the trigger is a real link), Tab-out closes; :hover opens only when
 * the block asked for it (data-trigger="hover"). A theme restyles the panel surface through
 * --wjs-bg-surface / --wjs-border-subtle and may retime the reveal via --wjs-transition. */
.wjs-block-mega-menu .wjs-has-submenu > .wjs-mega-menu__panel {
  visibility: hidden;
  opacity: 0;
  translate: 0 4px;
  transition: opacity var(--wjs-transition, 0.15s ease), translate var(--wjs-transition, 0.15s ease), visibility 0.15s;
}
.wjs-block-mega-menu .wjs-has-submenu:focus-within > .wjs-mega-menu__panel,
.wjs-block-mega-menu[data-trigger="hover"] .wjs-has-submenu:hover > .wjs-mega-menu__panel {
  visibility: visible;
  opacity: 1;
  translate: 0 0;
}

/* SiteLogo block — the brand (logo image and/or site title) placed in PAGE CONTENT. Reuses the header
 * brand hooks .wjs-header-logo (link/wrapper) and .wjs-site-title (title text) so themes style it with
 * the rules they already ship. Scoped under .wjs-block-site-logo so an in-content title takes the page's
 * own text colour instead of the masthead colour a bare .wjs-header-logo rule might carry. */
.wjs-block-site-logo .wjs-header-logo { text-decoration: none; }
.wjs-block-site-logo .wjs-site-title {
  color: var(--wjs-nav-color, var(--wjs-color-text-main, inherit));
  font-weight: 700;
}
.wjs-block-site-logo .wjs-header-logo-img { display: block; height: auto; }

/* BackToTop block — a floating scroll-to-top control. The look comes from utility classes on the
 * button; this only exposes a theme hook so a theme can restyle the floating affordance without
 * fighting inline styles. */
.wjs-block-back-to-top {
  color: var(--wjs-color-on-primary, #ffffff);
  background: var(--wjs-back-to-top-bg, var(--wjs-color-primary, #2F6D86));
}

/* OffCanvas block — a slide-in drawer in page content. The panel/overlay reuse the header's
 * .wjs-header-mobile-panel / .wjs-header-mobile-overlay hooks so existing theme CSS applies; this only
 * ensures the block wrapper itself adds no layout of its own (it is just the trigger + fixed drawer). */
.wjs-block-offcanvas { display: inline-block; }

.wjs-chrome-button--primary,
.wjs-chrome-button--primary:hover { color: var(--wjs-color-on-primary, #ffffff); }
.wjs-chrome-button--ghost { color: var(--wjs-color-primary, #2F6D86); }
.wjs-chrome-button--ghost:hover { color: var(--wjs-color-on-primary, #ffffff); }

/* Block titles in the composed FOOTER (a nav's / social links' title, a ChromeHeading) are headings
 * of the footer band, so they take the footer heading token. They need the !important and the two
 * classes: themes paint every heading with `:is(h1…h6):not(.wjs-block-heading) { color: … !important }`
 * — specificity 0,1,1, which also beats their own `footer h3, footer h4` rule — and that is the
 * page's dark ink, i.e. dark-on-dark on the footer band. Header titles keep the masthead colours. */
.wjs-chrome-footer .wjs-chrome-block-title {
  color: var(--wjs-color-text-footer-heading, #ffffff) !important;
  font-size: var(--wjs-chrome-title-size, 1rem);
}

/* A row NESTED in another row is a group (nav + button on the right of a logo), not a band: it sizes
 * to its content. At w-full it claimed the whole parent row and squeezed its siblings, wrapping the
 * site name onto two lines next to it. A row that is a ChromeColumns cell keeps its full width. */
.wjs-chrome-row .wjs-chrome-row { width: auto; }

/* Composed header: TRANSPARENT OVER THE HERO (chrome root.transparent). The public layout lays the
 * header over the top of the page (absolute, or fixed when it is also sticky) and the
 * ChromeHeaderScroll island mirrors scrolling onto data-scrolled. While the page sits at the top the
 * header has no surface of its own, so the hero shows through; its links and brand take
 * --wjs-header-overlay-text when the theme sets one (light text over a dark hero) and keep their
 * normal colours otherwise. Once the page scrolls the header gets its solid surface back, so it stays
 * readable over whatever passes beneath it.
 * !important on purpose: themes paint the masthead with `header { background-color: … !important }`
 * (the default theme does), which silently cancelled every transparent header — the built-in one's
 * `layout.header.transparent` included. Transparency is an explicit author choice, so it wins while
 * it applies (unscrolled, transparent header only) and the theme's surface returns on scroll. */
.wjs-chrome-header[data-transparent="true"][data-scrolled="false"] {
  background: transparent !important;
  border-bottom-color: transparent !important;
  box-shadow: none !important;
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
}
/* root.overlayText: the author's pick for text over the hero, as the overlay token. */
.wjs-chrome-header[data-overlay-text="light"] { --wjs-header-overlay-text: #ffffff; }
.wjs-chrome-header[data-overlay-text="dark"] { --wjs-header-overlay-text: #111827; }
.wjs-chrome-header[data-transparent="true"][data-scrolled="false"] .wjs-header-nav a { color: var(--wjs-header-overlay-text, var(--wjs-nav-color, var(--wjs-color-text-main))) !important; }
.wjs-chrome-header[data-overlay-text][data-transparent="true"][data-scrolled="false"] .wjs-chrome-button--ghost {
  color: var(--wjs-header-overlay-text) !important;
  border-color: var(--wjs-header-overlay-text) !important;
}
.wjs-chrome-header[data-transparent="true"][data-scrolled="false"] .wjs-header-logo,
.wjs-chrome-header[data-transparent="true"][data-scrolled="false"] .wjs-chrome-text { color: var(--wjs-header-overlay-text, var(--wjs-logo-color, var(--wjs-color-text-main))) !important; }
/* The header is out of flow, so the page content would start underneath it. A page that OPENS WITH A
 * HERO is the point — it slides under the header — but any other page keeps the room the header
 * takes (--wjs-chrome-header-h, a theme may tune it). Pure CSS (:has), no measuring script. */
.wjs-shell:has(> .wjs-chrome-header[data-transparent="true"]) > main {
  padding-top: var(--wjs-chrome-header-h, 6rem) !important;
}
.wjs-shell:has(> .wjs-chrome-header[data-transparent="true"]):has(> main .puck-content > .wjs-block-hero:first-child) > main {
  padding-top: 0 !important;
}

small, .small { font-size: 0.875em; }
mark, .mark { padding: 0.1875em; background-color: var(--wjs-mark-bg, #fcf8c3); color: #422006; } /* fixed dark text — highlight bg is always light */
strong, b { font-weight: 700; }
em, i { font-style: italic; }
sub, sup { position: relative; font-size: 0.75em; line-height: 0; vertical-align: baseline; }
sub { bottom: -0.25em; }
sup { top: -0.5em; }
abbr[title] { text-decoration: underline dotted; cursor: help; text-decoration-skip-ink: none; }
address { margin-bottom: 1rem; font-style: normal; line-height: inherit; }

ul, ol { margin: 0 0 1rem; padding-inline-start: 2rem; }
ul ul, ul ol, ol ul, ol ol { margin-bottom: 0; }
li { margin-bottom: 0.25rem; }
dl { margin: 0 0 1rem; }
dt { font-weight: 700; }
dd { margin-bottom: 0.5rem; margin-inline-start: 0; }

.list-unstyled, .list-inline { padding-inline-start: 0; list-style: none; }
.list-inline-item { display: inline-block; }
.list-inline-item:not(:last-child) { margin-inline-end: 0.5rem; }

blockquote {
  margin: 0 0 1rem;
  padding: var(--wjs-blockquote-padding, 0.5rem 1.25rem);
  border-inline-start: var(--wjs-blockquote-border-width, 4px) solid var(--wjs-blockquote-border-color, var(--wjs-color-primary));
  color: var(--wjs-blockquote-color, var(--wjs-color-text-muted));
  font-size: var(--wjs-blockquote-size, 1.125rem);
}
blockquote p:last-child { margin-bottom: 0; }
blockquote cite, blockquote footer { display: block; margin-top: 0.5rem; font-size: 0.875rem; font-style: normal; color: var(--wjs-color-text-muted); }

hr {
  margin: 1.5rem 0;
  border: 0;
  border-top: var(--wjs-border-width) solid var(--wjs-border-subtle);
  opacity: 1;
}

figure { margin: 0 0 1rem; }
figcaption { margin-top: 0.5rem; font-size: 0.875rem; color: var(--wjs-color-text-muted); }

/* ---------------------------------------------------------------- CODE -------*/
code, kbd, samp, pre { font-family: var(--wjs-font-family-mono); font-size: 0.875em; }
code {
  padding: 0.15em 0.4em;
  color: var(--wjs-color-danger);
  background-color: var(--wjs-bg-muted);
  border-radius: var(--wjs-radius-sm);
  word-wrap: break-word;
}
a > code { color: inherit; }
pre {
  display: block;
  margin: 0 0 1rem;
  padding: 1rem;
  overflow: auto;
  color: var(--wjs-color-text-main);
  background-color: var(--wjs-bg-muted);
  border: var(--wjs-border-width) solid var(--wjs-border-subtle);
  border-radius: var(--wjs-radius);
  line-height: 1.5;
}
pre code { padding: 0; color: inherit; background: transparent; border-radius: 0; font-size: inherit; }
kbd {
  padding: 0.15em 0.4em;
  color: #fff;
  background-color: var(--wjs-color-dark);
  border-radius: var(--wjs-radius-sm);
}
kbd kbd { padding: 0; font-weight: 700; }

/* --------------------------------------------------------------- TABLES ------*/
table { border-collapse: collapse; }
caption { padding: 0.75rem 0; color: var(--wjs-color-text-muted); text-align: start; caption-side: bottom; }
th { text-align: inherit; }

/* Auto-styled raw tables in content + the .table component share one look. */
.wjs-content table,
.table {
  width: 100%;
  margin-bottom: 1rem;
  color: var(--wjs-color-text-main);
  vertical-align: top;
  border-color: var(--wjs-border-subtle);
}
.wjs-content table > :not(caption) > * > *,
.table > :not(caption) > * > * {
  padding: 0.625rem 0.75rem;
  border-bottom: var(--wjs-border-width) solid var(--wjs-border-subtle);
}
.wjs-content table > thead,
.table > thead { vertical-align: bottom; }
.wjs-content table th,
.table > thead th { font-weight: 700; text-align: start; }

.table-bordered > :not(caption) > * { border-width: var(--wjs-border-width) 0; }
.table-bordered > :not(caption) > * > * { border-width: 0 var(--wjs-border-width); border: var(--wjs-border-width) solid var(--wjs-border-subtle); }
.table-striped > tbody > tr:nth-of-type(odd) > * { background-color: rgba(0, 0, 0, 0.03); }
.table-hover > tbody > tr:hover > * { background-color: rgba(0, 0, 0, 0.05); }
.table-sm > :not(caption) > * > * { padding: 0.3rem 0.5rem; }
.table-responsive { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* ---------------------------------------------------------------- FORMS ------*/
label { display: inline-block; }
.form-label { display: inline-block; margin-bottom: 0.5rem; font-weight: 600; }
.form-text { margin-top: 0.25rem; font-size: 0.875em; color: var(--wjs-color-text-muted); }
fieldset { min-width: 0; padding: 0; margin: 0; border: 0; }
legend { float: left; float: inline-start; width: 100%; padding: 0; margin-bottom: 0.5rem; font-size: 1.5rem; font-weight: 700; line-height: inherit; }

/* Reboot form controls so raw inputs look intentional, plus the .form-control class. */
button, input, optgroup, select, textarea { font-family: inherit; font-size: inherit; line-height: inherit; margin: 0; }
button, select { text-transform: none; }
button, [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; cursor: pointer; }
button:disabled, [type="button"]:disabled, [type="reset"]:disabled, [type="submit"]:disabled { cursor: not-allowed; }
textarea { resize: vertical; }

.form-control,
.form-select,
.wjs-content input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="submit"]):not([type="button"]):not([type="reset"]),
.wjs-content textarea,
.wjs-content select {
  display: block;
  width: 100%;
  padding: 0.5rem 0.75rem;
  font-size: var(--wjs-font-size-base);
  font-weight: 400;
  line-height: 1.5;
  color: var(--wjs-color-text-main);
  background-color: var(--wjs-bg-canvas);
  background-clip: padding-box;
  border: var(--wjs-border-width) solid var(--wjs-border-subtle);
  border-radius: var(--wjs-radius);
  transition: border-color var(--wjs-transition), box-shadow var(--wjs-transition);
  appearance: none;
}
.form-control:focus,
.form-select:focus,
.wjs-content input:focus,
.wjs-content textarea:focus,
.wjs-content select:focus {
  border-color: var(--wjs-color-primary);
  outline: 0;
  box-shadow: 0 0 0 0.2rem var(--wjs-focus-ring);
}
.form-control::placeholder { color: var(--wjs-color-text-muted); opacity: 1; }
.form-control:disabled, .form-select:disabled { background-color: var(--wjs-bg-muted); opacity: 0.65; cursor: not-allowed; }
.form-control-sm { padding: 0.3rem 0.6rem; font-size: 0.875rem; border-radius: var(--wjs-radius-sm); }
.form-control-lg { padding: 0.7rem 1rem; font-size: 1.125rem; border-radius: var(--wjs-radius-lg); }
textarea.form-control { min-height: 6rem; }

.form-select {
  padding-inline-end: 2.25rem;
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 16px 12px;
}
/* `background-position` is the one property here with no logical equivalent — there is no
 * "inline-end 0.75rem center". So the chevron gets the single explicit direction rule in this
 * stylesheet. :where() keeps its specificity at zero so a theme still wins without !important. */
:where([dir="rtl"]) .form-select { background-position: left 0.75rem center; }

.form-check { display: block; min-height: 1.5rem; padding-inline-start: 1.6em; margin-bottom: 0.25rem; }
.form-check .form-check-input { float: left; float: inline-start; margin-inline-start: -1.6em; }
.form-check-input {
  width: 1.1em; height: 1.1em; margin-top: 0.2em;
  vertical-align: top; background-color: var(--wjs-bg-canvas);
  border: var(--wjs-border-width) solid var(--wjs-border-subtle);
  appearance: none; cursor: pointer; transition: background-color var(--wjs-transition), border-color var(--wjs-transition);
}
.form-check-input[type="checkbox"] { border-radius: var(--wjs-radius-sm); }
.form-check-input[type="radio"] { border-radius: 50%; }
.form-check-input:checked { background-color: var(--wjs-color-primary); border-color: var(--wjs-color-primary); }
.form-check-input:checked[type="checkbox"] { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3 6-6'/%3e%3c/svg%3e"); background-size: contain; background-repeat: no-repeat; background-position: center; }
.form-check-input:checked[type="radio"] { background-image: radial-gradient(#fff 36%, transparent 38%); }
.form-check-input:focus { outline: 0; box-shadow: 0 0 0 0.2rem var(--wjs-focus-ring); }
.form-check-label { cursor: pointer; }

.form-range { width: 100%; height: 1.5rem; padding: 0; background: transparent; appearance: none; cursor: pointer; }
.form-range::-webkit-slider-thumb { width: 1rem; height: 1rem; margin-top: -0.25rem; background: var(--wjs-color-primary); border: 0; border-radius: 50%; appearance: none; }
.form-range::-webkit-slider-runnable-track { width: 100%; height: 0.5rem; background: var(--wjs-border-subtle); border-radius: 1rem; }

/* Validation states */
.is-invalid, .was-validated :invalid { border-color: var(--wjs-color-danger) !important; }
.is-valid, .was-validated :valid { border-color: var(--wjs-color-success) !important; }
.invalid-feedback { display: none; width: 100%; margin-top: 0.25rem; font-size: 0.875em; color: var(--wjs-color-danger); }
.is-invalid ~ .invalid-feedback, .was-validated :invalid ~ .invalid-feedback { display: block; }
.valid-feedback { display: none; width: 100%; margin-top: 0.25rem; font-size: 0.875em; color: var(--wjs-color-success); }
.is-valid ~ .valid-feedback, .was-validated :valid ~ .valid-feedback { display: block; }

.input-group { position: relative; display: flex; flex-wrap: wrap; align-items: stretch; width: 100%; }
.input-group > .form-control, .input-group > .form-select { position: relative; flex: 1 1 auto; width: 1%; min-width: 0; }
.input-group > :not(:first-child) { margin-inline-start: -1px; border-start-start-radius: 0; border-end-start-radius: 0; }
.input-group > :not(:last-child) { border-start-end-radius: 0; border-end-end-radius: 0; }
.input-group-text { display: flex; align-items: center; padding: 0.5rem 0.75rem; font-size: var(--wjs-font-size-base); color: var(--wjs-color-text-main); background-color: var(--wjs-bg-muted); border: var(--wjs-border-width) solid var(--wjs-border-subtle); border-radius: var(--wjs-radius); }

/* --------------------------------------------------------------- BUTTONS ----- */
.btn {
  display: inline-block;
  padding: 0.5rem 1rem;
  font-family: inherit;
  font-size: var(--wjs-font-size-base);
  font-weight: 600;
  line-height: 1.5;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  vertical-align: middle;
  cursor: pointer;
  user-select: none;
  color: var(--wjs-color-text-main);
  background-color: transparent;
  border: var(--wjs-border-width) solid transparent;
  border-radius: var(--wjs-radius);
  transition: color var(--wjs-transition), background-color var(--wjs-transition), border-color var(--wjs-transition), box-shadow var(--wjs-transition), transform var(--wjs-transition);
}
.btn:hover { text-decoration: none; }
.btn:focus-visible { outline: 0; box-shadow: 0 0 0 0.2rem var(--wjs-focus-ring); }
.btn:active { transform: translateY(1px); }
.btn:disabled, .btn.disabled { opacity: 0.6; pointer-events: none; cursor: not-allowed; }

.btn-sm { padding: 0.3rem 0.65rem; font-size: 0.875rem; border-radius: var(--wjs-radius-sm); }
.btn-lg { padding: 0.7rem 1.4rem; font-size: 1.125rem; border-radius: var(--wjs-radius-lg); }
.btn-block { display: block; width: 100%; }

/* Solid variants — one rule per token via a local custom property. */
.btn-primary   { --_bg: var(--wjs-color-primary);   --_bd: var(--wjs-color-primary);   --_fg: var(--wjs-color-on-primary, #fff); }
.btn-secondary { --_bg: var(--wjs-color-secondary); --_bd: var(--wjs-color-secondary); --_fg: var(--wjs-color-on-secondary, #fff); }
.btn-success   { --_bg: var(--wjs-color-success);   --_bd: var(--wjs-color-success);   --_fg: var(--wjs-color-on-success, #fff); }
.btn-danger    { --_bg: var(--wjs-color-danger);    --_bd: var(--wjs-color-danger);    --_fg: var(--wjs-color-on-danger, #fff); }
.btn-warning   { --_bg: var(--wjs-color-warning);   --_bd: var(--wjs-color-warning);   --_fg: var(--wjs-color-on-warning, #1f2937); }
.btn-info      { --_bg: var(--wjs-color-info);      --_bd: var(--wjs-color-info);      --_fg: var(--wjs-color-on-info, #fff); }
.btn-light     { --_bg: var(--wjs-color-light);     --_bd: var(--wjs-border-subtle);   --_fg: var(--wjs-color-on-light, #1f2937); }
.btn-dark      { --_bg: var(--wjs-color-dark);      --_bd: var(--wjs-color-dark);      --_fg: var(--wjs-color-on-dark, #fff); }
.btn-primary, .btn-secondary, .btn-success, .btn-danger, .btn-warning, .btn-info, .btn-light, .btn-dark {
  background-color: var(--_bg);
  border-color: var(--_bd);
  color: var(--_fg); /* max-contrast text picked per theme (see --wjs-color-on-*) */
}
.btn-primary:hover, .btn-secondary:hover, .btn-success:hover, .btn-danger:hover,
.btn-warning:hover, .btn-info:hover, .btn-light:hover, .btn-dark:hover {
  filter: brightness(0.92);
  box-shadow: var(--wjs-shadow-sm);
}

/* Outline variants */
.btn-outline-primary   { color: var(--wjs-color-primary);   border-color: var(--wjs-color-primary); }
.btn-outline-secondary { color: var(--wjs-color-secondary); border-color: var(--wjs-color-secondary); }
.btn-outline-success   { color: var(--wjs-color-success);   border-color: var(--wjs-color-success); }
.btn-outline-danger    { color: var(--wjs-color-danger);    border-color: var(--wjs-color-danger); }
.btn-outline-warning   { color: var(--wjs-color-warning);   border-color: var(--wjs-color-warning); }
.btn-outline-info      { color: var(--wjs-color-info);      border-color: var(--wjs-color-info); }
.btn-outline-dark      { color: var(--wjs-color-dark);      border-color: var(--wjs-color-dark); }
.btn-outline-primary:hover   { color: var(--wjs-color-on-primary, #fff); background-color: var(--wjs-color-primary); }
.btn-outline-secondary:hover { color: var(--wjs-color-on-secondary, #fff); background-color: var(--wjs-color-secondary); }
.btn-outline-success:hover   { color: var(--wjs-color-on-success, #fff); background-color: var(--wjs-color-success); }
.btn-outline-danger:hover    { color: var(--wjs-color-on-danger, #fff); background-color: var(--wjs-color-danger); }
.btn-outline-warning:hover   { color: var(--wjs-color-on-warning, #1f2937); background-color: var(--wjs-color-warning); }
.btn-outline-info:hover      { color: var(--wjs-color-on-info, #fff); background-color: var(--wjs-color-info); }
.btn-outline-dark:hover      { color: var(--wjs-color-on-dark, #fff); background-color: var(--wjs-color-dark); }

.btn-link { color: var(--wjs-color-link); text-decoration: underline; border-color: transparent; }
.btn-link:hover { color: var(--wjs-color-link-hover); }

.btn-group { display: inline-flex; vertical-align: middle; }
.btn-group > .btn { border-radius: 0; }
.btn-group > .btn:first-child { border-start-start-radius: var(--wjs-radius); border-end-start-radius: var(--wjs-radius); }
.btn-group > .btn:last-child { border-start-end-radius: var(--wjs-radius); border-end-end-radius: var(--wjs-radius); }
.btn-group > .btn:not(:first-child) { margin-inline-start: -1px; }

/* =========================================================== COMPONENTS ===== */

/* CARD */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  background-color: var(--wjs-bg-surface);
  border: var(--wjs-border-width) solid var(--wjs-border-subtle);
  border-radius: var(--wjs-radius-lg);
  box-shadow: var(--wjs-shadow-sm);
}
.card-body { flex: 1 1 auto; padding: 1.25rem; }
.card-title { margin-bottom: 0.5rem; font-size: 1.25rem; font-weight: 700; }
.card-subtitle { margin-top: -0.25rem; margin-bottom: 0.5rem; color: var(--wjs-color-text-muted); }
.card-text:last-child { margin-bottom: 0; }
.card-header { padding: 0.85rem 1.25rem; background-color: var(--wjs-bg-muted); border-bottom: var(--wjs-border-width) solid var(--wjs-border-subtle); border-radius: var(--wjs-radius-lg) var(--wjs-radius-lg) 0 0; font-weight: 600; }
.card-footer { padding: 0.85rem 1.25rem; background-color: var(--wjs-bg-muted); border-top: var(--wjs-border-width) solid var(--wjs-border-subtle); border-radius: 0 0 var(--wjs-radius-lg) var(--wjs-radius-lg); }
.card-img-top { width: 100%; border-radius: var(--wjs-radius-lg) var(--wjs-radius-lg) 0 0; object-fit: cover; }
.card-img-bottom { width: 100%; border-radius: 0 0 var(--wjs-radius-lg) var(--wjs-radius-lg); object-fit: cover; }
.card-link + .card-link { margin-inline-start: 1rem; }

/* ALERT */
.alert {
  position: relative;
  padding: 0.9rem 1.1rem;
  margin-bottom: 1rem;
  border: var(--wjs-border-width) solid transparent;
  border-inline-start-width: 4px;
  border-radius: var(--wjs-radius);
}
.alert-heading { color: inherit; font-weight: 700; }
.alert-link { font-weight: 700; color: inherit; }
.alert-dismissible { padding-inline-end: 3rem; }
.alert-dismissible .btn-close, .alert-dismissible .close { position: absolute; top: 0; inset-inline-end: 0; padding: 1rem; }
.alert-primary   { color: var(--wjs-color-primary-dark); background-color: color-mix(in srgb, var(--wjs-color-primary) 12%, white); border-color: var(--wjs-color-primary); }
.alert-secondary { color: var(--wjs-color-secondary-dark); background-color: color-mix(in srgb, var(--wjs-color-secondary) 12%, white); border-color: var(--wjs-color-secondary); }
.alert-success   { color: #0f5132; background-color: color-mix(in srgb, var(--wjs-color-success) 14%, white); border-color: var(--wjs-color-success); }
.alert-danger    { color: #842029; background-color: color-mix(in srgb, var(--wjs-color-danger) 14%, white); border-color: var(--wjs-color-danger); }
.alert-warning   { color: #664d03; background-color: color-mix(in srgb, var(--wjs-color-warning) 16%, white); border-color: var(--wjs-color-warning); }
.alert-info      { color: #055160; background-color: color-mix(in srgb, var(--wjs-color-info) 14%, white); border-color: var(--wjs-color-info); }
/* Fallback for engines without color-mix(): a tinted neutral surface. */
@supports not (background: color-mix(in srgb, red 10%, white)) {
  .alert-primary, .alert-secondary, .alert-success, .alert-danger, .alert-warning, .alert-info { background-color: var(--wjs-bg-muted); }
}

/* BADGE */
.badge {
  display: inline-block;
  padding: 0.35em 0.6em;
  font-size: 0.75em;
  font-weight: 700;
  line-height: 1;
  color: var(--wjs-color-on-secondary, #fff);
  text-align: center;
  white-space: nowrap;
  vertical-align: baseline;
  background-color: var(--wjs-color-secondary);
  border-radius: var(--wjs-radius-sm);
}
.badge.rounded-pill { border-radius: var(--wjs-radius-pill); }
.badge-primary   { background-color: var(--wjs-color-primary); color: var(--wjs-color-on-primary, #fff); }
.badge-secondary { background-color: var(--wjs-color-secondary); color: var(--wjs-color-on-secondary, #fff); }
.badge-success   { background-color: var(--wjs-color-success); color: var(--wjs-color-on-success, #fff); }
.badge-danger    { background-color: var(--wjs-color-danger); color: var(--wjs-color-on-danger, #fff); }
.badge-warning   { background-color: var(--wjs-color-warning); color: var(--wjs-color-on-warning, #1f2937); }
.badge-info      { background-color: var(--wjs-color-info); color: var(--wjs-color-on-info, #fff); }
.badge-light     { background-color: var(--wjs-color-light); color: var(--wjs-color-on-light, #1f2937); }
.badge-dark      { background-color: var(--wjs-color-dark); color: var(--wjs-color-on-dark, #fff); }

/* LIST GROUP */
.list-group { display: flex; flex-direction: column; padding-inline-start: 0; margin-bottom: 0; border-radius: var(--wjs-radius); list-style: none; }
.list-group-item {
  position: relative;
  display: block;
  padding: 0.75rem 1.25rem;
  color: var(--wjs-color-text-main);
  background-color: var(--wjs-bg-surface);
  border: var(--wjs-border-width) solid var(--wjs-border-subtle);
}
.list-group-item + .list-group-item { border-top-width: 0; }
.list-group-item:first-child { border-top-left-radius: inherit; border-top-right-radius: inherit; }
.list-group-item:last-child { border-bottom-left-radius: inherit; border-bottom-right-radius: inherit; }
a.list-group-item, .list-group-item-action { text-decoration: none; cursor: pointer; transition: background-color var(--wjs-transition); }
a.list-group-item:hover, .list-group-item-action:hover { background-color: var(--wjs-bg-muted); }
.list-group-item.active { color: var(--wjs-color-on-primary, #fff); background-color: var(--wjs-color-primary); border-color: var(--wjs-color-primary); }
.list-group-item.disabled { color: var(--wjs-color-text-muted); pointer-events: none; }

/* BREADCRUMB */
.breadcrumb { display: flex; flex-wrap: wrap; padding: 0; margin-bottom: 1rem; list-style: none; }
.breadcrumb-item + .breadcrumb-item { padding-inline-start: 0.5rem; }
.breadcrumb-item + .breadcrumb-item::before { content: "/"; padding-inline-end: 0.5rem; color: var(--wjs-color-text-muted); }
.breadcrumb-item.active { color: var(--wjs-color-text-muted); }

/* PAGINATION */
.pagination { display: flex; padding-inline-start: 0; list-style: none; gap: 0; }
.page-link {
  display: block; padding: 0.45rem 0.8rem; color: var(--wjs-color-link); text-decoration: none;
  background-color: var(--wjs-bg-surface); border: var(--wjs-border-width) solid var(--wjs-border-subtle);
  transition: background-color var(--wjs-transition);
}
.page-link:hover { background-color: var(--wjs-bg-muted); }
.page-item:first-child .page-link { border-start-start-radius: var(--wjs-radius); border-end-start-radius: var(--wjs-radius); }
.page-item:last-child .page-link { border-start-end-radius: var(--wjs-radius); border-end-end-radius: var(--wjs-radius); }
.page-item:not(:first-child) .page-link { margin-inline-start: -1px; }
.page-item.active .page-link { color: var(--wjs-color-on-primary, #fff); background-color: var(--wjs-color-primary); border-color: var(--wjs-color-primary); }
.page-item.disabled .page-link { color: var(--wjs-color-text-muted); pointer-events: none; }

/* NAV / NAVBAR */
.nav { display: flex; flex-wrap: wrap; padding-inline-start: 0; margin-bottom: 0; list-style: none; }
.nav-link { display: block; padding: 0.5rem 1rem; color: var(--wjs-color-link); text-decoration: none; transition: color var(--wjs-transition); }
.nav-link:hover { color: var(--wjs-color-link-hover); }
.nav-link.active { color: var(--wjs-color-text-main); font-weight: 600; }
.nav-link.disabled { color: var(--wjs-color-text-muted); pointer-events: none; }
.nav-tabs { border-bottom: var(--wjs-border-width) solid var(--wjs-border-subtle); }
.nav-tabs .nav-link { margin-bottom: -1px; border: var(--wjs-border-width) solid transparent; border-top-left-radius: var(--wjs-radius); border-top-right-radius: var(--wjs-radius); }
.nav-tabs .nav-link:hover { border-color: var(--wjs-border-subtle) var(--wjs-border-subtle) transparent; }
.nav-tabs .nav-link.active { color: var(--wjs-color-text-main); background-color: var(--wjs-bg-canvas); border-color: var(--wjs-border-subtle) var(--wjs-border-subtle) var(--wjs-bg-canvas); }
.nav-pills .nav-link { border-radius: var(--wjs-radius); }
.nav-pills .nav-link.active { color: var(--wjs-color-on-primary, #fff); background-color: var(--wjs-color-primary); }
.navbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; padding: 0.75rem 1rem; }
.navbar-brand { padding-top: 0.25rem; padding-bottom: 0.25rem; margin-inline-end: 1rem; font-size: 1.25rem; font-weight: 700; text-decoration: none; color: inherit; }
.navbar-nav { display: flex; flex-direction: column; padding-inline-start: 0; margin-bottom: 0; list-style: none; }

/* PROGRESS */
.progress { display: flex; height: 1rem; overflow: hidden; font-size: 0.75rem; background-color: var(--wjs-bg-muted); border-radius: var(--wjs-radius); }
.progress-bar { display: flex; flex-direction: column; justify-content: center; color: var(--wjs-color-on-primary, #fff); text-align: center; white-space: nowrap; background-color: var(--wjs-color-primary); transition: width 0.4s ease; }
.progress-bar-striped { background-image: linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent); background-size: 1rem 1rem; }

/* SPINNER */
@keyframes wjs-spin { to { transform: rotate(360deg); } }
.spinner-border { display: inline-block; width: 2rem; height: 2rem; vertical-align: -0.125em; border: 0.25em solid currentColor; border-right-color: transparent; border-radius: 50%; animation: wjs-spin 0.75s linear infinite; color: var(--wjs-color-primary); }
.spinner-border-sm { width: 1rem; height: 1rem; border-width: 0.2em; }

/* ACCORDION (CSS-only, built on <details>/<summary>) */
.accordion { border: var(--wjs-border-width) solid var(--wjs-border-subtle); border-radius: var(--wjs-radius); overflow: hidden; }
.accordion-item { border-bottom: var(--wjs-border-width) solid var(--wjs-border-subtle); }
.accordion-item:last-child { border-bottom: 0; }
.accordion-item > summary, .accordion-header { padding: 0.9rem 1.1rem; font-weight: 600; cursor: pointer; background-color: var(--wjs-bg-surface); list-style: none; }
.accordion-item > summary::-webkit-details-marker { display: none; }
.accordion-item > summary::after { content: "+"; float: inline-end; }
.accordion-item[open] > summary::after { content: "\2212"; }
.accordion-body { padding: 1rem 1.1rem; background-color: var(--wjs-bg-canvas); }

/* CLOSE BUTTON */
.btn-close, .close {
  box-sizing: content-box; width: 1em; height: 1em; padding: 0.25em; color: inherit; background: transparent;
  border: 0; border-radius: var(--wjs-radius-sm); opacity: 0.6; cursor: pointer; font-size: 1.25rem; line-height: 1;
}
.btn-close::before, .close::before { content: "\00D7"; }
.btn-close:hover, .close:hover { opacity: 1; }

/* MODAL (structure + .show toggling expected from theme/plugin JS) */
.modal-backdrop { position: fixed; inset: 0; z-index: 1050; background-color: rgba(0, 0, 0, 0.5); }
.modal { position: fixed; inset: 0; z-index: 1055; display: none; overflow-y: auto; }
.modal.show { display: block; }
.modal-dialog { position: relative; width: auto; max-width: 500px; margin: 1.75rem auto; }
.modal-content { display: flex; flex-direction: column; background-color: var(--wjs-bg-surface); border-radius: var(--wjs-radius-lg); box-shadow: var(--wjs-shadow-lg); }
.modal-header { display: flex; align-items: center; justify-content: space-between; padding: 1rem 1.25rem; border-bottom: var(--wjs-border-width) solid var(--wjs-border-subtle); }
.modal-title { margin: 0; font-size: 1.25rem; font-weight: 700; }
.modal-body { position: relative; flex: 1 1 auto; padding: 1.25rem; }
.modal-footer { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 0.5rem; padding: 1rem 1.25rem; border-top: var(--wjs-border-width) solid var(--wjs-border-subtle); }

/* DROPDOWN (structure + .show toggling expected from theme/plugin JS) */
.dropdown { position: relative; }
.dropdown-menu { position: absolute; z-index: 1000; display: none; min-width: 10rem; padding: 0.5rem 0; margin-top: 0.125rem; background-color: var(--wjs-bg-surface); border: var(--wjs-border-width) solid var(--wjs-border-subtle); border-radius: var(--wjs-radius); box-shadow: var(--wjs-shadow); }
.dropdown-menu.show { display: block; }
.dropdown-item { display: block; width: 100%; padding: 0.4rem 1rem; clear: both; color: var(--wjs-color-text-main); text-align: inherit; text-decoration: none; white-space: nowrap; background: transparent; border: 0; cursor: pointer; }
.dropdown-item:hover { background-color: var(--wjs-bg-muted); }
.dropdown-divider { height: 0; margin: 0.5rem 0; border-top: var(--wjs-border-width) solid var(--wjs-border-subtle); }
.dropdown-header { display: block; padding: 0.5rem 1rem; font-size: 0.875rem; color: var(--wjs-color-text-muted); }

/* ================================================================= GRID =====
 * LOGICAL PROPERTIES, from here down through the utility layer. `padding-inline` follows the
 * document's writing direction; `padding-left` does not. Under dir="rtl" the physical form is
 * symmetric here (both sides are 1rem) so it happens to look right, but the row gutters below and
 * every `.ms-*`/`.ps-*`/`.border-start`/`.float-start` utility are NOT symmetric — those are named
 * start/end and were implemented as left/right, which is the bug: a utility called `.ms-3` means
 * "margin at the start of the line" and in an RTL document that is the RIGHT side. */
.container, .container-fluid,
.container-sm, .container-md, .container-lg, .container-xl {
  width: 100%; padding-inline: 1rem; margin-inline: auto;
}
.container { max-width: var(--wjs-container-max); }
@media (min-width: 576px)  { .container, .container-sm { max-width: 540px; } }
@media (min-width: 768px)  { .container, .container-sm, .container-md { max-width: 720px; } }
@media (min-width: 992px)  { .container, .container-sm, .container-md, .container-lg { max-width: 960px; } }
@media (min-width: 1200px) { .container, .container-sm, .container-md, .container-lg, .container-xl { max-width: var(--wjs-container-max); } }

.row { --_gx: 1.5rem; --_gy: 0; display: flex; flex-wrap: wrap; margin-top: calc(-1 * var(--_gy)); margin-inline: calc(-0.5 * var(--_gx)); }
.row > * { flex-shrink: 0; width: 100%; max-width: 100%; padding-inline: calc(var(--_gx) * 0.5); margin-top: var(--_gy); }
.no-gutters { --_gx: 0; }
.g-0 { --_gx: 0; --_gy: 0; } .g-1 { --_gx: 0.25rem; --_gy: 0.25rem; } .g-2 { --_gx: 0.5rem; --_gy: 0.5rem; }
.g-3 { --_gx: 1rem; --_gy: 1rem; } .g-4 { --_gx: 1.5rem; --_gy: 1.5rem; } .g-5 { --_gx: 3rem; --_gy: 3rem; }

.col { flex: 1 0 0%; }
.col-auto { flex: 0 0 auto; width: auto; }
.col-1 { flex: 0 0 auto; width: 8.33333%; }   .col-2 { flex: 0 0 auto; width: 16.66667%; }
.col-3 { flex: 0 0 auto; width: 25%; }          .col-4 { flex: 0 0 auto; width: 33.33333%; }
.col-5 { flex: 0 0 auto; width: 41.66667%; }    .col-6 { flex: 0 0 auto; width: 50%; }
.col-7 { flex: 0 0 auto; width: 58.33333%; }    .col-8 { flex: 0 0 auto; width: 66.66667%; }
.col-9 { flex: 0 0 auto; width: 75%; }          .col-10 { flex: 0 0 auto; width: 83.33333%; }
.col-11 { flex: 0 0 auto; width: 91.66667%; }   .col-12 { flex: 0 0 auto; width: 100%; }

.row-cols-1 > * { width: 100%; } .row-cols-2 > * { width: 50%; } .row-cols-3 > * { width: 33.33333%; }
.row-cols-4 > * { width: 25%; } .row-cols-5 > * { width: 20%; } .row-cols-6 > * { width: 16.66667%; }

@media (min-width: 576px) {
  .col-sm { flex: 1 0 0%; } .col-sm-auto { flex: 0 0 auto; width: auto; }
  .col-sm-1 { width: 8.33333%; } .col-sm-2 { width: 16.66667%; } .col-sm-3 { width: 25%; } .col-sm-4 { width: 33.33333%; }
  .col-sm-5 { width: 41.66667%; } .col-sm-6 { width: 50%; } .col-sm-7 { width: 58.33333%; } .col-sm-8 { width: 66.66667%; }
  .col-sm-9 { width: 75%; } .col-sm-10 { width: 83.33333%; } .col-sm-11 { width: 91.66667%; } .col-sm-12 { width: 100%; }
}
@media (min-width: 768px) {
  .col-md { flex: 1 0 0%; } .col-md-auto { flex: 0 0 auto; width: auto; }
  .col-md-1 { width: 8.33333%; } .col-md-2 { width: 16.66667%; } .col-md-3 { width: 25%; } .col-md-4 { width: 33.33333%; }
  .col-md-5 { width: 41.66667%; } .col-md-6 { width: 50%; } .col-md-7 { width: 58.33333%; } .col-md-8 { width: 66.66667%; }
  .col-md-9 { width: 75%; } .col-md-10 { width: 83.33333%; } .col-md-11 { width: 91.66667%; } .col-md-12 { width: 100%; }
}
@media (min-width: 992px) {
  .col-lg { flex: 1 0 0%; } .col-lg-auto { flex: 0 0 auto; width: auto; }
  .col-lg-1 { width: 8.33333%; } .col-lg-2 { width: 16.66667%; } .col-lg-3 { width: 25%; } .col-lg-4 { width: 33.33333%; }
  .col-lg-5 { width: 41.66667%; } .col-lg-6 { width: 50%; } .col-lg-7 { width: 58.33333%; } .col-lg-8 { width: 66.66667%; }
  .col-lg-9 { width: 75%; } .col-lg-10 { width: 83.33333%; } .col-lg-11 { width: 91.66667%; } .col-lg-12 { width: 100%; }
}
@media (min-width: 1200px) {
  .col-xl { flex: 1 0 0%; } .col-xl-auto { flex: 0 0 auto; width: auto; }
  .col-xl-3 { width: 25%; } .col-xl-4 { width: 33.33333%; } .col-xl-6 { width: 50%; } .col-xl-8 { width: 66.66667%; } .col-xl-12 { width: 100%; }
}

/* Aspect ratio box */
.ratio { position: relative; width: 100%; }
.ratio::before { display: block; padding-top: var(--_ratio, 56.25%); content: ""; }
.ratio > * { position: absolute; inset: 0; width: 100%; height: 100%; }
.ratio-1x1 { --_ratio: 100%; } .ratio-4x3 { --_ratio: 75%; } .ratio-16x9 { --_ratio: 56.25%; } .ratio-21x9 { --_ratio: 42.857%; }

/* ============================================================ UTILITIES ===== */

/* Spacing — scale 0,1,2,3,4,5 = 0, .25, .5, 1, 1.5, 3 × --wjs-spacer */
.m-0{margin:0!important}.m-1{margin:calc(.25*var(--wjs-spacer))!important}.m-2{margin:calc(.5*var(--wjs-spacer))!important}.m-3{margin:var(--wjs-spacer)!important}.m-4{margin:calc(1.5*var(--wjs-spacer))!important}.m-5{margin:calc(3*var(--wjs-spacer))!important}.m-auto{margin:auto!important}
.mt-0{margin-top:0!important}.mt-1{margin-top:calc(.25*var(--wjs-spacer))!important}.mt-2{margin-top:calc(.5*var(--wjs-spacer))!important}.mt-3{margin-top:var(--wjs-spacer)!important}.mt-4{margin-top:calc(1.5*var(--wjs-spacer))!important}.mt-5{margin-top:calc(3*var(--wjs-spacer))!important}.mt-auto{margin-top:auto!important}
.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:calc(.25*var(--wjs-spacer))!important}.mb-2{margin-bottom:calc(.5*var(--wjs-spacer))!important}.mb-3{margin-bottom:var(--wjs-spacer)!important}.mb-4{margin-bottom:calc(1.5*var(--wjs-spacer))!important}.mb-5{margin-bottom:calc(3*var(--wjs-spacer))!important}.mb-auto{margin-bottom:auto!important}
.ms-0{margin-inline-start:0!important}.ms-1{margin-inline-start:calc(.25*var(--wjs-spacer))!important}.ms-2{margin-inline-start:calc(.5*var(--wjs-spacer))!important}.ms-3{margin-inline-start:var(--wjs-spacer)!important}.ms-4{margin-inline-start:calc(1.5*var(--wjs-spacer))!important}.ms-5{margin-inline-start:calc(3*var(--wjs-spacer))!important}.ms-auto{margin-inline-start:auto!important}
.me-0{margin-inline-end:0!important}.me-1{margin-inline-end:calc(.25*var(--wjs-spacer))!important}.me-2{margin-inline-end:calc(.5*var(--wjs-spacer))!important}.me-3{margin-inline-end:var(--wjs-spacer)!important}.me-4{margin-inline-end:calc(1.5*var(--wjs-spacer))!important}.me-5{margin-inline-end:calc(3*var(--wjs-spacer))!important}.me-auto{margin-inline-end:auto!important}
.mx-0{margin-inline:0!important}.mx-1{margin-inline:calc(.25*var(--wjs-spacer))!important}.mx-2{margin-inline:calc(.5*var(--wjs-spacer))!important}.mx-3{margin-inline:var(--wjs-spacer)!important}.mx-4{margin-inline:calc(1.5*var(--wjs-spacer))!important}.mx-5{margin-inline:calc(3*var(--wjs-spacer))!important}.mx-auto{margin-inline:auto!important}
.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:calc(.25*var(--wjs-spacer))!important;margin-bottom:calc(.25*var(--wjs-spacer))!important}.my-2{margin-top:calc(.5*var(--wjs-spacer))!important;margin-bottom:calc(.5*var(--wjs-spacer))!important}.my-3{margin-top:var(--wjs-spacer)!important;margin-bottom:var(--wjs-spacer)!important}.my-4{margin-top:calc(1.5*var(--wjs-spacer))!important;margin-bottom:calc(1.5*var(--wjs-spacer))!important}.my-5{margin-top:calc(3*var(--wjs-spacer))!important;margin-bottom:calc(3*var(--wjs-spacer))!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}
.p-0{padding:0!important}.p-1{padding:calc(.25*var(--wjs-spacer))!important}.p-2{padding:calc(.5*var(--wjs-spacer))!important}.p-3{padding:var(--wjs-spacer)!important}.p-4{padding:calc(1.5*var(--wjs-spacer))!important}.p-5{padding:calc(3*var(--wjs-spacer))!important}
.pt-0{padding-top:0!important}.pt-1{padding-top:calc(.25*var(--wjs-spacer))!important}.pt-2{padding-top:calc(.5*var(--wjs-spacer))!important}.pt-3{padding-top:var(--wjs-spacer)!important}.pt-4{padding-top:calc(1.5*var(--wjs-spacer))!important}.pt-5{padding-top:calc(3*var(--wjs-spacer))!important}
.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:calc(.25*var(--wjs-spacer))!important}.pb-2{padding-bottom:calc(.5*var(--wjs-spacer))!important}.pb-3{padding-bottom:var(--wjs-spacer)!important}.pb-4{padding-bottom:calc(1.5*var(--wjs-spacer))!important}.pb-5{padding-bottom:calc(3*var(--wjs-spacer))!important}
.ps-0{padding-inline-start:0!important}.ps-1{padding-inline-start:calc(.25*var(--wjs-spacer))!important}.ps-2{padding-inline-start:calc(.5*var(--wjs-spacer))!important}.ps-3{padding-inline-start:var(--wjs-spacer)!important}.ps-4{padding-inline-start:calc(1.5*var(--wjs-spacer))!important}.ps-5{padding-inline-start:calc(3*var(--wjs-spacer))!important}
.pe-0{padding-inline-end:0!important}.pe-1{padding-inline-end:calc(.25*var(--wjs-spacer))!important}.pe-2{padding-inline-end:calc(.5*var(--wjs-spacer))!important}.pe-3{padding-inline-end:var(--wjs-spacer)!important}.pe-4{padding-inline-end:calc(1.5*var(--wjs-spacer))!important}.pe-5{padding-inline-end:calc(3*var(--wjs-spacer))!important}
.px-0{padding-inline:0!important}.px-1{padding-inline:calc(.25*var(--wjs-spacer))!important}.px-2{padding-inline:calc(.5*var(--wjs-spacer))!important}.px-3{padding-inline:var(--wjs-spacer)!important}.px-4{padding-inline:calc(1.5*var(--wjs-spacer))!important}.px-5{padding-inline:calc(3*var(--wjs-spacer))!important}
.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:calc(.25*var(--wjs-spacer))!important;padding-bottom:calc(.25*var(--wjs-spacer))!important}.py-2{padding-top:calc(.5*var(--wjs-spacer))!important;padding-bottom:calc(.5*var(--wjs-spacer))!important}.py-3{padding-top:var(--wjs-spacer)!important;padding-bottom:var(--wjs-spacer)!important}.py-4{padding-top:calc(1.5*var(--wjs-spacer))!important;padding-bottom:calc(1.5*var(--wjs-spacer))!important}.py-5{padding-top:calc(3*var(--wjs-spacer))!important;padding-bottom:calc(3*var(--wjs-spacer))!important}
.gap-0{gap:0!important}.gap-1{gap:calc(.25*var(--wjs-spacer))!important}.gap-2{gap:calc(.5*var(--wjs-spacer))!important}.gap-3{gap:var(--wjs-spacer)!important}.gap-4{gap:calc(1.5*var(--wjs-spacer))!important}.gap-5{gap:calc(3*var(--wjs-spacer))!important}

/* Display */
.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-grid{display:grid!important}.d-table{display:table!important}
@media (min-width:768px){.d-md-none{display:none!important}.d-md-block{display:block!important}.d-md-flex{display:flex!important}.d-md-inline-block{display:inline-block!important}}
@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-block{display:block!important}.d-lg-flex{display:flex!important}}

/* Flex */
.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}
.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-fill{flex:1 1 auto!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}
.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}
.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}
.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-stretch{align-self:stretch!important}
@media (min-width:768px){.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}}

/* Text */
.text-start{text-align:start!important}.text-center{text-align:center!important}.text-end{text-align:end!important}
.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}
.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:800!important}
.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}
.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.6!important}.lh-lg{line-height:2!important}
.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-wrap{white-space:normal!important}
.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}
.font-monospace{font-family:var(--wjs-font-family-mono)!important}
.fs-1{font-size:var(--wjs-h1)!important}.fs-2{font-size:var(--wjs-h2)!important}.fs-3{font-size:var(--wjs-h3)!important}.fs-4{font-size:var(--wjs-h4)!important}.fs-5{font-size:var(--wjs-h5)!important}.fs-6{font-size:var(--wjs-h6)!important}

/* Text + background colors */
.text-primary{color:var(--wjs-color-primary)!important}.text-secondary{color:var(--wjs-color-secondary)!important}.text-success{color:var(--wjs-color-success)!important}.text-danger{color:var(--wjs-color-danger)!important}.text-warning{color:var(--wjs-color-warning)!important}.text-info{color:var(--wjs-color-info)!important}.text-light{color:var(--wjs-color-light)!important}.text-dark{color:var(--wjs-color-dark)!important}.text-body{color:var(--wjs-color-text-main)!important}.text-muted{color:var(--wjs-color-text-muted)!important}.text-white{color:#fff!important}.text-black{color:#000!important}.text-reset{color:inherit!important}
.bg-primary{background-color:var(--wjs-color-primary)!important}.bg-secondary{background-color:var(--wjs-color-secondary)!important}.bg-success{background-color:var(--wjs-color-success)!important}.bg-danger{background-color:var(--wjs-color-danger)!important}.bg-warning{background-color:var(--wjs-color-warning)!important}.bg-info{background-color:var(--wjs-color-info)!important}.bg-light{background-color:var(--wjs-color-light)!important}.bg-dark{background-color:var(--wjs-color-dark)!important}.bg-body{background-color:var(--wjs-bg-canvas)!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.bg-muted{background-color:var(--wjs-bg-muted)!important}

/* Borders */
.border{border:var(--wjs-border-width) solid var(--wjs-border-subtle)!important}.border-0{border:0!important}
.border-top{border-top:var(--wjs-border-width) solid var(--wjs-border-subtle)!important}.border-bottom{border-bottom:var(--wjs-border-width) solid var(--wjs-border-subtle)!important}.border-start{border-inline-start:var(--wjs-border-width) solid var(--wjs-border-subtle)!important}.border-end{border-inline-end:var(--wjs-border-width) solid var(--wjs-border-subtle)!important}
.border-primary{border-color:var(--wjs-color-primary)!important}.border-success{border-color:var(--wjs-color-success)!important}.border-danger{border-color:var(--wjs-color-danger)!important}.border-warning{border-color:var(--wjs-color-warning)!important}.border-info{border-color:var(--wjs-color-info)!important}
.rounded{border-radius:var(--wjs-radius)!important}.rounded-0{border-radius:0!important}.rounded-sm{border-radius:var(--wjs-radius-sm)!important}.rounded-lg{border-radius:var(--wjs-radius-lg)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--wjs-radius-pill)!important}
.rounded-top{border-top-left-radius:var(--wjs-radius)!important;border-top-right-radius:var(--wjs-radius)!important}.rounded-bottom{border-bottom-left-radius:var(--wjs-radius)!important;border-bottom-right-radius:var(--wjs-radius)!important}

/* Sizing */
.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}
.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}
.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}

/* Position */
.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}
.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.start-0{inset-inline-start:0!important}.start-50{inset-inline-start:50%!important}.end-0{inset-inline-end:0!important}
.translate-middle{transform:translate(-50%,-50%)!important}

/* Misc */
.shadow-none{box-shadow:none!important}.shadow-sm{box-shadow:var(--wjs-shadow-sm)!important}.shadow{box-shadow:var(--wjs-shadow)!important}.shadow-lg{box-shadow:var(--wjs-shadow-lg)!important}
.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}
.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}
.float-start{float:left!important;float:inline-start!important}.float-end{float:right!important;float:inline-end!important}.float-none{float:none!important}
.user-select-none{user-select:none!important}.user-select-all{user-select:all!important}
.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}
.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}
.img-fluid{max-width:100%!important;height:auto!important}.img-thumbnail{padding:.25rem;background-color:var(--wjs-bg-surface);border:var(--wjs-border-width) solid var(--wjs-border-subtle);border-radius:var(--wjs-radius)}
.rounded-img,.img-rounded{border-radius:var(--wjs-radius-lg)!important}
.clearfix::after{display:block;clear:both;content:""}
.visually-hidden{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.invisible{visibility:hidden!important}.visible{visibility:visible!important}

/* Optional content wrapper: extra rhythm for long-form article/post bodies. The bare-element
 * rules above already style raw content; add class="wjs-content" to a post body for tuned spacing. */
.wjs-content > :first-child { margin-top: 0; }
.wjs-content h2, .wjs-content h3, .wjs-content h4 { margin-top: 1.6em; }
.wjs-content img, .wjs-content figure, .wjs-content video, .wjs-content iframe { border-radius: var(--wjs-radius); }
.wjs-content > p, .wjs-content > ul, .wjs-content > ol, .wjs-content > blockquote, .wjs-content > pre, .wjs-content > table { margin-bottom: 1.25rem; }

/* ============================================================= WIDGETS ====== */
/* Output of the widget/sidebar system (admin widget editor → renderSidebar). Text uses `inherit` so a
 * widget adapts to its container (dark footer or light sidebar); accents/borders use tokens. */
.widget-area { display: flex; flex-direction: column; gap: 1.5rem; }
.widget { margin: 0; }
.widget-title { margin: 0 0 0.75rem; font-size: 1.05rem; font-weight: 700; color: inherit; }
.widget ul, .widget ol { list-style: none; margin: 0; padding: 0; }
.widget li { padding: 0.35rem 0; border-bottom: var(--wjs-border-width) solid color-mix(in srgb, currentColor 18%, transparent); }
.widget li:last-child { border-bottom: 0; }
.widget a { color: inherit; text-decoration: none; transition: color var(--wjs-transition); }
.widget a:hover { color: var(--wjs-color-primary); }
.widget .textwidget { color: inherit; }
.widget .search-form { display: flex; gap: 0.5rem; }
.widget .search-form input[type="search"], .widget .search-form input[type="text"] {
  flex: 1 1 auto; padding: 0.4rem 0.6rem; color: var(--wjs-color-text-main);
  background: var(--wjs-bg-canvas); border: var(--wjs-border-width) solid var(--wjs-border-subtle); border-radius: var(--wjs-radius);
}
@supports not (color: color-mix(in srgb, red, blue)) { .widget li { border-bottom-color: var(--wjs-border-subtle); } }

/* ================================================ MOBILE OVERFLOW GUARDS ====== */
/* <768px only — desktop rendering is untouched. Content HTML is author-supplied, so wide
 * tables and long unbroken strings (URLs, emails) must degrade to container-level scroll /
 * word wrapping instead of forcing body-level horizontal scroll on small viewports. */
@media (max-width: 767.98px) {
  /* Long page lists otherwise push past the viewport (.nav/.breadcrumb already wrap). */
  .pagination { flex-wrap: wrap; }

  /* Mobile type scale for visual-editor headings. Their inline style reads the framework-owned
   * --wjs-hN-size ALIASES (no theme defines them — see the alias block in :root), so capping the
   * alias here shrinks oversized desktop headings on phones while min() respects any theme whose
   * heading token is already smaller than the cap. Inline styles pick up the new value because
   * custom properties resolve at use time. */
  :root {
    --wjs-h1-size: min(var(--wjs-h1), 2.25rem);
    --wjs-h2-size: min(var(--wjs-h2), 1.75rem);
    --wjs-h3-size: min(var(--wjs-h3), 1.5rem);
    --wjs-h4-size: min(var(--wjs-h4), 1.25rem);
    --wjs-h5-size: min(var(--wjs-h5), 1.125rem);
    --wjs-h6-size: min(var(--wjs-h6), 1rem);
  }
  /* Classic-content headings get the same cap (plain specificity — a theme that deliberately
   * forces its own mobile sizes still wins). */
  .wjs-content h1 { font-size: min(var(--wjs-h1), 2.25rem); }
  .wjs-content h2 { font-size: min(var(--wjs-h2), 1.75rem); }
  .wjs-content h3 { font-size: min(var(--wjs-h3), 1.5rem); }
}

/* ================================================= CONTENT CONTAINMENT ====== */
/* At EVERY width (not just phones): a wide table, a <pre> or an unbreakable string (long URL,
 * token, word) must never widen the page — a 1600px word overflows a tablet or desktop container
 * just as it overflows a phone. These only bite when content actually exceeds its container, so
 * normal desktop rendering is unaffected. Covers BOTH content paths: classic .wjs-content and the
 * visual editor's .puck-content / .wp-block-*. (Was mobile-only, which left 768px+ unprotected.) */
.wjs-content table, .puck-content table { display: block; max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.wjs-content pre, .puck-content pre { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.wjs-content, .widget-area { overflow-wrap: break-word; }
.puck-content, .wjs-block-text, .wp-block-text, .wjs-block-heading, .wp-block-heading, .wjs-block-card, .wp-block-card { overflow-wrap: break-word; word-break: break-word; }
/* Media inside visual-editor content can never exceed its container. */
.puck-content img, .puck-content video, .puck-content iframe { max-width: 100%; height: auto; }

/* ================================================= RESPONSIVE VISIBILITY ====== */
/* Per-block "hide on device" from the visual editor (VisibilityField). The wrapper is
 * display:contents, so hiding via display:none removes the block without adding a layout box.
 * Breakpoints match the editor device previews: mobile <768, tablet 768-1023, desktop >=1024. */
@media (max-width: 767.98px) { .wjs-hide-mobile { display: none !important; } }
@media (min-width: 768px) and (max-width: 1023.98px) { .wjs-hide-tablet { display: none !important; } }
@media (min-width: 1024px) { .wjs-hide-desktop { display: none !important; } }

/* ================================================= ENTRANCE ANIMATIONS ====== */
/* Per-block scroll-reveal from the visual editor (AnimationField). The SSR HTML ships VISIBLE;
 * live JS sets data-wjs-anim="armed" right before observing and "in" on intersection, so no-JS
 * visitors and crawlers never see hidden content. Only opacity/transform animate (zero CLS).
 * Everything is wrapped in prefers-reduced-motion: no-preference — reduced-motion users get the
 * content instantly with no animation (the JS side skips arming too). */
@media screen and (prefers-reduced-motion: no-preference) {
  .wjs-anim[data-wjs-anim="armed"] { opacity: 0; }
  .wjs-anim[data-wjs-anim="in"] {
    animation-duration: var(--wjs-anim-dur, 600ms);
    animation-delay: var(--wjs-anim-delay, 0ms);
    animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
    animation-fill-mode: both;
  }
  .wjs-anim-fade[data-wjs-anim="in"] { animation-name: wjs-anim-fade; }
  .wjs-anim-fade-up[data-wjs-anim="in"] { animation-name: wjs-anim-fade-up; }
  .wjs-anim-fade-down[data-wjs-anim="in"] { animation-name: wjs-anim-fade-down; }
  .wjs-anim-fade-left[data-wjs-anim="in"] { animation-name: wjs-anim-fade-left; }
  .wjs-anim-fade-right[data-wjs-anim="in"] { animation-name: wjs-anim-fade-right; }
  .wjs-anim-zoom[data-wjs-anim="in"] { animation-name: wjs-anim-zoom; }
  .wjs-anim-zoom-out[data-wjs-anim="in"] { animation-name: wjs-anim-zoom-out; }
  .wjs-anim-blur[data-wjs-anim="in"] { animation-name: wjs-anim-blur; }
  .wjs-anim-rise[data-wjs-anim="in"] { animation-name: wjs-anim-rise; }
  .wjs-anim-flip[data-wjs-anim="in"] { animation-name: wjs-anim-flip; }
  .wjs-anim-reveal[data-wjs-anim="in"] { animation-name: wjs-anim-reveal; }
  .wjs-anim-swing[data-wjs-anim="in"] { animation-name: wjs-anim-swing; }
  /* `flip` gira sobre su eje: sin perspectiva el navegador lo aplana y el giro se
   * ve como un simple estrechamiento. Se declara en el elemento que anima porque
   * el wrapper de animación es su propia capa (ver blockShell: entrada y hover
   * viven en capas separadas a propósito). */
  .wjs-anim-flip { perspective: 1000px; }
  /* `reveal` descubre el bloque con un clip: el contenido nunca cambia de sitio
   * (cero CLS) y no necesita overflow:hidden en el padre. */
  .wjs-anim-reveal { will-change: clip-path; }
}
@keyframes wjs-anim-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes wjs-anim-fade-up { from { opacity: 0; transform: translateY(28px); } to { opacity: 1; transform: none; } }
@keyframes wjs-anim-fade-left { from { opacity: 0; transform: translateX(-32px); } to { opacity: 1; transform: none; } }
@keyframes wjs-anim-fade-right { from { opacity: 0; transform: translateX(32px); } to { opacity: 1; transform: none; } }
@keyframes wjs-anim-zoom { from { opacity: 0; transform: scale(0.92); } to { opacity: 1; transform: none; } }
/* Los 7 tipos que el panel del editor ofrecía SIN implementación: elegirlos no
 * hacía nada (controles muertos). Mismo contrato que los de arriba: solo
 * opacity/transform/filter/clip-path (cero reflow, cero CLS) y `to` siempre
 * neutro para que el estado final sea idéntico al del bloque sin animación. */
@keyframes wjs-anim-fade-down { from { opacity: 0; transform: translateY(-28px); } to { opacity: 1; transform: none; } }
@keyframes wjs-anim-zoom-out { from { opacity: 0; transform: scale(1.08); } to { opacity: 1; transform: none; } }
@keyframes wjs-anim-blur { from { opacity: 0; filter: blur(12px); } to { opacity: 1; filter: blur(0); } }
@keyframes wjs-anim-rise { from { opacity: 0; transform: translateY(64px) scale(0.98); } to { opacity: 1; transform: none; } }
@keyframes wjs-anim-flip { from { opacity: 0; transform: rotateX(-70deg); } to { opacity: 1; transform: none; } }
@keyframes wjs-anim-reveal {
  from { opacity: 1; clip-path: inset(0 100% 0 0); }
  to { opacity: 1; clip-path: inset(0 0 0 0); }
}
@keyframes wjs-anim-swing {
  from { opacity: 0; transform: rotate(-6deg) translateY(18px); }
  60% { opacity: 1; transform: rotate(2deg) translateY(0); }
  to { opacity: 1; transform: none; }
}

/* ============================================== VISUAL-EDITOR BLOCK CONTRACT ==
 * Every Puck block's look, expressed once, here, as `var(--wjs-<block>-<prop>, <base>)`.
 *
 * WHY THIS EXISTS. Blocks used to carry their looks as INLINE styles. An inline style beats any
 * stylesheet, so the only way a theme could restyle a block was `!important` on every declaration
 * (the bundled themes carried ~100 each). Moving the values here — behind per-block custom
 * properties — turns a block into something a theme can actually skin, with no `!important`
 * anywhere. `frontend/src/components/blocks/blockVars.ts` is the emitting half of this contract.
 *
 * THE CASCADE, in the order people expect:
 *   1. What the AUTHOR set on this one block  → inline `--wjs-hero-title-size` on that element
 *   2. What the THEME wants                   → `:root { --wjs-hero-title-size: … }` in style.css
 *   3. The block's own base                   → the second argument of `var()` below
 *
 * `blockVars` OMITS empty values rather than emitting `""`, so an author who chose nothing leaves
 * rule 2 in charge. That is the whole trick: an always-present inline variable would pin the block
 * to its default forever and lock the theme out again.
 *
 * A BASE IS NEVER A RAW VALUE WHEN A GLOBAL TOKEN EXISTS. Bases below read `--wjs-bg-surface`,
 * `--wjs-color-primary`, `--wjs-radius-lg`, … so a theme that only declares the ~20 global palette
 * tokens already restyles all 28 blocks coherently, and only reaches for a `--wjs-<block>-*`
 * override when it wants that ONE block to differ.
 *
 * NAMING. Block token = `--wjs-` + the blockVars prefix + `-` + the key. The prefixes are:
 *   heading text image card divider button spacer section grid flex columns accordion tabs video
 *   audio pricing testimonial cta posts catposts search hero quote table icon-list social stats
 * Extra tokens appear here that no field emits (e.g. `--wjs-card-desc-color`) — those are
 * theme-only seams: nothing in the editor sets them, a theme may.
 * ========================================================================================== */

/* ---------------------------------------------------------------- SHARED SCALE - */
/* The block contract needs a compact spacing/elevation ramp and a couple of Material-style
 * pairs that the framework did not name yet. All are aliases of tokens declared above, so a
 * theme that overrides only the canonical token still flows through; a theme that wants the
 * ramp itself can redeclare these. */
:root {
  /* Compact spacing scale used by block padding/gaps */
  --wjs-xs: 4px;
  --wjs-sm: 8px;
  --wjs-md: 16px;
  --wjs-lg: 24px;
  --wjs-xl: 48px;
  --wjs-2xl: 80px;

  /* Small type sizes (eyebrows, captions, table cells) */
  --wjs-label: 11px;
  --wjs-small: 13px;

  /* Surface ramp beyond canvas/surface/muted, for blocks that stack two levels of elevation */
  --wjs-bg-surface-raised: var(--wjs-bg-surface);
  --wjs-surface-highest: var(--wjs-bg-muted);
  --wjs-surface-lowest: var(--wjs-bg-canvas);

  /* Outlines: `--wjs-outline` is a VISIBLE line, `--wjs-border-subtle` a hairline */
  --wjs-outline: var(--wjs-border-subtle);
  --wjs-outline-variant: var(--wjs-border-subtle);
  /* Top inner highlight that makes a surface read as raised on dark themes; `none` on light */
  --wjs-inset-highlight: none;

  /* The accent pair: a solid fill + the text colour guaranteed to be legible on it */
  --wjs-primary-fixed: var(--wjs-color-primary);
  --wjs-color-on-accent: var(--wjs-color-on-primary);
  --wjs-color-on-accent-strong: var(--wjs-color-on-primary);

  /* Chrome surfaces the public layout reads. The header renders
   * bg-[var(--wjs-bg-surface-glass, white)]; with nothing declaring it, every DARK theme painted a
   * literal white bar with its own light text on it. Base equals the old fallback exactly. */
  --wjs-bg-surface-glass: var(--wjs-bg-surface);

  /* Elevation aliases (Material-style step numbers) */
  --wjs-shadow-2: var(--wjs-shadow);
  --wjs-shadow-3: var(--wjs-shadow-lg);

  /* Per-level heading tracking — display type usually wants negative tracking, body does not */
  --wjs-h1-tracking: normal;
  --wjs-h2-tracking: normal;
  --wjs-h3-tracking: normal;
}

/* ------------------------------------------------------------------- HEADING - */
.wjs-block-heading, .wp-block-heading {
  margin: 0 0 var(--wjs-heading-mb, 0.5em);
  font-family: var(--wjs-heading-family, var(--wjs-font-family-heading));
  line-height: var(--wjs-heading-leading, var(--wjs-heading-line-height));
  text-transform: var(--wjs-heading-transform, none);
  border-bottom: var(--wjs-heading-border-width, 0) solid var(--wjs-heading-border-color, var(--wjs-border-subtle));
  padding: var(--wjs-heading-pad, 0);
  background: var(--wjs-heading-bg, transparent);
  color: var(--wjs-heading-color, var(--wjs-color-heading));
}
/* Per level, so an unstyled H2 keeps the theme's H2 size instead of collapsing to 1em. The
 * block's own `--wjs-heading-size` wins when the author set one; otherwise the theme's --wjs-hN. */
h1.wjs-block-heading, h1.wp-block-heading {
  color: var(--wjs-heading-color, var(--wjs-h1-color, var(--wjs-color-heading)));
  line-height: var(--wjs-heading-leading, var(--wjs-h1-leading, var(--wjs-heading-line-height)));
  font-size: var(--wjs-heading-size, var(--wjs-h1));
  font-weight: var(--wjs-heading-font-weight, var(--wjs-h1-weight));
  letter-spacing: var(--wjs-heading-tracking, var(--wjs-h1-tracking));
}
h2.wjs-block-heading, h2.wp-block-heading {
  color: var(--wjs-heading-color, var(--wjs-h2-color, var(--wjs-color-heading)));
  line-height: var(--wjs-heading-leading, var(--wjs-h2-leading, var(--wjs-heading-line-height)));
  font-size: var(--wjs-heading-size, var(--wjs-h2));
  font-weight: var(--wjs-heading-font-weight, var(--wjs-h2-weight));
  letter-spacing: var(--wjs-heading-tracking, var(--wjs-h2-tracking));
}
h3.wjs-block-heading, h3.wp-block-heading {
  color: var(--wjs-heading-color, var(--wjs-h3-color, var(--wjs-color-heading)));
  line-height: var(--wjs-heading-leading, var(--wjs-h3-leading, var(--wjs-heading-line-height)));
  font-size: var(--wjs-heading-size, var(--wjs-h3));
  font-weight: var(--wjs-heading-font-weight, var(--wjs-h3-weight));
  letter-spacing: var(--wjs-heading-tracking, var(--wjs-h3-tracking));
}
h4.wjs-block-heading, h4.wp-block-heading { font-size: var(--wjs-heading-size, var(--wjs-h4)); font-weight: var(--wjs-heading-font-weight, var(--wjs-h4-weight)); letter-spacing: var(--wjs-heading-tracking, normal); }
h5.wjs-block-heading, h5.wp-block-heading { font-size: var(--wjs-heading-size, var(--wjs-h5)); font-weight: var(--wjs-heading-font-weight, var(--wjs-h5-weight)); letter-spacing: var(--wjs-heading-tracking, normal); }
h6.wjs-block-heading, h6.wp-block-heading { font-size: var(--wjs-heading-size, var(--wjs-h6)); font-weight: var(--wjs-heading-font-weight, var(--wjs-h6-weight)); letter-spacing: var(--wjs-heading-tracking, normal); }

/* ---------------------------------------------------------------------- TEXT - */
.wjs-block-text, .wp-block-text {
  color: var(--wjs-text-color, var(--wjs-color-text-main));
  font-size: var(--wjs-text-size, var(--wjs-font-size-base));
  line-height: var(--wjs-text-leading, var(--wjs-line-height-base));
  /* A measure caps the line length for readability; unset = fill the container */
  max-width: var(--wjs-text-measure, none);
}
/* The block owns its outer rhythm; the rich-text's first/last child must not add to it. */
.wjs-block-text > :first-child, .wp-block-text > :first-child { margin-top: 0; }
.wjs-block-text > :last-child, .wp-block-text > :last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------- IMAGE - */
.wjs-block-image, .wp-block-image {
  display: block;
  width: var(--wjs-image-width, auto);
  max-width: 100%;
  height: auto;
  border-radius: var(--wjs-image-radius, 0);
  box-shadow: var(--wjs-image-shadow, none);
  object-fit: var(--wjs-image-fit, cover);
}

/* ---------------------------------------------------------------------- CARD - */
.wjs-block-card, .wp-block-card {
  display: flex;
  flex-direction: column;
  padding: var(--wjs-card-pad, var(--wjs-xl));
  background: var(--wjs-card-bg, var(--wjs-bg-surface));
  color: var(--wjs-card-color, var(--wjs-color-text-main));
  border: var(--wjs-card-border-width, 1px) solid var(--wjs-card-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-card-radius, var(--wjs-radius-lg));
  box-shadow: var(--wjs-card-shadow, var(--wjs-inset-highlight));
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}
/* Lift on hover is opt-in: `none` by default so a card that should sit still, sits still. */
.wjs-block-card:hover, .wp-block-card:hover {
  background: var(--wjs-card-hover-bg, var(--wjs-card-bg, var(--wjs-bg-surface)));
  transform: var(--wjs-card-hover-transform, none);
  border-color: var(--wjs-card-hover-border-color, var(--wjs-card-border-color, var(--wjs-border-subtle)));
  box-shadow: var(--wjs-card-hover-shadow, var(--wjs-card-shadow, var(--wjs-inset-highlight)));
}
.wjs-block-card__icon, .wp-block-card__icon {
  display: grid;
  place-items: center;
  flex: none;
  width: var(--wjs-card-icon-size, 48px);
  height: var(--wjs-card-icon-size, 48px);
  margin-bottom: var(--wjs-md);
  border-radius: var(--wjs-card-icon-radius, var(--wjs-radius));
  background: var(--wjs-card-icon-bg, var(--wjs-surface-highest));
  color: var(--wjs-card-icon-color, var(--wjs-color-primary));
  /* Glyph scales with the tile so one field resizes both */
  font-size: var(--wjs-card-icon-glyph, calc(var(--wjs-card-icon-size, 48px) * 0.45));
}
.wjs-block-card__title, .wp-block-card__title {
  margin: 0 0 var(--wjs-sm);
  font-family: var(--wjs-font-family-heading);
  font-size: var(--wjs-card-title-size, var(--wjs-h4));
  font-weight: var(--wjs-card-title-weight, 700);
  line-height: var(--wjs-card-title-leading, 1.25);
  letter-spacing: var(--wjs-card-title-tracking, var(--wjs-h3-tracking));
  text-transform: var(--wjs-card-title-transform, none);
  color: var(--wjs-card-title-color, inherit);
}
.wjs-block-card__description, .wp-block-card__description {
  margin: 0;
  font-family: var(--wjs-card-desc-family, inherit);
  font-size: var(--wjs-card-desc-size, inherit);
  line-height: var(--wjs-card-desc-leading, inherit);
  color: var(--wjs-card-desc-color, var(--wjs-color-text-muted));
}
/* Variants set the block's OWN tokens, so an inline author choice still outranks them, and a
 * theme retunes a variant through its `--wjs-card-<variant>-*` seam rather than a new rule. */
.wjs-block-card.card-theme-dark, .wp-block-card.card-theme-dark {
  --wjs-card-bg: var(--wjs-card-dark-bg, var(--wjs-color-dark));
  --wjs-card-color: var(--wjs-card-dark-color, var(--wjs-color-on-dark));
  /* The variant must also re-point the TITLE token: themes set `--wjs-card-title-color` to their
   * ink at :root, which otherwise pierces this remap and paints ink-on-ink on the dark surface. */
  --wjs-card-title-color: var(--wjs-card-dark-title-color, var(--wjs-card-dark-color, var(--wjs-color-on-dark)));
  --wjs-card-desc-color: var(--wjs-card-dark-desc-color, color-mix(in srgb, var(--wjs-card-dark-color, var(--wjs-color-on-dark, #fff)) 72%, transparent));
  --wjs-card-border-color: var(--wjs-card-dark-border-color, transparent);
  --wjs-card-icon-bg: var(--wjs-card-dark-icon-bg, rgba(255, 255, 255, 0.1));
  --wjs-card-icon-color: var(--wjs-card-dark-icon-color, #fff);
}
.wjs-block-card.card-theme-accent, .wp-block-card.card-theme-accent {
  --wjs-card-bg: var(--wjs-card-accent-bg, var(--wjs-color-accent));
  --wjs-card-color: var(--wjs-card-accent-color, var(--wjs-color-on-accent));
  --wjs-card-title-color: var(--wjs-card-accent-title-color, var(--wjs-card-accent-color, var(--wjs-color-on-accent)));
  --wjs-card-desc-color: var(--wjs-card-accent-desc-color, color-mix(in srgb, var(--wjs-card-accent-color, var(--wjs-color-on-accent, #fff)) 80%, transparent));
  --wjs-card-border-color: var(--wjs-card-accent-border-color, transparent);
  --wjs-card-icon-bg: var(--wjs-card-accent-icon-bg, rgba(255, 255, 255, 0.18));
  --wjs-card-icon-color: var(--wjs-card-accent-icon-color, #fff);
}

/* ------------------------------------------------------------------- DIVIDER - */
.wjs-block-divider, .wp-block-divider {
  /* The vertical rhythm lives in tokens so a theme owns the page's spacing, not the block. */
  margin: var(--wjs-divider-mt, var(--wjs-xl)) auto var(--wjs-divider-mb, var(--wjs-xl));
  width: var(--wjs-divider-length, 100%);
  max-width: 100%;
  border: 0;
  opacity: 1;
}
.wjs-block-divider--solid, .wp-block-divider--solid { border-top: var(--wjs-divider-width, 1px) solid var(--wjs-divider-color, var(--wjs-border-subtle)); }
.wjs-block-divider--dashed, .wp-block-divider--dashed { border-top: var(--wjs-divider-width, 1px) dashed var(--wjs-divider-color, var(--wjs-border-subtle)); }
/* A gradient needs a painted box, not a border — hence the separate element in the renderer. */
.wjs-block-divider--gradient, .wp-block-divider--gradient {
  height: var(--wjs-divider-width, 2px);
  background: var(--wjs-divider-gradient, linear-gradient(90deg, transparent, var(--wjs-divider-color, var(--wjs-color-primary)), transparent));
}

/* -------------------------------------------------------------------- BUTTON - */
/* `align` is text-align on the wrapper: `justify-content: left|right` is legal Box-Alignment but
 * flexbox ignores those two keywords in most engines, which silently broke left/right. */
.wjs-block-button, .wp-block-button { text-align: var(--wjs-button-align, left); }
.wjs-block-button__link, .wp-block-button__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--wjs-sm);
  padding: var(--wjs-button-pad-y, 12px) var(--wjs-button-pad-x, 20px);
  font-family: var(--wjs-button-family, var(--wjs-font-family-base));
  font-size: var(--wjs-button-size, 15px);
  font-weight: var(--wjs-button-weight, 700);
  line-height: var(--wjs-button-leading, 1);
  text-transform: var(--wjs-button-transform, none);
  letter-spacing: var(--wjs-button-tracking, normal);
  text-decoration: none;
  border: var(--wjs-button-border-width, 1px) solid var(--wjs-button-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-button-radius, var(--wjs-radius));
  background: var(--wjs-button-bg, var(--wjs-color-primary));
  color: var(--wjs-button-color, var(--wjs-color-on-primary));
  box-shadow: var(--wjs-button-shadow, var(--wjs-shadow-2));
  cursor: pointer;
  transition: transform 0.15s ease, filter 0.2s ease, background 0.2s ease, color 0.2s ease;
}
/* `a:hover` in the reboot recolours links; restate the token so a button keeps its own colour. */
.wjs-block-button__link:hover, .wp-block-button__link:hover {
  background: var(--wjs-button-hover-bg, var(--wjs-button-bg, var(--wjs-color-primary)));
  color: var(--wjs-button-hover-color, var(--wjs-button-color, var(--wjs-color-on-primary)));
  box-shadow: var(--wjs-button-hover-shadow, var(--wjs-button-shadow, var(--wjs-shadow-2)));
  filter: brightness(1.08);
  transform: var(--wjs-button-hover-transform, scale(1.03));
}
.wjs-block-button__link:active, .wp-block-button__link:active { transform: var(--wjs-button-active-transform, scale(0.96)); }
/* Variants get DEDICATED seams first: without them a theme's primary `--wjs-button-bg/color`
 * bleeds into every variant (secondary ≡ primary; outline inherits on-primary text, invisible
 * on light canvases). The old chain stays as fallback so pre-seam themes keep their look. */
.wjs-block-button__link.button-variant-secondary, .wp-block-button__link.button-variant-secondary {
  background: var(--wjs-button-secondary-bg, var(--wjs-button-bg, var(--wjs-color-secondary)));
  color: var(--wjs-button-secondary-color, var(--wjs-button-color, var(--wjs-color-on-secondary)));
}
.wjs-block-button__link.button-variant-secondary:hover, .wp-block-button__link.button-variant-secondary:hover { color: var(--wjs-button-secondary-color, var(--wjs-button-color, var(--wjs-color-on-secondary))); }
.wjs-block-button__link.button-variant-outline, .wp-block-button__link.button-variant-outline {
  background: var(--wjs-button-outline-bg, transparent);
  border-color: var(--wjs-button-outline-border-color, var(--wjs-button-border-color, var(--wjs-outline)));
  color: var(--wjs-button-outline-color, var(--wjs-color-text-main));
  box-shadow: none;
}
.wjs-block-button__link.button-variant-outline:hover, .wp-block-button__link.button-variant-outline:hover {
  background: var(--wjs-button-outline-hover-bg, rgba(127, 127, 127, 0.12));
  color: var(--wjs-button-outline-color, var(--wjs-color-text-main));
  filter: none;
}

/* -------------------------------------------------------------------- SPACER - */
.wjs-block-spacer, .wp-block-spacer { width: 100%; height: var(--wjs-spacer-height, var(--wjs-lg)); }

/* ------------------------------------------------------------------- SECTION - */
.wjs-block-section, .wp-block-section {
  width: 100%;
  padding: var(--wjs-section-pad, var(--wjs-2xl) var(--wjs-lg));
  background: var(--wjs-section-bg, transparent);
  color: var(--wjs-section-color, inherit);
}
.wjs-block-section__inner, .wp-block-section__inner {
  width: 100%;
  max-width: var(--wjs-section-max-width, var(--wjs-container-max));
  margin-inline: auto;
}

/* ESCENA FIJA — el "pin" honesto (C5).
 *
 * La sección reserva su altura POR ADELANTADO (`--wjs-section-scene` pantallas) y su escenario se
 * queda quieto con `position: sticky` mientras esa altura pasa por delante. Nadie mueve el layout
 * al hacer scroll: cero CLS por construcción, cero JS. Es la diferencia con el `pin` de las
 * librerías, que inyecta un espaciador y REESCRIBE la maquetación en caliente.
 *
 * La sección declara además una timeline de vista con nombre: sus descendientes pueden engancharse
 * a ella (`animation-timeline: --wjs-ix-scene`) y así el movimiento lee el TIEMPO DE LA ESCENA. Con
 * `view()` a secas no funcionaría: mientras el escenario está fijo su posición en la ventana no
 * cambia, así que su propio progreso se congela justo cuando debería avanzar.
 *
 * `100svh` es la altura de la ventana con la barra del navegador DESPLEGADA: sin ella, el escenario
 * de un móvil sobresale y la sección "salta" al ocultarse la barra. `100vh` queda de reserva para
 * quien no la entienda.
 */
.wjs-block-section--scene, .wp-block-section--scene {
  min-height: calc(100vh * var(--wjs-section-scene, 2));
  min-height: calc(100svh * var(--wjs-section-scene, 2));
  /* El relleno pasa ENTERO al escenario, que es quien enmarca el contenido. Dejarlo también aquí
   * lo aplicaría dos veces y una escena saldría más estrecha que cualquier otra sección — medido:
   * 1102 px de contenido frente a los 1150 px de una sección normal con el mismo `pad`. */
  padding: 0;
}
.wjs-block-section__stage, .wp-block-section__stage {
  position: sticky;
  top: var(--wjs-section-stage-top, 0px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100vh;
  min-height: 100svh;
  padding: var(--wjs-section-pad, var(--wjs-2xl) var(--wjs-lg));
}
@supports (view-timeline-name: --x) {
  .wjs-block-section--scene, .wp-block-section--scene {
    view-timeline-name: --wjs-ix-scene;
    view-timeline-axis: block;
  }
}

/* ---------------------------------------------------------------------- GRID - */
/* The outer element only carries tokens. The GRID lives on "__items", the wrapper Puck puts around
 * a slot's children: declared on the outer element instead, that single wrapper became the only
 * grid item, so every child stacked into track 1 and the remaining tracks rendered empty. */
.wjs-block-grid__items, .wp-block-grid__items {
  display: grid;
  gap: var(--wjs-grid-gap, var(--wjs-md));
  grid-template-columns: repeat(var(--wjs-grid-columns, 3), minmax(0, 1fr));
}
.wjs-block-grid__items > *, .wp-block-grid__items > * { min-width: 0; }
@media (max-width: 1023.98px) { .wjs-block-grid__items, .wp-block-grid__items { grid-template-columns: repeat(var(--wjs-grid-columns-tablet, 2), minmax(0, 1fr)); } }
@media (max-width: 767.98px) { .wjs-block-grid__items, .wp-block-grid__items { grid-template-columns: repeat(var(--wjs-grid-columns-mobile, 1), minmax(0, 1fr)); } }

/* ------------------------------------------------------------------ FLEX ROW - */
.wjs-block-flex-row__items, .wp-block-flex-row__items {
  display: flex;
  flex-direction: var(--wjs-flex-direction, row);
  justify-content: var(--wjs-flex-justify, flex-start);
  align-items: var(--wjs-flex-align, center);
  gap: var(--wjs-flex-gap, var(--wjs-md));
  flex-wrap: var(--wjs-flex-wrap, wrap);
}
.wjs-block-flex-row__items > *, .wp-block-flex-row__items > * { min-width: 0; }

/* ------------------------------------------------------------------- COLUMNS - */
.wjs-block-columns, .wp-block-columns {
  display: grid;
  width: 100%;
  align-items: stretch;
  gap: var(--wjs-columns-gap, var(--wjs-lg));
  grid-template-columns: var(--wjs-columns-template, repeat(2, minmax(0, 1fr)));
  min-height: var(--wjs-columns-min-height, auto);
  background: var(--wjs-columns-bg, transparent);
  border-radius: var(--wjs-columns-radius, 0);
}
/* Each column carries its own `--wjs-col-*` set inline (the editor's per-column style panel). */
.wjs-block-columns__col, .wp-block-columns__col {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: var(--wjs-col-min-height, 100px);
  padding: var(--wjs-col-pad, var(--wjs-md));
  background: var(--wjs-col-bg, transparent);
  border: var(--wjs-col-border-width, 0) solid var(--wjs-col-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-col-radius, 0);
}
@media (max-width: 767.98px) { .wjs-block-columns, .wp-block-columns { grid-template-columns: 1fr; } }

/* ----------------------------------------------------------------- ACCORDION - */
/* Two shapes, one contract. DEFAULT: a single joined panel, items divided by a hairline. The other
 * is a STACK OF CARDS — each item its own surface with its own border and radius, separated by a
 * gap. A theme picks the second by giving the container a flex direction + gap, zeroing the
 * separator, and giving the item a box. Every base below is what it already rendered. */
.wjs-block-accordion, .wp-block-accordion {
  display: var(--wjs-accordion-display, block);
  flex-direction: column;
  gap: var(--wjs-accordion-item-gap, 0);
  /* `visible` lets a themed open item cast a glow past the container edge. */
  overflow: var(--wjs-accordion-overflow, hidden);
  padding: var(--wjs-accordion-inset, 0);
  background: var(--wjs-accordion-bg, var(--wjs-bg-surface));
  border: var(--wjs-accordion-border-width, 1px) solid var(--wjs-accordion-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-accordion-radius, var(--wjs-radius-lg));
  box-shadow: var(--wjs-accordion-shadow, none);
}
.wjs-block-accordion__item, .wp-block-accordion__item {
  overflow: hidden;
  background: var(--wjs-accordion-item-bg, transparent);
  border: var(--wjs-accordion-item-border-width, 0) solid var(--wjs-accordion-item-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-accordion-item-radius, 0);
  transition: border-color var(--wjs-transition), background var(--wjs-transition), box-shadow var(--wjs-transition);
}
.wjs-block-accordion__item:hover, .wp-block-accordion__item:hover {
  border-color: var(--wjs-accordion-item-hover-border-color, var(--wjs-accordion-item-border-color, var(--wjs-border-subtle)));
}
.wjs-block-accordion__item.is-open, .wp-block-accordion__item.is-open {
  background: var(--wjs-accordion-active-bg, var(--wjs-accordion-item-bg, transparent));
  border-color: var(--wjs-accordion-active-border-color, var(--wjs-accordion-item-border-color, var(--wjs-border-subtle)));
  box-shadow: var(--wjs-accordion-active-shadow, none);
}
/* The divider between items. Chained through `--wjs-accordion-border-width` so the 12 themes that
 * only ever set THAT keep their hairline; a card stack sets the separator to 0 on its own. */
.wjs-block-accordion__item + .wjs-block-accordion__item, .wp-block-accordion__item + .wp-block-accordion__item {
  border-top: var(--wjs-accordion-separator-width, var(--wjs-accordion-border-width, 1px)) solid var(--wjs-accordion-separator-color, var(--wjs-accordion-border-color, var(--wjs-border-subtle)));
}
.wjs-block-accordion__header, .wp-block-accordion__header {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  gap: var(--wjs-md);
  padding: var(--wjs-accordion-pad, var(--wjs-md) var(--wjs-lg));
  font-family: var(--wjs-accordion-header-family, inherit);
  font-size: var(--wjs-accordion-header-size, 1rem);
  font-weight: var(--wjs-accordion-header-weight, 600);
  text-transform: var(--wjs-accordion-header-transform, none);
  letter-spacing: var(--wjs-accordion-header-tracking, normal);
  border-radius: var(--wjs-accordion-header-radius, 0);
  box-shadow: var(--wjs-accordion-header-shadow, none);
  text-align: start;
  background: var(--wjs-accordion-header-bg, transparent);
  color: var(--wjs-accordion-header-color, var(--wjs-color-text-main));
  border: 0;
  border-bottom: var(--wjs-accordion-header-border-width, 0) solid var(--wjs-accordion-header-border-color, var(--wjs-border-subtle));
  cursor: pointer;
  transition: background var(--wjs-transition), color var(--wjs-transition);
}
.wjs-block-accordion__header:hover, .wp-block-accordion__header:hover { background: var(--wjs-accordion-header-hover-bg, var(--wjs-bg-muted)); }
.wjs-block-accordion__icon, .wp-block-accordion__icon { flex: none; color: var(--wjs-accordion-icon-color, inherit); transition: transform 0.2s ease; }
.wjs-block-accordion__item.is-open .wjs-block-accordion__icon, .wp-block-accordion__item.is-open .wp-block-accordion__icon { transform: var(--wjs-accordion-icon-open-transform, rotate(180deg)); }
.wjs-block-accordion__item.is-open .wjs-block-accordion__header, .wp-block-accordion__item.is-open .wp-block-accordion__header { color: var(--wjs-accordion-active-color, var(--wjs-color-primary)); }
/* El panel se REVELA con una transición de altura hecha con grid (0fr → 1fr). Se eligió esta
 * técnica y no `interpolate-size`/`calc-size()` —que animan hasta `height:auto` y son mucho más
 * directas— porque en 2026 esas dos siguen siendo exclusivas de Chromium: aquí funcionan los tres
 * motores, y sin medir un solo píxel en JavaScript.
 *
 * El panel vive SIEMPRE en el DOM (su contenido es HTML del servidor, rastreable). Cerrado es
 * `visibility:hidden`, así que sale del árbol de accesibilidad y del orden de tabulación — la
 * misma postura que el cajón OffCanvas. La visibilidad se conmuta con `0s`: al ABRIR, de inmediato
 * (si no, el contenido aparecería al final del recorrido); al CERRAR, con el retardo justo de la
 * transición, para que no desaparezca antes de terminar de plegarse. */
.wjs-block-accordion__panel, .wp-block-accordion__panel {
  display: grid;
  grid-template-rows: 0fr;
  visibility: hidden;
  background: var(--wjs-accordion-panel-bg, var(--wjs-bg-muted));
  color: var(--wjs-accordion-panel-color, var(--wjs-color-text-muted));
}
.wjs-block-accordion__item.is-open > .wjs-block-accordion__panel,
.wp-block-accordion__item.is-open > .wp-block-accordion__panel {
  grid-template-rows: 1fr;
  visibility: visible;
}
/* La caja interior es SOLO el recorte: sin `min-height:0` la fila no puede bajar de la altura
 * natural del contenido y no habría pliegue.
 *
 * Y el relleno NO puede vivir aquí: el `padding` no colapsa con `min-height:0` —la caja mide
 * contenido(0) + relleno—, así que un panel cerrado se quedaba en 32px en vez de cero (medido en el
 * navegador). Por eso el relleno baja un nivel más, DENTRO de la zona recortada, conservando el
 * mismo nombre de token para que los temas que lo fijan no se enteren del cambio. */
.wjs-block-accordion__panel-inner, .wp-block-accordion__panel-inner {
  overflow: hidden;
  min-height: 0;
}
.wjs-block-accordion__panel-body, .wp-block-accordion__panel-body {
  padding: var(--wjs-accordion-panel-pad, var(--wjs-md) var(--wjs-lg));
  font-family: var(--wjs-accordion-panel-family, inherit);
}
@media screen and (prefers-reduced-motion: no-preference) {
  .wjs-block-accordion__panel, .wp-block-accordion__panel {
    transition:
      grid-template-rows var(--wjs-accordion-reveal, 280ms) cubic-bezier(.16, 1, .3, 1),
      visibility 0s linear var(--wjs-accordion-reveal, 280ms);
  }
  .wjs-block-accordion__item.is-open > .wjs-block-accordion__panel,
  .wp-block-accordion__item.is-open > .wp-block-accordion__panel {
    transition:
      grid-template-rows var(--wjs-accordion-reveal, 280ms) cubic-bezier(.16, 1, .3, 1),
      visibility 0s;
  }
}

/* ---------------------------------------------------------------------- TABS - */
.wjs-block-tabs, .wp-block-tabs { display: block; }
/* The list is either an underlined rule (default) or a filled "pill" bar — a theme picks by
 * setting `--wjs-tabs-list-bg`/`-radius`/`-pad` and zeroing the border width. */
.wjs-block-tabs__list, .wp-block-tabs__list {
  display: flex;
  flex-wrap: wrap;
  /* Tabs are separated by a GAP in the reference, not by horizontal tab padding — the two look the
   * same until a tab's label is short, when padding centres it and a gap does not. */
  gap: var(--wjs-tabs-gap, 0);
  margin-bottom: var(--wjs-tabs-list-gap, var(--wjs-lg));
  padding: var(--wjs-tabs-list-pad, 0);
  background: var(--wjs-tabs-list-bg, transparent);
  border-bottom: var(--wjs-tabs-list-border-width, var(--wjs-tabs-border-width, 2px)) solid var(--wjs-tabs-list-border-color, var(--wjs-tabs-border-color, var(--wjs-border-subtle)));
  border-radius: var(--wjs-tabs-list-radius, 0);
}
.wjs-block-tabs__tab, .wp-block-tabs__tab {
  padding: var(--wjs-tabs-tab-pad, 12px 24px);
  /* Pull the tab's own underline over the list's, so the active tab "cuts" the rule. */
  margin-bottom: calc(var(--wjs-tabs-border-width, 2px) * -1);
  font-family: var(--wjs-tabs-family, inherit);
  font-size: var(--wjs-tabs-size, inherit);
  font-weight: var(--wjs-tabs-weight, 500);
  text-transform: var(--wjs-tabs-transform, none);
  letter-spacing: var(--wjs-tabs-tracking, normal);
  background: transparent;
  color: var(--wjs-tabs-color, var(--wjs-color-text-muted));
  border: 0;
  border-bottom: var(--wjs-tabs-border-width, 2px) solid transparent;
  border-radius: var(--wjs-tabs-radius, 0);
  cursor: pointer;
  transition: color var(--wjs-transition), border-color var(--wjs-transition), background var(--wjs-transition);
}
.wjs-block-tabs__tab:hover, .wp-block-tabs__tab:hover { color: var(--wjs-tabs-active-color, var(--wjs-color-primary)); }
.wjs-block-tabs__tab.is-active, .wp-block-tabs__tab.is-active {
  font-weight: var(--wjs-tabs-active-weight, 700);
  color: var(--wjs-tabs-active-color, var(--wjs-color-primary));
  background: var(--wjs-tabs-active-bg, transparent);
  box-shadow: var(--wjs-tabs-active-shadow, none);
  border-bottom-width: var(--wjs-tabs-active-border-width, var(--wjs-tabs-border-width, 2px));
  border-bottom-color: var(--wjs-tabs-active-border-color, var(--wjs-tabs-active-color, var(--wjs-color-primary)));
}
.wjs-block-tabs__panel, .wp-block-tabs__panel {
  padding: var(--wjs-tabs-panel-pad, var(--wjs-lg));
  background: var(--wjs-tabs-panel-bg, var(--wjs-bg-surface));
  border-top: var(--wjs-tabs-panel-border-width, 0) solid var(--wjs-tabs-panel-border-color, var(--wjs-border-subtle));
  color: var(--wjs-tabs-panel-color, inherit);
  border-radius: var(--wjs-tabs-panel-radius, var(--wjs-radius));
}

/* --------------------------------------------------------------- VIDEO EMBED - */
.wjs-block-video-embed, .wp-block-video-embed {
  position: relative;
  width: 100%;
  height: 0;
  padding-bottom: var(--wjs-video-aspect, 56.25%);
  overflow: hidden;
  background: var(--wjs-video-bg, var(--wjs-bg-muted));
  border: var(--wjs-video-border-width, 0) solid var(--wjs-video-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-video-radius, var(--wjs-radius-lg));
  box-shadow: var(--wjs-video-shadow, none);
}
.wjs-block-video-embed iframe, .wp-block-video-embed iframe,
.wjs-block-video-embed video, .wp-block-video-embed video { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.wjs-block-video-embed__placeholder, .wp-block-video-embed__placeholder {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  text-align: center;
  color: var(--wjs-video-placeholder-color, var(--wjs-color-text-muted));
}
.wjs-block-video-embed__placeholder i, .wp-block-video-embed__placeholder i { font-size: 2rem; margin-bottom: var(--wjs-sm); }

/* The poster cover: a real <button> filling the frame, so the whole poster is one keyboard-
 * reachable target rather than a div with a click handler. It unmounts once playback starts. */
.wjs-block-video-embed__cover, .wp-block-video-embed__cover {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
}
.wjs-block-video-embed__scrim, .wp-block-video-embed__scrim {
  position: absolute;
  inset: 0;
  background: var(--wjs-video-scrim, rgba(0, 0, 0, 0.4));
  transition: background var(--wjs-transition);
}
.wjs-block-video-embed__cover:hover .wjs-block-video-embed__scrim, .wp-block-video-embed__cover:hover .wp-block-video-embed__scrim {
  background: var(--wjs-video-scrim-hover, var(--wjs-video-scrim, rgba(0, 0, 0, 0.25)));
}
.wjs-block-video-embed__play, .wp-block-video-embed__play {
  position: relative;
  display: grid;
  place-items: center;
  width: var(--wjs-video-play-size, 72px);
  height: var(--wjs-video-play-size, 72px);
  font-size: calc(var(--wjs-video-play-size, 72px) * 0.32);
  border-radius: var(--wjs-video-play-radius, 50%);
  background: var(--wjs-video-play-bg, rgba(255, 255, 255, 0.92));
  color: var(--wjs-video-play-color, var(--wjs-color-text-main));
  box-shadow: var(--wjs-video-play-shadow, var(--wjs-shadow-2));
  transition: transform 0.15s ease, background var(--wjs-transition);
}
/* Nudge right: a play triangle is optically off-centre in a circle when centred geometrically. */
.wjs-block-video-embed__play i, .wp-block-video-embed__play i { transform: var(--wjs-video-play-glyph-transform, translateX(6%)); }
.wjs-block-video-embed__cover:hover .wjs-block-video-embed__play, .wp-block-video-embed__cover:hover .wp-block-video-embed__play { transform: var(--wjs-video-play-hover-transform, scale(1.06)); }
.wjs-block-video-embed__cover:focus-visible, .wp-block-video-embed__cover:focus-visible {
  outline: var(--wjs-block-focus-outline, 2px solid var(--wjs-color-primary));
  outline-offset: calc(var(--wjs-block-focus-offset, 2px) * -1);
}
.wjs-block-video-embed__chip, .wp-block-video-embed__chip {
  position: absolute;
  inset-inline-end: var(--wjs-md);
  bottom: var(--wjs-md);
  padding: var(--wjs-video-chip-pad, 2px 8px);
  font-family: var(--wjs-video-chip-family, inherit);
  font-size: var(--wjs-video-chip-size, var(--wjs-label));
  border-radius: var(--wjs-video-chip-radius, var(--wjs-radius-sm));
  background: var(--wjs-video-chip-bg, rgba(0, 0, 0, 0.65));
  color: var(--wjs-video-chip-color, #fff);
}
.wjs-block-video-embed__placeholder p, .wp-block-video-embed__placeholder p { margin: 0; }

/* --------------------------------------------------------------- AUDIO PLAYER - */
/* The transport is OURS, not the browser's. `<audio controls>` paints chrome no stylesheet can
 * reach, so the element is kept as the media engine only (see .__engine) and every visible part
 * below is real markup behind --wjs-audio-* tokens. */
.wjs-block-audio-player, .wp-block-audio-player {
  display: flex;
  align-items: center;
  gap: var(--wjs-md);
  padding: var(--wjs-audio-pad, var(--wjs-lg));
  background: var(--wjs-audio-bg, var(--wjs-bg-surface));
  border: var(--wjs-audio-border-width, 1px) solid var(--wjs-audio-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-audio-radius, var(--wjs-radius-lg));
  box-shadow: var(--wjs-audio-shadow, none);
}

/* Play / pause. Sized off the same token the old icon tile used, so a theme that already set
 * --wjs-audio-icon-* keeps its geometry. */
.wjs-block-audio-player__button, .wp-block-audio-player__button {
  display: grid;
  place-items: center;
  flex: none;
  width: var(--wjs-audio-icon-size, 48px);
  height: var(--wjs-audio-icon-size, 48px);
  padding: 0;
  font-size: var(--wjs-audio-icon-glyph, calc(var(--wjs-audio-icon-size, 48px) * 0.45));
  border-radius: var(--wjs-audio-icon-radius, var(--wjs-radius));
  background: var(--wjs-audio-icon-bg, var(--wjs-color-primary));
  color: var(--wjs-audio-icon-color, var(--wjs-color-on-primary));
  border: var(--wjs-audio-icon-border-width, 0) solid var(--wjs-audio-icon-border-color, var(--wjs-border-subtle));
  box-shadow: var(--wjs-audio-icon-shadow, none);
  cursor: pointer;
  transition: transform 0.15s ease, filter 0.2s ease;
}
.wjs-block-audio-player__button:hover, .wp-block-audio-player__button:hover { transform: var(--wjs-audio-icon-hover-transform, scale(1.05)); filter: brightness(1.06); }
.wjs-block-audio-player__button:active, .wp-block-audio-player__button:active { transform: var(--wjs-audio-icon-active-transform, scale(0.96)); }

.wjs-block-audio-player__body, .wp-block-audio-player__body { flex: 1; min-width: 0; }

/* Marquee: the label is rendered twice and the pair slides exactly half its width, so the loop has
 * no seam. Motion is opt-in per theme AND disabled outright under prefers-reduced-motion. */
/* TWO elements on purpose. The marquee CLIPS (it is exactly as wide as the column and hides
 * the overflow); the track INSIDE it is as wide as its content and is the thing that moves. Doing
 * both jobs on one element makes it grow past the player, and then there is nothing left to clip
 * against — the title spills out of the pill. */
.wjs-block-audio-player__marquee, .wp-block-audio-player__marquee {
  width: 100%;
  margin-bottom: var(--wjs-xs);
  overflow: hidden;
}
.wjs-block-audio-player__track, .wp-block-audio-player__track {
  display: flex;
  gap: var(--wjs-audio-marquee-gap, var(--wjs-xl));
  min-width: 0;
}
.wjs-block-audio-player__track.is-scrolling, .wp-block-audio-player__track.is-scrolling { width: max-content; }
/* Not scrolling: the single label must ellipsize rather than push the column wider. */
.wjs-block-audio-player__track:not(.is-scrolling) .wjs-block-audio-player__title, .wp-block-audio-player__track:not(.is-scrolling) .wp-block-audio-player__title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.wjs-block-audio-player__title, .wp-block-audio-player__title {
  flex: none;
  font-family: var(--wjs-audio-title-family, inherit);
  font-size: var(--wjs-audio-title-size, inherit);
  font-weight: var(--wjs-audio-title-weight, 600);
  text-transform: var(--wjs-audio-title-transform, none);
  letter-spacing: var(--wjs-audio-title-tracking, normal);
  white-space: nowrap;
  color: var(--wjs-audio-title-color, var(--wjs-color-text-main));
}
@media screen and (prefers-reduced-motion: no-preference) {
  .wjs-block-audio-player__track.is-scrolling, .wp-block-audio-player__track.is-scrolling {
    animation: wjs-audio-marquee var(--wjs-audio-marquee-duration, 0s) linear infinite;
  }
}
@keyframes wjs-audio-marquee {
  from { transform: translateX(0); }
  to { transform: translateX(calc(-50% - var(--wjs-audio-marquee-gap, var(--wjs-xl)) / 2)); }
}

/* Scrubber. A real range input: keyboard seeking and screen-reader semantics come for free, which
 * is exactly what hand-rolled slider divs throw away. The fill is a gradient stop driven by the
 * --wjs-audio-progress-pct the component writes on each frame. */
.wjs-block-audio-player__scrub, .wp-block-audio-player__scrub {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  height: var(--wjs-audio-track-height, 4px);
  margin: 0;
  background: transparent;
  cursor: pointer;
}
.wjs-block-audio-player__scrub::-webkit-slider-runnable-track, .wp-block-audio-player__scrub::-webkit-slider-runnable-track {
  height: var(--wjs-audio-track-height, 4px);
  border-radius: var(--wjs-audio-track-radius, 999px);
  background: linear-gradient(
    to right,
    var(--wjs-audio-progress-bg, var(--wjs-color-primary)) 0 var(--wjs-audio-progress-pct, 0%),
    var(--wjs-audio-track-bg, var(--wjs-surface-highest)) var(--wjs-audio-progress-pct, 0%) 100%
  );
  box-shadow: var(--wjs-audio-progress-shadow, none);
}
.wjs-block-audio-player__scrub::-moz-range-track, .wp-block-audio-player__scrub::-moz-range-track {
  height: var(--wjs-audio-track-height, 4px);
  border-radius: var(--wjs-audio-track-radius, 999px);
  background: linear-gradient(
    to right,
    var(--wjs-audio-progress-bg, var(--wjs-color-primary)) 0 var(--wjs-audio-progress-pct, 0%),
    var(--wjs-audio-track-bg, var(--wjs-surface-highest)) var(--wjs-audio-progress-pct, 0%) 100%
  );
  box-shadow: var(--wjs-audio-progress-shadow, none);
}
/* The handle is hidden by default (the reference shows a bare bar) but stays a real, focusable
 * target; it appears on hover and whenever the control has keyboard focus. */
.wjs-block-audio-player__scrub::-webkit-slider-thumb, .wp-block-audio-player__scrub::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: var(--wjs-audio-thumb-size, 12px);
  height: var(--wjs-audio-thumb-size, 12px);
  margin-top: calc((var(--wjs-audio-track-height, 4px) - var(--wjs-audio-thumb-size, 12px)) / 2);
  border: 0;
  border-radius: 50%;
  background: var(--wjs-audio-thumb-bg, var(--wjs-audio-progress-bg, var(--wjs-color-primary)));
  opacity: var(--wjs-audio-thumb-opacity, 0);
  transition: opacity var(--wjs-transition);
}
.wjs-block-audio-player__scrub::-moz-range-thumb, .wp-block-audio-player__scrub::-moz-range-thumb {
  width: var(--wjs-audio-thumb-size, 12px);
  height: var(--wjs-audio-thumb-size, 12px);
  border: 0;
  border-radius: 50%;
  background: var(--wjs-audio-thumb-bg, var(--wjs-audio-progress-bg, var(--wjs-color-primary)));
  opacity: var(--wjs-audio-thumb-opacity, 0);
  transition: opacity var(--wjs-transition);
}
.wjs-block-audio-player__scrub:hover::-webkit-slider-thumb, .wp-block-audio-player__scrub:hover::-webkit-slider-thumb,
.wjs-block-audio-player__scrub:focus-visible::-webkit-slider-thumb, .wp-block-audio-player__scrub:focus-visible::-webkit-slider-thumb { opacity: 1; }
.wjs-block-audio-player__scrub:hover::-moz-range-thumb, .wp-block-audio-player__scrub:hover::-moz-range-thumb,
.wjs-block-audio-player__scrub:focus-visible::-moz-range-thumb, .wp-block-audio-player__scrub:focus-visible::-moz-range-thumb { opacity: 1; }
.wjs-block-audio-player__scrub:focus-visible, .wp-block-audio-player__scrub:focus-visible {
  outline: var(--wjs-block-focus-outline, 2px solid var(--wjs-color-primary));
  outline-offset: var(--wjs-block-focus-offset, 4px);
}

.wjs-block-audio-player__times, .wp-block-audio-player__times {
  display: flex;
  justify-content: space-between;
  margin-top: var(--wjs-xs);
  font-family: var(--wjs-audio-time-family, inherit);
  font-size: var(--wjs-audio-time-size, var(--wjs-small));
  color: var(--wjs-audio-time-color, var(--wjs-color-text-muted));
}

/* The engine. Present for the media API and as the no-JS download link; never shown, because its
 * own controls are the thing this block exists to replace. */
.wjs-block-audio-player__engine, .wp-block-audio-player__engine { display: none; }

/* ------------------------------------------------------------- PRICING TABLE - */
.wjs-block-pricing, .wp-block-pricing {
  display: grid;
  align-items: stretch;
  gap: var(--wjs-pricing-gap, var(--wjs-lg));
  grid-template-columns: repeat(var(--wjs-pricing-columns, 3), minmax(0, 1fr));
}
.wjs-block-pricing__plan, .wp-block-pricing__plan {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: var(--wjs-pricing-pad, var(--wjs-xl));
  background: var(--wjs-pricing-bg, var(--wjs-bg-surface));
  border: var(--wjs-pricing-border-width, 1px) solid var(--wjs-pricing-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-pricing-radius, var(--wjs-radius-lg));
  box-shadow: var(--wjs-pricing-shadow, var(--wjs-inset-highlight));
  transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}
.wjs-block-pricing__plan:hover, .wp-block-pricing__plan:hover {
  border-color: var(--wjs-pricing-hover-border-color, var(--wjs-pricing-border-color, var(--wjs-border-subtle)));
  transform: var(--wjs-pricing-hover-transform, translateY(-8px));
  box-shadow: var(--wjs-pricing-hover-shadow, var(--wjs-pricing-shadow, var(--wjs-inset-highlight)));
}
.wjs-block-pricing__plan--highlighted, .wp-block-pricing__plan--highlighted {
  background: var(--wjs-pricing-highlight-bg, var(--wjs-bg-surface-raised));
  border: var(--wjs-pricing-highlight-border-width, 2px) solid var(--wjs-pricing-highlight-border-color, var(--wjs-pricing-accent, var(--wjs-color-primary)));
  box-shadow: var(--wjs-pricing-highlight-shadow, var(--wjs-shadow-3));
  color: var(--wjs-pricing-highlight-color, inherit);
  transform: scale(var(--wjs-pricing-highlight-scale, 1.02));
  /* The featured plan brightens its own copy by RETUNING the plan tokens, so a theme adjusts it
   * through `--wjs-pricing-highlight-*` instead of writing a second set of rules. */
  --wjs-pricing-name-color: var(--wjs-pricing-highlight-name-color, var(--wjs-primary-fixed));
  --wjs-pricing-feature-color: var(--wjs-pricing-highlight-feature-color, var(--wjs-color-text-main));
  /* Price/period need the same seam: a theme that re-tints the featured plan (dark/primary bg)
   * has no other way to keep them readable — its base price token would pierce this variant. */
  --wjs-pricing-price-color: var(--wjs-pricing-highlight-price-color, var(--wjs-pricing-highlight-color, var(--wjs-color-heading)));
  --wjs-pricing-period-color: var(--wjs-pricing-highlight-period-color, var(--wjs-pricing-highlight-color, var(--wjs-color-text-muted)));
}
.wjs-block-pricing__plan--highlighted:hover, .wp-block-pricing__plan--highlighted:hover {
  transform: var(--wjs-pricing-highlight-hover-transform, scale(var(--wjs-pricing-highlight-scale, 1.02)) translateY(-6px));
  box-shadow: var(--wjs-pricing-highlight-hover-shadow, var(--wjs-pricing-highlight-shadow, var(--wjs-shadow-3)));
}
.wjs-block-pricing__name, .wp-block-pricing__name {
  margin: 0 0 var(--wjs-sm);
  font-family: var(--wjs-pricing-name-family, inherit);
  font-size: var(--wjs-pricing-name-size, var(--wjs-h5));
  font-weight: var(--wjs-pricing-name-weight, 700);
  line-height: var(--wjs-pricing-name-leading, 1.2);
  text-transform: var(--wjs-pricing-name-transform, none);
  letter-spacing: var(--wjs-pricing-name-tracking, normal);
  color: var(--wjs-pricing-name-color, var(--wjs-color-text-main));
}
.wjs-block-pricing__price, .wp-block-pricing__price {
  margin-bottom: var(--wjs-lg);
  font-family: var(--wjs-pricing-price-family, var(--wjs-font-family-heading));
  font-size: var(--wjs-pricing-price-size, 40px);
  font-weight: var(--wjs-pricing-price-weight, 800);
  line-height: 1;
  letter-spacing: var(--wjs-pricing-price-tracking, var(--wjs-h1-tracking));
  color: var(--wjs-pricing-price-color, var(--wjs-color-heading));
}
.wjs-block-pricing__period, .wp-block-pricing__period {
  margin-inline-start: var(--wjs-xs);
  font-size: var(--wjs-pricing-period-size, var(--wjs-small));
  font-weight: 500;
  color: var(--wjs-pricing-period-color, var(--wjs-color-text-muted));
}
.wjs-block-pricing__features, .wp-block-pricing__features {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--wjs-md);
  margin: 0 0 var(--wjs-xl);
  padding: 0;
  list-style: none;
}
.wjs-block-pricing__feature, .wp-block-pricing__feature {
  display: flex;
  align-items: center;
  gap: var(--wjs-md);
  margin: 0;
  font-size: var(--wjs-pricing-feature-size, var(--wjs-small));
  color: var(--wjs-pricing-feature-color, var(--wjs-color-text-muted));
}
.wjs-block-pricing__feature i, .wp-block-pricing__feature i { flex: none; font-size: var(--wjs-pricing-feature-icon-size, 18px); color: var(--wjs-pricing-accent, var(--wjs-color-primary)); }
.wjs-block-pricing__button, .wp-block-pricing__button {
  display: block;
  margin-top: auto;
  padding: var(--wjs-pricing-button-pad, 12px 20px);
  text-align: center;
  text-decoration: none;
  font-weight: var(--wjs-pricing-button-weight, 700);
  background: var(--wjs-pricing-button-bg, var(--wjs-surface-highest));
  color: var(--wjs-pricing-button-color, var(--wjs-color-primary));
  border: 1px solid var(--wjs-pricing-button-border-color, var(--wjs-outline-variant));
  border-radius: var(--wjs-pricing-button-radius, var(--wjs-radius));
  transition: filter 0.2s ease, transform 0.15s ease;
}
.wjs-block-pricing__button:hover, .wp-block-pricing__button:hover {
  background: var(--wjs-pricing-button-hover-bg, var(--wjs-pricing-button-bg, var(--wjs-surface-highest)));
  color: var(--wjs-pricing-button-color, var(--wjs-color-primary));
  filter: brightness(1.08);
}
/* The highlighted plan's CTA is the page's primary action — it takes the accent fill. */
.wjs-block-pricing__plan--highlighted .wjs-block-pricing__button, .wp-block-pricing__plan--highlighted .wp-block-pricing__button {
  background: var(--wjs-pricing-highlight-button-bg, var(--wjs-pricing-accent, var(--wjs-color-primary)));
  color: var(--wjs-pricing-button-on-accent, var(--wjs-color-on-primary));
  border-color: transparent;
  box-shadow: var(--wjs-pricing-highlight-button-shadow, none);
}
.wjs-block-pricing__plan--highlighted .wjs-block-pricing__button:hover, .wp-block-pricing__plan--highlighted .wp-block-pricing__button:hover {
  background: var(--wjs-pricing-highlight-button-bg, var(--wjs-pricing-accent, var(--wjs-color-primary)));
  color: var(--wjs-pricing-button-on-accent, var(--wjs-color-on-primary));
}
.wjs-block-pricing__plan--highlighted .wjs-block-pricing__button:hover, .wp-block-pricing__plan--highlighted .wp-block-pricing__button:hover { color: var(--wjs-pricing-button-on-accent, var(--wjs-color-on-primary)); }
@media (max-width: 767.98px) {
  .wjs-block-pricing, .wp-block-pricing { grid-template-columns: 1fr; }
  .wjs-block-pricing__plan--highlighted, .wp-block-pricing__plan--highlighted { transform: var(--wjs-pricing-highlight-mobile-transform, none); }
  .wjs-block-pricing__plan--highlighted:hover, .wp-block-pricing__plan--highlighted:hover { transform: var(--wjs-pricing-highlight-mobile-hover-transform, translateY(-6px)); }
}

/* --------------------------------------------------------------- TESTIMONIAL - */
.wjs-block-testimonial, .wp-block-testimonial {
  position: relative;
  padding: var(--wjs-testimonial-pad, var(--wjs-xl));
  font-family: var(--wjs-testimonial-family, inherit);
  background: var(--wjs-testimonial-bg, var(--wjs-bg-surface));
  border: var(--wjs-testimonial-border-width, 1px) solid var(--wjs-testimonial-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-testimonial-radius, var(--wjs-radius-lg));
  box-shadow: var(--wjs-testimonial-shadow, var(--wjs-shadow-2));
}
.wjs-block-testimonial__mark, .wp-block-testimonial__mark {
  position: absolute;
  top: 12px;
  inset-inline-end: 24px;
  font-family: var(--wjs-testimonial-mark-family, var(--wjs-font-family-heading));
  font-size: var(--wjs-testimonial-mark-size, 64px);
  font-weight: var(--wjs-testimonial-mark-weight, inherit);
  line-height: 1;
  color: var(--wjs-testimonial-mark-color, var(--wjs-color-primary));
  opacity: var(--wjs-testimonial-mark-opacity, 0.1);
  pointer-events: none;
}
.wjs-block-testimonial__quote, .wp-block-testimonial__quote {
  position: relative;
  z-index: 1;
  margin: 0 0 var(--wjs-xl);
  font-family: var(--wjs-testimonial-quote-family, inherit);
  font-size: var(--wjs-testimonial-quote-size, var(--wjs-h5));
  font-style: var(--wjs-testimonial-quote-style, italic);
  line-height: 1.6;
  color: var(--wjs-testimonial-quote-color, var(--wjs-color-text-main));
}
.wjs-block-testimonial__person, .wp-block-testimonial__person { display: flex; align-items: center; gap: var(--wjs-md); }
.wjs-block-testimonial__avatar, .wp-block-testimonial__avatar {
  flex: none;
  width: var(--wjs-testimonial-avatar-size, 48px);
  height: var(--wjs-testimonial-avatar-size, 48px);
  border-radius: var(--wjs-testimonial-avatar-radius, 50%);
  object-fit: cover;
}
.wjs-block-testimonial__avatar--initials, .wp-block-testimonial__avatar--initials {
  display: grid;
  place-items: center;
  background: var(--wjs-testimonial-avatar-bg, var(--wjs-color-primary));
  color: var(--wjs-testimonial-avatar-color, var(--wjs-color-on-primary));
  font-weight: var(--wjs-testimonial-initials-weight, 700);
  font-size: calc(var(--wjs-testimonial-avatar-size, 48px) * 0.4);
}
.wjs-block-testimonial__author, .wp-block-testimonial__author {
  font-family: var(--wjs-testimonial-author-family, inherit);
  font-weight: var(--wjs-testimonial-author-weight, 700);
  color: var(--wjs-testimonial-author-color, var(--wjs-color-text-main));
}
.wjs-block-testimonial__role, .wp-block-testimonial__role {
  font-family: var(--wjs-testimonial-role-family, inherit);
  font-size: var(--wjs-testimonial-role-size, var(--wjs-small));
  font-weight: var(--wjs-testimonial-role-weight, inherit);
  text-transform: var(--wjs-testimonial-role-transform, none);
  letter-spacing: var(--wjs-testimonial-role-tracking, normal);
  color: var(--wjs-testimonial-role-color, var(--wjs-color-text-muted));
}

/* ---------------------------------------------------------------- CTA BANNER - */
.wjs-block-cta-banner, .wp-block-cta-banner {
  /* Layout is a token too: `block` gives the centred stack, `flex` turns the same three children
   * into a banner row (the flex properties below are inert while display is block). */
  display: var(--wjs-cta-display, block);
  flex-wrap: wrap;
  align-items: center;
  justify-content: var(--wjs-cta-justify, center);
  column-gap: var(--wjs-cta-gap, var(--wjs-xl));
  padding: var(--wjs-cta-pad, var(--wjs-2xl) var(--wjs-xl));
  text-align: var(--wjs-cta-text-align, center);
  border: var(--wjs-cta-border-width, 0) solid var(--wjs-cta-border-color, var(--wjs-border-subtle));
  backdrop-filter: var(--wjs-cta-backdrop, none);
  -webkit-backdrop-filter: var(--wjs-cta-backdrop, none);
  border-radius: var(--wjs-cta-radius, var(--wjs-radius-lg));
  /* `--wjs-cta-bg` is the author's override; the variant sets `--wjs-cta-variant-bg` below. */
  background: var(--wjs-cta-bg, var(--wjs-cta-variant-bg, var(--wjs-color-primary)));
  color: var(--wjs-cta-color, var(--wjs-color-on-primary));
  box-shadow: var(--wjs-cta-shadow, none);
}
/* Each variant carries its OWN legible text colour: one shared `--wjs-cta-color` cannot be right
 * on both an accent fill and a near-black one. The author's inline value still outranks all three. */
.wjs-block-cta-banner.cta-variant-primary, .wp-block-cta-banner.cta-variant-primary {
  --wjs-cta-variant-bg: var(--wjs-cta-primary-bg, var(--wjs-color-primary));
  color: var(--wjs-cta-color, var(--wjs-cta-primary-color, var(--wjs-color-on-primary)));
}
.wjs-block-cta-banner.cta-variant-dark, .wp-block-cta-banner.cta-variant-dark {
  --wjs-cta-variant-bg: var(--wjs-cta-dark-bg, var(--wjs-color-dark));
  color: var(--wjs-cta-color, var(--wjs-cta-dark-color, var(--wjs-color-on-dark)));
}
.wjs-block-cta-banner.cta-variant-gradient, .wp-block-cta-banner.cta-variant-gradient {
  --wjs-cta-variant-bg: var(--wjs-cta-gradient, linear-gradient(135deg, var(--wjs-color-primary), var(--wjs-color-accent)));
  color: var(--wjs-cta-color, var(--wjs-cta-gradient-color, var(--wjs-color-on-primary)));
}
.wjs-block-cta-banner__title, .wp-block-cta-banner__title {
  order: var(--wjs-cta-title-order, 0);
  flex: var(--wjs-cta-title-flex, 0 1 auto);
  margin: var(--wjs-cta-title-margin, 0 0 var(--wjs-md));
  padding-top: var(--wjs-cta-title-pad, 0);
  border-top: var(--wjs-cta-title-border-width, 0) solid var(--wjs-cta-title-border-color, var(--wjs-border-subtle));
  font-family: var(--wjs-cta-title-family, var(--wjs-font-family-heading));
  font-size: var(--wjs-cta-title-size, var(--wjs-h2));
  font-weight: var(--wjs-cta-title-weight, 800);
  line-height: var(--wjs-cta-title-leading, 1.15);
  letter-spacing: var(--wjs-cta-title-tracking, var(--wjs-h2-tracking));
  text-transform: var(--wjs-cta-title-transform, none);
  color: var(--wjs-cta-title-color, inherit);
}
.wjs-block-cta-banner__subtitle, .wp-block-cta-banner__subtitle {
  order: var(--wjs-cta-subtitle-order, 0);
  flex: var(--wjs-cta-subtitle-flex, 0 1 auto);
  margin: var(--wjs-cta-subtitle-margin, 0 auto var(--wjs-xl));
  max-width: var(--wjs-cta-measure, 46rem);
  font-size: var(--wjs-cta-subtitle-size, var(--wjs-h6));
  color: inherit;
  opacity: var(--wjs-cta-subtitle-opacity, 0.85);
}
.wjs-block-cta-banner__button, .wp-block-cta-banner__button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  order: var(--wjs-cta-button-order, 0);
  /* Reads the ALIAS on purpose: the alias is what carries a theme that still declares the old
   * `-ml` name, and it defaults to the canonical `--wjs-cta-button-margin-start`. */
  margin-inline-start: var(--wjs-cta-button-ml, 0);
  gap: var(--wjs-sm);
  padding: var(--wjs-cta-button-pad, 14px 28px);
  font-family: var(--wjs-cta-button-family, inherit);
  font-size: var(--wjs-cta-button-size, inherit);
  font-weight: var(--wjs-cta-button-weight, 700);
  text-transform: var(--wjs-cta-button-transform, none);
  letter-spacing: var(--wjs-cta-button-tracking, normal);
  text-decoration: none;
  background: var(--wjs-cta-button-bg, var(--wjs-bg-surface));
  color: var(--wjs-cta-button-color, var(--wjs-color-primary));
  border: var(--wjs-cta-button-border-width, 0) solid var(--wjs-cta-button-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-cta-button-radius, var(--wjs-radius));
  box-shadow: var(--wjs-cta-button-shadow, var(--wjs-shadow-2));
  transition: transform 0.15s ease, filter 0.2s ease;
}
.wjs-block-cta-banner__button:hover, .wp-block-cta-banner__button:hover {
  background: var(--wjs-cta-button-hover-bg, var(--wjs-cta-button-bg, var(--wjs-bg-surface)));
  color: var(--wjs-cta-button-hover-color, var(--wjs-cta-button-color, var(--wjs-color-primary)));
  box-shadow: var(--wjs-cta-button-hover-shadow, var(--wjs-cta-button-shadow, var(--wjs-shadow-2)));
  transform: var(--wjs-cta-button-hover-transform, scale(1.03));
  filter: brightness(1.05);
}

/* ---------------------------------------------------------------- POSTS GRID - */
.wjs-block-posts-grid, .wp-block-posts-grid {
  display: grid;
  gap: var(--wjs-posts-gap, var(--wjs-lg));
  grid-template-columns: repeat(var(--wjs-posts-columns, 3), minmax(0, 1fr));
}
.wjs-block-posts-grid__card, .wp-block-posts-grid__card {
  padding: var(--wjs-posts-pad, var(--wjs-lg));
  font-family: var(--wjs-posts-family, inherit);
  background: var(--wjs-posts-bg, var(--wjs-bg-surface));
  border: var(--wjs-posts-border-width, 1px) solid var(--wjs-posts-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-posts-radius, var(--wjs-radius-lg));
  box-shadow: var(--wjs-posts-shadow, none);
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}
.wjs-block-posts-grid__card:hover, .wp-block-posts-grid__card:hover {
  transform: var(--wjs-posts-hover-transform, none);
  border-color: var(--wjs-posts-hover-border-color, var(--wjs-posts-border-color, var(--wjs-border-subtle)));
  box-shadow: var(--wjs-posts-hover-shadow, var(--wjs-posts-shadow, none));
}
.wjs-block-posts-grid__thumb, .wp-block-posts-grid__thumb {
  height: var(--wjs-posts-thumb-height, 160px);
  margin-bottom: var(--wjs-md);
  border-radius: var(--wjs-posts-thumb-radius, var(--wjs-radius));
  /* The shorthand keeps --wjs-posts-thumb-bg as the whole-surface hook (color OR placeholder
   * gradient); the longhand below then re-decides the image layers. The post's photo arrives as
   * `--wjs-posts-thumb-image` (set inline by the block ONLY when the entry has an image — the
   * var-bridge, not a literal inline background-image, so this rule stays in charge), and
   * `--wjs-posts-thumb-scrim` is the theme's compositing layer painted ABOVE the photo
   * (first background-image layer = topmost). Defaults resolve to `none, <photo or the same
   * placeholder gradient as before>` — pixel-identical to the pre-bridge render. */
  background: var(--wjs-posts-thumb-bg, linear-gradient(135deg, var(--wjs-bg-muted), var(--wjs-surface-highest)));
  background-image: var(--wjs-posts-thumb-scrim, none), var(--wjs-posts-thumb-image, var(--wjs-posts-thumb-bg, linear-gradient(135deg, var(--wjs-bg-muted), var(--wjs-surface-highest))));
  background-size: cover;
  background-position: center;
}
.wjs-block-posts-grid__date, .wp-block-posts-grid__date {
  margin-bottom: var(--wjs-sm);
  font-size: var(--wjs-label);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--wjs-posts-date-color, var(--wjs-color-text-muted));
}
.wjs-block-posts-grid__title, .wp-block-posts-grid__title {
  margin: 0 0 var(--wjs-sm);
  font-size: var(--wjs-posts-title-size, var(--wjs-h6));
  font-weight: var(--wjs-posts-title-weight, 600);
  color: var(--wjs-posts-title-color, var(--wjs-color-text-main));
}
.wjs-block-posts-grid__excerpt, .wp-block-posts-grid__excerpt { margin: 0; font-size: var(--wjs-small); color: var(--wjs-posts-excerpt-color, var(--wjs-color-text-muted)); }
@media (max-width: 767.98px) { .wjs-block-posts-grid, .wp-block-posts-grid { grid-template-columns: 1fr; } }

/* Honest empty states. These blocks list real published entries; when there are none they say so
 * instead of inventing rows — which is exactly what they used to do. */
.wjs-block-posts-grid__empty, .wp-block-posts-grid__empty,
.wjs-block-category-posts__empty, .wp-block-category-posts__empty {
  margin: 0;
  padding: var(--wjs-lg);
  text-align: center;
  font-size: var(--wjs-small);
  color: var(--wjs-color-text-muted);
  background: var(--wjs-posts-bg, var(--wjs-bg-surface));
  border: var(--wjs-posts-border-width, 1px) dashed var(--wjs-posts-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-posts-radius, var(--wjs-radius-lg));
}
.wjs-block-category-posts__note, .wp-block-category-posts__note {
  font-size: var(--wjs-label);
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: var(--wjs-color-text-muted);
}
/* Post titles are links now that they point at real entries. */
.wjs-block-posts-grid__title a, .wp-block-posts-grid__title a,
.wjs-block-category-posts__card-title a, .wp-block-category-posts__card-title a { color: inherit; text-decoration: none; }
.wjs-block-posts-grid__title a:hover, .wp-block-posts-grid__title a:hover,
.wjs-block-category-posts__card-title a:hover, .wp-block-category-posts__card-title a:hover { color: var(--wjs-catposts-link-hover-color, var(--wjs-color-primary)); }

/* ------------------------------------------------------------ CATEGORY POSTS - */
.wjs-block-category-posts__heading, .wp-block-category-posts__heading {
  margin: 0 0 var(--wjs-lg);
  padding-bottom: var(--wjs-catposts-heading-pad, 0);
  font-family: var(--wjs-catposts-heading-family, inherit);
  font-size: var(--wjs-catposts-heading-size, var(--wjs-h5));
  font-weight: var(--wjs-catposts-heading-weight, 700);
  text-transform: var(--wjs-catposts-heading-transform, capitalize);
  letter-spacing: var(--wjs-catposts-heading-tracking, normal);
  background: var(--wjs-catposts-heading-bg, transparent);
  border-bottom: var(--wjs-catposts-heading-border-width, 0) solid var(--wjs-catposts-heading-border-color, var(--wjs-border-subtle));
  color: var(--wjs-catposts-heading-color, var(--wjs-color-text-main));
}
.wjs-block-category-posts__list, .wp-block-category-posts__list { margin: 0; padding: 0; list-style: none; }
.wjs-block-category-posts__item, .wp-block-category-posts__item {
  margin: 0;
  padding: var(--wjs-catposts-item-pad, var(--wjs-md) 0);
  border-bottom: var(--wjs-catposts-border-width, 1px) solid var(--wjs-catposts-border-color, var(--wjs-border-subtle));
}
.wjs-block-category-posts__item:last-child, .wp-block-category-posts__item:last-child { border-bottom: 0; }
.wjs-block-category-posts__link, .wp-block-category-posts__link {
  font-family: var(--wjs-catposts-link-family, inherit);
  font-size: var(--wjs-catposts-link-size, inherit);
  font-weight: var(--wjs-catposts-link-weight, 500);
  color: var(--wjs-catposts-link-color, var(--wjs-color-text-main));
  text-decoration: none;
}
.wjs-block-category-posts__link:hover, .wp-block-category-posts__link:hover { color: var(--wjs-catposts-link-hover-color, var(--wjs-color-primary)); }
.wjs-block-category-posts--grid, .wp-block-category-posts--grid {
  display: grid;
  gap: var(--wjs-catposts-gap, var(--wjs-lg));
  grid-template-columns: repeat(var(--wjs-catposts-columns, 2), minmax(0, 1fr));
}
.wjs-block-category-posts__card, .wp-block-category-posts__card {
  padding: var(--wjs-catposts-pad, var(--wjs-lg));
  background: var(--wjs-catposts-bg, var(--wjs-bg-surface));
  border: var(--wjs-catposts-border-width, 1px) solid var(--wjs-catposts-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-catposts-radius, var(--wjs-radius-lg));
  box-shadow: var(--wjs-catposts-shadow, none);
}
.wjs-block-category-posts__card-title, .wp-block-category-posts__card-title { margin: 0 0 var(--wjs-sm); font-weight: 600; color: var(--wjs-catposts-heading-color, var(--wjs-color-text-main)); }
.wjs-block-category-posts__excerpt, .wp-block-category-posts__excerpt { margin: 0; font-size: var(--wjs-small); color: var(--wjs-color-text-muted); }
@media (max-width: 767.98px) { .wjs-block-category-posts--grid, .wp-block-category-posts--grid { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------- SEARCH BAR - */
.wjs-block-search-wrap, .wp-block-search-wrap { display: flex; width: 100%; justify-content: var(--wjs-search-align, flex-start); }
.wjs-block-search, .wp-block-search {
  display: flex;
  gap: var(--wjs-sm);
  width: 100%;
  max-width: var(--wjs-search-width, 500px);
}
.wjs-block-search__input, .wp-block-search__input {
  flex: 1;
  min-width: 0;
  padding: var(--wjs-search-input-pad, 12px 16px);
  font-family: var(--wjs-search-input-family, inherit);
  font-size: var(--wjs-search-input-size, 1rem);
  font-weight: var(--wjs-search-input-weight, inherit);
  background: var(--wjs-search-input-bg, var(--wjs-bg-surface));
  color: var(--wjs-search-input-color, var(--wjs-color-text-main));
  border: var(--wjs-search-input-border-width, 1px) solid var(--wjs-search-input-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-search-input-radius, var(--wjs-radius));
  box-shadow: var(--wjs-search-input-shadow, none);
}
.wjs-block-search__input::placeholder, .wp-block-search__input::placeholder { color: var(--wjs-search-placeholder-color, var(--wjs-color-text-muted)); }
.wjs-block-search__input:focus, .wp-block-search__input:focus {
  outline: none;
  border-color: var(--wjs-search-focus-color, var(--wjs-color-primary));
  box-shadow: var(--wjs-search-focus-ring, 0 0 0 3px var(--wjs-focus-ring));
}
.wjs-block-search__button, .wp-block-search__button {
  display: inline-flex;
  align-items: center;
  gap: var(--wjs-sm);
  padding: var(--wjs-search-button-pad, 12px 20px);
  font-family: var(--wjs-search-button-family, inherit);
  font-weight: var(--wjs-search-button-weight, 600);
  text-transform: var(--wjs-search-button-transform, none);
  letter-spacing: var(--wjs-search-button-tracking, normal);
  background: var(--wjs-search-button-bg, var(--wjs-color-primary));
  color: var(--wjs-search-button-color, var(--wjs-color-on-primary));
  border: var(--wjs-search-button-border-width, 0) solid var(--wjs-search-button-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-search-button-radius, var(--wjs-radius));
  box-shadow: var(--wjs-search-button-shadow, none);
  cursor: pointer;
  transition: filter var(--wjs-transition);
}
.wjs-block-search__button:hover, .wp-block-search__button:hover { filter: brightness(1.08); }

/* ---------------------------------------------------------------------- HERO - */
.wjs-block-hero, .wp-block-hero {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: var(--wjs-hero-justify, center);
  min-height: var(--wjs-hero-height, 60vh);
  padding: var(--wjs-hero-pad, var(--wjs-2xl) var(--wjs-lg));
  overflow: hidden;
  text-align: var(--wjs-hero-text-align, center);
  color: var(--wjs-hero-color, #fff);
  /* A hero can be a full-bleed band (the default: no frame) or a framed "luminous" card. */
  border: var(--wjs-hero-border-width, 0) solid var(--wjs-hero-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-hero-radius, 0);
  box-shadow: var(--wjs-hero-shadow, none);
  background-color: var(--wjs-hero-bg, var(--wjs-bg-muted));
  /* An uploaded image wins; with none, the gradient pair paints the surface. A theme that sets only
     --wjs-hero-bg gets that colour: both ends of the default gradient fall back to it before the
     muted/canvas pair (the image layer used to paint over it, so the colour never showed). */
  background-image: var(--wjs-hero-bg-image, var(--wjs-hero-gradient, linear-gradient(var(--wjs-hero-gradient-angle, 135deg), var(--wjs-hero-gradient-from, var(--wjs-hero-bg, var(--wjs-bg-muted))), var(--wjs-hero-gradient-to, var(--wjs-hero-bg, var(--wjs-bg-canvas))))));
  background-size: cover;
  background-position: center;
}
.wjs-block-hero__overlay, .wp-block-hero__overlay {
  position: absolute;
  inset: 0;
  background: var(--wjs-hero-overlay-color, #000);
  opacity: var(--wjs-hero-overlay, 0);
  pointer-events: none;
}
.wjs-block-hero__inner, .wp-block-hero__inner { position: relative; z-index: 1; width: 100%; max-width: var(--wjs-hero-measure, 56rem); }
.wjs-block-hero__title, .wp-block-hero__title {
  margin: 0 0 var(--wjs-md);
  font-family: var(--wjs-font-family-heading);
  font-size: var(--wjs-hero-title-size, var(--wjs-h1));
  font-weight: var(--wjs-hero-title-weight, 800);
  line-height: 1.1;
  letter-spacing: var(--wjs-hero-title-tracking, var(--wjs-h1-tracking));
  color: var(--wjs-hero-title-color, inherit);
}
.wjs-block-hero__subtitle, .wp-block-hero__subtitle {
  margin: 0 0 var(--wjs-lg);
  font-size: var(--wjs-hero-subtitle-size, var(--wjs-h6));
  line-height: 1.6;
  color: var(--wjs-hero-subtitle-color, inherit);
  opacity: var(--wjs-hero-subtitle-opacity, 0.9);
}
.wjs-block-hero__actions, .wp-block-hero__actions { display: flex; flex-wrap: wrap; gap: var(--wjs-md); justify-content: var(--wjs-hero-actions-justify, center); }
.wjs-block-hero__button, .wp-block-hero__button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--wjs-sm);
  padding: var(--wjs-hero-button-pad, 12px 20px);
  font-size: var(--wjs-hero-button-size, 15px);
  font-weight: var(--wjs-hero-button-weight, 700);
  line-height: var(--wjs-hero-button-leading, 1);
  text-decoration: none;
  background: var(--wjs-hero-button-bg, var(--wjs-color-primary));
  color: var(--wjs-hero-button-color, var(--wjs-color-on-primary));
  border: 1px solid transparent;
  border-radius: var(--wjs-hero-button-radius, var(--wjs-radius));
  box-shadow: var(--wjs-shadow-2);
  transition: transform 0.15s ease, filter 0.2s ease, background 0.2s ease;
}
.wjs-block-hero__button:hover, .wp-block-hero__button:hover { filter: brightness(1.08); transform: var(--wjs-hero-button-hover-transform, scale(1.03)); color: var(--wjs-hero-button-color, var(--wjs-color-on-primary)); }
.wjs-block-hero__button--outline, .wp-block-hero__button--outline {
  background: var(--wjs-hero-button-outline-bg, transparent);
  border-color: var(--wjs-hero-button-outline-border, var(--wjs-outline));
  color: var(--wjs-hero-button-outline-color, #fff);
  box-shadow: none;
}
.wjs-block-hero__button--outline:hover, .wp-block-hero__button--outline:hover {
  background: var(--wjs-hero-button-outline-hover-bg, rgba(255, 255, 255, 0.08));
  color: var(--wjs-hero-button-outline-color, #fff);
  filter: none;
}

/* --------------------------------------------------------------------- QUOTE - */
.wjs-block-quote, .wp-block-quote {
  margin: 0 0 var(--wjs-lg);
  font-family: var(--wjs-quote-family, inherit);
  font-weight: var(--wjs-quote-weight, inherit);
  letter-spacing: var(--wjs-quote-tracking, inherit);
  font-size: var(--wjs-quote-size, var(--wjs-h5));
  font-style: var(--wjs-quote-style, italic);
  color: var(--wjs-quote-color, var(--wjs-color-text-main));
}
/* The reboot styles bare <blockquote> (bar + padding + size); inside the block the FIGURE owns
 * the frame, so the inner blockquote resets to plain text. */
.wjs-block-quote__body, .wp-block-quote__body { margin: 0; padding: 0; border: 0; font: inherit; color: inherit; }
.wjs-block-quote__cite, .wp-block-quote__cite {
  display: block;
  margin-top: var(--wjs-md);
  font-size: var(--wjs-quote-cite-size, var(--wjs-small));
  font-style: normal;
  color: var(--wjs-quote-cite-color, var(--wjs-color-text-muted));
}
.wjs-block-quote--bar, .wp-block-quote--bar {
  padding-inline-start: var(--wjs-lg);
  border-inline-start: var(--wjs-quote-bar-width, 4px) solid var(--wjs-quote-accent, var(--wjs-color-primary));
}
.wjs-block-quote--large, .wp-block-quote--large { padding: var(--wjs-xl) var(--wjs-lg); text-align: var(--wjs-quote-large-align, center); }
.wjs-block-quote--large .wjs-block-quote__mark, .wp-block-quote--large .wp-block-quote__mark {
  display: block;
  margin-bottom: var(--wjs-md);
  font-size: var(--wjs-quote-mark-size, 40px);
  color: var(--wjs-quote-accent, var(--wjs-color-primary));
  opacity: var(--wjs-quote-mark-opacity, 0.5);
}

/* --------------------------------------------------------------------- TABLE - */
.wjs-block-table, .wp-block-table { width: 100%; overflow-x: auto; }
.wjs-block-table__table, .wp-block-table__table {
  width: 100%;
  border-collapse: collapse;
  text-align: start;
  font-size: var(--wjs-table-size, var(--wjs-small));
}
.wjs-block-table__table th, .wp-block-table__table th {
  padding: var(--wjs-table-cell-pad, var(--wjs-sm) var(--wjs-md));
  font-family: var(--wjs-table-head-family, inherit);
  font-size: var(--wjs-table-head-size, inherit);
  text-transform: var(--wjs-table-head-transform, none);
  letter-spacing: var(--wjs-table-head-tracking, normal);
  font-weight: var(--wjs-table-head-weight, 600);
  color: var(--wjs-table-head-color, var(--wjs-color-text-muted));
  background: var(--wjs-table-head-bg, transparent);
  border-bottom: var(--wjs-table-border-width, 1px) solid var(--wjs-table-border-color, var(--wjs-border-subtle));
}
.wjs-block-table__table td, .wp-block-table__table td {
  padding: var(--wjs-table-cell-pad, var(--wjs-sm) var(--wjs-md));
  color: var(--wjs-table-color, inherit);
  border-bottom: var(--wjs-table-border-width, 1px) solid var(--wjs-table-border-color, var(--wjs-border-subtle));
}
.wjs-block-table--striped tbody tr:nth-child(odd), .wp-block-table--striped tbody tr:nth-child(odd) { background: var(--wjs-table-stripe-bg, var(--wjs-bg-muted)); }

/* ----------------------------------------------------------------- ICON LIST - */
.wjs-block-icon-list, .wp-block-icon-list {
  display: grid;
  gap: var(--wjs-icon-list-gap, var(--wjs-lg));
  grid-template-columns: repeat(var(--wjs-icon-list-columns, 3), minmax(0, 1fr));
}
.wjs-block-icon-list__item, .wp-block-icon-list__item { display: flex; align-items: flex-start; gap: var(--wjs-md); min-width: 0; }
.wjs-block-icon-list__icon, .wp-block-icon-list__icon {
  display: grid;
  place-items: center;
  flex: none;
  width: var(--wjs-icon-list-icon-size, 48px);
  height: var(--wjs-icon-list-icon-size, 48px);
  border-radius: var(--wjs-icon-list-icon-radius, var(--wjs-radius));
  background: var(--wjs-icon-list-icon-bg, var(--wjs-surface-highest));
  color: var(--wjs-icon-list-icon-color, var(--wjs-color-primary));
  font-size: var(--wjs-icon-list-icon-glyph, calc(var(--wjs-icon-list-icon-size, 48px) * 0.42));
}
.wjs-block-icon-list__title, .wp-block-icon-list__title {
  display: block;
  margin-bottom: var(--wjs-xs);
  font-size: var(--wjs-icon-list-title-size, inherit);
  font-weight: var(--wjs-icon-list-title-weight, 700);
  color: var(--wjs-icon-list-title-color, var(--wjs-color-text-main));
}
.wjs-block-icon-list__text, .wp-block-icon-list__text {
  display: block;
  font-size: var(--wjs-icon-list-text-size, var(--wjs-small));
  color: var(--wjs-icon-list-text-color, var(--wjs-color-text-muted));
}
@media (max-width: 767.98px) { .wjs-block-icon-list, .wp-block-icon-list { grid-template-columns: 1fr; } }

/* -------------------------------------------------------------- SOCIAL LINKS - */
.wjs-block-social-links, .wp-block-social-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--wjs-social-gap, var(--wjs-md));
  justify-content: var(--wjs-social-justify, flex-start);
}
.wjs-block-social-links__link, .wp-block-social-links__link {
  display: grid;
  place-items: center;
  width: var(--wjs-social-size, 44px);
  height: var(--wjs-social-size, 44px);
  font-size: calc(var(--wjs-social-size, 44px) * 0.42);
  text-decoration: none;
  border-radius: var(--wjs-social-radius, 50%);
  background: var(--wjs-social-bg, var(--wjs-surface-highest));
  color: var(--wjs-social-color, var(--wjs-color-text-main));
  transition: background var(--wjs-transition), color var(--wjs-transition), transform 0.15s ease;
}
.wjs-block-social-links__link:hover, .wp-block-social-links__link:hover {
  background: var(--wjs-social-hover-bg, var(--wjs-color-primary));
  color: var(--wjs-social-hover-color, var(--wjs-color-on-primary));
  transform: var(--wjs-social-hover-transform, translateY(-2px));
}

/* --------------------------------------------------------------------- STATS - */
.wjs-block-stats, .wp-block-stats {
  display: grid;
  gap: var(--wjs-stats-gap, var(--wjs-lg));
  grid-template-columns: repeat(var(--wjs-stats-columns, 3), minmax(0, 1fr));
}
.wjs-block-stats__item, .wp-block-stats__item {
  padding: var(--wjs-stats-pad, var(--wjs-xl));
  text-align: var(--wjs-stats-align, center);
  background: var(--wjs-stats-bg, var(--wjs-bg-surface));
  border: var(--wjs-stats-border-width, 1px) solid var(--wjs-stats-border-color, var(--wjs-border-subtle));
  border-radius: var(--wjs-stats-radius, var(--wjs-radius-lg));
  box-shadow: var(--wjs-stats-shadow, none);
}
.wjs-block-stats__value, .wp-block-stats__value {
  margin-bottom: var(--wjs-xs);
  font-family: var(--wjs-stats-value-family, var(--wjs-font-family-heading));
  font-size: var(--wjs-stats-value-size, 48px);
  font-weight: var(--wjs-stats-value-weight, 800);
  line-height: var(--wjs-stats-value-leading, 1.1);
  letter-spacing: var(--wjs-stats-value-tracking, var(--wjs-h1-tracking));
  color: var(--wjs-stats-value-color, var(--wjs-primary-fixed));
}
.wjs-block-stats__label, .wp-block-stats__label {
  font-family: var(--wjs-stats-label-family, inherit);
  font-size: var(--wjs-stats-label-size, var(--wjs-small));
  font-weight: var(--wjs-stats-label-weight, inherit);
  line-height: var(--wjs-stats-label-leading, 1);
  text-transform: var(--wjs-stats-label-transform, uppercase);
  letter-spacing: var(--wjs-stats-label-tracking, 0.08em);
  color: var(--wjs-stats-label-color, var(--wjs-color-text-muted));
}
@media (max-width: 767.98px) { .wjs-block-stats, .wp-block-stats { grid-template-columns: 1fr; } }

/* ------------------------------------------------------ CONTENT-AREA WIDTH - *
 * The Grid, Columns and Stats breakpoints above follow the VIEWPORT. A theme with a narrow content
 * column (Vergel's 880px main, a template that puts the page in half of a grid) gives a 4-column grid
 * a desktop viewport and a tablet-sized room: the tracks shrank to ~190px and headings split mid-word
 * ("Multi / lingual"). These rules follow the room the page content actually has — the same tablet /
 * mobile layouts the author already chose, applied when the CONTENT AREA is that narrow. In the
 * default theme the content area at a desktop viewport is wider than 900px, so nothing changes there.
 * `container-type: inline-size` applies no layout containment: position: fixed blocks (Back to top,
 * Side drawer) inside the content still anchor to the viewport. */
.puck-content { container: wjs-content / inline-size; }
@container wjs-content (max-width: 899.98px) {
  .wjs-block-grid__items, .wp-block-grid__items { grid-template-columns: repeat(var(--wjs-grid-columns-tablet, 2), minmax(0, 1fr)); }
  /* Stats has no tablet count of its own: four or more figures go two by two (a 64px "30+" stacked
   * its "+" under the "30" in a 180px track); three still fit side by side. */
  .wjs-block-stats:has(> :nth-child(4)), .wp-block-stats:has(> :nth-child(4)) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container wjs-content (max-width: 599.98px) {
  .wjs-block-grid__items, .wp-block-grid__items { grid-template-columns: repeat(var(--wjs-grid-columns-mobile, 1), minmax(0, 1fr)); }
  .wjs-block-columns, .wp-block-columns { grid-template-columns: 1fr; }
  .wjs-block-stats, .wp-block-stats,
  .wjs-block-stats:has(> :nth-child(4)), .wp-block-stats:has(> :nth-child(4)) { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------- HTML EMBED - */
.wjs-block-html-embed, .wp-block-html-embed { color: var(--wjs-html-color, inherit); }
.wjs-block-html-embed > :first-child, .wp-block-html-embed > :first-child { margin-top: 0; }
.wjs-block-html-embed > :last-child, .wp-block-html-embed > :last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------- FOCUS RING - */
/* Keyboard focus for every control a block renders, in one place. :focus-visible means a mouse
 * click never paints it — only keyboard/AT navigation does. */
.wjs-block-accordion__header:focus-visible, .wp-block-accordion__header:focus-visible,
.wjs-block-tabs__tab:focus-visible, .wp-block-tabs__tab:focus-visible,
.wjs-block-search__button:focus-visible, .wp-block-search__button:focus-visible,
.wjs-block-button__link:focus-visible, .wp-block-button__link:focus-visible,
.wjs-block-hero__button:focus-visible, .wp-block-hero__button:focus-visible,
.wjs-block-pricing__button:focus-visible, .wp-block-pricing__button:focus-visible,
.wjs-block-cta-banner__button:focus-visible, .wp-block-cta-banner__button:focus-visible,
.wjs-block-social-links__link:focus-visible, .wp-block-social-links__link:focus-visible {
  outline: var(--wjs-block-focus-outline, 2px solid var(--wjs-color-primary));
  outline-offset: var(--wjs-block-focus-offset, 2px);
}

/* ═══════════════════════════════════════════════════════════════════════════
 * FORM BLOCK (.wjs-form) — Webflow-parity forms with stored submissions.
 * Same token contract as the .wp-block-* family, with INHERITANCE: every knob
 * is var(--wjs-form-<prop>, <theme sources…>, base) — the fallback chain reads
 * the SEARCH-BLOCK input family, the BUTTON family and the CARD surfaces each
 * theme already defines, so all themes style forms in their own palette with
 * zero per-theme work; --wjs-form-* remains the explicit override hook.
 * ═══════════════════════════════════════════════════════════════════════════ */
.wjs-form {
  display: grid;
  gap: var(--wjs-form-gap, 14px);
  max-width: var(--wjs-form-max-width, 560px);
  font-family: var(--wjs-form-family, var(--wjs-font-family-base, inherit));
}
.wjs-form-field {
  display: grid;
  gap: var(--wjs-form-field-gap, 6px);
}
.wjs-form-field--checkbox {
  display: flex;
  align-items: center;
  gap: var(--wjs-form-field-gap, 8px);
}
.wjs-form-label {
  font-size: var(--wjs-form-label-size, 0.875rem);
  font-weight: var(--wjs-form-label-weight, 600);
  color: var(--wjs-form-label-color, var(--wjs-color-heading, inherit));
}
.wjs-form-required {
  color: var(--wjs-form-required-color, #dc2626);
}
.wjs-form-input,
.wjs-form-textarea,
.wjs-form-select {
  width: 100%;
  font: inherit;
  font-size: var(--wjs-form-input-size, var(--wjs-search-input-size, 1rem));
  color: var(--wjs-form-input-color, var(--wjs-search-input-color, var(--wjs-color-text-main, inherit)));
  background: var(--wjs-form-input-bg, var(--wjs-search-input-bg, var(--wjs-bg-surface, var(--wjs-card-bg, #fff))));
  border: var(--wjs-form-input-border,
    var(--wjs-search-input-border-width, 1px) solid
    var(--wjs-form-input-border-color, var(--wjs-search-input-border-color, var(--wjs-border-subtle, var(--wjs-outline-variant, rgba(0, 0, 0, 0.18))))));
  border-radius: var(--wjs-form-input-radius, var(--wjs-search-input-radius, 8px));
  padding: var(--wjs-form-input-pad, var(--wjs-search-input-pad, 10px 12px));
  box-shadow: var(--wjs-form-input-shadow, var(--wjs-search-input-shadow, none));
}
.wjs-form-input::placeholder,
.wjs-form-textarea::placeholder {
  color: var(--wjs-form-placeholder-color, var(--wjs-search-placeholder-color, inherit));
  opacity: var(--wjs-form-placeholder-opacity, 0.6);
}
.wjs-form-textarea {
  min-height: var(--wjs-form-textarea-height, 120px);
  resize: vertical;
}
.wjs-form-input:focus-visible,
.wjs-form-textarea:focus-visible,
.wjs-form-select:focus-visible {
  outline: var(--wjs-block-focus-outline, 2px solid var(--wjs-color-primary));
  outline-offset: var(--wjs-block-focus-offset, 2px);
}
.wjs-form-input[aria-invalid="true"],
.wjs-form-textarea[aria-invalid="true"] {
  border-color: var(--wjs-form-invalid-color, #dc2626);
}
.wjs-form-checkbox {
  width: var(--wjs-form-checkbox-size, 18px);
  height: var(--wjs-form-checkbox-size, 18px);
  accent-color: var(--wjs-form-accent, var(--wjs-color-primary));
}
.wjs-form-submit {
  justify-self: start;
  font: inherit;
  font-size: var(--wjs-form-submit-size, 1rem);
  font-weight: var(--wjs-form-submit-weight, var(--wjs-button-weight, 600));
  font-family: var(--wjs-form-submit-family, var(--wjs-button-family, inherit));
  color: var(--wjs-form-submit-color, var(--wjs-button-color, var(--wjs-color-on-primary, #fff)));
  background: var(--wjs-form-submit-bg, var(--wjs-button-bg, var(--wjs-color-primary, #2563eb)));
  border: var(--wjs-form-submit-border,
    var(--wjs-button-border-width, 0) solid var(--wjs-button-border-color, transparent));
  border-radius: var(--wjs-form-submit-radius, var(--wjs-button-radius, 9999px));
  padding: var(--wjs-form-submit-pad, var(--wjs-button-pad-y, 12px) var(--wjs-button-pad-x, 28px));
  box-shadow: var(--wjs-form-submit-shadow, var(--wjs-button-shadow, none));
  cursor: pointer;
  transition: opacity 0.15s ease;
}
.wjs-form-submit:hover {
  opacity: var(--wjs-form-submit-hover-opacity, 0.9);
  background: var(--wjs-form-submit-hover-bg, var(--wjs-button-hover-bg, var(--wjs-form-submit-bg, var(--wjs-button-bg, var(--wjs-color-primary, #2563eb)))));
  color: var(--wjs-form-submit-hover-color, var(--wjs-button-hover-color, var(--wjs-form-submit-color, var(--wjs-button-color, #fff))));
}
.wjs-form-submit:disabled {
  opacity: 0.55;
  cursor: default;
}
.wjs-form-status {
  font-size: var(--wjs-form-status-size, 0.9rem);
  min-height: 1.2em;
  margin: 0;
}
.wjs-form-status[data-status="success"] {
  color: var(--wjs-form-success-color, #15803d);
}
.wjs-form-status[data-status="error"] {
  color: var(--wjs-form-error-color, #dc2626);
}

/* ═══════════════════════════════════════════════════════════════════════════
 * RESPONSIVE OVERRIDES (--wjs-r-*) — per-breakpoint Appearance values.
 * The JS side (AppearanceField.appearanceToStyle) resolves the CASCADE and
 * emits, inline on the block: the physical declarations as var() refs plus
 * --wjs-r-<prop> (desktop), --wjs-r-<prop>-tb (tb ?? desktop) and
 * --wjs-r-<prop>-mb (mo ?? tb ?? desktop). These media rules only RE-POINT
 * the base var to the precomputed bucket. !important is load-bearing: the
 * base var lives in the style ATTRIBUTE, which outranks any normal stylesheet
 * declaration — an important author rule is the one thing that beats it.
 * Nothing else writes --wjs-r-*, so no theme collision is possible.
 * ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 1023.98px) {
  .wjs-resp {
    --wjs-r-padY: var(--wjs-r-padY-tb) !important;
    --wjs-r-padX: var(--wjs-r-padX-tb) !important;
    --wjs-r-mt: var(--wjs-r-mt-tb) !important;
    --wjs-r-mb: var(--wjs-r-mb-tb) !important;
    --wjs-r-maxWidth: var(--wjs-r-maxWidth-tb) !important;
    --wjs-r-minHeight: var(--wjs-r-minHeight-tb) !important;
    --wjs-r-fontSize: var(--wjs-r-fontSize-tb) !important;
    --wjs-r-lineHeight: var(--wjs-r-lineHeight-tb) !important;
    --wjs-r-letterSpacing: var(--wjs-r-letterSpacing-tb) !important;
    --wjs-r-align: var(--wjs-r-align-tb) !important;
    --wjs-r-radius: var(--wjs-r-radius-tb) !important;
  }
}
@media (max-width: 767.98px) {
  .wjs-resp {
    --wjs-r-padY: var(--wjs-r-padY-mb) !important;
    --wjs-r-padX: var(--wjs-r-padX-mb) !important;
    --wjs-r-mt: var(--wjs-r-mt-mb) !important;
    --wjs-r-mb: var(--wjs-r-mb-mb) !important;
    --wjs-r-maxWidth: var(--wjs-r-maxWidth-mb) !important;
    --wjs-r-minHeight: var(--wjs-r-minHeight-mb) !important;
    --wjs-r-fontSize: var(--wjs-r-fontSize-mb) !important;
    --wjs-r-lineHeight: var(--wjs-r-lineHeight-mb) !important;
    --wjs-r-letterSpacing: var(--wjs-r-letterSpacing-mb) !important;
    --wjs-r-align: var(--wjs-r-align-mb) !important;
    --wjs-r-radius: var(--wjs-r-radius-mb) !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 * SCROLL-DRIVEN INTERACTIONS (.wjs-scroll) — CSS scroll-timeline effects.
 * Progress follows the element's own journey through the viewport (forwards
 * AND backwards), no JS, no observer. Fully progressive: browsers without
 * animation-timeline simply skip the whole @supports block. Intensity comes
 * as a DISCRETE class (wjs-scroll-amt-10…100, steps of ten) because the
 * shared wrapper only applies className for this field; each step pins
 * --wjs-scroll-amt and the keyframes calc() from it.
 *
 * Coexistence with the ENTRANCE animation (same element): both families use
 * `animation`, and both animate transform, so a combined comma-list would
 * drop the entrance's translate anyway (last name wins per property) and 7
 * of the 12 entrance types ship without keyframes. Decision: when a scroll
 * effect is set, it WINS — the 0,3,0 rules below re-assert the scroll
 * animation over the entrance's 0,2,0 rules once the block reaches its
 * data-wjs-anim="in" state, and the armed (pre-entrance) state is forced
 * visible so scroll blocks can never sit at opacity 0.
 * ═══════════════════════════════════════════════════════════════════════════ */
@supports (animation-timeline: view()) {
  .wjs-scroll {
    animation-name: none;
    animation-duration: 1ms; /* dummy — the view() timeline drives progress */
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
    animation-fill-mode: both;
  }
  .wjs-scroll-parallax { animation-name: wjs-scroll-parallax; }
  .wjs-scroll-fade { animation-name: wjs-scroll-fade; }
  .wjs-scroll-scale { animation-name: wjs-scroll-scale; }
  .wjs-scroll-rotate { animation-name: wjs-scroll-rotate; }

  /* Scroll WINS over the entrance animation once the block is "in", and the
     armed (opacity-0) pre-entrance state never hides a scroll block. */
  .wjs-anim.wjs-scroll[data-wjs-anim="armed"] { opacity: 1; }
  .wjs-anim.wjs-scroll-parallax[data-wjs-anim="in"] {
    animation-name: wjs-scroll-parallax;
    animation-duration: 1ms;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
    animation-fill-mode: both;
  }
  .wjs-anim.wjs-scroll-fade[data-wjs-anim="in"] {
    animation-name: wjs-scroll-fade;
    animation-duration: 1ms;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
    animation-fill-mode: both;
  }
  .wjs-anim.wjs-scroll-scale[data-wjs-anim="in"] {
    animation-name: wjs-scroll-scale;
    animation-duration: 1ms;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
    animation-fill-mode: both;
  }
  .wjs-anim.wjs-scroll-rotate[data-wjs-anim="in"] {
    animation-name: wjs-scroll-rotate;
    animation-duration: 1ms;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
    animation-fill-mode: both;
  }

  .wjs-scroll-amt-10 { --wjs-scroll-amt: 10; }
  .wjs-scroll-amt-20 { --wjs-scroll-amt: 20; }
  .wjs-scroll-amt-30 { --wjs-scroll-amt: 30; }
  .wjs-scroll-amt-40 { --wjs-scroll-amt: 40; }
  .wjs-scroll-amt-50 { --wjs-scroll-amt: 50; }
  .wjs-scroll-amt-60 { --wjs-scroll-amt: 60; }
  .wjs-scroll-amt-70 { --wjs-scroll-amt: 70; }
  .wjs-scroll-amt-80 { --wjs-scroll-amt: 80; }
  .wjs-scroll-amt-90 { --wjs-scroll-amt: 90; }
  .wjs-scroll-amt-100 { --wjs-scroll-amt: 100; }

  @keyframes wjs-scroll-parallax {
    from { transform: translateY(calc(var(--wjs-scroll-amt, 30) * 1px)); }
    to { transform: translateY(calc(var(--wjs-scroll-amt, 30) * -1px)); }
  }
  @keyframes wjs-scroll-fade {
    0% { opacity: calc(1 - var(--wjs-scroll-amt, 30) / 100); }
    35% { opacity: 1; }
    65% { opacity: 1; }
    100% { opacity: calc(1 - var(--wjs-scroll-amt, 30) / 100); }
  }
  @keyframes wjs-scroll-scale {
    0% { transform: scale(calc(1 - var(--wjs-scroll-amt, 30) / 400)); }
    50% { transform: scale(1); }
    100% { transform: scale(calc(1 - var(--wjs-scroll-amt, 30) / 400)); }
  }
  @keyframes wjs-scroll-rotate {
    from { transform: rotate(calc(var(--wjs-scroll-amt, 30) * -0.06deg)); }
    to { transform: rotate(calc(var(--wjs-scroll-amt, 30) * 0.06deg)); }
  }
}
@media (prefers-reduced-motion: reduce) {
  .wjs-scroll,
  .wjs-anim.wjs-scroll[data-wjs-anim="in"] {
    animation: none !important;
  }
}

/* ---------------------------------------------------------------- PAUSA DEL MOVIMIENTO PERPETUO -
 * WCAG 2.2.2 (nivel A): lo que se mueve solo más de cinco segundos tiene que poder pararse. El
 * compilador emite `var(--wjs-ix-play,running)` dentro del atajo `animation` de cada bucle
 * infinito; esta regla es la otra mitad: marcar la casilla pone el token en `paused` en la RAÍZ, y
 * todos los bucles de la página se detienen a la vez. Cero JavaScript — una casilla nativa y
 * `:has()`, que es Baseline en los tres motores.
 *
 * `--wjs-ix-play` NO se declara en `:root` a propósito: sin declarar, cada animación usa el valor
 * de reserva `running` del propio `var()`. Así el token existe solo cuando alguien lo apaga. */
html:has(#wjs-motion-pause:checked) { --wjs-ix-play: paused; }

/* ------------------------------------------------------------------ ESPEJO RTL DEL MOVIMIENTO -
 * `x` y `skewX` son DIRECCIONALES: «entra deslizando desde la izquierda» horneado con signo fijo
 * entra por el lado equivocado en árabe o hebreo, y el movimiento va contra la lectura. El
 * compilador multiplica esos valores por este token, así que UNA regla espeja toda la hoja — sin
 * duplicar un solo `@keyframes` y sin que ninguna cadena del autor toque el CSS.
 *
 * El token NO se declara para LTR a propósito: sin declarar, el `var(--wjs-ix-dir,1)` de cada
 * valor ya vale 1. Así el sitio normal no paga ni una declaración.
 *
 * La lista es TOLERANTE (`:where`): `:dir()` es reciente y el atributo `dir` es lo que escribe
 * nuestro layout raíz; si un motor no entendiera el primero, el segundo sigue aplicando en vez de
 * invalidar la regla entera. */
:where([dir="rtl"], :dir(rtl)) { --wjs-ix-dir: -1; }

.wjs-motion-pause { display: flex; justify-content: center; padding: var(--wjs-sm) 0; }
/* La casilla se oculta VISUALMENTE pero sigue enfocable y anunciable: nada de `display:none`, que
 * la sacaría del orden de tabulación y del árbol de accesibilidad. */
.wjs-motion-pause__input {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}
.wjs-motion-pause__label {
  display: inline-flex; align-items: center; gap: var(--wjs-xs);
  padding: 0.35rem 0.8rem;
  font-size: var(--wjs-text-sm, 0.875rem);
  color: var(--wjs-color-text-muted);
  background: var(--wjs-bg-surface);
  border: var(--wjs-border-width) solid var(--wjs-border-subtle);
  border-radius: var(--wjs-radius-full, 999px);
  cursor: pointer;
}
.wjs-motion-pause__label:hover { color: var(--wjs-color-text-main); border-color: var(--wjs-color-primary); }
/* El anillo de foco vive en la ETIQUETA porque la casilla está oculta visualmente: sin esto, un
 * visitante con teclado no vería nunca dónde está. */
.wjs-motion-pause__input:focus-visible + .wjs-motion-pause__label {
  outline: 2px solid var(--wjs-color-primary);
  outline-offset: 2px;
}
/* Un solo texto a la vez, y el que toca: sin marcar ofrece PAUSAR; marcada, REANUDAR. */
.wjs-motion-pause__off { display: none; }
.wjs-motion-pause__input:checked + .wjs-motion-pause__label .wjs-motion-pause__on { display: none; }
.wjs-motion-pause__input:checked + .wjs-motion-pause__label .wjs-motion-pause__off { display: inline; }

/* ═══════════════════════════════════════════════════════════════════════════
   INTERACTIONS ENGINE (Verso F9) — the static half
   ═══════════════════════════════════════════════════════════════════════════
   Every rule the engine GENERATES already ships inside
   `@media screen and (prefers-reduced-motion: no-preference)`, and both runtime islands check the
   media query before arming anything. This block is the third lock on the same door: it kills any
   `.wjs-ix-*` motion outright when the visitor asked for less of it, whatever the generator did.
   Belt and braces, exactly like the `.wjs-scroll` block above.

   Reduced motion is ABSOLUTE here — there is no per-block or per-site override, and there is not
   going to be one: an accessibility preference set in the operating system is not a checkbox for
   the page author to untick. (Webflow's IX3 makes it optional "conditional playback"; this does
   not.) The content stays fully VISIBLE: only the movement stops, never the block.

   The selector is a prefix match on the class the compiler stamps (`wjs-ix-<hash>`), so it covers
   units that do not exist yet without this file having to know their names. `.wjs-ixw` is the
   per-word span of the split-text target. */
@media (prefers-reduced-motion: reduce) {
  [class*="wjs-ix-"],
  [class*="wjs-ix-"] > *,
  .wjs-ixw,
  .wjs-ixd {
    animation: none !important;
    transition: none !important;
  }
}

/* The per-word span of the split-text target (`target: { kind: "words" }`).
   `inline-block` is not cosmetic and not negotiable: `transform` needs a box, and an inline box has
   none — without this the whole words path silently animates nothing but opacity.

   It is also the reason the split carries an accessibility contract. One box per word is exactly
   what makes a screen reader treat the words as separate chunks, so the renderer emits the spans
   `aria-hidden="true"` and names the CONTAINER with `aria-label` (the full sentence). Never style
   this class in a way that turns the spans back into something a11y-visible.

   No `will-change`: a heading of 40 words would ask the compositor for 40 layers to animate an
   entrance that lasts 600ms. The transform itself is enough for the compositor to promote what it
   actually needs. */
.wjs-ixw {
  display: inline-block;
}

/* The SVG stroke of the draw target (`target: { kind: "svg" }`, engine capability P12).
   THE BLOCK'S CONTRACT: a block that declares its own SVG paths drawable stamps each one with
   class="wjs-ixd" AND pathLength="1". With the length normalized to 1, `stroke-dasharray: 1` here
   plus the compiler-emitted `stroke-dashoffset` (0..1) draw the stroke without measuring anything
   — no getTotalLength(), no per-path JS, and paint-only (zero layout). The custom-HTML sanitizer
   deliberately does NOT allow <svg> (mXSS surface): this ships for first-party/plugin blocks that
   render their own SVG, not for author-pasted markup. */
.wjs-ixd {
  stroke-dasharray: 1;
}

/* ── Particle field ─────────────────────────────────────────────────────────────────────────────
   A full-bleed animated <canvas> background (constellation / particle field). The block is a client
   island (see components/content/ParticleField.tsx) placed as the FIRST child of a container; these
   rules make that container its positioning context and keep the content legible ABOVE the canvas.

   Direction-agnostic on purpose (dir="rtl" mirrors nothing here): `inset`, `inline-size`/`block-size`
   and `z-index` carry no physical left/right. Zero CLS: the layer is out of flow and paints nothing
   until its island hydrates — the served HTML is just an empty <canvas> mount point. */
:where(.wjs-block-section, .wjs-block-columns, .wjs-block-flex-row, .wjs-block-grid):has(.wjs-block-particle-field) {
  position: relative;
}
.wjs-block-particle-field {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.wjs-block-particle-field > canvas {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}
/* The field is placed first inside its container; lift its siblings (the real content) above the
   canvas. `position: relative` with no offset keeps them in flow, so nothing shifts. */
.wjs-block-particle-field ~ * {
  position: relative;
  z-index: 1;
}

/* ── Navigation content blocks: Breadcrumbs / Language switcher / Table of contents ──────────────────
   Placed in PAGE CONTENT (not the masthead), so they paint from the main-text token set with hard-coded
   fallbacks — a theme that omits the tokens still renders. Links/hover use the shared primary token; the
   ToC active state (set by the scroll-spy island) and the breadcrumb/lang current item read as emphasis.
   All colour by hook, no `wp-block-*` (chrome is `--wjs-*` territory). */
.wjs-block-breadcrumbs, .wjs-block-lang-switcher, .wjs-block-toc {
  color: var(--wjs-color-text-main, #374151);
}
.wjs-breadcrumbs__link, .wjs-lang-switcher__link, .wjs-toc__link, .wjs-lang-switcher__summary {
  color: var(--wjs-color-text-muted, #6b7280);
  text-decoration: none;
  transition: color .15s ease;
}
.wjs-breadcrumbs__link:hover, .wjs-lang-switcher__link:hover, .wjs-toc__link:hover,
.wjs-lang-switcher__summary:hover {
  color: var(--wjs-color-primary, #2f6d86);
}
.wjs-breadcrumbs__sep { color: var(--wjs-color-text-muted, #9ca3af); }
.wjs-breadcrumbs__current, .wjs-lang-switcher__current {
  color: var(--wjs-color-text-main, #374151);
  font-weight: 600;
}
/* Active ToC link — toggled by the scroll-spy island; a bar on the inline-start edge marks position. */
.wjs-toc__link--active {
  color: var(--wjs-color-primary, #2f6d86);
  font-weight: 600;
}
.wjs-toc__title { color: var(--wjs-color-heading, var(--wjs-color-text-main, #1f2937)); }

/* SNAP STRIP — a swipeable row of full-width items, for sanitized HTML (shortcode output, imported or
   classic bodies) where neither a <style> block nor layout inline styles survive and no script runs.
   Plugin-neutral: any content may use it. Scrolls natively (touch, trackpad, shift+wheel, keyboard once
   focused); each item snaps into place. `--16x9` crops every item to that frame. */
.wjs-snap-strip {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overscroll-behavior-x: contain;
  gap: 0;
  width: 100%;
  max-width: 900px;
  margin: 2rem auto;
  border-radius: 16px;
  background: #1e293b;
  scrollbar-width: thin;
}
.wjs-snap-strip:focus-visible { outline: 2px solid var(--wjs-color-primary, #2f6d86); outline-offset: 2px; }
.wjs-snap-strip__item { flex: 0 0 100%; scroll-snap-align: start; margin: 0; }
.wjs-snap-strip__item > img { display: block; width: 100%; height: auto; }
.wjs-snap-strip--16x9 .wjs-snap-strip__item > img { aspect-ratio: 16 / 9; height: auto; object-fit: cover; }
.wjs-snap-strip__caption { padding: 0.75rem 1rem; color: #f8fafc; font-size: 0.95rem; }
@media (prefers-reduced-motion: reduce) { .wjs-snap-strip { scroll-behavior: auto; } }
