/* ============================================================
   ESCALATE DESIGN SYSTEM  (tokens.css)
   Bump ESC_VER in functions.php on every change (hCDN cache).
   ============================================================ */

/* ---------- Fonts (self-hosted, relative to this file) ---------- */
@font-face{font-family:'Inter';font-style:normal;font-weight:100 900;font-display:swap;src:url('../fonts/inter.woff2') format('woff2');}
@font-face{font-family:'Zilla Slab';font-style:normal;font-weight:500;font-display:swap;src:url('../fonts/zillaslab-500.woff2') format('woff2');}
@font-face{font-family:'Zilla Slab';font-style:normal;font-weight:600;font-display:swap;src:url('../fonts/zillaslab-600.woff2') format('woff2');}
@font-face{font-family:'Zilla Slab';font-style:normal;font-weight:700;font-display:swap;src:url('../fonts/zillaslab-700.woff2') format('woff2');}

/* ---------- Tokens ---------- */
:root{
  --blue:#1B3CF5; --blue-dark:#1430C9; --blue-700:#0E227F;
  /* Brand accent is ORANGE per the client brand kit (2026-07-09).
     The --coral names are kept as aliases so existing rules keep working. */
  --orange:#EA8C2E; --orange-dark:#C9741F;
  --coral:var(--orange); --coral-dark:var(--orange-dark);
  --ink:#16161D; --muted:#5B5E6E; --line:#E7E9F2; --line-strong:#C3C9E2;
  --mist:#F4F6FF; --cream:#F7F4EF; --white:#FFFFFF;
  --maxw:1180px; --gutter:24px;
  --r:14px; --r-lg:22px; --r-pill:999px;
  --sh-1:0 1px 2px rgba(16,16,29,.04), 0 4px 16px rgba(16,16,29,.05);
  --sh-2:0 8px 30px rgba(16,16,29,.08);
  --sh-blue:none; /* was a blue glow under primary buttons, removed 2026-07-18 */
  --ease:cubic-bezier(.22,1,.36,1);
  --display:'Zilla Slab',Rockwell,'Roboto Slab',Georgia,serif;
  --body:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
}

