/**
 * GENERATED FILE -- do not hand-edit.
 *
 * Composed by tokens/generate-css.php from, in order:
 *   - tokens/tokens.json               (custom properties + reduced-motion)
 *   - the design system's rule-bearing parts, carried VERBATIM
 *     (see Web_Jimco_Tokens::CSS_PARTS)
 *   - tokens/parts/elementor-bridge.css
 *   - an --e-global-* alias floor derived from KIT_COLOR_MAP
 *
 * Every @import is hoisted above the first rule: CSS requires it,
 * and a browser drops a late one with no error at all.
 *
 * Regenerate:  php tokens/generate-css.php
 * Verify:      php tokens/generate-css.php --check   (exit 1 if stale)
 * With Kit:    wp web-jimco sync-tokens
 */
@import url("https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400..700;1,9..40,400..700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&display=swap");

/* ===== tokens.json (generated) ===== */
:root {
  --font-sans: "DM Sans","Open Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;
  --font-display: var(--font-sans);
  --font-serif-accent: "Instrument Serif",Georgia,serif;
  --font-body: var(--font-sans);
  --font-mono: ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
  --navy-950: #0D1118;
  --navy-900: #141A23;
  --navy-800: #232A35;
  --navy-700: #2E3745;
  --navy-600: #3C4757;
  --navy-500: #4E5B6E;
  --royal-800: #063F80;
  --royal-700: #0857AC;
  --royal-600: #0B6FDA;
  --royal-500: #2C86E8;
  --royal-300: #8DC0F4;
  --royal-100: #DCEAFA;
  --royal-050: #F0F6FE;
  --steel-700: #5A6B7A;
  --steel-600: #6D8091;
  --steel-500: #7F93A4;
  --steel-300: #AEBDC8;
  --steel-100: #DCE3E9;
  --steel-050: #EEF2F5;
  --white: #FFFFFF;
  --cloud-100: #F4F5F7;
  --cloud-200: #E6E6E6;
  --cloud-300: #D2D4D8;
  --cloud-400: #B4B8BE;
  --success-600: #1F7A4D;
  --warning-600: #8A5B00;
  --danger-600: #B3261E;
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-md: 1.0625rem;
  --text-lg: 1.25rem;
  --text-xl: 1.5rem;
  --text-2xl: clamp(1.75rem,calc(1.5rem + 1.1vw),2.25rem);
  --text-3xl: clamp(2.125rem,calc(1.7rem + 1.8vw),3rem);
  --text-4xl: clamp(2.5rem,calc(1.9rem + 2.6vw),4rem);
  --text-5xl: clamp(3rem,calc(2.1rem + 3.8vw),5.25rem);
  --leading-tight: 1.04;
  --leading-snug: 1.16;
  --leading-normal: 1.35;
  --leading-relaxed: 1.62;
  --leading-loose: 1.75;
  --tracking-display: -0.026em;
  --tracking-heading: -0.017em;
  --tracking-normal: 0em;
  --tracking-wide: 0.02em;
  --tracking-eyebrow: 0.14em;
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-bold: 700;
  --weight-display: 500;
  --measure-prose: 64ch;
  --measure-lede: 46ch;
  --measure-display: 19ch;
  --space-0: 0;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;
  --space-20: 80px;
  --space-24: 96px;
  --space-32: 128px;
  --space-40: 160px;
  --section-y-sm: var(--space-20);
  --section-y: clamp(80px,9vw,128px);
  --section-y-lg: clamp(96px,12vw,160px);
  --radius-none: 0;
  --radius-xs: 2px;
  --radius-sm: 3px;
  --radius-md: 4px;
  --radius-lg: 6px;
  --radius-full: 999px;
  --border-hairline: 1px;
  --border-strong: 2px;
  --rule-color: var(--cloud-200);
  --rule-color-dark: rgba(255,255,255,0.14);
  --keyline-accent: 2px solid var(--royal-600);
  --shadow-none: none;
  --shadow-hairline: 0 0 0 1px rgba(35,42,53,0.08);
  --shadow-xs: 0 1px 2px rgba(13,17,24,0.05);
  --shadow-sm: 0 2px 6px rgba(13,17,24,0.06),0 0 0 1px rgba(35,42,53,0.05);
  --shadow-md: 0 8px 20px -6px rgba(13,17,24,0.12),0 0 0 1px rgba(35,42,53,0.05);
  --shadow-lg: 0 22px 48px -16px rgba(13,17,24,0.20),0 0 0 1px rgba(35,42,53,0.05);
  --shadow-focus: 0 0 0 3px rgba(11,111,218,0.35);
  --scrim-navy: linear-gradient(180deg,rgba(13,17,24,0.72) 0%,rgba(13,17,24,0.40) 45%,rgba(13,17,24,0.78) 100%);
  --scrim-navy-side: linear-gradient(90deg,rgba(13,17,24,0.86) 0%,rgba(13,17,24,0.55) 55%,rgba(13,17,24,0.15) 100%);
  --z-base: 0;
  --z-raised: 10;
  --z-sticky: 100;
  --z-header: 200;
  --z-overlay: 900;
  --z-modal: 1000;
  --photo-mono: grayscale(1) contrast(1.08) brightness(1.02);
  --photo-mono-backlit: grayscale(1) contrast(1.16) brightness(1.08);
  --photo-mono-deep: grayscale(1) contrast(1.2) brightness(0.92);
  --photo-ratio-wide: 16/9;
  --photo-ratio-landscape: 3/2;
  --photo-ratio-portrait: 4/5;
  --photo-ratio-square: 1/1;
  --ease-standard: cubic-bezier(0.22,0.61,0.36,1);
  --ease-entrance: cubic-bezier(0.16,0.84,0.44,1);
  --ease-exit: cubic-bezier(0.4,0,1,1);
  --dur-instant: 80ms;
  --dur-fast: 160ms;
  --dur-base: 240ms;
  --dur-slow: 420ms;
  --dur-reveal: 640ms;
  --reveal-distance: 18px;
  --reveal-stagger: 80ms;
  --container-max: 1240px;
  --container-wide: 1440px;
  --container-prose: 720px;
  --gutter: clamp(20px,5vw,64px);
  --grid-columns: 12;
  --grid-gap: clamp(16px,2vw,32px);
  --header-height: 80px;
  --header-height-compact: 64px;
  --bp-sm: 520px;
  --bp-md: 768px;
  --bp-lg: 1024px;
  --surface-page: var(--white);
  --surface-muted: var(--cloud-100);
  --surface-card: var(--white);
  --surface-inset: var(--royal-050);
  --surface-steel: var(--steel-050);
  --surface-steel-strong: var(--steel-100);
  --surface-inverse: var(--navy-800);
  --surface-inverse-deep: var(--navy-950);
  --text-strong: var(--navy-900);
  --text-body: var(--navy-700);
  --text-muted: var(--steel-700);
  --text-subtle: var(--steel-700);
  --text-accent: var(--royal-700);
  --text-steel: var(--steel-600);
  --text-steel-quiet: var(--steel-700);
  --text-steel-on-inverse: var(--steel-300);
  --text-on-inverse: var(--white);
  --text-on-inverse-muted: rgba(255,255,255,0.72);
  --text-on-accent: var(--white);
  --border-subtle: var(--cloud-200);
  --border-steel: var(--steel-300);
  --border-default: var(--cloud-300);
  --border-strong-color: var(--navy-800);
  --border-on-inverse: rgba(255,255,255,0.16);
  --action-primary: var(--navy-800);
  --action-primary-hover: var(--navy-900);
  --action-primary-active: var(--navy-950);
  --action-accent: var(--royal-600);
  --action-accent-hover: var(--royal-700);
  --action-accent-active: var(--royal-800);
  --action-quiet-hover: var(--cloud-100);
  --focus-ring: var(--royal-600);
  --link-color: var(--royal-700);
  --link-hover: var(--royal-800);
  --link-on-inverse: var(--royal-300);
  --link-on-inverse-hover: var(--white);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-instant: 0ms;
    --dur-fast: 0ms;
    --dur-base: 0ms;
    --dur-slow: 0ms;
    --dur-reveal: 0ms;
    --reveal-distance: 0px;
    --reveal-stagger: 0ms;
  }
}

/* ===== responsive ===== */
/* Breakpoints and the responsive layout utilities the UI kit composes with.
   Mobile and desktop carry equal priority, so every multi-column arrangement
   in this system collapses rather than compressing. */
:root{
  --bp-sm:520px;  /* @kind spacing */
  --bp-md:768px;  /* @kind spacing */
  --bp-lg:1024px; /* @kind spacing */
}

/* Two-column split: narrow heading column against a wider content column. */
.jc-split{display:grid;gap:var(--space-16);align-items:start}
@media (max-width:1023px){.jc-split{grid-template-columns:1fr !important;gap:var(--space-10)}}

/* Three-up card grid — two across on tablet, one on phone. */
@media (max-width:1023px){.jc-grid-3{grid-template-columns:repeat(2,minmax(0,1fr)) !important}}
@media (max-width:767px){.jc-grid-3{grid-template-columns:1fr !important}}

