/* ═══════════════════════════════════════════════════════════════
   LANDLORD FIRE RISK ASSESSMENT
   site.css — v5 · complete rewrite
   ───────────────────────────────────────────────────────────────
   The previous stylesheet had grown to 1,006 rules, 229
   !important declarations, 80 media queries and FOUR competing
   :root blocks that silently overrode each other. Selectors were
   redefined up to five times. This file replaces it with one
   coherent system, declared once, in cascade order.

   Design register: institutional technical document.
   Hairlines, not walls. Space, not decoration. Red as signal,
   never as ornament. Monospace only where the content is
   genuinely data.
   ═══════════════════════════════════════════════════════════════ */
@view-transition{navigation:auto}

/* Container padding and gap are set in Elementor (Layout -> Padding / Gap),
   not here: Elementor's generated rules outrank this file, so padding or gap
   re-added below would be dead CSS and would also kill the editor control.
   The values are var()/clamp(), so the responsive tokens still drive them. */

/* ── 1. FONTS ─────────────────────────────────────────────────
   Archivo is a variable font carrying both a weight (400–900)
   and a WIDTH axis (62.5%–125%); the display cuts use the width
   axis via font-stretch. Declared directly rather than through
   @import, which would chain three requests before first paint. */

@font-face{
  font-family:'Archivo';font-style:normal;
  font-weight:400 900;font-stretch:62.5% 125%;font-display:swap;
  src:url(https://fonts.gstatic.com/s/archivo/v25/k3kQo8UDI-1M0wlSfdnoLmvDIaI.woff2) format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{
  font-family:'JetBrains Mono';font-style:normal;
  font-weight:400 700;font-display:swap;
  src:url(https://fonts.gstatic.com/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxDcwgknk-4.woff2) format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}

/* ── 2. TOKENS — declared once, nowhere else ────────────────── */

:root{
  /* Surface. Warmer and appreciably brighter than the old
     #F2F0EB, which read as dingy rather than as paper. */
  --paper:#FAF8F4;
  --paper-2:#F2EEE7;
  --surface:#FFFFFF;

  /* Ink. Not pure black — pure black on warm paper looks like
     an unstyled document. */
  --ink:#141310;
  --ink-2:rgba(20,19,16,.66);
  --ink-3:rgba(20,19,16,.44);
  --ink-4:rgba(20,19,16,.28);

  /* Rules. Hairline is the default; --hair-2 is for emphasis. */
  --hair:rgba(20,19,16,.12);
  --hair-2:rgba(20,19,16,.22);

  /* Signal. The old #FF2E00 was fluorescent — it read cheap at
     large sizes. This is the same warm orange-red, deepened
     enough to carry authority and to pass contrast as text. */
  --red:#DC3C12;
  --red-ink:#B32D07;
  --red-wash:#FCEDE6;

  --dark:#141310;
  --dark-2:#1E1C18;
  --on-dark:#F6F3ED;
  --on-dark-2:rgba(246,243,237,.62);
  --on-dark-3:rgba(246,243,237,.38);
  --hair-dark:rgba(246,243,237,.16);

  --sans:'Archivo','Helvetica Neue',Arial,sans-serif;
  --mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;

  /* Geometry. Borders are hairlines by default. --bw is
     reserved for the few genuinely framed objects; at 1.5px it
     frames without walling in. */
  --bw:1.5px;
  --r:2px;

  /* Rhythm. Materially more generous than before — the single
     largest contributor to a page reading as considered. */
  --pad-x:max(clamp(24px,5vw,60px),calc((100% - 1260px) / 2));
  --cell:clamp(18px,2.2vw,32px);
  --sec-y:clamp(42px,4.2vw,72px);
  --sec-b:clamp(34px,3.4vw,58px);

  --mh:64px;
  --ease:cubic-bezier(.22,1,.36,1)}

/* WordPress-editable brand ------------------------------------------------
   The brand colour and the display face are mirrored into Elementor Site
   Settings (Global Colors / Global Fonts), so they can be changed from the
   WordPress admin without touching this file. Elementor scopes its globals to
   .elementor-kit-6 on <body>, which is why these are redeclared here rather
   than on :root. The value after each comma is the current one, so if a global
   is ever cleared the site keeps exactly the colours it has today. */
body{
  --red:var(--e-global-color-primary,#DC3C12);
  --red-ink:var(--e-global-color-accent,#B32D07);
  --sans:var(--e-global-typography-primary-font-family,'Archivo'),'Helvetica Neue',Arial,sans-serif}

/* A native Elementor widget (Text Editor, Heading, Button) otherwise takes the
   kit typography and colour. These take the page instead, so a widget added in
   the editor matches the design straight away. */
.elementor-widget-text-editor,.elementor-widget-heading .elementor-heading-title,
.elementor-widget-button .elementor-button{font-family:inherit;font-weight:inherit;color:inherit}

/* ── 3. RESET + ELEMENTOR NEUTRALISATION ────────────────────── */

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--sans);font-size:16.5px;line-height:1.65;
  font-weight:400;letter-spacing:-.005em;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  overflow-x:hidden}
/* The contact address is 38 unbreakable characters and the domain
   is 33. On a 320px screen either will run past the gutter, and
   because body clips overflow-x the tail is simply lost rather
   than scrollable. Let long tokens break. */
/* The Hostinger theme puts 75px of padding on the body:
     body.hostinger-ai-builder-elementor,
     body.hostinger-ai-builder-gutenberg { padding-top: 75px }
   It was presumably reserving room for a theme header this page
   does not use. Nothing in this stylesheet could reach it, so
   every section sat 75px lower than the design called for. The
   selector below matches its specificity and loads later. */
body.hostinger-ai-builder-elementor,
body.hostinger-ai-builder-gutenberg,
body.elementor-template-canvas{padding-top:0}

body,input,select,textarea,button{overflow-wrap:break-word}
.fb-mail,.fl-m,.cstrip .tr-v,.cstrip .tr-v a,.prose-in a{overflow-wrap:anywhere}
img,svg{max-width:100%}
h1,h2,h3,h4,h5,h6,p,ul,ol,figure{margin:0}
ul,ol{padding:0;list-style:none}
a{color:inherit;text-decoration:none}
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}
input,select,textarea{font-family:inherit;font-size:inherit;color:inherit}
::selection{background:var(--red);color:#fff}
:focus-visible{outline:2px solid var(--red);outline-offset:3px;border-radius:1px}

/* The theme sets bare headings in a serif; re-declare. */
body.elementor-page h1,body.elementor-page h2,body.elementor-page h3,
body.elementor-page h4,body.elementor-page h5,body.elementor-page h6{
  font-family:var(--sans)!important}

/* Elementor containers carry their own width, padding and gap.
   Every section here manages its own gutter, so the containers
   are flattened to transparent wrappers. */
body.elementor-page .elementor,
body.elementor-page .elementor-section-wrap{width:100%;max-width:none;margin:0;padding:0}
/* Elementor drives a container's whole box through custom
   properties: display:var(--display), gap:var(--row-gap)
   var(--column-gap), padding via --padding-*, margin via
   --margin-*.

   This reset used to be `padding:0!important; gap:0!important`,
   which was harmless while containers were only wrappers. Now
   that every section IS a container, that !important also
   overrode .sec's own padding and every grid gap — the page lost
   its vertical rhythm and its side gutters.

   Zeroing the custom properties instead removes Elementor's box
   without !important, so the design rules further down apply
   normally — and a padding a user sets in the editor still wins,
   because Elementor writes it at a higher specificity. */
/* Neutralise Elementor's .e-con defaults (10px padding, 20px gap) at LOW
   specificity, so each container's own Elementor setting (0,0,3,0) still wins.
   Do not raise this selector's specificity: that kills the editor controls. */
.e-con{
  --padding-top:0px;--padding-right:0px;--padding-bottom:0px;--padding-left:0px;
  --row-gap:0px;--column-gap:0px;--gap:0px}
body.elementor-page .e-con,body.elementor-page .e-con-inner,
body.elementor-page .elementor-element.e-con{
  --container-max-width:100%;--content-width:100%;--width:100%;
  max-width:none;width:100%}
body.elementor-page .elementor-widget-html,
  body.elementor-page .elementor-widget-text-editor,
body.elementor-page .elementor-widget-container,
body.elementor-page .elementor-widget-shortcode{margin:0!important;padding:0!important}
body.elementor-page .elementor-widget:not(:last-child){margin-block-end:0}

/* The theme hides every container until its own scroll script
   reveals it. The masthead container is zero-height with fixed
   children, so it never qualified and the header stayed
   invisible. Motion here is owned by site.js instead. */
/* The chrome container is only as tall as its own contents, which
   would end the sticky header's travel almost immediately. Taking it
   out of the box tree hands the header the full page to stick to. */
body.elementor-page .lfra-chrome{display:contents}

body .hostinger-elementor-aos{
  opacity:1!important;transform:none!important;
  will-change:auto!important;filter:none!important;
  perspective:none!important;contain:none!important}

.skip{
  position:absolute;left:-9999px;top:0;z-index:999;
  background:var(--ink);color:var(--paper);
  padding:14px 22px;font-size:14px;font-weight:700}
.skip:focus{left:0;top:0}

/* ── 4. TYPOGRAPHY PRIMITIVES ───────────────────────────────── */

/* Display type: expanded width axis, tight tracking, tight
   leading. The three together are what make a headline read as
   set rather than as typed. */
.hero h1,.phero h1,.sec-title h2,.cta-h,.report-what h3,
.incl-h,.pc-head h3,.bc-t,.prose-in h2,.duty-statement,.tr-v{
  font-family:var(--sans);font-stretch:112%;
  font-weight:700;letter-spacing:-.035em;
  text-wrap:balance;
  /* body carries overflow-wrap:break-word so a 38-character email
     cannot run past the gutter. Headlines must NOT inherit it:
     at display sizes it splits a word mid-way ("Assessme / nt")
     instead of simply setting it on its own line. */
  overflow-wrap:normal;word-break:normal;hyphens:none}

/* Technical label. Letterspaced sans, NOT monospace — mono in
   quantity reads as a developer portfolio rather than a
   consultancy. Mono is reserved for actual data below. */
.st-k,.rh-k,.rf-h,.s4-w,.tc-tag,.ps-o,.fcol h4,.iv-tag,
.wc-h,.tr-k,.ph-k,.cta-k,.hero-eyebrow,.bc-k,.dh-k{
  font-family:var(--sans);
  font-weight:700;text-transform:uppercase;
  font-size:clamp(11.5px,.92vw,13px);
  letter-spacing:.185em;line-height:1.5}

/* Mono, used only where the content is literally tabular or
   instrument-like: the specimen document, drawing annotations,
   reference codes and price figures. */
.doc-row,.rr-line,.rh-ref,.rspec-stamp,.pr-p,.dh-r,
.ps-n,.s4-n,.rspec-find .p{
  font-family:var(--mono);font-feature-settings:"tnum" 1}

/* Emphasis inside a heading takes the signal colour. Once per
   section: an accent, not a pattern. */
.sec-title h2 em,.report-what h3 em,.pc-head h3 em,
.phero h1 .red,.hero h1 .red{font-style:normal;color:var(--red)}

/* Hollow display type. Deliberately rare — the hero's third
   line and the two knockout words. Any more and it stops
   reading as emphasis. */
.hero h1 .outline,.ko{
  color:transparent;
  -webkit-text-stroke:1.6px var(--ink);
  paint-order:stroke fill}
.hero h1 .outline{-webkit-text-stroke-width:2px}
.cta-h .ko{-webkit-text-stroke-color:var(--on-dark)}

/* Marked text: the phrase the sentence turns on. */
.hero-lede b,.faq-a-in b,.duty-statement .hl{
  background:var(--red);color:#fff;
  padding:.05em .28em;font-weight:600;
  box-decoration-break:clone;-webkit-box-decoration-break:clone}

/* Links inside prose and lists: an underline that wipes in. */
.fcol ul a,.crumb a,.prose-in a,.fb-mail,.cstrip .tr-v a{
  position:relative;display:inline-block}
.fcol ul a::after,.crumb a::after,.prose-in a::after,
.fb-mail::after,.cstrip .tr-v a::after{
  content:"";position:absolute;left:0;right:0;bottom:-2px;height:1px;
  background:currentColor;opacity:.45;
  transform:scaleX(0);transform-origin:left;
  transition:transform .4s var(--ease)}
.fcol ul a:hover::after,.crumb a:hover::after,.prose-in a:hover::after,
.fb-mail:hover::after,.cstrip .tr-v a:hover::after{transform:scaleX(1)}

/* ── 5. MOTION PRIMITIVES ───────────────────────────────────── */
/* Everything below is single-pass, triggered once by
   IntersectionObserver, and fully disabled at the end of this
   file under prefers-reduced-motion. */

@keyframes draw{to{stroke-dashoffset:0}}
@keyframes fillDoc{from{opacity:0}to{opacity:var(--wash,.09)}}
@keyframes fillIn{from{opacity:0}to{opacity:.12}}
@keyframes markIn{from{opacity:0}to{opacity:1}}
@keyframes bandIn{from{transform:scaleY(.3);opacity:0}to{transform:scaleY(1);opacity:1}}
@keyframes ivIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.25}}

/* ── PRE-HIDE ────────────────────────────────────────────────
   site.js is the LAST widget on the page, so if the hidden
   state arrived only with the .rvl/.mask-up classes it adds,
   every animated element would paint visible first and then be
   snatched away — a flash of content, then blank space.

   These rules put the hidden state in the stylesheet instead,
   gated on html.js-motion, which a tiny inline script at the
   TOP of the body sets before anything paints. Three ways out,
   so content can never be stranded invisible:
     · the inline script never runs   → no .js-motion, all visible
     · site.js never boots            → the inline script strips
                                        .js-motion after 2.5s
     · :is() unsupported              → whole rule dropped, visible
   Reduced motion never gets .js-motion at all. */

html.js-motion :is(.sec-title h2,.phero h1,.cta-h,.report-what h3,
                   .incl-h,.pc-head h3){
  clip-path:inset(0 -.3em 100% -.3em);
  transform:translateY(.2em)}
html.js-motion :is(.sec-title h2,.phero h1,.cta-h,.report-what h3,
                   .incl-h,.pc-head h3).seen{
  clip-path:inset(-.3em -.3em -.3em -.3em);
  transform:none;
  transition:clip-path .9s var(--ease),transform .9s var(--ease)}

html.js-motion :is(.drow,.pstep,.tcell,.s4,.rw-list li,.trust-item,
                   .incl-list li,.rspec-find li,.bcard,.faq,
                   .who-col,.pill){
  opacity:0;transform:translateY(15px)}
html.js-motion :is(.drow,.pstep,.tcell,.s4,.rw-list li,.trust-item,
                   .incl-list li,.rspec-find li,.bcard,.faq,
                   .who-col,.pill).seen{
  opacity:1;transform:none;
  transition:opacity .8s var(--ease),transform .8s var(--ease);
  transition-delay:calc(var(--i,0) * 65ms)}

html.js-motion .report-spec{clip-path:inset(0 -40px 100% -40px)}
html.js-motion .report-spec.seen{
  clip-path:inset(-40px -40px -40px -40px);
  /* transform and shadow ride along here so the pointer tilt below
     shares the same transition declaration as the reveal — a second
     rule would simply replace this one */
  transition:clip-path 1.05s var(--ease) .1s,
             transform .14s var(--ease),
             box-shadow .4s var(--ease)}

/* The specimen answers to the pointer exactly as the hero card does.
   perspective lives on the parent; only the sheet itself rotates. */
.report{perspective:1400px}
.report-spec{transform-style:preserve-3d}
.report-spec:hover{
  box-shadow:0 2px 4px rgba(20,19,16,.05),
             0 26px 54px -18px rgba(20,19,16,.20),
             0 60px 110px -60px rgba(20,19,16,.34)}

html.js-motion :is(.prose-in > p,.prose-in > h2,.prose-in > h3,
                   .prose-in > ul,.prose-note){opacity:0;transform:translateY(12px)}
html.js-motion :is(.prose-in > p,.prose-in > h2,.prose-in > h3,
                   .prose-in > ul,.prose-note).seen{
  opacity:1;transform:none;
  transition:opacity .7s var(--ease),transform .7s var(--ease)}

/* Fade-rise. --i is set by site.js so siblings arrive in
   sequence rather than all at once. */
.rvl{
  opacity:0;transform:translateY(15px);
  transition:opacity .8s var(--ease),transform .8s var(--ease);
  transition-delay:calc(var(--i,0) * 65ms)}
.rvl.seen{opacity:1;transform:none}

/* Headline rise from behind a mask. Must not also carry .rvl —
   an opacity fade fights the clip and produces mush. */
.mask-up{
  clip-path:inset(0 -.3em 100% -.3em);
  transform:translateY(.2em);
  will-change:clip-path,transform}
.mask-up.seen{
  clip-path:inset(-.3em -.3em -.3em -.3em);
  transform:none;
  transition:clip-path .9s var(--ease),transform .9s var(--ease)}

/* Hero entrance. The three headline lines rise from behind
   their own overflow, then the supporting copy follows. This is
   the only autoplaying sequence on the site. */
@keyframes lineUp{from{transform:translateY(105%)}to{transform:none}}
@keyframes fadeUp{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

/* ── 6. MASTHEAD ────────────────────────────────────────────── */

.masthead{
  position:fixed;top:0;left:0;right:0;z-index:90;
  height:var(--mh);
  display:flex;align-items:center;gap:clamp(16px,2.4vw,36px);
  padding:0 var(--pad-x);
  background:rgba(250,248,244,.82);
  backdrop-filter:saturate(180%) blur(14px);
  -webkit-backdrop-filter:saturate(180%) blur(14px);
  border-bottom:1px solid transparent;
  transition:height .35s var(--ease),background .35s var(--ease),
             border-color .35s var(--ease)}
body.scrolled .masthead{
  height:calc(var(--mh) - 8px);
  background:rgba(250,248,244,.94);
  border-bottom-color:var(--hair)}

.mh-brand{
  display:flex;align-items:center;gap:9px;
  font-weight:700;font-stretch:108%;letter-spacing:-.03em;
  font-size:clamp(15px,1.25vw,17px);white-space:nowrap}
.mh-brand .fire-mark{width:14px;height:19px;flex-shrink:0;color:var(--red)}
/* the separator span the old two-word mark used is gone; keep the rule
   harmless in case a future wordmark wants it back */
.mh-brand span{color:var(--ink-3);font-weight:400;margin:0 1px}

.mh-nav{display:flex;align-items:center;gap:clamp(14px,1.9vw,30px);margin-left:auto}
.mh-link{
  position:relative;padding:6px 0;
  font-size:14.5px;font-weight:500;color:var(--ink-2);
  transition:color .25s var(--ease)}
.mh-link::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1.5px;
  background:var(--red);
  transform:scaleX(0);transform-origin:right;
  transition:transform .4s var(--ease)}
.mh-link:hover{color:var(--ink)}
.mh-link:hover::after{transform:scaleX(1);transform-origin:left}
.mh-link.current{color:var(--ink);font-weight:600}
.mh-link.current::after{transform:scaleX(1)}

.mh-cta{
  display:inline-flex;align-items:center;gap:8px;
  padding:11px 19px;background:var(--ink);color:var(--paper);
  font-size:13.5px;font-weight:600;letter-spacing:-.01em;
  border-radius:var(--r);white-space:nowrap;
  transition:background .3s var(--ease),transform .3s var(--ease)}
.mh-cta:hover{background:var(--red);transform:translateY(-1px)}
.mh-cta .ar{transition:transform .3s var(--ease)}
.mh-cta:hover .ar{transform:translateX(4px)}

/* Header phone: plain tel: link between the nav and the CTA. Lives here and not
   in Elementor because it sits inside an HTML widget's markup. */
.mh-tel{display:inline-flex;align-items:center;gap:8px;
  /* 10px + 1px border matches .mh-cta's 11px exactly, so the two sit as a pair */
  padding:10px 16px;border:1px solid var(--hair);border-radius:var(--r);
  font-size:13.5px;font-weight:600;letter-spacing:-.01em;
  color:var(--ink);white-space:nowrap;
  transition:border-color .3s var(--ease),background .3s var(--ease),
    transform .3s var(--ease)}
/* the handset tilts as the CTA's arrow slides: same gesture, same timing,
   so the pair reads as one set while the fill keeps the hierarchy */
.mh-tel .mh-tel-i{flex-shrink:0;color:var(--red);
  transition:transform .3s var(--ease)}
.mh-tel:hover .mh-tel-i{transform:rotate(-16deg) scale(1.06)}
.mh-tel:hover{border-color:var(--ink);background:rgba(20,19,16,.05);
  transform:translateY(-1px)}

/* Scroll progress. A 2px reading of how far down the page you
   are — the only persistent chrome besides the header. */
.worm{
  position:fixed;left:0;top:var(--mh);height:2px;width:0;
  background:var(--red);z-index:91;
  transition:width .12s linear,top .35s var(--ease)}
body.scrolled .worm{top:calc(var(--mh) - 8px)}

/* Bottom dock — the navigation on small screens. */
.dock{
  position:fixed;left:0;right:0;bottom:0;z-index:92;display:none;
  background:rgba(250,248,244,.94);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  border-top:1px solid var(--hair);
  padding:9px max(10px,env(safe-area-inset-left)) calc(9px + env(safe-area-inset-bottom))}
.dock a{
  flex:1;text-align:center;padding:7px 2px;
  font-size:11px;font-weight:600;letter-spacing:.04em;
  color:var(--ink-3);transition:color .25s var(--ease)}
.dock a.current{color:var(--red)}
.dock a:hover{color:var(--ink)}

/* WordPress admin bar offsets. WP already sets html{margin-top},
   so body padding must NOT also account for it. */
body.admin-bar .masthead{top:32px}
body.admin-bar .worm{top:calc(var(--mh) + 32px)}
body.admin-bar.scrolled .worm{top:calc(var(--mh) + 20px)}
@media screen and (max-width:782px){
  body.admin-bar .masthead{top:46px}
  body.admin-bar .worm{top:calc(var(--mh) + 46px)}
  body.admin-bar.scrolled .worm{top:calc(var(--mh) + 34px)}
}

/* Anchored sections must clear the fixed header. */
#top,#duty,#inspection,#method,#report,#pricing,#faq,#quote,#privacy,#main{
  scroll-margin-top:calc(var(--mh) + 14px)}