/* ---------- Base ---------- */
*{box-sizing:border-box;}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%;}
body{margin:0;font-family:var(--body);color:var(--ink);background:var(--white);font-size:1.0625rem;line-height:1.65;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;overflow-x:clip;}
img{max-width:100%;height:auto;display:block;}
a{color:var(--blue);text-decoration:none;}
a:hover{text-decoration:underline;}
h1,h2,h3,h4{font-family:var(--display);font-weight:700;line-height:1.07;letter-spacing:-.015em;color:var(--ink);margin:0 0 .4em;}
h1{font-size:clamp(2.6rem,6vw,4.6rem);}
h2{font-size:clamp(2rem,4vw,3.1rem);}
h3{font-size:clamp(1.35rem,2.2vw,1.7rem);}
p{margin:0 0 1.1em;}
::selection{background:var(--blue);color:#fff;}

/* ---------- Layout helpers ---------- */
.esc-wrap{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gutter);}
.esc-section{padding-block:clamp(64px,9vw,120px);}
.esc-section--tight{padding-block:clamp(44px,6vw,72px);}
.esc-band{width:100%;}
.bg-mist{background:var(--mist);}
.bg-cream{background:var(--cream);}
.bg-ink{background:var(--ink);color:#fff;}
.bg-blue{background:var(--blue);color:#fff;}
.bg-blue *{color:#fff;}
.text-center{text-align:center;}
.lede{font-size:clamp(1.1rem,1.6vw,1.3rem);color:var(--muted);line-height:1.6;max-width:62ch;}
.bg-blue .lede,.bg-ink .lede{color:rgba(255,255,255,.82);}

/* ---------- Eyebrow ---------- */
.esc-eyebrow{display:inline-flex;align-items:center;gap:.5rem;font-family:var(--body);font-weight:600;font-size:.78rem;letter-spacing:.14em;text-transform:uppercase;color:var(--blue);margin-bottom:1rem;}
.esc-eyebrow::before{content:"";width:26px;height:2px;background:var(--coral);display:inline-block;}
.bg-blue .esc-eyebrow,.bg-ink .esc-eyebrow{color:#fff;}
.bg-blue .esc-eyebrow::before{background:var(--coral);}

/* ---------- Buttons ---------- */
.esc-btn{display:inline-flex;align-items:center;gap:.55rem;font-family:var(--body);font-weight:600;font-size:1rem;line-height:1;padding:.95rem 1.6rem;border-radius:var(--r);border:1.5px solid transparent;cursor:pointer;transition:transform .25s var(--ease),box-shadow .25s var(--ease),background .2s;text-decoration:none;}
.esc-btn:hover{text-decoration:none;transform:translateY(-2px);}
.esc-btn--primary{background:var(--blue);color:#fff;box-shadow:var(--sh-blue);}
.esc-btn--primary:hover{background:var(--blue-dark);color:#fff;}
.esc-btn--coral{background:var(--coral);color:#fff;}
.esc-btn--coral:hover{background:var(--coral-dark);color:#fff;}
.esc-btn--ghost{background:transparent;color:var(--ink);border-color:var(--line);}
.esc-btn--ghost:hover{border-color:var(--blue);color:var(--blue);}
.bg-blue .esc-btn--ghost,.bg-ink .esc-btn--ghost{color:#fff;border-color:rgba(255,255,255,.4);}
.bg-blue .esc-btn--ghost:hover{background:#fff;color:var(--blue);}
.esc-btn--white{background:#fff;color:var(--blue);}
.esc-btn--white:hover{background:#f1f3ff;color:var(--blue-dark);}
.esc-btn .arr{transition:transform .25s var(--ease);}
.esc-btn:hover .arr{transform:translateX(4px);}

/* ---------- Header ---------- */
.esc-header{position:sticky;top:0;z-index:100;background:rgba(255,255,255,.86);backdrop-filter:saturate(160%) blur(14px);border-bottom:1px solid transparent;transition:border-color .3s,box-shadow .3s;}
.esc-header.scrolled{border-bottom-color:var(--line);box-shadow:0 6px 24px rgba(16,16,29,.05);}
.esc-header__inner{display:flex;align-items:center;justify-content:space-between;gap:1.5rem;height:74px;}
.esc-logo img{height:26px;width:auto;}
.esc-nav{display:flex;align-items:center;gap:2rem;}
.esc-nav a{color:var(--ink);font-weight:500;font-size:.98rem;position:relative;}
.esc-nav a::after{content:"";position:absolute;left:0;bottom:-6px;height:2px;width:0;background:var(--coral);transition:width .25s var(--ease);}
.esc-nav a:hover{text-decoration:none;}
.esc-nav a:hover::after{width:100%;}
.esc-header__cta{display:flex;align-items:center;gap:1rem;}
.esc-burger{display:none;background:none;border:0;cursor:pointer;width:30px;height:24px;position:relative;}
.esc-burger span{position:absolute;left:0;width:100%;height:2.5px;background:var(--ink);border-radius:2px;transition:.3s var(--ease);}
.esc-burger span:nth-child(1){top:2px;} .esc-burger span:nth-child(2){top:11px;} .esc-burger span:nth-child(3){top:20px;}
.esc-burger.open span:nth-child(1){top:11px;transform:rotate(45deg);}
.esc-burger.open span:nth-child(2){opacity:0;}
.esc-burger.open span:nth-child(3){top:11px;transform:rotate(-45deg);}

/* ---------- Hero ---------- */
.esc-hero{position:relative;overflow:hidden;background:var(--white);padding-block:clamp(70px,11vw,140px);}
.esc-hero__aurora{display:none;}
/* Aurora glow removed 2026-07-18 at Rene's request. The element still
   exists in the page content of all five pages, so it is hidden here
   rather than stripped from the markup. */
/* Hero background. Rene chose the soft wash over the ruled grid, 2026-08-21.
   Two radial tints in the brand's own mist and cream, so the hero has depth
   without a pattern competing with the headline and the stat cards.
   The backup he picked is diagonal hairlines. To switch, comment this rule out
   and uncomment the block beneath it. Both are pure CSS: no image, no request. */
.esc-hero__grid{position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(760px 440px at 76% 22%,var(--mist),transparent 70%),
    radial-gradient(560px 360px at 10% 88%,var(--cream),transparent 72%);}

/* Backup: diagonal hairlines.
.esc-hero__grid{position:absolute;inset:0;z-index:0;pointer-events:none;opacity:.85;
  background-image:repeating-linear-gradient(45deg,#e6eaf6 0 1px,transparent 1px 16px);
  -webkit-mask-image:radial-gradient(circle at 70% 34%,#000,transparent 74%);
          mask-image:radial-gradient(circle at 70% 34%,#000,transparent 74%);}
*/
@keyframes auroraFloat{from{transform:translate3d(0,0,0) scale(1);}to{transform:translate3d(-3%,2%,0) scale(1.08);}}
.esc-hero__inner{position:relative;z-index:2;display:grid;grid-template-columns:1.15fr .85fr;gap:3.5rem;align-items:center;}
.esc-hero h1 .hl{color:var(--blue);}
.esc-hero h1 .mark{position:relative;white-space:nowrap;}
.esc-hero h1 .mark::after{content:"";position:absolute;left:-2px;right:-2px;bottom:.06em;height:.34em;background:rgba(234,140,46,.30);z-index:-1;border-radius:3px;}
.esc-hero__lede{font-size:clamp(1.1rem,1.5vw,1.3rem);color:var(--muted);max-width:46ch;margin:1.4rem 0 2rem;}
.esc-hero__cta{display:flex;flex-wrap:wrap;gap:1rem;align-items:center;}
.esc-hero__trust{margin-top:2.2rem;display:flex;align-items:center;gap:1rem;color:var(--muted);font-size:.92rem;}
.esc-hero__trust b{color:var(--ink);}

/* hero visual stat card stack */
.esc-hero__panel{position:relative;}
.esc-statcard{background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--sh-2);padding:1.6rem 1.7rem;}
.esc-statcard+.esc-statcard{margin-top:1rem;}
.esc-statcard__big{font-family:var(--display);font-weight:700;font-size:2.8rem;line-height:1;color:var(--blue);letter-spacing:-.02em;}
.esc-statcard__big.coral{color:var(--coral);}
.esc-statcard__big.has-coral-color{color:var(--coral);}
.esc-statcard__big.has-ink-color{color:var(--ink);}
.esc-rail__dot.has-coral-color{background:var(--coral);}
.esc-rail__dot.has-ink-color{background:var(--ink);}
.esc-statcard__label{color:var(--muted);font-size:.96rem;margin-top:.45rem;}
.esc-statcard--float{position:absolute;}
.esc-statcard--tilt{transform:rotate(-2deg);}

/* ---------- Section heading ---------- */
.esc-head{max-width:54ch;margin-bottom:clamp(2.2rem,4vw,3.4rem);}
.esc-head.center{margin-inline:auto;text-align:center;}
.esc-head p{color:var(--muted);font-size:1.1rem;margin-top:.4rem;}

/* ---------- Stat band ---------- */
.esc-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:2.5rem;}
.esc-stat__num{font-family:var(--display);font-weight:700;font-size:clamp(2.6rem,5vw,3.8rem);line-height:1;letter-spacing:-.02em;}
.esc-stat__num .u{color:var(--coral);}
.esc-stat__txt{margin-top:.6rem;font-size:1.02rem;opacity:.85;max-width:30ch;}
.esc-stat__rule{width:46px;height:3px;background:var(--coral);margin-top:1rem;border-radius:2px;}

/* ---------- Service category cards ---------- */
.esc-cats{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem;}
.esc-cat{position:relative;background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);padding:2rem 1.9rem 2.1rem;overflow:hidden;transition:transform .35s var(--ease),box-shadow .35s var(--ease),border-color .35s;}
.esc-cat:hover{transform:translateY(-6px);box-shadow:var(--sh-2);border-color:transparent;}
.esc-cat__ic{width:54px;height:54px;border-radius:14px;display:grid;place-items:center;background:var(--mist);color:var(--blue);margin-bottom:1.3rem;transition:.35s var(--ease);}
.esc-cat:hover .esc-cat__ic{background:var(--blue);color:#fff;transform:scale(1.05) rotate(-4deg);}
.esc-cat__ic svg{width:26px;height:26px;}
.esc-cat__count{font-family:var(--display);font-weight:700;color:var(--coral);font-size:.95rem;letter-spacing:.02em;}
.esc-cat h3{margin:.2rem 0 .6rem;}
.esc-cat p{color:var(--muted);font-size:1rem;margin-bottom:1.1rem;}
.esc-cat__tags{display:flex;flex-wrap:wrap;gap:.45rem;}
.esc-cat__tags span{font-size:.82rem;color:var(--ink);background:var(--mist);border-radius:var(--r-pill);padding:.32rem .7rem;}
.esc-cat__link{display:inline-flex;align-items:center;gap:.4rem;margin-top:1.2rem;font-weight:600;color:var(--blue);}
.esc-cat__link .arr{transition:transform .25s var(--ease);}
.esc-cat:hover .esc-cat__link .arr{transform:translateX(4px);}

/* ---------- Service detail grid (services page) ---------- */
.esc-svc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:1rem;}
.esc-svc{background:#fff;border:1px solid var(--line);border-radius:var(--r);padding:1.25rem 1.3rem;transition:.3s var(--ease);}
.esc-svc:hover{border-color:var(--blue);box-shadow:var(--sh-1);transform:translateY(-3px);}
.esc-svc h4{font-family:var(--display);font-size:1.08rem;margin:0 0 .3rem;}
.esc-svc p{color:var(--muted);font-size:.92rem;margin:0;line-height:1.5;}

/* ---------- Steps (how it works) ---------- */
.esc-steps{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem;counter-reset:s;}
.esc-step{background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);padding:2rem 1.8rem;position:relative;}
.esc-step__n{counter-increment:s;font-family:var(--display);font-weight:700;font-size:1rem;width:42px;height:42px;border-radius:50%;background:var(--blue);color:#fff;display:grid;place-items:center;margin-bottom:1.1rem;}
.esc-step__n::before{content:"0" counter(s);}
.esc-step h3{font-size:1.25rem;}
.esc-step p{color:var(--muted);margin:0;}

/* ---------- Quote / results ---------- */
.esc-quote{font-family:var(--display);font-weight:600;font-size:clamp(1.5rem,3vw,2.3rem);line-height:1.25;letter-spacing:-.01em;max-width:22ch;}
.esc-quote .hl{color:var(--coral);}

/* ---------- Marquee ---------- */
.esc-marquee{overflow:hidden;-webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);}
.esc-marquee__track{display:flex;gap:3rem;width:max-content;animation:marquee 32s linear infinite;}
.esc-marquee__track span{font-family:var(--display);font-weight:600;font-size:1.15rem;color:var(--muted);white-space:nowrap;display:inline-flex;align-items:center;gap:3rem;}
.esc-marquee__track span::after{content:"•";color:var(--coral);}
@keyframes marquee{from{transform:translateX(0);}to{transform:translateX(-50%);}}

/* Logo band. The customer marks are dark, so this band is light where the
   word marquee is ink. Logos are held to one optical size by the file itself
   (normalize_logos.py fits each mark to the same share of a fixed canvas),
   so the CSS only has to set a height and let width follow. */
.esc-marquee--logos .esc-marquee__track{gap:0}
/* The word band separates its terms with an orange bullet. Logos separate
   themselves, so the bullet has to be switched off or it reads as debris
   between the marks. */
.esc-marquee--logos .esc-marquee__track span::after{content:none}
.esc-marquee__logo{display:inline-flex;align-items:center;justify-content:center;
  padding-inline:clamp(1.8rem,4vw,3.6rem)}
.esc-marquee__logo img{height:46px;width:auto;display:block;object-fit:contain;
  opacity:.55;filter:grayscale(1);
  transition:opacity .3s var(--ease),filter .3s var(--ease)}
.esc-marquee__logo img:hover{opacity:1;filter:none}
@media(max-width:620px){
  .esc-marquee__logo img{height:34px}
  .esc-marquee__logo{padding-inline:1.4rem}
}
@media (prefers-reduced-motion:reduce){
  .esc-marquee--logos .esc-marquee__track{animation:none;justify-content:center;
    flex-wrap:wrap;width:100%}
}

/* ---------- CTA band ---------- */
.esc-cta{position:relative;overflow:hidden;border-radius:var(--r-lg);padding:clamp(2.6rem,5vw,4.4rem);background:var(--blue);color:#fff;}
.esc-cta__glow{display:none;}
.esc-cta__inner{position:relative;z-index:2;}
.esc-cta h2{color:#fff;max-width:18ch;}

/* ---------- Footer ---------- */
.esc-footer{background:var(--ink);color:#fff;padding-block:clamp(48px,7vw,80px) 32px;}
.esc-footer a{color:rgba(255,255,255,.72);}
.esc-footer a:hover{color:#fff;text-decoration:none;}
.esc-footer__grid{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:2.5rem;}
.esc-footer__logo img{height:24px;width:auto;margin-bottom:1rem;}
/* Footer column labels are h2, not h4. An h4 straight after the page h1 or
   h2 skips a level, which every page was doing. The look is unchanged. */
.esc-footer__col h4,.esc-footer__h{font-family:var(--body);font-weight:600;font-size:.82rem;letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.5);margin:0 0 1rem;}
.esc-footer__col ul{list-style:none;margin:0;padding:0;display:grid;gap:.6rem;}
.esc-footer__bottom{margin-top:3rem;padding-top:1.5rem;border-top:1px solid rgba(255,255,255,.12);display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;color:rgba(255,255,255,.55);font-size:.9rem;}

/* ---------- Scroll reveal ---------- */
/* Everything below starts at opacity:0 and waits for JavaScript to add a
   class. Measured 2026-08-21: with scripts off that hid 79% of the home page
   text, 91% of services and 82% of about, and the hero rendered as an empty
   white screen. The words were in the HTML the whole time, so a plain crawler
   read them, but any client that applies CSS without running scripts saw
   nothing, and a single script error would have done the same to a visitor.
   The block below hands every one of those elements back when scripting is
   off, which costs no JavaScript at all. */
@media (scripting: none){
  /* The reveals, the figure arrivals and the rail used to need rescuing here.
     They no longer do: their hidden start state exists only inside an
     @supports block that guarantees the browser animates it back, so they are
     visible by default whatever happens to scripts. What remains below is the
     one component whose LAYOUT is computed by script. */

  /* The stat gallery is a coverflow: every card is absolutely stacked at
     opacity:0 and JavaScript promotes one to active. With no script the whole
     set disappears, and the set is the proof numbers, which is the content
     most worth being readable. This gives it a resting state that shows all of
     it as a plain row, no script and no change to the markup. */
  .esc-gal__track{height:auto!important;display:grid!important;
    grid-template-columns:repeat(auto-fit,minmax(240px,1fr))!important;
    gap:1.2rem!important}
  .esc-gcard{position:static!important;width:auto!important;height:280px!important;
    margin-left:0!important;transform:none!important;opacity:1!important;
    pointer-events:auto!important;filter:none!important}
  /* The card's inner block carries its own opacity, so raising the card alone
     leaves the number and its label invisible. That inner block is the stat. */
  .esc-gcard__in{opacity:1!important;transform:none!important;
    margin-left:0!important;text-align:left!important}
  /* Type scaled to the smaller card. Without this the coverflow's 4.4rem
     number overflows a 240px-wide tile and is cut off. Mirrored in the
     editor-canvas block below; change one and change the other. */
  .esc-gcard{height:auto!important;min-height:260px!important}
  .esc-gcard__big{font-size:2.3rem!important;line-height:1.05!important}
  .esc-gcard__lbl{font-size:.95rem!important;line-height:1.4!important;
    max-width:none!important;margin-top:.5rem!important}
  .esc-gcard__in{max-width:none!important;padding-right:.4rem!important}
  .esc-gal__ui,.esc-gal__dots,.esc-gal__arrows{display:none!important}

  /* The support cards orbiting the phone, and the chips inside it. Both start
     at opacity:0 and wait for script to add .is-in to the orbit and .show to
     each chip, so with scripts off the phone sat in empty space on desktop.
     Below 980px they are already static and visible, and reduced-motion
     already rescues them; this is the third client that needed the same
     answer. Measured 2026-08-26: these six cards were the ONLY page text
     genuinely lost to a missing script, 197 characters of 6616. */
  .esc-sat{opacity:1!important;transform:none!important;transition:none!important}
  .esc-chip{opacity:1!important;transform:none!important;transition:none!important}
}
/* Arrival animation is driven by the scroll position in CSS, with no
   IntersectionObserver and no class toggling.
   The important part is not the saved JavaScript, it is the inversion: an
   element is visible by default, and only starts hidden inside the @supports
   block, where the browser is guaranteed to animate it back. The old
   arrangement had every element invisible until a script rescued it, which is
   what blanked most of the site when scripts did not run. A browser without
   scroll-driven animation now simply shows the content with no animation.
   Longhand, not the `animation:` shorthand, because the shorthand resets
   animation-timeline to auto and the effect silently stops working. */
@keyframes esc-rise{from{opacity:0;transform:translateY(26px)}to{opacity:1;transform:none}}
@keyframes esc-rise-scale{from{opacity:0;transform:translateY(28px) scale(.965)}
  to{opacity:1;transform:none}}
@keyframes esc-plate{from{opacity:0;transform:translate(10px,-14px)}
  to{opacity:1;transform:translate(0,0)}}
@keyframes esc-line{from{transform:scaleX(0)}to{transform:scaleX(1)}}

@supports (animation-timeline: view()){
  @media not (prefers-reduced-motion: reduce){
    .reveal{animation-name:esc-rise;animation-fill-mode:both;
      animation-timing-function:linear;animation-timeline:view();
      animation-range:entry 0% entry 58%}
    .reveal.d1{animation-range:entry 4% entry 62%}
    .reveal.d2{animation-range:entry 8% entry 66%}
    .reveal.d3{animation-range:entry 12% entry 70%}
    .reveal.d4{animation-range:entry 16% entry 74%}
  }
}
@media (prefers-reduced-motion:reduce){.esc-marquee__track{animation:none;}}

/* ---------- Gutenberg alignment guards ---------- */
.wp-block-group.alignfull{margin-block:0;}
/* WordPress zeroes the block margins on the children of a flow layout. This
   guard restores the START margin only, and deliberately so.

   Tried and reverted 2026-08-26: adding margin-block-end:revert here. `revert`
   rolls a declaration back to the BROWSER's default rather than to our own
   stylesheet, so instead of restoring theme margins it handed paragraphs and
   headings their user-agent margins. Four pages changed height, home by 53px,
   services by 109px and about by 104px, and nothing that was meant to be fixed
   was fixed. Where a converted section needs its bottom margin back, give that
   element its own rule rather than reaching for revert again. */
.is-layout-flow>*{margin-block-start:revert;}

/* ---------- Tables ----------
   The theme carried no table styling at all, so the cookie tables on the
   privacy policy rendered with core block-library defaults and were CLIPPED on
   a phone: body{overflow-x:clip} swallowed the overflow, so find_overflow.py
   reported the page clean at 390px while the Expires column sat off-screen and
   every cell wrapped to one word per line. The figure scrolls on its own axis
   instead, and min-width keeps the columns readable rather than letting them
   collapse. Verified 2026-08-25 at 390px and 1440px. */
.wp-block-table{display:block;margin:2rem 0;overflow-x:auto;-webkit-overflow-scrolling:touch;}
.wp-block-table table{width:100%;min-width:38rem;border-collapse:collapse;font-size:.95rem;line-height:1.5;}
.wp-block-table th,.wp-block-table td{padding:.7rem .9rem;text-align:left;vertical-align:top;border:1px solid var(--line);}
.wp-block-table thead th{font-family:var(--body);font-weight:600;font-size:.78rem;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);background:var(--mist);}
.wp-block-table tbody tr:nth-child(even) td{background:#FBFCFF;}
.wp-block-table code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.88em;background:var(--cream);padding:.12em .28em;border-radius:4px;white-space:nowrap;}

/* ---------- Legal pages ----------
   The privacy policy is ~3,200 words of continuous prose. In the full 1,140px
   content column that is about 150 characters a line, which nobody reads.

   Every child gets the SAME fixed measure, not a ch value. Two earlier attempts
   failed for reasons worth keeping:
   1. `70ch` resolves against each element's own font-size, so a display-type h2
      never reached the cap and stayed 1,140px wide while the prose narrowed.
      The two left edges stopped agreeing.
   2. Overriding the margins to force everything flush left does not work either.
      Gutenberg's constrained layout sets `margin-left:auto !important` on its
      children, so the column re-centres whatever this file says.
   One fixed max-width on every child sidesteps both: each block is the same
   width, core centres them all identically, and the edges line up. */
.privacy-policy .wp-block-post-content>*{max-width:48rem;}
.privacy-policy .wp-block-post-content>.wp-block-table{max-width:48rem;}
.privacy-policy .wp-block-post-content>h2{margin-top:2.8rem;font-size:clamp(1.6rem,2.4vw,2.1rem);}
.privacy-policy .wp-block-post-content>h3{margin-top:1.9rem;font-size:1.35rem;}
.privacy-policy .wp-block-post-content>h2:first-child{margin-top:0;}
.privacy-policy .wp-block-separator{max-width:48rem;margin-top:3rem;margin-bottom:3rem;border:0;border-top:1px solid var(--line);}
.privacy-policy .wp-block-post-title{max-width:48rem;margin-left:auto;margin-right:auto;font-size:clamp(2.2rem,4vw,3.2rem);}

/* ---------- Proof panel ----------
   A cobalt panel of headline numbers, built to sit beside the contact form so the
   page can lead on proof without a hero pushing the form below the fold.

   COLOUR IS NOT A CHOICE HERE. The number is light blue and the supporting line
   is white. Orange on brand blue measures 2.75:1, under the 3.0 minimum, and Rene
   has a red/green colour vision difference that makes an orange figure on this
   blue unreadable. Orange is only allowed to carry a big stat number on a light
   panel, cream or light blue. See reference_escalate_stat_colour_on_dark_panels. */
/* The contact section sits on the mist wash so the white form card separates
   from the page instead of floating on the same white. Three levels now: mist
   page, white card, white fields inside a stronger border. */
.esc-section--contact{background:var(--mist);}
.esc-section--contact .esc-form{border-color:var(--line-strong);}
.esc-section--contact .esc-form input,
.esc-section--contact .esc-form select,
.esc-section--contact .esc-form textarea{border-color:var(--line-strong);background:#fff;}
.esc-section--contact .esc-form input:focus,
.esc-section--contact .esc-form select:focus,
.esc-section--contact .esc-form textarea:focus{outline:2px solid var(--blue);outline-offset:1px;border-color:var(--blue);}

/* ---------- Press credential ----------
   A third-party name does more for credibility than any number we write
   ourselves, so it sits above the panel rather than inside it. NPR ran a
   national feature on 2026-08-17; the link goes to the piece so the claim is
   checkable rather than asserted. */
.esc-cred{display:flex;align-items:center;gap:.75rem;margin-top:1.3rem;}
.esc-cred__rule{flex:0 0 28px;height:2px;background:var(--orange);border-radius:2px;}
/* The credential IS the masthead, so the masthead carries the display face and
   the date stays small. An earlier pass had this the wrong way round and set the
   month in the big serif while NPR sat in body text. */
.esc-cred__txt{margin:0;font-size:.88rem;color:var(--muted);line-height:1.4;}
.esc-cred__txt a{font-family:var(--display);font-weight:700;font-size:1.05rem;color:var(--ink);letter-spacing:.005em;text-decoration:none;border-bottom:2px solid var(--orange);padding-bottom:0;}
.esc-cred__txt a:hover{color:var(--blue);border-bottom-color:var(--blue);}
/* Rene, 2026-08-26: the credential is one line, not a three-line masthead. The
   date used to sit on its own row under an outsized NPR wordmark and the block
   ate ~70px above the fold. Separator lives in CSS so the block content stays
   plain text an editor can retype without breaking the punctuation. */
.esc-cred__txt .esc-cred__when{display:inline;margin-top:0;}
.esc-cred__txt .esc-cred__when::before{content:"\00B7";margin:0 .4rem;color:var(--muted);}
.esc-trust__row img{height:30px;}

/* ---------- Customer row ---------- */
.esc-trust{margin-top:1.4rem;}
.esc-trust__label{margin:0 0 .7rem;font-family:var(--body);font-weight:600;font-size:.74rem;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);}
.esc-trust__row{display:flex;align-items:center;gap:2rem;flex-wrap:wrap;}
.esc-trust__row img{height:26px;width:auto;opacity:.55;filter:grayscale(1);}
/* The customer logos were bare imgs and are wp:image now, so each one arrives
   wrapped in a figure carrying WordPress's default bottom margin. The row grew
   from 26px to 43px and pushed everything below it down by 17px. The row owns
   its spacing through gap, so the figures need none. */
.esc-trust__row figure{margin:0;line-height:0;}

/* Rene, 2026-08-26: this was a tall blue card stacking three numbers, ~430px of
   the left column for three facts. It is a rule-topped row now: three across
   while the column can hold them, stacked into number-beside-label lines when it
   cannot. Same three numbers, about a quarter of the height either way. */
.esc-proof{background:transparent;border-radius:0;padding:1.3rem 0 0;margin-top:1.5rem;border-top:1px solid var(--line-strong);}
.esc-proof__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1.4rem;}
.esc-proof__item+.esc-proof__item{margin-top:0;padding-top:0;border-top:0;}
.esc-proof__num{font-family:var(--display);font-weight:700;font-size:clamp(1.45rem,2.1vw,1.85rem);line-height:1.05;letter-spacing:-.02em;color:var(--blue);margin:0;}
.esc-proof__txt{color:var(--muted);font-size:.84rem;line-height:1.4;margin:.3rem 0 0;max-width:none;}
.esc-proof__foot{color:var(--muted);font-size:.78rem;line-height:1.4;margin:1.1rem 0 0;}
/* Below this the three cells are too narrow for "$300,000" to sit over its own
   label, so each number moves beside its label instead of above it. */
@media(max-width:1080px){
  .esc-proof__grid{grid-template-columns:1fr;gap:.75rem;}
  .esc-proof__item{display:flex;align-items:baseline;gap:.85rem;}
  .esc-proof__num{flex:0 0 auto;min-width:6rem;font-size:1.4rem;}
  .esc-proof__txt{margin:0;}
}
/* The contact page leads with the form, so its left column starts at the top
   rather than centring against a form that is much taller than the copy. */
.esc-section--contact .esc-2col{align-items:start;}
.esc-section--contact h1{font-size:clamp(2.1rem,3.6vw,3rem);margin-bottom:.5rem;}

/* ---------- Case study pages ----------
   Same fixed measure the legal pages use, and for the same reason: a `ch` value
   resolves against each element's own font-size, so display type never reaches
   the cap and the headings and the prose stop sharing a left edge. One width on
   every child gives the page a single column. */
/* page-id-145 is the case studies index itself; parent-pageid-145 is each child
   page. Both need the same column, or the index lede centres while its heading
   sits flush left. */
/* The case study template owns its own widths, so no measure cap here. The
   pull quote and the button row still want one, and they are the only blocks on
   these pages that sit directly in the content flow. */
/* The hero carries the h1 on these pages, so the template's own post title is
   result and the case-studies listing all read.

   REMOVED 2026-08-25: a block of `.parent-pageid-145 .wp-block-post-content>*`
   caps at 48rem, plus a display:none on the post title. All of it was scaffolding
   for the approach that preceded the page-wide template, and every rule outlived
   its purpose. They were also MORE SPECIFIC than the component rules underneath,
   so the quote kept snapping back to 768px while the button row beside it sat at
   1180 and the two would not line up. Dead CSS does not just sit there; it wins
   arguments it should not be in. */
.esc-cs--quote{background:var(--cream);border-radius:var(--r-lg);padding:2rem 2.2rem;margin:2.5rem auto;border-left:0;max-width:1180px;box-sizing:border-box;}
.esc-cs--quote p{font-family:var(--display);font-size:1.25rem;line-height:1.45;margin:0;}
.esc-cs--quote cite{display:block;margin-top:.7rem;font-family:var(--body);font-style:normal;font-size:.95rem;color:var(--muted);}

/* ---------- Case study template ----------
   Modelled on the structure of the Pulsora customer pages: a two-column hero
   with the customer's own logo beside a dark stat card, a full-bleed metric
   band, then the story with a sticky snapshot card alongside it. Escalate has
   fewer facts per customer than Pulsora does, so the snapshot carries what we
   actually know rather than empty rows.

   Every stat number on cobalt is light blue with white supporting text. Orange
   on brand blue measures 2.75:1 and is banned for stat numbers.
   See reference_escalate_stat_colour_on_dark_panels. */

/* The case study pages use the page-wide template, which already renders an
   unconstrained main with no post title. That template existed before this
   build; three CSS workarounds were written before I looked for it.

   Two viewport-unit tricks were tried first and both failed, because 50% and
   left:50% resolve against the PARENT rather than the viewport. The third
   attempt hid the post title with display:none, which the semantic checker
   correctly rejected: a hidden h1 is still an h1, so the page still had two.
   Assigning the right template removes all three problems at once.

   The lesson is in the theme: look for the template before writing CSS to
   simulate one. */

.parent-pageid-145 .wp-block-post-content>.wp-block-buttons{max-width:1180px;margin:1.5rem auto 3rem;padding:0 24px;}
.esc-cs-hero{background:var(--cream);padding:4.5rem 0 4rem;}
.esc-cs-hero__grid{display:grid;grid-template-columns:1.15fr .85fr;gap:3.5rem;align-items:center;}
/* The customer logo. Written when the logo was a bare <img>; as a wp:image the
   class moves onto the FIGURE and the picture inside it is unconstrained, so
   the McDonald's mark rendered at its natural 520x200 across the headline while
   its box stayed 44px tall. Every converted image needs the figure sized and
   the picture told to follow it (memory/reference_wp_treatments_stay_editable).
   fit-content, because a figure is a block and would otherwise run the full
   column width and take the margin with it. */
.esc-cs-hero__logo{height:44px;width:fit-content;margin:0 0 1.6rem;}
.esc-cs-hero__logo img{height:44px;width:auto;display:block;}
.esc-cs-hero h1.esc-cs-hero__h,.esc-cs-hero .esc-cs-hero__h{font-size:clamp(2.1rem,3.6vw,3.1rem);line-height:1.08;margin:0 0 1rem;}
/* The standfirst carries the numbers now, so it gets more room and a little
   more weight than a caption. Rene, 2026-08-26: be bolder. */
.esc-cs-hero__dek{font-size:1.24rem;line-height:1.5;color:var(--ink);
  max-width:56ch;margin:0 0 1.6rem;}
/* The standfirst is the last child of its group, and WordPress zeroes the
   bottom margin of a last child in a flow layout. As raw HTML the paragraph
   kept its 1.6rem; as a block it lost it, which is the 26px the index dropped
   when it was converted. Two classes, so the rule outranks core's. */
.esc-cs-hero .esc-cs-hero__dek{margin-bottom:1.6rem;}

/* The dark card. One headline figure, then labelled rows under hairlines. */
/* The card was a solid near-black slab. Rene, 2026-08-25: too omnipresent, keep
   black as an element rather than the whole field. So the card is now white on
   the site's own statcard language, and black appears twice on purpose: as the
   label chip and as the figure itself. The cobalt metric band below still gives
   the page its dark break, so nothing is lost by lightening the card. */
.esc-cs-card{background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--sh-2);padding:2.2rem 2.3rem;}
.esc-cs-card__label{display:inline-block;margin:0 0 1.2rem;padding:.42rem .72rem;background:var(--blue);color:#fff;border-radius:7px;font-family:var(--body);font-weight:600;font-size:.7rem;letter-spacing:.13em;text-transform:uppercase;}
/* ---------- The preview card, given something to read ----------
   Rene, 2026-08-26: the case study index is barren and the preview cards have
   no meat on them. A card carrying one figure and a caption is a link with
   decoration. These parts are what make it worth reading before the click: who
   the customer is, how big they are, and what else changed besides the headline
   number. Every figure comes from the story page it links to. */
/* Bigger and at full strength, Rene 2026-08-26. The grey filter and the 62%
   opacity were washing out a mark that is already monochrome: both files, ours
   and the client's own on escalateusa.com, measure zero coloured pixels, so the
   filter removed nothing and only made the logo faint. Colour would need the
   official brand marks, which is a trademark decision rather than a CSS one. */
.esc-cs-card__logo{display:block;height:80px;margin:0 0 1.4rem;}
.esc-cs-card__logo img{height:80px;width:auto;display:block;}
.esc-cs-card__ctx{margin:.9rem 0 0;font-size:.95rem;line-height:1.5;
  color:var(--muted);}
.esc-cs-card__stats{display:grid;grid-template-columns:repeat(3,1fr);
  gap:1rem;margin-top:1.4rem;padding-top:1.2rem;
  border-top:1px solid var(--line);}
/* The supporting numbers in orange. Rene: the cards read as black and white.
   Orange on a LIGHT panel is the one place it is allowed to carry a figure, and
   it appears nowhere else on this page, so the numbers become the colour rather
   than decoration doing it (memory/reference_escalate_stat_colour_on_dark_panels). */
.esc-cs-card__statnum{margin:0;font-family:var(--display);font-weight:700;
  font-size:1.35rem;line-height:1.1;letter-spacing:-.01em;color:var(--coral);}
.esc-cs-card__statlab{margin:.3rem 0 0;font-size:.82rem;line-height:1.35;
  color:var(--muted);}
@media(max-width:560px){
  .esc-cs-card__stats{grid-template-columns:1fr 1fr;}
}
.esc-cs-card__big{font-family:var(--display);font-weight:700;font-size:clamp(2.8rem,4.6vw,3.8rem);line-height:1;letter-spacing:-.02em;color:var(--ink);margin:0;}
.esc-cs-card__cap{color:var(--muted);margin:.5rem 0 0;font-size:1rem;}
.esc-cs-card__row{margin-top:1.3rem;padding-top:1.3rem;border-top:1px solid var(--line);}
.esc-cs-card__k{margin:0;font-size:.74rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);}
.esc-cs-card__v{margin:.3rem 0 0;color:var(--ink);font-size:1.02rem;}
a.esc-cs-card{transition:box-shadow .2s var(--ease),transform .2s var(--ease);}
a.esc-cs-card:hover{box-shadow:0 14px 40px rgba(16,16,29,.13);transform:translateY(-2px);}
a.esc-cs-card .esc-cs-card__v{color:var(--blue);font-weight:600;}

/* Full-bleed metric band. */
.esc-cs-band{background:var(--blue);padding:3.2rem 0;}
.esc-cs-band__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:2.5rem;}
.esc-cs-band__num{font-family:var(--display);font-weight:700;font-size:clamp(2.4rem,4vw,3.4rem);line-height:1;letter-spacing:-.02em;color:#DEE3FF;margin:0;}
.esc-cs-band__lab{margin:.6rem 0 0;color:#fff;font-size:.82rem;letter-spacing:.1em;text-transform:uppercase;line-height:1.4;}

/* Story, with the snapshot card sticky beside it. */
.esc-cs-body{padding:4rem 0 1rem;}
.esc-cs-body__grid{display:grid;grid-template-columns:300px 1fr;gap:3.5rem;align-items:start;}
.esc-cs-snap{border:1px solid var(--line-strong);border-radius:var(--r);padding:1.5rem 1.6rem;position:sticky;top:100px;}
.esc-cs-snap__h{margin:0 0 1rem;font-family:var(--body);font-weight:600;font-size:.74rem;letter-spacing:.14em;text-transform:uppercase;color:var(--blue);}
.esc-cs-snap__row+.esc-cs-snap__row{margin-top:.9rem;padding-top:.9rem;border-top:1px solid var(--line);}
.esc-cs-snap__k{margin:0;font-size:.86rem;color:var(--muted);}
.esc-cs-snap__v{margin:.15rem 0 0;font-weight:600;}
.esc-cs-prose>h2{font-size:clamp(1.5rem,2.4vw,2rem);margin:2.4rem 0 .7rem;}
.esc-cs-prose>h2:first-child{margin-top:0;}
.esc-cs-prose>p{margin:0 0 1rem;}
/* WordPress zeroes the bottom margin of the last child of a flow layout, so the
   closing paragraph of a converted story lost its 1rem and each case study page
   came up 16px short. Two classes, so the rule outranks core's. */
.esc-cs-body .esc-cs-prose>p{margin-bottom:1rem;}

@media (max-width:900px){
  .esc-cs-hero__grid,.esc-cs-body__grid{grid-template-columns:1fr;gap:2.2rem;}
  .esc-cs-band__grid{grid-template-columns:1fr;gap:1.8rem;}
  .esc-cs-snap{position:static;}
}
.esc-cardtools{position:absolute;top:8px;right:8px;z-index:6;display:flex;gap:4px;
  opacity:0;transition:opacity .15s ease}
.esc-gcard:hover .esc-cardtools,.esc-gcard:focus-within .esc-cardtools{opacity:1}
.esc-cardtools button{background:rgba(22,22,29,.82);color:#fff;border:0;
  border-radius:6px;width:28px;height:28px;cursor:pointer;font-size:13px;
  line-height:1;display:flex;align-items:center;justify-content:center}
.esc-cardtools button:hover{background:#1B3CF5}
.esc-cardtools button.is-danger:hover{background:#B3261E}
.esc-addcard{display:flex;align-items:center;justify-content:center;height:280px;
  border:2px dashed #b4b9c9;border-radius:14px;background:#FBFCFF;color:#1B3CF5;
  font-weight:700;cursor:pointer;font-size:14px;gap:8px}
.esc-addcard:hover{border-color:#1B3CF5;background:#F4F6FF}
/* The thread is rendered statically by render.php for the editor, and the
   bubbles carry .show already, so nothing here needs to force them visible. */

/* ---------- Responsive ---------- */
@media (max-width:980px){
  .esc-hero__inner{grid-template-columns:1fr;gap:2.5rem;}
  .esc-hero__panel{max-width:460px;}
  .esc-stats,.esc-cats,.esc-steps{grid-template-columns:1fr;}
  .esc-footer__grid{grid-template-columns:1fr 1fr;}
}
@media (max-width:860px){
  /* backdrop-filter makes .esc-header the containing block for every
     position:fixed descendant, so the open menu resolved `inset:74px 0 0`
     against the 74px header and stood 51px tall instead of covering the
     screen. The page then showed through between the links. No amount of
     z-index fixes that, because the box is the wrong size rather than behind
     anything. Dropping the blur at this width restores normal fixed
     positioning; the background goes solid because the translucency only ever
     read correctly with the blur behind it. */
  .esc-header{backdrop-filter:none;-webkit-backdrop-filter:none;background:#fff;}
  .esc-nav,.esc-header__cta .esc-btn{display:none;}
  .esc-burger{display:block;}
  .esc-nav.open{display:flex;position:fixed;inset:74px 0 0;background:#fff;flex-direction:column;align-items:flex-start;gap:.4rem;padding:1.6rem var(--gutter);z-index:99;}
  .esc-nav.open a{font-size:1.4rem;font-family:var(--display);padding:.5rem 0;width:100%;border-bottom:1px solid var(--line);}
  .esc-nav.open a::after{display:none;}
}
@media (max-width:560px){
  .esc-footer__grid{grid-template-columns:1fr;}
  .esc-statcard--float{position:static!important;margin-top:1rem;}
  .esc-hero__panel{max-width:100%;}
  .esc-section [style*="grid-template-columns:1fr 1fr"],
  .esc-section [style*="grid-template-columns:repeat(3,1fr)"],
  .esc-cta__inner[style]{grid-template-columns:1fr!important;}
  .esc-hero h1{font-size:clamp(2.1rem,9vw,2.8rem);}
}
@media (max-width:980px){
  .esc-hero__panel{max-width:520px;}
}

/* ============================================================
   EDITABLE-BLOCKS SUPPORT  (native Gutenberg conversion, home)
   Additive only. Reuses the existing design system; adds hooks so
   colored words and 2-col rows work as native, warning-free blocks.
   ============================================================ */
/* Hero headline colour now runs on native inline text-colour (mark +
   has-*-color), not on strong. Bold is bold again. Italic still drives
   the orange underline-highlight below. */
/* Browsers default <mark> to a yellow highlighter background. WordPress's
   native text-colour tool wraps a coloured word in exactly that tag, so
   without this reset every colour picked this way sat behind a yellow
   band nothing in the editor UI could explain or remove. */
mark.has-inline-color{background:transparent;}
.esc-hero h1 em{font-style:normal;position:relative;white-space:nowrap;}
.esc-hero h1 em::after{content:"";position:absolute;left:-2px;right:-2px;bottom:.06em;height:.34em;background:rgba(234,140,46,.30);z-index:-1;border-radius:3px;}
/* Coral highlight word in the results quote */
.esc-quote strong{color:var(--coral);font-weight:inherit;}
/* Two-column editable rows (results + CTA) */
.esc-2col{display:grid;grid-template-columns:1fr 1fr;gap:3.5rem;align-items:center;}
.esc-cta-2col{display:grid;grid-template-columns:1.3fr .7fr;gap:2rem;align-items:center;}
.esc-cta-actions{display:flex;flex-direction:column;gap:1rem;align-items:flex-start;}
.esc-statstack{display:grid;gap:1rem;}
@media (max-width:560px){
  .esc-2col,.esc-cta-2col{grid-template-columns:1fr!important;}
}
/* Neutralise WordPress block-group flow spacing inside our design containers */
.esc-hero__copy.wp-block-group,.esc-head.wp-block-group,.esc-step.wp-block-group,.esc-cat.wp-block-group{display:block;}
.esc-stats.wp-block-group,.esc-cats.wp-block-group,.esc-steps.wp-block-group{align-items:start;}

/* ============================================================
   EDITABLE-BLOCKS SUPPORT  (services / results / about / contact)
   Additive only. Replaces the former inline styles of the raw-HTML
   pages with real classes, so the same look survives native blocks.
   ============================================================ */
/* Interior page hero (shorter than the home hero) */
.esc-hero--page{padding-block:clamp(60px,8vw,110px);}
/* Page heroes carry a photo. A headline over a paragraph left the inner pages
   with nothing to look at above the fold. The copy column keeps its own
   max-width rule for pages that still run a hero without a photo. */
.esc-hero__split{position:relative;z-index:2;display:grid;
  grid-template-columns:1.08fr .92fr;gap:clamp(2rem,4vw,3.5rem);align-items:center;}
.esc-hero__split .esc-hero__narrow{max-width:none;}
.esc-fig--hero{height:380px;width:100%;max-width:340px;margin-left:auto;}
/* A landscape photo cropped into a portrait arch keeps only a narrow slice of
   the middle, which on a wide shot can be the blurred foreground rather than
   the subject. These shift the slice; add one to the figure, not the image. */
.esc-fig--focus-right .esc-fig__arch img{object-position:74% center;}
.esc-fig--focus-left .esc-fig__arch img{object-position:26% center;}
@media(max-width:980px){
  .esc-hero__split{grid-template-columns:1fr;gap:2.2rem;}
  .esc-fig--hero{margin-inline:auto;max-width:300px;height:330px;}
}
.esc-hero__narrow{position:relative;z-index:2;max-width:820px;}
.esc-hero__narrow .lede{margin-top:1.2rem;}
.esc-hero__pagenav{margin-top:1.6rem;display:flex;gap:1rem;flex-wrap:wrap;}

/* Stat blocks: pin the rhythm now that the text is a <p>, not a <div> */
.esc-stat p.esc-stat__txt{margin-block:.6rem 0;}
.esc-stat .esc-stat__rule{margin-top:1rem;}
.esc-statcard p.esc-statcard__label{margin-block:.45rem 0;}

/* Results: worked-example 3-up */
.esc-worked{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem;max-width:980px;margin-inline:auto;}
.esc-worked .esc-statcard+.esc-statcard{margin-top:0;}

/* Results: centered quote band */
.esc-centered-narrow{max-width:860px;margin-inline:auto;text-align:center;}
.esc-centered-narrow .esc-quote{margin-inline:auto;max-width:24ch;}
p.esc-note{color:var(--muted);margin-top:1.4rem;}

/* About / contact two-column rows aligned to the top */
.esc-2col--start{align-items:start;}

/* Contact page */
.esc-section--contact{padding-top:clamp(56px,7vw,96px);}
.esc-section--contact h1{font-size:clamp(2.2rem,4.5vw,3.4rem);}
/* Rene, 2026-08-26 chose the two short sentences INSIDE the headline rather than
   as a separate intro line, set smaller underneath. em, not rem, so it tracks
   the h1's own clamp instead of drifting away from it at either end. */
.esc-section--contact h1 .esc-h1__sub{display:block;margin-top:.5rem;font-size:.42em;line-height:1.25;letter-spacing:0;color:var(--blue);}
/* The customer logos moved out of the bottom of the copy column and above the
   form, where they land above the fold. */
.esc-section--contact .esc-trust{margin:0 0 1.3rem;}
/* And the address, the inbox and the reply time moved under the form, where a
   visitor who has just read it can check who they are about to write to. */
.esc-contact__meta{margin-top:1.5rem;display:grid;gap:.85rem;}
.esc-contact__row{display:flex;gap:.8rem;align-items:center;}
/* The email address used to be a bare anchor in this flex row. Gutenberg has no
   link block, so converting the page put it in a paragraph, and the paragraph
   arrived with a 17px top margin that pushed the row 5px taller. The row owns
   its own spacing through gap, so its children need none of their own. */
.esc-contact__row>p{margin:0;}
/* The tiles used to sit on white and were filled with mist. They sit ON the mist
   now, under the form card, so they invert: white fill, real border. */
.esc-contact__ic{flex:0 0 auto;width:32px;height:32px;border-radius:9px;background:#fff;border:1px solid var(--line-strong);color:var(--blue);display:grid;place-items:center;font-weight:700;font-size:.8rem;line-height:1;}
.esc-contact__addr{color:var(--ink);font-size:.92rem;}
.esc-section--contact .esc-contact__row{font-size:.92rem;}
/* The form column now stacks three things (logos, form, details) where it used
   to hold one. WordPress's flow rule would add its own 24px between each on top
   of the margins above, so the column owns its rhythm outright and each piece
   states its own gap. */
.esc-section--contact .reveal.d1 > *{margin-block-start:0;}
.esc-section--contact .esc-contact__meta > *{margin-block-start:0;}
.esc-proof > .esc-proof__grid{margin-block-start:0;}
.esc-contact__row a{font-weight:600;color:var(--ink);}
.esc-contact__muted{color:var(--muted);}
.esc-form{background:#fff;border:1px solid var(--line);border-radius:22px;box-shadow:var(--sh-2);padding:2rem;display:grid;gap:1rem;}
.esc-form__row{display:grid;grid-template-columns:1fr 1fr;gap:1rem;}
.esc-form label{display:grid;gap:.4rem;font-weight:600;font-size:.92rem;}
.esc-form input,.esc-form select,.esc-form textarea{padding:.8rem .9rem;border:1px solid var(--line);border-radius:10px;font:inherit;}
.esc-form select{background:#fff;}
.esc-form textarea{resize:vertical;}
.esc-form .esc-btn{justify-content:center;}
.esc-form #escFormMsg{margin:0;color:var(--blue);font-weight:600;display:none;}

/* ---------- HubSpot form container ----------
   ONLY the container is stylable from here. The HubSpot v2 embed renders the
   form inside a cross-origin iframe, so no rule in this stylesheet reaches the
   labels, inputs or the submit button, however specific it is. An earlier
   version of this block tried and changed nothing on screen.

   The form's own appearance lives in HubSpot, on the form record, under
   displayOptions.style: fontFamily, labelTextColor, labelTextSize,
   helpTextColor, submitColor, submitFontColor, submitSize, submitAlignment.
   Escalate's values are set there. Change them with a PATCH to
   /marketing/v3/forms/<id>, not here. The self-hosted Inter file is not
   available inside the iframe, so the fontFamily there names a fallback stack.

   Form 57db2cb4-24ce-45ad-b8c8-ed4e1702856a, portal 148867514, region eu1. */
.esc-form--hs{padding:1.4rem;}
.esc-form--hs iframe{width:100%;border:0;display:block;}

/* Neutralise WP flow spacing inside the new design containers */
.esc-svc.wp-block-group,.esc-statcard.wp-block-group,.esc-stat.wp-block-group{display:block;}
.esc-svc-grid.wp-block-group,.esc-worked.wp-block-group{align-items:start;}
.esc-svc.wp-block-group h4{margin:0 0 .3rem;}
.esc-svc.wp-block-group p{margin:0;}
.esc-step.wp-block-group h3{margin:0 0 .4rem;}

@media (max-width:860px){
  .esc-worked{grid-template-columns:1fr;}
}
@media (max-width:560px){
  .esc-2col--start{grid-template-columns:1fr!important;}
  .esc-form__row{grid-template-columns:1fr;}
}

/* ============================================================
   BLOCK-CONTEXT CORRECTIONS
   Two WordPress behaviours fight the design once content is
   native blocks. Both are corrected here, nothing else changes.

   1. `.is-layout-flow>*{margin-block-start:revert}` (the flow-spacing
      guard) reverts headings to the BROWSER default top margin
      (h1 .67em = 48.24px, h2 .83em = 39.84px), and WordPress's
      `:root :where(.wp-block-heading)` zeroes the bottom margin.
      Net effect: every heading sat ~50px too low. Restore the
      design's own `margin:0 0 .4em`.
   2. `.esc-head p` (0,1,1) outranks `.esc-eyebrow` (0,1,0), so an
      eyebrow authored as <p> instead of <div> rendered at 17.6px
      muted grey instead of 12.48px brand blue.
   ============================================================ */
.esc-hero h1.wp-block-heading,
.esc-head h2.wp-block-heading,
.esc-cta h2.wp-block-heading{margin:0 0 .4em;}
.esc-step h3.wp-block-heading,
.esc-cat h3.wp-block-heading{margin:0 0 .4em;}
.esc-svc h4.wp-block-heading{margin:0 0 .3rem;}

/* Eyebrows are paragraphs now: restore size, colour and rhythm */
.esc-head p.esc-eyebrow,
.esc-hero p.esc-eyebrow{font-size:.78rem;color:var(--blue);margin:0 0 1rem;}
.bg-blue .esc-head p.esc-eyebrow,
.bg-ink .esc-head p.esc-eyebrow{color:#fff;}

/* Restore the paragraph bottom rhythm WordPress zeroes out */
.esc-hero p.lede,
.esc-head p:not(.esc-eyebrow){margin-block-end:1.1em;}

/* ---------- CTA PANEL CONTRAST FIX (2026-07-18) ----------
   .esc-cta paints itself blue with background:var(--blue) but does not carry
   the .bg-blue class, so the rules that flip text to white never matched.
   Result: the eyebrow rendered brand blue on blue and was invisible, and the
   ghost button rendered near-black on blue. Both fixed here. */
.esc-cta .esc-eyebrow{color:#fff;}
.esc-cta .esc-eyebrow::before{background:var(--orange);}
.esc-cta .esc-btn--ghost{color:#fff;border-color:rgba(255,255,255,.55);}
.esc-cta .esc-btn--ghost:hover{background:#fff;color:var(--blue);border-color:#fff;}

/* ============================================================
   ESCALATE IMAGE TREATMENTS  (added 2026-07-18)
   The photography system agreed with Rene. Components:
     .esc-fig       offset plate + arch, the signature device
     .esc-gal       coverflow gallery for the stats band
     .esc-convo     conversation section on moss
     .esc-rail      connected how-it-works steps
     .esc-peek      photo with a card overlapping it
   Plate colours are restricted to orange and blue; moss and light blue
   were dropped because they read as a shadow rather than a decision.
   ============================================================ */

/* ---------- signature device: arch with an offset plate ---------- */
.esc-fig{position:relative}
.esc-fig__plate{position:absolute;left:-16px;top:20px;width:100%;height:100%;
  border-radius:999px 999px 18px 18px;z-index:1}
.esc-fig__plate--orange{background:var(--orange);}
.esc-fig__plate--blue{background:var(--blue);}
.esc-fig__arch{position:relative;z-index:2;height:100%;overflow:hidden;
  border-radius:999px 999px 18px 18px}
.esc-fig__arch img{width:100%;height:100%;object-fit:cover;display:block}

/* Predefined styles, picked from the block's own "Styles" panel, same
   mechanism as core's Image block. The plate stays visible on every style,
   Rene's call 2026-08-24, and its own corners follow the photo's rather
   than disappearing: an arch plate behind an arch photo, a square plate
   behind a square photo, a rounded plate behind a rounded photo.

   The hand-assembled version (most of the real photos on the site) wraps
   .esc-fig__plate and .esc-fig__arch in an outer group, but that outer
   group's own class varies by context: plain "esc-fig" on About, "esc-hero__fig"
   on the home hero, "esc-cat__fig" on category tiles, "esc-cta__fig" in CTAs.
   Scoping this to ".esc-fig" alone silently missed every other context, so
   these key off is-style-* wherever it lands, not the wrapper's own name. */
.is-style-standard .esc-fig__arch{border-radius:0;}
.is-style-rounded .esc-fig__arch{border-radius:var(--r-lg);}
.is-style-standard .esc-fig__plate{border-radius:0;}
.is-style-rounded .esc-fig__plate{border-radius:var(--r-lg);}

/* Arrival: the plate slides out from behind the photo. Scroll-driven in CSS,
   and visible by default where that is unsupported. The plate starts a little
   later than the photo so the colour follows the image rather than racing it. */
@supports (animation-timeline: view()){
  @media not (prefers-reduced-motion: reduce){
    .esc-fig--anim .esc-fig__arch,
    .esc-fig--anim .esc-fig__frame{animation-name:esc-rise-scale;
      animation-fill-mode:both;animation-timing-function:linear;
      animation-timeline:view();animation-range:entry 0% entry 55%}
    .esc-fig--anim .esc-fig__plate{animation-name:esc-plate;
      animation-fill-mode:both;animation-timing-function:linear;
      animation-timeline:view();animation-range:entry 8% entry 64%}
  }
}

/* Standalone arch. .esc-fig has no intrinsic height and .esc-fig__arch is
   height:100%, so the device collapses unless a parent sizes it. On the home
   page a grid cell does that. This modifier lets the pattern stand on its own
   in normal flow, which is how the inner pages use it. */
.esc-fig--solo{height:400px;width:100%;max-width:400px;margin-inline:auto}
@media(max-width:820px){.esc-fig--solo{height:340px;max-width:340px}}

/* Section head paired with a photo in a core columns block. The plate is
   absolutely positioned at top:20px, so it overhangs the column by 20px and
   would paint over whatever follows. This clears it. */
.esc-head--split{margin-bottom:clamp(2.5rem,5vw,4rem)}
.esc-head--split .esc-head{margin-bottom:0}

/* ---------- hero figure ---------- */
.esc-hero__fig{position:relative;height:430px;width:100%;max-width:390px;margin-left:auto}
.esc-hero__fig .esc-statcard{position:absolute;left:-70px;bottom:26px;z-index:3;max-width:250px;}
/* Three stats over the photo instead of one. Compact, because three cards at
   the full stat-card scale would cover the picture rather than sit on it.
   Staggered left so each card overlaps the arch by a different amount and the
   stack does not read as a solid slab down the edge. */
.esc-hero__stats{position:absolute;left:-120px;top:50%;transform:translateY(-50%);
  z-index:3;display:grid;gap:.6rem;width:236px}
.esc-hero__stats .esc-statcard{position:static;max-width:none;margin:0;
  padding:.85rem 1rem;border-radius:var(--r)}
.esc-hero__stats .esc-statcard:nth-child(2){margin-left:18px}
.esc-hero__stats .esc-statcard:nth-child(3){margin-left:36px}
.esc-hero__stats .esc-statcard__big{font-size:1.7rem}
.esc-hero__stats .esc-statcard__label{font-size:.8rem;margin-top:.2rem;line-height:1.35}
@media(max-width:980px){
  .esc-hero__stats{position:static;transform:none;width:100%;margin-top:1.2rem;
    grid-template-columns:repeat(3,1fr)}
  .esc-hero__stats .esc-statcard:nth-child(2),
  .esc-hero__stats .esc-statcard:nth-child(3){margin-left:0}
}
@media(max-width:620px){
  .esc-hero__stats{grid-template-columns:1fr}
}
@media(max-width:980px){
  .esc-hero__fig{margin-inline:auto;margin-top:2rem}
  .esc-hero__fig .esc-statcard{left:0}
}

/* ---------- category arches ---------- */
.esc-cat__fig{position:relative;height:260px;margin-bottom:2.1rem}
.esc-cat__fig .esc-fig__plate{left:-10px;top:14px;border-radius:999px 999px 14px 14px}
.esc-cat__fig .esc-fig__arch{border-radius:999px 999px 14px 14px}

/* ---------- coverflow gallery (blue stats band) ---------- */
/* The neighbour cards are pushed out sideways by design and nothing clipped
   them, so on a phone the right-hand card reached 545px against a 390px
   screen and the whole page scrolled sideways. `clip` rather than `hidden`
   because clip does not create a scroll container, which would otherwise
   change how focus and sticky positioning behave inside the gallery. */
.esc-gal{position:relative;margin-top:1rem;overflow-x:clip}
.esc-gal__track{position:relative;height:520px}
.esc-gcard{position:absolute;top:0;left:50%;width:min(560px,60%);height:100%;
  margin-left:calc(min(560px,60%) / -2);
  border-radius:26px;overflow:hidden;display:flex;align-items:flex-end;padding:2.4rem;
  cursor:pointer;will-change:transform,opacity;
  transition:transform .62s var(--ease),opacity .62s var(--ease),
             filter .62s var(--ease),box-shadow .62s var(--ease);
  transform:translateX(0) scale(.78);opacity:0;pointer-events:none;
  box-shadow:0 10px 26px rgba(0,0,0,.2)}
.esc-gcard.is-active{transform:translateX(0) scale(1);opacity:1;z-index:3;filter:none;
  pointer-events:auto;box-shadow:0 30px 70px rgba(0,0,0,.42)}
.esc-gcard.is-prev{transform:translateX(-62%) scale(.8);opacity:.74;z-index:2;
  filter:saturate(.9);pointer-events:auto}
.esc-gcard.is-next{transform:translateX(62%) scale(.8);opacity:.74;z-index:2;
  filter:saturate(.9);pointer-events:auto}
.esc-gcard.is-prev:hover,.esc-gcard.is-next:hover{opacity:.92;filter:none}
.esc-gcard img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transform:scale(1.08);transition:transform 1.2s var(--ease)}
.esc-gcard.is-active img{transform:scale(1)}
.esc-gcard::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,rgba(10,10,20,.93) 12%,rgba(10,10,20,.35) 52%,rgba(10,10,20,.05) 82%)}
.esc-gcard__in{position:relative;z-index:2;color:#fff;max-width:34ch;
  transform:translateY(18px);opacity:0;
  transition:transform .6s var(--ease) .12s,opacity .55s ease .12s}
.esc-gcard.is-active .esc-gcard__in{transform:translateY(0);opacity:1}
/* neighbours keep the number and label visible, which is the tease to click */
.esc-gcard.is-prev .esc-gcard__in,.esc-gcard.is-next .esc-gcard__in{opacity:1;transform:translateY(0)}
.esc-gcard.is-prev .esc-gcard__big,.esc-gcard.is-next .esc-gcard__big{font-size:3.1rem;opacity:.92}
.esc-gcard.is-prev .esc-gcard__lbl,.esc-gcard.is-next .esc-gcard__lbl{opacity:.88;font-size:.95rem;max-width:19ch}
/* the right card is overlapped on its left, so its content sits to the outer edge */
.esc-gcard.is-next .esc-gcard__in{margin-left:auto;text-align:right}
.esc-gcard.is-next .esc-gcard__lbl{margin-left:auto}
.esc-gcard__big{font-family:var(--display);font-weight:700;font-size:4.4rem;line-height:1;
  letter-spacing:-.02em;color:#fff;margin:0}
.esc-gcard__big .esc-gcard__accent{color:var(--orange)}
.esc-gcard__big .esc-gcard__num{color:inherit}
.esc-gcard__lbl{font-size:1.08rem;line-height:1.5;color:rgba(255,255,255,.9);margin:.7rem 0 0;max-width:32ch}
.esc-gal__ui{display:flex;align-items:center;justify-content:space-between;margin-top:2rem}
.esc-gal__dots{display:flex;gap:.55rem}
.esc-gal__dot{width:32px;height:4px;border-radius:99px;background:rgba(255,255,255,.32);
  border:0;padding:0;cursor:pointer;transition:background .35s,width .35s}
.esc-gal__dot.is-active{background:var(--orange);width:52px}
.esc-gal__arrows{display:flex;gap:.6rem}
.esc-gal__btn{width:48px;height:48px;border-radius:50%;border:1.5px solid rgba(255,255,255,.45);
  background:transparent;color:#fff;font-size:1.15rem;cursor:pointer;
  transition:background .3s,border-color .3s,transform .3s}
.esc-gal__btn:hover{background:#fff;color:var(--blue);border-color:#fff;transform:translateY(-2px)}
@media(max-width:820px){
  .esc-gal__track{height:430px}
  .esc-gcard{width:86%;margin-left:-43%;padding:1.8rem}
  .esc-gcard.is-prev{transform:translateX(-78%) scale(.82)}
  .esc-gcard.is-next{transform:translateX(78%) scale(.82)}
  .esc-gcard__big{font-size:3.2rem}
}

/* ---------- conversation section on moss ---------- */
.bg-moss{background:#3D4435;color:#fff}
.esc-convo{position:relative;overflow:hidden;padding-block:clamp(70px,8vw,110px)}
.esc-convo::after{content:"";position:absolute;inset:0;pointer-events:none;opacity:.35;
  background-image:linear-gradient(rgba(255,255,255,.05) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(255,255,255,.05) 1px,transparent 1px);
  background-size:64px 64px;
  -webkit-mask-image:radial-gradient(closest-side at 50% 40%,#000,transparent 78%);
          mask-image:radial-gradient(closest-side at 50% 40%,#000,transparent 78%)}
.esc-convo > .esc-wrap{position:relative;z-index:2}
.esc-convo__head{max-width:60ch;margin-inline:auto;text-align:center;
  margin-bottom:clamp(2.4rem,4vw,3.6rem)}
.esc-convo__head .esc-eyebrow{color:#fff;justify-content:center}
.esc-convo__head h2{color:#fff}
.esc-convo__head p{color:rgba(255,255,255,.78);font-size:1.1rem;max-width:52ch;margin-inline:auto}
.esc-orbit{position:relative;display:flex;justify-content:center;min-height:620px}
.esc-stage{display:flex;flex-direction:column;align-items:center;gap:18px;position:relative;z-index:3}
.esc-sat{position:absolute;z-index:2;width:312px;background:rgba(255,255,255,.09);
  border:1px solid rgba(255,255,255,.18);border-radius:18px;padding:20px 22px;
  backdrop-filter:blur(9px);-webkit-backdrop-filter:blur(9px);
  opacity:0;transform:translateY(16px);
  transition:opacity .7s var(--ease),transform .7s var(--ease)}
.esc-orbit.is-in .esc-sat{opacity:1;transform:translateY(0)}
.esc-sat__t{font-family:var(--display);font-size:1.3rem;color:#fff;line-height:1.2}
.esc-sat__l{font-size:.98rem;color:rgba(255,255,255,.72);margin-top:.45rem;line-height:1.45}
.esc-sat::before{content:"";position:absolute;left:22px;top:-1px;width:44px;height:3px;
  border-radius:2px;background:var(--orange)}
.esc-sat--l{left:20px}.esc-sat--r{right:20px}
.esc-sat--1{top:26px}.esc-sat--2{top:238px;left:64px}.esc-sat--3{top:450px}
.esc-sat--4{top:26px}.esc-sat--5{top:238px;right:64px}.esc-sat--6{top:450px}
.esc-orbit.is-in .esc-sat--1{transition-delay:.05s}
.esc-orbit.is-in .esc-sat--2{transition-delay:.14s}
.esc-orbit.is-in .esc-sat--3{transition-delay:.23s}
.esc-orbit.is-in .esc-sat--4{transition-delay:.10s}
.esc-orbit.is-in .esc-sat--5{transition-delay:.19s}
.esc-orbit.is-in .esc-sat--6{transition-delay:.28s}

/* phone */
.esc-phone{position:relative;width:274px;height:558px;border-radius:52px;padding:5px;
  background:linear-gradient(150deg,#e0e3eb,#a9adbd 24%,#777b8d 52%,#b8bcc9 76%,#8a8e9e);
  box-shadow:0 0 0 1px rgba(120,124,142,.5),inset 0 1.5px 2.5px rgba(255,255,255,.72),
             inset 0 -2.5px 6px rgba(60,63,80,.38),0 40px 80px rgba(0,0,0,.45);
  animation:escFloat 6.5s ease-in-out infinite}
@keyframes escFloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-9px)}}
.esc-phone .pwr{position:absolute;right:-2px;top:150px;width:3px;height:52px;border-radius:3px;
  background:linear-gradient(180deg,#b9bdc9,#7e8294)}
.esc-phone .vol{position:absolute;left:-2px;top:130px;width:3px;height:30px;border-radius:3px;
  background:linear-gradient(180deg,#b9bdc9,#7e8294)}
.esc-phone .vol:before{content:"";position:absolute;top:42px;left:0;width:3px;height:30px;
  border-radius:3px;background:linear-gradient(180deg,#b9bdc9,#7e8294)}
.esc-screen{position:relative;height:100%;border-radius:47px;background:var(--mist);
  overflow:hidden;display:flex;flex-direction:column}
.esc-notch{position:absolute;top:9px;left:50%;transform:translateX(-50%);width:82px;height:23px;
  border-radius:14px;background:#14141b;z-index:5}
.esc-bar{padding:42px 18px 10px;background:#fff;border-bottom:1px solid var(--line);
  display:flex;align-items:center;gap:9px}
.esc-avatar{width:30px;height:30px;border-radius:50%;background:var(--blue);color:#fff;
  display:grid;place-items:center;font-family:var(--display);font-size:13px;font-weight:700}
.esc-bar__t{font-weight:600;font-size:13px;line-height:1.2}
.esc-bar__s{font-size:10.5px;color:#9296A8}
.esc-thread{flex:1;overflow:hidden;padding:14px 13px;display:flex;flex-direction:column;gap:8px}
.esc-bub{max-width:86%;font-size:13.2px;line-height:1.45;padding:10px 13px;border-radius:16px;
  opacity:0;transform:translateY(9px) scale(.97);transition:opacity .4s ease,transform .4s ease}
.esc-bub.show{opacity:1;transform:none}
.esc-bub--them{align-self:flex-start;background:#fff;border:1px solid var(--line);
  border-bottom-left-radius:5px;color:var(--ink)}
.esc-bub--me{align-self:flex-end;background:var(--blue);color:#fff;border-bottom-right-radius:5px}
.esc-typing{align-self:flex-start;background:#fff;border:1px solid var(--line);border-radius:16px;
  border-bottom-left-radius:5px;padding:12px 14px;display:flex;gap:4px}
.esc-typing--me{align-self:flex-end;background:var(--blue);border:none;border-bottom-right-radius:5px}
.esc-typing i{width:6px;height:6px;border-radius:50%;background:#9296A8;animation:escBlink 1.2s infinite}
.esc-typing--me i{background:rgba(255,255,255,.75)}
.esc-typing i:nth-child(2){animation-delay:.2s}.esc-typing i:nth-child(3){animation-delay:.4s}
@keyframes escBlink{0%,60%,100%{opacity:.25}30%{opacity:1}}
.esc-mcard{align-self:flex-start;width:94%;background:#fff;border:1px solid #DDE1F0;
  border-radius:16px;padding:13px;opacity:0;transform:translateY(9px) scale(.97);transition:.4s}
.esc-mcard.show{opacity:1;transform:none}
.esc-mcard .k{font-size:10.5px;color:#9296A8;letter-spacing:.04em;text-transform:uppercase}
/* The value needs its own colour. Every other piece of the card sets one and
   this line did not, so it inherited white from the dark section and rendered
   white on the white card. It was invisible on the live site in every scenario,
   found 2026-08-27 while probing the card in the browser. */
.esc-mcard .v{font-size:15.5px;font-weight:600;margin-top:3px;line-height:1.25;color:var(--ink)}
.esc-mcard .meta{font-size:11.5px;color:var(--muted);margin-top:6px}
.esc-mcard .go{display:block;text-align:center;background:var(--blue);color:#fff;font-weight:600;
  font-size:12.5px;padding:10px;border-radius:11px;margin-top:11px}
.esc-bub--done{align-self:flex-end;background:linear-gradient(135deg,#2a8f5d,#33a168);color:#fff;
  border-bottom-right-radius:5px;font-weight:500;display:flex;align-items:center;gap:7px;
  transform:translateY(15px) scale(.9);
  transition:opacity .5s cubic-bezier(.2,1.5,.4,1),transform .5s cubic-bezier(.2,1.5,.4,1)}
.esc-bub--done.show{transform:none}
/* Capped so six tabs wrap to a second line INSIDE the clear channel between the
   two columns of support cards. Uncapped, the row runs 682px on one line and the
   stage outranks the cards in the stacking order, so it would print across them
   rather than behind.

   370px, not the 520px first tried. The channel is not a constant: it is the
   orbit width less both cards and their offsets, so it narrows from 468px at
   1440 to about 393px just above the 980px stacking breakpoint. 520 measured as
   an overlap at every width except 1220. 370 clears the cards everywhere the
   cards are beside the phone, and still leaves the six labels breaking three and
   three rather than four and two. */
.esc-tabs{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;
  max-width:370px;margin-inline:auto}
.esc-tabs button{font-family:inherit;font-size:11.5px;font-weight:600;padding:7px 14px;
  border-radius:20px;border:1px solid rgba(255,255,255,.2);background:rgba(255,255,255,.08);
  color:rgba(255,255,255,.72);cursor:pointer;transition:.18s}
.esc-tabs button:hover{color:#fff}
.esc-tabs button.on{background:#fff;color:#3D4435;border-color:#fff}
.esc-chips{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;min-height:32px}
/* The chips carry the outcome of the conversation, and they now sit between the
   phone and the lower tab row. As pills with a border they were the same object
   as a tab, so a reader met three rows of pills and had to click one to find out
   which were controls. Square corners, no border and a tick separate them.
   Rene, 2026-08-27. */
.esc-chip{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;font-weight:600;
  padding:6px 12px;border-radius:7px;background:rgba(255,255,255,.13);border:0;color:#fff;
  opacity:0;transform:translateY(7px);transition:.45s}
.esc-chip::before{content:"\2713";font-size:12px;line-height:1;opacity:.9}
.esc-chip.show{opacity:1;transform:none}
.esc-chip--orange{background:rgba(234,140,46,.22);color:#F6C48A}
@media(max-width:1220px){.esc-sat{width:250px}.esc-sat--2{left:0}.esc-sat--5{right:0}}
@media(max-width:980px){
  .esc-orbit{flex-direction:column;align-items:center;min-height:0;gap:2.4rem}
  .esc-sat{position:static;width:100%;max-width:420px;opacity:1;transform:none}
  .esc-orbit .esc-stage{order:-1}
}

/* ---------- how it works: connected rail ---------- */
.esc-rail__head{max-width:640px;margin:0 auto clamp(2.6rem,4vw,3.4rem);text-align:center}
.esc-rail__head .esc-eyebrow{justify-content:center}
.esc-rail__head h2{font-size:clamp(1.9rem,3.2vw,2.7rem);margin:0 0 .5em;max-width:none}
.esc-rail__head p{color:var(--muted);margin:0}
.esc-rail{position:relative;display:grid;grid-template-columns:repeat(3,1fr);gap:2.4rem}
.esc-rail::before{content:"";position:absolute;top:26px;left:12%;right:12%;height:2px;
  background:linear-gradient(90deg,var(--blue),var(--orange));
  transform-origin:left center}
.esc-rail__step{position:relative;text-align:center}
@supports (animation-timeline: view()){
  @media not (prefers-reduced-motion: reduce){
    .esc-rail::before{animation-name:esc-line;animation-fill-mode:both;
      animation-timing-function:linear;animation-timeline:view();
      animation-range:entry 0% entry 62%}
    .esc-rail__step{animation-name:esc-rise;animation-fill-mode:both;
      animation-timing-function:linear;animation-timeline:view()}
    .esc-rail__step:nth-child(1){animation-range:entry 6% entry 56%}
    .esc-rail__step:nth-child(2){animation-range:entry 13% entry 63%}
    .esc-rail__step:nth-child(3){animation-range:entry 20% entry 70%}
  }
}
.esc-rail__dot{width:54px;height:54px;border-radius:50%;background:var(--blue);color:#fff;
  display:grid;place-items:center;font-family:var(--display);font-weight:700;font-size:1.05rem;
  margin:0 auto 1.3rem;border:4px solid var(--mist);position:relative;z-index:2}
.esc-rail__step h3{font-size:1.2rem;margin:0 0 .45rem}
.esc-rail__step p{font-size:.95rem;max-width:30ch;margin:0 auto;color:var(--muted)}
@media(max-width:900px){.esc-rail{grid-template-columns:1fr;gap:2rem}.esc-rail::before{display:none}}

/* ---------- photo with an overlapping card ---------- */
.esc-peek{position:relative;padding-top:30px}
.esc-peek__img{width:62%;height:380px;margin-left:auto;border-radius:22px;overflow:hidden}
.esc-peek__img img{width:100%;height:100%;object-fit:cover;display:block}
.esc-peek__card{position:absolute;left:0;top:120px;width:46%;background:#fff;
  border:1px solid var(--line);border-radius:22px;padding:2.2rem 2rem;box-shadow:var(--sh-2)}
.esc-peek__card h3{font-size:1.5rem;margin:0 0 .4em}
.esc-peek__card p{margin:0;color:var(--muted)}
@media(max-width:820px){
  .esc-peek__img{width:100%}
  .esc-peek__card{position:static;width:100%;margin-top:1.2rem}
}

/* ---------- Press credentials ----------
   A row of media links, built for the foot of the pilot card on the home page.
   The NPR mark is three saturated blocks, so it is kept small and the rule
   above it does the separating; at credential size it reads as a source rather
   than competing with the cobalt.

   The links point at OUR pages, /npr/ and /pr-mcd/, not at npr.org. Sending a
   visitor off-site from the one section that proves the pilot worked is the
   opposite of what the section is for. */
.esc-press{display:flex;align-items:center;gap:1.1rem;margin-top:1.5rem;
  padding-top:1.2rem;border-top:1px solid var(--line)}
.esc-press__logo{margin:0;flex:0 0 auto}
.esc-press__logo img{display:block;width:74px;height:auto;border-radius:3px}
.esc-press__links{margin:0;font-size:.88rem;line-height:1.55;color:var(--muted)}
.esc-press__links a{color:var(--ink);text-decoration:none;
  border-bottom:1px solid var(--line);padding-bottom:1px}
.esc-press__links a:hover{color:var(--blue);border-bottom-color:var(--blue)}
/* No narrow-screen override for the logo. The image block is is-resized, so
   Gutenberg writes style="width:74px" on the <img> itself and any width rule
   here loses to it. Measured at 390px: the row is 276 wide inside a 342 card
   and the mark sits at 74 with no distortion, so the override was dead code
   pretending to be a responsive rule. */
@media(max-width:420px){
  .esc-press{align-items:flex-start;gap:.9rem}
}

/* Page header built on the peek. The card overlapping the photo IS the design
   here, which is why the usual no-overlap rule does not apply: the card is
   solid, so no text ever crosses the image. Rene, 2026-08-21.
   Differences from the in-body peek: the card carries an h1 rather than an h3,
   so it needs more width and sits at the foot of the photo instead of near the
   top, and the photo runs taller because a header has to fill the fold. */
.esc-peek--header{padding-top:0}
.esc-peek--header .esc-peek__img{width:66%;height:clamp(340px,36vw,500px);
  border-radius:var(--r-lg)}
/* The card lifts clear of the photo's bottom edge rather than sitting flush on
   it, so it reads as floating over the image instead of being docked to it. */
.esc-peek--header .esc-peek__card{top:auto;bottom:clamp(28px,4vw,64px);width:54%;
  padding:clamp(1.8rem,3vw,2.6rem) clamp(1.6rem,2.6vw,2.4rem)}
.esc-peek--header .esc-peek__card h1{font-size:clamp(1.9rem,3.4vw,3rem);
  margin:0 0 .55rem}
.esc-peek--header .esc-peek__card .lede{margin:0;font-size:1.05rem}
.esc-peek--header .esc-hero__pagenav{margin-top:1.3rem}
@media(max-width:820px){
  .esc-peek--header .esc-peek__img{width:100%;height:260px}
  /* Keep a little of the overlap on a phone. Dropping it entirely turns the
     header into a stacked photo and paragraph, which is the layout this
     component exists to replace. */
  .esc-peek--header .esc-peek__card{margin-top:-2.6rem;width:calc(100% - 1.6rem);
    margin-inline:auto;position:relative;z-index:2}
}

/* ---------- CTA, rebuilt ---------- */
.esc-cta--split{display:grid;grid-template-columns:1.15fr .85fr;gap:clamp(2rem,4vw,3.6rem);
  align-items:center;padding:clamp(2.4rem,4vw,3.4rem) clamp(2rem,4vw,3.6rem)}
.esc-cta--split h2{color:#fff;max-width:16ch;margin-bottom:.5em}
.esc-cta__lede{color:rgba(255,255,255,.82);font-size:1.05rem;max-width:42ch;margin:0 0 1.9rem}
.esc-cta__actions{display:flex;gap:.9rem;flex-wrap:wrap}
.esc-cta__fig{position:relative;height:300px}
.esc-cta__fig .esc-fig__plate{left:-14px;top:16px}
.esc-cta__fig .esc-fig__arch{height:100%}
@media(max-width:900px){
  .esc-cta--split{grid-template-columns:1fr}
  .esc-cta__fig{height:240px;order:-1}
}

/* ---------- motion preference ---------- */
@media (prefers-reduced-motion:reduce){
  .esc-phone{animation:none}
  .esc-sat,.esc-fig--anim .esc-fig__plate,.esc-fig--anim .esc-fig__arch,
  .esc-fig--anim .esc-fig__frame,
  .esc-rail__step{transition:none;opacity:1;transform:none}
  .esc-rail::before{transform:scaleX(1);transition:none}
}

/* ---------- native wp:image support ----------
   Photos are wp:image blocks so they carry srcset and stay swappable in the
   editor. That wraps each one in <figure class="wp-block-image">, which these
   components have to account for. */
.esc-fig__arch figure,.esc-gcard figure,.esc-peek__img figure,.esc-hero__fig figure{
  margin:0;height:100%;width:100%}
.esc-fig__arch figure img,.esc-peek__img figure img,.esc-hero__fig figure img{
  width:100%;height:100%;object-fit:cover;display:block}
.esc-gcard figure{position:absolute;inset:0}
.esc-gcard figure img{width:100%;height:100%;object-fit:cover;display:block;
  transform:scale(1.08);transition:transform 1.2s var(--ease)}
.esc-gcard.is-active figure img{transform:scale(1)}
/* the gradient must sit above the figure, below the text */
.esc-gcard::after{z-index:1}
.esc-gcard__in{z-index:2}
/* headings inside these components must not inherit the section heading margins */
.esc-gcard__big.wp-block-heading{margin:0}
.esc-rail__step h3.wp-block-heading{margin:0 0 .45rem}
.esc-peek__card h3.wp-block-heading{margin:0 0 .4em}

/* ---------- Sized images, in the page AND in the editor ----------
   Rene, twice: the McDonald's logo at full size across the headline in wp-admin.

   TWO FAULTS STACKED, and the first fix only addressed one of them.

   1. Gutenberg's editor stylesheet carries `.wp-block-image img{height:auto}`
      at one class and one element. Every image-sizing rule in this file is also
      one class and one element, and the editor's loads afterwards, so it wins
      and the picture returns to its natural size.

   2. The first fix scoped the correction with `.editor-styles-wrapper`, which
      cannot work from this file. The editor PREFIXES every theme selector with
      `.editor-styles-wrapper` itself, so a rule that already names it asks for
      two such ancestors and the canvas only ever has one. Those rules matched
      nothing, which is why the logo looked identical after deploying the fix.

   The answer needs no editor scope at all. Doubling the class raises the rule to
   two classes and one element, which beats Gutenberg's in the canvas and behaves
   exactly the same on the page, where Gutenberg's rule is absent. Anything added
   later that sizes an image wants the same doubling. */
.esc-cs-hero__logo.esc-cs-hero__logo{height:44px;width:fit-content;margin:0 0 1.6rem;}
.esc-cs-hero__logo.esc-cs-hero__logo img{height:44px;width:auto;display:block;}
.esc-trust__row.esc-trust__row img{height:26px;width:auto;}
.esc-trust__row.esc-trust__row figure{margin:0;line-height:0;}
.esc-marquee__logo.esc-marquee__logo img{height:46px;width:auto;}
.esc-press__logo.esc-press__logo img{width:74px;height:auto;}
.esc-fig__arch.esc-fig__arch img{width:100%;height:100%;object-fit:cover;}
.esc-peek__img.esc-peek__img img{width:100%;height:100%;object-fit:cover;}
.esc-member.esc-member img{width:100%;height:100%;object-fit:cover;}
.esc-gcard.esc-gcard img{width:100%;height:100%;object-fit:cover;}
.esc-fig__arch.esc-fig__arch figure,
.esc-peek__img.esc-peek__img figure,
.esc-member.esc-member figure{margin-bottom:0;}

/* ============================================================
   CORE BUTTON STYLES
   The theme styles .esc-btn as the clickable element, but core/button puts
   the class on a wrapper and the link inside it. These rules dress the inner
   link so the client can use the normal Button block and choose a look from
   the Styles panel. The arrow is drawn with ::after, which is what allows the
   button text to be plain editable text rather than markup.
   ============================================================ */
.wp-block-button.is-style-esc-primary > .wp-block-button__link,
.wp-block-button.is-style-esc-white > .wp-block-button__link,
.wp-block-button.is-style-esc-orange > .wp-block-button__link,
.wp-block-button.is-style-esc-ghost > .wp-block-button__link{
  display:inline-flex;align-items:center;gap:.55rem;
  font-family:var(--body);font-weight:600;font-size:1rem;line-height:1;
  padding:.95rem 1.6rem;border-radius:var(--r);border:1.5px solid transparent;
  text-decoration:none;box-shadow:none;
  transition:transform .25s var(--ease),background .2s,color .2s,border-color .2s;}

.wp-block-button.is-style-esc-primary > .wp-block-button__link{
  background:var(--blue);color:#fff;}
.wp-block-button.is-style-esc-primary > .wp-block-button__link:hover{
  background:var(--blue-dark);color:#fff;transform:translateY(-1px);}

.wp-block-button.is-style-esc-white > .wp-block-button__link{
  background:#fff;color:var(--blue);}
.wp-block-button.is-style-esc-white > .wp-block-button__link:hover{
  transform:translateY(-1px);}

.wp-block-button.is-style-esc-ghost > .wp-block-button__link{
  background:transparent;color:var(--ink);border-color:var(--line);}
.wp-block-button.is-style-esc-ghost > .wp-block-button__link:hover{
  border-color:var(--ink);}
/* on the blue and moss panels the ghost button has to invert */
.bg-blue .wp-block-button.is-style-esc-ghost > .wp-block-button__link,
.bg-ink .wp-block-button.is-style-esc-ghost > .wp-block-button__link,
.esc-cta .wp-block-button.is-style-esc-ghost > .wp-block-button__link{
  color:#fff;border-color:rgba(255,255,255,.55);}
.esc-cta .wp-block-button.is-style-esc-ghost > .wp-block-button__link:hover{
  background:#fff;color:var(--blue);border-color:#fff;}

/* fourth style: solid brand orange, for use on dark panels */
.wp-block-button.is-style-esc-orange > .wp-block-button__link{
  background:var(--orange);color:#fff;}
.wp-block-button.is-style-esc-orange > .wp-block-button__link:hover{
  background:#C9741F;color:#fff;transform:translateY(-1px);}

/* the arrow, previously a <span class="arr"> that forced raw HTML */
.wp-block-button.is-style-esc-primary > .wp-block-button__link::after,
.wp-block-button.is-style-esc-orange > .wp-block-button__link::after,
.wp-block-button.is-style-esc-white > .wp-block-button__link::after{
  content:"\2192";font-size:1.05em;line-height:1;transition:transform .25s var(--ease);}
.wp-block-button.is-style-esc-primary:hover > .wp-block-button__link::after,
.wp-block-button.is-style-esc-orange:hover > .wp-block-button__link::after,
.wp-block-button.is-style-esc-white:hover > .wp-block-button__link::after{
  transform:translateX(3px);}

.wp-block-buttons.esc-hero__cta,.wp-block-buttons.esc-cta__actions{
  display:flex;gap:.9rem;flex-wrap:wrap;}
.wp-block-buttons.esc-hero__cta{margin-top:1.6rem;}

/* category links: a normal paragraph with a link inside, arrow in CSS */
p.esc-cat__linkwrap{margin:1.1rem 0 0;}
p.esc-cat__linkwrap a{display:inline-flex;align-items:center;gap:.4rem;
  font-weight:600;font-size:.95rem;color:var(--blue);text-decoration:none;}
p.esc-cat__linkwrap a::after{content:"\2192";transition:transform .25s var(--ease);}
p.esc-cat__linkwrap a:hover::after{transform:translateX(3px);}

/* ============================================================
   ABOUT: founder rows and team grid  (added 2026-08-20)
   ============================================================ */

/* The founder photo is a smaller arch than the inner-page solo figure. At the
   400px .esc-fig--solo height a headshot overpowers a two-sentence bio. */
.esc-fig--portrait{height:340px;width:100%;max-width:290px;margin-inline:auto}
@media(max-width:820px){.esc-fig--portrait{height:300px;max-width:260px}}

/* The second founder row mirrors the first, so the plate has to swap sides.
   Left at its default -16px it would point away from the copy. */
.esc-fig--flip .esc-fig__plate{left:auto;right:-16px}

/* Row spacing. .esc-fig__plate sits at top:20px and overhangs its column, so
   each row needs clearance under it, same reason as .esc-head--split. */
.esc-founder{margin-bottom:clamp(2.5rem,5vw,4rem)}
.esc-founder:last-of-type{margin-bottom:0}
.esc-founder .esc-eyebrow{margin-bottom:.35rem}
.esc-founder h3{margin:0 0 .9rem;font-size:clamp(1.5rem,2.4vw,1.9rem)}
.esc-founder p:last-child{margin-bottom:0}

/* Team roster. Four across, and the photo box is a forced square: the source
   headshots run from 133px to 1000px wide and mix square with portrait, so
   without the crop the row goes ragged. A quarter of the 1180px content width
   is about 265px, and the two smallest sources are soft above roughly 160px,
   which is why the grid caps each tile rather than filling the column. */
.esc-team{display:grid;grid-template-columns:repeat(4,1fr);
  gap:2.4rem 1.6rem;margin-top:2.6rem}
@media(max-width:900px){.esc-team{grid-template-columns:repeat(3,1fr)}}
@media(max-width:620px){.esc-team{grid-template-columns:repeat(2,1fr);gap:1.8rem 1.1rem}}
/* Each tile is the signature device at tile scale: colour plate behind an
   arched photo. .esc-fig has no intrinsic height, so the tile has to size it
   here or the arch collapses. The 4:5 frame matches the crop the headshots
   were normalized to; changing one without the other brings back the ragged
   framing the crop removed. */
.esc-fig--tile{width:100%;max-width:180px;aspect-ratio:4/5;margin-bottom:24px}
/* The offset is proportionally larger than the full-size device, not smaller.
   The plate is only visible where it sticks out past the photo, so a fixed
   -10px on a 180px tile reads as a coloured outline; it has to move far enough
   to read as a plate sitting behind. */
.esc-fig--tile .esc-fig__plate{left:-15px;top:17px;border-radius:999px 999px 14px 14px}
.esc-fig--tile .esc-fig__arch{border-radius:999px 999px 14px 14px}
/* The plate is absolute at top:17px, so it hangs 17px past the tile and would
   paint over the name. The 24px margin above clears it. */
.esc-member figure{margin:0}
.esc-member img{width:100%;height:100%;object-fit:cover;display:block}
.esc-member__name{font-family:var(--display);font-weight:600;font-size:1.02rem;
  margin:0 0 .1rem;color:var(--ink);line-height:1.3}
.esc-member__role{font-size:.86rem;color:var(--muted);margin:0;line-height:1.45}

/* --- the team wall ---------------------------------------------------
   Borrowed from the Loncom build of 2026-08-25, where the whole team stands in
   one row on a hairline with the name and role under it. Rene, 2026-08-27:
   push the people much further up the About page.

   Two things are deliberately not borrowed. Loncom's row drifts, because
   eighteen people cannot fit across a screen; eight can, so this row is static
   and nobody has to wait for a face to arrive. And the portraits there are cut
   out of their background, while Escalate's own device is the arched photo on a
   colour plate, which is what each face keeps here.

   The row is a sibling of .esc-wrap rather than a child so its width is a
   number here rather than an inherited one. It is set to the wrap's own width
   on purpose: a wider row was tried at 1500px and it overhung the left-aligned
   headline by 160px, which reads as a mistake rather than a bleed. Widening it
   later is this one line.

   align-items:start, not end. The tile is a fixed 4:5 of its column, so a top
   aligned row puts every hairline at the same height and the wall reads as one
   line. Bottom aligned, the two-line roles pushed their photos up and the row
   went ragged. */
.esc-wall{width:100%;max-width:var(--maxw);margin:clamp(2rem,3.4vw,3.2rem) auto 0;
  padding-inline:var(--gutter);
  display:grid;grid-template-columns:repeat(8,1fr);gap:1.5rem;align-items:start}
/* The tile caps itself at 180px for the grid four across. In the wall the
   column is already narrower than that, so the cap only stops the row filling
   the space it was given. */
.esc-wall .esc-fig--tile{max-width:none}
/* The rule the caption stands on. This is the piece of the Loncom wall worth
   taking: it turns a photo with a label under it into a record. */
.esc-wall .esc-member__name{border-top:1px solid var(--line-strong);padding-top:.55rem}
@media(max-width:1080px){.esc-wall{grid-template-columns:repeat(4,1fr);gap:2.2rem 1.5rem}}
@media(max-width:620px){.esc-wall{grid-template-columns:repeat(2,1fr);gap:1.8rem 1.1rem}}

/* --- About: centred headline, faces directly under it -----------------
   Rene, 2026-08-27: centre the headline for this page and pull the people line
   right underneath, so they are seen above the fold.

   The wall sits INSIDE the hero section for that reason. As two sections the
   hero's bottom padding stacked on the next section's top padding, and 100px of
   nothing between the headline and the faces is what puts the first row off the
   screen on a laptop. One section, one gap. The page hero padding is cut here
   too, for the same
   reason. */
.esc-hero--people{padding-block:clamp(40px,4.6vw,68px) clamp(28px,3.4vw,48px)}
.esc-hero--people .esc-hero__narrow{max-width:780px;margin-inline:auto;text-align:center}
/* The eyebrow is a flex row with its own rule before the label, so it centres
   from the container rather than from text-align. */
.esc-hero--people .esc-eyebrow{justify-content:center}
.esc-hero--people .esc-wall{margin-top:clamp(1.5rem,2.4vw,2.2rem)}
/* The line that used to be the team section's standfirst. It reads as a caption
   under the wall now rather than as an introduction above it. */
.esc-wall__note{max-width:62ch;margin:clamp(1.3rem,2vw,1.9rem) auto 0;text-align:center;
  color:var(--muted);font-size:.95rem;padding-inline:var(--gutter)}
/* On a phone the first row of two faces measured 25px past the fold, so the
   space above them is cut rather than the faces. */
@media(max-width:620px){
  .esc-hero--people{padding-block:18px 22px}
  .esc-hero--people .esc-wall{margin-top:.6rem}
}

/* ============================================================
   BLOG: post body, byline, cards, questions  (added 2026-08-21)
   ============================================================ */

/* The post's own banner. NOT the arch: a blog featured image is often a card
   graphic carrying its own headline, and a portrait dome crops the words off
   it. This keeps the whole 16:9 image and still carries the plate, so the
   device reads without eating the artwork. */
.esc-fig--wide{position:relative;margin:clamp(2.2rem,4vw,3.2rem) 0 0;
  width:100%;max-width:900px}
.esc-fig--wide .esc-fig__plate{left:-18px;top:20px;width:100%;height:100%;
  border-radius:var(--r-lg)}
.esc-fig__frame{position:relative;z-index:2;overflow:hidden;
  border-radius:var(--r-lg)}
.esc-fig__frame figure{margin:0}
.esc-fig__frame img{width:100%;height:auto;display:block}
/* The arrival animation targets .esc-fig__arch, so the wide frame needs its
   own rule or it stays invisible forever. */
.esc-fig--anim .esc-fig__frame{opacity:0;transform:translateY(28px) scale(.985);
  transition:transform .8s var(--ease),opacity .6s ease}
.esc-fig--anim.is-in .esc-fig__frame{opacity:1;transform:none}
@media(max-width:820px){
  .esc-fig--wide .esc-fig__plate{left:-12px;top:14px}
}

/* ---------- Post header ----------
   The hero used to open with an eyebrow above the headline, which pushed the
   whole thing down the page for one word. The category now sits as a tag on
   the byline line and costs no vertical space, so the headline, standfirst,
   byline and banner all fit above the fold. */
.esc-posthead{padding-block:clamp(24px,3vw,44px) clamp(28px,4vw,52px)}
.esc-posthead__copy{max-width:820px}
.esc-posthead h1{font-size:clamp(2.1rem,4.4vw,3.5rem);margin:0 0 .55rem}
.esc-posthead .lede{margin:0}

.esc-postmeta{display:flex;flex-wrap:wrap;gap:.7rem;align-items:center;
  margin-top:1.5rem;font-size:.93rem;color:var(--muted)}
.esc-postmeta__face{width:38px;height:38px;border-radius:50%;object-fit:cover;
  display:block;margin-right:.15rem}
.esc-postmeta__by{font-weight:600;color:var(--ink)}
.esc-postmeta__sep{width:4px;height:4px;border-radius:50%;background:var(--line);
  display:inline-block;flex:none}
.esc-postmeta__tags{display:flex;gap:.5rem;margin-left:.4rem}
.esc-tag{display:inline-block;padding:.28rem .7rem;border-radius:999px;
  background:var(--mist);color:var(--blue);font-size:.78rem;font-weight:600;
  letter-spacing:.04em;text-transform:uppercase;text-decoration:none}
.esc-tag:hover{background:var(--blue);color:#fff;text-decoration:none}

/* ---------- Post body: contents on the left, prose on the right ----------
   Deliberately asymmetric. The header's left edge sits under the logo, and
   the prose column's right edge sits under the Get Started button, so both
   ends of the page line up with something rather than floating (Rene,
   2026-08-21). The contents column fills the space that asymmetry creates. */
.esc-postbody{display:grid;grid-template-columns:230px minmax(0,1fr);
  gap:clamp(2rem,4vw,4rem);align-items:start}
/* min-width:0 is load-bearing, not tidiness. A grid item defaults to
   min-width:auto, which means it refuses to shrink below its widest content.
   The tables in the month 2 posts carry min-width:38rem so their columns stay
   readable, and .wp-block-table scrolls on its own axis to contain that. It
   cannot, because the prose column grew to 608px to fit the table and the
   figure was never narrower than what it was meant to clip. The page then ran
   to 632px on a 390px phone. body{overflow-x:clip} hid the scrollbar, so this
   read as content simply cut off at the right edge. Found 2026-08-26. */
.esc-postbody .esc-prose{max-width:none;margin:0;min-width:0}
@media(max-width:960px){
  /* Same reason, one column: a bare 1fr track still hands the item
     min-width:auto. */
  .esc-postbody{grid-template-columns:minmax(0,1fr)}
  .esc-postbody .esc-prose{max-width:760px}
}

.esc-toc{position:sticky;top:100px;font-size:.92rem}
@media(max-width:960px){
  .esc-toc{position:static;border:1px solid var(--line);border-radius:var(--r);
    padding:1.1rem 1.2rem;margin-bottom:2rem}
}
.esc-toc__title{font-family:var(--body);font-weight:600;font-size:.76rem;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted);
  margin:0 0 .8rem}
.esc-toc ul{list-style:none;margin:0;padding:0;display:grid;gap:.55rem;
  border-left:1px solid var(--line);padding-left:1rem}
@media(max-width:960px){.esc-toc ul{border-left:0;padding-left:0}}
.esc-toc a{color:var(--muted);text-decoration:none;line-height:1.35;
  display:block}
.esc-toc a:hover{color:var(--blue);text-decoration:none}
.esc-toc__l3{padding-left:.9rem;font-size:.88rem}
/* A contents link jumps to a heading that would otherwise sit under the
   sticky header. */
.esc-prose h2,.esc-prose h3{scroll-margin-top:96px}

/* Post body. A blog runs at a narrower measure than a marketing section: the
   pages carry short blocks of copy, a post carries continuous prose. */
.esc-prose{max-width:760px}
.esc-prose > *{max-width:100%}
.esc-prose h2{font-size:clamp(1.6rem,2.8vw,2.15rem);margin:2.4em 0 .5em}
.esc-prose h3{font-size:clamp(1.25rem,2vw,1.5rem);margin:1.9em 0 .45em}
.esc-prose h2:first-child,.esc-prose h3:first-child{margin-top:0}
.esc-prose p,.esc-prose li{font-size:1.08rem;line-height:1.72}
.esc-prose ul,.esc-prose ol{padding-left:1.3rem;margin:0 0 1.3em}
.esc-prose li{margin-bottom:.5em}
.esc-prose a{text-decoration:underline;text-underline-offset:3px}
.esc-prose figure{margin:2.2em 0}
.esc-prose figure img{border-radius:var(--r-lg)}
.esc-prose blockquote{margin:2.2em 0;padding:0 0 0 1.4rem;
  border-left:3px solid var(--orange);font-family:var(--display);
  font-size:clamp(1.2rem,2vw,1.45rem);line-height:1.4;color:var(--ink)}
.esc-prose blockquote p:last-child{margin-bottom:0}
.esc-prose blockquote cite{display:block;margin-top:.7rem;font-family:var(--body);
  font-size:.92rem;font-style:normal;color:var(--muted)}

/* Card grid, shared by the index, the category archives and related posts. */
.esc-cards{display:grid;grid-template-columns:repeat(3,1fr);
  gap:clamp(2rem,3vw,2.8rem) clamp(1.4rem,2vw,2rem);list-style:none;
  margin:0;padding:0}
@media(max-width:900px){.esc-cards{grid-template-columns:repeat(2,1fr)}}
@media(max-width:600px){.esc-cards{grid-template-columns:1fr}}

/* ---------- b2be/listing ----------
   The house listing block prints .esc-cards so it inherits the card design
   above, and adds its own column count on top. Three across stops being a CSS
   constant only a developer can change: the editor picks it, and the narrow
   breakpoints below still step every choice down to two and then one, so no
   setting can produce a four-across grid on a phone. */
.b2be-listing{list-style:none;margin:0;padding:0}
.b2be-listing--cols-1{grid-template-columns:1fr}
.b2be-listing--cols-2{grid-template-columns:repeat(2,1fr)}
.b2be-listing--cols-3{grid-template-columns:repeat(3,1fr)}
.b2be-listing--cols-4{grid-template-columns:repeat(4,1fr)}
@media(max-width:1100px){
  .b2be-listing--cols-4{grid-template-columns:repeat(3,1fr)}
}
@media(max-width:900px){
  .b2be-listing--cols-3,.b2be-listing--cols-4{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:600px){
  .b2be-listing--cols-2,.b2be-listing--cols-3,.b2be-listing--cols-4{grid-template-columns:1fr}
}
.b2be-listing__item{margin:0}
/* The card heading is an h3 so a listing dropped mid-page never outranks the
   section heading above it. Headings stop at h3 on every build. */
.b2be-listing__title{font-family:var(--display);font-size:1.18rem;line-height:1.3;
  margin:.15rem 0 .5rem}
.b2be-listing__title a{color:var(--ink);text-decoration:none}
.b2be-listing__title a:hover{color:var(--blue)}
.b2be-listing__empty{color:var(--muted);margin:0}
/* Pagination reuses .esc-pagination so the blog looks the same after the swap.
   display:flex here because the core block set its own layout inline and this
   nav does not. */
.b2be-listing__pagination{display:flex;flex-wrap:wrap}
.b2be-listing__pagination .page-numbers{color:var(--muted);text-decoration:none;
  padding:.2rem .55rem;border-radius:6px}
.b2be-listing__pagination a.page-numbers:hover{color:var(--blue);background:var(--mist)}
/* The chip for the filter you are currently looking at. The templates had no
   current state at all, because the row was four static links that could not
   know which archive was open. */
.b2be-chips .wp-block-button.is-current .wp-block-button__link{
  background:var(--ink);border-color:var(--ink);color:#fff}

/* ---------- Blog and archive header ----------
   Rene, 2026-08-26, looking at the live blog: the eyebrow, the headline and the
   standfirst all go, and the chips move up so more of the grid is above the
   fold. The header was also inset 156px further than the cards below it,
   because it sat in .esc-hero__narrow, which caps at 820px and centres. Chips
   and grid now share one .esc-wrap, so the two left edges cannot drift apart
   again.

   The h1 stays in the markup and out of the picture. A page with no h1 tells a
   crawler and a screen reader nothing about what it is, and the archive's h1
   is the term name, which is the one thing that distinguishes /category/support/
   from /blog/ to a machine. Naming Escalate in a visible headline on Escalate's
   own site is what Rene rejected on the inner pages
   (memory/feedback_onsite_page_no_self_attribution_line), so the visible page
   is exactly what he asked for: chips, then posts.

   Chosen ONLY when a listing page follows it, so no other section moves. */
.esc-archive{padding-block:clamp(40px,5vw,68px) clamp(44px,6vw,72px)}
.esc-archive .b2be-chips{margin-bottom:clamp(1.8rem,3vw,2.6rem)}
/* The same size as an inner-page headline, Rene 2026-08-26: shrunk to 38px it
   read as lost above a full-width grid. Measured across the site at 1440,
   inner-page h1s sit between 48 and 56px (services 48, contact 54.4, about 56),
   and this clamp is the contact page's rule, so the blog now matches the
   cluster rather than inventing a size of its own.

   The old blog headline was 3.5rem over two lines, which is a different problem
   and is not what came back: this one is a single short line, so the first row
   of cards still clears the fold. */
.esc-archive__h1{font-size:clamp(2.2rem,4.5vw,3.4rem);line-height:1.07;
  margin:0 0 clamp(1.4rem,2.2vw,1.9rem)}

/* Visually hidden, still read aloud and still indexed. The clip-path pair keeps
   it out of the layout without display:none, which would remove it from the
   accessibility tree entirely and defeat the point of keeping it. */
.esc-vh{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;
  border:0}
.esc-card{display:flex;flex-direction:column}
.esc-card__img{margin:0 0 1.1rem}
/* 16:9, matching the source graphics exactly. At 16:10 the cover crop shaved
   both sides off every card, which read as the artwork being cut off. */
.esc-card__img img{width:100%;aspect-ratio:16/9;object-fit:cover;
  border-radius:var(--r-lg);display:block;
  transition:transform .5s var(--ease)}
.esc-card__img a{display:block;overflow:hidden;border-radius:var(--r-lg)}
.esc-card:hover .esc-card__img img{transform:scale(1.03)}
.esc-card .esc-eyebrow{margin-bottom:.55rem}
/* Titles are h2 on the index and h3 in related posts, because the heading
   level depends on what precedes them. The look must not. */
.esc-card h2,.esc-card h3{font-size:1.22rem;line-height:1.25;margin:0 0 .55rem}
.esc-card h2 a,.esc-card h3 a{color:var(--ink);text-decoration:none}
.esc-card h2 a:hover,.esc-card h3 a:hover{color:var(--blue);text-decoration:none}
.esc-card__ex{color:var(--muted);font-size:.97rem;margin:0 0 .9rem}
.esc-card__date{font-size:.86rem;color:var(--muted);margin:auto 0 0}

.esc-pagination{margin-top:3rem;gap:.6rem;align-items:center;
  font-size:.95rem;color:var(--muted)}
.esc-pagination .page-numbers.current{font-weight:700;color:var(--ink)}

/* Questions at the end of a post. Plain disclosure rows: the answer is in the
   markup whether or not the row is open, so it stays readable to a crawler. */
.esc-faq{margin:3rem 0 0;border-top:1px solid var(--line)}
.esc-faq__q{border-bottom:1px solid var(--line);padding:1.15rem 0}
.esc-faq__q > summary{cursor:pointer;list-style:none;font-family:var(--display);
  font-weight:600;font-size:1.1rem;line-height:1.35;color:var(--ink);
  display:flex;justify-content:space-between;gap:1.5rem;align-items:flex-start}
.esc-faq__q > summary::-webkit-details-marker{display:none}
.esc-faq__q > summary::after{content:"+";font-family:var(--body);font-weight:400;
  font-size:1.5rem;line-height:1;color:var(--orange);flex:none;
  transition:transform .25s var(--ease)}
.esc-faq__q[open] > summary::after{transform:rotate(45deg)}
.esc-faq__q p{margin:.85rem 0 0;color:var(--muted);font-size:1.02rem;
  line-height:1.65;max-width:64ch}

/* Honeypot. Kept out of sight without display:none, because some bots skip
   fields that are display:none and fill the rest, which defeats the trap. */
.esc-form__hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.esc-form__error{margin:0;padding:.8rem .9rem;border-radius:10px;
  background:#FDF1E6;color:var(--orange-dark);font-size:.94rem;font-weight:600}
.esc-form__error a{color:var(--orange-dark);text-decoration:underline}

/* The home headline is a full sentence naming both benefits and the product,
   so it needs more words than a three-word hero line. At the global h1 scale
   it wrapped to five lines and pushed the standfirst off the fold. */
.esc-hero h1{font-size:clamp(2.3rem,4.5vw,3.5rem);}

/* ============================================================
   SERVICES: numbered index with the arch on the numeral
   Concepts 1 and 3 combined (Rene, 2026-08-21). The index carries the
   structure, the arch carries the number.
   ============================================================ */

/* Numbering comes from a CSS counter, not from the markup, so adding or
   deleting a service in the editor renumbers the rest on its own. The numbers
   are ordering rather than information, which is why they can live here. */
/* Multi-column, not a two-column grid. A grid fills left to right, so a reader
   going down the first column sees 01, 03, 05. Columns flow downward, which is
   how an index is actually read. */
.esc-index{counter-reset:svc;display:block;columns:2;column-gap:clamp(2rem,4vw,3.6rem);
  border-top:1px solid var(--line)}
@media(max-width:820px){.esc-index{columns:1}}

/* Overrides the card treatment these tiles used to carry. */
.esc-index .esc-svc{break-inside:avoid;display:grid;grid-template-columns:40px minmax(0,1fr);
  gap:0 1rem;align-items:start;padding:1.05rem 0;
  border:0;border-bottom:1px solid var(--line);border-radius:0;
  background:none;box-shadow:none}
.esc-index .esc-svc::before{
  counter-increment:svc;content:counter(svc,decimal-leading-zero);
  grid-row:1 / span 2;width:40px;height:36px;
  border-radius:999px 999px 6px 6px;
  background:var(--mist);color:var(--blue);
  font-family:var(--display);font-weight:700;font-size:.82rem;
  display:grid;place-items:center;margin-top:2px}
/* Every third numeral takes the warm pair, so a long list has a rhythm
   without any tile needing its own class. */
.esc-index .esc-svc:nth-child(3n)::before{background:#FBEEDD;color:var(--orange)}
.esc-index .esc-svc h3,.esc-index .esc-svc h4{grid-column:2;
  font-family:var(--display);font-size:1.04rem;line-height:1.25;margin:0}
.esc-index .esc-svc p{grid-column:2;color:var(--muted);font-size:.87rem;
  line-height:1.5;margin:.2rem 0 0}

/* A page header with no photo does not need the same breathing room beneath
   it as one that does. Applied with :has so no page needs a modifier class. */
.esc-hero--page:not(:has(.esc-fig)):not(:has(.esc-peek)){
  padding-block:clamp(52px,6vw,84px) clamp(24px,3vw,44px);}

/* The section after a photoless header starts closer to it. At the standard
   rhythm the two paddings stack to 163px under a hero that is now only four
   lines tall, which reads as a hole rather than as breathing room. */
.esc-hero--page:not(:has(.esc-fig)):not(:has(.esc-peek)) + .esc-section{
  padding-top:clamp(30px,4vw,58px);}

/* Any section reached by an anchor stops clear of the sticky header. Without
   this the header covers the top of the target, which affects the services
   Life/Work/Advancement links as well as the new how-it-works one. */
section[id]{scroll-margin-top:92px}

/* --- a peek card carrying a customer quote -------------------------------
   The peek device was built for a headline and a line of body copy. A quote
   needs different furniture: the words at heading size because they are the
   point of the section, and an attribution, because an unattributed quote is
   worth nothing. Reusable on any build, not Escalate specific. */
.esc-peek__card blockquote{margin:0}
.esc-peek__card blockquote p{font-family:var(--display);font-weight:600;
  font-size:clamp(1.15rem,1.7vw,1.45rem);line-height:1.34;letter-spacing:-.005em;
  color:var(--ink);margin:0 0 .9rem}
.esc-peek__card blockquote cite{display:block;font-style:normal;
  font-size:.85rem;line-height:1.5;color:var(--muted)}
.esc-peek__card blockquote cite b{display:block;font-weight:600;color:var(--ink)}