/* Two-up grid. */
@media (max-width:767px){.jc-grid-2{grid-template-columns:1fr !important}}

/* Stat row: never let a figure wrap mid-label. */
.jc-stats{grid-template-columns:repeat(3,minmax(0,1fr)) !important}
@media (max-width:1023px){.jc-stats{grid-template-columns:repeat(2,minmax(0,1fr)) !important}.jc-stats [data-stat-figure]{font-size:var(--text-2xl) !important}}
@media (max-width:519px){.jc-stats{grid-template-columns:1fr !important}}

/* Hero: the framed photograph moves below the copy. */
@media (max-width:1023px){.jc-hero{grid-template-columns:1fr !important;gap:var(--space-10) !important}}

/* Header: primary nav collapses out below tablet, leaving mark + booking CTA. */
@media (max-width:767px){.jc-nav-links{display:none !important}}

/* Footer columns stack. */
@media (max-width:767px){.jc-footer-grid{grid-template-columns:1fr !important;gap:var(--space-10) !important}}

/* Sticky side columns release once the layout is single-column. */
@media (max-width:1023px){.jc-unstick{position:static !important}}

/* ===== base ===== */
/* Minimal element defaults so a bare page already reads as JIM & Co. */
:root{color-scheme:light}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--surface-page);color:var(--text-body);font-family:var(--font-body);font-size:var(--text-md);line-height:var(--leading-relaxed);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
h1,h2,h3,h4,h5,h6{margin:0;color:var(--text-strong);font-weight:var(--weight-bold);line-height:var(--leading-snug);letter-spacing:var(--tracking-heading);text-wrap:balance}
h1{font-size:var(--text-4xl);line-height:var(--leading-tight);letter-spacing:var(--tracking-display)}
h2{font-size:var(--text-3xl);letter-spacing:var(--tracking-display)}
h3{font-size:var(--text-xl)}
p{margin:0;text-wrap:pretty}
/* Accent serif. Apply to ONE phrase inside a heading or pull quote — never a whole heading.
   A heading containing an accent drops to --weight-display; Bold overpowers the serif at 400. */
em.jc-accent{font-family:var(--font-serif-accent);font-style:italic;font-weight:var(--weight-regular);letter-spacing:0;color:var(--text-steel-quiet)}
/* steel-600 is 4.08:1 — AA only at large sizes. Headings are >=24px by construction, so the
   accent brightens there and nowhere else. An accent dropped into smaller text stays at
   steel-700 (5.1:1) automatically rather than depending on the author reading a comment. */
h1 em.jc-accent,h2 em.jc-accent,h3 em.jc-accent{color:var(--text-steel)}
.jc-hero em.jc-accent,[data-tone^="inverse"] em.jc-accent{color:var(--text-steel-on-inverse)}
h1:has(em.jc-accent),h2:has(em.jc-accent),h3:has(em.jc-accent){font-weight:var(--weight-display)}
a{color:var(--link-color);text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px;transition:color var(--dur-fast) var(--ease-standard)}
a:hover{color:var(--link-hover)}
:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px;border-radius:var(--radius-xs)}
img{max-width:100%;display:block}
::selection{background:var(--royal-100);color:var(--navy-900)}

/* ===== components ===== */
/* JIM & Co. — component layer
 *
 * Class-based equivalents of the React components in this directory. Authored
 * ONCE here so every deliverable's page CSS holds page-specific layout only —
 * five mockups re-implementing .btn is five diverging buttons.
 *
 * Source of truth for each block is the sibling .jsx inline styles. Where a
 * component composes another (ServiceCard renders Card with `keyline`), the
 * classes compose the same way: .jc-card .jc-card--keyline .jc-servicecard.
 * If you change a .jsx, change its block here in the same commit.
 *
 * Naming: .jc-<block> / .jc-<block>__<part> / .jc-<block>--<variant>.
 * Every value is a token. Nothing here may name an Elementor class.
 *
 * Base grid declarations for .jc-split, .jc-grid-3, .jc-grid-2, .jc-stats,
 * .jc-hero, .jc-nav-links and .jc-footer-grid live here; tokens/responsive.css
 * carries their collapse rules and is imported before this file.
 */

/* ── Container ─────────────────────────────────────────────── */
.jc-container{max-width:var(--container-max);margin-inline:auto;padding-inline:var(--gutter)}
.jc-container--bleed{max-width:var(--container-wide)}
.jc-container--prose{max-width:var(--container-prose)}

/* ── Section — mirrors Section.jsx tones + sizes ───────────── */
.jc-section{padding-block:var(--section-y)}
.jc-section--compact{padding-block:var(--section-y-sm)}
.jc-section--tall{padding-block:var(--section-y-lg)}
.jc-section{background:var(--surface-page);color:var(--text-body)}
.jc-section--muted{background:var(--surface-muted)}
.jc-section--steel{background:var(--surface-steel)}
.jc-section--steel-strong{background:var(--surface-steel-strong)}
.jc-section--inset{background:var(--surface-inset)}
.jc-section--inverse{background:var(--surface-inverse);color:var(--text-on-inverse-muted)}
.jc-section--inverse-deep{background:var(--surface-inverse-deep);color:var(--text-on-inverse-muted)}

/* ── Eyebrow — Eyebrow.jsx. 28px rule is literal in source. ── */
.jc-eyebrow{display:inline-flex;align-items:center;gap:var(--space-3);font-family:var(--font-sans);font-size:var(--text-xs);font-weight:var(--weight-bold);letter-spacing:var(--tracking-eyebrow);text-transform:uppercase;color:var(--text-muted)}
.jc-eyebrow::before{content:"";width:28px;height:var(--border-strong);background:var(--royal-600);flex:0 0 auto}
.jc-eyebrow--norule::before{display:none}
.jc-eyebrow--accent{color:var(--text-accent)}
[data-tone^="inverse"] .jc-eyebrow{color:rgba(255,255,255,0.68)}
[data-tone^="inverse"] .jc-eyebrow::before{background:var(--royal-300)}

/* ── Button — Button.jsx. Padding/min-height are literal px in
      the source; there is no token for 9/13/17px or 44/48/58px.
      --sm's min-height is 44px, not the 38px Button.jsx originally
      carried: at 38 it failed the 44px minimum touch target, and it is
      the header CTA on every page. Raised in both places together
      (2026-09-15) — see readme.md §Accessibility.                 */
.jc-btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--space-3);font-family:var(--font-sans);font-weight:var(--weight-bold);letter-spacing:0.005em;line-height:1;text-decoration:none;cursor:pointer;border-radius:var(--radius-md);border:var(--border-hairline) solid transparent;transition:background var(--dur-base) var(--ease-standard),color var(--dur-base) var(--ease-standard),border-color var(--dur-base) var(--ease-standard),transform var(--dur-fast) var(--ease-standard)}
.jc-btn:active{transform:translateY(1px)}
.jc-btn--sm{padding:9px 16px;font-size:var(--text-sm);min-height:44px}
.jc-btn--md{padding:13px 24px;font-size:var(--text-base);min-height:48px}
.jc-btn--lg{padding:17px 32px;font-size:var(--text-lg);min-height:58px}
.jc-btn--full{width:100%}
.jc-btn--primary{background:var(--action-primary);color:var(--white);border-color:var(--action-primary)}
.jc-btn--primary:hover{background:var(--action-primary-hover);border-color:var(--action-primary-hover);color:var(--white)}
.jc-btn--accent{background:var(--action-accent);color:var(--white);border-color:var(--action-accent)}
.jc-btn--accent:hover{background:var(--action-accent-hover);border-color:var(--action-accent-hover);color:var(--white)}
.jc-btn--secondary{background:transparent;color:var(--navy-800);border-color:var(--navy-800)}
.jc-btn--secondary:hover{background:var(--navy-800);color:var(--white)}
.jc-btn--ghost{background:transparent;color:var(--navy-800)}
.jc-btn--ghost:hover{background:var(--action-quiet-hover);color:var(--navy-800)}
.jc-btn--inverse{background:var(--white);color:var(--navy-900);border-color:var(--white)}
.jc-btn--inverse:hover{background:var(--cloud-100);border-color:var(--cloud-100);color:var(--navy-900)}
.jc-btn--inverse-outline{background:transparent;color:var(--white);border-color:rgba(255,255,255,0.42)}
.jc-btn--inverse-outline:hover{background:rgba(255,255,255,0.10);border-color:rgba(255,255,255,0.72);color:var(--white)}
.jc-btn__icon{display:inline-block;transition:transform var(--dur-base) var(--ease-standard)}
.jc-btn:hover .jc-btn__icon{transform:translateX(3px)}