body.admin-bar #top,body.admin-bar #duty,body.admin-bar #inspection,
body.admin-bar #method,body.admin-bar #report,body.admin-bar #pricing,
body.admin-bar #faq,body.admin-bar #quote,body.admin-bar #privacy,
body.admin-bar #main{scroll-margin-top:calc(var(--mh) + 46px)}

/* ── 7. BUTTONS ─────────────────────────────────────────────── */

.btn{
  position:relative;overflow:hidden;
  /* isolation makes .btn a stacking context, so the z-index:-1
     fill below sits ABOVE the button's own background but BELOW
     its inline label. Without it the label is a bare text node
     and any positive z-index on the fill would cover it. */
  isolation:isolate;
  display:inline-flex;align-items:center;gap:10px;
  padding:15px 26px;border-radius:var(--r);
  font-size:15px;font-weight:600;letter-spacing:-.012em;
  border:1.5px solid transparent;
  /* Colour SNAPS partway through the wipe. Cross-fading colour
     and ground at the same rate sends both through the same
     mid-tone and the label vanishes for a frame. */
  transition:color 0s linear .15s,border-color .28s var(--ease),
             transform .28s var(--ease)}
/* The fill wipes across from the left rather than cross-fading. */
.btn::before{
  content:"";position:absolute;inset:0;z-index:-1;
  transform:scaleX(0);transform-origin:left;
  transition:transform .42s var(--ease)}
.btn:hover::before{transform:scaleX(1)}
.btn .ar{transition:transform .3s var(--ease)}
.btn:hover .ar{transform:translateX(5px)}
.btn:hover{transform:translateY(-2px)}
.btn:active{transform:translateY(0)}