/* ── Card — Card.jsx ──────────────────────────────────────── */
.jc-card{position:relative;border-radius:var(--radius-md);padding:var(--space-8);background:var(--surface-card);border:var(--border-hairline) solid var(--border-subtle);box-shadow:var(--shadow-xs);transition:box-shadow var(--dur-base) var(--ease-standard),transform var(--dur-base) var(--ease-standard),border-color var(--dur-base) var(--ease-standard)}
.jc-card--muted{background:var(--surface-muted);border-color:transparent;box-shadow:none}
.jc-card--steel{background:var(--surface-steel);border-color:var(--steel-100);box-shadow:none}
.jc-card--inset{background:var(--surface-inset);border-color:var(--royal-100);box-shadow:none}
.jc-card--inverse{background:var(--navy-700);border-color:var(--border-on-inverse);box-shadow:none;color:var(--text-on-inverse)}
.jc-card--outline{background:transparent;border-color:var(--border-default);box-shadow:none}
.jc-card--interactive:hover{box-shadow:var(--shadow-md);transform:translateY(-2px);border-color:var(--steel-300)}
/* The accent mark: 48x2px royal keyline, flush top-left. Never a side border. */
.jc-card--keyline::before{content:"";position:absolute;top:0;left:0;width:48px;height:var(--border-strong);background:var(--royal-600)}

/* ── SectionHeading — SectionHeading.jsx ──────────────────── */
.jc-heading{display:grid;gap:var(--space-5);justify-items:start;text-align:start}
.jc-heading--center{justify-items:center;text-align:center}
.jc-heading__title{max-width:var(--measure-display);font-size:var(--text-3xl);line-height:var(--leading-snug);letter-spacing:var(--tracking-display);color:var(--text-strong)}
.jc-heading__lede{max-width:var(--measure-lede);font-size:var(--text-lg);line-height:var(--leading-relaxed);color:var(--text-muted)}
[data-tone^="inverse"] .jc-heading__title{color:var(--white)}
[data-tone^="inverse"] .jc-heading__lede{color:var(--text-on-inverse-muted)}

/* ── Stat — Stat.jsx. Figure is steel-600: AA at large sizes
      only, and --text-4xl/--text-2xl are both >=24px.
      REQUIRED HOOK: the figure span must carry the data-stat-figure
      attribute as well as the class —
        <span class="jc-stat__figure" data-stat-figure>
      tokens/responsive.css keys the below-lg downsize off the ATTRIBUTE
      (.jc-stats [data-stat-figure]), matching what Stat.jsx emits. With the
      class alone the figure stays at --text-4xl on tablet, wraps mid-label
      and pushes the third stat onto its own row. Do not "fix" this by
      retargeting responsive.css; that is the token layer and the React
      component already satisfies it.                              */
.jc-stat{display:grid;gap:var(--space-2)}
.jc-stat__figure{font-family:var(--font-display);font-size:var(--text-4xl);font-weight:var(--weight-bold);letter-spacing:var(--tracking-display);line-height:var(--leading-tight);color:var(--text-steel)}
.jc-stat--strong .jc-stat__figure{color:var(--text-strong)}
.jc-stat__label{font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--text-muted);max-width:24ch}
[data-tone^="inverse"] .jc-stat__figure{color:var(--text-steel-on-inverse)}
[data-tone^="inverse"] .jc-stat--strong .jc-stat__figure{color:var(--white)}
[data-tone^="inverse"] .jc-stat__label{color:var(--text-on-inverse-muted)}

/* ── Divider — Divider.jsx ────────────────────────────────── */
.jc-rule{border:0;height:var(--border-hairline);width:100%;background:var(--rule-color);margin-block:var(--space-8)}
.jc-rule--accent{height:var(--border-strong);width:48px;background:var(--royal-600)}
[data-tone^="inverse"] .jc-rule{background:var(--rule-color-dark)}

/* ── Prose ────────────────────────────────────────────────── */
.jc-lede{font-size:var(--text-lg);line-height:var(--leading-relaxed);color:var(--text-body);max-width:var(--measure-lede)}
.jc-prose{font-size:var(--text-md);line-height:var(--leading-relaxed);color:var(--text-body);max-width:var(--measure-prose)}
.jc-prose--muted{color:var(--text-muted)}
[data-tone^="inverse"] .jc-lede,[data-tone^="inverse"] .jc-prose{color:var(--text-on-inverse-muted)}

/* ── Hero — Hero.jsx, variant="full" ──────────────────────── */
.jc-herowrap{position:relative;background:var(--surface-inverse-deep);color:var(--white);overflow:hidden}
.jc-herowrap__media{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;filter:var(--photo-mono-deep)}
/* register="warm" — the full-bleed counterpart of .jc-frame--warm. */
.jc-herowrap__media--warm{filter:none}
/* The system's only permitted gradients are the two photo scrims, and only
   over a real photograph. Never a decorative gradient. */
.jc-herowrap__scrim{position:absolute;inset:0;background:var(--scrim-navy-side)}
.jc-hero{position:relative;display:grid;grid-template-columns:1fr;gap:var(--space-16);align-items:center;max-width:var(--container-max);margin-inline:auto;padding:var(--section-y-lg) var(--gutter);min-height:640px}
.jc-hero--split{grid-template-columns:minmax(0,1.05fr) minmax(0,0.95fr)}
.jc-hero__copy{display:grid;gap:var(--space-6);justify-items:start;max-width:min(680px,66%)}
.jc-hero--split .jc-hero__copy{max-width:none}
.jc-hero__title{font-size:var(--text-5xl);line-height:var(--leading-tight);letter-spacing:var(--tracking-display);color:var(--white);max-width:var(--measure-display)}
.jc-hero__lede{font-size:var(--text-lg);line-height:var(--leading-relaxed);color:var(--text-on-inverse-muted);max-width:var(--measure-lede)}
.jc-hero__actions{display:flex;flex-wrap:wrap;gap:var(--space-4);margin-top:var(--space-2)}
@media (max-width:1023px){.jc-hero__copy{max-width:none}}
@media (max-width:519px){.jc-hero__actions{width:100%}.jc-hero__actions .jc-btn{width:100%}}

/* ── PressCycle ────────────────────────────────────────────────
      "As featured in" strip. ONE masthead at a time: each outlet is a
      frame, all frames stacked in a single grid cell, crossfading in
      sequence. Only opacity animates — no layout thrash, no JS.

      NEW PATTERN. The system's only other animation is the one-shot
      scroll reveal; this is its first continuous loop. It carries no
      meaning (the same outlets are credited whether it runs or not),
      so it satisfies motion.css's "ambient only, never explanation"
      rule, but it is a precedent worth a deliberate sign-off.

      NO TOKEN EXISTS for a loop dwell — motion.css tops out at
      --dur-reveal (640ms) for one-shot motion. --jc-presscycle-cycle
      is declared here as 25600ms (40x --dur-reveal); divided by the
      frame count that is ~5.1s per masthead at five frames. If a
      loop-duration token is added, consume it here and delete the
      local value.

      MONO TREATMENT. The supplied files are all white-on-transparent
      variants, built for dark backgrounds. On a light surface
      brightness(0) flattens each to a single black tone, which
      opacity then softens to sit level with --steel-700 — one
      treatment for every file regardless of its source colour, and no
      second asset set. On an inverse surface the files are used as
      supplied.

      FRAME COUNT IS A CLASS. A strip of N mastheads needs
      .jc-presscycle--N: the keyframe set holds each frame for ~1/N of
      the cycle and the delay ladder offsets the nth frame by
      (n-1)/N. Sets for 2 through 7 are defined below. Adding or
      removing an outlet means changing that modifier to match, or the
      strip will show gaps or overlaps. */
.jc-presscycle{--jc-presscycle-cycle:25600ms /* @kind other */;display:grid;gap:var(--space-5)}
.jc-presscycle__label{font-size:var(--text-xs);font-weight:var(--weight-bold);letter-spacing:var(--tracking-eyebrow);text-transform:uppercase;color:var(--text-subtle)}
.jc-presscycle__stage{display:grid;align-items:center;min-height:var(--space-16)}
.jc-presscycle__frame{grid-area:1/1;display:flex;align-items:center;opacity:0;animation-duration:var(--jc-presscycle-cycle);animation-timing-function:var(--ease-standard);animation-iteration-count:infinite}
.jc-presscycle--2 .jc-presscycle__frame{animation-name:jc-presscycle-2}
.jc-presscycle--3 .jc-presscycle__frame{animation-name:jc-presscycle-3}
.jc-presscycle--4 .jc-presscycle__frame{animation-name:jc-presscycle-4}
.jc-presscycle--5 .jc-presscycle__frame{animation-name:jc-presscycle-5}
.jc-presscycle--6 .jc-presscycle__frame{animation-name:jc-presscycle-6}
.jc-presscycle--7 .jc-presscycle__frame{animation-name:jc-presscycle-7}
.jc-presscycle--2 .jc-presscycle__frame:nth-child(2){animation-delay:calc(var(--jc-presscycle-cycle) * 0.5)}
.jc-presscycle--3 .jc-presscycle__frame:nth-child(2){animation-delay:calc(var(--jc-presscycle-cycle) * 0.3333)}
.jc-presscycle--3 .jc-presscycle__frame:nth-child(3){animation-delay:calc(var(--jc-presscycle-cycle) * 0.6667)}
.jc-presscycle--4 .jc-presscycle__frame:nth-child(2){animation-delay:calc(var(--jc-presscycle-cycle) * 0.25)}
.jc-presscycle--4 .jc-presscycle__frame:nth-child(3){animation-delay:calc(var(--jc-presscycle-cycle) * 0.5)}
.jc-presscycle--4 .jc-presscycle__frame:nth-child(4){animation-delay:calc(var(--jc-presscycle-cycle) * 0.75)}
.jc-presscycle--5 .jc-presscycle__frame:nth-child(2){animation-delay:calc(var(--jc-presscycle-cycle) * 0.2)}
.jc-presscycle--5 .jc-presscycle__frame:nth-child(3){animation-delay:calc(var(--jc-presscycle-cycle) * 0.4)}
.jc-presscycle--5 .jc-presscycle__frame:nth-child(4){animation-delay:calc(var(--jc-presscycle-cycle) * 0.6)}
.jc-presscycle--5 .jc-presscycle__frame:nth-child(5){animation-delay:calc(var(--jc-presscycle-cycle) * 0.8)}
.jc-presscycle--6 .jc-presscycle__frame:nth-child(2){animation-delay:calc(var(--jc-presscycle-cycle) * 0.1667)}
.jc-presscycle--6 .jc-presscycle__frame:nth-child(3){animation-delay:calc(var(--jc-presscycle-cycle) * 0.3333)}
.jc-presscycle--6 .jc-presscycle__frame:nth-child(4){animation-delay:calc(var(--jc-presscycle-cycle) * 0.5)}
.jc-presscycle--6 .jc-presscycle__frame:nth-child(5){animation-delay:calc(var(--jc-presscycle-cycle) * 0.6667)}
.jc-presscycle--6 .jc-presscycle__frame:nth-child(6){animation-delay:calc(var(--jc-presscycle-cycle) * 0.8333)}
.jc-presscycle--7 .jc-presscycle__frame:nth-child(2){animation-delay:calc(var(--jc-presscycle-cycle) * 0.1429)}
.jc-presscycle--7 .jc-presscycle__frame:nth-child(3){animation-delay:calc(var(--jc-presscycle-cycle) * 0.2857)}
.jc-presscycle--7 .jc-presscycle__frame:nth-child(4){animation-delay:calc(var(--jc-presscycle-cycle) * 0.4286)}
.jc-presscycle--7 .jc-presscycle__frame:nth-child(5){animation-delay:calc(var(--jc-presscycle-cycle) * 0.5714)}
.jc-presscycle--7 .jc-presscycle__frame:nth-child(6){animation-delay:calc(var(--jc-presscycle-cycle) * 0.7143)}
.jc-presscycle--7 .jc-presscycle__frame:nth-child(7){animation-delay:calc(var(--jc-presscycle-cycle) * 0.8571)}
@keyframes jc-presscycle-2{0%{opacity:0}1.2%{opacity:1}48.8%{opacity:1}50%{opacity:0}100%{opacity:0}}
@keyframes jc-presscycle-3{0%{opacity:0}1.2%{opacity:1}32.1%{opacity:1}33.33%{opacity:0}100%{opacity:0}}
@keyframes jc-presscycle-4{0%{opacity:0}1.2%{opacity:1}23.8%{opacity:1}25%{opacity:0}100%{opacity:0}}
@keyframes jc-presscycle-5{0%{opacity:0}1.2%{opacity:1}18.8%{opacity:1}20%{opacity:0}100%{opacity:0}}
@keyframes jc-presscycle-6{0%{opacity:0}1.2%{opacity:1}15.4%{opacity:1}16.67%{opacity:0}100%{opacity:0}}
@keyframes jc-presscycle-7{0%{opacity:0}1.2%{opacity:1}13%{opacity:1}14.29%{opacity:0}100%{opacity:0}}
/* Normalize every masthead to the SAME optical height and let width vary — the
   standard treatment for a masthead strip, and the only way a 2474x360 wordmark
   and a 74x28 one read as equals. Use `height`, NOT `max-height`: max-height
   only constrains a replaced element, it never upscales past intrinsic size, so
   a short file sits at its natural size while tall ones clamp to the cap. And
   do NOT cap max-width in px — a px cap governs the wide wordmarks instead of
   the height, reintroducing mismatched heights. Widest ratio here is ~7:1, so
   56px tall resolves to ~400px, inside the ~466px column. */
.jc-presscycle__mark{height:56px;width:auto;max-width:100%;object-fit:contain;filter:brightness(0);opacity:0.62}
/* Fallback for an outlet with no masthead file: set the name as type instead. */
.jc-presscycle__outlet{font-size:var(--text-base);font-weight:var(--weight-bold);letter-spacing:var(--tracking-heading);color:var(--steel-700);white-space:nowrap}
[data-tone^="inverse"] .jc-presscycle__label{color:rgba(255,255,255,0.56)}
[data-tone^="inverse"] .jc-presscycle__outlet{color:rgba(255,255,255,0.78)}
[data-tone^="inverse"] .jc-presscycle__mark{filter:none;opacity:0.85}
/* Reduced motion: stop the loop and show the first masthead only. Zeroing the
   duration via the motion tokens is not enough — an infinite animation at 0s
   still jumps. */
@media (prefers-reduced-motion:reduce){
  .jc-presscycle__frame{animation:none}
  .jc-presscycle__frame:nth-child(1){opacity:1}
  .jc-presscycle__frame:nth-child(n+2){display:none}
}

/* ── LogoWall — LogoWall.jsx. 108px cell is literal in source. ─ */
.jc-logowall{display:grid;gap:var(--space-8)}
.jc-logowall__label{font-size:var(--text-xs);font-weight:var(--weight-bold);letter-spacing:var(--tracking-eyebrow);text-transform:uppercase;color:var(--text-subtle);text-align:center}
.jc-logowall__list{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));border-top:var(--border-hairline) solid var(--border-subtle);border-left:var(--border-hairline) solid var(--border-subtle)}
.jc-logowall__list--3{grid-template-columns:repeat(3,minmax(0,1fr))}
/* 4 and 6 exist because the widget's Columns control offers 3-6. Without a
   class for every value the widget falls back to an inline grid-template-
   columns, and an inline style beats the collapse rules below - silently
   producing a wall that never reflows on mobile. */
.jc-logowall__list--4{grid-template-columns:repeat(4,minmax(0,1fr))}
.jc-logowall__list--6{grid-template-columns:repeat(6,minmax(0,1fr))}
/* Image logos. The wordmark path needs no rule; this one does. Capped well
   under the 108px cell so cell height stays driven by the grid, not by art. */