.btn-red{background:var(--red);color:#fff;border-color:var(--red)}
.btn-red::before{background:var(--ink)}
.btn-red:hover{border-color:var(--ink)}

.btn-black{background:transparent;color:var(--ink);border-color:var(--ink)}
.btn-black::before{background:var(--ink)}
.btn-black:hover{color:var(--paper)}

.btn-ghost{background:transparent;color:var(--on-dark);border-color:var(--hair-dark)}
.btn-ghost::before{background:var(--on-dark)}
.btn-ghost:hover{color:var(--ink);border-color:var(--on-dark)}

/* ── 8. SECTION SHELL ───────────────────────────────────────── */

.sec{}

/* The section number sits in its own column, as it does in the source
   design — but with space doing the separating rather than the heavy
   bordered cell that design used. Below 760px it stacks above the
   eyebrow so the heading keeps the full width. */
/* The source design sets the head as a two-cell band: a large red
   figure in its own cell, ruled off from the title beside it, with a
   rule closing the whole head. Reproduced here with hairlines instead
   of its 2.5px rules, and inside our page gutter rather than
   full-bleed, so it sits in this theme rather than shouting over it. */
.sec-head{
  display:grid;grid-template-columns:minmax(0,1fr);
  align-items:stretch;
  border-bottom:1px solid var(--hair);
  margin-bottom:clamp(24px,2.5vw,40px)}
@media(min-width:760px){
  .sec-head{grid-template-columns:auto minmax(0,1fr)}
}
.pas .sec-head{border-bottom-color:var(--hair-dark)}

.sec-num{
  font-family:var(--sans);font-stretch:112%;
  font-weight:900;font-size:clamp(42px,5.9vw,92px);
  line-height:.8;letter-spacing:-.045em;
  font-variant-numeric:tabular-nums;
  /* Red on black, and the tile runs the full height of the head — the
     eyebrow, the heading and the standfirst together — as the cell does
     in the source. Sized as a block against the whole title rather than
     floated beside its first line. */
  background:var(--ink);color:var(--red);
  border-radius:var(--r);
  display:flex;align-items:center;justify-content:center;
  align-self:stretch;
  padding:clamp(14px,1.6vw,24px) clamp(20px,2.4vw,36px);
  min-width:clamp(104px,12.4vw,196px);
  border-right:none;margin-right:0}

/* 62ch was computed on the 16.5px base — about 530px — while the
   heading beside it runs to 52px and needs closer to 800. That cap,
   not the type size, is what was folding every heading onto two
   lines. The column now takes the width it is given and the
   standfirst carries its own measure. */
.sec-title{
  max-width:none;
  padding:clamp(16px,1.8vw,26px) 0 clamp(16px,1.8vw,26px) clamp(18px,2.2vw,36px);
  display:flex;flex-direction:column;justify-content:center}

@media(max-width:759px){
  /* stacked there is no cell to rule off, so the figure takes a rule
     beneath it instead and the title returns to the gutter */
  .sec-num{
    font-size:clamp(30px,7.1vw,44px);
    padding:clamp(11px,1.9vw,16px) clamp(17px,2.9vw,24px);
    min-width:calc(clamp(27px,6.4vw,39px) * 2.2);
    align-self:flex-start;
    align-self:flex-start;
    margin:0 0 clamp(12px,1.8vw,18px);
    border-bottom:none}
  .sec-title{padding:clamp(14px,2vw,20px) 0}
}

/* the figure arrives with the rest of the head */
html.js-motion .sec-num{opacity:0;transform:translateY(10px)}
html.js-motion .sec-head.seen .sec-num{
  opacity:1;transform:none;
  transition:opacity .7s var(--ease),transform .7s var(--ease)}

.st-k{
  display:flex;align-items:center;gap:12px;
  color:var(--red-ink);margin-bottom:clamp(16px,1.6vw,24px)}
.st-k::before{
  content:"";width:clamp(20px,2.6vw,36px);height:2px;
  background:var(--red);flex-shrink:0;
  transform:scaleX(0);transform-origin:left;
  transition:transform .7s var(--ease) .1s}
.sec-head.seen .st-k::before{transform:scaleX(1)}

/* The source design sets its section headings in caps with tight
   leading — that is the trait that gives them their character. Caps
   run wider and read larger, so the size comes down a little and the
   tracking opens up: -.035em was tuned for lowercase and pinches
   capitals together. */
.sec-title h2{
  font-size:clamp(26px,3.6vw,52px);line-height:.96;
  letter-spacing:-.018em;text-transform:uppercase;
  margin-bottom:clamp(14px,1.5vw,20px)}
.st-d{
  font-size:clamp(15.5px,1.3vw,18.5px);line-height:1.5;
  color:var(--ink-2);
  /* wide enough for two lines at desktop, still capped so it does not
     run to an unreadable measure on a very wide screen */
  max-width:118ch}

/* ── 9. HERO ────────────────────────────────────────────────── */

/* --mh reserves the fixed header's height; the clamp is the
   breathing room below it. At 64px that put ~140px of empty paper
   above the first line of content, which read as a dead band. */
.hero{}

.hero-top{
  display:flex;justify-content:space-between;align-items:center;
  gap:20px;flex-wrap:wrap;
  padding-bottom:10px;margin-bottom:clamp(10px,1vw,16px);
  border-bottom:1px solid var(--hair);
  font-size:13px;letter-spacing:.13em;text-transform:uppercase;
  font-weight:600;color:var(--ink-3)}
.hero-top .ht-r{display:flex;align-items:center;gap:9px}
/* Square and hard-switched, as in the source: a soft round pulse reads
   as decoration, a 9px square cutting on and off reads as a live status
   light — which is the point of it sitting beside the Order. */
.hero-top .blink{
  width:9px;height:9px;border-radius:0;
  background:var(--red);display:inline-block;flex-shrink:0;
  animation:blink 1.1s steps(1) infinite}
@keyframes blink{50%{opacity:0}}

.hero-main{
  display:grid;grid-template-columns:minmax(0,1fr);
  gap:clamp(32px,3.6vw,62px);align-items:start}
@media(min-width:1040px){
  /* The copy column takes min-content as its floor, so the track
     always fits the longest word in the headline — "Assessment"
     at 118px is wider than a flat 1.06fr share, and a minmax(0,…)
     floor let the column shrink under it and wrap the word. */
  .hero-main{grid-template-columns:minmax(min-content,1.06fr) minmax(0,.94fr);gap:clamp(36px,3.8vw,68px)}
}

.hero-eyebrow{color:var(--red-ink);margin-bottom:clamp(12px,1.2vw,18px)}

.hero h1{
  font-size:clamp(46px,8.2vw,118px);
  line-height:.92;letter-spacing:-.045em;
  margin-bottom:clamp(16px,1.7vw,26px)}
.hero h1 .red{color:var(--red)}
/* Each line is its own overflow window; the span inside rises
   through it. None of these three words has a descender, so a
   hard overflow clip is safe here. */
.hero h1 .line{display:block;overflow:hidden}
.hero h1 .line > span{display:block;animation:lineUp 1s var(--ease) both}
.hero h1 .line:nth-child(1) > span{animation-delay:.06s}
.hero h1 .line:nth-child(2) > span{animation-delay:.17s}
.hero h1 .line:nth-child(3) > span{animation-delay:.28s}

/* Supporting copy follows the headline in. */
.hero-eyebrow,.hero-lede,.hero-actions,.hero-kicker,.hero-visual{
  animation:fadeUp .85s var(--ease) both}
.hero-eyebrow{animation-delay:.02s}
.hero-lede{animation-delay:.40s}
.hero-actions{animation-delay:.48s}
.hero-kicker{animation-delay:.56s}
.hero-visual{animation-delay:.34s}

.hero-lede{
  font-size:clamp(16.5px,1.45vw,20px);line-height:1.62;
  color:var(--ink-2);max-width:56ch;
  margin-bottom:clamp(28px,2.8vw,40px)}
.hero-actions{display:flex;flex-wrap:wrap;margin-bottom:clamp(20px,2vw,30px)}

.hero-kicker{display:flex;flex-wrap:wrap;gap:8px}
.pill{
  padding:7px 13px;border:1px solid var(--hair-2);border-radius:var(--r);
  font-size:13.5px;font-weight:600;color:var(--ink-2);
  letter-spacing:-.005em;
  transition:border-color .3s var(--ease),color .3s var(--ease),
             background .3s var(--ease)}
.pill:hover{border-color:var(--ink);color:var(--ink);background:var(--surface)}

/* The specimen document. A white sheet on the paper ground,
   raised by a soft shadow rather than outlined by a heavy rule. */
.hero-visual{position:relative}
.doc{
  background:var(--surface);
  border:1px solid var(--hair);border-radius:var(--r);
  box-shadow:0 1px 2px rgba(20,19,16,.04),
             0 14px 34px -14px rgba(20,19,16,.16),
             0 40px 80px -50px rgba(20,19,16,.30);
  overflow:hidden}
.doc-head{
  display:flex;justify-content:space-between;align-items:flex-start;gap:18px;
  padding:clamp(18px,1.8vw,24px) clamp(18px,1.8vw,26px);
  border-bottom:1px solid var(--hair)}
.dh-k{color:var(--ink-3);margin-bottom:7px}
.dh-t{font-size:clamp(16px,1.4vw,19px);font-weight:700;letter-spacing:-.025em;line-height:1.15}
.dh-r{
  text-align:right;font-size:11.5px;line-height:1.6;
  color:var(--ink-3);letter-spacing:.05em;text-transform:uppercase;
  flex-shrink:0}
.doc-body{padding:clamp(14px,1.6vw,22px) clamp(18px,1.8vw,26px);background:var(--paper-2)}
.doc-svg{width:100%;height:auto;display:block}
.doc-svg .dl{fill:none;stroke:var(--hair-2);stroke-width:1;vector-effect:non-scaling-stroke}
.doc-svg .dl-s{fill:none;stroke:var(--ink);stroke-width:1.25;vector-effect:non-scaling-stroke}
.doc-svg .dl-r{fill:none;stroke:var(--red);stroke-width:1.75;vector-effect:non-scaling-stroke;stroke-linecap:round}
.doc-svg .dmark{fill:var(--red)}
/* The rating drives this through a custom property rather than an
   inline opacity: a running keyframe outranks inline styles, so a
   direct style.opacity would be overwritten the moment the plan
   redraws. Keyframes read the same property, so the two agree. */
.doc-svg .dfill{fill:var(--red);opacity:var(--wash,.09)}
.doc-svg .doc-mark.off{display:none}
.doc-svg .dtx{font-family:var(--sans);font-size:7.5px;font-weight:700;letter-spacing:.12em;fill:var(--ink-3)}
.doc-svg .dtx-r{fill:var(--red-ink)}
/* The plan draws itself once, on load. */
.doc-svg .dl,.doc-svg .dl-s,.doc-svg .dl-r{
  stroke-dasharray:1200;stroke-dashoffset:1200;
  animation:draw 1.15s var(--ease) both}
.doc-svg .dl-s{animation-delay:.14s}
.doc-svg .dl-r{animation-delay:.74s;animation-duration:.85s}
.doc-svg .dfill{animation:fillDoc .6s var(--ease) .6s both}
.doc-svg .dmark{animation:markIn .45s var(--ease) .8s both}

.doc-rows{padding:0 clamp(18px,1.8vw,26px)}
.doc-row{
  display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  padding:11px 0;border-bottom:1px solid var(--hair);
  font-size:13px}
.doc-row:last-child{border-bottom:none}
.doc-row .k{color:var(--ink-3);letter-spacing:.02em}
.doc-row .v{font-weight:700;letter-spacing:-.01em;text-align:right}
.doc-row .v.red{color:var(--red-ink)}

.doc-scale{display:flex;gap:3px;padding:0 clamp(18px,1.8vw,26px) clamp(18px,1.8vw,24px)}
/* These bands carry their own labels and are selectable, the same
   as the specimen report lower down: choosing one re-states the
   card at that rating. They were 5px tall with the label text
   spilling out of the box. */
.doc-scale span{
  flex:1;border-radius:1px;
  background:var(--hair);
  padding:6px 3px 5px;
  font-size:clamp(8.5px,.68vw,10px);
  font-weight:700;letter-spacing:.03em;text-transform:uppercase;
  text-align:center;color:var(--ink-3);
  white-space:nowrap;overflow:hidden;
  cursor:pointer;user-select:none;
  transition:background .3s var(--ease),color .3s var(--ease)}
.doc-scale span:hover{background:var(--red-wash);color:var(--red-ink)}
.doc-scale span:focus-visible{outline:2px solid var(--red);outline-offset:2px}
.doc-scale span.on{background:var(--red);color:#fff}
.doc-scale span.on:hover{background:var(--red);color:#fff}
/* The card is ~44% of the content width, so five short labels fit
   comfortably down to a phone. Only drop them when the card itself
   gets genuinely narrow. */
@media(max-width:430px){
  .doc-scale span{font-size:0;padding:0;height:5px}
}

/* ── 10. TRUST BAR ──────────────────────────────────────────── */

/* Four facts, ruled off. The seams are drawn by a pseudo-element
   on each cell rather than by a gap over a coloured ground, so
   the bar can carry the page gutter without the rules running
   out to the window edge. */
.trust{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  border-top:1px solid var(--hair);border-bottom:1px solid var(--hair)}
@media(min-width:840px){.trust{grid-template-columns:repeat(3,minmax(0,1fr))}}
.trust-item{
  position:relative;
  /* padding on BOTH sides: with a left of 0 the second and third
     columns started hard against the divider on their left, which is
     what made the row look pinned to the wall. The first column keeps
     a zero left so it still lines up with the page gutter. */
  padding:clamp(26px,2.9vw,40px) var(--cell);
  transition:background .35s var(--ease)}
.trust-item::after{
  content:"";position:absolute;top:0;bottom:0;right:0;width:1px;
  background:var(--hair)}
/* first column aligns with the page gutter, not with an indent */
.trust > .trust-item:first-child,
.trust > :first-child .trust-item{padding-left:0}
@media(min-width:840px){.trust > .trust-item:nth-child(3)::after,
  .trust > :nth-child(3) .trust-item::after{display:none}}
@media(max-width:839px){
  .trust{grid-template-columns:minmax(0,1fr)}
  /* stacked there is no divider to clear, so every row sits on the gutter */
  .trust-item{padding-left:0;padding-right:0}
  .trust-item::after{display:none}
  .trust > :not(:last-child) .trust-item,
  .trust > .trust-item:not(:last-child){border-bottom:1px solid var(--hair)}
}
.trust-item .tr-v{
  font-size:clamp(32px,4.2vw,56px);line-height:.9;
  font-weight:800;letter-spacing:-.035em;margin-bottom:0}
.trust-item .tr-v .u{color:var(--red)}
.trust-item .tr-k{
  color:var(--ink-3);margin-top:clamp(9px,1vw,13px);
  max-width:30ch;line-height:1.5;letter-spacing:.14em}

/* ── 11. DUTY ───────────────────────────────────────────────── */

/* The statement is the loudest sentence on the page. It earns
   that by being the legal position stated plainly. */
.duty-statement{
  font-size:clamp(25px,3.5vw,50px);line-height:1.12;
  letter-spacing:-.035em;font-weight:700;
  max-width:22ch;margin-bottom:clamp(30px,3.2vw,54px)}
/* "suitable and sufficient" is 23 characters and this line never
   drops below 25px, so on a 320px screen nowrap ran it ~38px past
   the gutter. box-decoration-break:clone already makes a wrapped
   highlight look right, so the nowrap was buying nothing. */

.duty-rows{border-top:1px solid var(--hair-2)}
.drow{
  position:relative;overflow:hidden;
  display:grid;grid-template-columns:auto minmax(0,1fr);
  gap:clamp(16px,2.4vw,42px);align-items:start;
  padding:clamp(24px,2.6vw,38px) clamp(14px,1.6vw,24px);
  border-bottom:1px solid var(--hair);
  /* The background wipes; the colour SNAPS at the midpoint.
     Transitioning both at the same rate sends text and ground
     through the same mid-tone and the row goes blank. */
  transition:color 0s linear .09s}
.drow::before{
  content:"";position:absolute;inset:0;z-index:0;background:var(--ink);
  transform:scaleX(0);transform-origin:left;
  transition:transform .45s var(--ease)}
.drow > *{position:relative;z-index:1}
.drow:hover::before{transform:scaleX(1)}
.drow:hover{color:var(--on-dark)}
.drow:hover .dr-n{color:var(--red)}
.drow:hover .dr-b{color:var(--on-dark-2)}
.drow:hover .dr-b b{color:var(--on-dark)}

/* The 01–05 index sat at 12px against a 25px title, so it read as
   a footnote rather than as a numbered step. Same face, colour and
   tracking — just scaled to sit alongside the text it indexes. */
/* The index figure on every row-by-row list. In the source these are
   set large in the expanded face rather than as small monospace
   labels — that is what makes the rows read as a numbered sequence
   instead of a list with captions. */
.dr-n,.rw-n,.bc-n{
  font-family:var(--sans);font-stretch:112%;
  font-weight:800;font-size:clamp(26px,3.4vw,48px);
  line-height:.85;letter-spacing:-.03em;
  color:var(--red-ink);
  font-variant-numeric:tabular-nums;
  padding-top:0;
  transition:color 0s linear .09s}
.dr-t{
  font-size:clamp(19px,1.85vw,25px);line-height:1.2;
  font-weight:700;letter-spacing:-.028em;margin-bottom:9px}
.dr-b{
  font-size:clamp(15.5px,1.2vw,17px);line-height:1.62;
  color:var(--ink-2);max-width:74ch;
  transition:color 0s linear .09s}
.dr-b b{color:var(--ink);font-weight:600;transition:color 0s linear .09s}

/* In / out of scope. Two panels, one inverted. */
.who{
  display:grid;grid-template-columns:minmax(0,1fr);
  margin-top:clamp(30px,3.2vw,54px);
  background:var(--hair);border:1px solid var(--hair);border-radius:var(--r);
  overflow:hidden}
@media(min-width:820px){.who{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}}
.who-col{padding:clamp(26px,2.8vw,44px)}
.who-col.yes{background:var(--ink);color:var(--on-dark)}
.who-col.no{background:var(--surface)}
.wc-h{
  display:flex;align-items:center;gap:clamp(11px,1.1vw,14px);
  margin-bottom:clamp(14px,1.4vw,20px)}
.who-col.yes .wc-h{color:var(--on-dark-2)}
.who-col.no .wc-h{color:var(--ink-3)}
/* the tick and the cross carry the whole distinction this panel is
   making, so they are sized to be read at a glance rather than to sit
   quietly beside the label */
.wc-h .ic{
  width:clamp(28px,2.6vw,36px);height:clamp(28px,2.6vw,36px);
  flex-shrink:0;
  display:grid;place-items:center;border-radius:50%;
  font-size:clamp(15px,1.4vw,19px);font-weight:800;line-height:1;
  border:1.5px solid currentColor}
.who-col.yes .wc-h .ic{border-color:var(--red);color:var(--red)}
.who-col h3{
  font-size:clamp(20px,2vw,27px);line-height:1.15;
  font-weight:700;letter-spacing:-.03em;margin-bottom:11px}
.who-col p{font-size:clamp(15.5px,1.2vw,17px);line-height:1.62}
.who-col.yes p{color:var(--on-dark-2)}
.who-col.no p{color:var(--ink-2)}

/* ── 12. INSPECTION ─────────────────────────────────────────── */
/* The one section set on white, so the middle of the page has
   a change of ground without a full-bleed colour band. */

#inspection{background:var(--surface);border-top:1px solid var(--hair);border-bottom:1px solid var(--hair)}

.insp{
  display:grid;grid-template-columns:minmax(0,1fr);align-items:start}
@media(min-width:960px){.insp{grid-template-columns:minmax(0,.82fr) minmax(0,1.18fr)}}

.insp-index{border-top:1px solid var(--hair)}
.insp-btn{
  position:relative;width:100%;text-align:left;
  display:grid;grid-template-columns:auto minmax(0,1fr) auto;
  gap:14px;align-items:center;
  padding:clamp(19px,1.9vw,26px) clamp(4px,.8vw,12px);
  border-bottom:1px solid var(--hair);
  transition:color .25s var(--ease),padding-left .35s var(--ease)}
.insp-btn::before{
  content:"";position:absolute;left:0;top:-1px;bottom:-1px;width:2px;
  background:var(--red);
  transform:scaleY(0);transform-origin:top;
  transition:transform .4s var(--ease)}
.insp-btn:hover{color:var(--ink);padding-left:clamp(12px,1.6vw,22px)}
.insp-btn.on{padding-left:clamp(12px,1.6vw,22px)}
.insp-btn.on::before{transform:scaleY(1)}
/* section 02's index — sized with the numerals in the other lists
   rather than as a caption beside the label */
.ib-n{
  font-family:var(--sans);font-stretch:112%;
  font-weight:800;font-size:clamp(20px,2.4vw,34px);
  line-height:.85;letter-spacing:-.035em;
  font-variant-numeric:tabular-nums;
  color:var(--ink-4);
  transition:color .25s var(--ease)}
.insp-btn.on .ib-n{color:var(--red)}
.insp-btn:hover .ib-n{color:var(--ink-3)}
.ib-t{
  font-size:clamp(16px,1.4vw,19px);font-weight:600;
  letter-spacing:-.024em;color:var(--ink-2);
  transition:color .25s var(--ease)}
.insp-btn.on .ib-t{color:var(--ink);font-weight:700}
.ib-x{
  color:var(--ink-4);font-size:15px;
  transform:translateX(-4px);opacity:0;
  transition:transform .35s var(--ease),opacity .35s var(--ease)}
.insp-btn.on .ib-x,.insp-btn:hover .ib-x{opacity:1;transform:none;color:var(--red)}

.insp-view{
  background:var(--ink);color:var(--on-dark);border-radius:var(--r);
  padding:clamp(24px,2.6vw,38px);
  display:grid;gap:clamp(20px,2.1vw,30px)}
.iv-tag{color:var(--red);margin-bottom:12px}
.iv-big{
  font-size:clamp(22px,2.5vw,34px);line-height:1.12;
  font-weight:700;font-stretch:112%;letter-spacing:-.035em;
  margin-bottom:14px}
.iv-body{font-size:clamp(15.5px,1.2vw,17.5px);line-height:1.65;color:var(--on-dark-2);max-width:56ch}
/* the three lines animate individually (see §12 below), so the
   wrapper must not also fade or the two stack up */

.insp-schema{border-top:1px solid var(--hair-dark);padding-top:clamp(16px,1.7vw,24px)}
.insp-svg{
  display:block;margin:0 auto;
  width:100%;max-width:clamp(240px,23vw,330px);
  aspect-ratio:300/240;height:auto;
  overflow:visible}
.insp-svg .ss{fill:none;stroke:rgba(246,243,237,.22);stroke-width:1;vector-effect:non-scaling-stroke}
.insp-svg .ss-on{fill:none;stroke:var(--red);stroke-width:2;vector-effect:non-scaling-stroke;stroke-linecap:round;stroke-linejoin:round}
.insp-svg .sfill{fill:var(--red);opacity:.12}
/* Selecting a line used to swap the schematic with display:none —
   one frame, no transition. The layers occupy the same SVG
   coordinate space, so they can simply cross-fade in place:
   the outgoing annotation drops away while the incoming one
   redraws itself along its own path. */
.sk{
  opacity:0;visibility:hidden;
  transform-box:fill-box;transform-origin:center;
  transform:scale(.985);
  transition:opacity .22s var(--ease),transform .22s var(--ease),
             visibility 0s linear .22s}
.sk.on{
  opacity:1;visibility:visible;transform:none;
  transition:opacity .4s var(--ease) .12s,transform .5s var(--ease) .12s,
             visibility 0s}
/* The red annotation redraws each time a line is selected. */
.sk.on .ss-on{stroke-dasharray:900;stroke-dashoffset:900;animation:draw .75s var(--ease) .16s both}
.sk.on .sfill{animation:fillIn .45s var(--ease) .16s both}
.sk.on circle{animation:markIn .45s var(--ease) .16s both}

/* The grey plan underneath gives a single quiet pulse on change,
   so the drawing reads as being re-measured rather than swapped. */
.insp-svg .ss{transition:stroke .45s var(--ease)}
.insp-svg.pulse .ss{stroke:rgba(246,243,237,.42)}

/* Panel copy arrives in sequence rather than as one block. */
.iv-fade .iv-tag{animation:ivIn .4s var(--ease) .02s both}
.iv-fade .iv-big{animation:ivIn .45s var(--ease) .09s both}
.iv-fade .iv-body{animation:ivIn .5s var(--ease) .16s both}

/* ── 13. PAS — the dark band ────────────────────────────────── */

.pas{background:var(--dark);color:var(--on-dark)}
.pas .st-k{color:var(--red)}
.pas .st-k::before{background:var(--red)}
.pas .sec-title h2{color:var(--on-dark)}
.pas .sec-title h2 em{color:var(--red)}
.pas .st-d{color:var(--on-dark-2)}

.pas-steps{
  display:grid;grid-template-columns:minmax(0,1fr);
  border-top:1px solid rgba(255,255,255,.3)}
@media(min-width:760px){.pas-steps{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(min-width:1180px){.pas-steps{grid-template-columns:repeat(5,minmax(0,1fr))}}

.pstep{
  position:relative;
  padding:clamp(24px,2.6vw,34px) clamp(18px,1.8vw,26px) clamp(28px,3vw,40px);
  border-bottom:1px solid var(--hair-dark);
  transition:background .4s var(--ease)}
.pstep:hover{background:var(--dark-2)}
/* Vertical seams between steps, without a seam before the first
   or after the last in a row. */
.pstep::after{
  content:"";position:absolute;top:0;bottom:-1px;left:-1px;width:1px;
  background:var(--hair-dark)}
@media(min-width:760px) and (max-width:1179px){.pas-steps > .pstep:nth-child(2n+1)::after,
  .pas-steps > :nth-child(2n+1) .pstep::after{display:none}}
@media(min-width:1180px){.pas-steps > .pstep:nth-child(5n+1)::after,
  .pas-steps > :nth-child(5n+1) .pstep::after{display:none}}
@media(max-width:759px){.pstep::after{display:none}}

.ps-n{
  font-size:12.5px;font-weight:700;letter-spacing:.13em;
  color:var(--red);margin-bottom:clamp(16px,1.8vw,26px)}
.ps-t{
  font-size:clamp(18px,1.6vw,21px);line-height:1.2;
  font-weight:700;letter-spacing:-.028em;margin-bottom:11px}
.ps-b{font-size:15px;line-height:1.6;color:var(--on-dark-2);margin-bottom:clamp(18px,2vw,26px)}
.ps-o{
  display:inline-block;color:var(--on-dark-3);
  padding-top:12px;border-top:1px solid var(--hair-dark);width:100%}

/* ── 14. REPORT ─────────────────────────────────────────────── */

.report{
  display:grid;grid-template-columns:minmax(0,1fr);align-items:start}
@media(min-width:1000px){.report{grid-template-columns:minmax(0,1.02fr) minmax(0,.98fr)}}

/* A printed sheet: white ground, hairline edge, soft lift. The
   previous version used a flat tinted panel with no border at
   all, which is why it read as a grey box rather than a
   document. */
.report-spec{
  background:var(--surface);
  border:1px solid var(--hair);border-radius:var(--r);
  box-shadow:0 1px 2px rgba(20,19,16,.04),
             0 16px 40px -18px rgba(20,19,16,.18),
             0 44px 90px -60px rgba(20,19,16,.32);
  overflow:hidden;
  /* Reveals top-to-bottom. Both states use negative side insets
     so the offset shadow — which falls outside the border box —
     is not clipped away by the animation. */
  clip-path:inset(0 -40px 100% -40px)}
.report-spec.seen{
  clip-path:inset(-40px -40px -40px -40px);
  transition:clip-path 1.05s var(--ease) .1s}

.rspec-head{
  display:flex;justify-content:space-between;align-items:flex-start;gap:18px;
  padding:clamp(22px,2.2vw,32px) clamp(22px,2.2vw,32px) clamp(18px,1.8vw,26px);
  border-bottom:1px solid var(--hair)}
.rh-k{color:var(--ink-3);margin-bottom:8px}
.rspec-head h3{
  font-size:clamp(18px,1.7vw,23px);line-height:1.15;
  font-weight:700;letter-spacing:-.03em}
.rh-ref{
  text-align:right;flex-shrink:0;
  font-size:11.5px;line-height:1.7;color:var(--ink-3);
  letter-spacing:.04em}

.rscale{display:flex;gap:3px;padding:clamp(18px,1.8vw,26px) clamp(22px,2.2vw,32px) 0}
/* The five bands are selectable: choosing one re-states the
   specimen at that rating. They carry their own labels, so they
   are sized for a hit target rather than as a bare bar. */
.rscale .rs{
  flex:1;border-radius:1px;
  background:var(--paper-2);
  padding:7px 4px 6px;
  font-size:clamp(9.5px,.8vw,11px);
  font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  text-align:center;color:var(--ink-3);
  white-space:nowrap;overflow:hidden;text-overflow:clip;
  cursor:pointer;user-select:none;
  transition:background .3s var(--ease),color .3s var(--ease),
             transform .3s var(--ease)}
.rscale .rs:hover{background:var(--red-wash);color:var(--red-ink)}
.rscale .rs:focus-visible{outline:2px solid var(--red);outline-offset:2px}
.rscale .rs.on{color:#fff}
.rscale .rs.on:hover{background:var(--red);color:#fff}
@media(max-width:520px){
  .rscale .rs{font-size:0;padding:0;height:clamp(12px,1.2vw,16px)}
}
.rscale .rs.on{background:var(--red)}
/* the whole scale now climbs in sequence — see §25.3 — so the
   single-band pop that used to live here would fight it */

.rspec-rows{padding:clamp(18px,1.8vw,26px) clamp(22px,2.2vw,32px) 0}
.rr-line{
  display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  padding:clamp(12px,1.2vw,16px) 0;
  border-bottom:1px solid var(--hair);font-size:13.5px}
.rr-line:last-child{border-bottom:none}
.rr-line .k{color:var(--ink-3);letter-spacing:.02em}
.rr-line .v{font-weight:700;letter-spacing:-.01em;text-align:right}
.rr-line .v.red{color:var(--red-ink)}

.rspec-find{padding:clamp(20px,2vw,28px) clamp(22px,2.2vw,32px) 0;border-top:1px solid var(--hair)}
.rf-h{color:var(--ink-3);margin-bottom:clamp(14px,1.4vw,20px)}
.rspec-find ul{display:grid;gap:clamp(14px,1.5vw,18px)}
.rspec-find li{
  display:grid;grid-template-columns:auto minmax(0,1fr);gap:12px;align-items:start;
  font-size:14.5px;line-height:1.55;color:var(--ink-2)}
.rspec-find li .p{
  font-size:11.5px;font-weight:700;letter-spacing:.06em;
  padding:4px 8px;border-radius:2px;
  border:1px solid var(--hair-2);color:var(--ink-3)}
/* Priority badges read hot to cool: P1 solid, P2 washed,
   P3 outline only. P3 inherits the base rule — stated here so
   that is visibly a decision rather than an omission. */
.rspec-find li .p.p1{background:var(--red);color:#fff;border-color:var(--red)}
.rspec-find li .p.p2{background:var(--red-wash);color:var(--red-ink);border-color:transparent}
.rspec-find li .p.p3{background:transparent;color:var(--ink-3);border-color:var(--hair-2)}

.rspec-stamp{
  margin-top:clamp(22px,2.2vw,30px);
  padding:clamp(16px,1.6vw,22px) clamp(22px,2.2vw,32px);
  border-top:1px dashed var(--hair-2);
  background:var(--paper);
  font-size:13px;line-height:1.62;color:var(--ink-3)}
.rspec-stamp b{color:var(--ink-2);font-weight:600}

.report-what h3{
  font-size:clamp(26px,3.2vw,44px);line-height:1.06;
  margin-bottom:clamp(16px,1.6vw,22px)}
.rw-lede{
  font-size:clamp(16px,1.3vw,18.5px);line-height:1.62;
  color:var(--ink-2);margin-bottom:clamp(26px,2.6vw,38px);max-width:52ch}
.rw-list{border-top:var(--bw) solid var(--ink)}
/* Same black wipe as the duty rows and building cards, so every
   numbered list on the site behaves the same way under the pointer.
   The colour snaps mid-wipe rather than cross-fading — fading both
   at once sends the text through the same mid-tone as the ground. */
.rw-list li{
  position:relative;overflow:hidden;
  display:grid;grid-template-columns:auto minmax(0,1fr);
  gap:clamp(14px,1.6vw,22px);align-items:start;
  padding:clamp(19px,2vw,28px) clamp(10px,1.2vw,18px);
  border-bottom:1px solid var(--hair);
  transition:color 0s linear .09s}
.rw-list li::before{
  content:"";position:absolute;inset:0;z-index:0;background:var(--ink);
  transform:scaleX(0);transform-origin:left;
  transition:transform .45s var(--ease)}
.rw-list li > *{position:relative;z-index:1}
.rw-list li:hover::before{transform:scaleX(1)}
.rw-list li:hover{color:var(--on-dark)}
.rw-list li:hover .rw-n{color:var(--red)}
.rw-list li:hover span{color:var(--on-dark-2)}
.rw-list li:hover b{color:var(--on-dark)}
/* a step down from the shared size: this list sits in a narrower column */
/* this list sits in the report's narrow right column, so the figure
   runs a size below the full-width lists elsewhere */
.rw-n{font-size:clamp(28px,3.1vw,44px);padding-top:.04em}
.rw-list li b{
  display:block;font-size:clamp(18px,1.6vw,22px);
  font-weight:700;letter-spacing:-.025em;margin-bottom:7px}
.rw-list li span{font-size:clamp(15.5px,1.25vw,17.5px);line-height:1.62;color:var(--ink-2);transition:color 0s linear .09s}

/* ── 15. TYPES ──────────────────────────────────────────────
   A row of cards rather than a stack of rows, as in the source
   design: letter, title, copy, tag — read down, not across.

   The seams are 1px grid gaps over a hairline ground rather than
   borders on each cell. With the column count varying by page (four
   building types on the home page, five inspection areas on
   services) there is no reliable "last in row" to strip a border
   from, and gaps sidestep that entirely. */
/* stated at container specificity so the generic block rule above
   cannot take it back */
body.elementor-page .types.e-con,
.types{
  display:grid;grid-template-columns:minmax(0,1fr);
  background:var(--hair);
  border-top:1px solid var(--hair);
  border-bottom:1px solid var(--hair)}
@media(min-width:600px){body.elementor-page .types.e-con,
  .types{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* One row, whatever the count. auto-fit was deciding the track count
   from the available width, so at narrower desktop widths four cards
   still split over two rows. Flowing by column instead puts every card
   on a single line and shares the width equally — four on the home
   page, five on services, without either page needing its own rule. */
@media(min-width:900px){
  body.elementor-page .types.e-con,
  .types{
    grid-template-columns:none;
    grid-auto-flow:column;
    grid-auto-columns:minmax(0,1fr)}
  /* the copy has less room per card in one row, so the padding eases in */
  .tcell{padding:clamp(20px,2vw,28px) clamp(15px,1.4vw,22px)}
}

.tcell{
  position:relative;overflow:hidden;isolation:isolate;
  display:flex;flex-direction:column;
  background:var(--paper);
  padding:clamp(22px,2.4vw,32px) clamp(18px,1.9vw,26px);
  /* the ground wipes, the text snaps at the midpoint — cross-fading
     both sends the words through the same tone as the ground */
  transition:color 0s linear .09s}
.tcell::before{
  content:"";position:absolute;inset:0;z-index:-1;background:var(--red);
  transform:scaleY(0);transform-origin:bottom;
  transition:transform .42s var(--ease)}
.tcell:hover::before{transform:scaleY(1)}
.tcell:hover{color:#fff}
.tcell:hover .tc-n{color:#fff}
.tcell:hover p{color:rgba(255,255,255,.9)}
.tcell:hover .tc-tag{color:rgba(255,255,255,.85);border-color:rgba(255,255,255,.42)}

.tc-n{
  font-family:var(--sans);font-stretch:112%;
  font-weight:800;font-size:clamp(26px,3vw,40px);
  line-height:.82;letter-spacing:-.03em;color:var(--red);
  transition:color 0s linear .09s}
.tc-t{
  font-family:var(--sans);font-stretch:112%;
  font-weight:700;font-size:clamp(16.5px,1.7vw,21px);
  line-height:1.05;letter-spacing:-.015em;text-transform:uppercase;
  margin:clamp(13px,1.4vw,18px) 0 clamp(8px,.9vw,11px)}
.tcell p{
  font-size:14.5px;line-height:1.5;color:var(--ink-2);
  flex:1;transition:color 0s linear .09s}
.tc-tag{
  display:inline-block;align-self:flex-start;
  margin-top:clamp(12px,1.3vw,16px);
  font-size:11.5px;font-weight:700;letter-spacing:.11em;
  text-transform:uppercase;color:var(--ink-3);
  padding:5px 9px;border:1px solid var(--hair);border-radius:2px;
  transition:color 0s linear .09s,border-color .3s var(--ease)}

/* ── 16. FOUR-STEP PROCESS ──────────────────────────────────── */
/* A horizontal stepper with a scroll-linked fill, rather than a
   column of pale boxes. */

.steps4{
  --s4-gap:clamp(28px,3vw,44px);
  position:relative;
  display:grid;grid-template-columns:minmax(0,1fr);
  gap:clamp(26px,2.8vw,40px);
  padding-top:var(--s4-gap)}
@media(min-width:820px){.steps4{grid-template-columns:repeat(4,minmax(0,1fr));gap:clamp(20px,2.2vw,34px)}}

.tl-track{
  position:absolute;left:0;right:0;top:0;height:2px;
  background:var(--hair);overflow:hidden}
.tl-fill{
  position:absolute;left:0;top:0;bottom:0;width:0;
  background:var(--red);
  transition:width .18s linear}

.s4{position:relative}
/* The node sits ON the track, which is --s4-gap above the top of
   the step. Offsetting by that variable rather than a literal
   keeps the two aligned at every breakpoint. */
.s4::before{
  content:"";position:absolute;left:0;
  top:calc(-1 * var(--s4-gap) - 4px);
  width:10px;height:10px;border-radius:50%;
  background:var(--paper);border:2px solid var(--hair-2);
  transition:border-color .45s var(--ease),background .45s var(--ease),
             transform .45s var(--ease)}
.s4.lit::before{border-color:var(--red);background:var(--red);transform:scale(1.15)}
/* Stacked, a horizontal track and four nodes at the same point
   are meaningless. Each step takes its own rule instead. */
@media(max-width:819px){
  .tl-track{display:none}
  .s4::before{display:none}
  .steps4{padding-top:0;gap:0}
  .s4{padding:clamp(22px,4vw,30px) 0;border-top:1px solid var(--hair)}
  .steps4 > :nth-child(2) .s4,
  .steps4 > .s4:nth-child(2){border-top:var(--bw) solid var(--ink)}
}
.s4-n{
  font-size:12.5px;font-weight:700;letter-spacing:.13em;
  color:var(--ink-3);margin-bottom:clamp(14px,1.6vw,22px);
  transition:color .4s var(--ease)}
.s4.lit .s4-n{color:var(--red-ink)}
.s4-w{color:var(--ink-3);margin-bottom:8px;display:block}
.s4-t{
  font-size:clamp(18px,1.6vw,22px);line-height:1.18;
  font-weight:700;letter-spacing:-.028em;margin-bottom:10px}
.s4-b{font-size:15.5px;line-height:1.62;color:var(--ink-2)}

/* ── 17. FAQ ────────────────────────────────────────────────── */

.faq{border-bottom:1px solid var(--hair)}
/* Each FAQ sits alone inside its own widget wrapper, so a bare
   :first-child matched all of them and drew a doubled rule between
   every pair. Anchor it to the list instead. */
.lfra-faqs > :first-child .faq,
.lfra-faqs > .faq:first-child{border-top:1px solid var(--hair-2)}
.faq-q{
  width:100%;text-align:left;
  display:grid;grid-template-columns:auto minmax(0,1fr) auto;
  gap:clamp(14px,2vw,28px);align-items:center;
  padding:clamp(20px,2.2vw,30px) clamp(4px,1vw,14px);
  transition:color .25s var(--ease)}
.faq-q:hover{color:var(--red-ink)}
.fq-n{
  font-family:var(--sans);font-stretch:112%;
  font-weight:800;font-size:clamp(17px,1.7vw,23px);
  line-height:1;letter-spacing:-.03em;
  font-variant-numeric:tabular-nums;
  color:var(--ink-3)}
.faq.on .fq-n{color:var(--red)}
.fq-t{
  font-size:clamp(18.5px,1.8vw,25px);line-height:1.28;
  font-weight:600;letter-spacing:-.026em}
.faq.on .fq-t{font-weight:700}
.fq-x{
  width:31px;height:31px;flex-shrink:0;
  display:grid;place-items:center;border-radius:50%;
  border:1px solid var(--hair-2);
  font-size:17px;font-weight:400;color:var(--ink-3);
  transition:transform .4s var(--ease),background .3s var(--ease),
             color .3s var(--ease),border-color .3s var(--ease)}
.faq.on .fq-x{
  transform:rotate(135deg);
  background:var(--red);border-color:var(--red);color:#fff}
.faq-a{max-height:0;overflow:hidden;transition:max-height .5s var(--ease)}
.faq-a-in{
  padding:0 clamp(4px,1vw,14px) clamp(24px,2.4vw,32px)
          calc(clamp(14px,2vw,28px) + 32px);
  font-size:clamp(16.5px,1.35vw,19px);line-height:1.7;
  color:var(--ink-2);max-width:74ch}

/* ── 18. PRICING ────────────────────────────────────────────── */

.pricing{padding-bottom:clamp(30px,3vw,48px)}

.incl{
  margin-top:clamp(30px,3vw,46px);
  padding:clamp(26px,2.8vw,42px);
  background:var(--surface);
  border:1px solid var(--hair);border-radius:var(--r)}
.incl-h{
  font-size:clamp(18px,1.7vw,24px);line-height:1.2;
  font-weight:700;letter-spacing:-.03em;
  margin-bottom:clamp(18px,1.9vw,26px)}
.incl-h span{color:var(--red)}
.incl-list{
  display:grid;grid-template-columns:minmax(0,1fr);
  gap:clamp(11px,1.1vw,15px)}
@media(min-width:700px){.incl-list{grid-template-columns:minmax(0,1fr) minmax(0,1fr);column-gap:clamp(24px,3vw,50px)}}
.incl-list li{
  display:grid;grid-template-columns:auto minmax(0,1fr);gap:11px;align-items:start;
  font-size:15.5px;line-height:1.55;color:var(--ink-2)}
.incl-list li .ic{color:var(--red);font-weight:800;font-size:13px;padding-top:.22em}

.pc-head{
  padding:clamp(24px,2.5vw,38px) var(--pad-x) clamp(14px,1.5vw,20px)}
.pc-head h3{
  font-size:clamp(23px,2.7vw,38px);line-height:1.08;
  margin-bottom:10px}
.pc-head p{font-size:16px;line-height:1.6;color:var(--ink-2);max-width:62ch}

.pr-row{
  position:relative;overflow:hidden;
  display:grid;grid-template-columns:minmax(0,1fr) auto;
  gap:14px clamp(18px,2.4vw,40px);align-items:center;
  padding:clamp(17px,1.8vw,24px) var(--pad-x);
  border-top:1px solid var(--hair);
  transition:color 0s linear .09s}
.pr-row::before{
  content:"";position:absolute;inset:0;z-index:0;background:var(--paper-2);
  transform:scaleX(0);transform-origin:left;
  transition:transform .45s var(--ease)}
.pr-row > *{position:relative;z-index:1}
.pr-row:hover::before{transform:scaleX(1)}
/* 701px, not 720px: the mobile rules below stop at 700px, and a
   720px threshold left 701–719px with a two-column row holding
   three children, so the Book button wrapped onto its own line. */
@media(min-width:701px){.pr-row{grid-template-columns:minmax(0,1fr) auto auto}}

.pr-t{font-size:clamp(16px,1.35vw,18.5px);font-weight:600;letter-spacing:-.022em;min-width:0}
.pr-p{
  font-size:clamp(18px,1.7vw,23px);font-weight:700;
  letter-spacing:-.03em;white-space:nowrap}
.pr-p span{font-size:.62em;font-weight:500;color:var(--ink-3);margin-left:5px;letter-spacing:0}
.pr-b{
  display:inline-flex;align-items:center;justify-content:center;
  padding:10px 17px;border-radius:var(--r);
  font-family:var(--sans);
  font-size:14px;font-weight:600;letter-spacing:-.008em;
  border:1.5px solid var(--ink);color:var(--ink);white-space:nowrap;
  transition:background .3s var(--ease),color .3s var(--ease),
             border-color .3s var(--ease)}
.pr-b:hover{background:var(--ink);color:var(--paper)}
.pr-b.alt{border-color:var(--red);color:var(--red-ink)}
.pr-b.alt:hover{background:var(--red);border-color:var(--red);color:#fff}

.price-foot{
  padding:clamp(16px,1.7vw,22px) var(--pad-x) clamp(26px,2.8vw,40px);
  border-top:1px solid var(--hair);
  font-size:13.5px;line-height:1.65;color:var(--ink-3);max-width:none}
.price-legal{
  padding:0 var(--pad-x) var(--sec-b);
  font-size:13.5px;line-height:1.7;color:var(--ink-3);max-width:none}
.price-legal b{color:var(--ink-2);font-weight:600}

/* ── 19. CTA ────────────────────────────────────────────────── */

/* was padding-top:0, which put this band 49px below the section
   above it against a 109px rhythm everywhere else */
.cta{}
.cta-panel{
  background:var(--dark);color:var(--on-dark);border-radius:var(--r);
  display:grid;grid-template-columns:minmax(0,1fr);align-items:end}
@media(min-width:900px){.cta-panel{grid-template-columns:minmax(0,1.25fr) minmax(0,.75fr)}}
.cta-k{
  display:flex;align-items:center;gap:12px;
  color:var(--red);margin-bottom:clamp(16px,1.6vw,24px)}
.cta-k::before{
  content:"";width:clamp(20px,2.6vw,36px);height:2px;background:var(--red);
  transform:scaleX(0);transform-origin:left;
  transition:transform .7s var(--ease) .1s}
.cta-panel.seen .cta-k::before{transform:scaleX(1)}
.cta-h{
  font-size:clamp(30px,4vw,58px);line-height:1.02;
  margin-bottom:clamp(16px,1.6vw,22px)}
.cta-b{font-size:clamp(16px,1.3vw,18.5px);line-height:1.62;color:var(--on-dark-2);max-width:56ch}
.cta-act{display:flex;flex-wrap:wrap;gap:12px;align-items:center}
@media(min-width:900px){.cta-act{justify-content:flex-end}}

/* ── 20. FOOTER ─────────────────────────────────────────────── */

.foot{
  background:var(--dark);color:var(--on-dark)}
.foot-top{
  display:grid;grid-template-columns:minmax(0,1fr);
  gap:clamp(26px,2.8vw,46px);
  padding-bottom:clamp(26px,2.8vw,42px);
  border-bottom:1px solid var(--hair-dark)}
@media(min-width:880px){.foot-top{grid-template-columns:minmax(0,1fr) minmax(0,1.6fr);gap:clamp(28px,3vw,52px)}}

.fb-mark{
  display:flex;align-items:center;gap:9px;
  font-size:clamp(16px,1.4vw,19px);font-weight:700;
  font-stretch:108%;letter-spacing:-.03em;
  margin-bottom:clamp(14px,1.4vw,20px)}
.fb-mark svg{color:var(--red);flex-shrink:0}
.fb-desc{font-size:15px;line-height:1.65;color:var(--on-dark-2);max-width:46ch;margin-bottom:clamp(16px,1.6vw,22px)}
.fb-mail{font-size:14.5px;font-weight:600;color:var(--on-dark)}
.fb-tel{display:block;width:fit-content;margin-bottom:9px}

.foot-links{align-items:start;
  display:grid;grid-template-columns:minmax(0,1fr)}
@media(min-width:560px){.foot-links{grid-template-columns:repeat(2,minmax(0,1fr))}}
.fcol h4{color:var(--red);margin-bottom:clamp(14px,1.4vw,20px)}
.fcol ul{display:grid;gap:10px}
.fcol.two-up ul{grid-template-columns:repeat(2,minmax(0,1fr));gap:11px 18px}
/* list items carry the type, so a column of plain facts matches a column of
   links instead of inheriting body size and full brightness */
.fcol ul li{font-size:14.5px;line-height:1.5;color:var(--on-dark-2)}
.fcol ul a{color:var(--on-dark-2);transition:color .25s var(--ease)}
.fcol ul a:hover{color:var(--on-dark)}
.fc-v{font-size:14.5px;line-height:1.7;color:var(--on-dark-2)}
.fc-v b{color:var(--on-dark);font-weight:600}

.foot-legal{border-top:1px solid var(--hair-dark);
  display:grid;grid-template-columns:minmax(0,1fr);
  gap:clamp(22px,2.4vw,40px);
  padding-top:clamp(26px,2.8vw,40px)}
@media(min-width:880px){.foot-legal{grid-template-columns:minmax(0,1.75fr) minmax(0,.75fr);gap:clamp(26px,3vw,52px)}}
.fl-d{font-size:13.5px;line-height:1.7;color:var(--on-dark-3);max-width:92ch}
.fl-d b{color:var(--on-dark-2);font-weight:600}
.fl-m{
  font-size:12.5px;line-height:1.9;color:var(--on-dark-3);
  letter-spacing:.02em}
@media(min-width:880px){.fl-m{text-align:right}}

/* ── 21. INNER PAGES ────────────────────────────────────────── */

.phero{
  border-bottom:1px solid var(--hair)}
.phero-in{
  display:grid;grid-template-columns:minmax(0,1fr);align-items:end}
/* same floor for the inner-page headline column */
@media(min-width:900px){.phero-in{grid-template-columns:minmax(min-content,1.1fr) minmax(0,.9fr)}}
.ph-k{color:var(--red-ink);margin-bottom:clamp(10px,1.1vw,16px)}
.phero h1{
  font-size:clamp(38px,5.8vw,82px);line-height:.96;letter-spacing:-.042em}
.ph-d{font-size:clamp(16.5px,1.35vw,19.5px);line-height:1.62;color:var(--ink-2);max-width:52ch}

.crumb{
  padding:clamp(16px,1.7vw,22px) var(--pad-x);
  font-size:13px;letter-spacing:.06em;text-transform:uppercase;
  font-weight:600;color:var(--ink-3);
  border-bottom:1px solid var(--hair)}
.crumb a{color:var(--ink-2)}
.crumb span{color:var(--ink)}

/* Contact strip */
.cstrip{
  display:grid;grid-template-columns:minmax(0,1fr);
  border-bottom:1px solid var(--hair)}
@media(min-width:760px){.cstrip{grid-template-columns:repeat(3,minmax(0,1fr))}}
.cstrip .trust-item{
  padding:clamp(22px,2.4vw,34px) 0;
  background:transparent}
@media(min-width:760px){
  .cstrip .trust-item{padding-left:var(--cell)}
  .cstrip > .trust-item:first-child,
  .cstrip > :first-child .trust-item{padding-left:0}
}
.cstrip .trust-item::after{background:var(--hair)}
@media(min-width:760px){.cstrip > .trust-item:nth-child(3)::after,
  .cstrip > :nth-child(3) .trust-item::after{display:none}}
@media(max-width:759px){.cstrip .trust-item::after{display:none}}
.cstrip .tr-k{color:var(--ink-3);margin-bottom:8px}
.cstrip .tr-v{
  font-size:clamp(15px,1.25vw,17.5px);line-height:1.5;
  font-weight:600;letter-spacing:-.02em;color:var(--ink)}
.cstrip .trust-item:hover{background:transparent}

/* Blog index */
/* the widget wrappers inside a card are display:contents, so they generate no
   box and cannot hold a z-index. The content itself has to be lifted above
   the black wipe, or it paints underneath it. */

/* Article body */
.prose{}
.prose-in{max-width:760px}
.prose-in p{font-size:18.5px;line-height:1.75;color:var(--ink-2);margin-bottom:22px}
.prose-in p:first-of-type{font-size:21.5px;line-height:1.6;color:var(--ink)}
.prose-in h2{
  font-size:clamp(24px,2.7vw,35px);line-height:1.1;
  margin:clamp(38px,4vw,56px) 0 16px}
.prose-in h3{
  font-size:clamp(19px,2vw,23px);line-height:1.2;
  font-weight:700;font-stretch:110%;letter-spacing:-.03em;
  margin:32px 0 12px}
.prose-in ul{margin:0 0 24px}
.prose-in ul li{
  position:relative;padding-left:26px;margin-bottom:12px;
  font-size:18px;line-height:1.7;color:var(--ink-2)}
.prose-in ul li::before{
  content:"";position:absolute;left:0;top:.75em;
  width:10px;height:var(--bw);background:var(--red)}
.prose-in b,.prose-in strong{color:var(--ink);font-weight:600}
.prose-note{
  margin-top:clamp(34px,3.6vw,52px);
  padding:clamp(22px,2.4vw,32px);
  background:var(--surface);
  border:1px solid var(--hair);border-left:2px solid var(--red);
  border-radius:var(--r);
  font-size:14.5px;line-height:1.7;color:var(--ink-3)}
.prose-note b{color:var(--ink-2);font-weight:600}
/* Sign-off line closing an article. It had no rule at all and was
   rendering as ordinary body copy. */
.amark{
  margin-top:clamp(26px,2.8vw,38px);
  padding-top:clamp(16px,1.6vw,22px);
  border-top:1px solid var(--hair);
  font-size:clamp(11.5px,.92vw,13px);
  font-weight:700;text-transform:uppercase;letter-spacing:.185em;
  color:var(--ink-3)}
/* Article body arrives in sequence. */
.prose-in > p,.prose-in > h2,.prose-in > h3,.prose-in > ul,.prose-note{
  opacity:0;transform:translateY(12px);
  transition:opacity .7s var(--ease),transform .7s var(--ease)}
.prose-in > p.seen,.prose-in > h2.seen,.prose-in > h3.seen,
.prose-in > ul.seen,.prose-note.seen{opacity:1;transform:none}

.qf-tiny{font-size:13.5px;color:var(--ink-3);margin-top:20px;line-height:1.7}

/* ── 22. WPFORMS ────────────────────────────────────────────── */
/* WPForms ships its own stylesheet with high-specificity rules,
   so these need !important to land. Nothing else in this file
   does. */

.wpforms-container{margin:0!important;max-width:100%}
.wpforms-container .wpforms-field-container{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:0 clamp(16px,1.8vw,26px)}
@media(max-width:620px){
  /* The digits do not fit beside the brand and the CTA at this width, but the
     call button must stay reachable: it keeps the handset as a tap-to-call
     target and only the number is dropped. */
  .mh-tel{padding:9px 10px;gap:0}
  .mh-tel span{display:none}
  .mh-tel .mh-tel-i{width:17px;height:17px}
.wpforms-container .wpforms-field-container{grid-template-columns:minmax(0,1fr)}}
/* Name and message span the full width; the rest pair up. */
.wpforms-container .wpforms-field:nth-child(1),
.wpforms-container .wpforms-field:nth-child(8){grid-column:1/-1}
.wpforms-container .wpforms-field{padding:0 0 20px!important;min-width:0}
.wpforms-container .wpforms-field-hp{display:none!important}

.wpforms-container .wpforms-field-label{
  display:block!important;
  font-family:var(--sans)!important;
  font-size:11.5px!important;font-weight:700!important;
  letter-spacing:.16em!important;text-transform:uppercase!important;
  color:var(--ink-3)!important;
  margin:0 0 9px!important}
.wpforms-container .wpforms-required-label{color:var(--red)!important;border:none!important;margin-left:3px}

.wpforms-container input[type=text],
.wpforms-container input[type=email],
.wpforms-container input[type=tel],
.wpforms-container input[type=url],
.wpforms-container input[type=number],
.wpforms-container select,
.wpforms-container textarea{
  width:100%!important;max-width:100%!important;
  background:var(--surface)!important;
  border:1px solid var(--hair-2)!important;
  border-radius:var(--r)!important;
  padding:13px 15px!important;
  font-family:var(--sans)!important;
  font-size:15.5px!important;color:var(--ink)!important;
  box-shadow:none!important;
  transition:border-color .25s var(--ease),box-shadow .25s var(--ease)!important}
.wpforms-container textarea{min-height:112px!important;line-height:1.6!important;resize:vertical!important}
.wpforms-container ::placeholder{color:var(--ink-3)!important;opacity:1}
.wpforms-container input:focus,
.wpforms-container select:focus,
.wpforms-container textarea:focus{
  border-color:var(--ink)!important;outline:none!important;
  box-shadow:0 0 0 3px rgba(220,60,18,.13)!important}
.wpforms-container select{
  appearance:none;-webkit-appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,var(--ink-3) 50%),
                   linear-gradient(135deg,var(--ink-3) 50%,transparent 50%)!important;
  background-position:calc(100% - 19px) calc(50% + 1px),calc(100% - 14px) calc(50% + 1px)!important;
  background-size:5px 5px,5px 5px!important;
  background-repeat:no-repeat!important;
  padding-right:40px!important}

.wpforms-container .wpforms-submit-container{
  grid-column:1/-1;
  padding-top:18px!important;margin-top:6px!important;
  border-top:1px solid var(--hair)}
.wpforms-container button[type=submit]{
  display:inline-flex!important;align-items:center;gap:10px;
  background:var(--ink)!important;color:#fff!important;
  border:1.5px solid var(--ink)!important;border-radius:var(--r)!important;
  padding:15px 28px!important;
  font-family:var(--sans)!important;
  font-size:15px!important;font-weight:600!important;letter-spacing:-.012em!important;
  transition:background .3s var(--ease),border-color .3s var(--ease),
             transform .3s var(--ease)!important}
.wpforms-container button[type=submit]::after{
  content:"→";transition:transform .3s var(--ease)}
.wpforms-container button[type=submit]:hover{
  background:var(--red)!important;border-color:var(--red)!important;
  transform:translateY(-2px)}
.wpforms-container button[type=submit]:hover::after{transform:translateX(5px)}
.wpforms-container button[type=submit][disabled]{opacity:.5!important;transform:none}

.wpforms-container .wpforms-error{
  color:var(--red-ink)!important;
  font-size:12.5px!important;margin-top:7px!important}
.wpforms-container input.wpforms-error,
.wpforms-container select.wpforms-error,
.wpforms-container textarea.wpforms-error{border-color:var(--red)!important}
.wpforms-confirmation-container,
.wpforms-confirmation-container-full{
  background:var(--surface)!important;
  border:1px solid var(--hair)!important;border-left:2px solid var(--red)!important;
  border-radius:var(--r)!important;
  padding:clamp(24px,2.6vw,36px)!important;
  color:var(--ink)!important;font-size:16px!important;line-height:1.65!important}

/* ── 22b. FORM POLISH ───────────────────────────────────────── */

/* the labels were at --ink-3, which is a tone meant for captions; at
   11.5px uppercase they need more weight to stay readable */
.wpforms-container .wpforms-field-label{color:var(--ink-2)!important}

/* a little more air between fields */
.wpforms-container .wpforms-field{padding:0 0 22px!important}

.wpforms-container input:hover,
.wpforms-container select:hover,
.wpforms-container textarea:hover{border-color:var(--hair-2)!important}

/* WPForms ships an unstyled spinner and a noscript warning */
.wpforms-submit-spinner{width:16px;height:16px;margin-left:10px;vertical-align:-3px}
.wpforms-error-noscript{
  font-size:13px;line-height:1.6;color:var(--red-ink);
  margin:0 0 16px;padding:12px 14px;
  background:var(--red-wash);border-radius:var(--r)}

/* Inside the quote panel the fields sat white on a white card, so they
   read as flat areas with a faint outline rather than as inputs. Sinking
   them to paper gives the card some depth; focus lifts them back to
   white so the active field is unmistakable. */
.quote-form .wpforms-container input[type=text],
.quote-form .wpforms-container input[type=email],
.quote-form .wpforms-container input[type=tel],
.quote-form .wpforms-container input[type=url],
.quote-form .wpforms-container input[type=number],
.quote-form .wpforms-container select,
.quote-form .wpforms-container textarea{
  background:var(--paper)!important}
.quote-form .wpforms-container input:focus,
.quote-form .wpforms-container select:focus,
.quote-form .wpforms-container textarea:focus{
  background:var(--surface)!important}

/* the submit spans its column here — a form this narrow reads better
   with a full-width action than a button floated at the left */
.quote-form .wpforms-container .wpforms-submit-container{
  padding-top:22px!important;margin-top:2px!important}
.quote-form .wpforms-container button[type=submit]{
  width:100%;justify-content:center;
  padding-top:17px!important;padding-bottom:17px!important}

/* ── 22c. QUOTE FORM — STRUCTURE ────────────────────────────
   Eight fields in one flat run read as a raw form. Splitting them into
   two named groups — who you are, then what the building is — gives the
   panel a shape and tells the reader how much is left. The labels are
   drawn with CSS rather than added as fields, so the form itself is
   still just the eight inputs WPForms is submitting. */

.quote-form .wpforms-container .wpforms-field:nth-child(1)::before{
  content:"Your details"}
.quote-form .wpforms-container .wpforms-field:nth-child(4)::before{
  content:"About the building"}
.quote-form .wpforms-container .wpforms-field:nth-child(1)::before,
.quote-form .wpforms-container .wpforms-field:nth-child(4)::before{
  display:block;
  font-size:11.5px;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--red-ink);
  margin-bottom:clamp(12px,1.2vw,16px)}
/* the rule runs under both cells of the row the group starts on */
.quote-form .wpforms-container .wpforms-field:nth-child(4){
  border-top:1px solid var(--hair);
  padding-top:clamp(20px,2vw,26px)!important;
  margin-top:clamp(4px,.6vw,8px)}
@media(min-width:1101px){
  .quote-form .wpforms-container .wpforms-field:nth-child(5){
    border-top:1px solid var(--hair);
    padding-top:clamp(20px,2vw,26px)!important;
    margin-top:clamp(4px,.6vw,8px)}
  /* keeps the paired field's label level with the one carrying the
     group heading */
  .quote-form .wpforms-container .wpforms-field:nth-child(5)::before{
    content:"";display:block;
    height:calc(11.5px * 1.35 + clamp(12px,1.2vw,16px))}
}

/* ── 22d. QUOTE FORM — FIELD DETAIL ─────────────────────────── */

/* a touch taller, and the label tracking eased back: .16em was set for
   a standalone caption, and at eight repeats it read as strain */
.quote-form .wpforms-container input[type=text],
.quote-form .wpforms-container input[type=email],
.quote-form .wpforms-container input[type=tel],
.quote-form .wpforms-container select,
.quote-form .wpforms-container textarea{
  padding:14px 16px!important;
  border-radius:var(--r)!important}
.quote-form .wpforms-container .wpforms-field-label{
  font-size:11px!important;letter-spacing:.14em!important;
  margin-bottom:8px!important}
.quote-form .wpforms-container textarea{min-height:120px!important}

/* the focused field takes a red edge as well as the ring, so which one
   is live is obvious at a glance down the column */
.quote-form .wpforms-container input:focus,
.quote-form .wpforms-container select:focus,
.quote-form .wpforms-container textarea:focus{
  box-shadow:inset 3px 0 0 var(--red),
             0 0 0 3px rgba(220,60,18,.12)!important}

/* a crisper chevron than two stacked gradients */
.quote-form .wpforms-container select{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='7' viewBox='0 0 11 7'%3E%3Cpath d='M1 1l4.5 4.5L10 1' fill='none' stroke='%23141310' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' opacity='.5'/%3E%3C/svg%3E")!important;
  background-position:calc(100% - 16px) center!important;
  background-size:11px 7px!important;
  background-repeat:no-repeat!important}

/* ── 23. ELEMENTOR STRUCTURE ────────────────────────────────
   The page is a real Elementor container tree: every section is a
   container, and every block inside it is its own widget, so each
   one can be dragged, duplicated or deleted in the editor.

   Containers read the `css_classes` setting — NOT `_css_classes`,
   which is the widget key and is silently ignored on containers.
   That is why earlier rules had to target the generated
   `elementor-element-<id>` class, which breaks the moment a
   section is deleted and rebuilt. These target real classes and
   survive editing.
   ============================================================ */

/* Sections that were block-level markup must stay block; Elementor
   makes every container a flex column by default.

   .types is deliberately NOT in this list any more: it became a card
   grid, and this rule outranks `.types{display:grid}` — which is why
   the cards kept stacking however the columns were declared. */
body.elementor-page :is(.sec,.hero,.phero,.cta,.prose,.foot,
                        .blist,.duty-rows,.hero-copy,
                        .lfra-formwrap,.lfra-faqs,
                        .lfra-pricecard,.lfra-pricerows).e-con{
  display:block}

/* Elementor wraps each widget in a div. Inside these layout
   parents that extra box would become the grid or flex item
   instead of the content, so it is removed from the box tree.
   Scoped to raw-HTML widgets only: a native widget added later
   keeps its normal box and Elementor's own styling. */
body.elementor-page :is(.sec,.hero,.phero,.cta,.prose,.foot,
                        .duty-rows,.who,.types,.steps4,.pas-steps,
                        .trust,.blist,.cstrip,.foot-links,.hero-kicker,
                        .hero-main,.hero-copy,.hero-actions,.phero-in,
                        .report,.cta-panel,.foot-top,.insp,.quote,
                        .lfra-faqs,.lfra-pricerows,.lfra-pricecard,
                        .lfra-pricegrid,.bcard) > :is(.elementor-widget-html,.elementor-widget-text-editor){
  display:contents}

/* contact: the quote form, capped so fields are not stretched */
body.elementor-page .lfra-formwrap{
}
body.elementor-page .lfra-formwrap .wpforms-container,
body.elementor-page .lfra-formwrap .qf-tiny{max-width:720px}

/* FAQ groups carry their own gutter on the entries. The heading
   sits in a separate .sec above them, so that section drops its
   bottom padding or the two stack into a dead band. */
body.elementor-page .lfra-faqs{}
#faq{padding-bottom:0}

/* Same split on the contact page: heading in .sec, form below. */
body.elementor-page .lfra-formhead .sec{padding-bottom:0}

/* services: the two price tables stack full width */
body.elementor-page .lfra-pricegrid{}
body.elementor-page .lfra-pricecard{border:none;background:var(--surface)}

/* ── 24. RESPONSIVE ─────────────────────────────────────────── */

@media(max-width:1039px){
  .hero-visual{max-width:560px}
}
@media(max-width:900px){
  :root{--mh:58px}
  .mh-nav{display:none}
  .dock{display:flex}
  /* The dock is fixed and overlays the foot of the page. The
     clearance goes on the footer, not on body — body padding
     would show a strip of paper below the dark footer. */
  .foot{padding-bottom:calc(clamp(26px,2.8vw,38px) + 64px)}
}
@media(max-width:700px){
  :root{--sec-y:clamp(40px,9vw,58px);--sec-b:clamp(32px,7.5vw,48px)}
  .mh-cta{padding:9px 14px;font-size:12.5px}
  .mh-cta .ar{display:none}
  .drow,.tcell{grid-template-columns:minmax(0,1fr);gap:12px}
  .rspec-head,.doc-head{flex-direction:column;gap:12px}
  .rh-ref,.dh-r{text-align:left}
  .pr-row{grid-template-columns:minmax(0,1fr) auto}
  .pr-b{grid-column:1/-1;justify-self:start}
  .hero-actions .btn,.cta-act .btn{flex:1 1 auto;justify-content:center}
}
@media(max-width:420px){
  /* At 320px the wordmark and the quote button together measured
     wider than the header's content box, and since body clips
     overflow-x the button was simply cut off rather than pushed.
     Tighten both, and let the brand clip before the button does. */
  .masthead{gap:10px}
  .mh-brand{font-size:clamp(9.8px,3.1vw,13px);min-width:0;overflow:hidden;letter-spacing:-.035em}
  .mh-cta{padding:8px 12px;font-size:12px;flex-shrink:0}
  .hero h1{font-size:clamp(38px,12vw,52px)}
  .doc-head,.doc-rows,.doc-scale,.rspec-head,.rscale,
  .rspec-rows,.rspec-find,.rspec-stamp{padding-left:18px;padding-right:18px}
}

/* ── 25. MOTION — SECOND PASS ───────────────────────────────
   Six additions. Each does one job, each is short, and each is
   tied to something the page already means. */

/* 1 · Inner-page hero. The headline was masking in on its own
      while the kicker and standfirst just appeared — the entrance
      read half-finished. These are always above the fold, so they
      run on a delay rather than waiting on the observer. */
.ph-k,.ph-d{animation:fadeUp .85s var(--ease) both}
.ph-k{animation-delay:.04s}
.ph-d{animation-delay:.34s}
html.js-motion .phero h1.seen{transition-delay:.12s}

/* 2 · FAQ answers rise as the panel opens instead of being
      revealed flatly by the height change alone. */
html.js-motion .faq-a-in{
  opacity:0;transform:translateY(7px);
  transition:opacity .45s var(--ease) .06s,transform .45s var(--ease) .06s}
html.js-motion .faq.on .faq-a-in{opacity:1;transform:none}

/* 3 · Risk scale. Five bands climbing left to right, so the
      rating reads as a measurement being taken rather than a
      static graphic. Replaces the single-band pop. */
@keyframes barIn{from{transform:scaleY(.22);opacity:0}to{transform:none;opacity:1}}
html.js-motion .rscale .rs{transform-origin:bottom;transform:scaleY(.22);opacity:0}
html.js-motion .report-spec.seen .rscale .rs{
  transform:none;opacity:1;
  transition:transform .5s var(--ease),opacity .4s var(--ease)}
.report-spec.seen .rscale .rs:nth-child(1){transition-delay:.34s}
.report-spec.seen .rscale .rs:nth-child(2){transition-delay:.41s}
.report-spec.seen .rscale .rs:nth-child(3){transition-delay:.48s}
.report-spec.seen .rscale .rs:nth-child(4){transition-delay:.55s}
.report-spec.seen .rscale .rs:nth-child(5){transition-delay:.62s}

/* the hero's copy of the same scale is above the fold, so it is
   timed against the headline rather than observed */
.doc-scale span{transform-origin:bottom;animation:barIn .5s var(--ease) both}
.doc-scale span:nth-child(1){animation-delay:.88s}
.doc-scale span:nth-child(2){animation-delay:.95s}
.doc-scale span:nth-child(3){animation-delay:1.02s}
.doc-scale span:nth-child(4){animation-delay:1.09s}
.doc-scale span:nth-child(5){animation-delay:1.16s}

/* 4 · Footer columns arrive in sequence. The footer had no
      entrance at all, so the page ended abruptly. */
html.js-motion :is(.foot-brand,.fcol){opacity:0;transform:translateY(14px)}
html.js-motion :is(.foot-brand,.fcol).seen{
  opacity:1;transform:none;
  transition:opacity .75s var(--ease),transform .75s var(--ease);
  transition-delay:calc(var(--i,0) * 80ms)}

/* 5 · The specimen tilts a degree or so toward the pointer.
      site.js composes this with the scroll drift into one
      transform — both write to .doc, so neither may own it
      alone. Desktop only, and off under reduced motion. */
.hero-visual{perspective:1200px}
.doc{
  transform-style:preserve-3d;
  /* a short transition on transform smooths both the pointer tilt
     and the scroll drift without making either feel laggy */
  transition:transform .14s var(--ease),box-shadow .4s var(--ease)}
.hero-visual:hover .doc{
  box-shadow:0 2px 4px rgba(20,19,16,.05),
             0 26px 54px -18px rgba(20,19,16,.24),
             0 60px 110px -60px rgba(20,19,16,.38)}

/* 6 · Price rows: the figure steps forward slightly as the row
      lights up, so the eye lands on the number. */
.pr-p{transition:transform .38s var(--ease)}
.pr-row:hover .pr-p{transform:translateX(-4px)}

/* ── 25b. QUOTE SECTION ──────────────────────────────────────
   The source design closes on a two-panel block: the pitch on a solid
   red ground, the form on paper beside it. Kept here in our red, with
   hairlines, wrapping the real WPForms form so it actually submits. */

.quote-sec{padding-bottom:var(--sec-b)}
.quote{
  display:grid;grid-template-columns:minmax(0,1fr);
  border:1px solid var(--hair);border-radius:var(--r);
  overflow:hidden;
  box-shadow:0 1px 2px rgba(20,19,16,.04),
             0 18px 44px -22px rgba(20,19,16,.16)}
@media(min-width:900px){
  .quote{grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr)}
}

.quote-say{
  position:relative;color:#fff;
  /* the panel stretches to the form's height, so the copy is centred in
     the column — anchoring it top or bottom collects all the slack into
     a single gap */
  display:flex;flex-direction:column;justify-content:center;
  padding:clamp(28px,3.4vw,52px);
  /* This panel is the site's one large field of red and it stays that
     way — it is the closing moment. The red that came off elsewhere in
     this pass was the incidental kind: whole cards flipping red on
     hover. */
  background:var(--red);
  background-image:radial-gradient(125% 95% at 100% 0%,
                   rgba(255,255,255,.16), rgba(255,255,255,0) 62%)}
.quote-say .qs-k{
  display:flex;align-items:center;gap:12px;
  font-weight:700;text-transform:uppercase;
  font-size:clamp(11.5px,.92vw,13px);letter-spacing:.185em;
  color:rgba(255,255,255,.85);margin-bottom:clamp(14px,1.5vw,20px)}
.quote-say .qs-k::before{
  content:"";width:clamp(20px,2.6vw,36px);height:2px;flex-shrink:0;
  background:rgba(255,255,255,.85);
  transform:scaleX(0);transform-origin:left;
  transition:transform .7s var(--ease) .55s}
.quote.seen .qs-k::before{transform:scaleX(1)}
.quote-say h2{
  font-family:var(--sans);font-stretch:112%;font-weight:800;
  font-size:clamp(30px,4vw,56px);line-height:.92;
  letter-spacing:-.022em;text-transform:uppercase;
  margin-bottom:clamp(14px,1.5vw,20px);
  text-wrap:balance;overflow-wrap:normal}
.quote-say h2 em{font-style:normal;color:rgba(255,255,255,.62)}
.quote-say .qs-b{
  font-size:clamp(15.5px,1.25vw,17.5px);line-height:1.55;
  color:rgba(255,255,255,.9);max-width:40ch;
  margin-bottom:clamp(22px,2.4vw,32px)}
.qs-promise{display:grid}
.qs-promise li{
  display:grid;grid-template-columns:auto minmax(0,1fr);
  gap:clamp(11px,1.2vw,16px);align-items:baseline;
  padding:clamp(12px,1.3vw,17px) 0;
  border-top:1px solid var(--hair-dark)}
.qs-promise li:last-child{border-bottom:1px solid rgba(255,255,255,.3)}
.qs-promise .qp-n{
  font-weight:800;font-stretch:112%;
  font-size:clamp(17px,1.6vw,21px);letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;color:rgba(255,255,255,.72)}
.qs-promise li b{
  display:block;font-stretch:112%;
  font-size:clamp(14.5px,1.25vw,16.5px);font-weight:700;
  text-transform:uppercase;letter-spacing:-.005em}
.qs-promise li small{
  display:block;margin-top:3px;
  font-size:13.5px;line-height:1.5;color:rgba(255,255,255,.78)}

.quote-form{background:var(--surface)}
.qf-head{
  display:flex;justify-content:space-between;align-items:baseline;
  gap:16px;flex-wrap:wrap;
  border-bottom:1px solid var(--hair);
  padding-bottom:clamp(12px,1.3vw,16px);
  margin-bottom:clamp(20px,2.2vw,30px)}
.qf-head h3{
  font-family:var(--sans);font-stretch:112%;font-weight:700;
  font-size:clamp(19px,1.9vw,26px);line-height:1.05;
  letter-spacing:-.02em;text-transform:uppercase}
.qf-tag{
  font-size:12px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--red-ink);white-space:nowrap}
/* when a price row has filled the property type in for you, say so
   briefly rather than changing it silently */
@keyframes prefilled{
  0%,70%{box-shadow:0 0 0 3px rgba(220,60,18,.22);border-color:var(--red)}
  100%{box-shadow:0 0 0 3px rgba(220,60,18,0)}
}
.wpforms-container select.prefilled{animation:prefilled 2.6s var(--ease) both}
/* this panel is narrower than the contact page, so paired fields go
   single-column sooner than the global 620px rule would allow */
@media(max-width:1100px){
  .quote-form .wpforms-container .wpforms-field-container{grid-template-columns:minmax(0,1fr)}
}
@media(min-width:1101px){
  .quote-form .wpforms-container .wpforms-field-container{grid-template-columns:1fr 1fr}
}

/* ── 25c. QUOTE SECTION — MOTION ────────────────────────────
   The block assembles rather than simply fading up: the red ground
   wipes across, then the form builds a field at a time. */

/* the coloured panel sweeps in from the left, carrying its own copy
   with it — the headline needs no separate reveal on top of this */
html.js-motion .quote-say{clip-path:inset(0 100% 0 0)}
html.js-motion .quote.seen .quote-say{
  clip-path:inset(0 0 0 0);
  transition:clip-path .95s var(--ease)}

/* the form heading rule follows the panel */
html.js-motion .qf-head{opacity:0;transform:translateY(10px)}
html.js-motion .quote.seen .qf-head{
  opacity:1;transform:none;
  transition:opacity .6s var(--ease) .4s,transform .6s var(--ease) .4s}

/* then the fields arrive in order, so the form looks like it is being
   laid out rather than switched on */
html.js-motion .quote .wpforms-field,
html.js-motion .quote .wpforms-submit-container,
html.js-motion .quote .qf-tiny{opacity:0;transform:translateY(12px)}
html.js-motion .quote.seen .wpforms-field,
html.js-motion .quote.seen .wpforms-submit-container,
html.js-motion .quote.seen .qf-tiny{
  opacity:1;transform:none;
  transition:opacity .55s var(--ease),transform .55s var(--ease)}
.quote.seen .wpforms-field:nth-child(1){transition-delay:.50s}
.quote.seen .wpforms-field:nth-child(2){transition-delay:.56s}
.quote.seen .wpforms-field:nth-child(3){transition-delay:.62s}
.quote.seen .wpforms-field:nth-child(4){transition-delay:.68s}
.quote.seen .wpforms-field:nth-child(5){transition-delay:.74s}
.quote.seen .wpforms-field:nth-child(6){transition-delay:.80s}
.quote.seen .wpforms-field:nth-child(7){transition-delay:.86s}
.quote.seen .wpforms-field:nth-child(8){transition-delay:.92s}
.quote.seen .wpforms-submit-container{transition-delay:.98s}
.quote.seen .qf-tiny{transition-delay:1.04s}

/* the promise rows keep their own stagger, offset to land after the
   panel has finished wiping */
html.js-motion .qs-promise li.seen{transition-delay:calc(.55s + var(--i,0) * 80ms)}

/* ── 25d. PAS 79 STEPS — MOTION ─────────────────────────────
   Five steps that only faded up read as a static table. A red rule now
   draws across the top of each one in turn, so the sequence advances
   through the row the way the timeline does further down the page. */

.pstep::before{
  content:"";position:absolute;left:0;right:0;top:0;height:2px;
  background:var(--red);
  transform:scaleX(0);transform-origin:left;
  transition:transform .6s var(--ease),height .3s var(--ease)}
html.js-motion .pstep.seen::before{
  transform:scaleX(1);
  transition-delay:calc(var(--i,0) * 110ms)}

/* hovering a step brings its rule and its tag forward */
.pstep:hover::before{height:3px}
.pstep .ps-n,.pstep .ps-o,.pstep .ps-t{
  transition:color .3s var(--ease),border-color .3s var(--ease),
             transform .35s var(--ease)}
.pstep:hover .ps-n{color:#fff}
.pstep:hover .ps-t{transform:translateX(3px)}
.pstep:hover .ps-o{color:var(--red);border-top-color:var(--red)}

/* the label counts up out of the rule rather than arriving with the
   body copy, so the eye follows the sequence across */
html.js-motion .pstep .ps-n{opacity:0;transform:translateY(8px)}
html.js-motion .pstep.seen .ps-n{
  opacity:1;transform:none;
  transition:opacity .5s var(--ease),transform .5s var(--ease);
  transition-delay:calc(var(--i,0) * 110ms + .18s)}

/* ── 26. MOTION — THIRD PASS ────────────────────────────────
   Six more, all small, all hover- or arrival-triggered. Nothing
   here loops or moves on its own. */

/* 1 · Trust bar. A red rule draws under the figure on hover, so
      the four facts feel like entries rather than decoration. */
.trust .trust-item .tr-v{position:relative;display:inline-block}
.trust .trust-item .tr-v::after{
  content:"";position:absolute;left:0;right:0;bottom:-7px;height:2px;
  background:var(--red);
  transform:scaleX(0);transform-origin:left;
  transition:transform .45s var(--ease)}
.trust .trust-item:hover .tr-v::after{transform:scaleX(1)}

/* 2 · A closed FAQ's plus turns a quarter on hover, so the row
      reads as openable before you click. Scoped to :not(.on) or it
      would fight the 135° the open state already uses. */
.faq:not(.on) .faq-q:hover .fq-x{
  transform:rotate(90deg);
  border-color:var(--red);color:var(--red)}

/* 3 · Priority badges settle in just behind their line, so the
      specimen fills in the way a form gets stamped. */
html.js-motion .rspec-find li .p{opacity:0;transform:scale(.84)}
html.js-motion .rspec-find li.seen .p{
  opacity:1;transform:none;
  transition:opacity .3s var(--ease) calc(var(--i,0) * 65ms + 140ms),
             transform .42s var(--ease) calc(var(--i,0) * 65ms + 140ms)}

/* 4 · The wordmark's flame lifts very slightly on hover. */
.mh-brand .fire-mark{transition:transform .4s var(--ease)}
.mh-brand:hover .fire-mark{transform:translateY(-1px) scale(1.09)}

/* 5 · Price buttons take the same wipe as the main buttons rather
      than cross-fading, which sent the label through a mid-tone. */
.pr-b{position:relative;overflow:hidden;isolation:isolate;
  transition:color 0s linear .15s,border-color .3s var(--ease)}
.pr-b::before{
  content:"";position:absolute;inset:0;z-index:-1;background:var(--ink);
  transform:scaleX(0);transform-origin:left;
  transition:transform .4s var(--ease)}
.pr-b:hover{background:transparent;color:var(--paper)}
.pr-b:hover::before{transform:scaleX(1)}
.pr-b.alt::before{background:var(--red)}
.pr-b.alt:hover{background:transparent;color:#fff}

/* 6 · The timeline node gives one small pop as its step is
      reached — the only thing on the page that reacts to scroll
      position rather than to the pointer. */
@keyframes nodePop{0%{transform:scale(1)}45%{transform:scale(1.42)}100%{transform:scale(1.15)}}
.s4.lit::before{animation:nodePop .45s var(--ease) both}

/* ── 27. REDUCED MOTION + PRINT ─────────────────────────────── */

@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms!important;animation-iteration-count:1!important;
    animation-delay:0s!important;
    transition-duration:.001ms!important;transition-delay:0s!important}
  /* the schematic layers are shown/hidden by class, so they must
     still respond instantly rather than waiting out a delay */
  .sk{transition:none!important}
  .rvl,.mask-up,.report-spec,.prose-in > p,.prose-in > h2,
  .prose-in > h3,.prose-in > ul,.prose-note,
  .hero h1 .line > span,.hero-eyebrow,.hero-lede,
  .hero-actions,.hero-kicker,.hero-visual,
  .ph-k,.ph-d,.doc-scale span,.rscale .rs,.faq-a-in,
  .foot-brand,.fcol,.quote-say,.qf-head,.pstep .ps-n,
  .quote .wpforms-field,.quote .wpforms-submit-container,.quote .qf-tiny{
    opacity:1!important;transform:none!important;clip-path:none!important}
  .st-k::before,.cta-k::before,.pstep::before{transform:none!important}
  .hero-top .blink{opacity:1!important}
  /* the inline bootstrap already withholds .js-motion here; this
     covers a preference changed after the page loaded */
  html.js-motion *{
    opacity:1!important;transform:none!important;clip-path:none!important}
  .doc-svg .dl,.doc-svg .dl-s,.doc-svg .dl-r{stroke-dashoffset:0!important}
  .doc-svg .dfill{opacity:.09!important}
  .insp-svg .sfill{opacity:.12!important}
}

/* BLOG CARD THUMBNAIL ------------------------------------------------
   The picture is an Elementor Image widget, so it is swapped from the
   media library, not from this file. Only the reveal behaviour lives
   here. The card padding and gap are Elementor container settings. */
/* the title link is stretched over the whole card, so the card stays one
   real crawlable link rather than a div made clickable by script */
/* The thumbnail is always fully visible - no fade. On hover it lifts and
   scales, so it pops off the tile while the black wipe crosses behind it. */

/* nothing to hover on touch, so it simply shows */

/* ARTICLE HERO AND CENTRED COLUMN ------------------------------------ */
@keyframes heroIn{from{opacity:0;transform:translateY(20px) scale(.975)}
  to{opacity:1;transform:none}}
/* the illustration carries its own paper ground, so the hero needs no inner
   padding: the picture fills the frame the way a photograph would */
.post-hero{margin:0 auto clamp(42px,4.6vw,74px);max-width:760px;
  border:1px solid var(--hair);border-radius:var(--r);overflow:hidden;
  animation:heroIn .95s var(--ease) both .16s}
.post-hero img{display:block;width:100%;height:auto}
.prose-in{margin-inline:auto}
.post-head .phero-in{grid-template-columns:minmax(0,1fr);
  justify-items:center;text-align:center;max-width:900px;margin-inline:auto}
.post-head .ph-d{max-width:58ch}

/* article meta line under the title */
.ph-meta{display:flex;align-items:center;justify-content:center;gap:10px;
  margin-top:clamp(14px,1.5vw,20px);font-size:13px;font-weight:600;
  letter-spacing:.02em;color:var(--ink-3)}
.ph-meta i{font-style:normal;width:4px;height:4px;border-radius:50%;
  background:var(--red);flex-shrink:0}

/* keep-reading heading: reuses the section kicker style */
.kr-head{margin-bottom:clamp(18px,2vw,28px);color:var(--ink-3)}

/* article headings carry the same red numerals the rest of the site uses,
   drawn by a CSS counter so the copy stays plain h2s in the editor */
.prose-in{counter-reset:artsec}
.prose-in h2{counter-increment:artsec;position:relative}
.prose-in h2::before{content:counter(artsec,decimal-leading-zero);
  display:block;margin-bottom:.42em;color:var(--red);
  font-size:.4em;font-weight:800;letter-spacing:.12em;
  font-variant-numeric:tabular-nums;line-height:1}
/* the aside gets a red spine so it reads as a deliberate stop in the text */
.prose-note{border-left:3px solid var(--red)}

/* PRICING GRID ---------------------------------------------------------
   Residential and Commercial sit side by side from 900px up. The divider
   between them is the 1px container gap letting the grid background show
   through, the same hairline treatment .who and .types use. The column
   count lives here because Elementor cannot express it. */
.lfra-pricegrid{display:grid;grid-template-columns:minmax(0,1fr)}
@media(min-width:900px){
  body.elementor-page .lfra-pricegrid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
/* each card keeps its rows flowing normally inside the grid cell */
.lfra-pricecard{display:flex;flex-direction:column}
.lfra-pricerows{flex:1}

/* SHARED-ELEMENT PAGE TRANSITION ------------------------------------- */
/* the card thumbnail is named by site.js on click, and morphs into this */
.post-hero img{view-transition-name:post-img}
.masthead{view-transition-name:masthead}
@media(prefers-reduced-motion:reduce){
  ::view-transition-group(*),::view-transition-old(*),
  ::view-transition-new(*){animation:none!important}
}

/* a fourth footer column (Our Policies) needs more room than three did */
@media(min-width:900px){
  .foot-links{grid-template-columns:minmax(0,.55fr) minmax(0,1.2fr) minmax(0,1.25fr)}
}

/* Inside a price card, --pad-x means the card inset, not the page gutter.
   The card was full width on the old Services page, so the page gutter was
   right there. At half width on the home page it indented every row ~48px
   past the section heading, which is what made the block look detached.
   Rebinding the token fixes .pc-head, .pr-row and .price-foot at once. */
.lfra-pricecard{--pad-x:var(--cell)}

/* A policy is a reference document rather than an article, so it reads wider
   than the 760px blog measure. The heading block widens with it so the two
   stay aligned. */
.policy .prose-in{max-width:920px}
.policy .post-hero{max-width:920px}

/* CTA BUTTON ROW ------------------------------------------------------
   Phone leads in solid red. The other two are outlines, so the row reads
   as one primary action and two alternatives rather than three competing
   shapes. A firmer border keeps the outlines from vanishing on the dark
   panel, and a common min-height stops the icon button sitting proud. */
.cta-act{gap:14px}
.cta-act .btn{min-height:52px}
.cta-panel .btn-ghost{border-color:rgba(246,243,237,.34)}
.cta-panel .btn-ghost:hover{border-color:var(--on-dark)}
.cta-tel .mh-tel-i{color:currentColor}

/* the call button sits between the statement and the fallback line, so the
   phone reads as the first thing to do on the contact page */
.qs-tel{align-self:flex-start;margin:clamp(18px,2vw,26px) 0 clamp(14px,1.6vw,20px)}
.qs-tel .mh-tel-i{color:currentColor}

/* The grouped input rule above uses the padding shorthand, which wipes the
   40px right padding the base select rule set aside for the chevron. The
   option text then runs under the arrow and it reads as half cut off.
   Put the room back, and clip rather than collide if a label is long. */
.quote-form .wpforms-container select{
  padding-right:42px!important;
  text-overflow:ellipsis}

/* WPForms locks a fixed height on inputs and selects:
     div.wpforms-container-full select{height:var(--wpforms-field-size-input-height)}
   and its stylesheet loads AFTER this file. Our 14px padding then needs more
   room than that height allows, so the text overflowed the bottom edge and the
   field looked cut in half. Let padding and line-height set the height instead.
   WPForms does not use !important there, so this wins on cascade order too. */
.wpforms-container input[type=text],
.wpforms-container input[type=email],
.wpforms-container input[type=tel],
.wpforms-container input[type=url],
.wpforms-container input[type=number],
.wpforms-container select{height:auto!important;line-height:1.4!important}

/* The black wipe stops before the picture instead of sweeping behind it, so
   the image keeps the paper ground and reads as a separate object that pops
   forward on hover. The right inset is the width of everything to the right
   of the text: padding, arrow, gap, picture, gap. These four values MUST
   match the card padding and gap set on the container in Elementor. */
/* stacked on mobile there is no side column, so the wipe fills the tile */

/* BLOG TILE POLISH ----------------------------------------------------
   A red hairline marks where the black band meets the artwork, so the two
   halves read as one designed object rather than two blocks that happen to
   touch. It draws itself as the wipe lands. */
/* the arrow sits over the artwork once it fills, so it takes the ink colour */

/* PRICE CARD EDGES ----------------------------------------------------
   Lines belong to the cards, not the grid: the grid carries the page
   gutter as padding, so a background or border on it bled into the margins
   and showed as grey bands outside the cards. */
.lfra-pricecard{border-top:1px solid var(--hair);
  border-bottom:1px solid var(--hair)}
@media(min-width:900px){
  .lfra-pricecard + .lfra-pricecard{border-left:1px solid var(--hair)}
}
/* the card is in the display:block list at (0,0,3,1), so matching that
   specificity is what lets it be a column and push the note to the foot */
body.elementor-page .lfra-pricecard.e-con{display:flex;flex-direction:column}
body.elementor-page .lfra-pricerows.e-con{flex:1 0 auto}
.price-foot{margin-top:auto}

/* BLOG TILES -----------------------------------------------------------
   Two to a row: narrower and taller than the old full-width strips. The
   picture sits on top at its own 2:1 ratio, so the frame and the artwork
   match exactly and nothing is ever cropped or scaled.

   The whole tile lifts slowly on hover. Only transform, shadow and colour
   move, so no card ever shifts its neighbours. */

/* picture first, full width, flush to three edges */

/* the lift */

/* red rule draws across the foot of the picture as the tile lifts */

/* TILE MOTION ---------------------------------------------------------
   The tiles tilt in 3D the way the specimen card on the home page does, so
   the motion belongs to this site rather than being a stock card effect.
   The list carries the perspective; without it the rotation reads flat. */
:root{--ease-pop:cubic-bezier(.2,.9,.28,1.28)}

/* the numeral swings and grows */

/* the arrow swings up to point out of the tile */

/* the picture tips the other way, very slightly, so the layers separate */

/* TILE SWING ----------------------------------------------------------
   A transition can only travel from A to B. To rotate and then settle back
   the motion has to be a keyframe animation, so the card swings past its
   resting angle and returns - that overshoot is what makes it feel physical. */

@keyframes tileSwing{
  0%{transform:translateY(0) rotateX(0) rotateY(0) scale(1)}
  38%{transform:translateY(-14px) rotateX(5.5deg) rotateY(-7deg) scale(1.025)}
  68%{transform:translateY(-6px) rotateX(1.2deg) rotateY(3.2deg) scale(1.008)}
  86%{transform:translateY(-10px) rotateX(3.4deg) rotateY(-1.2deg) scale(1.016)}
  100%{transform:translateY(-8px) rotateX(2.6deg) rotateY(0) scale(1.013)}
}

/* and they rotate into place as they scroll in, staggered down the grid */
/* Each tile swings in on its own hinge - odd cards from the left edge, even
   cards from the right - then settles square. The nth-child delays stagger
   them without relying on the --i the script sets, so the sequence runs
   whether or not that lands. */

/* CARD SWING-IN -------------------------------------------------------
   Hung off .rvl, the class the script actually puts on each card, rather
   than html.js-motion - that gets stripped if the script does not flag
   itself as booted, and the rotation silently fell back to a 15px fade.
   .bcard.rvl is (0,0,2,0) so it outranks the plain .rvl rule. */

/* overflow:hidden forces transform-style back to flat, which flattens the
   depth the picture needs, so the card clips with a radius instead */


/* BLOG TILES - single source of truth ----------------------------------
   Everything for the tile lives here and nowhere else. Fifteen rounds of
   patching had left sixty-nine overlapping rules, five of them competing
   hover transforms, which is why changes stopped behaving predictably.

   Layout: two to a row, picture on top at its own 2:1 ratio so it is never
   cropped, then number, kicker, title, description, arrow.
   Hover: the whole card spins a full turn and settles. */

/* Tile tokens. The picture's bleed margin is built from these; with them
   undefined that margin is invalid at computed-value time and dropped,
   which is why the artwork stopped reaching the card edges. */
.bcard{--bc-padx:clamp(20px,2.2vw,30px);--bc-pady:clamp(22px,2.4vw,32px)}

body.elementor-page .blist.e-con{display:grid;
  grid-template-columns:minmax(0,1fr);
  perspective:1600px;perspective-origin:50% 45%;border-top:none}
@media(min-width:760px){
  body.elementor-page .blist.e-con{grid-template-columns:repeat(2,minmax(0,1fr))}
}

body.elementor-page .bcard.e-con{display:grid;
  grid-template-columns:minmax(0,1fr);align-content:start}
.bcard{position:relative;overflow:hidden;
  background:var(--surface);border:none;border-radius:6px;
  box-shadow:0 1px 2px rgba(20,19,16,.05),
    0 12px 26px -20px rgba(20,19,16,.30);
  transition:transform .45s var(--ease),box-shadow .45s var(--ease)}
  transition:background .4s var(--ease),border-color .4s var(--ease),
    box-shadow .4s var(--ease)}

/* picture: first, full width, flush to three edges, exact 2:1 */
.bc-img{order:1;width:100%;display:block;
  position:relative;overflow:hidden;
  margin:calc(-1 * var(--bc-pady,24px)) calc(-1 * var(--bc-padx,22px))
         clamp(16px,1.8vw,22px) calc(-1 * var(--bc-padx,22px))}
.bc-img img{display:block;width:100%;height:auto;
  background:var(--paper);
  transition:transform .8s var(--ease)}
.bcard:hover .bc-img img,.bcard:focus-within .bc-img img{transform:scale(1.045)}

.bc-n{order:2;line-height:1;margin-bottom:clamp(6px,.7vw,10px)}
.bc-mid{order:3;min-width:0}
.bc-k{color:var(--ink-3);margin-bottom:9px}
.bc-t{font-size:clamp(19px,1.9vw,26px);line-height:1.16;margin-bottom:9px}
.bc-t a{color:inherit}
.bc-t a::after{content:"";position:absolute;inset:0;z-index:4}
.bc-mid p{font-size:15.5px;line-height:1.6;color:var(--ink-2)}
.bc-ar{order:4;justify-self:end;
  transition:transform .4s var(--ease),color .3s var(--ease)}

/* the full turn */
}
body.elementor-page .bcard.e-con:hover,
body.elementor-page .bcard.e-con:focus-within{
  transform:translateY(-6px);
  box-shadow:0 2px 4px rgba(20,19,16,.06),
    0 28px 50px -28px rgba(20,19,16,.42);z-index:2}
.bcard:hover .bc-n,.bcard:focus-within .bc-n{color:var(--red)}
.bcard:hover .bc-k,.bcard:focus-within .bc-k{color:var(--red)}
.bcard:hover .bc-ar,.bcard:focus-within .bc-ar{
  color:var(--red);transform:translate(5px,-4px) rotate(-45deg)}

/* and they turn into place as they scroll in, alternating hinges */
.bcard.rvl{opacity:0;transform-origin:left center;
  transform:perspective(1100px) rotateY(-38deg) translate3d(-40px,26px,-70px) scale(.94)}
.blist .bcard.rvl:nth-child(even){transform-origin:right center;
  transform:perspective(1100px) rotateY(38deg) translate3d(40px,26px,-70px) scale(.94)}
.bcard.rvl.seen{opacity:1;transform:none;
  transition:opacity .6s var(--ease),transform 1.05s var(--ease-pop)}
.blist .bcard.rvl:nth-child(2).seen{transition-delay:140ms}
.blist .bcard.rvl:nth-child(3).seen{transition-delay:280ms}
.blist .bcard.rvl:nth-child(4).seen{transition-delay:420ms}

@media(prefers-reduced-motion:reduce){
  /* the flip is a deliberate, single, user-initiated motion, so it stays;
     the scroll-in rotation is the one that is withheld */
  .bcard.rvl{opacity:1;transform:none}
}




/* TABLE OF CONTENTS ---------------------------------------------------
   A sticky rail to the left of the article, built by site.js from the h2s.
   Stacked above the copy on narrower screens, where there is no room for a
   sidebar. The picture spans both columns so it keeps its full width. */

.toc{margin:0 0 clamp(26px,2.8vw,38px)}
.toc-h{font-family:var(--sans);font-weight:700;text-transform:uppercase;
  font-size:clamp(11px,.88vw,12.5px);letter-spacing:.185em;
  color:var(--ink-3);margin-bottom:clamp(12px,1.3vw,16px)}
.toc ol{list-style:none;margin:0;padding:0;display:grid;gap:0;
  border-left:1px solid var(--hair-2)}
.toc li{position:relative;padding:clamp(7px,.8vw,10px) 0
  clamp(7px,.8vw,10px) clamp(14px,1.4vw,20px)}
.toc li::before{content:"";position:absolute;left:-1px;top:0;bottom:0;
  width:2px;background:var(--red);
  transform:scaleY(0);transform-origin:center;
  transition:transform .35s var(--ease)}
.toc li.is-active::before{transform:scaleY(1)}
.toc a{display:block;font-size:15px;line-height:1.45;color:var(--ink-3);
  transition:color .25s var(--ease)}
.toc a:hover{color:var(--ink-2)}
.toc li.is-active a{color:var(--ink);font-weight:600}

@media(min-width:1040px){
  body.elementor-page .prose.e-con{display:grid;
    grid-template-columns:clamp(196px,19vw,252px) minmax(0,1fr);
    column-gap:clamp(34px,3.8vw,68px);align-items:start}
  .post-hero{grid-column:1/-1;max-width:none;
    margin:0 0 clamp(40px,4.4vw,68px)}
  .toc{grid-column:1;position:sticky;
    top:calc(var(--mh) + clamp(18px,2vw,30px));margin:0}
  .prose-in{grid-column:2;margin:0;max-width:none}
  .policy .prose-in{max-width:none}
}
/* the masthead is fixed, so an anchor must stop below it */
.prose-in h2{scroll-margin-top:calc(var(--mh) + clamp(16px,2vw,28px))}


/* HERO SPACING --------------------------------------------------------
   body.elementor-page .elementor-widget:not(:last-child) zeroes every
   widget margin at (0,0,3,1). The hero is an Image widget, so a plain
   .post-hero rule at (0,0,1,0) loses and the first paragraph ends up
   flush against the picture. Match the specificity to win it back. */
body.elementor-page .post-hero.elementor-widget{
  margin-block-end:clamp(40px,4.4vw,68px)}
@media(max-width:1039px){
  body.elementor-page .post-hero.elementor-widget{
    margin-block-end:clamp(34px,3.8vw,56px)}
}


/* CARD IMAGE SPACING --------------------------------------------------
   .elementor-widget:not(:last-child) zeroes widget margins at (0,0,3,1),
   which flattens the gap between the picture and the copy below it. */
body.elementor-page .bc-img.elementor-widget{
  margin-block-end:clamp(18px,2vw,26px)}

@media print{
  .masthead,.dock,.worm,.cta,.skip{display:none!important}
  body{background:#fff;color:#000;font-size:11pt}
  .e-con.e-con-full.sec,.e-con.e-con-full.hero,
  .e-con.e-con-full.phero,.e-con.e-con-full.prose{padding:12pt 0}
  .foot{background:#fff;color:#000}
  .prose-in a::after{content:" (" attr(href) ")";font-size:9pt;color:#666}
}