.jc-logowall__logo{max-height:40px;max-width:100%;width:auto;object-fit:contain;filter:var(--photo-mono);opacity:.72}
.jc-logowall__item{display:grid;place-items:center;min-height:108px;padding:var(--space-6);border-right:var(--border-hairline) solid var(--border-subtle);border-bottom:var(--border-hairline) solid var(--border-subtle);font-size:var(--text-lg);font-weight:var(--weight-bold);letter-spacing:var(--tracking-heading);color:var(--steel-700)}
[data-tone^="inverse"] .jc-logowall__label{color:rgba(255,255,255,0.56)}
[data-tone^="inverse"] .jc-logowall__list,[data-tone^="inverse"] .jc-logowall__item{border-color:var(--border-on-inverse)}
[data-tone^="inverse"] .jc-logowall__item{color:rgba(255,255,255,0.80)}
/* Knock a logo to flat white on navy - greyscale alone leaves a dark mark. */
[data-tone^="inverse"] .jc-logowall__logo{filter:brightness(0) invert(1);opacity:.80}
@media (max-width:1023px){.jc-logowall__list--6{grid-template-columns:repeat(3,minmax(0,1fr))}.jc-logowall__list--4{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:767px){.jc-logowall__list,.jc-logowall__list--3,.jc-logowall__list--4,.jc-logowall__list--6{grid-template-columns:1fr}}

/* ── ServiceCard — ServiceCard.jsx (composes Card keyline) ── */
.jc-servicecard{display:grid;gap:var(--space-5);align-content:start;height:100%}
.jc-servicecard__index{font-size:var(--text-sm);font-weight:var(--weight-bold);letter-spacing:var(--tracking-eyebrow);color:var(--text-steel-quiet)}
.jc-servicecard__title{font-size:var(--text-xl);letter-spacing:var(--tracking-heading);color:var(--text-strong)}
.jc-servicecard__summary{font-size:var(--text-base);line-height:var(--leading-relaxed);color:var(--text-muted)}
.jc-servicecard__link{display:inline-flex;align-items:center;gap:var(--space-2);margin-top:var(--space-1);font-size:var(--text-sm);font-weight:var(--weight-bold);color:var(--link-color);text-decoration:none}
.jc-servicecard__link:hover{color:var(--link-hover)}
.jc-servicecard__link .jc-btn__icon{transition:transform var(--dur-base) var(--ease-standard)}
.jc-card:hover .jc-servicecard__link .jc-btn__icon{transform:translateX(3px)}
/* List markers are an 8x2px royal rule — never a bullet or a checkmark glyph. */
.jc-servicecard__points{list-style:none;margin:0;padding:var(--space-5) 0 0;display:grid;gap:var(--space-3);border-top:var(--border-hairline) solid var(--border-subtle)}
.jc-servicecard__points li{display:grid;grid-template-columns:14px 1fr;gap:var(--space-3);font-size:var(--text-sm);color:var(--text-body)}
.jc-servicecard__points li::before{content:"";margin-top:9px;width:8px;height:var(--border-strong);background:var(--royal-600)}
/* ServiceCard on a dark band. ServiceCard.jsx is authored for light surfaces;
   these rules are what let it sit on navy, and they key off the tone attribute
   so the card describes itself rather than depending on where it lands. Any
   dark-surface use MUST carry data-tone="inverse…" on an ancestor. */
[data-tone^="inverse"] .jc-servicecard__index{color:var(--text-steel-on-inverse)}
[data-tone^="inverse"] .jc-servicecard__title{color:var(--white)}
[data-tone^="inverse"] .jc-servicecard__summary{color:var(--text-on-inverse-muted)}
[data-tone^="inverse"] .jc-servicecard__link{color:var(--link-on-inverse)}
[data-tone^="inverse"] .jc-servicecard__link:hover{color:var(--link-on-inverse-hover)}
/* Royal-600 is too close to navy to read as a keyline on it; the ramp steps up. */
[data-tone^="inverse"] .jc-card--keyline::before{background:var(--royal-500)}
[data-tone^="inverse"] .jc-card--interactive:hover{border-color:rgba(255,255,255,0.32)}

/* ── Quote — Quote.jsx ────────────────────────────────────── */
.jc-quote{margin:0;display:grid;gap:var(--space-6);max-width:30ch}
.jc-quote::before{content:"";width:48px;height:var(--border-strong);background:var(--royal-600)}
.jc-quote__text{margin:0;font-size:var(--text-2xl);line-height:var(--leading-snug);letter-spacing:var(--tracking-heading);font-weight:var(--weight-medium);color:var(--text-strong)}
.jc-quote__attr{font-size:var(--text-sm);color:var(--text-muted)}
.jc-quote__name{font-weight:var(--weight-bold);color:var(--text-strong)}
[data-tone^="inverse"] .jc-quote::before{background:var(--royal-300)}
[data-tone^="inverse"] .jc-quote__text,[data-tone^="inverse"] .jc-quote__name{color:var(--white)}
[data-tone^="inverse"] .jc-quote__attr{color:var(--text-on-inverse-muted)}

/* ── LogoWall, bare variant ────────────────────────────────
      The default wall sets each name in a bordered cell — a table of
      credentials. The bare variant drops the cells and runs the names
      as one line separated by royal keylines, so the row reads as a
      single statement instead of a grid. Built for the inverse tone,
      where a bordered grid on navy reads as chrome. */
.jc-logowall--bare{gap:var(--space-6)}
.jc-logowall--bare .jc-logowall__list{border:0;grid-template-columns:repeat(3,minmax(0,auto));justify-content:start;gap:var(--space-10);align-items:center}
.jc-logowall--bare .jc-logowall__item{min-height:0;padding:0;border:0;justify-items:start;font-size:var(--text-xl);position:relative}
.jc-logowall--bare .jc-logowall__item+.jc-logowall__item::before{content:"";position:absolute;left:calc(var(--space-10) / -2);top:50%;width:var(--border-strong);height:1em;background:var(--royal-500);transform:translateY(-50%)}
@media (max-width:767px){
  .jc-logowall--bare .jc-logowall__list{grid-template-columns:1fr;gap:var(--space-4)}
  .jc-logowall--bare .jc-logowall__item+.jc-logowall__item::before{display:none}
}

/* ── QuoteBand ─────────────────────────────────────────────
      A quote set over a full-bleed photograph rather than beside a
      framed one. The photograph is the emotional register and the
      quote is the only thing on the band, so it can carry display
      scale — which the side-by-side Quote cannot without crowding the
      frame next to it.
      The scrim is one of the system's two permitted gradients and it
      sits over a real photograph, per imagery.css. The band is a
      pitch section, so the register is MONO; never use a warm frame
      here. Set data-tone="inverse-deep" on the section so the nested
      Quote picks up its on-navy colours. */
.jc-quoteband{position:relative;background:var(--surface-inverse-deep);color:var(--text-on-inverse);overflow:hidden;isolation:isolate}
.jc-quoteband__media{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;filter:var(--photo-mono-deep);z-index:-2}
.jc-quoteband__scrim{position:absolute;inset:0;background:var(--scrim-navy);z-index:-1}
.jc-quoteband__inner{position:relative;max-width:var(--container-max);margin-inline:auto;padding:var(--section-y-lg) var(--gutter)}
.jc-quoteband .jc-quote{max-width:none}
/* Measure goes on the TEXT, not the figure. `ch` resolves against the
   element's own font-size, and .jc-quote is the <figure> at inherited body
   size — 36ch there is ~420px, which at --text-4xl is a 15-character column.
   `em` on .jc-quote__text tracks the quote's own size instead, so the measure
   holds whatever the band's display size is set to. */
.jc-quoteband .jc-quote__text{font-size:var(--text-4xl);font-weight:var(--weight-display);line-height:var(--leading-tight);letter-spacing:var(--tracking-display);max-width:22em}

/* ── MediaMention — MediaMention.jsx ──────────────────────── */
.jc-media{display:grid;grid-template-columns:1fr auto;gap:var(--space-6);align-items:baseline;padding-block:var(--space-6);border-top:var(--border-hairline) solid var(--border-subtle);text-decoration:none;color:inherit}
.jc-media--nodate{grid-template-columns:1fr}
.jc-media__body{display:grid;gap:var(--space-2)}
.jc-media__outlet{font-size:var(--text-xs);font-weight:var(--weight-bold);letter-spacing:var(--tracking-eyebrow);text-transform:uppercase;color:var(--text-accent)}
.jc-media__headline{font-size:var(--text-lg);line-height:var(--leading-snug);letter-spacing:var(--tracking-heading);font-weight:var(--weight-bold);color:var(--text-strong);text-underline-offset:4px}
a.jc-media:hover .jc-media__headline{text-decoration:underline}
.jc-media__date{font-size:var(--text-sm);color:var(--text-subtle);white-space:nowrap}
.jc-media__list>.jc-media:last-child{border-bottom:var(--border-hairline) solid var(--border-subtle)}
[data-tone^="inverse"] .jc-media{border-color:var(--border-on-inverse)}
[data-tone^="inverse"] .jc-media__outlet{color:var(--royal-300)}
[data-tone^="inverse"] .jc-media__headline{color:var(--white)}
[data-tone^="inverse"] .jc-media__date{color:var(--text-on-inverse-muted)}

/* ── Media frame — the framed-photo treatment Hero.jsx uses ── */
.jc-frame{position:relative;border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-lg)}
.jc-frame>img{width:100%;height:100%;object-fit:cover;filter:var(--photo-mono)}
.jc-frame--deep>img{filter:var(--photo-mono-deep)}
.jc-frame--warm>img{filter:none}
.jc-frame--4x3>img{aspect-ratio:4/3}
.jc-frame--3x2>img{aspect-ratio:var(--photo-ratio-landscape)}
.jc-frame--4x5>img{aspect-ratio:var(--photo-ratio-portrait)}

/* ── SiteHeader — SiteHeader.jsx. The one translucent surface
      in the system: rgba white .92 over a 12px backdrop blur.   */
.jc-header{position:sticky;top:0;z-index:var(--z-header);background:rgba(255,255,255,0.92);backdrop-filter:saturate(140%) blur(12px);-webkit-backdrop-filter:saturate(140%) blur(12px);border-bottom:var(--border-hairline) solid var(--border-subtle)}
.jc-header--inverse{background:rgba(19,24,32,0.88);border-bottom-color:var(--border-on-inverse)}
.jc-header__inner{max-width:var(--container-max);margin-inline:auto;padding-inline:var(--gutter);height:var(--header-height);display:flex;align-items:center;gap:var(--space-10)}
.jc-header__mark{display:flex;align-items:center;flex:0 0 auto}
.jc-header__mark img{height:26px;width:auto}
.jc-header__nav{display:flex;align-items:center;gap:var(--space-8);margin-inline-start:auto}
.jc-nav-links{display:flex;align-items:center;gap:var(--space-8)}
.jc-navlink{position:relative;font-size:var(--text-sm);font-weight:var(--weight-medium);letter-spacing:0.01em;text-decoration:none;padding-bottom:3px;color:var(--text-muted);border-bottom:var(--border-strong) solid transparent;transition:color var(--dur-fast) var(--ease-standard),border-color var(--dur-fast) var(--ease-standard)}
.jc-navlink:hover{color:var(--navy-900)}
.jc-navlink[aria-current="page"]{color:var(--navy-900);border-bottom-color:var(--royal-600)}
.jc-header--inverse .jc-navlink{color:rgba(255,255,255,0.74)}
.jc-header--inverse .jc-navlink:hover,.jc-header--inverse .jc-navlink[aria-current="page"]{color:var(--white)}

/* ── SiteFooter — SiteFooter.jsx ──────────────────────────── */
.jc-footer{background:var(--surface-inverse-deep);color:var(--text-on-inverse-muted)}
.jc-footer__inner{max-width:var(--container-max);margin-inline:auto;padding:var(--space-20) var(--gutter) var(--space-10)}
.jc-footer-grid{display:grid;grid-template-columns:minmax(220px,1fr) repeat(auto-fit,minmax(140px,auto));gap:var(--space-12);align-items:start}
.jc-footer__mark{height:28px;width:auto}
.jc-footer__col{display:grid;gap:var(--space-3);align-content:start}
.jc-footer__coltitle{font-size:var(--text-xs);font-weight:var(--weight-bold);letter-spacing:var(--tracking-eyebrow);text-transform:uppercase;color:rgba(255,255,255,0.52)}
.jc-footer__link{font-size:var(--text-sm);color:rgba(255,255,255,0.78);text-decoration:none}
.jc-footer__link:hover{color:var(--white)}
.jc-footer__base{margin-top:var(--space-16);padding-top:var(--space-6);border-top:var(--border-hairline) solid var(--border-on-inverse);display:flex;flex-wrap:wrap;gap:var(--space-4);justify-content:space-between;font-size:var(--text-xs);color:rgba(255,255,255,0.52)}

/* ── Layout primitives ────────────────────────────────────── */
/* .jc-split's display/gap and every collapse rule are in responsive.css. */
.jc-split{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
.jc-split--narrow-lead{grid-template-columns:minmax(0,0.85fr) minmax(0,1.15fr)}
.jc-split--wide-lead{grid-template-columns:minmax(0,1.15fr) minmax(0,0.85fr)}
.jc-split--center{align-items:center}
.jc-grid-3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--grid-gap)}
.jc-grid-2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--grid-gap)}
.jc-stats{display:grid;gap:var(--space-8)}
.jc-stack{display:grid;gap:var(--space-6)}
.jc-stack--tight{gap:var(--space-4)}
.jc-stack--loose{gap:var(--space-10)}

/* ── Reveal — Reveal.jsx / wordpress/jimco-reveal.js.
      The script owns the behaviour: it adds .jc-reveal to the direct
      children of a .jc-reveal-group, sets their transition-delay, and
      toggles .is-revealed on intersection. These rules must stay
      identical to the CSS that script injects — if they drift, a block
      can be left permanently invisible.                          */
.jc-reveal{opacity:0;transform:translateY(var(--reveal-distance));transition:opacity var(--dur-reveal) var(--ease-entrance),transform var(--dur-reveal) var(--ease-entrance);will-change:opacity,transform}
.jc-reveal.is-revealed{opacity:1;transform:none}
/* Fallback for JavaScript off. THIS SELECTOR ONLY WORKS IF SOMETHING SETS THE
   CLASS. It requires the two-part class-swap convention in
   wordpress/functions-snippet.php section 5: no-js is printed onto <html>
   server side, and an inline <head> script swaps it for js before first
   paint. Ship both or neither - without them this rule never matches, and
   every .jc-reveal element sits at opacity:0 permanently for anyone with JS
   disabled. That is not hypothetical: Quote and ServiceCard emit .jc-reveal
   from a control, and the Home page carries it on the logo wall, headings and
   prose stacks. */
.no-js .jc-reveal{opacity:1;transform:none}

.jc-visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}

/* ===== sections ===== */
/* JIM & Co. — section band library
 *
 * A section is a full-width band: the unit a page is assembled from, sitting
 * between a widget and a whole page. In Elementor each one is a saved
 * Container template.
 *
 * WHAT BELONGS HERE. Band-level layout only — the rhythm between the blocks
 * inside a band, and nothing else. A rule that styles a component belongs in
 * components/components.css. A rule that styles one page belongs in that
 * page's own stylesheet. If a rule here would be useful on a second band, it
 * is a component rule in the wrong file.
 *
 * PURE SYSTEM CSS, NO EXCEPTIONS. No `.elementor-widget-*`, no `.e-con`, no
 * `.elementor-*` of any kind. This file ships on the spine path, where it
 * propagates to every platform in the repo — most of which will never run
 * Elementor. Anything needing an Elementor selector belongs in the theme-owned
 * elementor-bridge.css instead. A band whose CSS cannot pass that test is not
 * a system section; it is a theme patch wearing one.
 *
 * ONE FLAT FILE, DELIBERATELY. Each band has its own .md next to this file,
 * but the CSS is not split per band: tokens/Tokens.php CONCATENATES the parts
 * named in CSS_PARTS, and an index file using @import would not survive that
 * concatenation. One file is one CSS_PARTS entry with nothing to resolve.
 *
 * REGISTER THIS FILE IN CSS_PARTS (tokens/Tokens.php) IN THE SAME PR THAT
 * ADDS IT. The --check gate cannot report a part it does not know about, so an
 * unregistered part produces a stale stylesheet and a gate that exits 0 —
 * which reads as a pass.
 *
 * Load order: after components/components.css. These rules position
 * components within a band and must win over nothing; they are not overrides.
 */

/* ── sec-positioning ──────────────────────────────────────────
 * Divider closing the positioning prose, before the nested stat row.
 * Divider.jsx is called with spacing="var(--space-4)"; .jc-rule's own default
 * is --space-8, which is too much inside a column. */
.jc-sec-positioning__rule{margin-block:var(--space-4)}

/* The stat row sits INSIDE the positioning column, not across the container.
   At ~600px wide three figures share ~180px each, and --text-4xl overflows, so
   the figures step down to --text-2xl — the same size responsive.css uses for
   this row below 1024px. Figures here are phrases ("Nearly 25 years"), not
   numerals, so a two-line wrap is expected and reads correctly.
   Keyed off the data attribute, not a class, because responsive.css keys the
   below-lg downsize off the same attribute. */
.jc-sec-positioning__stats [data-stat-figure]{font-size:var(--text-2xl)}

/* ── sec-service-trio ─────────────────────────────────────────
 * Card grid clears the section heading above it. */
.jc-sec-service-trio__grid{margin-top:var(--space-12)}

/* ── sec-press ────────────────────────────────────────────────
 * Press strip sits under the press heading in the left column, set off by a
 * hairline so it reads as a summary of the list beside it rather than as a
 * free-floating credential. */
.jc-sec-press__cycle{padding-top:var(--space-6);border-top:var(--border-hairline) solid var(--border-subtle)}

/* ── sec-closing-cta ──────────────────────────────────────────
 * The one centred block in the system. Every other band is an asymmetric
 * split; this is the documented exception, and it is the exception because a
 * closing call to action has no second column to balance against. */
.jc-sec-closing-cta__inner{display:grid;justify-items:center;text-align:center;gap:var(--space-8)}

/* ===== elementor-bridge ===== */
/* Web-JimCo — Elementor bridge (WEBJIM-J05)
 *
 * The ONLY part of the composed stylesheet that may name an Elementor class.
 * Nothing in context/brand-strategy/ may, because context/ propagates to every
 * platform on this mega-repo and most of them will never run Elementor — that
 * boundary is what keeps the design system truthful for its other consumers.
 *
 * Keep this file small and keep every rule's evidence with it. A bridge that
 * grows into a second design system is how the first one stops being the
 * source of truth.
 */

/* ── Focus ring, at Elementor's own specificity ─────────────────────────
 * base.css supplies `:focus-visible{outline:2px solid var(--focus-ring)}` and,
 * now that the base layer actually reaches the theme, that covers most of the
 * page. Two stacks still out-specify a bare pseudo-class selector:
 *
 *   hello-elementor/assets/css/reset.css
 *     [type="button"]:focus:not(:focus-visible) { outline: none }
 *   elementor/base-desktop.css
 *     .elementor .e-form-submit-button-base:focus-visible { background-color }
 *
 * The Hello rule only fires when focus is NOT focus-visible, so it does not
 * remove our ring — but the Elementor rules are class-scoped and would win a
 * tie on any property they share. Restating the ring at comparable specificity
 * costs three selectors and removes the ambiguity. Measured 2026-09-14
 * (WEBJIM-J04 §The defects §1): zero visible focus indicator anywhere on Home,
 * while --focus-ring sat correctly defined and unconsumed.
 */
.elementor a:focus-visible,
.elementor button:focus-visible,
.elementor .elementor-button:focus-visible,
.elementor [type="button"]:focus-visible,
.elementor [type="submit"]:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

/* ── Typeface inheritance ───────────────────────────────────────────────
 * Elementor's heading and text-editor widgets render their own wrappers. When
 * a widget sets no typography, the wrapper should inherit the design system's
 * face from `body` (base.css) rather than fall through to Elementor's Kit
 * default. Measured on live Home 2026-09-14: 71 of 86 text elements rendered
 * in Roboto. The --e-global-typography-* aliases (emitted by Tokens.php, not
 * here) fix the widgets that DO reference a Kit global; these two rules cover
 * the ones that reference nothing at all.
 */
.elementor-widget-heading .elementor-heading-title,
.elementor-widget-text-editor {
  font-family: inherit;
}

/* ── Elementor's stock accent ───────────────────────────────────────────
 * Elementor paints an unstyled button with its Kit accent colour, which ships
 * as #61CE70 — a green that appears nowhere in this brand. It reached the live
 * footer's three service-line links at 1.64:1 contrast (WEBJIM-J03 §3).
 *
 * The real fix is the --e-global-color-accent alias, which makes Elementor's
 * own variable resolve to a design-system token. This rule is the floor under
 * it: a button that somehow resolves no accent at all gets the design system's
 * action colour, never a fallback literal. It deliberately does NOT set a
 * background on link-type buttons — the design system renders those with no
 * surface at all, so painting one would be a restyle, not a bridge.
 */
.elementor .elementor-button[class*="elementor-size-"]:not([href]) {
  background-color: var(--action-primary);
}

/* ── JIM & Co. widget wrappers, promoted out of the way (WEBJIM-L01) ────
 * The jimco-components widgets return `has_widget_inner_wrapper(): false`, so
 * Elementor's inner `.elementor-widget-container` is gone and exactly one
 * wrapper remains: `.elementor-widget-{name}`. That wrapper is still the grid
 * or flex item, which breaks every layout relationship the components rely on
 * — `.jc-servicecard{height:100%}` resolves against the wrapper rather than the
 * track, and `.jc-stats`' columns lay out wrappers instead of `.jc-stat`s.
 *
 * `display: contents` removes the wrapper from the box tree and promotes the
 * component's own root to be the real item. Scoped by name, never to
 * `.elementor-widget` at large: Elementor's own widgets need their wrapper.
 *
 * Accessibility: `display:contents` on a plain `div` with no role and no
 * generated content is the case current browsers handle correctly — the
 * element leaves the box tree, not the accessibility tree. ADR-WEBJIM-013
 * leaves "worth measuring on target browsers" open; WEBJIM-E06's audit is
 * where it gets measured on the assembled page.
 */
.elementor-widget-jimco-service-card,
.elementor-widget-jimco-stat,
.elementor-widget-jimco-quote,
.elementor-widget-jimco-media-mention {
  display: contents;
}

/* ── Container grids: the layout class lands one box too high ───────────
 * An Elementor Container renders as
 *
 *   .e-con  >  .e-con-inner  >  the widgets
 *
 * and its `css_classes` control writes to the OUTER element. So a section
 * template that puts `jc-grid-3` on a Container makes `.e-con-inner` the
 * grid's only item: it takes column 1 and every child stacks inside it,
 * while `grid-template-columns` reports three perfectly correct tracks.
 *
 * Measured on staging 2026-09-22, at 1440px, after WEBJIM-E06's assembly:
 *
 *   .jc-split    cols 436.9px 591.1px     children: 1
 *   .jc-grid-3   cols 344.8px x3          children: 1
 *   .jc-stats    cols 162.4px x3          children: 1
 *
 * — and all three service cards at the same `x: 174`. Home rendered as one
 * narrow left column for its whole length. Nothing errored, and the grid
 * declarations were all present and correct, which is why it survived the
 * static conformance gate: that tier reads the stylesheet, not the box tree.
 *
 * The fix moves the grid down one box rather than restating it. The track
 * lists stay in components.css and responsive.css -- `inherit` forwards each
 * one, including every `!important` breakpoint override, so this rule has no
 * values of its own to drift. Verified live at 1440px: cards land at
 * x 174 / 548 / 921, the split resolves 437/591 (components.css's 0.85/1.15
 * narrow-lead ratio) and the stat row goes three across inside it.
 *
 * `display:block` on the outer, not `display:contents`: the wrapper carries
 * `.jc-reveal` on most bands, and opacity and transform do not apply to an
 * element with no box. Elementor's boxed `max-width` lives on `.e-con-inner`
 * and is untouched either way.
 *
 * Scoped through `.e-con` deliberately. The same utility classes are used by
 * the static mockups and by the header/footer theme parts, where the markup
 * has no wrapper and the grid is already on the right element.
 */
.e-con.jc-split,
.e-con.jc-grid-2,
.e-con.jc-grid-3,
.e-con.jc-stats {
  display: block;
}

.e-con.jc-split > .e-con-inner,
.e-con.jc-grid-2 > .e-con-inner,
.e-con.jc-grid-3 > .e-con-inner,
.e-con.jc-stats > .e-con-inner {
  display: grid;
  grid-template-columns: inherit;
  gap: inherit;
  align-items: inherit;
}

/* ── Footer wordmark, at Elementor's own specificity ────────────────────
 * Same shape as the focus ring above, and the same cause.
 *
 *   elementor/custom-frontend.min.css   .elementor img { height: auto }   0,1,1
 *   components.css                      .jc-footer__mark { height: 28px } 0,1,0
 *
 * Elementor wins the class-plus-element selector, so the mark falls back to
 * `height:auto` and is then sized by `max-width:100%` against its grid
 * column. Measured on staging 2026-09-22: 560x136 natural, rendering
 * 219.97x53.42 in an ~220px column and 560x136 at 1440px — against a 28px
 * spec, so it scaled with the viewport instead of holding its size.
 *
 * The sibling selector is already immune by accident rather than by design:
 * `.jc-header__mark img` carries an element too, ties Elementor at 0,1,1 and
 * wins on load order, which is why the header mark measures a correct 26px
 * on the same page. One selector in the pair has an element in it and the
 * other does not; that asymmetry is the whole bug.
 *
 * Restated here rather than corrected upstream because components.css is a
 * mirror of the Claude Design project (ADR-WEBJIM-019, design-pull §Step 3) --
 * an in-repo edit there is reintroduced by the next pull. `img.jc-footer__mark`
 * is the durable fix and belongs upstream; this rule holds the line until it
 * lands, and becomes a harmless no-op when it does.
 *
 * Verified live before being written: the rule at this specificity resolves
 * the mark to 28px x 115.29px, matching the inline-style control exactly.
 */
.elementor .jc-footer__mark,
/* WEBJIM-J11: the class now sits on the Site Logo widget's WRAPPER, not on
 * the <img>. components.css writes `.jc-footer__mark{height:28px}` for markup
 * where that class IS the image, so on a wrapper it sized the div to 28px and
 * left a 560x136 image overflowing it — measured live 2026-09-23. The header
 * escapes this because its own rule is already `.jc-header__mark img`; the
 * footer's is not, and that asymmetry is the whole defect. `img.jc-footer__mark`
 * is the durable fix and belongs upstream with the sibling note above. */
.elementor .jc-footer__mark img {
  height: 28px; /* components.css's own literal; the mockup's TOKEN GAPS
                   block records that no logo-height token exists and that
                   the value is mirrored, not invented. */
  width: auto;
}

/* ── Photo bands: media and scrim must size to the band ─────────────────
 * The hero and the quote band are a photograph and a scrim layered under
 * content, each `position:absolute; inset:0; width:100%; height:100%` over a
 * `position:relative` band. In the static mockup that resolves exactly: band,
 * media and scrim all measure the same box. On the Elementor build, neither
 * band did. Measured on staging at 1440px, 2026-09-22:
 *
 *              band          media          scrim
 *   hero    1420x675      1420x1901      1420x675
 *   quote   1440x603      1420x945       1420x0      <- zero height
 *
 * Two independent causes, both Elementor's:
 *
 * 1. `.elementor img{height:auto}` is 0,1,1 and beats
 *    `.jc-quoteband__media{height:100%}` at 0,1,0, so each photograph fell
 *    back to its natural aspect -- the hero rendering 2.8x its band's height
 *    and being cropped to a much tighter frame than the design. This is the
 *    third rule in this file defeated by that same selector; see the footer
 *    wordmark block above.
 *
 * 2. The quote band's media and scrim are each wrapped in their own Elementor
 *    widget div, which is `position:relative` and zero-height. `inset:0` and
 *    the percentages then resolve against that wrapper instead of the band --
 *    so the scrim painted a correct gradient over an area of zero. The hero
 *    escapes this one because its widget emits `.jc-herowrap` as its own root,
 *    putting the two layers directly inside the band.
 *
 * `display:contents` removes the wrapper's box so the layers become the band's
 * own children, the same technique this file already applies to the jimco-*
 * widget wrappers. The `padding:0` is Elementor's container default, which
 * inset the layers by 10px a side and is why they measured 1420 inside a 1440
 * band; the band's own `__inner` owns its padding.
 *
 * Verified in a browser before being written, with a reversion check: both
 * bands wrong before, both exactly band-sized after, and removing the rules
 * restored the broken measurements byte for byte.
 */
.jc-quoteband > .elementor-widget-html {
  display: contents;
}

.e-con.jc-quoteband {
  padding: 0;
}

.elementor .jc-herowrap__media,
.elementor .jc-quoteband__media {
  width: 100%;
  height: 100%;
}

/* ── Press-cycle mastheads, at Elementor's own specificity ──────────────
 * Fourth instance in this file of one selector defeating one design-system
 * rule. `.elementor img{height:auto}` is 0,1,1;
 * `.jc-presscycle__mark{height:56px}` is 0,1,0.
 *
 * The strip's whole premise is that every masthead is normalised to the same
 * 56px height, so six logos of wildly different proportions read as one row.
 * Without that, each rendered at whatever its file and the column's max-width
 * produced. Measured on staging 2026-09-22, immediately after the six real
 * mastheads replaced the text fallbacks:
 *
 *   58  54  43  73  136  65   px tall, against a spec of 56 for all six
 *
 * The 136 is CEO Weekly, more than twice its neighbours -- the exact failure
 * the normalisation exists to prevent, and invisible in the stylesheet, where
 * the rule reads correctly.
 *
 * `filter` and `opacity` were never contested and are left where they are;
 * only the two properties Elementor also sets are restated. Verified in a
 * browser with a reversion check: all six resolve to 56 with this rule, and
 * removing it returns the six original heights exactly.
 *
 * See the focus-ring, footer-wordmark and photo-band blocks above. When a
 * fifth appears, the pattern -- not the instance -- is what belongs in the
 * platform template (foundation/backlog/fb-002).
 */
.elementor .jc-presscycle__mark {
  height: 56px;
  width: auto;
}

/* ── Site header: the nav's auto margin has nothing to push against ─────
 * `.jc-header__nav{margin-inline-start:auto}` (components.css) is what
 * right-aligns the nav against the logo. It is a flex-item property, and it
 * only does anything when the nav IS the flex item.
 *
 * Live, it is not. The header is assembled from two Elementor HTML widgets
 * inside `.jc-header__inner`, so the box tree reads
 *
 *   .jc-header__inner (flex)  >  .elementor-widget-html  >  nav.jc-header__nav
 *
 * The wrapper is the flex item; the nav is a block-level child filling it.
 * `auto` on a block whose width is already `auto` resolves to zero, so the
 * declaration applies, computes, and moves nothing.
 *
 * Measured at 1440px against the mockup, which is the spec (ADR-WEBJIM-019):
 *
 *                       mockup                live (before)
 *   .jc-header__inner   1240 @100-1340        1240 @100-1340   same
 *   .jc-header__mark     108 @164              108 @164        same
 *   .jc-header__nav      329 @947-1276         329 @312-641    635px adrift
 *   nav margin-i-start   635.469px             0px
 *
 * The 635px displacement is the auto margin the mockup resolves and the live
 * page does not -- the defect is entirely this one property, not a difference
 * in widths, gutters or container geometry, all three of which already match.
 *
 * This is the same remedy as the jimco-widget block above and the quote
 * band's: promote the component's own root to be the real item rather than
 * restate the layout one box higher. No value is introduced here -- the
 * `auto` stays in components.css and simply starts applying to an element
 * that can use it. Scoped to this container: `.elementor-widget-html` is a
 * VENDOR widget, and the block above is explicit that Elementor's own widgets
 * need their wrapper in the general case.
 *
 * Verified live with a reversion check: with this rule the nav lands at
 * 329 @947-1276 and the margin resolves to 635.469px -- both identical to the
 * mockup -- and removing it returns the nav to @312 exactly.
 *
 * Third `display:contents` promotion in this file (see fb-002's note in the
 * press-masthead block above about the pattern, not the instance, being what
 * belongs in a platform template).
 */
.jc-header__inner > .elementor-widget-html {
  display: contents;
}

/* ── Header mobile nav: the toggle the design system never budgeted for ──
 * WEBJIM-J11 / ADR-WEBJIM-028 put the header nav on Elementor's Nav Menu
 * widget, which brings a mobile dropdown — the native fix for fb-003, where
 * `responsive.css:30` hides `.jc-nav-links` below 768px with nothing to
 * reopen them.
 *
 * FLAGGED: THIS BLOCK INTRODUCES VALUES, DELIBERATELY.
 *
 * Every other block in this file restates specificity and forwards the design
 * system's own values. This one does not, and the reason is worth stating
 * rather than burying: **the design system has no mobile-header spec that
 * includes a toggle.** Its readme keeps "the wordmark and the booking CTA"
 * below `md` and stops there. A toggle is a third element in a row that was
 * costed for two.
 *
 * Measured at 390px, content box 370px:
 *
 *   wordmark 108  +  toggle 33  +  CTA 166  =  307
 *   .jc-header__inner's own gap is --space-10 (40px), .jc-header__nav's
 *   --space-8 (32px)  ->  307 + 72 = 379, over by 9px.
 *
 * At that width the row either wraps to two (the container default) or, with
 * `flex_wrap: nowrap` set on the Containers, squashes the CTA to three lines.
 * Both were measured on 2026-09-23. There is no arrangement of the spec's own
 * values that fits, so a value had to be chosen.
 *
 * The choice: tighten both gaps to --space-4 at mobile only. It is the
 * smallest change that keeps all three elements on one row and keeps the CTA
 * at its natural 166x44 rather than wrapping — and it preserves what the
 * design system actually asks for, which is that the wordmark and the booking
 * CTA both survive the collapse.
 *
 * **This is a provisional build decision, not a design-system fact.** It
 * belongs upstream in Claude Design as a real mobile-header spec, and when one
 * lands this block should shrink to whatever that spec does not express. See
 * fb-003 and WEBJIM-J11.
 *
 * The three structural rules below are ordinary vendor repair and introduce
 * nothing:
 *
 * - `flex: 0 0 auto` on the nav's widget children stops the CTA being chosen
 *   as the flex item to shrink; without it it compresses to 159x48 and wraps.
 * - `position: static` on the nav-menu widget hands the dropdown's anchoring
 *   to `.jc-header__nav`. Elementor's own absolute rule is scoped to
 *   `.elementor-nav-menu--stretch`, which only exists when the widget's
 *   `full_width` control is on — and that variant stretches the panel to the
 *   full viewport, which is not this design. Without re-anchoring, the panel
 *   right-aligns to the 33px toggle and renders at left -33, off-screen.
 *   Measured before and after.
 * - `position: absolute` on the panel keeps it out of flow; in flow it sat
 *   97px wide beneath the toggle and widened the nav by that much.
 *
 * Verified live at 390px, closed and open: wordmark 108, nav 206, CTA 166x44
 * on one row with no page overflow; toggle opens to aria-expanded="true" with
 * the panel at 220x84 spanning 140-360, fully on-screen. Desktop is untouched
 * -- the whole block is inside the same max-width:767px boundary the design
 * system already uses.
 */
/* DURABILITY AGAINST THE NEXT `/design-pull`, stated precisely.
 *
 * The two gap overrides below are the only declarations in this file that a
 * design-system pull could plausibly fight, because they contradict values
 * `components.css` sets for the same classes. What protects them:
 *
 * - `elementor-bridge` is LAST in `Tokens::CSS_PARTS`, after `responsive`,
 *   `base`, `components` and `sections`, so at equal specificity it wins on
 *   source order.
 * - The selectors below are scoped through `.jc-header` (0,2,0) rather than
 *   written bare (0,1,0), so an ordinary pulled rule loses on specificity too
 *   and does not depend on part order holding.
 *
 * **The one change upstream that WOULD regress this:** an `!important` mobile
 * rule on `.jc-header__inner` or `.jc-header__nav`'s gap. `!important` beats
 * both defences regardless of order or specificity, and it is not a
 * hypothetical shape — `tokens/responsive.css:30` already uses exactly that
 * idiom (`.jc-nav-links{display:none !important}`) for this same header at
 * this same breakpoint.
 *
 * So: safe against a value change, safe against a new non-important mobile
 * rule, and NOT safe against an `!important` one. If the design system ever
 * gains a real mobile-header spec, that is the line to check first.
 */
@media (max-width: 767px) {
  .jc-header .jc-header__inner {
    gap: var(--space-4);
  }

  .jc-header .jc-header__nav {
    gap: var(--space-4);
    position: relative;
  }

  .jc-header__nav > .elementor-widget {
    flex: 0 0 auto;
  }

  .jc-header__nav .elementor-widget-nav-menu {
    position: static;
  }

  .jc-header__nav .elementor-nav-menu--dropdown {
    position: absolute;
    top: 100%;
    inset-inline-end: 0;
    width: max-content;
    min-width: 220px;
  }
}

/* ===== elementor global alias (floor) ===== */
:root {
  --e-global-color-primary: var(--action-primary);
  --e-global-color-secondary: var(--text-steel-quiet);
  --e-global-color-text: var(--text-body);
  --e-global-color-accent: var(--action-accent);
  --e-global-typography-primary-font-family: var(--font-sans);
  --e-global-typography-primary-font-size: var(--text-4xl);
  --e-global-typography-secondary-font-family: var(--font-sans);
  --e-global-typography-secondary-font-size: var(--text-2xl);
  --e-global-typography-text-font-family: var(--font-sans);
  --e-global-typography-text-font-size: var(--text-md);
  --e-global-typography-accent-font-family: var(--font-sans);
  --e-global-typography-accent-font-size: var(--text-base);
}

