/* ============================================================
   00 — FONTS
   Season Mix (Displaay) · GT Era Text + GT Canon (Grilli Type)
   The @font-face descriptors below override each file's internal
   metadata. GT Canon's real family name is "GT Canon L Medium" and
   Season Mix SemiBold is its own family — declaring them as below
   unifies both correctly. Do not "fix" these names.
   ============================================================ */
@font-face{font-family:"Season Mix";src:url("/assets/fonts/SeasonMix-Regular.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Season Mix";src:url("/assets/fonts/SeasonMix-SemiBold.woff2") format("woff2");
  font-weight:600;font-style:normal;font-display:swap}
@font-face{font-family:"GT Era Text";src:url("/assets/fonts/GT-Era-Text-Regular.woff2") format("woff2");
  font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"GT Era Text";src:url("/assets/fonts/GT-Era-Text-Bold.woff2") format("woff2");
  font-weight:700;font-style:normal;font-display:swap}
@font-face{font-family:"GT Canon";src:url("/assets/fonts/GT-Canon-L-Standard-Medium-Italic.woff2") format("woff2");
  font-weight:500;font-style:italic;font-display:swap}

/* ============================================================
   01 — TOKENS
   ============================================================ */
:root{
  --graphite:#232323;
  --ocean:#006f81;
  --seaglass:#c3e3d6;
  --sand:#c8aa6e;
  --stone:#f2f0e7;
  --ivory:#fffffa;
  /* one sanctioned tonal step of Graphite — the footer (§7) and the hero panel.
     Not a seventh brand colour; do not use it as a section ground. */
  --graphite-deep:#1b1b1b;

  /* derived — hairlines only, never fills */
  --line-dark:rgba(35,35,35,.18);
  --line-gold:rgba(200,170,110,.34);
  --line-light:rgba(255,255,250,.20);

  --maxw:1440px;
  --gutter:clamp(20px,5vw,72px);
  --ease:cubic-bezier(.22,1,.36,1);

  --f-display:"Season Mix","Newsreader",Georgia,serif;
  --f-text:"GT Era Text","Inter",-apple-system,BlinkMacSystemFont,sans-serif;
  --f-detail:"GT Canon","Playfair Display",Georgia,serif;

  --t-h1:clamp(2.2rem,4.1vw,3.6rem);       /* TIER 1 section headlines — 5, 10, 13 */
  --t-h1-hero:clamp(2.1rem,5.6vw,5rem);    /* hero only — the page's one 80px moment */
  --t-h1-sm:clamp(1.85rem,3.15vw,2.8rem);  /* TIER 2 section headlines */
  --t-pull:clamp(1.5rem,2.45vw,2.15rem);   /* closing statements and pull quotes */
  --t-h2:clamp(1.35rem,2.2vw,1.85rem);
  --t-h3:clamp(1.5rem,2.6vw,2.1rem);
  --t-lead:clamp(1.05rem,1.5vw,1.3rem);
  --t-body:clamp(1rem,1.15vw,1.075rem);
  --t-small:.875rem;
  --t-eyebrow:.78rem;
  --t-stat:clamp(2.5rem,5.4vw,4.35rem);

  --dur-int:.3s;   /* interaction — measured on the reference set */
  --dur-rev:.6s;   /* scroll reveal */
  --dur-draw:1.6s; /* line draw */
}

/* ============================================================
   02 — RESET
   ============================================================ */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;
  /* the nav is fixed, so an anchor jump put the target heading underneath it --
     measured 89px of nav on mobile, 109px on desktop */
  scroll-padding-top:clamp(104px,9vw,136px)}
body{margin:0;background:var(--graphite);color:var(--ivory);
  font-family:var(--f-text);font-size:var(--t-body);line-height:1.65;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow-x:hidden}
img,svg,video{display:block;max-width:100%}
img{height:auto}
h1,h2,h3,h4,h5,p,figure,blockquote{margin:0}
ul,ol{margin:0;padding:0;list-style:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
a{color:inherit}
/* Focus has to clear 3:1 against whatever it sits on (WCAG 2.2 focus
   appearance). Measured: Sand on Ivory is only 2.20:1, so the default is
   Ocean for light grounds and Sea Glass for dark -- 5.85:1 and 11.5:1.
   Sand was failing on both light grounds AND on Ocean, at 2.65:1. */
:focus-visible{outline:2px solid var(--ocean);outline-offset:3px}
.on-graphite :focus-visible,.on-ocean :focus-visible,
.nav :focus-visible,.modal :focus-visible{outline-color:var(--seaglass)}
.skip{position:absolute;left:-9999px;top:0;z-index:200;background:var(--sand);color:var(--graphite);
  padding:12px 20px;font-weight:700}
.skip:focus{left:var(--gutter);top:12px}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ============================================================
   03 — LAYOUT PRIMITIVES
   ============================================================ */
.wrap{max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gutter)}
.pad{padding-block:clamp(76px,8.8vw,138px)}
.pad-sm{padding-block:clamp(64px,7vw,112px)}
.grid12{display:grid;grid-template-columns:repeat(12,1fr);gap:clamp(16px,2vw,32px)}
.sect{position:relative;isolation:isolate}

/* ---- section grounds. each carries its own line + accent tokens ---- */
.on-graphite{background:var(--graphite);color:var(--ivory);
  --fg:var(--ivory);--accent:var(--sand);--line:var(--line-gold);--soft:rgba(255,255,250,.82);--faint:rgba(255,255,250,.62)}
.on-ivory{background:var(--ivory);color:var(--graphite);
  --fg:var(--graphite);--accent:var(--ocean);--line:var(--line-dark);--soft:rgba(35,35,35,.78);--faint:rgba(35,35,35,.68)}
.on-stone{background:var(--stone);color:var(--graphite);
  --fg:var(--graphite);--accent:var(--ocean);--line:var(--line-dark);--soft:rgba(35,35,35,.78);--faint:rgba(35,35,35,.68)}
.on-ocean{background:var(--ocean);color:var(--ivory);
  --fg:var(--ivory);--accent:var(--seaglass);--line:var(--line-light);--soft:rgba(255,255,250,.84);--faint:rgba(255,255,250,.64)}
.on-seaglass{background:var(--seaglass);color:var(--graphite);
  --fg:var(--graphite);--accent:var(--ocean);--line:var(--line-dark);--soft:rgba(35,35,35,.78);--faint:rgba(35,35,35,.68)}

/* ---- texture. generated grain, NOT a gradient. §3 sanctions this. ---- */
.tex::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:300px 300px;opacity:.2;mix-blend-mode:multiply}
.on-ivory.tex::after,.on-stone.tex::after,.on-seaglass.tex::after{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-image:url("/assets/img/tex-grain-light.webp");
  background-size:46% auto;opacity:.42;mix-blend-mode:overlay}
.on-stone.tex::after{opacity:.36}
.on-seaglass.tex::after{opacity:.3}
/* Surface tooth on dark grounds. Held at the treatment Jacob had already
   signed off — the synthesised replacement is backed out pending a new
   direction. Britt's smoothed-patch note is still open against these tiles. */
.on-graphite.tex::before,.on-ocean.tex::before{
  background-image:url("/assets/img/tex-grain-dark.webp");
  background-size:52% auto;opacity:.5;mix-blend-mode:overlay}
/* a whisper of Sand in the grain so the dark grounds read warm, not neutral */
.on-graphite.tex::after{opacity:.045}
/* A second grain layer tinted Sand, masked not painted — uniform noise, no
   directional ramp, so it reads as material rather than as a gradient. */
.on-graphite.tex::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-color:var(--sand);opacity:.07;
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='340' height='340'%3E%3Cfilter id='m'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='340' height='340' filter='url(%23m)'/%3E%3C/svg%3E");
  mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='340' height='340'%3E%3Cfilter id='m'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='340' height='340' filter='url(%23m)'/%3E%3C/svg%3E");
  -webkit-mask-size:340px 340px;mask-size:340px 340px}

/* ============================================================
   04 — TYPE SYSTEM (brand hierarchy §5.3)
   ============================================================ */
.eyebrow{font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:var(--t-eyebrow);line-height:1.2;color:var(--accent);margin:0}
/* 17 Sep, Britt: "I think with the eyebrow, we standardize on the line length...
   not the copy length, the line length after it." She was right that they
   differed: the rule was flex:1 up to a 160px cap, so it took whatever space
   the container had left and came out shorter wherever the copy ran long or
   the column was narrow. It is now one fixed length everywhere.
   It also thickens to 2px, per Jacob: "if the font itself is bold, then the
   line could probably match that same width." */
.eyebrow--rule{display:flex;align-items:center;gap:16px}
.eyebrow--rule::after{content:"";flex:0 0 auto;width:96px;height:2px;
  background:var(--line);max-width:none}

.h1{font-family:var(--f-display);font-weight:400;font-size:var(--t-h1);
  line-height:1.04;letter-spacing:.01em;max-width:20ch}
/* Tier 2 sections (§7 polish tiers): 4 Problem, 6 Benefits, 7 How, 8 Docket,
   9 Outcome, 11 Methodology, 12 FAQ. Tier 1 keeps --t-h1. */
.h1.t2{font-size:var(--t-h1-sm);line-height:1.06}
/* .stack — the copy is written as deliberate lines; let the <br> govern, not the measure */
.h1.stack{max-width:none}
.h1-sm{font-family:var(--f-display);font-weight:400;font-size:var(--t-h1-sm);
  line-height:1.05;letter-spacing:.01em;max-width:20ch}
.h2{font-family:var(--f-text);font-weight:700;font-size:var(--t-h2);
  line-height:1.2;letter-spacing:-.025em}
.h3{font-family:var(--f-display);font-weight:400;font-size:var(--t-h3);
  line-height:1.05;letter-spacing:.01em}
.h4{font-family:var(--f-display);font-weight:600;text-transform:uppercase;
  letter-spacing:.1em;line-height:.95}
.h5{font-family:var(--f-detail);font-weight:500;font-style:italic;letter-spacing:.025em;line-height:1.5}
.body{font-size:var(--t-body);line-height:1.65;max-width:68ch;color:var(--soft)}
.lead{font-size:var(--t-lead);line-height:1.55;max-width:56ch;color:var(--soft)}
strong,b{font-weight:700}

/* ============================================================
   05 — COMPONENTS
   ============================================================ */
.btn{display:inline-flex;align-items:center;gap:.6em;font-family:var(--f-text);font-weight:700;
  text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;line-height:1;
  padding:18px 32px;border-radius:2px;text-decoration:none;min-height:48px;
  transition:background var(--dur-int) var(--ease),color var(--dur-int) var(--ease),
             border-color var(--dur-int) var(--ease),transform var(--dur-int) var(--ease)}
.btn .ar{transition:transform var(--dur-int) var(--ease)}
.btn:hover .ar{transform:translateX(4px)}
.btn-primary{background:var(--sand);color:var(--graphite)}
.btn-primary:hover{background:var(--ivory)}
.on-ivory .btn-primary:hover,.on-stone .btn-primary:hover,.on-seaglass .btn-primary:hover{background:var(--graphite);color:var(--ivory)}
.btn-secondary{background:transparent;color:var(--sand);border:1px solid var(--sand)}
.btn-secondary:hover{background:var(--sand);color:var(--graphite)}
.on-ocean .btn-secondary{color:var(--ivory);border-color:var(--ivory)}
.on-ocean .btn-secondary:hover{background:var(--ivory);color:var(--ocean)}

.link-arrow{display:inline-flex;align-items:center;gap:.5em;text-decoration:underline;
  text-underline-offset:4px;text-decoration-thickness:1px;font-size:var(--t-body);
  color:var(--fg);background:none;padding:11px 0;min-height:44px}
.link-arrow .ar{transition:transform var(--dur-int) var(--ease)}
.link-arrow:hover .ar{transform:translateX(4px)}
.link-arrow.down:hover .ar{transform:translateY(4px)}

.rule{height:1px;background:var(--line);border:0;margin:0;transform-origin:left center}
.rule-accent{background:var(--accent);opacity:.4}

/* Large outlined diamonds, cropped by the panel edge — the ornamental
   Moderate-tier mark from the brand guide, drawn 1px and left to run off. */
.dia-mark{position:absolute;pointer-events:none;z-index:0;
  width:clamp(150px,26%,290px);aspect-ratio:1;
  border:1px solid currentColor;opacity:.26}
.dia-mark.two{width:clamp(96px,17%,188px);opacity:.34}
/* anchored on the corner and centred there, so both crop to the same
   chevron and sit concentric rather than overlapping at random */
.dia-mark.tr{top:0;right:0;transform:translate(50%,-50%) rotate(45deg)}
.dia-mark.br{bottom:0;right:0;transform:translate(50%,50%) rotate(45deg)}
.dia-mark.bl{bottom:0;left:0;transform:translate(-50%,50%) rotate(45deg)}
.js .dia-mark{opacity:0}
.js .dia-mark.tr{transform:translate(50%,-50%) rotate(45deg) scale(.9)}
.js .dia-mark.br{transform:translate(50%,50%) rotate(45deg) scale(.9)}
.js .dia-mark.bl{transform:translate(-50%,50%) rotate(45deg) scale(.9)}
.js .dia-mark{transition:opacity .9s var(--ease),transform .9s var(--ease)}
.js .in .dia-mark.tr,.js .dia-mark.tr.in{opacity:.26;transform:translate(50%,-50%) rotate(45deg) scale(1)}
.js .in .dia-mark.br,.js .dia-mark.br.in{opacity:.26;transform:translate(50%,50%) rotate(45deg) scale(1)}
.js .in .dia-mark.bl,.js .dia-mark.bl.in{opacity:.26;transform:translate(-50%,50%) rotate(45deg) scale(1)}
.js .in .dia-mark.two,.js .dia-mark.two.in{opacity:.34}

/* moderate tier — 1px frame with diamond corner accents */
.frame{position:relative;border:1px solid var(--line);padding:clamp(28px,4vw,56px)}
.frame::before,.frame::after,.frame>.dm::before,.frame>.dm::after{
  content:"";position:absolute;width:5px;height:5px;background:var(--accent);
  transform:rotate(45deg);opacity:.85}
.frame::before{top:-3px;left:-3px}
.frame::after{top:-3px;right:-3px}
.frame>.dm::before{bottom:-3px;left:-3px}
.frame>.dm::after{bottom:-3px;right:-3px}

 /* %, "days" and + are units, not numerals — one subordinate size for all three
    so the four figures read off a common baseline */
.stat-label{font-size:var(--t-small);line-height:1.5;color:var(--faint);max-width:26ch;margin-top:14px}

.dash-list li{position:relative;padding-left:26px;margin-block:10px;color:var(--soft)}
.dash-list li::before{content:"";position:absolute;left:0;top:.72em;width:14px;height:1px;background:var(--fg);opacity:.5}

/* ============================================================
   06 — MOTION
   ============================================================ */
.js .reveal{opacity:0;transform:translateY(18px);
  transition:opacity var(--dur-rev) var(--ease),transform var(--dur-rev) var(--ease)}
.js .reveal.in{opacity:1;transform:none}
.js .reveal-stagger>*{opacity:0;transform:translateY(18px);
  transition:opacity var(--dur-rev) var(--ease),transform var(--dur-rev) var(--ease);
  transition-delay:calc(var(--i,0) * 70ms)}
.js .reveal-stagger.in>*{opacity:1;transform:none}

.js .line-draw [data-draw]{stroke-dasharray:var(--len);stroke-dashoffset:var(--len);
  transition:stroke-dashoffset var(--dur-draw) var(--ease);
  transition-delay:calc(var(--d,0) * 1ms)}
.js .line-draw.in [data-draw]{stroke-dashoffset:0}
.js .pop{opacity:0;transform:scale(.4);transform-box:fill-box;transform-origin:center;
  transition:opacity .5s var(--ease),transform .5s var(--ease);
  transition-delay:calc(var(--d,0) * 1ms)}
.js .line-draw.in .pop{opacity:1;transform:scale(1)}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;transition-delay:0ms!important}
  .reveal,.reveal-stagger>*{opacity:1!important;transform:none!important}
  .js .line-draw [data-draw]{stroke-dashoffset:0!important}
  .pop{opacity:1!important;transform:scale(1)!important}
  .parallax{transform:none!important}
}


/* ============================================================
   SECTION 01 — NAVIGATION
   ============================================================ */
.nav{position:fixed;top:0;left:0;right:0;z-index:100;background:transparent;
  border-bottom:1px solid transparent;
  transition:background var(--dur-int) var(--ease),border-color var(--dur-int) var(--ease)}
.nav.stuck{background:var(--graphite);border-bottom-color:var(--line-light)}
/* the nav CTA yields to any other Schedule a Consult that is on screen */
.nav .btn{transition:opacity .32s var(--ease),transform .32s var(--ease),
  visibility 0s linear 0s}
.nav .btn.stand-down{opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .32s var(--ease),transform .32s var(--ease),
    visibility 0s linear .32s}
.nav-in{display:flex;align-items:center;justify-content:space-between;gap:24px;
  padding-block:clamp(20px,2.4vw,30px)}
/* Aaron: all-white read a little basic. Custom properties inherit into a
   <use> shadow tree where class selectors cannot, so the mark takes Sand and
   the wordmark stays Ivory. */
.nav-logo{--mark-fill:var(--sand);
  display:flex;align-items:center;color:var(--ivory);width:clamp(172px,17.5vw,248px);
  min-height:44px}
.nav-logo svg{width:100%;height:auto}
.nav .btn{padding:14px 26px}
.nav-btn-short{display:none}

/* ============================================================
   SECTION 02 — HERO
   ============================================================ */
.hero{min-height:min(92vh,940px);min-height:min(92svh,940px);display:flex;align-items:center;
  padding-block:clamp(124px,14vh,168px) clamp(72px,8vw,112px);position:relative;overflow:hidden}
.hero-grid{align-items:center;row-gap:clamp(56px,7vw,88px)}
.hero-copy{grid-column:1/8}
.hero-eyebrow{margin-bottom:clamp(26px,3vw,38px)}
.hero h1{font-family:var(--f-display);font-weight:400;font-size:var(--t-h1-hero);
  line-height:1.04;letter-spacing:.01em;max-width:none;color:var(--ivory);margin:0}
/* three deliberate lines — the copy is written as a stack, not a paragraph */
.hero h1 span{display:block;white-space:nowrap}
@media (max-width:430px){.hero h1 span{white-space:normal}}
.hero-sub{margin-top:clamp(28px,3.2vw,40px);color:rgba(255,255,250,.82);max-width:54ch}
.hero-cta{display:flex;flex-wrap:wrap;align-items:center;gap:clamp(20px,2.4vw,32px);
  margin-top:clamp(36px,4vw,52px)}

/* the arch — complex-tier linework. one of three on the page. */
.hero-art{grid-column:8/13;position:relative;align-self:stretch;min-height:clamp(340px,42vw,560px)}
/* The one sanctioned product moment -- Britt: "there is a place to somewhere
   show that this is a real product... maybe one instance on this webpage."
   A sibling of .arch-panel, not a child, because the panel clips its own
   children; overhanging both edges is what stops it reading as a thumbnail. */
.arch-panel{position:relative;background:var(--graphite-deep);border:1px solid var(--line-gold);overflow:hidden}
/* Photographic ground sits under the linework at a flat opacity — never a scrim.
   The poster is painted on the container, so if the video is removed under
   reduced-motion the frame still shows. That container background is why the
   homepage kept showing a strip of the /mass-tort corridor under its own plate:
   the <picture> does not fill the box on its own. Both are set below. */
.arch-photo{position:absolute;inset:0;opacity:.5;
  background:url("/assets/img/arch-arcade.jpg") center/cover no-repeat}
.arch-photo video{width:100%;height:100%;object-fit:cover;display:block}
/* 17 Sep: the panel used to hold a video, which filled the box by the rule
   above. Now it holds a still, and a picture that is not told to fill lets the
   container background show through as a band across the foot of the frame. */
.arch-photo picture,.arch-photo img{display:block;width:100%;height:100%;object-fit:cover}
/* anchored to the foot of the panel so the uprights actually reach it --
   centring left them stopping short about two thirds down */
.arch-svg{position:absolute;left:50%;bottom:0;transform:translateX(-50%);
  width:118%;height:auto;color:var(--sand)}
.arch-svg [data-draw]{stroke:currentColor;stroke-width:1;fill:none;vector-effect:non-scaling-stroke}
.arch-svg .faint{opacity:.34}
.arch-svg .dm{fill:var(--sand);stroke:none}

/* the "improved logo legibility square" — solid quiet panel over the busier ground */
/* The figure is a full-height plane sharing an edge with the arches loop —
   the two are one composition, not a photo stuck on top of another. */
.hero-art{display:grid;grid-template-columns:38fr 62fr}
.hero-figure{position:relative;overflow:hidden;background:var(--graphite-deep);
  border:1px solid var(--line-gold);border-right:0;margin:0}
.hero-figure img{width:100%;height:100%;object-fit:cover;display:block;opacity:.92}
.legibility{position:absolute;left:0;right:clamp(60px,14%,150px);bottom:0;
  background:var(--ivory);color:var(--graphite);
  padding:clamp(20px,2.2vw,28px) clamp(22px,2.4vw,32px);z-index:4}
.legibility .mark{width:34px;color:var(--ocean);margin-bottom:16px}
.legibility .lab{font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:var(--t-eyebrow);color:var(--ocean)}
.legibility .det{font-size:.79rem;line-height:1.5;color:rgba(35,35,35,.70);margin-top:9px}

/* ============================================================
   SECTION 03 — PROOF STRIP
   ============================================================ */
/* The stats are gone with Britt's rewrite; the firm logos stay, so what was
   the proof strip is now just the trust strip. */
.trust{padding-block:clamp(44px,5vw,72px)}
.firms{margin-top:0}
.firms-lab{font-family:var(--f-text);font-weight:700;text-transform:uppercase;letter-spacing:.05em;
  font-size:var(--t-eyebrow);color:rgba(35,35,35,.64);margin-bottom:clamp(30px,3.4vw,44px)}
/* Aaron: the strip felt static. Two rows drifting opposite directions, tied to
   scroll position rather than a timer -- it moves as you scroll and stops when
   you do. The container clips so the drift can never make the page scroll. */
.firms{overflow:hidden}
/* Britt asked twice for the label to line up with the first logo. The row was
   centred, which left the marks inset from the wrap edge while the label sat
   on it. Span the row edge to edge instead; the clip box below widens so the
   drift still has room to travel. */
.firm-row{display:flex;flex-wrap:nowrap;justify-content:space-between;align-items:center;
  list-style:none;margin:0;padding:0;
  gap:clamp(24px,2.8vw,44px);
  will-change:transform}
.firm-row+.firm-row{margin-top:clamp(28px,3.6vw,52px)}
.js .firm-row{transform:translate3d(var(--drift,0px),0,0)}
/* Seven abreast only fits from here up. Below it the rows wrap like an
   ordinary grid and the drift stands down -- translating a wrapped row would
   just push half the marks off the side. */
/* 12 Oct, Jacob: "See if we can get some animation on the Trusted by PI Firms.
   It's just static right now", and the same for /mass-tort. This block used to
   wrap the rows into a static grid below 900. The marquee runs at every width
   now -- see the keyframe block below, which lost its min-width gate. */
/* The row now touches both wrap edges, so the drift (max 46px either way) had
   nowhere to travel without the clip shaving the two end marks. Inset the row
   by a hair over that and move the label in with it, so they stay flush with
   each other and nothing gets clipped. Pushing the clip box outside the wrap
   instead overflowed the viewport at 900. */
/* Between 900 and 1100 the seven cells plus gaps already fill the wrap, so
   there is no room for a 48px inset and the drift would shave the end marks.
   Stand the drift down there instead: with no drift no inset is needed, and
   space-between puts the first mark on the wrap edge where the label already
   sits, so they line up either way. */
@media (min-width:900px) and (max-width:1099px){
  .js .firm-row{transform:none}
}
@media (min-width:1100px){
  .firm-row{padding-inline:48px}
  .firms-lab{padding-left:48px}
}
/* Cells are a fixed width with the mark centred inside, so each row's apparent
   left edge moved with whatever logo happened to lead it. Pin the end cells
   outward and both rows read flush with the label and with each other. */
@media (min-width:900px){
  .firm-row .firm:first-child{justify-content:flex-start}
  .firm-row .firm:last-child{justify-content:flex-end}
}
.firm{flex:0 0 auto;width:clamp(88px,9.5%,122px);
  display:flex;align-items:center;justify-content:center;height:44px}
/* REMOVED 12 Oct. This was Jacob on 24 Aug: "the drift never reads at that
   size, so stop pretending -- just list them, stacked full width across",
   which made .firm-row a four-column GRID below 899px.

   He reversed that on 12 Oct -- "see if we can get some animation on the
   Trusted by PI Firms" -- and this rule was the thing quietly defeating it.
   A grid auto-places into rows, so the marquee track wrapped into seven lines
   375px tall while reporting flex-wrap:nowrap, which is meaningless on a grid.
   Two attempts at the marquee looked broken because of it.

   Only found by reading computed display off the live row. The row said
   display:grid; every rule I had been writing assumed flex. */
/* optical normalisation — heavier marks sit smaller so none dominates the row */
.firm img[alt="Hicks Law Firm"]{max-height:76%}
.firm img[alt="Roden Law"]{max-height:78%}
.firm img[alt="Ellis"]{max-height:82%}
.firm img[alt="ACTS Law"]{max-height:80%}
.firm img[alt="Traut"]{max-height:74%}
.firm img[alt="Saeedian Law Group"]{max-height:88%}
.firm img[alt="Russell &amp; Lazarus"]{max-height:96%}
.firm img[alt="Gibson Hughes"]{max-height:94%}
.firm img[alt="WCTL"]{max-height:64%}
.firm img[alt="Bush &amp; Bush"]{max-height:36%}
.firm img[alt="Razavi Law Group"]{max-height:78%}
/* brightness(0) forced every opaque pixel to black, which silently destroyed
   any logo built on a knockout -- Aitken's TRIAL LAWYERS bar, Russell &
   Lazarus's RL monogram and Saeedian's SLG all collapsed into solid blocks.
   Grayscale alone keeps the internal luminance, so the letterforms survive. */
.firm img,.firm svg{max-height:100%;width:auto;object-fit:contain;
  filter:grayscale(1) opacity(.68);
  transition:filter var(--dur-int) var(--ease)}
.firm:hover img,.firm:hover svg{filter:grayscale(1) opacity(1)}
/* ACTS supplied a reversed (white) mark -- it needs inverting to read on Ivory,
   where every other logo is already dark on transparent. */
.firm img[alt="ACTS Law"]{filter:grayscale(1) invert(1) opacity(.68)}
.firm:hover img[alt="ACTS Law"]{filter:grayscale(1) invert(1) opacity(1)}
/* Traut and Gibson Hughes are light-weight marks with no dark ink at all --
   measured 2.99 and 3.45 against Ivory where the rest of the row sits near
   7.9. Neither is a knockout, so brightness is safe on them specifically. */
.firm img[alt="Traut"]{filter:grayscale(1) brightness(.62) opacity(.68)}
.firm:hover img[alt="Traut"]{filter:grayscale(1) brightness(.62) opacity(1)}
.firm img[alt="Gibson Hughes"]{filter:grayscale(1) brightness(.68) opacity(.68)}
.firm:hover img[alt="Gibson Hughes"]{filter:grayscale(1) brightness(.68) opacity(1)}

/* ============================================================
   SECTION 04 — PROBLEM
   ============================================================ */
/* Britt, 24 Aug: the subhead was stacking on itself. It sat in a 7-of-12
   column, which is a narrow measure for a 150-character sentence. The block
   takes 10 of 12 now and the headline is capped on its own, so the big line
   keeps its punch while the sentence runs long instead of deep. */
.prob-head{grid-column:1/11}
/* Britt, 24 Aug: "Exposure is not causation." on one line, mobile and desktop.
   The 16ch cap I added was what wrapped it -- measured, the line only needs
   40.2px of type at a 500px viewport and it was already set at 29.6px.
   nowrap guarantees it, and the size is tied to the viewport so the guarantee
   cannot turn into an overflow on a narrow phone: at 375 the line needs to
   stay under 29.9px; 7.4vw gives 27.8px, leaving room for the fallback face,
   which sets wider than Season Mix. Above tablet the clamp caps it
   long before the vw term matters. */
/* Wrapping is the DEFAULT here. This used to be white-space:nowrap for every
   page, to hold /mass-tort's "Exposure is not causation." on one line. That is
   a guarantee only a short headline can survive: it ran /about's origin line
   off the side of a phone (patched 8 Sep) and then did the same to Britt's
   "Stop letting demand work slow down your cases" on /demands, forcing a 628px
   grid track against a 390px viewport. Inverted 11 Sep -- nowrap is now opt-in,
   on the one page whose headline is short enough to take it. */
.prob-head .h1{max-width:none;font-size:min(var(--t-h1-sm),7.4vw);
  text-wrap:balance}
/* white-space is a SHORTHAND in CSS Text 4: it sets white-space-collapse AND
   text-wrap. Writing text-wrap after it in the same block silently undoes the
   nowrap half, which is how this shipped inert for a moment on 11 Sep. The
   shorthand alone is what overrides the text-wrap:balance set above. */
body[data-page="mass-tort"] .prob-head .h1{white-space:nowrap}
.prob-rows{margin-top:clamp(40px,4.6vw,72px)}
.prob-row{padding-block:clamp(34px,4vw,54px);border-top:1px solid var(--line);
  display:grid;grid-template-columns:repeat(12,1fr);gap:clamp(16px,2vw,32px);align-items:start}
.prob-row:last-child{border-bottom:1px solid var(--line)}
.prob-n{grid-column:1/4;font-family:var(--f-text);font-weight:700;
  text-transform:uppercase;letter-spacing:.05em;font-size:var(--t-eyebrow);
  /* Sand measures 2.06:1 on this ground -- the same failure already found on
     the focus ring. Ocean is the light-ground accent and is what the benefits
     numerals use, so the active label matches them. */
  line-height:1.4;color:var(--ocean);padding-top:.35em}
.prob-t{grid-column:4/8;font-size:clamp(1.18rem,1.7vw,1.48rem);line-height:1.25}
.prob-b{grid-column:8/13;color:var(--soft)}
/* The Sand bracket rides the scroll — it moves 01 -> 02 -> 03 as each row
   reaches the reading position. No pin: the page never stops moving. */
.prob-row{position:relative;padding-left:clamp(18px,2.2vw,32px);
  margin-left:calc(clamp(18px,2.2vw,32px) * -1)}
.prob-row::before{content:"";position:absolute;left:0;top:0;bottom:0;width:1px;
  background:var(--sand);opacity:0;transform:scaleY(.4);transform-origin:center}
.prob-row::after{content:"";position:absolute;left:-3px;top:calc(50% - 3px);
  width:7px;height:7px;background:var(--sand);transform:rotate(45deg) scale(.3);opacity:0}
.js .prob-row::before{transition:opacity .5s var(--ease),transform .5s var(--ease)}
.js .prob-row::after{transition:opacity .45s var(--ease),transform .45s var(--ease)}
.js .prob-row.active::before{opacity:.6;transform:scaleY(1)}
.js .prob-row.active::after{opacity:1;transform:rotate(45deg) scale(1)}
/* Aaron and Jacob both asked for the active card to move, not just recolour.
   Scaling the row would blur the type, so it lifts and gains breathing room
   instead -- same read, no resampling. */
.js .prob-row{transition:transform .55s var(--ease),padding .55s var(--ease),
  background-color .55s var(--ease)}
.js .prob-row.active{transform:translateX(clamp(6px,0.9vw,14px));
  background-color:rgba(255,255,250,.42)}
/* Hover is the desktop counterpart of the scroll-driven state -- on mobile the
   rows still pop as you scroll past. Gated on a real pointer so a touch device
   never gets a stuck hover. It grows outward through padding cancelled by an
   equal negative margin, so the row widens without reflowing the ones below. */
@media (hover:hover) and (pointer:fine){
  .js .prob-row{transition:transform .45s var(--ease),
    background-color .45s var(--ease),padding-inline .45s var(--ease),
    margin-inline .45s var(--ease)}
  .js .prob-rows:hover .prob-row:not(:hover){background-color:transparent}
  .js .prob-row:hover{
    background-color:rgba(255,255,250,.66);
    padding-inline:clamp(14px,1.6vw,26px);
    margin-inline:clamp(-26px,-1.6vw,-14px);
    transform:translateX(clamp(6px,0.9vw,14px))}
  .js .prob-row:hover .prob-n{color:var(--ocean)}
  /* the bracket and its diamond belong to hover too, not just to the
     scroll-driven state -- hovering a row that is not the active one used to
     tint it but leave the marker behind on whichever row the scroll had lit */
  .js .prob-row:hover::before{opacity:.6;transform:scaleY(1)}
  .js .prob-row:hover::after{opacity:1;transform:rotate(45deg) scale(1)}
}
.js .prob-row .prob-n{transition:color .5s var(--ease)}
/* .4 measured 2.35:1 -- this is the dim-the-text-to-signal-state trap again.
   The row already signals state with its bracket, diamond and background
   tint, so the label does not need to go unreadable to do it. Raised to
   clear 4.5 in the inactive state, which is the state most rows are in. */
.js .prob-row:not(.active) .prob-n{color:rgba(35,35,35,.68)}
/* no JS: every bracket shows, nothing is hidden */
.prob-row::before{opacity:.6;transform:scaleY(1)}
.prob-row::after{opacity:1;transform:rotate(45deg) scale(1)}
.js .prob-row::before{opacity:0;transform:scaleY(.4)}
.js .prob-row::after{opacity:0;transform:rotate(45deg) scale(.3)}
/* Aaron wanted this set as a quote, centred and larger. Jacob: centre the
   watermark with it. Both sit on one axis now and the statement is pulled up
   toward headline weight -- it is the last beat of the problem, so it should
   be the loudest thing in the section. */
.prob-close-row{position:relative;isolation:isolate;
  /* Britt, 24 Aug: too much vertical padding. Measured at 1440 it was 130px of
     margin plus 131px of air each side of the text -- 260px above the words.
     Trimmed by about a quarter, to 101 + 91. Jacob wanted it still breathing
     on mobile so it lands as a beat, and mobile is governed by its own rule
     below, which is untouched. */
  margin-top:clamp(72px,7vw,108px);
  display:flex;align-items:center;justify-content:center;
  min-height:clamp(260px,24vw,340px)}
/* markup #97, Britt: "Bring this text box a little wider. See if we can reduce
   to 3 lines instead of 4." Wider measure plus a slightly tighter size: at
   1440 the /mass-tort close now sets to three lines instead of four.
   #96: on phones the same line was running long, so the floor comes down. */
.prob-close{margin:0;max-width:min(100%,1120px);position:relative;z-index:1;
  text-align:center;text-wrap:balance;font-style:italic;
  font-size:clamp(1.35rem,2.85vw,2.5rem);line-height:1.24;letter-spacing:-.015em}
@media (max-width:640px){
  .prob-close{font-size:clamp(1.15rem,5vw,1.45rem);line-height:1.3}
}
/* Aaron: "let's throw it in quotes." Set as pseudo-elements so it is a
   treatment rather than copy -- it survives Britt's rewrite of the line. */
.prob-close::before{content:"\201C"}
.prob-close::after{content:"\201D"}
.prob-close strong{font-weight:400}
/* centred on the same axis as the words rather than tucked into a corner */
.prob-close-row .wm{position:absolute;z-index:0;pointer-events:none;
  inset:0;display:flex;align-items:center;justify-content:center}
.prob-close-row .wm svg{width:clamp(240px,34vw,470px);height:auto;
  color:rgba(0,111,129,.075)}
@media (max-width:900px){
  .prob-close-row{min-height:clamp(220px,44vw,320px)}
  .prob-close-row .wm svg{width:clamp(190px,50vw,300px)}
}

/* ============================================================
   SECTION 05 — CAUSATION ENGINE (pinned + pathway)
   ============================================================ */
.engine{overflow:clip}
.engine-head{grid-column:1/8}
.engine-lead{grid-column:8/13;color:rgba(255,255,250,.82);align-self:end}

/* 50/50: the product holds on the left while the three nodes scroll past on
   the right, threaded by one line that draws itself as you go. */
/* Both product frames sit inside the gutter -- neither runs to a screen edge.
   The visual takes a slightly larger share than the chain so the screens are
   not tiny, but this frame is still the smallest on the page. */
  /* Centring inside a 100svh box read well mid-section but left ~285px of dead
     space above the frame at the section start, and pushed the screen out of
     view exactly while node 01 was being read -- so the swap was invisible.
     A plain sticky offset clears the nav, starts flush, and keeps the screen
     on-stage the whole way down. */
  /* The arch stands on its own. It shared a row with the node column and the
   two competed; the arch lost. Now it is the whole width and the nodes follow
   it instead of sitting beside it. */


/* ============================================================
   SECTION 08 GROUND  ·  the corridor
   Variant C from the motion study at low volume. overflow:hidden
   keeps the near rings from spilling into the sections either side,
   and nothing inside this section is sticky, so clipping is free.
   ============================================================ */
.engine{position:relative;overflow:hidden}
.engine>.wrap{position:relative;z-index:1}
.eng-tunnel{position:absolute;inset:0;z-index:0;pointer-events:none;
  perspective:900px;display:grid;place-items:center;
  opacity:.42;transform-style:preserve-3d}
.eng-tunnel .ring{position:absolute;display:grid;place-items:center;
  will-change:transform,opacity}
.eng-tunnel .ring svg{width:min(74vw,820px);height:auto;overflow:visible}
.eng-tunnel .ring path{fill:none;stroke:var(--line-gold);stroke-width:1;
  vector-effect:non-scaling-stroke}
@media (max-width:900px){ .eng-tunnel{opacity:.3} }
@media (prefers-reduced-motion:reduce){ .eng-tunnel{opacity:.22} }
.chain{position:relative;list-style:none;margin:0;padding:0 0 0 clamp(26px,2.8vw,40px)}
/* The engine headline had nothing holding it off the first node: the gap was
   only ever the slack left by whichever of the two head columns was taller,
   which measured 0px at 1440 once the lead paragraph was merged down to one.
   Scoped to .engine so it outranks the .chain{margin:0} above regardless of
   source order -- that exact rule has silently eaten this gap once before. */
.engine .chain{margin-top:clamp(44px,5vw,80px)}
/* Arches behind these points crossed the live copy and read as noise even at
   watermark weight. The closing CTA is where that motif belongs; here the
   connector goes back to the plain drawn spine. */
.chain-svg{position:absolute;left:5px;top:.55em;height:calc(100% - 1.1em);width:1px;
  color:var(--sand);overflow:visible}
.chain-svg .ln{stroke:currentColor;stroke-width:1;fill:none;vector-effect:non-scaling-stroke}
.chain>li{position:relative;z-index:1}
.node{position:relative;padding-bottom:clamp(38px,4.4vw,66px)}
.node:last-child{padding-bottom:0}
.js .node{opacity:.84;transition:opacity .7s var(--ease)}
.js .node.lit{opacity:1}
/* the mark has to sit ON the spine, which lives 5px inside .chain's border
   box — so it steps back out of the node's own left padding to reach it */
.node::before{content:"";position:absolute;top:.35em;width:11px;height:11px;
  left:calc(clamp(26px,2.8vw,40px) * -1 - 0.5px);
  background:var(--sand);transform:rotate(45deg)}
.js .node::before{transform:rotate(45deg) scale(.3);opacity:0;
  transition:opacity .45s var(--ease),transform .45s var(--ease)}
.js .node.lit::before{opacity:1;transform:rotate(45deg) scale(1)}
.node-n{font-size:clamp(.8rem,1vw,.95rem);color:var(--sand);margin-bottom:14px}
.node-q{color:var(--ivory);margin-bottom:14px}
.node-b{color:rgba(255,255,250,.78);font-size:var(--t-body);line-height:1.6;max-width:46ch}
.outcome{margin-top:clamp(52px,6vw,86px);padding-top:clamp(30px,3.4vw,46px);
  border-top:1px solid var(--line-gold);display:flex;flex-wrap:wrap;align-items:center;
  /* 12 Oct, Jacob: "this needs to be centered. Maybe even split to two lines." */
  justify-content:center;text-align:center;
  gap:.9em 1.1em;font-size:clamp(.72rem,1.02vw,.9rem);color:var(--sand)}
.outcome .sep{opacity:.5}
.outcome .brk{display:none}
/* Six steps now, and it overshot the measure by 5 to 7 per cent, so it broke
   with "Specific causation report" alone on a second line. Held to one line
   from 1100 up: nowrap guarantees it and the size is tied to the viewport so
   the guarantee cannot become an overflow. Below 1100 one line would need
   sub-9px type, so it wraps there instead. */
@media (min-width:1100px){
  /* Was forced onto one line with nowrap, which meant squeezing six steps and
     five arrows into the measure at 13.5px -- small, cramped, and hard against
     the left edge. Two centred lines at a readable size reads far better, so
     the nowrap goes and a measure does the breaking instead. */
  .outcome{max-width:min(100%,940px);margin-inline:auto;
    font-size:clamp(.78rem,.95vw,.92rem);gap:.7em 1em}
  /* forces the 3/3 break; see the note in the markup */
  .outcome .brk{display:block;flex-basis:100%;height:0;margin:0}
}

/* ============================================================
   SECTION 06 — BENEFITS
   ============================================================ */
.ben-head{grid-column:1/7;margin-bottom:clamp(32px,3.4vw,50px);align-self:center}
/* The header ran headline-left, nothing-right. Shot from behind on purpose:
   faces are not the subject, so it reads as the room rather than as stock
   actors -- and it sidesteps the sameness problem the generated people had. */
/* markup #100, Britt: "Frame this video and increase the width so it feels
   50/50 like the sections below." The .ben-row list underneath runs 5fr/6fr,
   so the head and the clip now split 6/6 to match, and the clip gets the
   same offset Sand hairline the product panel uses -- a frame, not a card. */
.ben-film{grid-column:7/13;margin:0 0 clamp(32px,3.4vw,50px);
  aspect-ratio:16/9;overflow:visible;position:relative;
  /* poster on the container too, so reduced motion still gets the image */
  background:var(--stone) url("/assets/img/corridor-poster.jpg") center/cover no-repeat}
.ben-film::after{content:"";position:absolute;inset:0;border:1px solid var(--line);
  pointer-events:none;z-index:2}
.ben-film::before{content:"";position:absolute;z-index:0;pointer-events:none;
  inset:clamp(10px,1.1vw,16px) calc(-1 * clamp(10px,1.1vw,16px))
        calc(-1 * clamp(10px,1.1vw,16px)) clamp(10px,1.1vw,16px);
  border:1px solid var(--sand)}
.ben-film video{position:relative;z-index:1}
.ben-film video{width:100%;height:100%;object-fit:cover;display:block}
@media (max-width:900px){
  .ben-film{grid-column:1/-1;margin-bottom:clamp(26px,4vw,38px)}
}
/* Britt, 21 Aug: "too much dead space and not enough visual storytelling --
   make the benefits section demonstrate the product rather than simply
   describe the benefits." The rows were centred statements with nothing
   beside them, which is exactly the describe-not-demonstrate problem. Now
   each row alternates side to side and carries a fragment of the real
   interface, so the claim and the thing that proves it sit together.
   These are single stills, not a sequence -- Aaron's "no interface
   walkthrough, it reads as data entry" still holds. */
.ben-rows{margin-top:clamp(16px,1.8vw,28px)}
.ben-row{padding-block:clamp(28px,3.2vw,46px);border-top:1px solid var(--line);
  display:grid;gap:clamp(22px,2.8vw,38px);align-items:center}
.ben-row:last-child{border-bottom:1px solid var(--line)}
@media (min-width:900px){
  .ben-row{grid-template-columns:minmax(0,5fr) minmax(0,6fr);
    gap:clamp(38px,4.4vw,80px)}
  /* flip the track sizes too, or the reversed row hands the fragment the
     narrow column and the text the wide one */
  .ben-row:nth-child(even){grid-template-columns:minmax(0,6fr) minmax(0,5fr)}
  .ben-row:nth-child(even) .ben-lead{grid-column:2;grid-row:1}
  .ben-row:nth-child(even) .ben-vis{grid-column:1;grid-row:1}
}
/* px, not ch -- ch resolves against the wrong face here and squeezed the
   statement to six lines */
.ben-lead{max-width:min(100%,640px)}
.ben-n{font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:var(--t-eyebrow);color:var(--ocean);
  margin-bottom:clamp(12px,1.4vw,18px)}
.ben-t{font-family:var(--f-text);font-weight:700;letter-spacing:-.025em;
  font-size:clamp(1.32rem,2.15vw,1.95rem);line-height:1.2;color:var(--graphite);
  text-wrap:balance}

/* The fragments reuse the product's own .ui-* classes, so this is the
   interface at native size rather than a second visual language or a scaled
   screenshot. .ui itself is absolutely positioned inside the mockup frame,
   so the type context it establishes has to be restated here. */
.ben-vis{margin:0;font-family:var(--f-text);font-size:13px;line-height:1.45;
  color:var(--graphite);-webkit-font-smoothing:antialiased;
  background:var(--ivory);border:1px solid rgba(35,35,35,.12);
  padding:clamp(13px,1.4vw,19px);min-width:0}
.ben-vis .ui-table,.ben-vis .ui-settle,.ben-vis .ui-panel:first-of-type{margin-top:0}
.ben-vis-cap,.ben-vis-foot{font-family:var(--f-text);font-size:10.5px;font-weight:700;
  letter-spacing:.05em;text-transform:uppercase;color:rgba(35,35,35,.44)}
.ben-vis-cap{margin-bottom:9px}
.ben-vis-foot{margin-top:11px;padding-top:10px;
  border-top:1px solid rgba(35,35,35,.09);text-transform:none;
  letter-spacing:0;font-weight:400;font-size:11.5px}
/* The product greys are tuned for the mockup, where the whole interface is
   scaled down and decorative. Here the same classes render at native size in
   the reading flow, so they have to clear 4.5:1. Scoped to .ben-vis so the
   mockup itself is untouched -- it is still a faithful rebuild. Measured:
   .44 gave 2.67, .5 gave 3.05, .62 gave 4.29. */
.ben-vis .ben-vis-cap,.ben-vis .ben-vis-foot,
.ben-vis .ui-table th,.ben-vis .ui-table .meta,
.ben-vis .ui-panel .row{color:rgba(35,35,35,.74)}
.ben-vis .ui-stat.draft{color:rgba(35,35,35,.78)}
/* the statement bar is 1100px wide in the product; at half that the action
   was wrapping onto two lines */
@media (min-width:900px){ .ben-vis .ui-settle .b{white-space:nowrap} }
/* Below the two-column breakpoint the fragments are simply wider than the
   screen -- an interface does not reflow to 350px. Let each one scroll inside
   its own plate rather than shrinking it to illegibility or dropping the
   columns that carry the point. Caught by screenshot, not by the overflow
   probe: Chrome headless clamps a 375px window to a 500px viewport, so the
   probe was measuring a screen wider than the one it was asked about. */
@media (max-width:899px){
  .ben-vis{overflow-x:auto}
  .ben-vis>*{min-width:440px}
}

/* ============================================================
   SECTION 07 — HOW IT WORKS (horizontal rail)
   ============================================================ */
/* ---- compliance (Section 07) ---- */
/* Jacob: "let's not use that colour as a background, can we do a video
   texture, like ocean waves." Generated on Artlist and cut to a 5s loop.
   The plate replaces the grain entirely here -- no .tex on this section. */
.compliance{position:relative;overflow:hidden;isolation:isolate}
/* the poster rides on the container, not just the <video>, so it still shows
   when reduced-motion removes the clip */
.comp-video{position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:var(--ocean) url("/assets/img/ocean-poster.jpg") center/cover no-repeat}
.comp-video video{width:100%;height:100%;object-fit:cover;display:block}
/* a flat scrim, not a gradient -- the plate is already low contrast but the
   copy needs a guaranteed floor to sit on */
.comp-video::after{content:"";position:absolute;inset:0;
  background:rgba(9,38,44,.66)}

/* 26ch was measuring against the wrong font and broke this across four lines,
   splitting the hyphenate. A px cap with balanced wrapping gives two. */
/* the cap moves onto the headline: it was the block that was 640px wide, so
   the subhead could never reach one line however wide its own max-width was */
.comp-head{max-width:100%}
.comp-head .h1{max-width:min(100%,640px)}
/* Britt, 24 Aug: the subhead was stacking on itself. The head column caps at
   7 of 12, which left it a narrow measure; the sentence gets the full column
   so it runs long instead of deep. */
.prob-sub{max-width:min(100%,72ch)}
.comp-head .h1{text-wrap:balance}
/* The four names carry the section instead of being repeated inside boxes.
   Bracketed top and bottom by rules, which frame rather than decorate. */
.certs{list-style:none;margin:clamp(32px,3.8vw,54px) 0 0;padding:clamp(30px,3.4vw,46px) 0 0;
  border-top:1px solid rgba(255,255,250,.24);
  display:grid;grid-template-columns:repeat(4,1fr);
  gap:clamp(14px,1.6vw,26px);align-items:stretch}
/* Britt asked for iconography here and the first attempt was four abstract
   marks. They failed for a findable reason: audited, bounded, shielded and
   contained are four ways of saying protected, so nothing distinguished SOC 2
   from HIPAA except the word underneath, and the mark carried no information
   the label did not already carry. The four items are not parallel either --
   an audit, a law, a data regime and a product policy.
   So the arch stays and frames content instead of ornament, which is the test
   the linework has to pass anyway. The head is an elliptical radius rather
   than an SVG arc so the bay can stretch and the copy can reflow inside it. */
.certs li{position:relative;display:flex;flex-direction:column;align-items:center;
  justify-content:center;
  gap:clamp(10px,1.1vw,15px);text-align:center;
  /* "Zero AI training on your data" is far longer than the other three and was
     running into the curved edge of its bay -- the inline padding is set by
     that label, not by the short ones */
  padding:clamp(28px,2.8vw,38px) clamp(20px,2.2vw,30px) clamp(22px,2.2vw,30px);
  border:1px solid rgba(255,255,250,.2);border-bottom:0;
  border-top-left-radius:50% clamp(52px,6vw,84px);
  border-top-right-radius:50% clamp(52px,6vw,84px)}
/* keystone, the page's existing accent, sitting on the crown of each bay */
.certs li::before{content:"";position:absolute;top:0;left:50%;
  width:9px;height:9px;background:var(--sand);
  transform:translate(-50%,-50%) rotate(45deg)}
/* plinth: one continuous rule under the arcade rather than a box per bay */
.certs li::after{content:"";position:absolute;left:0;right:0;bottom:0;
  height:1px;background:rgba(255,255,250,.24)}
.certs .cert-l{font-family:var(--f-display);font-weight:400;
  font-size:clamp(1.02rem,1.45vw,1.34rem);line-height:1.2;letter-spacing:-.005em;
  color:var(--ivory);text-wrap:balance}
/* Art Deco marks. They are not asked to mean anything -- Britt: "I don't think
   meaningless is too bad as long as it's an icon and feels like it fits the
   brand." Fan, stepped setback, sunburst, chevron column: staples of the
   idiom, drawn with the page's own straight lines and diamond. */
/* Britt, 24 Aug: subhead copy comes out of these bays and the marks grow to
   fill what it leaves. Roughly double. */
.cert-mark{width:clamp(72px,7vw,104px);height:auto;display:block;
  color:var(--seaglass);overflow:visible;margin-bottom:clamp(6px,0.8vw,12px)}
.cert-mark .s{fill:none;stroke:currentColor;stroke-width:1;
  vector-effect:non-scaling-stroke;stroke-linecap:square}
.cert-mark .f{fill:var(--sand);stroke:none}
/* the supporting line is a subhead under the title now, not a footnote below
   the bays */
/* Britt, 24 Aug: one line. The 46ch cap was what broke it, and the sentence
   is 66 characters -- no cap, so it sits on one line wherever there is room.
   It still wraps on a phone, where one line is not physically possible. */
.comp-sub{margin-top:clamp(16px,1.8vw,24px);max-width:none;
  /* no balance here: balancing splits a sentence into two even lines even
     when it would fit on one, which is the opposite of what was asked */
  color:rgba(255,255,250,.9)}
@media (max-width:900px){
  .certs{grid-template-columns:repeat(2,1fr);gap:clamp(12px,2vw,20px)}
}
/* Jacob, 24 Aug: two to a line on a phone -- SOC 2 and GDPR, then HIPAA and
   Zero AI. It used to collapse to a single column below 520, which left the
   marks stranded on their own row each. Two columns hold all the way down;
   the bays just get tighter inside. */
@media (max-width:520px){
  .certs{gap:clamp(10px,2.6vw,16px)}
  .certs li{padding-inline:clamp(8px,2.6vw,14px);
    padding-block:clamp(22px,5vw,30px) clamp(16px,3.4vw,22px)}
  .cert-mark{width:clamp(52px,15vw,68px)}
  .certs .cert-l{font-size:clamp(.92rem,3.8vw,1.06rem)}
}
.how-head{margin-bottom:clamp(48px,5.5vw,76px)}
.how-head .h1{max-width:18ch}
/* ---- the product tour ----
   The screen runs full width so the interface is actually legible; the four
   steps sit beneath it as a row of tabs. Nothing competes for horizontal
   space, and all four descriptions stay intact. */
/* Jacob: "title on the left and image on the right so you can see where you
   click into it." The steps now sit beside the screen they drive, so the
   cause and the effect are in the same glance. The stage bleeds to the
   viewport edge, which buys back the width the UI needs to stay legible --
   that was the whole reason it went full-width in the first place. */
/* The headline leads the section now, so the step column carries only the
   steps -- it can be narrower, which hands the screen back some width, and
   the two columns centre against each other instead of stretching. */
/* The step column carries every description now, not just the active one, so
   a 248px measure wrapped step 04 to eleven lines. Wider column, shorter list,
   and the two sides come closer to level. */
.tour{display:grid;grid-template-columns:clamp(248px,23vw,340px) 1fr;
  gap:clamp(26px,2.8vw,44px);align-items:start}
.tour-side{display:flex;flex-direction:column}
/* Nothing was making the two columns agree, so the screen stopped 415px short
   of the step list and left a hole. The stage now stretches to the row and the
   frame takes whatever height that is -- taller frame just reveals more of the
   product screen, which is the thing worth showing anyway. */
.tour-stage{display:flex;flex-direction:column;min-width:0}
@media (min-width:1000px){
  /* The screens are authored 1100x720, so anything taller than that ratio is
     empty white inside the frame. Cap it there and fill the rest of the column
     with the CTA, which belongs under the product shot anyway. */
  .tour-stage .ui-frame{flex:0 0 auto;height:auto;max-height:none;
    aspect-ratio:1100/720;max-width:1060px}
  /* Jacob: "I want to see the mockup on the right when I'm scrolling; once
     I get to #4 it is too far up the screen." The steps run taller than the
     screen, so the screen rides along rather than scrolling away. Sticky,
     not pinned: the section never takes over the scroll. */
  .tour-stage{padding-top:0;position:sticky;top:clamp(84px,11vh,116px)}
  .tour-side{justify-content:space-between}
}
.how-head{margin-bottom:clamp(38px,4.4vw,62px)}
.how-head .h1{max-width:22ch}
/* This used to break at 1300, which put a 1200px-wide laptop into the stacked
   layout: the screen sat under all four steps, and any attempt to bring it up
   beside its own step meant relocating a ~630px block, which is what made the
   page jump on hover. Side by side from 1000 instead. The screen is smaller
   down here -- roughly 7-9px effective UI type at the low end -- but it is an
   illustration of a product, not something anyone reads, and the step copy
   carries the meaning. Below 1000 there is genuinely no room to split. */
@media (max-width:999px){
  .tour{grid-template-columns:1fr;margin-right:0;
    gap:clamp(26px,4vw,40px)}
  .tour-side{position:static}
}
/* Britt: "design this as a real workflow timeline rather than another set of
   text cards so it doesn't feel repetitive to section 3." Section 3 is now a
   vertical spine, so this runs horizontally -- one rail across the top, a
   station per step, and a fill that creeps forward as the walkthrough
   advances. The plates stay: they are what made the steps read as clickable,
   which was the whole point of the last pass. */
/* The timeline runs down the side column: one rail, a station per step, and a
   fill that walks to the active one. Vertical at every width now, so it no
   longer breaks when the stations stop being a single row. */
.tour-steps{display:grid;grid-template-columns:1fr;gap:clamp(8px,0.85vw,11px);
  margin-top:clamp(12px,1.4vw,18px);position:relative;
  padding-left:clamp(26px,2.4vw,34px)}
.tour-steps::before,.tour-steps::after{content:"";position:absolute;left:5px;width:1px;
  pointer-events:none}
.tour-steps::before{top:0;bottom:0;background:var(--line-light)}
.tour-steps::after{top:0;height:var(--fill,0%);background:var(--seaglass);
  transition:height var(--fill-t,.45s) linear}
/* > li throughout: with the frame inside a step, the product mock's own 25
   list items are descendants of .tour-steps and would otherwise take the
   timeline diamonds and the column flex. */
.tour-steps > li{display:flex;position:relative}
/* Stacked layouts park the product screen inside the active step rather than
   after all four. Britt: "images between steps"; on a phone the screen sat
   past step 04, so 03 could be lit while its picture was two steps away. */
@media (max-width:999px){
  .tour-steps > li{flex-direction:column}
  /* height:100% on the button used to mean "fill the li". Now that the li can
     also hold the frame, that resolves against the frame's height too and the
     plate balloons to several hundred empty px. */
  .tour-steps > li > button{height:auto;flex:0 0 auto}
  .tour-steps > li > .ui-frame{margin-top:clamp(12px,2.4vw,20px);width:100%;
    aspect-ratio:16/9.6;max-height:none}
  /* every step carries its own screen down here, so the shared stage has
     nothing left to show */
  .tour-stage{display:none}
}
.tour-steps > li::before{content:"";position:absolute;z-index:1;top:1.15em;
  left:calc(clamp(26px,2.4vw,34px) * -1 - 0.5px);
  width:11px;height:11px;background:var(--ocean);border:1px solid var(--seaglass);
  transform:rotate(45deg);transition:background .4s var(--ease)}
.tour-steps > li.on::before{background:var(--seaglass)}
.tour-steps button{display:block;width:100%;height:100%;text-align:left;color:inherit;
  position:relative;cursor:pointer;
  padding:clamp(13px,1.25vw,16px) clamp(13px,1.25vw,17px) clamp(14px,1.35vw,17px);
  border:1px solid var(--line-light);background:rgba(255,255,250,.035);
  transition:background .35s var(--ease),border-color .35s var(--ease),
             opacity .4s var(--ease)}
.tour-steps button:hover{background:rgba(255,255,250,.08);
  border-color:rgba(255,255,250,.32)}
.tour-steps > li.on > button{background:rgba(255,255,250,.095);
  border-color:rgba(255,255,250,.36)}
.tour-cue{display:flex;align-items:center;gap:10px;margin-top:0;
  font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:.7rem;color:rgba(255,255,250,.92)}

.tour-cue .dm{width:7px;height:7px;background:var(--seaglass);transform:rotate(45deg);
  flex:none}
.tour-steps .n{display:block;font-family:var(--f-display);font-weight:400;
  /* must stay at or above 24px: below that WCAG wants 4.5:1, and Sea Glass on
     Ocean tops out at 4.24, so no opacity value can clear it. At 24px+ the
     large-text threshold of 3.0 applies and it passes with margin. */
  font-size:clamp(1.5rem,1.75vw,1.62rem);line-height:1;letter-spacing:.01em;
  color:var(--seaglass);opacity:.86;margin-bottom:6px;
  transition:opacity .4s var(--ease)}
.tour-steps > li.on > button .n{opacity:1}
.tour-steps .h{display:block;font-family:var(--f-text);font-weight:700;color:var(--ivory);
  font-size:clamp(.86rem,1.0vw,.96rem);line-height:1.3;letter-spacing:-.02em;
  color:var(--ivory);margin-bottom:7px;
  /* two of the four titles wrap, which left the collapsed plates uneven --
     reserving the second line squares them off */
  min-height:2.56em}
/* Descriptions used to collapse to 0fr and expand for the active step. That
   made hovering a step move it: picking step 04 collapsed 01 and pulled 04
   up 89px under the cursor, and near a plate edge that flips the hover to the
   neighbour and oscillates. Scroll drove the same change, so scrolling shifted
   the page too. Every step now shows its copy, so the list geometry is fixed
   and neither hover nor scroll can move anything. Active state is carried by
   the plate treatment and the rail instead. */
.tour-steps .sd{display:grid;grid-template-rows:1fr}
.tour-steps .dw{overflow:hidden;min-height:0}
.tour-steps .d{display:block;font-size:.84rem;line-height:1.5;
  color:rgba(255,255,250,.99);padding-top:8px}
.tour-steps .d+.d{padding-top:6px}
.js .tour-steps button{opacity:1}
.js .tour-steps > li.on > button{opacity:1}
.tour-steps button:hover{opacity:.82}
.tour-steps > li.on > button:hover{opacity:1}
/* the rail is vertical at every width now, so no breakpoint override is
   needed -- this block used to rotate it and is redundant */


/* ============================================================
   PRODUCT UI — faithful rebuild of Arches Mass Tort
   ------------------------------------------------------------
   Rebuilt screen-for-screen from the Aug 19 product captures:
   same layout, same fields, same labels, same workflow. Only two
   things are changed — the branding, and the data.

   ALL DATA IS FABRICATED. Every plaintiff, case, firm, physician,
   address and case number is invented and internally consistent
   across the four screens. No real record appears anywhere, and
   no firm from the Section 3 trust bar is used as the tenant.

   The green product palette maps to brand as:
     primary green -> Ocean      accents -> Sand
     white cards   -> Ivory      panel bg -> Stone
   Status pills carry no red or green (§3): Ocean = complete,
   Sand = in review, Stone = draft, Graphite = rejected.
   ============================================================ */
.ui-frame{position:relative;width:100%;aspect-ratio:16/9.6;overflow:hidden;
  max-height:clamp(340px,calc(100svh - 400px),720px);
  background:var(--ivory);border:1px solid var(--line-light)}
/* the standalone dashboard has no tabs under it, so it can run taller */
/* the UI is laid out at a true 1100px desktop width and scaled to fit, so the
   proportions match the real application rather than being re-flowed */
.ui{position:absolute;top:0;left:0;width:1100px;transform-origin:top left;
  transform:scale(var(--ui-s,1));font-family:var(--f-text);color:var(--graphite);
  font-size:13px;line-height:1.45;-webkit-font-smoothing:antialiased}
.ui-screen{display:none}
.ui-screen.on{display:block}
@keyframes screen-in{from{opacity:0}to{opacity:1}}
.js .engine-visual .ui-screen.on{animation:screen-in .4s var(--ease)}

.ui-nav{display:flex;align-items:center;gap:26px;background:var(--ivory);
  border-bottom:1px solid rgba(35,35,35,.1);padding:11px 22px}
.ui-brand{display:flex;align-items:center;gap:9px;font-weight:700;font-size:14px;
  letter-spacing:-.01em}
.ui-brand svg{width:20px;color:var(--ocean)}
.ui-nav ul{display:flex;gap:22px;margin-left:14px;font-size:12.5px;color:rgba(35,35,35,.62)}
.ui-nav li.on{color:var(--ocean);font-weight:700;position:relative}
.ui-nav li.on::after{content:"";position:absolute;left:0;right:0;bottom:-13px;height:2px;background:var(--ocean)}
.ui-nav .sp{margin-left:auto;display:flex;gap:10px;align-items:center}
.ui-pill{border:1px solid var(--ocean);color:var(--ocean);border-radius:2px;
  padding:5px 12px;font-size:11.5px;font-weight:700}
.ui-pill.solid{background:var(--ocean);color:var(--ivory);border-color:var(--ocean)}
.ui-pill.ghost{border-color:rgba(35,35,35,.2);color:rgba(35,35,35,.6)}

.ui-body{padding:20px 26px;background:var(--ivory);min-height:720px}
.ui-card{background:var(--stone);border:1px solid rgba(35,35,35,.09);padding:20px 22px}
.ui-hello{font-size:15px;margin-bottom:14px;color:rgba(35,35,35,.8)}
.ui-serif{font-family:var(--f-display);font-weight:400;letter-spacing:.01em}

.ui-steps{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-bottom:16px}
.ui-step{background:var(--stone);border:1px solid rgba(35,35,35,.09);padding:16px 18px}
.ui-step .n{width:24px;height:24px;display:grid;place-items:center;background:var(--ocean);
  color:var(--ivory);font-size:12px;font-weight:700;margin-bottom:12px}
.ui-step .t{font-weight:700;font-size:14.5px;line-height:1.25;margin-bottom:10px}
.ui-step .l{color:var(--ocean);font-size:12px;font-weight:700}

.ui-toolbar{display:flex;align-items:center;gap:16px;margin-bottom:12px}
.ui-toolbar h4{font-family:var(--f-display);font-weight:400;font-size:22px;letter-spacing:.01em}
.ui-search{margin-left:auto;border:1px solid rgba(35,35,35,.18);background:var(--ivory);
  padding:6px 12px;font-size:12px;color:rgba(35,35,35,.45);width:190px}
.ui-toggle{display:flex;align-items:center;gap:8px;font-size:12px;color:rgba(35,35,35,.62)}
.ui-toggle i{width:28px;height:15px;border-radius:9px;background:rgba(35,35,35,.16);position:relative}
.ui-toggle i::after{content:"";position:absolute;top:2px;left:2px;width:11px;height:11px;
  border-radius:50%;background:var(--ivory)}

.ui-table{width:100%;border-collapse:collapse;background:var(--stone);
  border:1px solid rgba(35,35,35,.09);font-size:12.5px}
.ui-table th{text-align:left;font-weight:700;font-size:11px;letter-spacing:.04em;
  text-transform:uppercase;color:rgba(35,35,35,.5);padding:10px 14px;
  background:var(--ivory);border-bottom:1px solid rgba(35,35,35,.09)}
.ui-table td{padding:12px 14px;border-bottom:1px solid rgba(35,35,35,.07);vertical-align:middle}
.ui-table tr:last-child td{border-bottom:0}
.ui-table .case{font-weight:700}
.ui-table .meta{color:rgba(35,35,35,.5);font-size:11.5px}
.ui-stat{display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:2px;
  font-size:11px;font-weight:700;letter-spacing:.02em}
.ui-stat.done{background:var(--ocean);color:var(--ivory)}
.ui-stat.review{background:var(--sand);color:var(--graphite)}
.ui-stat.appr{background:var(--seaglass);color:var(--graphite)}
.ui-stat.draft{background:var(--ivory);color:rgba(35,35,35,.6);
  box-shadow:inset 0 0 0 1px rgba(35,35,35,.12)}
.ui-stat.rej{background:var(--graphite);color:var(--ivory)}

/* Hover a status and the workflow popover shows where the case actually sits.
   Straight from the product — Britt called this out as the useful part. */
.ui-wf{position:relative;display:inline-block}
.ui-wf-pop{position:absolute;top:calc(100% + 7px);left:0;z-index:20;width:190px;
  background:var(--ivory);border:1px solid rgba(35,35,35,.14);
  box-shadow:0 12px 30px rgba(35,35,35,.14);padding:11px 13px;
  opacity:0;visibility:hidden;transform:translateY(-4px);
  transition:opacity .2s var(--ease),transform .2s var(--ease),visibility .2s}
.ui-wf:hover .ui-wf-pop,.ui-wf:focus-within .ui-wf-pop{opacity:1;visibility:visible;transform:none}
.ui-wf-pop .hd{font-size:9.5px;letter-spacing:.09em;text-transform:uppercase;
  color:rgba(35,35,35,.45);font-weight:700;margin-bottom:8px}
.ui-wf-pop ol{display:grid;gap:6px}
.ui-wf-pop li{display:flex;align-items:center;gap:8px;font-size:11.5px;
  color:rgba(35,35,35,.42)}
.ui-wf-pop li::before{content:"";width:6px;height:6px;flex:0 0 auto;
  background:rgba(35,35,35,.22);transform:rotate(45deg)}
.ui-wf-pop li.at{color:var(--graphite);font-weight:700}
.ui-wf-pop li.at::before{background:var(--ocean)}
.ui-foot-note{display:flex;align-items:center;gap:14px;margin-top:12px;
  font-size:11.5px;color:rgba(35,35,35,.5)}
.ui-foot-note .pg{margin-left:auto;display:flex;gap:5px}
.ui-foot-note .pg span{min-width:19px;height:19px;display:grid;place-items:center;
  border:1px solid rgba(35,35,35,.16);font-size:10.5px}
.ui-foot-note .pg span.on{background:var(--ocean);color:var(--ivory);border-color:var(--ocean)}
.ui-acts{display:flex;gap:6px;justify-content:flex-end}
.ui-btn{border:1px solid rgba(35,35,35,.18);padding:5px 10px;font-size:11px;font-weight:700;
  color:rgba(35,35,35,.72);white-space:nowrap}
.ui-btn.pri{border-color:var(--ocean);color:var(--ocean)}

/* ---- Create Case: stepper, liability, address history ---- */
.ui-head{display:flex;align-items:center;gap:14px;margin-bottom:16px}
.ui-head h4{font-family:var(--f-display);font-weight:400;font-size:26px;letter-spacing:.01em}
.ui-stepper{display:flex;align-items:center;gap:0;margin-bottom:18px;font-size:12px}
.ui-stepper span{display:flex;align-items:center;gap:7px;color:rgba(35,35,35,.45);white-space:nowrap}
.ui-stepper span i{width:13px;height:13px;border-radius:50%;
  box-shadow:inset 0 0 0 1.5px rgba(35,35,35,.28)}
.ui-stepper span.done i{background:var(--ocean);box-shadow:none}
.ui-stepper span.now{color:var(--graphite);font-weight:700}
.ui-stepper span.now i{background:var(--ivory);box-shadow:inset 0 0 0 4px var(--ocean)}
.ui-stepper hr{flex:1;height:1px;border:0;background:rgba(35,35,35,.16);margin:0 12px}
.ui-sec{font-weight:700;font-size:16px;margin-bottom:14px}
/* Aaron, 24 Aug: this screen read as data entry, "old school DemandPro". Same
   record, read back as a file Arches already holds. Values are stated, not
   sitting in boxes waiting to be typed into. */
.ui-hist{width:100%;border-collapse:collapse;margin-top:10px;font-size:12.5px}
.ui-hist td{padding:7px 10px;border-bottom:1px solid rgba(35,35,35,.07);vertical-align:top}
.ui-hist tr:last-child td{border-bottom:0}
.ui-hist .yr{white-space:nowrap;font-weight:700;width:1%;padding-right:18px}
.ui-hist .src{color:rgba(35,35,35,.62);text-align:right;white-space:nowrap}
.ui-field .ro{font-weight:700;padding-top:3px}
.ui-calc{margin-top:16px;background:var(--graphite);color:var(--ivory);padding:14px 16px}
.ui-calc .cl{font-size:12.5px;font-weight:700}
.ui-calc .bar{height:4px;background:rgba(255,255,250,.18);margin:9px 0 7px}
.ui-calc .bar span{display:block;height:100%;background:var(--sand)}
.ui-calc .cs{font-size:11px;color:rgba(255,255,250,.66)}

.ui-grid2{display:grid;grid-template-columns:1fr 1fr;gap:14px 22px}
.ui-field label{display:block;font-size:11.5px;color:rgba(35,35,35,.6);margin-bottom:5px}
.ui-field label b{color:var(--sand);font-weight:700}
.ui-field .in{border:1px solid rgba(35,35,35,.2);background:var(--ivory);padding:8px 11px;
  font-size:12.5px;min-height:33px;display:flex;align-items:center;justify-content:space-between}
.ui-field .in.sel{border-color:var(--ocean)}
.ui-field .in .ph{color:rgba(35,35,35,.35)}
.ui-field .in .cv{color:rgba(35,35,35,.35);font-size:10px}
.ui-addr{border:1px solid rgba(35,35,35,.14);padding:14px 16px;margin-top:12px;position:relative}
.ui-addr>.hd{font-size:11.5px;color:rgba(35,35,35,.6);margin-bottom:11px}
.ui-addr>.x{position:absolute;top:11px;right:13px;color:rgba(35,35,35,.35);font-size:12px}
.ui-foot{display:flex;align-items:center;gap:12px;margin-top:18px;padding-top:14px;
  border-top:1px solid rgba(35,35,35,.1)}
.ui-foot .r{margin-left:auto;display:flex;gap:10px}

/* ---- Case overview + doctor review modal ---- */
.ui-ov-t{font-family:var(--f-display);font-weight:400;font-size:24px;letter-spacing:.01em}
.ui-ov-m{color:rgba(35,35,35,.6);font-size:12.5px;margin-top:4px}
.ui-ov-teams{display:flex;align-items:center;gap:10px;font-size:12px;
  color:rgba(35,35,35,.6);margin-top:10px}
.ui-ov-teams b{width:22px;height:22px;border-radius:50%;background:var(--seaglass);
  display:grid;place-items:center;font-size:10px;color:var(--graphite)}
.ui-settle{background:var(--graphite);color:var(--ivory);padding:16px 20px;margin-top:16px;
  display:flex;align-items:center;gap:16px}
.ui-settle .t{font-family:var(--f-display);font-weight:400;font-size:19px;letter-spacing:.01em}
.ui-settle .s{font-size:11.5px;color:rgba(255,255,250,.6);margin-top:2px}
.ui-settle .b{margin-left:auto;background:var(--sand);color:var(--graphite);
  padding:7px 14px;font-size:11.5px;font-weight:700}
.ui-panel{background:var(--stone);border:1px solid rgba(35,35,35,.09);
  padding:14px 16px;margin-top:14px;font-size:12.5px}
.ui-panel .ph{font-weight:700;margin-bottom:10px}
.ui-panel .row{display:flex;gap:10px;color:rgba(35,35,35,.62);padding:5px 0}

.ui-dim{position:absolute;inset:0;background:rgba(35,35,35,.42)}
.ui-modal{position:absolute;left:50%;top:58px;transform:translateX(-50%);
  width:430px;background:var(--ivory);border:1px solid rgba(35,35,35,.14);
  box-shadow:0 18px 50px rgba(35,35,35,.22)}
.ui-modal .mh{display:flex;align-items:flex-start;gap:14px;padding:18px 22px 0}
.ui-modal .mh h5{font-family:var(--f-display);font-weight:400;font-size:20px;letter-spacing:.01em}
.ui-modal .mh .x{margin-left:auto;color:rgba(35,35,35,.4)}
.ui-modal .mb{padding:12px 22px 18px;font-size:12.5px;color:rgba(35,35,35,.66);line-height:1.55}
.ui-modal .mf{display:flex;justify-content:flex-end;gap:10px;padding:0 22px 18px}
.ui-modal .mf .go{background:var(--ocean);color:var(--ivory);border-color:var(--ocean)}

/* ---- Upload Medical Records modal ---- */
.ui-rec{position:absolute;left:50%;top:2%;transform:translateX(-50%);width:640px;
  background:var(--ivory);border:1px solid rgba(35,35,35,.14);
  box-shadow:0 22px 60px rgba(35,35,35,.24);z-index:30;max-height:90%;overflow:hidden}
.ui-rec .rh{background:var(--ocean);color:var(--ivory);padding:15px 20px;
  display:flex;align-items:flex-start;gap:12px}
.ui-rec .rh .n{width:22px;height:22px;flex:0 0 auto;display:grid;place-items:center;
  background:rgba(255,255,250,.18);font-size:11px;font-weight:700}
.ui-rec .rh h5{font-family:var(--f-display);font-weight:400;font-size:18px;letter-spacing:.01em}
.ui-rec .rh .s{font-size:11.5px;color:rgba(255,255,250,.72);margin-top:2px}
.ui-rec .rh .x{margin-left:auto;color:rgba(255,255,250,.7);font-size:14px}
.ui-rec .rb{padding:16px 20px;font-size:12px;line-height:1.55;color:rgba(35,35,35,.66)}
.ui-note{background:var(--stone);border-left:2px solid var(--sand);
  padding:11px 14px;margin:13px 0;font-size:11.5px;line-height:1.5;color:rgba(35,35,35,.74)}
.ui-note b{color:var(--graphite)}
.ui-rec .scan{display:flex;align-items:center;gap:9px;margin-top:13px}
.ui-rec .scaninfo{font-size:10.5px;color:rgba(35,35,35,.48);margin-top:9px;line-height:1.5}
.ui-rec .drop{border:1px solid rgba(35,35,35,.14);padding:12px 14px;margin-top:13px;
  font-size:11.5px;color:rgba(35,35,35,.6);line-height:1.5}
.ui-rec .err{font-family:var(--f-detail);font-style:italic;font-size:11px;
  color:rgba(35,35,35,.55);margin-top:8px}
.ui-rec .dh{font-family:var(--f-display);font-weight:400;font-size:17px;letter-spacing:.01em;
  color:var(--graphite);margin:18px 0 10px}
.ui-rec .rf{display:flex;justify-content:flex-end;padding:0 20px 16px}

/* ---- Dashboard: chart, average creation time, account tiles ---- */
.ui-dash{display:grid;grid-template-columns:1fr 320px;gap:20px;align-items:stretch}
.ui-dashhead{display:flex;align-items:center;gap:14px;margin-bottom:18px}
.ui-dashhead h4{font-family:var(--f-display);font-weight:400;font-size:24px;letter-spacing:.01em}
.ui-seg{display:inline-flex;border:1px solid rgba(35,35,35,.18);background:var(--ivory)}
.ui-seg span{padding:5px 14px;font-size:12px;color:rgba(35,35,35,.55)}
.ui-seg span.on{background:var(--ocean);color:var(--ivory);font-weight:700}
.ui-chart{position:relative;height:250px;display:flex;align-items:flex-end;gap:2.2%;
  padding:0 6px 26px;border-left:1px solid rgba(35,35,35,.14);
  border-bottom:1px solid rgba(35,35,35,.14)}
.ui-chart .bar{flex:1;background:var(--ocean);position:relative;height:var(--h);
  transform-origin:bottom center}
.ui-chart .bar.hi{background:var(--sand)}
.ui-chart .bar b{position:absolute;top:-17px;left:50%;transform:translateX(-50%);
  font-size:10.5px;color:rgba(35,35,35,.6);font-weight:700}
.ui-chart .bar i{position:absolute;bottom:-19px;left:50%;transform:translateX(-50%);
  font-size:9.5px;color:rgba(35,35,35,.42);font-style:normal;letter-spacing:.04em}
.ui-avg{background:var(--graphite);color:var(--ivory);padding:22px 20px;
  display:flex;flex-direction:column;justify-content:center}
.ui-avg .l{font-size:12px;color:rgba(255,255,250,.62)}
.ui-avg .n{font-family:var(--f-display);font-weight:400;font-size:44px;line-height:1.05;
  letter-spacing:.01em;color:var(--sand);margin:8px 0 6px}
.ui-avg .s{font-size:12px;color:rgba(255,255,250,.62)}
.ui-tiles{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:18px}
.ui-tile{background:var(--stone);border:1px solid rgba(35,35,35,.09);padding:14px 16px}
.ui-tile .l{font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;
  color:rgba(35,35,35,.5);font-weight:700}
.ui-tile .v{font-family:var(--f-display);font-weight:400;font-size:26px;letter-spacing:.01em;
  margin-top:7px}
.ui-tile .v small{font-size:13px;color:rgba(35,35,35,.45)}

/* the chart draws itself when the screen becomes active */
.js .ui-screen.on .ui-chart .bar{animation:uiBar .8s var(--ease) both;
  animation-delay:calc(var(--i,0) * 70ms + 200ms)}
@keyframes uiBar{from{transform:scaleY(0)}to{transform:scaleY(1)}}
.js .ui-screen.on .ui-chart .bar b{animation:uiFade .5s var(--ease) both;
  animation-delay:calc(var(--i,0) * 70ms + 700ms)}
.js .ui-screen.on .ui-tile{animation:uiIn .5s var(--ease) both;
  animation-delay:calc(var(--i,0) * 90ms + 500ms)}
@media (prefers-reduced-motion:reduce){
  .js .ui-screen.on .ui-chart .bar,.js .ui-screen.on .ui-chart .bar b,
  .js .ui-screen.on .ui-tile{animation:none}
}

/* ---- the screens come alive when their step becomes active ---- */
.js .ui-screen.on .ui-step,
.js .ui-screen.on .ui-table tbody tr,
.js .ui-screen.on .ui-addr,
.js .ui-screen.on .ui-panel .row,
.js .ui-screen.on .ui-settle{
  animation:uiIn .5s var(--ease) both;
  animation-delay:calc(var(--i,0) * 90ms + 120ms)}
@keyframes uiIn{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:none}}

/* status resolves a beat after its row lands, so the docket reads as working */
.js .ui-screen.on .ui-stat{animation:uiPop .45s var(--ease) both;
  animation-delay:calc(var(--i,0) * 90ms + 420ms)}
@keyframes uiPop{from{opacity:0;transform:scale(.82)}to{opacity:1;transform:none}}

/* a light sweep travels the table once the rows have landed */
.js .ui-screen.on .ui-table{position:relative;overflow:hidden}
.js .ui-screen.on .ui-table::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:var(--seaglass);opacity:0;
  animation:uiSweep 2.6s var(--ease) 1s both}
@keyframes uiSweep{0%{opacity:0;transform:translateX(-100%)}
  22%{opacity:.16}55%{opacity:.16}100%{opacity:0;transform:translateX(100%)}}

/* the stepper fills to the active stage */
.js .ui-screen.on .ui-stepper hr{transform-origin:left center;
  animation:uiRule .6s var(--ease) both;animation-delay:calc(var(--i,0) * 140ms + 200ms)}
@keyframes uiRule{from{transform:scaleX(0)}to{transform:scaleX(1)}}

/* the review modal arrives over the dimmed case */
.js .ui-screen.on .ui-dim{animation:uiFade .4s var(--ease) both;animation-delay:.35s}
.js .ui-screen.on .ui-modal{animation:uiModal .5s var(--ease) both;animation-delay:.5s}
@keyframes uiFade{from{opacity:0}to{opacity:1}}
@keyframes uiModal{from{opacity:0;transform:translateX(-50%) translateY(8px)}
  to{opacity:1;transform:translateX(-50%) translateY(0)}}

/* hover the frame and the active row lifts — "you can see new pieces" */
.ui-table tbody tr{transition:background .25s var(--ease)}
.ui-frame:hover .ui-table tbody tr:hover{background:var(--stone)}
.ui-frame:hover .ui-step{transition:border-color .25s var(--ease)}
.ui-frame:hover .ui-step:hover{border-color:var(--ocean)}

@media (prefers-reduced-motion:reduce){
  .js .ui-screen.on *{animation:none!important}
  .js .ui-screen.on .ui-table::after{display:none}
}


/* ============================================================
   SECTION 12 — FAQ
   ============================================================ */
.faq-head{margin-bottom:clamp(34px,3.6vw,52px);max-width:44rem}
.faq{max-width:44rem}
.faq details{border-top:1px solid var(--line)}
.faq details:last-of-type{border-bottom:1px solid var(--line)}
.faq summary{list-style:none;cursor:pointer;padding-block:clamp(15px,1.5vw,19px);
  display:flex;align-items:flex-start;justify-content:space-between;gap:24px;
  font-family:var(--f-text);font-weight:700;
  font-size:clamp(1.12rem,1.35vw,1.2rem);line-height:1.35;letter-spacing:-.02em}
.faq summary::-webkit-details-marker{display:none}
.faq .ind{flex:0 0 14px;height:14px;position:relative;margin-top:.5em}
.faq .ind::before,.faq .ind::after{content:"";position:absolute;background:var(--ocean);
  transition:transform var(--dur-int) var(--ease),opacity var(--dur-int) var(--ease)}
.faq .ind::before{left:0;right:0;top:50%;height:1px}
.faq .ind::after{top:0;bottom:0;left:50%;width:1px}
.faq details[open] .ind::after{transform:rotate(90deg);opacity:0}
.faq .ans{overflow:hidden;display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .4s var(--ease)}
.faq details[open] .ans{grid-template-rows:1fr}
.faq .ans>div{min-height:0}
.faq .ans p{color:var(--soft);padding-bottom:clamp(20px,2.2vw,28px);max-width:60ch}
.faq .ans p .no{display:block;font-weight:700;color:var(--graphite);margin-bottom:6px}
.faq-foot{margin-top:clamp(44px,5vw,72px);display:flex;flex-wrap:wrap;align-items:center;gap:20px 32px}

/* ============================================================
   SECTION 13 — FINAL CTA
   ============================================================ */
.final{position:relative;overflow:hidden;text-align:center;
  padding-block:clamp(76px,8.8vw,138px)}
.final-in{position:relative;z-index:2;display:flex;flex-direction:column;align-items:center;
  overflow:hidden;
  border:1px solid var(--line-gold);
  padding:clamp(46px,6vw,92px) clamp(24px,5vw,80px)}
/* the closing arches: same geometry as the hero, drawn on arrival, sitting
   behind the CTA rather than beside it */
/* sized by height, not width: .final-in clips its children, and width-driven
   sizing pushed the crown of the outer arch past the top edge */
.final-arches{position:absolute;z-index:-1;left:50%;bottom:0;
  translate:-50% 0;height:84%;width:auto;max-width:none;
  color:var(--sand);opacity:.52;pointer-events:none}
.final-arches [data-draw]{stroke:currentColor;stroke-width:1;fill:none;
  vector-effect:non-scaling-stroke}
/* same treatment as the hero composition, not an imitation of it: the cross
   lines sit back, the crown diamonds are solid Sand */
.final-arches .faint{opacity:.42}
.final-arches .dm{fill:var(--sand);stroke:none}
@media (max-width:700px){
  .final-arches{height:76%;opacity:.4}
}
/* Complex tier: bracket returns on all four corners + diamonds on the mid-edges */
.final-in .cnr{position:absolute;width:clamp(26px,3.4vw,52px);height:clamp(26px,3.4vw,52px);
  border:1px solid var(--sand);opacity:.6}
.final-in .cnr.tl{top:-7px;left:-7px;border-right:0;border-bottom:0}
.final-in .cnr.tr{top:-7px;right:-7px;border-left:0;border-bottom:0}
.final-in .cnr.bl{bottom:-7px;left:-7px;border-right:0;border-top:0}
.final-in .cnr.br{bottom:-7px;right:-7px;border-left:0;border-top:0}
.final-in .edm{position:absolute;left:50%;width:8px;height:8px;background:var(--sand);
  transform:translateX(-50%) rotate(45deg)}
.final-in .edm.t{top:-4px}
.final-in .edm.b{bottom:-4px}
.final-in>*{max-width:min(100%,760px)}
.final .h1{max-width:18ch;margin-inline:auto;color:var(--ivory)}
.final-body{margin-top:clamp(26px,3vw,38px);color:rgba(255,255,250,.82);max-width:52ch;margin-inline:auto}
.final-cta{display:flex;flex-wrap:wrap;justify-content:center;gap:16px;margin-top:clamp(38px,4.4vw,56px)}
.js .final-cta .btn{opacity:0;transform:scale(.97);
  transition:opacity .5s var(--ease) .12s,transform .5s var(--ease) .12s,
             background var(--dur-int) var(--ease),color var(--dur-int) var(--ease)}
.js .final.in .final-cta .btn{opacity:1;transform:none}
.final-micro{margin-top:clamp(26px,3vw,36px);color:rgba(255,255,250,.65);font-size:1.02rem}

/* ============================================================
   FOOTER
   ============================================================ */
.foot{background:var(--graphite-deep);border-top:1px solid var(--line-gold);color:var(--ivory)}
.foot-in{display:grid;grid-template-columns:repeat(12,1fr);gap:clamp(28px,3vw,40px);
  padding-block:clamp(56px,6vw,88px) clamp(32px,3.4vw,44px)}
.foot-a{grid-column:1/5}
.foot-links{grid-column:5/10;align-self:end}
.foot-b{grid-column:10/13;text-align:right;align-self:end}
.foot-logo{width:clamp(160px,16vw,220px);color:var(--ivory);margin-bottom:24px}
.foot-a p{color:rgba(255,255,250,.66);font-size:var(--t-small);max-width:40ch}
.foot-b .sig{font-family:var(--f-display);font-weight:600;text-transform:uppercase;letter-spacing:.1em;
  font-size:clamp(1rem,1.8vw,1.4rem);color:var(--sand);line-height:1}
.foot-bar{border-top:1px solid var(--line-light);padding-block:24px 30px;
  display:flex;flex-wrap:wrap;justify-content:space-between;gap:12px 28px;
  font-size:.8rem;color:rgba(255,255,250,.5)}

/* ============================================================
   MODAL + FORM
   ============================================================ */
.modal{position:fixed;inset:0;z-index:200;display:none;align-items:flex-start;justify-content:center;
  padding:clamp(16px,4vh,56px) var(--gutter);overflow-y:auto;
  background:rgba(27,27,27,.88)}
.modal[open],.modal.open{display:flex}
.modal-panel{position:relative;background:var(--graphite);color:var(--ivory);width:min(100%,620px);
  padding:clamp(28px,4vw,52px);border:1px solid var(--line-gold);margin-block:auto;
  --fg:var(--ivory);--accent:var(--sand);--line:var(--line-gold);--soft:rgba(255,255,250,.8)}
.modal-panel::before,.modal-panel::after,
.modal-panel>.dm::before,.modal-panel>.dm::after{content:"";position:absolute;width:6px;height:6px;
  background:var(--sand);transform:rotate(45deg);opacity:.9}
.modal-panel::before{top:-3.5px;left:-3.5px}
.modal-panel::after{top:-3.5px;right:-3.5px}
.modal-panel>.dm::before{bottom:-3.5px;left:-3.5px}
.modal-panel>.dm::after{bottom:-3.5px;right:-3.5px}
.modal-close{position:absolute;top:14px;right:14px;width:44px;height:44px;display:grid;place-items:center;
  color:rgba(255,255,250,.6);transition:color var(--dur-int) var(--ease)}
.modal-close:hover{color:var(--sand)}
.modal-close span{position:relative;width:16px;height:16px;display:block}
.modal-close span::before,.modal-close span::after{content:"";position:absolute;left:0;right:0;top:50%;
  height:1px;background:currentColor}
.modal-close span::before{transform:rotate(45deg)}
.modal-close span::after{transform:rotate(-45deg)}
.modal h2{margin-bottom:10px;color:var(--ivory)}
.modal .sub{color:rgba(255,255,250,.68);font-size:var(--t-small);margin-bottom:clamp(24px,3vw,34px)}
.f-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(16px,2vw,24px)}
.f-full{grid-column:1/-1}
.field{position:relative;display:flex;flex-direction:column;gap:7px}
.field label{font-family:var(--f-text);font-weight:700;text-transform:uppercase;letter-spacing:.05em;
  font-size:.68rem;color:rgba(255,255,250,.6)}
.field input,.field select,.field textarea{font-family:var(--f-text);font-size:.98rem;color:var(--ivory);
  background:transparent;border:0;border-bottom:1px solid var(--line-light);
  padding:9px 0;border-radius:0;-webkit-appearance:none;appearance:none;
  transition:border-color var(--dur-int) var(--ease)}
.field select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23c8aa6e'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 2px center;background-size:12px}
.field select option{background:var(--graphite);color:var(--ivory)}
.field textarea{resize:vertical;min-height:76px}
.field input:focus,.field select:focus,.field textarea:focus{outline:0;border-bottom-color:var(--sand)}
.field .err{font-family:var(--f-detail);font-style:italic;font-size:.76rem;color:var(--sand);
  min-height:1.1em}
.field.bad input,.field.bad select{border-bottom-color:var(--sand)}
.radio-set{display:flex;gap:14px;padding-top:4px}
/* the case-type labels are long; let them wrap instead of squeezing */
.check-set{flex-wrap:wrap;gap:10px 22px}
.check-set label{display:flex;align-items:center;gap:8px}
/* .62 measured 3.40:1 on the modal ground; .84 clears 4.5. The form is
   hidden by default, so it had never been through the contrast probe until
   this pass opened it. */
.field .opt{font-weight:400;opacity:.84;font-size:.85em}
/* the label is the tap area for these, and it measured 50x25 -- under what a
   finger reliably hits. Padding takes it to 44 without changing the look. */
.radio-set label{display:flex;align-items:center;gap:9px;text-transform:none;letter-spacing:0;
  min-height:44px;padding-inline:10px;margin-inline:-10px;
  font-weight:400;font-size:.95rem;color:rgba(255,255,250,.84);cursor:pointer}
/* without this the checkboxes inherit the text-input styling above and
   render as invisible underlines -- only the radios had an override */
.radio-set input[type="radio"],.radio-set input[type="checkbox"]{-webkit-appearance:auto;appearance:auto;
  width:16px;height:16px;accent-color:var(--sand);border:0;padding:0;margin:0;flex:0 0 auto}
.hp{position:absolute!important;left:-9999px;width:1px;height:1px;overflow:hidden}
.modal .btn{width:100%;justify-content:center;margin-top:clamp(24px,3vw,34px)}
.modal .fine{font-family:var(--f-detail);font-style:italic;font-size:.76rem;
  color:rgba(255,255,250,.5);margin-top:16px;text-align:center}
.form-msg{padding:14px 0;font-size:.9rem;color:var(--sand);display:none}
.form-msg.on{display:block}
.form-done{text-align:center;padding-block:clamp(20px,4vw,44px)}
/* The confirmation heading takes focus so screen readers announce it. It is
   tabindex="-1", so it is never reached by keyboard and the ring would only
   ever be a box drawn around static text. */
#done-h:focus{outline:none}
.form-done .mk{width:44px;color:var(--sand);margin:0 auto 24px}
.form-done h2{margin-bottom:14px}
.form-done p{color:rgba(255,255,250,.72);max-width:38ch;margin-inline:auto}
body.locked{overflow:hidden}

/* ============================================================
   RESPONSIVE — 1200 / 1024 / 768 / 560
   ============================================================ */
@media (max-width:1200px){
  .hero-copy{grid-column:1/8}
  .hero-art{grid-column:8/13}
}
@media (max-width:1024px){
  .grid12{grid-template-columns:repeat(8,1fr)}
  .hero-copy,.hero-art{grid-column:1/-1}
  .hero-art{min-height:clamp(300px,52vw,440px)}
  .hero h1{max-width:16ch}
  .prob-head,.engine-head{grid-column:1/-1}
  .engine-lead{grid-column:1/-1;margin-top:28px}
  .ben-head{grid-column:1/-1;margin-bottom:clamp(28px,4vw,40px)}
  .prob-row{grid-template-columns:repeat(8,1fr)}
  .prob-n{grid-column:1/3}.prob-t{grid-column:3/9}.prob-b{grid-column:3/9;margin-top:14px}
  .stat:nth-child(3){padding-left:0}
  .stat:nth-child(3)::before{display:none}
  .firm-grid{grid-template-columns:repeat(4,1fr)}
}
@media (max-width:768px){
  .grid12{grid-template-columns:repeat(4,1fr)}
  .nav-logo{width:168px}
  .nav-btn-full{display:none}
  .nav-btn-short{display:inline}
  .hero{min-height:0;padding-block:clamp(120px,20vh,150px) clamp(64px,10vw,88px)}
  .prob-row{grid-template-columns:repeat(4,1fr)}
  .prob-n,.prob-t,.prob-b{grid-column:1/-1}
  .prob-t{margin-top:12px}
  .prob-row.feature{margin-inline:0;padding-inline:0}
  /* The chain is already vertical at every width now, so mobile only has to
     stack the split and let the product sit above the nodes. */
  .f-grid{grid-template-columns:1fr}
  .foot-a,.foot-b,.foot-links{grid-column:1/-1;text-align:left}
  .foot-b{margin-top:8px}
  .firm-grid{grid-template-columns:repeat(3,1fr)}
  /* the cells are grid tracks on a phone now, so a fixed width here only
     overflowed the row -- this rule sits later than the phone block above and
     was quietly winning */
  .firm{width:auto;min-width:0}
  .legibility{position:relative;max-width:none;margin-top:-1px}
  .hero-art{grid-template-columns:1fr}
  .hero-figure{border-right:1px solid var(--line-gold);border-bottom:0;aspect-ratio:16/9}
  .legibility{right:0}
  .hero-art{min-height:0}
  .arch-panel{position:relative;inset:auto;aspect-ratio:4/3}
}
@media (max-width:560px){
  .stat{padding-inline:0}
  .stat+.stat{padding-top:clamp(24px,5vw,32px)}
  .stat+.stat::before{left:0;right:0;top:0;bottom:auto;width:auto;height:1px;
    transform:scaleX(0);transform-origin:left center}
  .firm-grid{grid-template-columns:repeat(2,1fr)}
  .outcome{font-size:.72rem;gap:.6em .7em}
  .final-cta{flex-direction:column;align-items:stretch}
  .final-cta .btn{justify-content:center}
  .btn{padding:16px 24px}
}


/* ============================================================
   09 — CORRECTIONS & SPECIFICS
   Bold weights use real cuts. Season Mix has a SemiBold (600);
   never let the browser synthesise a bold on a display face.
   ============================================================ */
/* hero grain drifts at 0.85x scroll — inset overscan so no edge gap */
.hero.tex::before{inset:-18% 0;transform:translateY(var(--par,0));will-change:transform}

/* ==========================================================================
   HubSpot embedded form, skinned to the Arches modal.
   Their markup, our design. Two layers:
     1. --hsf-* variable overrides, which is their sanctioned theming API
     2. targeted rules on .hsfc-* for what the variables do not reach
   Scoped to #hs-form-mount so nothing leaks into the rest of the page.
   ========================================================================== */

#hs-form-mount [data-hsfc-id="Renderer"]{
  --hsf-default-field-input__font-family:var(--f-text);
  --hsf-default-field-input__background-color:transparent;
  --hsf-default-field-input__border-color:var(--line-light);
  --hsf-default-field-input__border-style:solid;
  --hsf-default-field-input__border-width:0 0 1px 0;
  --hsf-default-field-input__border-radius:0;
  --hsf-default-field-input__padding:9px 0 9px 0;
  --hsf-default-field-input__placeholder-color:rgba(255,255,250,.34);

  --hsf-default-field-textarea__font-family:var(--f-text);
  --hsf-default-field-textarea__background-color:transparent;
  --hsf-default-field-textarea__border-color:var(--line-light);
  --hsf-default-field-textarea__border-style:solid;
  --hsf-default-field-textarea__border-width:0 0 1px 0;
  --hsf-default-field-textarea__border-radius:0;
  --hsf-default-field-textarea__padding:9px 0 9px 0;
  --hsf-default-field-textarea__placeholder-color:rgba(255,255,250,.34);

  --hsf-default-field-label__font-family:var(--f-text);
  --hsf-default-field-label__font-size:.68rem;
  --hsf-default-field-label__color:rgba(255,255,250,.6);

  --hsf-default-field-checkbox__background-color:transparent;
  --hsf-default-field-checkbox__border-color:var(--line-light);
  --hsf-default-field-radio__background-color:transparent;
  --hsf-default-field-radio__border-color:var(--line-light);

  --hsf-default-button__font-family:var(--f-text);
  --hsf-default-button__font-size:.8rem;
  --hsf-default-button__color:var(--graphite);
  --hsf-default-button__background-color:var(--sand);
  --hsf-default-button--hover__background-color:var(--ivory);
  --hsf-default-button__border-radius:2px;
  --hsf-default-button__padding:18px 32px 18px 32px;
  --hsf-default-button__box-shadow:none;

  --hsf-default-erroralert__font-family:var(--f-detail);
  --hsf-default-erroralert__color:var(--sand);
  --hsf-default-field-description__font-family:var(--f-text);
  --hsf-default-field-description__color:rgba(255,255,250,.6);
  --hsf-default-row__horizontal-spacing:clamp(16px,2vw,24px);
  --hsf-default-row__vertical-spacing:clamp(16px,2vw,24px);
}

/* Their copy duplicates the modal heading and subtitle we already render.
   Hide the whole Row, not just the RichText, or its row margin leaves a
   dead band above the first field. */
/* Do NOT blanket-hide RichText. HubSpot uses it twice: once for the intro copy
   that duplicates our heading, and again for the post-submit thank-you. Hiding
   both left an empty panel after submitting. The intro row is hidden from JS
   instead (it is the one that renders while fields are present), and the
   thank-you is made legible here as a fallback in case the JS swap ever fails. */
#hs-form-mount [data-hsfc-id="RichText"]{
  color:var(--ivory);font-family:var(--f-text);text-align:center}
#hs-form-mount [data-hsfc-id="RichText"] *{color:var(--ivory)!important}
#hs-form-mount [data-hsfc-id="RichText"] p:first-child{
  font-family:var(--f-display);font-size:var(--t-h3);line-height:1.1;margin-bottom:10px}
#hs-form-mount .hsfc-Row--intro-hidden{display:none!important;margin:0}
/* Structural version of the same thing, so the duplicated intro never flashes
   before the observer runs. Scoped to rows inside the <form>, which the
   post-submit step is not. */
#hs-form-mount form .hsfc-Row:has([data-hsfc-id="RichText"]){display:none;margin:0}
#hs-form-mount .hsfc-Step__Content>.hsfc-Row:first-child:not(:has(input)):not(:has(select)):not(:has(textarea)){
  display:none;margin:0}
#hs-form-mount [data-hsfc-id="FormWrapper"],
#hs-form-mount [data-hsfc-id="Form"]{background:transparent;border:0;padding:0;margin:0}
/* Their Step__Content carries the form background padding and, at some widths,
   a width:50% rule. Both fight the modal's own padding and leave the fields
   inset from the heading above them. */
#hs-form-mount .hsfc-Step__Content{width:100%;padding:0;max-width:none}
#hs-form-mount [data-hsfc-id="Step"]{padding:0;margin:0}
#hs-form-mount [data-hsfc-id="Renderer"]{--hsf-default-background__padding:0;--hsf-background__padding:0}

/* ---- labels ---- */
/* HubSpot puts the label text in a bare <span> inside the <label> and sets a
   colour on that span, so colouring the label alone leaves black-on-graphite.
   Measured: 1.34:1 before this rule. */
#hs-form-mount .hsfc-FieldLabel,
#hs-form-mount .hsfc-FieldLabel span{
  font-family:var(--f-text);font-weight:700;text-transform:uppercase;letter-spacing:.05em;
  font-size:.68rem;color:rgba(255,255,250,.72)}
#hs-form-mount .hsfc-FieldLabel{margin-bottom:7px;display:block}
/* The label text arrives as <span style="color:#000000"> — inline black baked
   in by HubSpot's form editor, so only !important reaches it. This selector is
   generic on purpose: any field Britt adds later inherits the fix. */
#hs-form-mount .hsfc-FieldLabel span:not(.hsfc-FieldLabel__RequiredIndicator){
  color:rgba(255,255,250,.72)!important;font-size:inherit}
#hs-form-mount .hsfc-FieldLabel__RequiredIndicator,
#hs-form-mount .hsfc-FieldLabel span.hsfc-FieldLabel__RequiredIndicator{
  color:var(--sand);margin-left:.25em}

/* ---- text, email, textarea ---- */
#hs-form-mount .hsfc-TextInput,
#hs-form-mount .hsfc-TextareaInput{
  font-family:var(--f-text);font-size:.98rem;color:var(--ivory);
  background:transparent;border:0;border-bottom:1px solid var(--line-light);
  border-radius:0;padding:9px 0;width:100%;
  -webkit-appearance:none;appearance:none;box-shadow:none;
  transition:border-color var(--dur-int) var(--ease)}
#hs-form-mount .hsfc-TextInput:focus,
#hs-form-mount .hsfc-TextareaInput:focus{outline:0;border-bottom-color:var(--sand);box-shadow:none}
#hs-form-mount .hsfc-TextareaInput{resize:vertical;min-height:76px}
#hs-form-mount .hsfc-TextInput::placeholder,
#hs-form-mount .hsfc-TextareaInput::placeholder{color:rgba(255,255,250,.34)}
/* Chrome autofill repaints the field white and undoes the underline treatment */
#hs-form-mount .hsfc-TextInput:-webkit-autofill{
  -webkit-text-fill-color:var(--ivory);
  -webkit-box-shadow:0 0 0 1000px var(--graphite) inset;
  caret-color:var(--ivory)}

/* ---- the custom dropdown ---- */
#hs-form-mount .hsfc-DropdownInput{
  background:transparent;border:0;border-bottom:1px solid var(--line-light);border-radius:0;
  padding:9px 0;color:var(--ivory);font-family:var(--f-text);font-size:.98rem}
#hs-form-mount .hsfc-DropdownInput:focus-within{border-bottom-color:var(--sand)}
#hs-form-mount .hsfc-DropdownInput__Caret{color:var(--sand)}
#hs-form-mount .hsfc-DropdownInput__Caret svg{fill:var(--sand);stroke:var(--sand)}
#hs-form-mount .hsfc-DropdownInput__Caret *{color:var(--sand)}
#hs-form-mount .hsfc-TextInput--button{
  background:transparent;border:0;color:var(--ivory);padding:0;text-align:left}
#hs-form-mount .hsfc-DropdownOptions{
  background:var(--graphite);border:1px solid var(--line-gold);border-radius:0;
  color:var(--ivory);font-family:var(--f-text)}
#hs-form-mount .hsfc-DropdownOptions__List__ListItem{
  color:var(--ivory);font-size:.95rem;background:transparent}
#hs-form-mount .hsfc-DropdownOptions__List__ListItem:hover,
#hs-form-mount .hsfc-DropdownOptions__List__ListItem[aria-selected="true"]{
  background:rgba(200,170,110,.16);color:var(--ivory)}
#hs-form-mount .hsfc-DropdownOptions__Search input{
  background:transparent;color:var(--ivory);border:0;border-bottom:1px solid var(--line-light)}

/* ---- checkboxes and radios ---- */
#hs-form-mount .hsfc-CheckboxFieldGroup__Options,
#hs-form-mount .hsfc-RadioFieldGroup__Options{
  display:flex;flex-wrap:wrap;gap:10px 22px;padding-top:4px}
#hs-form-mount .hsfc-CheckboxFieldGroup__Options .hsfc-FieldLabel,
#hs-form-mount .hsfc-RadioFieldGroup__Options .hsfc-FieldLabel{
  display:flex;align-items:center;gap:9px;text-transform:none;letter-spacing:0;
  min-height:44px;padding-inline:10px;margin-inline:-10px;margin-bottom:0;
  font-weight:400;font-size:.95rem;color:rgba(255,255,250,.84);cursor:pointer}
#hs-form-mount .hsfc-CheckboxFieldGroup__Options .hsfc-FieldLabel span,
#hs-form-mount .hsfc-RadioFieldGroup__Options .hsfc-FieldLabel span,
#hs-form-mount .hsfc-CheckboxFieldGroup__Options .hsfc-FieldLabel span:not(.hsfc-FieldLabel__RequiredIndicator),
#hs-form-mount .hsfc-RadioFieldGroup__Options .hsfc-FieldLabel span:not(.hsfc-FieldLabel__RequiredIndicator){
  text-transform:none;letter-spacing:0;font-weight:400;font-size:.95rem;
  color:rgba(255,255,250,.84)!important}
#hs-form-mount .hsfc-CheckboxInput,
#hs-form-mount .hsfc-RadioInput{
  -webkit-appearance:auto;appearance:auto;width:16px;height:16px;
  accent-color:var(--sand);border:0;padding:0;margin:0;flex:0 0 auto;background:transparent}

/* ---- submit ---- */
#hs-form-mount .hsfc-NavigationRow{margin-top:clamp(24px,3vw,34px)}
#hs-form-mount .hsfc-NavigationRow__Buttons{display:block}
#hs-form-mount .hsfc-Button{
  display:inline-flex;align-items:center;justify-content:center;gap:.6em;
  font-family:var(--f-text);font-weight:700;text-transform:uppercase;letter-spacing:.05em;
  font-size:.8rem;line-height:1;padding:18px 32px;border-radius:2px;border:0;
  min-height:48px;width:100%;cursor:pointer;
  background:var(--sand);color:var(--graphite);box-shadow:none;
  transition:background var(--dur-int) var(--ease),color var(--dur-int) var(--ease)}
#hs-form-mount .hsfc-Button:hover{background:var(--ivory);color:var(--graphite)}
#hs-form-mount .hsfc-Button{white-space:nowrap;padding-inline:clamp(16px,4vw,32px)}

/* ---- errors ---- */
#hs-form-mount .hsfc-ErrorAlert,
#hs-form-mount [data-hsfc-id="ErrorAlert"]{
  font-family:var(--f-detail);font-style:italic;font-size:.76rem;color:var(--sand)}

/* ---- reCAPTCHA: cannot be restyled, so give it room and centre it ---- */
#hs-form-mount .hsfc-ReCaptchaV2{margin-top:clamp(16px,2vw,22px);display:flex;justify-content:center}
/* Google renders the widget in its own iframe, so its white ground cannot be
   themed from here. A hairline stops it reading as a hole in the panel. */
#hs-form-mount .hsfc-ReCaptchaV2 iframe{border:1px solid var(--line-gold)}
#hs-form-mount .hsfc-ReCaptchaV2>div{max-width:100%;overflow:hidden}

/* ---- rows: two up on desktop, stacked on a phone ---- */
#hs-form-mount .hsfc-Row{display:flex;gap:clamp(16px,2vw,24px);margin-bottom:clamp(16px,2vw,24px)}
#hs-form-mount .hsfc-Row>*{flex:1 1 0;min-width:0}
@media (max-width:560px){
  #hs-form-mount .hsfc-Row{flex-direction:column}
}

/* ==========================================================================
   Trust strip carousel (Britt, markup 1). Replaces the scroll-linked drift.
   Desktop only: below 900px the rows still stack as a grid, which is what
   Jacob asked for on 24 Aug and Britt agreed to. See the JS at 4b.
   ========================================================================== */
@keyframes firm-marquee{
  from{transform:translate3d(0,0,0)}
  to{transform:translate3d(-50%,0,0)}
}
@media (min-width:1px){
  .firms{overflow:hidden}
  .firm-row{width:max-content;max-width:none;flex-wrap:nowrap;
    justify-content:flex-start;gap:0;padding-inline:0;
    animation:firm-marquee var(--mq,60s) linear infinite;
    will-change:transform}
  /* the two lines run opposite, which is the part Britt wanted kept */
  .firm-row[data-drift="-1"]{animation-direction:reverse}
  /* the gap rides on each mark, not on the row: flex gap puts the loop
     point half a gap out and the strip jumps once per cycle */
  /* .firm carries width:9.5% from the base rule. A percentage inside a
     width:max-content track has nothing to resolve against, so the row
     measured ~200px and the builder cloned eight sets to fill it. A viewport
     unit gives every mark a definite width and the measurement comes out right. */
  .firm-row .firm{width:clamp(96px,8vw,128px);margin-right:clamp(24px,2.8vw,44px)}
  .firm-row .firm:first-child,.firm-row .firm:last-child{justify-content:center}
  /* let someone stop it to actually read a name */
  .firms:hover .firm-row,.firm-row:focus-within{animation-play-state:paused}
}
@media (prefers-reduced-motion:reduce){
  .firm-row{animation:none}
}

/* ==========================================================================
   PHASE 2 — SITE NAVIGATION
   Four flat links, no dropdown. Doc §6: a dropdown over four items is
   furniture, not navigation. Active state is a Sand hairline on the type
   baseline, driven by body[data-page] so the partial is byte-identical on
   every page.
   ========================================================================== */
.nav-in{display:grid;grid-template-columns:auto 1fr auto;align-items:center;
  gap:clamp(20px,3vw,44px)}

.nav-links{display:flex;justify-content:center;gap:clamp(18px,2.4vw,38px)}
.nav-links a{position:relative;font-family:var(--f-text);font-weight:700;
  text-transform:uppercase;letter-spacing:.05em;font-size:var(--t-eyebrow);
  color:rgba(255,255,250,.72);text-decoration:none;white-space:nowrap;
  padding-block:6px;min-height:44px;display:inline-flex;align-items:center;
  transition:color var(--dur-int) var(--ease)}
.nav-links a:hover{color:var(--ivory)}
/* the hairline sits on the baseline, not under the box */
.nav-links a::after{content:"";position:absolute;left:0;right:0;bottom:calc(50% - .78em);
  height:1px;background:var(--sand);opacity:0;
  transition:opacity var(--dur-int) var(--ease)}
body[data-page="mass-tort"] .nav-links a[data-nav="mass-tort"],
body[data-page="demands"]   .nav-links a[data-nav="demands"],
body[data-page="resources"] .nav-links a[data-nav="resources"],
body[data-page="about"]     .nav-links a[data-nav="about"]{color:var(--ivory)}
body[data-page="mass-tort"] .nav-links a[data-nav="mass-tort"]::after,
body[data-page="demands"]   .nav-links a[data-nav="demands"]::after,
body[data-page="resources"] .nav-links a[data-nav="resources"]::after,
body[data-page="about"]     .nav-links a[data-nav="about"]::after{opacity:1}

.nav-right{display:flex;align-items:center;gap:14px;justify-self:end}
.nav-right .btn{text-decoration:none}

/* burger: desktop hides it entirely, no hamburger above the breakpoint */
.nav-burger{display:none;width:44px;height:44px;padding:0;background:none;border:0;
  cursor:pointer;flex-direction:column;justify-content:center;gap:5px;align-items:center}
.nav-burger span{display:block;width:24px;height:2px;background:var(--ivory);
  transition:transform var(--dur-int) var(--ease),opacity var(--dur-int) var(--ease)}
.nav-burger[aria-expanded="true"] span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.nav-burger[aria-expanded="true"] span:nth-child(2){opacity:0}
.nav-burger[aria-expanded="true"] span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}

/* full-height Graphite panel; Aaron approved the mobile treatment, so this
   extends it rather than redesigning it */
.nav-panel{position:fixed;inset:0;top:0;z-index:99;background:var(--graphite);
  padding:calc(var(--nav-h,84px) + clamp(28px,7vh,64px)) var(--gutter) var(--gutter);
  overflow-y:auto}
.nav-panel nav{display:flex;flex-direction:column;gap:clamp(18px,3.4vh,30px)}
.nav-panel a{font-family:var(--f-display);font-weight:400;font-size:var(--t-h3);
  line-height:1.1;color:var(--ivory);text-decoration:none;
  padding-block:6px;border-bottom:1px solid var(--line-light)}
.nav-panel a:last-child{border-bottom:0}
.nav-panel .nav-panel-cta{color:var(--sand);font-family:var(--f-text);font-weight:700;
  text-transform:uppercase;letter-spacing:.05em;font-size:var(--t-eyebrow);
  margin-top:clamp(10px,2vh,20px)}
body.nav-open{overflow:hidden}

@media (max-width:900px){
  .nav-links{display:none}
  .nav-burger{display:flex}
  .nav-in{grid-template-columns:auto 1fr}
  .nav-logo{width:clamp(150px,42vw,200px)}
}
@media (min-width:901px){
  .nav-panel{display:none!important}
}

/* ---- footer links row ---- */
.foot-links{display:flex;flex-wrap:wrap;gap:clamp(12px,1.8vw,28px);align-items:center}
.foot-links a{font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:var(--t-eyebrow);color:rgba(255,255,250,.72);
  text-decoration:none;min-height:44px;display:inline-flex;align-items:center;
  transition:color var(--dur-int) var(--ease)}
.foot-links a:hover{color:var(--ivory)}

/* Doc §7: --t-h1-hero is the homepage's one 80px moment. Interior pages,
   including the re-homed Mass Tort page, open one tier down. */
.hero h1.hero-h--interior{font-size:var(--t-h1)}

/* ==========================================================================
   PHASE 2 — HOMEPAGE
   Only two new blocks: the fork and the through-line. Everything else on the
   page is the approved treatments reused.
   ========================================================================== */

/* ---- the fork ----
   Doc §7 Page 1: two panels, asymmetric, not two equal cards. Master §3 bans
   three-cards-with-icons and two equal cards is the same instinct. So: a
   stacked editorial split with Mass Tort at full scale and Demands beneath at
   reduced scale, separated by a hairline rather than boxed. No border, no
   radius, no shadow — the client rejected that treatment on the compliance
   section and it has not become acceptable since. */
.fork-list{margin-top:clamp(40px,5vw,72px);display:grid;gap:0}
.fork-item{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(10px,1.2vw,16px);
  padding-block:clamp(34px,4.4vw,60px)}
.fork-item + .fork-item{border-top:1px solid var(--line)}
.fork-label{font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:var(--t-eyebrow);color:var(--accent)}
.fork-head{font-family:var(--f-display);font-weight:400;line-height:1.08;
  font-size:var(--t-h2);max-width:20ch;color:var(--fg)}
.fork-lead{font-family:var(--f-text);font-size:var(--t-body);color:var(--soft);max-width:58ch}
.fork-caps{list-style:none;margin:clamp(6px,0.8vw,12px) 0 0;padding:0;
  display:grid;gap:9px;max-width:56ch}
.fork-caps li{position:relative;padding-left:22px;font-family:var(--f-text);
  font-size:var(--t-small);color:var(--soft)}
/* a rotated square, the page's own bullet. Not an icon set. */
.fork-caps li::before{content:"";position:absolute;left:0;top:.52em;width:6px;height:6px;
  background:var(--accent);transform:rotate(45deg)}
.fork-link{margin-top:clamp(8px,1vw,14px);justify-self:start}

/* Mass Tort leads: it is the strategic priority and the funded line. The scale
   difference is the whole point of the asymmetry, so it is a type-size step,
   not a colour or a box. */
.fork-item--lead .fork-head{font-size:var(--t-h3);max-width:24ch}
.fork-item--lead .fork-lead{font-size:var(--t-lead)}

@media (min-width:900px){
  .fork-item{grid-template-columns:minmax(0,7fr) minmax(0,5fr);
    column-gap:clamp(32px,4vw,72px);align-items:start}
  .fork-label{grid-column:1/-1}
  .fork-head{grid-column:1}
  .fork-lead{grid-column:2;grid-row:2/4}
  .fork-caps{grid-column:1}
  .fork-link{grid-column:1}
}

/* ---- the through-line ---- */
.thru-head .eyebrow,.thru-head h2{grid-column:1/9}
.thru-chain{margin-top:clamp(40px,5vw,72px);display:grid;gap:clamp(30px,3.6vw,52px)}
.thru-chain .node-b{max-width:64ch}

/* The product heroes are three clipped lines that must hold their breaks, so
   the hero h1 inherits white-space:nowrap. The homepage carries the brand
   statement instead, which needs 1010px on one line inside a 744px column and
   was being cut by the art. Scoped to the homepage so the product pages keep
   their forced breaks. */
body[data-page="home"] .hero h1 span{white-space:normal;text-wrap:balance}

/* At 375 the row had 335px to place a 158px lockup, a 149px button and a 44px
   burger with two gaps: 365px of content. body{overflow-x:hidden} hid the
   overflow, so 29px of the menu button sat off-screen and unreachable rather
   than visibly broken. §6 requires the lockup and the button to stay visible on
   mobile, so nothing is dropped — the three just get sized to fit. */
@media (max-width:600px){
  .nav-in{gap:8px}
  .nav-logo{width:clamp(118px,34vw,140px)}
  .nav-right{gap:8px}
  .nav-right .btn{padding-inline:14px;font-size:.72rem}
  .nav-burger{width:40px}
}

/* ============================================================
   30 — LAYOUT DEVICES
   Phase 2 revision. The first pass gave every page the same
   silhouette: graphite hero, alternating light bands, dark CTA.
   Worse, two pages independently invented the same three-column
   row list. These are the sanctioned structures. Each page picks
   ONE as its signature; no device appears on two pages.
   ============================================================ */

/* ---- shared: escape the wrap ---- */
.bleed{margin-inline:calc(var(--gutter) * -1)}
@media (min-width:1441px){
  /* .wrap is centred at 1440, so a true bleed needs the overflow too */
  .bleed{margin-inline:calc(50% - 50vw)}
}

/* ------------------------------------------------------------
   A — DUO   ·   signature of the HOMEPAGE fork
   Two panels, edge to edge, each carrying its own ground. The
   page forks in half where the products fork.
   ------------------------------------------------------------ */
.duo{display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(14px,1.8vw,28px);min-height:clamp(520px,58vw,680px)}
.duo-panel{position:relative;display:flex;flex-direction:column;min-width:0;
  padding:clamp(48px,6.6vw,96px) var(--duo-pad,clamp(36px,5.2vw,76px)) 0;
  transition:background var(--dur-int) var(--ease)}

.duo-label{font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:var(--t-eyebrow);color:var(--accent)}
/* Sand on Ocean measured 4.26:1, just under the 4.5 floor for label copy.
   Sea Glass is the accent that holds on the dark teal. */
.on-ocean .duo-label{color:var(--seaglass)}
.duo-head{font-family:var(--f-display);font-weight:400;font-size:var(--t-h3);
  line-height:1.1;letter-spacing:-.012em;margin-top:clamp(18px,2vw,26px);max-width:17ch}
.duo-lead{margin-top:clamp(16px,1.8vw,22px);color:var(--soft);max-width:42ch}
.duo-caps{margin-top:auto;padding-top:clamp(28px,3.4vw,44px)}
.duo-caps li{position:relative;padding:14px 0 14px 26px;font-size:var(--t-small);
  color:var(--soft);border-top:1px solid var(--line)}
.duo-caps li::before{content:"";position:absolute;left:0;top:1.35em;width:6px;height:6px;
  background:var(--accent);transform:rotate(45deg)}
.duo-foot{margin-top:clamp(26px,3vw,38px)}
/* Both panels set type at the same size. ARCHES-PHASE-2.md 177 asked for
   Mass Tort to lead at a larger scale, and this rule used to do that with
   --t-h1-sm on the head and --t-lead on the lead. It stopped reading as
   hierarchy once the fork became two equal cards: symmetric boxes with
   asymmetric type read as a mistake, which is exactly how Jacob read it on
   9 Sep. Priority now comes from order and from the Graphite ground.
   If the size differential comes back, the containers have to differ too. */
@media (max-width:900px){
  .duo{grid-template-columns:1fr;min-height:0;gap:clamp(12px,3vw,20px)}
}

/* ------------------------------------------------------------
   C — MARGINAL   ·   signature of /about
   Long-form editorial. A reading measure with short labels
   hanging in the left margin, and statements that break out.
   ------------------------------------------------------------ */
.marginal{margin-top:clamp(44px,5vw,72px);
  /* held to a reading column and centred. Left-hugging text in a 1296px field
     reads as an unfinished layout; a measure with margin reads as editorial. */
  max-width:calc(clamp(96px,11vw,168px) + clamp(20px,3vw,48px) + 66ch);
  margin-inline:auto}
.marg-block{display:grid;min-width:0;grid-template-columns:clamp(96px,11vw,168px) minmax(0,1fr);
  gap:clamp(20px,3vw,48px);align-items:start}
.marg-block + .marg-block{margin-top:clamp(38px,4.4vw,64px)}
.marg-key{font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:var(--t-eyebrow);color:var(--accent);
  padding-top:.42em;line-height:1.4}
.marg-text{min-width:0;max-width:66ch;font-size:var(--t-lead);line-height:1.6}
.marg-text p + p{margin-top:1.1em}
.marg-text strong{font-weight:400;font-family:var(--f-display);font-size:1.16em;letter-spacing:-.008em}
/* the breakout: one sentence at section-headline scale, full width */
.marg-say{margin-block:clamp(48px,5.6vw,84px);padding-block:clamp(32px,3.6vw,50px);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.marg-say p{font-family:var(--f-display);font-weight:400;font-size:var(--t-h1-sm);
  line-height:1.14;letter-spacing:-.016em;max-width:24ch}
.marg-say .marg-cite{display:block;margin-top:18px;font-family:var(--f-text);
  font-size:var(--t-small);letter-spacing:.04em;text-transform:uppercase;
  color:var(--faint);font-weight:700}
@media (max-width:760px){
  .marg-block{grid-template-columns:1fr;row-gap:10px}
  .marg-key{padding-top:0}
}

/* ------------------------------------------------------------
   D — INDEX   ·   signature of /resources
   A journal index, not a card grid. One lead item at scale,
   then hairline-ruled rows with aligned metadata columns.
   ------------------------------------------------------------ */
.idx-lead{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);
  gap:clamp(28px,4vw,64px);align-items:end;
  padding-bottom:clamp(36px,4.2vw,58px);border-bottom:2px solid var(--fg)}
.idx-lead-kind{font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:var(--t-eyebrow);color:var(--accent)}
.idx-lead-t{font-family:var(--f-display);font-weight:400;font-size:var(--t-h1-sm);
  line-height:1.08;letter-spacing:-.016em;margin-top:clamp(16px,1.8vw,24px)}
.idx-lead-d{margin-top:clamp(16px,1.8vw,22px);color:var(--soft);max-width:46ch}
.idx-lead-meta{font-size:var(--t-small);color:var(--faint);letter-spacing:.03em}
.idx-rows{margin-top:clamp(8px,1vw,16px)}
.idx-row{display:grid;min-width:0;
  grid-template-columns:clamp(74px,8vw,110px) minmax(0,1fr) max-content;
  gap:clamp(16px,2.4vw,40px);align-items:baseline;
  padding-block:clamp(20px,2.3vw,30px);border-bottom:1px solid var(--line);
  text-decoration:none;color:inherit;transition:padding-left var(--dur-int) var(--ease)}
.idx-row:hover{padding-left:12px}
.idx-kind{font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:var(--t-eyebrow);color:var(--accent)}
.idx-t{min-width:0;font-family:var(--f-display);font-weight:400;font-size:var(--t-h2);
  line-height:1.18;letter-spacing:-.008em}
.idx-row:hover .idx-t{text-decoration:underline;text-underline-offset:5px;
  text-decoration-thickness:1px;text-decoration-color:var(--accent)}
.idx-meta{font-size:var(--t-small);color:var(--faint);text-align:right;
  font-variant-numeric:tabular-nums;white-space:nowrap}
@media (max-width:820px){
  .idx-lead{grid-template-columns:1fr;align-items:start;row-gap:18px}
  .idx-row{grid-template-columns:1fr;row-gap:8px}
  .idx-meta{text-align:left}
}

/* ------------------------------------------------------------
   E — CONSOLE   ·   signature of /schedule
   Two columns that hold the full viewport: what happens next on
   the left, sticky; the form on the right.
   ------------------------------------------------------------ */
.console{display:grid;min-width:0;grid-template-columns:minmax(0,.85fr) minmax(0,1fr);
  gap:clamp(36px,5vw,96px);align-items:start}
.console-rail{position:sticky;top:clamp(96px,12vh,132px)}
.console-steps{margin-top:clamp(30px,3.4vw,46px)}
.console-steps li{display:grid;grid-template-columns:clamp(78px,8vw,112px) minmax(0,1fr);
  gap:clamp(16px,2vw,28px);padding-block:clamp(18px,2vw,26px);
  border-top:1px solid var(--line);font-size:var(--t-body);color:var(--soft)}
.console-steps li:last-child{border-bottom:1px solid var(--line)}
.console-steps li b{min-width:0;font-weight:400;font-family:var(--f-display);
  font-size:var(--t-h2);line-height:1.18;letter-spacing:-.008em;color:var(--fg);
  display:block;margin-bottom:8px}
.console-steps .cs-n{font-family:var(--f-text);text-transform:uppercase;
  letter-spacing:.05em;color:var(--accent);font-weight:700;
  font-size:var(--t-eyebrow);padding-top:.5em;line-height:1.4}
@media (max-width:900px){
  .console{grid-template-columns:1fr;gap:clamp(40px,6vw,64px)}
  .console-rail{position:static}
}

/* ------------------------------------------------------------
   F — STATEMENT   ·   a reusable band break
   One sentence at headline scale. Breaks a run of bands without
   pretending to be a section.
   ------------------------------------------------------------ */
.statement{padding-block:clamp(56px,6.4vw,96px)}
.statement p{font-family:var(--f-display);font-weight:400;font-size:var(--t-h1-sm);
  line-height:1.14;letter-spacing:-.016em;max-width:22ch}
.statement .st-side{margin-top:clamp(22px,2.6vw,32px);color:var(--soft);
  font-size:var(--t-body);max-width:44ch;font-family:var(--f-text)}
.statement--wide p{max-width:30ch}

/* ------------------------------------------------------------
   HERO VARIANTS — so four heroes are not one hero
   ------------------------------------------------------------ */
/* short masthead: a nameplate, not a hero. /resources */
.masthead{min-height:0;padding-block:clamp(96px,10vw,152px) clamp(40px,4.4vw,64px);
  display:block}
.masthead-in{display:grid;grid-template-columns:minmax(0,1fr) auto;
  gap:clamp(24px,4vw,64px);align-items:end;
  padding-bottom:clamp(26px,3vw,40px);border-bottom:1px solid var(--line)}
.masthead h1{font-family:var(--f-display);font-weight:400;font-size:var(--t-h1);
  line-height:1.04;letter-spacing:-.02em;margin-top:clamp(18px,2.2vw,30px);max-width:18ch}
.masthead-count{font-size:var(--t-body);color:var(--soft);max-width:34ch;
  padding-bottom:.35em}
@media (max-width:700px){.masthead-in{grid-template-columns:1fr;align-items:start;row-gap:16px}}

/* type-only hero, no void. /about */
.hero--type{min-height:0;padding-block:clamp(104px,11vw,168px) clamp(60px,6.4vw,96px);
  display:block}
.hero--type h1{max-width:15ch}
.hero--type .hero-note{display:grid;
  grid-template-columns:minmax(0,1fr) auto;gap:clamp(24px,4vw,64px);
  margin-top:clamp(38px,4.4vw,60px);padding-top:clamp(28px,3.2vw,42px);
  border-top:1px solid var(--line);align-items:start}
.hero--type .hero-note p{color:var(--soft);max-width:58ch;font-size:var(--t-lead)}
.hero--type .hero-note .hn-tag{white-space:nowrap;padding-top:.5em}
.hero--type .hero-note .hn-tag{font-family:var(--f-text);font-weight:700;
  text-transform:uppercase;letter-spacing:.05em;font-size:var(--t-eyebrow);
  color:var(--accent)}
@media (max-width:760px){.hero--type .hero-note{grid-template-columns:1fr;row-gap:18px}}


/* ------------------------------------------------------------
   TRUST STRIP — nine real firms, two rows running opposite.
   A static set stood here briefly. It also carried
   `.firm-row{display:none}` above 861px, which hid the marquee on
   every page that had no static list -- /mass-tort rendered the
   label with nothing beneath it. Removed 17 Sep; the carousel in
   section "TRUST MARQUEE" and its builder in the JS at 4b are the
   only treatment now.
   ------------------------------------------------------------ */

/* ------------------------------------------------------------
   G — TRIPTYCH   ·   the homepage through-line
   The one horizontal band on a site that is otherwise vertical.
   Hairline-divided columns, no boxes: the three-card treatment
   the client rejected is a border + radius + shadow, which this
   deliberately has none of.
   ------------------------------------------------------------ */
.triptych{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  margin-top:clamp(44px,5.2vw,76px);border-top:1px solid var(--line)}
.tri-col{min-width:0;padding:clamp(30px,3.4vw,48px) clamp(22px,2.6vw,40px) 0 0}
.tri-col + .tri-col{border-left:1px solid var(--line);
  padding-left:clamp(22px,2.6vw,40px)}
.tri-n{font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:var(--t-eyebrow);color:var(--accent)}
.tri-h{font-family:var(--f-display);font-weight:400;font-size:var(--t-h2);
  line-height:1.14;letter-spacing:-.01em;margin-top:clamp(14px,1.6vw,20px)}
.tri-b{margin-top:clamp(14px,1.6vw,20px);color:var(--soft);font-size:var(--t-body)}
@media (max-width:900px){
  .triptych{grid-template-columns:1fr;border-top:0}
  .tri-col{padding:clamp(26px,4vw,36px) 0 0;border-top:1px solid var(--line)}
  .tri-col + .tri-col{border-left:0;padding-left:0}
}

/* ------------------------------------------------------------
   31 — THE FORK, to Harvey density (8 Sep audit M1)
   Two lines and a button per panel. The product runs off the
   bottom of the panel rather than sitting in an inset card, so
   the interface is the largest thing in the panel and the copy
   is the smallest. The bullet lists are gone: Aaron called the
   fork "super language dense" and that is what they were.
   ------------------------------------------------------------ */
.duo{min-height:0}
.duo-panel{overflow:hidden;padding-bottom:0;min-height:clamp(620px,58vw,800px);
  --duo-pad:clamp(36px,5.2vw,76px)}
.duo-head{max-width:20ch;margin-top:clamp(22px,2.6vw,34px);text-wrap:balance}
.duo-lead{max-width:34ch;font-size:var(--t-body);line-height:1.6;
  margin-top:clamp(20px,2.2vw,30px);text-wrap:pretty}
.duo-foot{padding-top:clamp(30px,3.4vw,46px);
  padding-bottom:clamp(34px,4vw,56px)}
/* the outlined button reads quieter than solid Sand, which is right for a
   panel whose job is to route, not to close */
.duo-foot .btn{background:transparent;border:1px solid currentColor;color:var(--fg)}
.duo-foot .btn:hover{background:var(--fg);color:var(--graphite)}
.on-ocean .duo-foot .btn:hover{color:var(--ocean)}

/* THE CARD PHOTO, 14 Sep. This zone used to hold a cropped product mockup on
   an Ivory strip. Britt and Jacob, 14 Sep: the fork cards "can serve a purpose
   without having the actual product images attached," since the case-file
   section directly below already shows the product. Britt: pictures that
   "come in from the bottom right corner into the box."
   So the card is its textured ground top to bottom now -- the Ivory strip is
   gone -- and a photograph sits in the bottom-right corner, bleeding off the
   card's right and bottom edges. Generated interiors, no people (5.6b), each
   checked at full size for fake lettering on spines and paper. */
/* 17 Sep, Jacob: "let's make the images go all the way across the bottom.
   Maybe a tad thinner, some off the top. I don't like how they're in the
   bottom right corner." So the photograph is a band on the foot of the panel,
   bleeding off both edges rather than hanging in one corner, and 16:9 instead
   of 4:3 takes roughly a third off its height. The drop shadow went with the
   corner: a full-width band has no floating edge to cast one. */
.duo-photo{position:relative;margin:auto calc(var(--duo-pad) * -1) 0;
  width:calc(100% + var(--duo-pad) * 2);aspect-ratio:16 / 9;overflow:hidden;min-width:0}
.duo-photo img{width:100%;height:100%;object-fit:cover;display:block}
/* it rises into place now that it spans the foot, instead of arriving from a
   corner it no longer occupies */
.js .duo-photo.reveal{transform:translateY(26px)}
.js .duo-photo.reveal.in{transform:none}
@media (max-width:900px){
  .duo-panel{min-height:0}
  /* "Explore Arches Mass Tort" wrapped to two lines inside the button at 390 */
  .duo-foot .btn{padding-inline:18px;font-size:.74rem;letter-spacing:.04em}
  /* full width at every size now; nothing to narrow */
}

/* ------------------------------------------------------------
   32 — SHOWCASE (8 Sep audit C3)
   Aaron: the laptop mockup is "very 2016." Harvey shows product
   as a cropped UI panel bleeding off the frame edge. No device,
   no perspective, no shadow. Harvey's own container is rounded;
   ours is square -- 9 Sep, Jacob: "we don't have rounded cards
   anywhere else." The only radius on this site is the 2px on
   buttons, pills and status chips.
   ------------------------------------------------------------ */
.showcase{margin-top:clamp(56px,6.4vw,96px);padding-top:clamp(44px,5vw,72px);
  border-top:1px solid var(--line);min-width:0}
/* headline and lead sit side by side so the band opens to its full measure
   before the product arrives underneath it */
.showcase-copy{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(24px,4vw,72px);align-items:end}
.showcase-copy .eyebrow{grid-column:1/-1}
.showcase-copy h3{min-width:0;font-family:var(--f-display);font-weight:400;
  font-size:var(--t-h1-sm);line-height:1.1;letter-spacing:-.016em;
  margin-top:clamp(16px,1.8vw,24px);max-width:16ch}
.showcase-copy p{margin:0;color:var(--soft);max-width:48ch}
@media (max-width:900px){
  .showcase-copy{grid-template-columns:1fr;gap:clamp(16px,3vw,22px);align-items:start}
}

/* Rebuilt 9 Sep. This was a second cropped panel sitting beside its copy,
   which made three medium product cards on one page and gave the fork
   nothing to be bigger than. It is now the page's ONE full-size product
   moment: copy above, then the whole application at 1:1 across the full
   measure, cropped only by the bottom of the band. Sierra's pattern --
   the interface floats on a pale ground with a hairline and a cast
   shadow. No container tint, no perspective, no device. */
.showcase-ui{position:relative;margin:clamp(38px,4.4vw,64px) 0 0;min-width:0;
  overflow:hidden}
.showcase-ui .ui-frame{aspect-ratio:auto;height:clamp(400px,40vw,580px);
  max-height:none;background:var(--ivory);
  border:1px solid rgba(35,35,35,.12);border-bottom:0;
  box-shadow:0 -26px 60px rgba(35,35,35,.10)}
/* the app is authored at 1100px; centre it in the frame and hold 1:1 for as
   long as the measure allows, then step down rather than shrink to a thumbnail */
.showcase-ui .ui{--ui-s:1;left:50%;margin-left:-550px;transform-origin:top center}
@media (max-width:1180px){.showcase-ui .ui{--ui-s:.92}}
@media (max-width:1000px){.showcase-ui .ui{--ui-s:.82}}
@media (max-width:900px){
  .showcase-ui{margin-inline:calc(var(--gutter) * -1)}
  .showcase-ui .ui-frame{height:330px;border-radius:0;border-inline:0}
  /* centring the app is right when the frame is wider than it; on a phone it
     is not, so centring crops BOTH edges and you read the middle of a table.
     Anchor left instead, the same crop the fork panels use. */
  .showcase-ui .ui{--ui-s:.6;left:0;margin-left:0;transform-origin:top left}
}

/* ------------------------------------------------------------
   33 — INTERSTITIAL   ·   a full-bleed image band
   /about only. Breaks a long reading page without pretending to
   be a section: no headline, no CTA, one caption.
   ------------------------------------------------------------ */
.interstitial{padding:0;position:relative}
.interstitial figure{margin:0;position:relative;overflow:hidden;
  aspect-ratio:21/8;background:var(--graphite-deep)}
.interstitial img{width:100%;height:100%;object-fit:cover;opacity:.94}
.interstitial figcaption{position:absolute;left:0;right:0;bottom:0;
  padding:clamp(20px,2.6vw,34px) var(--gutter);
  font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:var(--t-eyebrow);color:var(--ivory);
  /* a flat scrim, not a gradient: §3 rules gradients out */
  background:rgba(27,27,27,.58)}
@media (max-width:760px){.interstitial figure{aspect-ratio:3/2}}

/* ---- the demand letter fragment. Home only; /demands shows the chronology
   and the citation table, so the output belongs here rather than a third
   copy of the same panel. Claimant, providers and page ranges fabricated. ---- */
.ui-letter{background:var(--ivory);border:1px solid rgba(35,35,35,.10);
  padding:15px 17px;font-size:12px;line-height:1.55;color:rgba(35,35,35,.78)}
.ui-letter .lh{display:flex;align-items:baseline;gap:8px;
  padding-bottom:9px;margin-bottom:11px;border-bottom:1px solid rgba(35,35,35,.12)}
.ui-letter .lh b{font-family:var(--f-display);font-weight:400;font-size:14px;
  color:var(--graphite);letter-spacing:.01em}
.ui-letter .lh span{margin-left:auto;font-size:10.5px;letter-spacing:.04em;
  text-transform:uppercase;color:rgba(35,35,35,.46);font-weight:700}
.ui-letter p + p{margin-top:9px}
.ui-letter .cite{color:var(--ocean);font-weight:700;
  text-decoration:underline;text-underline-offset:2px;
  text-decoration-color:rgba(0,111,129,.42)}

/* ---- a letter page fragment. /resources featured lead. Portrait, so it
   reads as a document rather than as an interface. ---- */
.ui-page{background:var(--ivory);border:1px solid rgba(35,35,35,.12);
  padding:clamp(18px,2vw,26px) clamp(18px,2vw,26px) 0;
  aspect-ratio:17/22;overflow:hidden;font-size:11.5px;line-height:1.6;
  color:rgba(35,35,35,.72)}
.ui-page .pg-h{font-family:var(--f-display);font-weight:400;font-size:15px;
  color:var(--graphite);letter-spacing:.01em;
  padding-bottom:10px;margin-bottom:12px;border-bottom:1px solid rgba(35,35,35,.14)}
.ui-page .pg-s{font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:9.5px;color:rgba(35,35,35,.46);
  margin-top:14px;margin-bottom:6px}
.ui-page p{margin-bottom:8px}
.ui-page .cite{color:var(--ocean);font-weight:700}
/* the page runs off the bottom of its frame, the way a page does */
.ui-page .pg-fade{height:56px}

.idx-lead-fig{margin:0;max-width:300px;justify-self:end;width:100%}
@media (max-width:820px){.idx-lead-fig{justify-self:start;max-width:240px}}

/* ------------------------------------------------------------
   34 — ARCH FIELD   ·   /about, the three principles
   Three principles, three nested arches. The brand's own
   ornament framing the content rather than sitting beside it,
   which is the rule Jacob set when the architectural photo
   bands were pulled for reading as random.
   Hairlines only, well under text contrast, and behind content
   at z-index 0 so nothing competes with the copy.
   ------------------------------------------------------------ */
.arch-field{position:absolute;left:50%;top:clamp(74px,8vw,124px);
  transform:translateX(-50%);width:min(1180px,92%);height:auto;
  z-index:0;pointer-events:none;color:var(--graphite);opacity:.13}
.arch-field [data-draw]{stroke:currentColor;stroke-width:1;fill:none;
  vector-effect:non-scaling-stroke}
.arch-field .dm{fill:var(--ocean);stroke:none;opacity:.55}
.has-arch-field > .wrap{position:relative;z-index:1}
@media (max-width:900px){.arch-field{display:none}}


/* ============================================================
   35 — THE ARCH BEING RAISED
   Recovered from the v3-aug23 engine section. Six voussoirs and
   a keystone: the arch only stands when every stone is in place,
   which is the argument the product makes. Stones are drawn
   faintly from the start so you can see what has to arrive, then
   set as the section travels. Scroll is the only driver; there
   is nothing to click and nothing is announced.
   ============================================================ */
.arch-raise{margin-inline:auto;
  max-width:min(100%,720px,calc((100svh - 300px) * 1.39))}
.arch-raise-svg{width:100%;height:auto;display:block;overflow:visible}
/* every stone is drawn from the start, so what has to be in place is visible
   before any of it is */
.arch-raise-svg .vs{fill:none;stroke:var(--accent);stroke-width:1;
  vector-effect:non-scaling-stroke;opacity:.16;
  transition:opacity .55s var(--ease)}
.arch-raise-svg .vs.set{opacity:.95}
.arch-raise-svg .vs.key.set{stroke-width:1.8}
/* the extrusion: the arch has thickness, and only a set stone shows it */
.arch-raise-svg .vs-back,.arch-raise-svg .vs-side{fill:none;stroke:var(--accent);
  stroke-width:1;vector-effect:non-scaling-stroke;opacity:0;
  transition:opacity .55s var(--ease)}
.arch-raise-svg .vs-back.set{opacity:.26}
.arch-raise-svg .vs-side.set{opacity:.46}
.arch-raise-svg .vs-joint{stroke:var(--accent);stroke-width:1;
  vector-effect:non-scaling-stroke;opacity:0;transition:opacity .55s var(--ease)}
.arch-raise-svg .vs-joint.set{opacity:.42}
.arch-raise-svg .vs-dot{fill:var(--accent);opacity:0;
  transition:opacity .45s var(--ease)}
.arch-raise-svg .vs-dot.set{opacity:.95}
.arch-raise-svg .vs-pier,.arch-raise-svg .vs-plinth{stroke:var(--accent);fill:none;
  stroke-width:1;vector-effect:non-scaling-stroke;opacity:.3}
.arch-raise-svg .vs-pier.back{opacity:.14}

/* reduced motion, and the no-JS case: the arch simply stands */
@media (prefers-reduced-motion:reduce){
  .arch-raise-svg .vs{opacity:.95}
  .arch-raise-svg .vs-back{opacity:.26}
  .arch-raise-svg .vs-side{opacity:.46}
  .arch-raise-svg .vs-joint{opacity:.42}
  .arch-raise-svg .vs-dot{opacity:.95}
}

/* the band the arch sits in, on both pages that carry it */
.arch-raise-band{margin-top:clamp(40px,4.6vw,72px)}
.arch-sect .arch-raise-band{margin-top:clamp(30px,3.4vw,52px)}
body[data-page="demands"] .arch-raise-band{margin-bottom:clamp(44px,5vw,76px)}
body[data-page="demands"] .arch-raise{max-width:min(100%,560px)}

/* ---- the seven lines the arch carries. Recovered with the build; these are
   the v3 styles, re-scoped from .vsr-stage to .arch-raise. ---- */
.arch-raise-svg .vs-hit{fill:transparent;stroke:none;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.arch-raise-svg .vs-hit:focus{outline:none}
.arch-raise-svg .vs-hit:focus-visible{outline:2px solid var(--seaglass);outline-offset:2px}
.vsr-read{max-width:min(100%,620px);margin:clamp(26px,3vw,44px) auto 0;text-align:center;
  transition:opacity .3s var(--ease)}
/* before the first stone there is nothing to read, so the panel holds its height
   rather than popping the layout when the copy arrives */
.arch-raise.pre .vsr-read{opacity:0}
.vsr-step-n{font-family:var(--f-text);font-weight:700;font-size:10.5px;
  letter-spacing:.16em;color:var(--accent)}
.vsr-title{font-family:var(--f-display);font-weight:400;
  font-size:clamp(1.5rem,2.6vw,2.15rem);line-height:1.15;letter-spacing:-.01em;
  color:var(--fg);margin-top:clamp(10px,1.2vw,16px)}
.vsr-body{font-family:var(--f-text);font-size:var(--t-body);line-height:1.6;
  color:var(--soft);margin-top:clamp(10px,1.2vw,16px);min-height:4.8em}
.vsr-steps{display:flex;justify-content:center;gap:10px;margin-top:clamp(18px,2vw,28px)}
.vs-step{position:relative;width:9px;height:9px;padding:0;
  border:1px solid rgba(200,170,110,.55);background:transparent;
  transform:rotate(45deg);cursor:pointer;
  transition:background-color .3s var(--ease),border-color .3s var(--ease)}
/* 9px is the mark, not the target: the hit area is expanded past the paint so a
   coarse pointer still clears 44px without growing the diamond */
.vs-step::after{content:"";position:absolute;inset:-13px}
@media (pointer:coarse){
  .vsr-steps{gap:20px}
  .vs-step{width:12px;height:12px}
  .vs-step::after{inset:-16px}
}
.vs-step.on{background:var(--accent);border-color:var(--accent)}
.vs-step:focus-visible{outline:2px solid var(--seaglass);outline-offset:3px}

/* ---- the same line marks as the /mass-tort certifications row, reused where a
   section is three abstract statements with nothing to look at. Same 72x72 grid,
   same 1px non-scaling stroke, same Art Deco geometry: fan, stepped setback,
   sunburst, chevron column. Nothing here is asked to mean anything literal. ---- */
.tri-mark,.prin-mark{width:clamp(56px,5.2vw,76px);height:auto;display:block;
  color:var(--accent);overflow:visible}
.tri-mark .s,.prin-mark .s{fill:none;stroke:currentColor;stroke-width:1;
  vector-effect:non-scaling-stroke;stroke-linecap:square}
.tri-mark{margin-bottom:clamp(16px,1.8vw,24px)}
.prin-mark{margin-bottom:clamp(14px,1.6vw,20px)}
@media (max-width:900px){.tri-mark,.prin-mark{width:56px}}

/* the homepage carries its own plates in the hero panels, not /mass-tort's */
body[data-page="home"] .arch-photo{background-image:url("/assets/img/hero-record.jpg")}
body[data-page="home"] .arch-photo picture,
body[data-page="home"] .arch-photo img{display:block;width:100%;height:100%;object-fit:cover}
body[data-page="home"] .hero-figure img{width:100%;height:100%;object-fit:cover}

/* .arch-photo paints hero-poster.jpg as a container background so the frame
   survives the video being pulled under reduced motion. /demands carries its own
   plate, so it needs its own background and its picture has to fill the box --
   the same bleed that showed a strip of the /mass-tort corridor on the homepage. */
.dm-arch-photo{background-image:url("/assets/img/dm-arch.jpg")}
.dm-arch-photo picture,.dm-arch-photo img{display:block;width:100%;height:100%;object-fit:cover}

/* .ben-n and .ben-t hardcode Ocean and Graphite, which was safe while .ben-row
   only ever sat on Ivory or Stone. /demands now runs a .ben-row on the Ocean
   band, where Graphite type is unreadable and an Ocean label is invisible.
   Handed to the ground's own tokens. Scoped to .on-ocean, so /mass-tort and
   /about are untouched. */
.on-ocean .ben-n{color:var(--accent)}
.on-ocean .ben-t{color:var(--fg)}
.on-ocean .ben-lead .body{color:var(--soft)}

/* ============================================================
   36 — /about, rebuilt 8 Sep
   Britt: "I don't feel like I have a wireframe for the about
   section to start writing... just underwhelmed by the layout."
   The origin is a numbered run against a held visual rather
   than a column of prose with labels in the margin.
   ============================================================ */
.origin{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
  gap:clamp(32px,4.5vw,88px);align-items:start;
  margin-top:clamp(44px,5vw,76px);min-width:0}
/* 12 Oct, Jacob: "I wonder if we center it better instead."
   The plate used to be sticky and pinned to the top of the column. That was
   right while it was a 4:5 portrait roughly as tall as the prose beside it.
   Now it is 16:10 and about half that height, so pinning it to the top left
   roughly 340px of dead column underneath. Centred against the prose instead:
   the space splits evenly above and below and the two columns read as a pair.
   Sticky comes off -- a centred element cannot also be pinned. */
.origin-vis{align-self:center;min-width:0}
/* material, not another water frame -- the coastline is already the band directly
   above this and two of them back to back read as one image repeated */
/* 21 Sep, Jacob: the stacked-paper plate "feels cut off weird at the top,
   almost like it's at an angle" -- the page edges ran diagonally out of frame.
   Now 106 from the library: someone at a window with a laptop, from behind. */
/* markup #66, Britt: "Frame this photo with the art deco lines, increase the
   drop shadow... frame around the outside like we have on the product images
   and carrot the edges slightly." Offset Ocean hairline behind, a deeper cast
   shadow, and the same 3px edge the collage took in #94.
   12 Oct: the photograph landed. Easton & Easton outside the office, the four
   of them under the arcade -- which is the thing the brand is named after, so
   it does more work here than any studio portrait would. #66 is closed.
   The plate was 4:5. The photograph is 1.66:1 and the four of them span nearly
   the whole frame, so a portrait crop would have cut two men out. The plate is
   16:10 now and the source is cropped 30px a side, which touches no one.
   Sized for the plate exactly: 523 CSS wide at 2x wants 1046, the file is 1600. */
.origin-vis{isolation:isolate}  /* position/centring is set once, above */
/* 12 Oct, Jacob: "Swap the images on Demands and About, the walking and the
   office one." So the plate takes the walking shot and /demands takes the four
   under the arcade. Ratio follows the photograph: 755/554 is the walking shot's
   native frame, used whole rather than cropped. */
.origin-plate{aspect-ratio:755/554;background:var(--graphite-deep) center/cover no-repeat;
  /* the real photograph is detailed glass and suiting, so it costs more as a
     JPEG than the generated plate it replaces: 218K against 130K. The plate is
     a CSS background, so <picture> cannot serve the WebP -- image-set can, at
     82K. The plain url() stays first as the fallback, so a browser that does
     not know image-set simply keeps today's behaviour. */
  background-image:url("/assets/img/about-origin.jpg");
  background-image:image-set(url("/assets/img/about-origin.webp") type("image/webp"),
                             url("/assets/img/about-origin.jpg") type("image/jpeg"));
  position:relative;border-radius:3px;
  box-shadow:0 26px 56px rgba(20,19,17,.30)}
.origin-plate::before{content:"";position:absolute;z-index:-1;pointer-events:none;
  inset:clamp(12px,1.3vw,20px) calc(-1 * clamp(12px,1.3vw,20px))
        calc(-1 * clamp(12px,1.3vw,20px)) clamp(12px,1.3vw,20px);
  border:1px solid var(--ocean);border-radius:3px}
.origin-list{counter-reset:og;min-width:0}
.origin-list li{padding-block:clamp(26px,3vw,42px);border-top:1px solid var(--line);
  min-width:0}
.origin-list li:last-child{border-bottom:1px solid var(--line)}
.origin-list .on{font-family:var(--f-text);font-weight:700;font-size:var(--t-eyebrow);
  letter-spacing:.05em;color:var(--accent)}
.origin-list h3{font-family:var(--f-display);font-weight:400;font-size:var(--t-h2);
  line-height:1.16;letter-spacing:-.01em;margin-top:clamp(10px,1.2vw,15px);max-width:24ch}
.origin-list p{margin-top:clamp(10px,1.2vw,15px);color:var(--soft);max-width:52ch}
@media (max-width:900px){
  .origin{grid-template-columns:1fr;row-gap:clamp(28px,4vw,40px)}
}

/* the disciplines. Three columns of type, hairline separated, no icons and no
   cards -- §3 bans icon + heading + white card + shadow, which this is not. */
/* 21 Sep, Jacob: "images and heights should be the same here." They were not:
   the first column had padding on its right only and the other two on both
   sides, so the first image got a wider column and, at 4:3, a taller picture.
   The columns are now equal and the gutter is a real grid gap, with the
   hairline divider drawn down the middle of the gap instead of as a border. */
.disc{--disc-gap:clamp(40px,4.8vw,76px);
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));column-gap:var(--disc-gap);
  margin-top:clamp(44px,5vw,76px);border-top:1px solid var(--line)}
.disc-item{position:relative;min-width:0;padding:clamp(28px,3.2vw,44px) 0 0}
.disc-item + .disc-item::before{content:"";position:absolute;top:0;bottom:0;
  left:calc(-.5 * var(--disc-gap));border-left:1px solid var(--line)}
/* two-line names ("Environmental and hydrological science") pushed their body
   copy lower than the one-line names beside them; reserve two lines for every
   name so the three paragraphs start on the same line too */
@media (min-width:901px){
  .disc-n{min-height:2.36em;display:flex;align-items:flex-end}
}
/* 17 Sep, Jacob: "it'd be cool to have images for this section." One photograph
   per discipline, above the name, inside the existing hairline columns -- the
   columns already exist, so this adds pictures rather than a card treatment.
   4:3 so three of them across do not push the copy below the fold. */
.disc-fig{margin:0 0 clamp(18px,2.2vw,28px);aspect-ratio:4 / 3;overflow:hidden;
  background:var(--graphite-deep)}
.disc-fig img{display:block;width:100%;height:100%;object-fit:cover}
.js .disc-item.reveal .disc-fig img{transform:scale(1.04);transition:transform 900ms var(--ease)}
.js .disc-item.reveal.in .disc-fig img{transform:none}
.disc-n{font-family:var(--f-display);font-weight:400;font-size:var(--t-h2);
  line-height:1.18;letter-spacing:-.008em;color:var(--fg);max-width:16ch}
.disc-b{margin-top:clamp(14px,1.6vw,20px);color:var(--soft);font-size:var(--t-body)}
@media (max-width:900px){
  .disc{grid-template-columns:1fr;border-top:0;column-gap:0}
  .disc-item{padding:clamp(24px,4vw,34px) 0 0;border-top:1px solid var(--line)}
  .disc-item + .disc-item::before{content:none}
}

/* /about keeps its own measure cap; the nowrap it used to undo is gone from the
   base rule now (see section 14), so this only sets the measure. */
body[data-page="about"] .prob-head .h1{max-width:26ch}

/* ============================================================
   37 — FULL-BLEED HERO
   Jacob, 8 Sep: "It's still basic as ass. I want you to try
   harder to make this a VISUAL experience."

   He is right and the diagnosis is structural: every section on
   this site is a mid-height band with type in a measure and an
   image at 30-40%. Nothing has ever taken the screen. This is
   the opposite -- the image IS the section, full bleed, full
   viewport, with type over it.

   Aaron, 8 Sep: "this should feel like a breath of fresh air for
   someone who's sitting in a loft all day long and not feel like
   just analogous to the work that they're doing every day."
   ============================================================ */
/* Copy CENTRED in the space below the nav, not pinned to the floor. Britt,
   14 Sep: "I just want this copy moved up so there's not such a huge gap."
   Pinned with flex-end, the void above the copy grew with the viewport: 119px
   on a 900px-tall screen and 399px at 1200 on the homepage, 302 and 581px on
   /about, whose copy is shorter. The padding-top clears the overlaid nav
   (109px).
   First tried align-items:center; that roughly halved the gap but still left
   223px (home) and 314px (/about) at 1200 tall, because centring short copy
   in a tall box always leaves room above it. Anchored from the top instead:
   the gap is now set by padding-top alone, so it is the same on every page
   whatever the length of the copy, and it grows gently with height instead
   of in step with it. Any spare height falls below the copy, where the image
   breathes and the scroll cue sits, not above it.
   This departs from the Hebbia reference in master 6.2 ("content sits low,
   ~55% down, vast empty space above") -- the client read that space as a gap. */
.hero--bleed{position:relative;min-height:100vh;min-height:100svh;display:flex;align-items:flex-start;
  padding-block:clamp(196px,23vh,290px) clamp(56px,8vh,112px);overflow:hidden;isolation:isolate}
.hero-bleed-media{position:absolute;inset:0;z-index:-2;background:var(--graphite-deep)}
.hero-bleed-media img,.hero-bleed-media video{
  width:100%;height:100%;object-fit:cover;display:block}
/* video sits over its own poster, so the frame is never empty while it loads
   and the poster is what stands in under reduced motion */
.hero-bleed-media video{position:absolute;inset:0}
@media (prefers-reduced-motion:reduce){.hero-bleed-media video{display:none}}
/* a flat scrim, not a gradient -- §3 rules gradients out and the type has to
   clear whatever the water is doing underneath it */
/* .52 turned a pale sand and teal plate into brown mud. The scrim is light
   enough now to leave the picture alone; the type block carries its own
   readability from the panel below rather than from drowning the image. */
.hero-bleed-media::after{content:"";position:absolute;inset:0;
  background:rgba(20,19,17,.30)}
/* A flat band left a hard horizontal seam across the picture that read as a
   rendering bug. This is the same photographic vignette the logomark hero uses
   -- weighted to the lower left where the type sits. §3's no-gradient rule is
   about painted brand surfaces; a falloff on a photographic layer is a lighting
   effect, which is the exception already taken on .lm3d-vig. */
.hero--bleed::before{content:"";position:absolute;inset:0;z-index:-1;
  background:radial-gradient(130% 100% at 78% 18%,
    rgba(18,17,15,0) 22%, rgba(18,17,15,.44) 62%, rgba(18,17,15,.78) 100%)}
.hero--bleed .wrap{position:relative;z-index:1;width:100%}
.hero--bleed h1{font-family:var(--f-display);font-weight:400;
  font-size:var(--t-h1-hero);line-height:1.02;letter-spacing:-.022em;
  max-width:17ch;color:var(--ivory)}
.hero--bleed .hero-sub{max-width:52ch;color:rgba(255,255,250,.88)}
/* the eyebrow sits on a rule that runs to the edge of the measure, so the type
   block reads as anchored to the frame rather than floating on the picture */
/* Britt: the hero eyebrow "is getting a little visually lost." Over a moving
   picture a 12.5px label at .78rem does disappear. Bumped a step and given more
   tracking, which reads as deliberate rather than merely bigger. Colour is
   still Sand: Ocean was tried and measured 2.1:1 on the video, see the audit
   note in the CHANGES table. */
.hero--bleed .hero-eyebrow{margin-bottom:clamp(20px,2.4vw,32px);
  font-size:clamp(.82rem,1.04vw,.92rem);letter-spacing:.09em}
.hero--bleed .hero-eyebrow::after{width:120px}
@media (max-width:760px){
  .hero--bleed{min-height:88vh;min-height:88svh;padding-bottom:clamp(40px,6vh,64px)}
  .hero-bleed-media::after{background:rgba(20,19,17,.38)}
  .hero--bleed::before{background:radial-gradient(150% 100% at 82% 12%,
    rgba(18,17,15,0) 12%, rgba(18,17,15,.56) 52%, rgba(18,17,15,.84) 100%)}
}

/* /resources featured, 8 Sep audit M4: a photographic plate, not a screenshot.
   Larger than the document mock it replaces -- it is the one image on the page
   and it has to carry the block. */
.idx-lead-fig--photo{max-width:none;width:100%;aspect-ratio:4/5;overflow:hidden;
  background:var(--graphite-deep)}
.idx-lead-fig--photo img{width:100%;height:100%;object-fit:cover;display:block}
@media (max-width:820px){.idx-lead-fig--photo{aspect-ratio:16/10;max-width:none}}

/* /schedule, 8 Sep audit C4. The console rail is gone; these are Britt's
   1-2-3 across the top, then the form takes the full measure below. Hairline
   columns, no boxes. */
.sched-head{max-width:60ch}
.steps-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  margin-top:clamp(40px,4.6vw,64px);border-top:1px solid var(--line);
  padding-bottom:clamp(44px,5vw,72px);border-bottom:1px solid var(--line)}
.steps-row li{min-width:0;padding:clamp(24px,2.8vw,38px) clamp(20px,2.4vw,36px) 0 0}
.steps-row li + li{border-left:1px solid var(--line);padding-left:clamp(20px,2.4vw,36px)}
.steps-row .cs-n{display:block;font-family:var(--f-text);font-weight:700;
  text-transform:uppercase;letter-spacing:.05em;font-size:var(--t-eyebrow);
  color:var(--accent)}
.steps-row b{display:block;margin-top:clamp(10px,1.2vw,16px);font-family:var(--f-display);
  font-weight:400;font-size:var(--t-h2);line-height:1.18;letter-spacing:-.008em;
  color:var(--fg)}
.steps-row p{margin-top:clamp(10px,1.2vw,14px);color:var(--soft)}
/* the form takes the full measure now, capped so a 1440 line of fields does
   not run wider than a person can scan */
.sched-form{margin-top:clamp(44px,5vw,72px);max-width:880px}
@media (max-width:820px){
  .steps-row{grid-template-columns:1fr;border-top:0}
  .steps-row li{padding:clamp(22px,4vw,30px) 0 0;border-top:1px solid var(--line)}
  .steps-row li + li{border-left:0;padding-left:0}
}
/* .idx-lead bottom-aligns its columns, which was right for a short document
   mock and wrong for a 4:5 plate: the copy sank to the foot with a void above
   it. Centred against the photo. */
.idx-lead:has(.idx-lead-fig--photo){align-items:center}

/* ============================================================
   38 — CLOSING CTA AS A FULL-BLEED IMAGE BAND (8 Sep audit H1)
   The .hero--bleed vocabulary, reused to close a page on an
   image rather than on flat ground. The framed .final-in block
   keeps its corner marks; it just sits on a picture now.
   ============================================================ */
.final--bleed{position:relative;isolation:isolate;overflow:hidden}
.final--bleed .hero-bleed-media{z-index:-2}
.final--bleed .hero-bleed-media::after{background:rgba(20,19,17,.34)}
/* same photographic vignette as the heroes, centred, since the CTA block is */
.final--bleed::before{content:"";position:absolute;inset:0;z-index:-1;
  background:radial-gradient(120% 100% at 50% 50%,
    rgba(18,17,15,.18) 0%, rgba(18,17,15,.52) 60%, rgba(18,17,15,.80) 100%)}
.final--bleed > .wrap{position:relative;z-index:1}
/* the framed block reads better with a hairline against a picture than the
   corner marks alone, which vanish into busy tone */
.final--bleed .final-in{border:1px solid rgba(255,255,250,.22);
  background:rgba(18,17,15,.28)}
@media (prefers-reduced-motion:reduce){.final--bleed video{display:none}}

/* The homepage carries the certifications on Graphite with no video behind them.
   .certs and .comp-* were written for the Ocean band on the product pages, where
   the plate supplies the contrast; on a flat ground the row needs its own rule
   above it and the marks need the ground's accent rather than Sea Glass. */
.compliance--home{position:relative}
.compliance--home .certs{border-top-color:var(--line)}
.compliance--home .cert-mark{color:var(--accent)}
.compliance--home .comp-sub{color:var(--soft)}

/* The homepage gets the site's one full-screen hero; interior pages sit under it.
   Jacob, 9 Sep: "I don't want the same cover for about and home page" -- the
   headline was the real duplication, but an identical 100vh silhouette on both
   is what made them read as one template. */
.hero--bleed-short{min-height:78vh;min-height:78svh}
@media (max-width:760px){.hero--bleed-short{min-height:72vh;min-height:72svh}}

/* ------------------------------------------------------------
   34 — THE STACK   ·   home only, replaces the triptych (9 Sep)
   Jacob picked this off the Hebbia frames. Each band is sticky at
   an offset of one label height per index, so as you scroll the
   labels pile up at the top of the viewport and each new band
   slides over the last. The ground changes per band and the
   product runs off the right and bottom edges.

   Two constraints this depends on:
   - no ancestor of .stack-band may carry overflow:hidden, or the
     sticky positioning silently stops working. Overflow ON the
     band itself is fine and is what crops the product.
   - every band needs an opaque background, which the ground
     classes already provide. Do not make one transparent.
   ------------------------------------------------------------ */
.stack{padding:0;position:relative}
.stack-head{padding-block:clamp(76px,8.8vw,138px) clamp(52px,6vw,88px)}
.stack-head h2{margin-top:clamp(26px,3vw,38px);max-width:20ch}

.stack-set{--label-h:clamp(50px,4.6vw,64px)}
.stack-band{position:sticky;top:calc(var(--i) * var(--label-h));
  min-height:clamp(470px,64vh,650px);display:flex;flex-direction:column;
  overflow:hidden}
.band-label{width:100%;max-width:var(--maxw);margin-inline:auto;
  padding-inline:var(--gutter);height:var(--label-h);display:flex;
  align-items:center;flex:0 0 auto;
  font-family:var(--f-text);font-weight:700;text-transform:uppercase;
  letter-spacing:.05em;font-size:var(--t-eyebrow);color:var(--fg)}
.band-in{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
  gap:clamp(28px,4vw,64px);align-items:end;flex:1 1 auto;min-width:0}
.band-copy{min-width:0;padding-bottom:clamp(34px,4.4vw,64px)}
.band-h{font-family:var(--f-display);font-weight:400;font-size:var(--t-h1-sm);
  line-height:1.05;letter-spacing:-.016em;max-width:15ch;text-wrap:balance}
.band-b{margin-top:clamp(18px,2vw,26px);color:var(--soft);max-width:40ch;
  line-height:1.6;text-wrap:pretty}

/* the product: anchored to the band foot, wider than its column, cropped by
   the band. Same rule as the fork -- crop at 1:1, never shrink to fit. */
/* .ui-body carries a global min-height:720px so a WHOLE screen fills its
   frame. These bands show a fragment, so that min-height becomes 300-odd
   pixels of empty ivory under the content. Release it here only. */
.band-ui .ui-body{min-height:0}
.band-ui{position:relative;margin:0;min-width:0;align-self:stretch}
.band-ui .ui-frame{position:absolute;left:0;bottom:0;
  /* each band sets --band-ui-h to just under its fragment's natural height,
     so the content runs off the bottom of the frame instead of sitting in a
     pool of empty ivory. Capped so it can never outgrow the band. */
  height:min(var(--band-ui-h,400px), calc(100% - clamp(26px,3vw,44px)));
  aspect-ratio:auto;max-height:none;
  width:calc(100% + var(--gutter) + 90px);
  background:var(--ivory);border:1px solid rgba(35,35,35,.12);border-bottom:0;
  box-shadow:0 -18px 44px rgba(35,35,35,.10), -18px 0 44px rgba(35,35,35,.06)}
.band-ui .ui{--ui-s:1}
@media (min-width:1441px){
  .band-ui .ui-frame{width:calc(100% + (50vw - 50%) + 90px)}
}
@media (max-width:1180px){.band-ui .ui{--ui-s:.88}}
@media (max-width:1000px){.band-ui .ui{--ui-s:.78}}

/* Below 900 the two-column band cannot hold: the copy column drops under
   40ch and the product has no room to crop usefully. The sticky mechanic
   also fights a phone's address-bar resize, so it comes off entirely and
   the bands become ordinary stacked sections. */
@media (max-width:900px){
  .stack-band{position:static;min-height:0;
    padding-bottom:clamp(34px,6vw,52px)}
  .band-in{grid-template-columns:1fr;row-gap:clamp(26px,5vw,40px);align-items:start}
  .band-copy{padding-bottom:0}
  .band-ui{min-height:300px}
  /* the frame follows the fragment down in scale too, or the short one
     (the demand letter) leaves a pool of empty ivory under itself */
  .band-ui .ui-frame{position:relative;height:calc(var(--band-ui-h,400px) * .66);
    width:calc(100% + var(--gutter) + 40px)}
  .band-ui .ui{--ui-s:.62}
}
@media (prefers-reduced-motion:reduce){
  .stack-band{position:static}
}

/* ------------------------------------------------------------
   35 — HERO DRIFT (9 Sep)
   Three attempts at this hero, all measured the same way: mean
   per-pixel change between frames sampled half a second apart.

     delta.mp4    0.56   Jacob: "still not loving the delta"
     delta-2.mp4 17.72   Jacob: "makes me sick"
     this         ~3.0

   The second one was a camera DESCENT. Slowing it did not fix it --
   at 6x slower it still measured 7.49, because a descent changes
   the scale of the entire field at once, which is the motion axis
   that causes that reaction. Pure lateral translation does not.
   It is also what a real top-down aerial over flat terrain looks
   like, since there is no parallax to render at that altitude.

   Speed is 0.42% of frame width per second. Travel is 11% of the
   image scaled by 1.16, so 12.8% of the container over 30s. The
   scale gives 8% of overhang per side and the pan uses 6.4%, so
   the frame edge is never revealed.

   TO RETUNE, CHANGE ONLY --hero-drift-dur. Larger is slower.
   Roughly: motion = 6.2 * (percent of width per second) + 0.36.
   ------------------------------------------------------------ */
.hero-drift{
  --hero-drift-dur:32s;
  transform:scale(1.16) translate3d(-5.5%,0,0);
  animation:heroDrift var(--hero-drift-dur) linear infinite alternate;
  will-change:transform}
@keyframes heroDrift{
  from{transform:scale(1.16) translate3d(-5.5%,0,0)}
  to  {transform:scale(1.16) translate3d(5.5%,0,0)}}
/* the scale stays so the composition does not jump for these users */
@media (prefers-reduced-motion:reduce){
  .hero-drift{animation:none;transform:scale(1.16)}}

/* 17 Sep, Jacob on the /about stair: "this background is AWESOME. I wonder if
   we slightly animate it?" Same drift device as the homepage, but slower and
   on the diagonal the stair already runs, so the light appears to creep up the
   steps rather than sliding sideways past them. 52s against the homepage's 32
   -- by the formula above that is roughly 1.4 mean frame change, well under
   the ~3 that shipped on the homepage and nowhere near the 17.7 that was
   rejected. */
.hero-drift--stair{
  /* 21 Sep: "so subtle I'm not even noticing it" -- 52s became 36s */
  --hero-drift-dur:36s;
  transform:scale(1.12) translate3d(-2.4%,1.6%,0);
  animation-name:heroDriftStair}
@keyframes heroDriftStair{
  from{transform:scale(1.12) translate3d(-2.4%,1.6%,0)}
  to  {transform:scale(1.12) translate3d(2.4%,-1.6%,0)}}
@media (prefers-reduced-motion:reduce){
  .hero-drift--stair{animation:none;transform:scale(1.12)}}

/* The product-page bleeds get the same treatment at a slower rate again: these
   pictures carry more structure than the delta and a faster move reads as a
   wobble against all those verticals. */
/* 21 Sep, Jacob: the delta is "moving almost unnoticeably. I'd like that
   animation to be a little bit quicker." 64s over 6% became 30s over 10%:
   roughly 3.5x the speed, in line with the homepage drift that shipped at ~3
   and far under the 17.7 that was rejected. /demands is its only user now. */
.hero-drift--slow{--hero-drift-dur:30s;transform:scale(1.12) translate3d(-5%,0,0)}
@keyframes heroDriftSlow{
  from{transform:scale(1.12) translate3d(-5%,0,0)}
  to  {transform:scale(1.12) translate3d(5%,0,0)}}
.hero-drift--slow{animation-name:heroDriftSlow}
@media (prefers-reduced-motion:reduce){
  .hero-drift--slow{animation:none;transform:scale(1.1)}}

/* the three-line stacked headline is set nowrap for the interior hero shape; in
   a bleed it has the full measure, and at 390 nowrap would push it off the side */
.hero--bleed h1 span{white-space:normal}

/* The /mass-tort bleed: measured on the render, the 90th percentile of the copy
   zone put ivory body copy at 3.08:1 -- the arcade throws a lot of lit concrete
   straight through the measure. .52 brings it to 4.9; .46 was still
   4.41, under the floor. /demands sits on
   the delta and needs nothing: it measured 5.43:1 on the base .30. */
/* 22 Sep: the heroes swapped. /mass-tort now sits on the delta, which needs only
   the base .30. The glass towers on /demands carry a bright sky through the copy
   zone: 3.55:1 at .30, measured at the 90th percentile. */
body[data-page="demands"] .hero--bleed .hero-bleed-media::after{
  background:rgba(20,19,17,.5)}

/* ------------------------------------------------------------
   36 — CASE FILE SEQUENCE   ·   home only, 9 Sep
   Tier 1 of the animated dashboard, per Jacob: it plays itself,
   nothing is clickable.

   Driven entirely off `.showcase-ui.reveal.in`, which the observer
   already in arches.js sets when the band scrolls into view. No new
   JS, no timers to fall out of sync, and it inherits the existing
   reduced-motion and no-IntersectionObserver guards (arches.js drops
   the .js flag, and every rule here is scoped to .js).

   IT INVENTS NO STATE. Every label animated into place is already in
   the markup; the sequence only delays its arrival, so the final
   frame is pixel-identical to the static one. That is deliberate:
   the screen is fabricated data under the HIPAA rule, and an
   animation that flipped a value would be asserting an outcome the
   approved copy does not make.

   Only opacity and transform animate, never display or visibility,
   so the frame holds its full height from first paint and nothing
   reflows while the sequence runs.

   Order: header, table with its chips, the four evidence rows, then
   the Causation Report bar last. The bar sits visually above the
   evidence but lands after it, which is the point -- the report
   becomes submittable once the evidence is assembled.
   ------------------------------------------------------------ */
/* NOTE ON SPECIFICITY, 11 Sep. Every selector below carries .ui-screen.on
   deliberately. The older product-UI block earlier in this file animates
   .js .ui-screen.on .ui-panel .row and .js .ui-screen.on .ui-settle at a
   specificity of 0,5,0. Without .ui-screen.on these rules sit at 0,4,0 and
   LOSE, regardless of coming later in the file -- measured, the evidence rows
   and the report bar hit opacity 1 at 200ms while the header and table
   correctly waited. Do not simplify these selectors. */
/* The sequence is declared as a PAUSED animation rather than a static
   opacity:0 that .in then overrides. That is not a style preference, it is
   the only thing that works here: .ui-settle and .ui-panel .row already carry
   animations from the older product-UI block above, and an animated value
   beats a normal declaration in the cascade. A plain `opacity:0` on those two
   lost to it, so the report bar and the evidence rows appeared at page load
   while the header and table waited for .in -- measured 11 Sep, opacity 1 at
   200ms on exactly those elements. Re-declaring `animation` replaces the
   earlier animation outright, which is what makes the whole set behave.

   The container is itself a .reveal fading over --dur-rev (600ms) on the same
   .in, so the run starts at .45s to let that settle. One step is .34s. */
.js .showcase-ui .ui-screen.on .seq{
  animation:seqIn .55s var(--ease) both;
  animation-delay:calc(.45s + var(--s,0) * .34s);
  animation-play-state:paused}
.js .showcase-ui .ui-screen.on .seq-ev .row{
  animation:seqIn .5s var(--ease) both;
  animation-delay:calc(.45s + (3 + var(--r,0)) * .34s);
  animation-play-state:paused}
/* --r inherits from the row, so each Complete trails its own line */
.js .showcase-ui .ui-screen.on .ck{
  animation:ckIn .45s var(--ease) both;
  animation-delay:calc(.45s + (3 + var(--r,0)) * .34s + .26s);
  animation-play-state:paused}
.js .showcase-ui .ui-screen.on .ui-stat{
  animation:statIn .5s var(--ease) both;
  animation-delay:calc(.45s + 1 * .34s + .3s);
  animation-play-state:paused}

.js .showcase-ui.in .ui-screen.on .seq,
.js .showcase-ui.in .ui-screen.on .seq-ev .row,
.js .showcase-ui.in .ui-screen.on .ck,
.js .showcase-ui.in .ui-screen.on .ui-stat{animation-play-state:running}

@keyframes seqIn {from{opacity:0;transform:translateY(10px)} to{opacity:1;transform:none}}
@keyframes ckIn  {from{opacity:0;transform:translateX(7px)}  to{opacity:1;transform:none}}
@keyframes statIn{from{opacity:0;transform:scale(.94)}       to{opacity:1;transform:none}}

@media (prefers-reduced-motion:reduce){
  .js .showcase-ui .ui-screen.on .seq,
  .js .showcase-ui .ui-screen.on .seq-ev .row,
  .js .showcase-ui .ui-screen.on .ck,
  .js .showcase-ui .ui-screen.on .ui-stat{opacity:1;animation:none}
}

/* ------------------------------------------------------------
   37 — /demands, Britt's 11 Sep copy
   New sections only. No new tokens, colours or grounds; every rule
   here leans on components the site already has.
   ------------------------------------------------------------ */

/* the hero carries a second, smaller paragraph under the lead */
.hero-sub2{margin-top:clamp(14px,1.6vw,20px);color:var(--soft);max-width:52ch}

/* SECTION 2 — the rename. Deliberately quiet and CTA-free: its whole job is
   to answer "did I land in the right place" for someone who knows the old
   name. A measure, not a layout. */
.dm-evo .evo-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.52fr);
  gap:clamp(32px,5vw,80px);align-items:center}
.dm-evo .evo-in{max-width:min(100%,820px);min-width:0}
.dm-evo h2{letter-spacing:-.014em;text-wrap:balance}

/* ---- the rename -----------------------------------------------------
   The ADP mark and the Arches mark share one box, and one fades into the
   other. Rides .reveal.in like everything else -- no new JS. */
.evo-mark{margin:0;display:flex;flex-direction:column;align-items:center;
  gap:clamp(14px,1.8vw,22px);min-width:0}
.evo-svg{width:clamp(150px,15vw,210px);height:auto;overflow:visible}
/* A PLAIN CROSSFADE, 14 Sep. The earlier version collapsed each ray on its
   own stagger and wiped the arch up from the floor. Britt and Jacob both
   pulled back from it -- Jacob: "almost like, oh, look what I learned how to
   code." It was showing off instead of presenting. Now the ADP mark fades out
   as one piece and the Arches mark fades in growing gently from small to
   large, which is Britt's description from the call. Still loops.
   Opacity and scale only: no rotation, no clip, no per-ray timing.
   The caption that sat under the marks is gone too -- "we're describing it on
   the left" -- so its rules went with it. */
.js .dm-evo .adp{opacity:1}
.js .dm-evo .evo-mark.in .adp{animation:adpFade 7s var(--ease) infinite}
@keyframes adpFade{
  0%,30% {opacity:1}
  44%,86%{opacity:0}
  100%   {opacity:1}}

.arch-mark{color:var(--ocean);overflow:visible}
/* view-box so the scale grows from the centre of the arch (90,103), not from
   the corner of the outer svg */
.arch-g{transform-box:view-box;transform-origin:90px 103px}
.js .dm-evo .arch-g{opacity:0}
.js .dm-evo .evo-mark.in .arch-g{animation:archFade 7s var(--ease) infinite}
@keyframes archFade{
  0%,34%  {opacity:0;transform:scale(.78)}
  54%,84% {opacity:1;transform:scale(1)}
  96%,100%{opacity:0;transform:scale(1)}}

@media (prefers-reduced-motion:reduce){
  .js .dm-evo .adp{opacity:0;animation:none}
  .js .dm-evo .arch-g{opacity:1;animation:none;transform:none}
}
@media (max-width:900px){
  .dm-evo .evo-grid{grid-template-columns:1fr;row-gap:clamp(34px,6vw,52px)}
  .evo-svg{width:clamp(130px,34vw,170px)}
}

/* SECTION 4 — the one CTA under the chain.
   Indented by the chain's own left padding so it lines up with the step copy
   (x=112 at 1440), not with the spine line (x=72). Sitting on the spine is what
   read as "weird spacing" to Britt once the outcome strip that used to sit
   between them was removed. */
.how-cta{margin:clamp(48px,5.4vw,80px) 0 0;padding-left:clamp(26px,2.8vw,40px)}
/* when the steps pin, the CTA follows the pin's own bottom edge; the section
   gap on top of that put it a screen away from the steps it belongs to */
.how-pin.pinned + .how-cta{margin-top:clamp(12px,1.6vw,24px)}
@media (max-width:1000px){.how-cta{padding-left:0}}

/* SECTION 5 — the statement band. Reuses .prob-close-row for the watermark,
   but .prob-close adds curly quotes as pseudo-elements (Aaron asked for that
   on the closing statement) and this is a statement, not a quotation.
   29 Sep: V2 finally supplies the statement itself, so the h1 override this
   rule used to carry comes off. It was there because the band held four words
   and nothing else; the sentence that replaced them sets to nine lines at
   --t-h1 and 16ch. Back to the shared .prob-close scale, which is what the
   same component uses on /mass-tort. */
.prob-close--plain::before,
.prob-close--plain::after{content:none}
.dm-stmt{padding-block:clamp(64px,7vw,104px)}
.dm-stmt .prob-close-row{align-items:center;min-height:0}
.dm-stmt .stmt-in{position:relative;z-index:1;max-width:min(100%,900px);
  margin-inline:auto;text-align:center}
.dm-stmt .prob-close{margin-inline:auto;text-wrap:balance}
/* 17 Sep, Jacob: "center this." It measured 220px of air above the words and
   83px below -- .prob-close-row carries a top margin for the context it was
   built in (a close under body copy), and here it is the only thing in the
   band. The section's own padding does the spacing, so the margin comes off
   and the block sits on the band's centre line. */
.dm-stmt .prob-close-row{margin-top:0}

/* SECTION 6 — customer proof, layered (14 Sep).
   Britt: "it's image and stylized quote. That could be good enough." The two
   story paragraphs are gone; the story is linked, not retold.
   Layered rather than blocked -- Jacob's own direction on the call, text that
   comes over an image instead of image, then text. */
.dm-proof .proof-head{max-width:min(100%,820px)}
/* balanced so "PI firms." does not orphan onto its own line */
.dm-proof .proof-head h2{text-wrap:balance}
/* The photo is landscape with a person at each edge, so a card coming over its
   side would cover someone. The card overlaps the bottom-right corner instead,
   where the frame is pavement and briefcases -- the same move the phone layout
   already makes. Faces stay clear at every width. */
.proof-layer{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));
  align-items:start;margin-top:clamp(40px,4.6vw,72px)}
/* 17 Sep: "image to quote ratio could be smaller so I don't have to scroll so
   freakin far." The photo loses two columns and the card climbs further up it,
   which takes about 250px out of the section at 1200 without changing the
   device. The card still lands on pavement and briefcases, not on faces. */
/* markup #94, Britt: "Round these corners and increase drop shadow." The
   radius had gone on the /demands collage but never on this pair, which is
   what the pin was actually on. Both layers take the same 3px the collage
   uses -- any more and a law firm starts looking like a consumer app -- and
   the photo gains a cast shadow so the two planes separate instead of the
   card appearing to float on nothing. */
/* 12 Oct: swapped with /about. This slot now holds the four of them under the
   arcade, which is 1.66:1, so the ratio moves off the walking shot's 755/554. */
.proof-photo{grid-column:1 / 8;grid-row:1;margin:0;min-width:0;aspect-ratio:16 / 10;
  overflow:hidden;background:var(--stone);
  border-radius:3px;box-shadow:0 18px 44px rgba(35,35,35,.18)}
.proof-photo img{display:block;width:100%;height:100%;object-fit:cover;border-radius:3px}
.proof-card{grid-column:6 / 13;grid-row:2;margin-top:calc(-1 * clamp(130px,15vw,230px));
  position:relative;z-index:1;min-width:0;
  background:var(--ivory);border:1px solid var(--line);border-radius:3px;
  padding:clamp(28px,3.6vw,56px) clamp(26px,3.4vw,54px);
  box-shadow:0 30px 70px rgba(35,35,35,.20)}
.proof-quote{margin:0;font-family:var(--f-display);font-weight:400;
  font-size:var(--t-pull);line-height:1.22;letter-spacing:-.01em;color:var(--fg);
  text-wrap:pretty}
.proof-quote::before{content:"\201C"}
.proof-quote::after{content:"\201D"}
.proof-by{margin-top:clamp(20px,2.4vw,30px);font-family:var(--f-text);font-weight:700;
  font-size:var(--t-small);line-height:1.4;color:var(--fg)}
.proof-by span{display:block;font-weight:400;color:var(--faint);margin-top:4px}

@media (max-width:900px){
  .proof-layer{grid-template-columns:1fr}
  .proof-photo{grid-column:1;aspect-ratio:16 / 10}
  /* on a phone the card pulls up over the bottom of the photo instead */
  .proof-card{grid-column:1;grid-row:2;margin:-9% clamp(12px,4vw,24px) 0}
}

@media (max-width:900px){
  .dm-stmt .prob-close{max-width:none}
}

/* ------------------------------------------------------------
   38 — THE DEMAND BEING WRITTEN   ·   /demands section 5
   A rebuild of the demandpro.ai loop as real markup. Square
   corners, Arches palette, no cobalt gradient: it is our surface
   showing our product, not a transplant of their art direction.

   The reveal is a STEPPED max-height on the wrapper rather than a
   per-character script. That matters because the paragraph breaks
   into a different number of lines at every width, so anything
   keyed to a line count is wrong on a phone. steps() over the full
   height gives partial-line reveals that read as writing, and the
   step count is deliberately higher than the line count at any
   breakpoint so it never lands as a curtain.

   The caret bar sits after the wrapper in normal flow, so it
   follows the written edge down without being positioned.
   ------------------------------------------------------------ */
.gen{margin:clamp(44px,5vw,72px) auto 0;max-width:min(100%,660px);
  background:var(--ivory);border:1px solid rgba(35,35,35,.14);
  box-shadow:0 18px 44px rgba(35,35,35,.10);position:relative;z-index:1}
.gen-bar{display:flex;align-items:center;gap:14px;
  padding:clamp(12px,1.4vw,16px) clamp(16px,1.8vw,22px);
  border-bottom:1px solid rgba(35,35,35,.12)}
.gen-title{font-family:var(--f-text);font-weight:700;font-size:var(--t-small);
  color:var(--graphite)}
.gen-pill{margin-left:auto;display:inline-flex;align-items:center;gap:7px;
  border:1px solid var(--ocean);color:var(--ocean);border-radius:2px;
  padding:4px 10px;font-family:var(--f-text);font-weight:700;font-size:11.5px;
  letter-spacing:.03em;white-space:nowrap}
.gen-pill i{width:6px;height:6px;border-radius:50%;background:var(--ocean);
  flex:0 0 auto}
.js .gen-pill i{animation:genDot 1.4s var(--ease) infinite}
@keyframes genDot{0%,100%{opacity:.25;transform:scale(.8)}50%{opacity:1;transform:scale(1)}}

.gen-doc{padding:clamp(18px,2.2vw,28px) clamp(16px,1.8vw,24px) clamp(22px,2.6vw,32px)}
.gen-h{font-family:var(--f-text);font-weight:700;font-size:var(--t-small);
  letter-spacing:.02em;color:var(--graphite);text-transform:uppercase;
  margin-bottom:clamp(12px,1.4vw,16px)}
.gen-p{font-family:var(--f-text);font-size:14.5px;line-height:1.62;
  color:rgba(35,35,35,.86);margin:0;min-height:1.62em}

/* The untyped remainder keeps its space. visibility:hidden, NOT display:none
   and not a clip -- the full paragraph is laid out from the first frame, so
   moving characters from .gen-rest into .gen-typed cannot reflow it. That is
   what holds the line breaks still and keeps the cursor on the write head.
   An earlier version wiped a horizontal band down the paragraph instead,
   which cut through the middle of a line and read as a rendering fault. */
/* 17 Sep: the write head, from the Demand Pro loop Jacob sent -- a filled band
   sitting on the line being written, so the paragraph reads as being composed
   rather than revealed. Positioned by the JS from the cursor's own offsets, so
   it tracks the real write head at any measure and never drifts off it. */
.sc-bd{position:relative}
.gen-hl{position:absolute;z-index:0;left:0;height:0;
  background:rgba(0,111,129,.13);border-left:2px solid var(--ocean);
  opacity:0;transition:top .16s var(--ease),width .16s var(--ease),opacity .3s var(--ease);
  pointer-events:none}
.sc-bd.typing .gen-hl{opacity:1}
.sc-bd.done .gen-hl{opacity:0}
.gen-p{position:relative;z-index:1}

.gen-rest{visibility:hidden}
.gen-cursor{display:inline-block;width:2px;height:1.05em;background:var(--ocean);
  vertical-align:-.16em;margin-left:1px}
.js .gen .gen-cursor{animation:genBlink 1.05s steps(1,end) infinite}
@keyframes genBlink{0%,55%{opacity:1}56%,100%{opacity:0}}
/* while it holds the finished demand at the end of a cycle, the cursor rests */
.gen.done .gen-cursor,.sc-bd.done .gen-cursor{animation:none;opacity:0}

@media (prefers-reduced-motion:reduce){
  /* the script also bails out early under reduced motion and prints the whole
     demand; this covers the case where the stylesheet loads without it */
  .gen-rest{visibility:visible}
  .js .gen .gen-cursor,.js .gen-pill i{animation:none}
  .gen-cursor{display:none}
}
@media (max-width:900px){
  .gen-p{font-size:13.5px}
  .gen{max-width:100%}
}

/* ------------------------------------------------------------
   39 — HOW IT WORKS, two columns   ·   /demands section 4
   Jacob, 11 Sep: the right half of this section was empty and the
   demand assembling itself illustrates the four steps beside it.
   The figure is sticky, so it types while the steps scroll past.
   ------------------------------------------------------------ */
.dm-how .how-body{display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,.92fr);
  gap:clamp(34px,5vw,84px);align-items:start}
.dm-how .how-body .chain{min-width:0}
/* top clears the sticky nav; the panel is short enough that it never outgrows
   the chain beside it, so it holds for the whole scroll.
   17 Sep: this moved from .gen to .stage. The stage wraps the panel now, and
   `.stage .gen{position:relative}` was quietly beating this rule -- the panel
   scrolled away with the first step, so steps 02 to 04 changed the scene long
   after it had left the screen. That is the "can't see all 4" report. */
.dm-how .stage{position:sticky;top:clamp(88px,12vh,132px);
  margin:clamp(44px,5vw,80px) 0 0;max-width:none}

/* On Graphite the ivory card needs a light hairline -- the dark border and
   dark cast shadow it carried on Sea Glass are both invisible here. */
.on-graphite .gen{border-color:rgba(255,255,250,.16);
  box-shadow:0 24px 60px rgba(0,0,0,.34)}

@media (max-width:1000px){
  .dm-how .how-body{grid-template-columns:1fr;row-gap:clamp(34px,6vw,52px)}
  /* sticky in a single column would pin the document over the steps */
  .dm-how .stage{position:static;margin-top:clamp(30px,5vw,44px)}
}

/* ============================================================
   40 — THE PALETTE TEXTURES   ·   14 Sep 2026
   Britt: "look at the way we've named the colours... the names
   literally tell you what texture to look for." Each painted
   ground now carries a photographic plate of its own material,
   drawn from the brand guide's texture inspiration page:

     Sea Glass  fluted, reeded glass
     Stone      concrete with diagonal light shafts
     Ocean      fine ripples on deep water
     Graphite   fine film grain (a tile, not a plate)
     Sand       rippled satin   (an accent, not a ground)

   Ivory is deliberately left as it was. It is the paper ground
   dense copy rests on, and texture on near-white reads as dirt.

   HOW THE CONTRAST IS GUARANTEED. Each plate is generated, then
   its luminance is re-mapped into a fixed duotone band around its
   own ground colour and clamped after resampling. No pixel can be
   lighter or darker than the band's ends, so worst-case contrast
   is measured on the band, not hoped for:

     Stone     graphite text  11.54:1
     Sea Glass graphite text   9.21:1
     Ocean     ivory text      5.83:1   (band's light end IS Ocean:
                                         the plate may darken this
                                         ground, never lighten it)

   The ocean source ran bright-top to dark-bottom. Toned as-is that
   becomes a directional sweep across the section -- a gradient in
   everything but name -- so its large-scale light was subtracted
   before toning and only the ripple detail survives.

   Generated textures are sanctioned (master 5.6b). No people here.
   Recorded preference: light catching a surface, never grunge.
   ============================================================ */
.on-stone.tex,.on-seaglass.tex,.on-ocean.tex,.on-graphite.tex{
  background-size:cover;background-repeat:no-repeat;background-position:50% 50%}
.on-stone.tex   {background-image:url("/assets/img/tex-stone.webp")}
.on-seaglass.tex{background-image:url("/assets/img/tex-seaglass.webp")}
.on-ocean.tex   {background-image:url("/assets/img/tex-ocean.webp")}
/* Graphite is ASPHALT WITH VARIANCE + A DRIFTING SHEEN (17 Sep).
   Jacob kept the asphalt but asked for "a variance in the grain on that
   asphalt" and "a slight shimmer animation."
   Variance: the grain's AMPLITUDE is modulated by a slow blurred envelope
   (0.62x to 1.17x), so it runs coarser in places and finer in others instead
   of being one uniform field. No speck is big enough to read as a crumb --
   that was the 14 Sep rejection.
   Sheen: a SECOND TILE of broad soft lobes, drifting. It is deliberately a
   material and not a CSS gradient: section 3 bans gradients on painted brand
   surfaces, and what moves here is a texture, translated by one whole tile
   period so the loop cannot show a seam.
   Measured on the rendered page with the sheen at its brightest point over
   the brightest grain -- see the numbers in the note above .sheen below. */
/* Graphite is FILM GRAIN (14 Sep, third pass). Two rejections define it:
   the glinted mineral grain was "crumbly and weird" (sparse bright specks, and
   a 4-5px noise cell that reads as crumbs), and fluted glass belongs to Sea Glass
   only. So: fine near-pixel grain, one octave, no glints, no cloud-scale mottle,
   a whisper of Sand in the highlights only. Averages exactly #232323, so the
   ground colour does not drift. A 512 tile at one texel per CSS pixel, which
   keeps it visible on 1x screens where a half-size tile averages away.
   Seamless by construction. Worst case on the brightest texel:
   fg 12.31, soft 9.20, faint 6.08. */
.on-graphite.tex{background-image:url("/assets/img/tex-graphite.webp");
  background-size:512px 512px;background-repeat:repeat;background-position:0 0}

/* 21 Sep: the drifting sheen that sat here came off. Jacob: "I decided i hate
   this 'sheen' thing." On the page it read as water stains -- blotchy patches
   drifting across the ground -- not as light. The varied asphalt grain stays. */
.on-graphite.tex::after{content:none}

/* The generic noise and grain pseudo-layers sat over these grounds and would
   now muddy a real plate, so they come off wherever a plate replaces them.
   Ivory keeps its original light grain. */
.on-stone.tex::before,.on-stone.tex::after,
.on-seaglass.tex::before,.on-seaglass.tex::after,
.on-ocean.tex::before,.on-ocean.tex::after,
.on-graphite.tex::before{content:none}

/* The same plate on consecutive sections of one ground reads as a repeat --
   the exact "duplicated water" note. Stone's light shafts are distinctive, so
   alternate sections show a different band of the plate. */
.on-stone.tex:nth-of-type(even){background-position:100% 85%}

/* Sand, as an accent. Held the /demands proof slot until the photo landed 14 Sep;
   currently unused, kept for the next accent panel. */
.tex-sand{background:var(--sand) url("/assets/img/tex-sand.webp") 50% 50% / cover no-repeat}

/* ------------------------------------------------------------
   41 — HERO VARIANT  ·  ?hero=video  (14 Sep)
   The site's own .hero-bleed-media video rule sets display:block, which
   beats the browser's default handling of the hidden attribute, so hidden
   has to be enforced here or the variant would paint over the delta.
   ------------------------------------------------------------ */
.hero-alt-video[hidden]{display:none!important}
.hero-video .hero-drift{display:none}

/* ------------------------------------------------------------
   43 — HOMEPAGE HERO, CUT VIDEO  ·  17 Sep
   The cut is much brighter than the delta: a golden skyline and two
   near-white interiors. Measured on the bright end (90th percentile)
   of the zone the copy occupies, compositing BOTH layers the hero
   has -- the flat scrim and the radial vignette -- ivory copy came
   out at 3.74:1 on the base .30. The worst frame is the sunlit
   office. .42 holds every frame of the loop at 4.9:1 or better.
   Homepage only: /about and /mass-tort keep .30 over their stills.
   ------------------------------------------------------------ */
/* scoped to the cut, since the delta is the default again and it only ever
   needed .30. Whatever footage replaces this has to be re-measured the same
   way -- the number belongs to the pictures, not to the page. */
body[data-page="home"] .hero--bleed:has(.hero-cut-video) .hero-bleed-media::after{
  background:rgba(20,19,17,.42)}
@media (max-width:760px){
  body[data-page="home"] .hero--bleed:has(.hero-cut-video) .hero-bleed-media::after{
    background:rgba(20,19,17,.46)}
}
/* the still underneath is the poster and the reduced-motion fallback, so it
   must not also drift -- two motions in one frame read as a wobble */
.hero-bleed-media video + .hero-drift,
.hero-bleed-media:has(video) .hero-drift{animation:none}
/* The delta is a mid-tone image and carries headline copy at a .30 scrim. The
   video is not: its stone rooms and lit glass are bright. At .30 the glass and
   reading-room scenes put ivory body copy near 3:1. Solved on the bright end
   (90th percentile) of the text zone in every scene: .48 is the lightest flat
   scrim that holds all five at 4.75:1 or better. A boardroom scene was cut from
   the loop because on its own it forced .56 and would have darkened the rest.
   Flat, not a gradient; scoped to the variant so the delta is unchanged. */
.hero-video .hero-bleed-media::after{background:rgba(20,19,17,.48)}

/* ------------------------------------------------------------
   42 — HOMEPAGE DIFFERENTIATION  ·  Britt's section 04 (17 Sep)
   Four numbered statements. Four cards with icons is the obvious
   move and master §3 bans it, so the device is a hairline index:
   the numeral and the statement hold a narrow left column, the
   body a wider right one. The numeral is Sand and set in the
   display face, large enough to be the thing the eye lands on,
   so the four read as an argument in order rather than a grid.
   ------------------------------------------------------------ */
.diff-head{max-width:min(100%,900px)}
.diff-head .h1-sm{text-wrap:balance}
.diff-rows{margin-top:clamp(44px,5vw,76px);list-style:none;counter-reset:none}
.diff-row{padding-block:clamp(30px,3.4vw,52px);border-top:1px solid var(--line);
  display:grid;gap:clamp(18px,2.4vw,34px);align-items:start;min-width:0}
.diff-row:last-child{border-bottom:1px solid var(--line)}
@media (min-width:900px){
  .diff-row{grid-template-columns:minmax(0,5fr) minmax(0,6fr);gap:clamp(40px,4.6vw,88px)}
}
.diff-lead{min-width:0}
/* Sand on Stone measured 1.95:1 in the 17 Sep audit, against a 3:1 floor at
   this size. Ocean is the accent that holds on light grounds. */
.diff-n{font-family:var(--f-display);font-weight:400;line-height:1;
  font-size:clamp(1.6rem,2.6vw,2.3rem);color:var(--ocean);
  margin-bottom:clamp(12px,1.4vw,18px)}
.diff-t{font-family:var(--f-text);font-weight:700;letter-spacing:-.025em;
  font-size:clamp(1.28rem,2vw,1.8rem);line-height:1.2;color:var(--fg);
  max-width:min(100%,460px);text-wrap:balance}
.diff-b{color:var(--soft);max-width:54ch;min-width:0}

/* ------------------------------------------------------------
   44 — /demands STAGE  ·  four scenes in a framed plate (17 Sep)
   Jacob: "this just looks like a fucking screenshot... put some
   layering in there. Maybe we have some gold framing around it."
   Three layers, not one: an Ocean plate offset under the bottom
   right, the product panel itself, and a Sand hairline frame
   drawn off the top left with corner marks holding the two
   together. Linework that frames content is what the brand guide
   sanctions (pg 29); it is framing here, not decoration.
   One scene per step, swapped by the same scroll position that
   lights the chain. Only the active scene animates -- every
   keyframe is paused until .stage carries its step.
   ------------------------------------------------------------ */
.stage{position:relative;margin:clamp(44px,5vw,72px) auto 0;max-width:min(100%,660px);
  isolation:isolate}
/* an Ocean block under the bottom right corner, so the panel has something to
   sit ON rather than floating on the ground */
.stage-plate{position:absolute;z-index:0;inset:46px -20px -20px 46%;
  background:var(--ocean);opacity:.38}
/* The plain Sand rectangle that used to draw the frame is gone: the business-card
   corner does that job now, and two framing devices on one panel compete. */
.stage-frame{display:none}
/* The business-card corner, at the two corners where the layers cross. It
   holds the panel itself rather than the frame behind it, and only two corners
   carry it -- four would box the panel in, which is the thing the guide's
   "linework frames, never decorates" rule is guarding against. */
/* The junction diamond sits at 21.75% of the symbol's box, and the two arms run
   from it toward the far corner. So the offset has to clear BOTH: push the box
   out by that 21.75% plus the gap you want between the arms and the panel, or
   the arms land on the ivory where Sand measures about 1.9:1 and vanishes. */
.stage .deco{--deco-w:clamp(200px,20vw,280px);
  position:absolute;z-index:3;width:var(--deco-w);height:auto;
  color:var(--sand);opacity:1;overflow:visible;pointer-events:none}
/* Jacob's motif: both arms run 3.25% in from the top and left of its box, and
   the stepped box at the corner reaches 16.4% in. Offsetting by the arm inset
   plus a 26px gap puts the arms on the graphite and lands the box just outside
   the panel's corner, where it frames it instead of overlapping it. */
.stage .deco.tl{top:calc(-1 * (0.0325 * var(--deco-w) + 26px));
  left:calc(-1 * (0.0325 * var(--deco-w) + 26px))}
.stage .deco.br{bottom:calc(-1 * (0.0325 * var(--deco-w) + 26px));
  right:calc(-1 * (0.0325 * var(--deco-w) + 26px));transform:rotate(180deg)}
/* it draws itself in when the panel arrives, like the other linework */
.js .stage.reveal .deco{opacity:0;transition:opacity .9s var(--ease) .25s}
.js .stage.reveal.in .deco{opacity:1}
.stage .gen{position:relative;z-index:2;margin:0;max-width:none;
  box-shadow:0 24px 60px rgba(9,10,10,.45)}
/* the panel is a fixed stage: scenes are stacked in it and cross-faded, so the
   surrounding layout never jumps as the steps change */
.stage .scene{grid-area:1 / 1;padding:clamp(18px,2.2vw,26px) clamp(16px,1.8vw,24px) clamp(20px,2.4vw,28px);
  opacity:0;visibility:hidden;transition:opacity .45s var(--ease),visibility .45s}
.stage-scenes{display:grid;position:relative;min-height:clamp(250px,27vw,320px)}
.stage[data-step="0"] .sc-up,.stage[data-step="1"] .sc-an,
.stage[data-step="2"] .sc-bd,.stage[data-step="3"] .sc-rv{opacity:1;visibility:visible}

/* the bar label follows the step */
.stage[data-step="1"] .gen-title::after{content:none}
.stage .gen-pill{transition:color .3s var(--ease),border-color .3s var(--ease)}
.stage[data-step="3"] .gen-pill{color:var(--graphite);border-color:var(--sand)}
.stage[data-step="3"] .gen-pill i{background:var(--sand);animation:none}

/* 01 — the docket, with a case arriving */
.up-head{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.up-title{font-family:var(--f-display);font-size:1.15rem;color:var(--graphite)}
.up-add{margin-left:auto;background:var(--ocean);color:var(--ivory);
  font-family:var(--f-text);font-weight:700;font-size:11px;letter-spacing:.03em;
  padding:6px 12px;border-radius:2px}
.up-table .up-stat{white-space:nowrap}
.up-prog{display:inline-flex;align-items:center;gap:8px}
.up-prog em{font-style:normal;font-weight:700;font-size:11px;color:var(--ocean);
  min-width:30px;display:inline-block}
.up-bar{display:inline-block;width:64px;height:4px;background:rgba(35,35,35,.12)}
.up-bar b{display:block;height:100%;width:0;background:var(--ocean)}
.up-ready{display:none}
.js .stage[data-step="0"] .up-new{animation:upRow .7s var(--ease) both}
.js .stage[data-step="0"] .up-bar b{animation:upFill 2.4s var(--ease) .5s forwards}
.js .stage[data-step="0"] .up-prog{animation:upSwap 0s linear 3.1s forwards}
.js .stage[data-step="0"] .up-ready{animation:upShow 0s linear 3.1s forwards}
@keyframes upRow{from{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:none}}
@keyframes upFill{to{width:100%}}
@keyframes upSwap{to{display:none}}
@keyframes upShow{to{display:inline-flex}}

/* 02 — the record, scanned and sorted */
.an-doc{position:relative;overflow:hidden;background:var(--stone);
  border:1px solid rgba(35,35,35,.09);padding:16px 18px;display:grid;gap:9px}
.an-l{display:block;height:7px;background:rgba(35,35,35,.12)}
.an-l:nth-child(2n){width:88%}
.an-l:nth-child(3n){width:72%}
.an-scan{position:absolute;left:0;right:0;top:-30%;height:30%;
  background:rgba(0,111,129,.16);border-top:1px solid rgba(0,111,129,.5);
  border-bottom:1px solid rgba(0,111,129,.5)}
.js .stage[data-step="1"] .an-scan{animation:anScan 2.6s var(--ease) infinite}
@keyframes anScan{0%{top:-30%}100%{top:100%}}
.an-chips{list-style:none;margin:16px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:8px}
.an-chips li{font-family:var(--f-text);font-weight:700;font-size:11px;letter-spacing:.02em;
  color:var(--graphite);background:var(--ivory);border:1px solid rgba(35,35,35,.14);
  padding:5px 10px;border-radius:2px;opacity:0}
.an-chips b{color:var(--ocean);margin-left:6px}
.js .stage[data-step="1"] .an-chips li{
  animation:anChip .5s var(--ease) both;animation-delay:calc(.5s + var(--i) * .45s)}
@keyframes anChip{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* 04 — review */
.rv-row{display:flex;align-items:center;gap:12px;padding:11px 2px;
  border-bottom:1px solid rgba(35,35,35,.09);
  font-family:var(--f-text);font-size:13px;color:rgba(35,35,35,.86);opacity:0}
.rv-tick{width:16px;height:16px;flex:0 0 auto;border:1px solid var(--ocean);
  position:relative}
.rv-tick::after{content:"";position:absolute;left:4px;top:1px;width:5px;height:9px;
  border-right:2px solid var(--ocean);border-bottom:2px solid var(--ocean);
  transform:rotate(45deg) scale(0);transform-origin:center}
.js .stage[data-step="3"] .rv-row{animation:anChip .45s var(--ease) both;
  animation-delay:calc(.3s + var(--i) * .5s)}
.js .stage[data-step="3"] .rv-tick::after{animation:rvTick .3s var(--ease) both;
  animation-delay:calc(.55s + var(--i) * .5s)}
@keyframes rvTick{to{transform:rotate(45deg) scale(1)}}
.rv-foot{margin-top:18px;opacity:0}
.rv-foot span{display:inline-block;background:var(--sand);color:var(--graphite);
  font-family:var(--f-text);font-weight:700;font-size:11.5px;letter-spacing:.03em;
  padding:7px 14px;border-radius:2px}
.js .stage[data-step="3"] .rv-foot{animation:anChip .5s var(--ease) both;animation-delay:2.5s}

@media (prefers-reduced-motion:reduce){
  .js .stage *{animation:none!important}
  .up-bar b{width:100%}
  .an-chips li,.rv-row,.rv-foot{opacity:1}
  .rv-tick::after{transform:rotate(45deg) scale(1)}
}
@media (max-width:900px){
  /* 17 Sep audit: at 390 the Ocean plate (right:-12px) and the corner diamond
     hung 12px past the wrap and the page scrolled sideways. On a phone the
     layers sit inside the measure instead; the frame still overhangs left,
     where there is padding to absorb it. */
  /* 21 Sep audit: on a phone the plate ran up behind the step copy and down past
     the CTA, a two-tone slab with text across the seam. The panel stands alone. */
  .stage-plate{display:none}
  .stage-frame{inset:-12px 52px 24px -12px}
  /* the diamond is rotated 45deg, so its box corner still reached 3px past the
     wrap at 390. Sit it fully inside on a phone. */
  /* 21 Sep: at 390 the motif sits outside the panel by design, and on a phone
     there is no outside -- it pushed the page to 417px and it scrolled sideways.
     The frame is a desktop flourish; the panel stands on its own here. */
  .stage .deco{display:none}
}

/* 17 Sep audit: at 390 the cases table inside the stage widened its grid track
   to 482px and the page scrolled sideways -- the min-width:auto hazard again.
   The stage and its scenes are pinned to zero, and the table scrolls inside
   its own panel instead of pushing the page. */
.dm-how .how-body > *,.stage,.stage-scenes,.stage .scene,.stage .gen{min-width:0}
.sc-up{overflow-x:auto}
.up-table{min-width:380px}
@media (max-width:560px){
  .up-table thead th:nth-child(3),.up-table tbody td:nth-child(3){display:none}
  .up-table{min-width:0}
  .sc-up{overflow-x:visible}
}

/* ------------------------------------------------------------
   45 — /about on Britt's copy (21 Sep)
   ------------------------------------------------------------ */
/* Hero: three paragraphs where there used to be one. The lead carries the
   argument, the six-word line is the page in a sentence and is set apart in
   the display face, and the third drops to body size so the block reads as a
   hierarchy rather than a wall of lead text over a photograph. */
.about-intro{max-width:min(100%,640px)}
.about-intro-line{margin-top:clamp(18px,2vw,26px);font-family:var(--f-display);
  font-size:clamp(1.3rem,1.9vw,1.7rem);line-height:1.2;color:var(--ivory)}
.about-intro-b{margin-top:clamp(12px,1.4vw,18px);max-width:52ch;
  color:rgba(255,255,250,.84);font-size:var(--t-body);line-height:1.6}

/* Section 02: her copy is prose, so the numbered origin list becomes a reading
   column beside the same held plate. */
.origin-prose{min-width:0;max-width:62ch}
.origin-prose p + p{margin-top:clamp(14px,1.6vw,20px)}
.origin-prose .origin-sub{margin-bottom:clamp(8px,1vw,14px);color:var(--fg)}
.origin-prose p{color:var(--soft)}
.origin-prose .origin-close{margin-top:clamp(24px,2.8vw,36px);padding-top:clamp(18px,2vw,26px);
  border-top:1px solid var(--line);font-family:var(--f-display);
  font-size:clamp(1.2rem,1.7vw,1.5rem);line-height:1.3;color:var(--fg)}

/* 30 Sep: About V2 gives the closing line to Travis by name, so the closer is
   a blockquote now. It keeps the rule and the display face it already had --
   only the quote marks and the attribution are new. Marks are pseudo-elements
   for the same reason the statement bands use them: a treatment, not copy. */
.origin-prose .origin-close--quote{margin-inline:0}
.origin-prose .origin-close--quote p{color:var(--fg);font:inherit;margin:0;font-style:italic}
.origin-prose .origin-close--quote p::before{content:"\201C"}
.origin-prose .origin-close--quote p::after{content:"\201D"}
.origin-prose .origin-close--quote cite{display:block;font-style:normal;
  font-family:var(--f-body);font-size:var(--t-small);color:var(--soft);
  margin-top:clamp(12px,1.4vw,18px);line-height:1.45}
.origin-prose .origin-close--quote cite span{display:block;color:var(--soft);opacity:.8}

/* Section 04: each principle has a one-line thesis before its paragraph. */
.prin-lede{font-weight:700;color:var(--fg);margin-bottom:clamp(8px,1vw,12px)}

/* ------------------------------------------------------------
   46 — THE FRAME MOTIF, sitewide (21 Sep)
   Jacob's FrameMotif.svg, the #deco-corner symbol. One job everywhere: it
   frames the two moments that matter on every page, the product panel and
   the closing ask. Top-left and bottom-right only -- four corners would box
   the content in rather than frame it.
   On /demands it sits OUTSIDE the panel (see .stage .deco). In the closers
   .final-in clips its children, so it sits INSIDE the frame's edge, which is
   also how it sits on the business card it came from.
   ------------------------------------------------------------ */
.final-in .deco{--deco-w:clamp(150px,15vw,230px);position:absolute;z-index:0;
  width:var(--deco-w);height:auto;color:var(--sand);opacity:.9;
  overflow:visible;pointer-events:none}
.final-in .deco.tl{top:clamp(14px,1.6vw,22px);left:clamp(14px,1.6vw,22px)}
.final-in .deco.br{bottom:clamp(14px,1.6vw,22px);right:clamp(14px,1.6vw,22px);
  transform:rotate(180deg)}
.final-in > :not(.deco):not(.final-arches){position:relative;z-index:1}
/* draws in with the block, like the rest of the linework */
.js .final .final-in .deco{opacity:0;transition:opacity 1s var(--ease) .3s}
.js .final.in .final-in .deco{opacity:.9}
/* On a phone the frame is narrow and the copy fills it, so the motif scales
   down to a mark that lives inside the padding and never reaches the words. */
@media (max-width:700px){
  .final-in .deco{--deco-w:84px}
  .final-in .deco.tl{top:10px;left:10px}
  .final-in .deco.br{bottom:10px;right:10px}
}


/* ------------------------------------------------------------
   47 — HOMEPAGE VIDEO HERO, NO CROP  ·  21 Sep
   Jacob: "Don't CROP or stretch the video at all if possible."
   The bleed hero is a full-viewport box with the media set to cover, which
   crops 16:9 footage to whatever shape the screen is -- about a tenth off the
   sides on a laptop, most of the frame on a phone. So, for the homepage video:
   - Desktop: the hero IS 16:9, the footage's own shape, so it fills exactly.
     The video is `contain`, never `cover`: if the copy ever makes the box a
     little taller than 16:9, the result is a thin letterbox on the graphite,
     never a crop. No stretching is possible with either value.
   - Phone: no tall screen can show 16:9 footage behind copy without cropping
     it, so the video becomes a full-width 16:9 band at the top and the copy
     runs beneath it on the graphite.
   Scoped with :has(.hero-cut-video) so the delta and ?hero=delta are untouched.
   ------------------------------------------------------------ */
body[data-page="home"] .hero--bleed:has(.hero-cut-video) .hero-bleed-media video{
  object-fit:contain;object-position:50% 50%}
@media (min-width:761px){
  body[data-page="home"] .hero--bleed:has(.hero-cut-video){
    min-height:0;aspect-ratio:16 / 9}
}
@media (max-width:760px){
  body[data-page="home"] .hero--bleed:has(.hero-cut-video){
    display:block;min-height:0;padding:0 0 clamp(40px,8vw,56px)}
  body[data-page="home"] .hero--bleed:has(.hero-cut-video) .hero-bleed-media{
    position:relative;inset:auto;aspect-ratio:16 / 9;z-index:0}
  /* no copy sits on the footage here, so it needs no scrim or vignette */
  body[data-page="home"] .hero--bleed:has(.hero-cut-video) .hero-bleed-media::after{background:none}
  body[data-page="home"] .hero--bleed:has(.hero-cut-video)::before{content:none}
  body[data-page="home"] .hero--bleed:has(.hero-cut-video) .wrap{padding-top:clamp(28px,7vw,40px)}
  /* the still under the video would show at full height behind it */
  body[data-page="home"] .hero--bleed:has(.hero-cut-video) .hero-drift{display:none}
}

/* ------------------------------------------------------------
   48 — DIFFERENTIATION ROWS, ANIMATED  ·  21 Sep
   Jacob: "we don't have anything animated happening here." The rows had the
   site's generic fade-up, which at this scale reads as static. Now each row
   builds itself in the brand's own idiom, the drawn line:
     1. its hairline draws left to right across the full measure
     2. a short Sand bar -- the tapered bar from the brand's linework -- runs
        out along the line under the numeral and stops
     3. the numeral, the statement and the body arrive behind it, in order
   Driven by the same .in class the observer already sets, so nothing new runs
   on scroll. Gentle by design: short travel, no bounce, nothing loops.
   ------------------------------------------------------------ */
.diff-row{border-top:0;position:relative}
.diff-row:last-child{border-bottom:0}
/* the hairline, now a drawn element rather than a border */
.diff-row::before,.diff-row:last-child::after{content:"";position:absolute;left:0;right:0;
  height:1px;background:var(--line);transform-origin:0 50%}
.diff-row::before{top:0}
.diff-row:last-child::after{bottom:0}
/* the tapered bar: Linework 4's proportions, a 90 degree point at its end */
.diff-lead{position:relative}
.diff-lead::before{content:"";position:absolute;left:0;
  top:calc(-1 * clamp(30px,3.4vw,52px) - 3px);width:clamp(56px,6vw,88px);height:7px;
  background:var(--ocean);clip-path:polygon(0 0,calc(100% - 3.5px) 0,100% 50%,calc(100% - 3.5px) 100%,0 100%);
  transform-origin:0 50%}

.js .diff-row.reveal{opacity:1;transform:none}
.js .diff-row::before,.js .diff-row:last-child::after{transform:scaleX(0);
  transition:transform 1.1s cubic-bezier(.22,.61,.36,1)}
.js .diff-lead::before{transform:scaleX(0);
  transition:transform .7s cubic-bezier(.22,.61,.36,1) .35s}
.js .diff-row .diff-n,.js .diff-row .diff-t,.js .diff-row .diff-b{opacity:0;transform:translateY(12px);
  transition:opacity .7s var(--ease),transform .7s var(--ease)}
.js .diff-row .diff-n{transition-delay:.45s}
.js .diff-row .diff-t{transition-delay:.6s}
.js .diff-row .diff-b{transition-delay:.75s}

.js .diff-row.in::before,.js .diff-row.in:last-child::after,
.js .diff-row.in .diff-lead::before{transform:none}
.js .diff-row.in .diff-n,.js .diff-row.in .diff-t,.js .diff-row.in .diff-b{opacity:1;transform:none}

@media (prefers-reduced-motion:reduce){
  .js .diff-row::before,.js .diff-row:last-child::after,.js .diff-lead::before,
  .js .diff-row .diff-n,.js .diff-row .diff-t,.js .diff-row .diff-b{
    transform:none!important;opacity:1!important;transition:none!important}
}

/* ------------------------------------------------------------
   49 — /demands COLLAGE  ·  21 Sep
   Two photographs layered like a magazine spread rather than one photo beside
   a text block. The copy takes seven columns -- its measure was running past a
   hundred characters a line anyway -- and the collage the other five.
     A  the larger picture, set back, with a Sand hairline frame offset behind
     B  the smaller one, mounted like a print: an Ivory border, a soft shadow,
        and it sits over A's lower-left corner so the two read as one object
   No rotation. Straight edges keep it editorial.
   ------------------------------------------------------------ */
body[data-page="demands"] .prob-head{grid-column:1 / 8}
.collage{grid-column:8 / 13;position:relative;margin:clamp(8px,1vw,16px) 0 0;
  align-self:start;min-width:0;aspect-ratio:5 / 6}
.collage-frame{position:absolute;top:0;right:0;width:74%;aspect-ratio:4 / 5;
  border:1px solid var(--sand);transform:translate(16px,-16px);opacity:.75}
.collage-a{position:absolute;top:0;right:0;width:74%;aspect-ratio:4 / 5;overflow:hidden}
.collage-b{position:absolute;left:0;bottom:0;width:52%;aspect-ratio:1 / 1;
  padding:clamp(7px,.7vw,10px);background:var(--ivory);
  box-shadow:0 18px 44px rgba(35,35,35,.18),0 2px 6px rgba(35,35,35,.08)}
.collage img{display:block;width:100%;height:100%;object-fit:cover}
/* the print arrives a beat after the photograph it sits on */
.js .collage.reveal .collage-b{opacity:0;transform:translate(-14px,14px);
  transition:opacity .8s var(--ease) .35s,transform .8s var(--ease) .35s}
.js .collage.reveal.in .collage-b{opacity:1;transform:none}
@media (max-width:1000px){
  body[data-page="demands"] .prob-head{grid-column:1 / -1}
  .collage{grid-column:1 / -1;max-width:560px;margin-top:clamp(28px,6vw,44px)}
}
@media (prefers-reduced-motion:reduce){
  .js .collage.reveal .collage-b{opacity:1;transform:none;transition:none}
}

/* 21 Sep, Jacob: "the Arches.Legal isn't needed in the far right. I'd rather
   have the menu go all the way across." The signature is gone and the menu
   takes the full width beside the logo block, one row, spread edge to edge,
   so "Schedule a Consult" no longer drops onto a line of its own. */
@media (min-width:1101px){
  .foot-links{grid-column:5 / 13;justify-content:space-between;flex-wrap:nowrap}
}
@media (min-width:901px) and (max-width:1100px){
  .foot-links{grid-column:5 / 13}
}

/* /about's principles carry a one-line thesis above each paragraph */
.diff-b .prin-lede{font-weight:700;color:var(--fg);margin-bottom:clamp(8px,1vw,12px)}
.diff-b p + p{margin-top:0}

/* ------------------------------------------------------------
   50 — /demands PINNED STEPS  ·  21 Sep
   The steps and the product panel hold still while the page scrolls through
   four equal stretches, one per step, then release. Only .pinned (added by
   the JS when it can drive it) changes anything, so the fallback is the plain
   scrolling section.
   ------------------------------------------------------------ */
@media (min-width:1001px){
  /* 21 Sep: "still a little too much scrolling... that stop point is a little
     tough." 78vh a step became 42vh -- half the travel -- and the 1.4s hold
     still protects each animation from a fast flick. */
  .how-pin.pinned{height:calc(100vh + 4 * 42vh);height:calc(100svh + 4 * 42svh)}
  /* "the background scrolls as we go along": the texture belonged to the
     section, which kept moving under the pinned content. The pinned view now
     carries its own copy of the ground, so it holds still with everything else. */
  .how-pin.pinned .how-pin-in{position:sticky;top:0;height:100vh;height:100svh;
    display:flex;align-items:center;padding-top:clamp(64px,8vh,88px);
    background:var(--graphite) url("/assets/img/tex-graphite.webp") 0 0 / 512px 512px repeat}
  .how-pin.pinned .how-body{width:100%;align-items:center}
  /* the whole block is pinned now, so the panel stops being sticky on its own */
  .how-pin.pinned .stage{position:relative;top:auto;margin-top:0}
  .how-pin.pinned .chain{margin-top:0}
  /* four steps in one screen: every number and title, one paragraph */
  .how-pin.pinned .node{padding-bottom:clamp(16px,2.6vh,30px)}
  .how-pin.pinned .node .node-b{max-height:0;opacity:0;overflow:hidden;margin:0;
    transition:max-height .6s var(--ease),opacity .45s var(--ease),margin .6s var(--ease)}
  .how-pin.pinned .node.current .node-b{max-height:9em;opacity:1;margin-top:10px}
  .how-pin.pinned .node .node-q{margin-bottom:0;transition:opacity .4s var(--ease)}
  .how-pin.pinned .node:not(.current) .node-q{opacity:.55}
}

/* The collage carries the frame motif too (21 Sep), on the larger photograph.
   The deco box sits exactly over photo A; the arms run outside its top-left
   and bottom-right, clear of the picture, the way they sit outside the panel.
   The plain offset rectangle it replaces is gone. */
.collage-frame{display:none}
.collage-deco{position:absolute;top:0;right:0;width:74%;aspect-ratio:4 / 5;
  pointer-events:none;z-index:0}
.collage-a{z-index:1}.collage-b{z-index:2}
.collage-deco .deco{--deco-w:clamp(130px,12vw,190px);position:absolute;width:var(--deco-w);
  height:auto;color:var(--ocean);overflow:visible}
.collage-deco .deco.tl{top:calc(-1 * (0.0325 * var(--deco-w) + 16px));
  left:calc(-1 * (0.0325 * var(--deco-w) + 16px))}
.collage-deco .deco.br{bottom:calc(-1 * (0.0325 * var(--deco-w) + 16px));
  right:calc(-1 * (0.0325 * var(--deco-w) + 16px));transform:rotate(180deg)}
.js .collage.reveal .collage-deco{opacity:0;transition:opacity 1s var(--ease) .5s}
.js .collage.reveal.in .collage-deco{opacity:1}
/* on a phone the photograph sits against the page edge; no room outside it */
@media (max-width:700px){ .collage-deco{display:none} }

/* ------------------------------------------------------------
   51 — /demands "Upload the case" scene cleanup  ·  21 Sep
   The product panel sits inside a Graphite section, so the table inherited
   the section's Ivory text: case names and parties rendered white on the
   Ivory panel. The panel sets its own ink. And the status chips were three
   unrelated solid fills -- the Sand "In review" block in particular -- so
   they become one quiet family: tinted grounds, same size, same weight.
   ------------------------------------------------------------ */
.stage .gen{color:var(--graphite)}
.stage .ui-table td{color:rgba(35,35,35,.86)}
.stage .ui-table .case{color:var(--graphite)}
.stage .ui-table .meta{color:rgba(35,35,35,.56)}
.stage .ui-stat{font-size:10.5px;font-weight:700;letter-spacing:.02em;padding:3px 9px;
  border-radius:2px;box-shadow:none}
.stage .ui-stat.review{background:rgba(200,170,110,.2);color:#6b5427}
.stage .ui-stat.appr{background:rgba(0,111,129,.1);color:var(--ocean)}
.stage .ui-stat.draft{background:transparent;color:rgba(35,35,35,.62);
  box-shadow:inset 0 0 0 1px rgba(35,35,35,.18)}
.stage .ui-stat.done{background:var(--ocean);color:var(--ivory)}

/* ------------------------------------------------------------
   52 — /resources featured item, reduced  ·  21 Sep
   Jacob: "the image next to the sample demand letter is way too big. The whole
   sample demand section is way too massive." The photograph filled a whole
   column at 4:5 -- taller than the text beside it by half again -- and the
   title ran at section-headline size. Now the photograph is a 4:3 plate capped
   at 360px, the title steps down to a subheading, and the block's bottom rule
   and padding tighten, so it reads as the lead item of the index rather than
   a section of its own.
   ------------------------------------------------------------ */
.idx-lead{grid-template-columns:minmax(0,1.6fr) minmax(0,1fr);
  padding-bottom:clamp(26px,3vw,40px)}
.idx-lead-t{font-size:var(--t-h2)}
.idx-lead-fig--photo{aspect-ratio:4 / 3;max-width:360px;justify-self:end}
@media (max-width:820px){
  .idx-lead-fig--photo{aspect-ratio:16 / 10;max-width:none;justify-self:stretch}
}


/* The frame motif around the /demands customer proof (21 Sep): top-left of
   the photograph and bottom-right of the quote card, so it holds the pair as
   one composition. Ocean, since Sand on Ivory disappears. Desktop only, like
   every placement that sits outside its content. */
.proof-layer{position:relative}
.proof-deco{position:absolute;inset:0;pointer-events:none;z-index:0}
.proof-photo{position:relative;z-index:1}
.proof-deco .deco{--deco-w:clamp(130px,12vw,190px);position:absolute;width:var(--deco-w);
  height:auto;color:var(--ocean);overflow:visible}
.proof-deco .deco.tl{top:calc(-1 * (0.0325 * var(--deco-w) + 18px));
  left:calc(-1 * (0.0325 * var(--deco-w) + 18px))}
.proof-deco .deco.br{bottom:calc(-1 * (0.0325 * var(--deco-w) + 18px));
  right:calc(-1 * (0.0325 * var(--deco-w) + 18px));transform:rotate(180deg)}
@media (max-width:900px){ .proof-deco{display:none} }

/* 53 -- homepage fork: breathing room under the photo bands (Jacob, 21 Sep).
   The panels ended flush with the section, so the photos met the sea glass. */
body[data-page="home"] section.fork{padding-bottom:clamp(64px,7vw,112px)}

/* 54 -- small-label contrast (21 Sep audit). Ocean on Sea Glass and Sea Glass on
   Ocean both measure 4.26:1, under AA for 12px text. Large numerals pass at 3:1
   and keep the brand colour; only the small labels change.
   Deep-ocean ink on Sea Glass: 5.73:1. Ivory on Ocean: 5.8:1. */
.on-seaglass .eyebrow{color:#005a69}
.on-ocean .eyebrow,.on-ocean .duo-label{color:var(--ivory)}

/* 55 -- retired 22 Sep: the /mass-tort closer dropped its drawn arches for the sand-flats photograph. */

/* 56 -- product colours flip (22 Sep, Aaron): Demands leans ocean and blue,
   Mass Torts leans graphite and gold. The /demands steps move onto Ocean; the
   /mass-tort product walkthrough moves onto graphite.
   The pinned view paints its own copy of the ground, so it follows. */
@media (min-width:901px){
  .dm-how.on-ocean .how-pin.pinned .how-pin-in{
    background:var(--ocean) url("/assets/img/tex-ocean.webp") 50% 50% / cover no-repeat}
}
/* the Ocean plate under the panel disappears on an Ocean ground: graphite instead */
.dm-how.on-ocean .stage-plate{background:var(--graphite);opacity:.42}

/* 23 Sep: the divider line came off. Britt checked the reference sites --
   "none of them have a divider line. It just is like you either transition the
   colour, or it's all one colour." The grounds do the work now (see the page
   markup), and the seam carries the soft shadow Aaron was reaching for when he
   said "gradient": a shadow cast by the section above, not a painted fade. */
.sect + .sect{position:relative}
.sect + .sect::before{content:"";position:absolute;left:0;right:0;top:0;height:22px;
  background:linear-gradient(to bottom,rgba(0,0,0,.14),rgba(0,0,0,0));
  pointer-events:none;z-index:2}
/* no shadow where a section opens on a photograph or a video of its own */
.final--bleed + .sect::before,.sect.hero--bleed + .sect::before,
.sect.compliance::before{content:none}

/* 57 -- homepage, 22 Sep review.
   Trust label: "it blends in with the logos" (Britt). Ocean, which measures
   5.4:1 on Ivory at label size. */
.firms-lab{color:var(--ocean)}
/* Fork. Aaron: "the product names get super lost because of the font size...
   the product name should feel just as prominent as the headline of what it's
   for." The name becomes the first line of the heading, same face and size;
   the "for..." line follows it, a step quieter in colour only. */
.duo-label{font-family:var(--f-display);font-weight:400;text-transform:none;
  letter-spacing:-.012em;font-size:var(--t-h3);line-height:1.1;color:var(--fg)}
.on-ocean .duo-label{color:var(--ivory)}
.duo-head{margin-top:.12em;color:var(--soft)}
/* "I want the buttons to be aligned." The two leads run different lengths, so
   both panels share one set of rows: name, heading, lead, button, photograph. */
@media (min-width:901px){
  .duo{grid-template-rows:auto auto auto auto 1fr}
  .duo-panel{display:grid;grid-row:span 5;grid-template-rows:subgrid;row-gap:0;
    align-content:start}
  .duo-panel > .duo-foot{align-self:end}
  .duo-photo{margin-top:0;align-self:end}
}

/* 58 -- footer with substance (22 Sep review). Brand block left, three short
   columns right: talk to us, customers, company. */
.foot-in--cols{align-items:start}
.foot-in--cols .foot-a{grid-column:1 / 5}
.foot-col{grid-column:span 2;min-width:0}
.foot-in--cols .foot-col:nth-of-type(2){grid-column:7 / 9}
.foot-in--cols .foot-col:nth-of-type(3){grid-column:9 / 11}
.foot-in--cols .foot-col:nth-of-type(4){grid-column:11 / 13}
.foot-h{font-family:var(--f-text);font-weight:700;text-transform:uppercase;letter-spacing:.06em;
  font-size:var(--t-eyebrow);color:var(--sand);margin-bottom:16px}
.foot-col ul{list-style:none;margin:0;padding:0;display:grid;gap:10px}
.foot-col a,.foot-col span{font-size:var(--t-small);color:rgba(255,255,250,.74);text-decoration:none}
.foot-col a:hover{color:var(--ivory);text-decoration:underline;text-underline-offset:4px}
/* 29 Sep: the real office address replaces the pending placeholder. Not a link,
   so it needs the list type sizing the anchors were carrying. */
.foot-addr{font-size:var(--t-small);color:rgba(255,255,250,.74);line-height:1.5}
/* 11 Oct: privacy and terms sit on the copyright bar, not in a nav column --
   they are obligations, not navigation. */
.foot-legal{display:inline-flex;gap:clamp(16px,2vw,26px);flex-wrap:wrap}
.foot-legal a{color:rgba(255,255,250,.6);font-size:var(--t-small);text-decoration:none}
.foot-legal a:hover{color:var(--ivory);text-decoration:underline;text-underline-offset:4px}
/* 12 Oct: the legal bar now carries four documents, so it wraps rather than
   fighting the copyright line for one row. */
.foot-bar{align-items:flex-start}
.legal-note{margin:0 0 clamp(26px,3vw,40px);padding:clamp(14px,1.6vw,20px) clamp(16px,1.8vw,22px);
  border-left:2px solid var(--sand);background:rgba(200,170,110,.08);
  font-size:var(--t-small);color:var(--fg)}
/* review-build only: a visible, labelled gap where Britt's detail goes */
.foot-tbd{border-bottom:1px dashed rgba(200,170,110,.6);font-style:italic}
@media (max-width:900px){
  .foot-in--cols .foot-a{grid-column:1 / -1}
  .foot-in--cols .foot-col:nth-of-type(n){grid-column:span 4}
}
@media (max-width:560px){
  .foot-in--cols .foot-col:nth-of-type(n){grid-column:1 / -1}
}

/* 59 -- /demands steps, 22 Sep review. The heading moved inside the pinned
   view, so the pinned view stacks heading then steps and centres the pair. */
@media (min-width:901px){
  .how-pin.pinned .how-pin-in{flex-direction:column;justify-content:center;align-items:stretch}
  .how-pin.pinned .how-head{margin-bottom:clamp(28px,4vh,48px)}
  .how-pin.pinned .how-head .h1{font-size:var(--t-h1-sm)}
  /* the Ocean texture is cover-sized, so a second copy on the pinned view drew a
     visible box. Hold the section's own texture still instead and let the
     pinned view be transparent. */
  .dm-how.on-ocean{background-attachment:fixed}
  .dm-how.on-ocean .how-pin.pinned .how-pin-in{background:none}
}
/* on Ocean the Sand step numbers fell to about 2.4:1; Ivory holds, and the
   diamonds keep the gold */
.dm-how.on-ocean .node-n{color:rgba(255,255,250,.86)}
@media (min-width:901px){
  .dm-how.on-ocean .how-pin.pinned .node:not(.current) .node-q{opacity:.68}
}

/* 60 -- "Analyze the record" as a readable page (22 Sep review) */
.sc-an{display:flex;flex-direction:column;height:100%}
.sc-an .an-doc{flex:1;padding:18px 20px 16px;min-height:0}
.an-top{display:flex;justify-content:space-between;gap:12px;margin:0 0 12px;padding-bottom:10px;
  border-bottom:1px solid rgba(35,35,35,.14);font-family:var(--f-text);font-weight:700;
  font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:rgba(35,35,35,.62)}
.an-rec{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:7px 16px;margin:0;
  font-family:var(--f-text);font-size:12px;line-height:1.5;color:rgba(35,35,35,.84)}
.an-rec dt{font-weight:700;color:rgba(35,35,35,.6);font-size:10.5px;letter-spacing:.04em;
  text-transform:uppercase;padding-top:2px}
.an-rec dd{margin:0}
.an-rec mark{background:transparent;color:inherit;border-radius:2px;padding:0 2px;
  transition:background-color .5s var(--ease)}
/* each finding lights in turn while the scan runs, and stays lit */
.js .stage[data-step="1"] .an-rec mark{animation:anHit .6s var(--ease) forwards;
  animation-delay:calc(.5s + var(--i) * .7s)}
@keyframes anHit{to{background:rgba(0,111,129,.16)}}
@media (prefers-reduced-motion:reduce){ .an-rec mark{background:rgba(0,111,129,.16)} }
.sc-an .an-doc{display:block}

/* 61 -- /demands, 22 Sep review.
   Collage: "I want to see the Art Deco framing... I don't love it behind the
   image." The frame now sits over both photographs, at the heavier weight. */
.collage-deco{z-index:3}
.collage-deco .deco,.proof-deco .deco{--deco-stroke:1.75px}
/* "More padding above and below the watermark so this feels more substantial" */
.dm-stmt{padding-block:clamp(104px,11vw,168px)}

/* 62 -- /about principles, 22 Sep review. Aaron: "grow the bold part of the
   line as you're scrolling... why stop there? Send it a third of the way
   across." And Britt wanted the rows to build a little more visibly, without
   the stacking effect everyone found annoying before: a longer, slower draw
   and a deeper rise. Scoped to /about; the homepage rows are unchanged. */
body[data-page="about"] .diff-lead::before{width:clamp(160px,28vw,430px)}
body[data-page="about"] .js .diff-lead::before,
.js body[data-page="about"] .diff-lead::before{transition-duration:1.5s}
.js body[data-page="about"] .diff-row .diff-n,
.js body[data-page="about"] .diff-row .diff-t,
.js body[data-page="about"] .diff-row .diff-b{transform:translateY(26px);transition-duration:.9s}
.js body[data-page="about"] .diff-row.in .diff-n,
.js body[data-page="about"] .diff-row.in .diff-t,
.js body[data-page="about"] .diff-row.in .diff-b{transform:none}

/* ------------------------------------------------------------
   63 — TWO TIERS OF RUNNING TEXT, SET ON PURPOSE  ·  22 Sep
   Jacob: "why does the first paragraph look larger than the smaller one
   below it?" The site has exactly two prose sizes, the deck (--t-lead) and
   the body (--t-body), which is right. What made the step read as an
   accident rather than a hierarchy:
     1. both were measured in ch, and a ch is a fraction of each paragraph's
        OWN size -- so 52ch under a deck is 716px and 52ch of body is 570px.
        Two ragged edges 146px apart, stacked, with no reason a reader can see.
     2. the gap between them was paragraph-sized, so the size change looked
        like a slip instead of a new tier.
   So: one measure in px shared by both tiers, and a deliberate step of space
   between the deck and the body under it. The sizes themselves do not change.
   ------------------------------------------------------------ */
:root{--measure:min(100%,clamp(360px,42vw,600px));
  --tier-gap:clamp(22px,2.4vw,32px)}

/* the bleed heroes: deck, then supporting line */
.hero--bleed .hero-sub,.hero--bleed .hero-sub2{max-width:var(--measure)}
.hero--bleed .hero-sub2{margin-top:var(--tier-gap)}

/* /about hero: deck, the six-word statement, then the supporting line. The
   block already holds the measure, so the paragraphs stop setting their own
   and all three edges line up. */
.about-intro{max-width:var(--measure)}
.about-intro .hero-sub,.about-intro-b{max-width:none}
.about-intro-line{margin-top:var(--tier-gap)}
.about-intro-b{margin-top:clamp(14px,1.6vw,20px)}

/* /about origin: the standfirst and the paragraphs under it */
.origin-prose{max-width:var(--measure)}
.origin-prose .origin-sub{margin-bottom:var(--tier-gap)}

/* ------------------------------------------------------------
   64 — 23 Sep review with Britt
   ------------------------------------------------------------ */
/* Line weight. "You've increased the line weight on a number of things. I think
   we need to increase it on the navigation, and in the eyebrow when it has the
   line." The frame motif now draws at 1.5-1.75px, so the hairlines beside it
   read as leftovers. The eyebrow rule keeps its 96px length. */
.eyebrow--rule::after{height:3px;background:currentColor;opacity:.55}
.nav-links a::after{height:2px}
/* the eyebrow rule must not compete with the frame motif: where a block carries
   the motif, the rule stays quieter */
.final-in .eyebrow--rule::after,.stage-wrap .eyebrow--rule::after{opacity:.42}

/* The trust label is a headline, not an eyebrow (Britt): centred, larger, and
   back to the quiet ink. The Ocean was solving the wrong problem. */
.firms-lab{font-family:var(--f-display);font-weight:400;text-transform:none;
  letter-spacing:-.008em;font-size:var(--t-h3);line-height:1.15;
  color:rgba(35,35,35,.82);text-align:center;
  margin-bottom:clamp(34px,4vw,52px)}
@media (max-width:860px){ .firms-lab{padding-left:0} }
/* the slate variant of the security band: the asphalt texture instead of water,
   which Britt asked to see used in more places */
/* 25 Sep: the container changed from .comp-video to .comp-still when the clip
   was replaced, and this rule stopped matching -- the water came back on
   /demands and ran Ocean into Ocean again. */
.compliance--slate .comp-video,.compliance--slate .comp-still{display:none}
/* the engine block was written for a dark ground; on Stone its ink flips. The
   chain, the tunnel rings and the numerals all follow the section now. */
.engine.on-stone .engine-lead{color:var(--soft)}
.engine.on-stone .node-q{color:var(--fg)}
.engine.on-stone .node-b{color:var(--soft)}
.engine.on-stone .eng-tunnel .ring path{stroke:rgba(200,170,110,.5)}
.engine.on-stone .eng-tunnel{opacity:.5}

/* ------------------------------------------------------------
   65 — the security band, rebuilt  ·  23 Sep, Britt
   "I hate the overlap of the connecting lines. It feels unfinished and
   unclean." / "The shapes aren't doing anything for me on the outside. Let the
   icons stand for themselves." / "If this is our security posturing visually,
   it needs to feel strong, and it feels light... like line-work tattoos."
   So: the arch bays, their keystones and the plinth rule are gone. Each mark
   sits inside a diamond -- the shape the brand already owns, and the one she
   pointed at on the references -- and the strokes are twice the weight.
   ------------------------------------------------------------ */
.certs li{--cw:clamp(56px,5.4vw,78px);--pt:clamp(34px,3.6vw,52px);
  border:0;border-radius:0;
  padding:var(--pt) clamp(14px,1.6vw,22px) clamp(24px,2.4vw,32px)}
.certs li::before{content:"";position:absolute;
  top:calc(var(--pt) + var(--cw) / 2);left:50%;
  width:calc(var(--cw) * 1.66);height:calc(var(--cw) * 1.66);
  background:none;border:2px solid var(--sand);
  transform:translate(-50%,-50%) rotate(45deg)}
.certs li::after{content:none}
/* the diamond is 1.66 x the mark on its side, so its bottom point falls
   1.17 x below the mark's centre. The label clears that, not the mark. */
.cert-mark{width:var(--cw);color:var(--ivory);
  margin-bottom:calc(var(--cw) * 0.92);position:relative;z-index:1}
/* stroke weight now set with the new marks further down (2px) */
.cert-mark .s{stroke-linecap:butt}
.certs .cert-l{position:relative;z-index:1}
/* on the Ivory band the diamond and the marks take the page's accent */
.compliance--home .certs li::before{border-color:var(--ocean)}
.compliance--home .cert-mark{color:var(--ocean)}

/* 66 -- hero type, 23 Sep. Britt on /demands and /about: "you've got three
   different [sizes] going on right here. It's super distracting... I'd almost
   want to see this paragraph in this size." The supporting line joins the deck
   rather than dropping a tier inside the same block; the colour still steps. */
.hero--bleed .hero-sub2,.about-intro-b{font-size:var(--t-lead);line-height:1.55}
/* the steps are clickable now, so they look it */
.dm-how .node{cursor:pointer}
.dm-how .node:focus-visible{outline:2px solid var(--sand);outline-offset:6px}
.dm-how .node:hover .node-q{color:var(--ivory)}
/* the scenes fill the panel (Britt: "there's a ton of white space on the bottom
   of that box... just make sure it fills the space") */
.stage .scene{display:flex;flex-direction:column}
.sc-bd .gen-p{flex:1}
.sc-rv{justify-content:space-between}
.sc-rv .rv-row{padding-block:clamp(10px,1.4vw,16px)}

/* 67 -- the water behind the security band, 23 Sep, Britt: "such a zoomed out
   image of an ocean... I can tell that it's a repeated video. It's almost like
   two videos." and "maybe had it lighter so it's not nearly as dark."
   The clip is 1280x720 covering a 1440+ band, so its texture read as tiling.
   Scaled up it becomes macro -- surface detail rather than a whole sea -- and
   the scrim lifts. Contrast is measured on the render, not guessed. */
/* the still that replaced the clip: ours, sharp at band width, and it holds
   still, which is the third thing the video kept getting wrong */
.comp-still{position:absolute;inset:0;z-index:-1;pointer-events:none;overflow:hidden;
  background:var(--ocean) url("/assets/img/comp-ocean-poster.jpg") center/cover no-repeat}
.comp-still img,.comp-still video{width:100%;height:100%;object-fit:cover;display:block}
.comp-still::after{content:"";position:absolute;inset:0;background:rgba(9,38,44,.5)}
/* "the icons are so small inside such a large shape" -- the mark grows and the
   diamond tightens around it */
.certs li{--cw:clamp(72px,7vw,96px)}
.certs li::before{width:calc(var(--cw) * 1.42);height:calc(var(--cw) * 1.42)}
.cert-mark{margin-bottom:calc(var(--cw) * 0.72)}
.cert-mark .s{stroke-width:2}
/* 25 Sep, Jacob: on the Stone engine the Sand step labels measured 1.95:1.
   Ocean holds at 5.12:1 and keeps the diamond and the rule in gold. */
.engine.on-stone .node-n{color:var(--ocean)}

/* 68 -- mobile audit, 25 Sep: footer links were 17px tall, under the 40px a
   thumb needs. Only on touch widths, so the desktop footer keeps its rhythm. */
@media (max-width:900px){
  .foot-col ul{gap:0}
  .foot-col li{display:flex;align-items:center;min-height:44px}
  .foot-col li + li{border-top:1px solid rgba(255,255,250,.08)}
}

/* 69 -- 25 Sep: the outcome chain sat in Sand on the Stone engine at 1.95:1.
   Ocean holds 5.12:1; the rule above it stays gold. */
.engine.on-stone .outcome{color:var(--ocean)}
.engine.on-stone .outcome .sep{opacity:.55}
/* the statement band that came out of the /about hero */
.about-stmt-in{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(24px,4vw,64px);align-items:start}
.about-stmt-b{color:var(--soft);max-width:var(--measure)}
/* markup #102, Britt: "Edit this headline to ocean." The band sits on
   on-ivory, so ocean clears contrast comfortably at display size. */
body[data-page="about"] #stmt-h{color:var(--ocean)}
@media (max-width:860px){ .about-stmt-in{grid-template-columns:1fr;gap:clamp(16px,3vw,24px)} }

/* ------------------------------------------------------------
   70 — the hero stops short of the fold  ·  29 Sep, Jacob
   "The hero video is too tall, let's make it so you can see the start of the
   next section." It was a strict 16:9 band, so at 1440 it stood 810px tall and
   a 13-inch laptop saw none of the trust strip below it.
   The hero is now the shorter of its 16:9 height and 76% of the viewport, so a
   slice of the next section is always showing. Below that height the footage
   is cropped top and bottom rather than letterboxed -- a crop keeps the frame
   full width and nothing is ever stretched, which was the original rule.
   ------------------------------------------------------------ */
@media (min-width:761px){
  body[data-page="home"] .hero--bleed:has(.hero-cut-video){
    aspect-ratio:auto;
    /* 12 Oct, Britt: "what's going on with the hero?" -- the CTA was spilling
       out of the hero on a short window. Measured: 39px over at 1280x600, and
       only 7px of clearance at 1440x700. A fixed `height` cannot do anything
       but clip once the copy needs more room than the cap allows.
       min-height keeps the cap as the target and lets the block grow when it
       has to, so the button is never cut off. At 1280x600 the hero settles at
       ~495px against a 600px viewport, so the next section still shows -- the
       whole point of capping it in the first place. */
    min-height:min(calc(100vw * 9 / 16), 76vh);
    min-height:min(calc(100vw * 9 / 16), 76svh)}
  body[data-page="home"] .hero--bleed:has(.hero-cut-video) .hero-bleed-media video{
    object-fit:cover}
}
/* The copy block was a fixed 773px tall -- 196 of top padding, an 80px
   headline, a five-line subhead and wide gaps -- so simply capping the hero
   clipped the CTA. Its rhythm now scales with the viewport's height, so on a
   short laptop everything tightens instead of overflowing. */
@media (min-width:761px){
  body[data-page="home"] .hero--bleed:has(.hero-cut-video){
    padding-top:clamp(104px,16vh,196px);padding-bottom:clamp(30px,5vh,64px)}
  body[data-page="home"] .hero--bleed:has(.hero-cut-video) h1{
    font-size:min(var(--t-h1),8.4vh)}
  body[data-page="home"] .hero--bleed:has(.hero-cut-video) .hero-eyebrow{
    margin-bottom:clamp(14px,2.4vh,32px)}
  body[data-page="home"] .hero--bleed:has(.hero-cut-video) .hero-sub{
    margin-top:clamp(16px,2.6vh,38px);max-width:min(100%,clamp(520px,54vw,760px))}
  body[data-page="home"] .hero--bleed:has(.hero-cut-video) .hero-cta{
    margin-top:clamp(22px,3.4vh,52px)}
}

/* ------------------------------------------------------------
   71 — the same for the interior heroes  ·  29 Sep, Jacob
   "Probably want to do this for all the headers." /demands, /mass-tort and
   /about each filled the viewport exactly, so nothing below them ever showed.
   On a 13-inch screen /demands was worse than that: its copy ran 780px against
   an 800px viewport, so the hero was already overflowing.

   These use min-height rather than a fixed height, so the copy can never be
   clipped -- a long subhead just makes the hero taller than the floor. The
   rhythm scales with viewport height the same way the homepage does.
   Does not touch the homepage video hero, which has its own block above.
   ------------------------------------------------------------ */
@media (min-width:761px){
  body:not([data-page="home"]) .hero--bleed{
    min-height:82vh;min-height:82svh;
    padding-block:clamp(134px,17vh,250px) clamp(40px,5vh,96px)}
  body:not([data-page="home"]) .hero--bleed h1{font-size:min(var(--t-h1),8.4vh)}
  body:not([data-page="home"]) .hero--bleed .hero-eyebrow{
    margin-bottom:clamp(14px,2.4vh,32px)}
  body:not([data-page="home"]) .hero--bleed .hero-sub{margin-top:clamp(16px,2.6vh,40px)}
  body:not([data-page="home"]) .hero--bleed .hero-sub2{margin-top:clamp(14px,2.2vh,32px)}
  body:not([data-page="home"]) .hero--bleed .hero-cta{margin-top:clamp(22px,3.4vh,52px)}
}
/* 29 Sep, Jacob: two heights, not one. Home, /demands and /mass-tort stay tall
   at the 82vh floor above; /about drops to the shorter band /resources uses, so
   the two reference pages match each other and the product pages lead. */
@media (min-width:761px){
  body[data-page="about"] .hero--bleed,body[data-page="resources"] .res-mast--bleed{
    min-height:clamp(520px,69vh,660px);
    padding-block:clamp(130px,17vh,210px) clamp(58px,7vw,92px)}
}

/* ------------------------------------------------------------
   72 — 29 Sep checkpoint with Britt
   ------------------------------------------------------------ */
/* "This line here is doing nothing for me." The rule above the trust marks sat
   directly over four diamonds and their linework; Jacob: "it's a distraction
   because you've got so much line work below it." */
.certs{border-top:0;padding-top:clamp(18px,2.4vw,32px)}

/* "I want to see this centered... left-aligned it feels like leftover copy." */
.final-micro{text-align:center}

/* The drawn arches behind the engine were gold at low opacity and disappeared
   into the ground. Sea Glass reads without pulling focus. */
.eng-tunnel .ring path{stroke:rgba(195,227,214,.5)}
.engine.on-stone .eng-tunnel .ring path{stroke:rgba(0,111,129,.32)}

/* The /about numbered rows took a longer bar on 21 Sep at Aaron's request.
   Britt, 29 Sep: it reads "like a loading bar that isn't finished" -- back to
   the homepage's shorter bar, which frames the numeral instead. */
body[data-page="about"] .diff-lead::before{width:clamp(56px,6vw,88px)}
/* The chain on /demands and /mass-tort read lighter than the homepage rows:
   "this feels like I'm going to scroll past it." The numeral carries it, with
   the spine and its diamond a touch heavier. */
.chain .node-n{font-size:clamp(1.15rem,1.6vw,1.5rem);letter-spacing:-.01em}
.chain .node::before{width:13px;height:13px}
.chain-svg .ln{stroke-width:1.6}

/* Britt on the /demands collage: the photographs want something under them.
   A 3px radius and a soft shadow, both products, nothing more. */
.collage-a img,.collage-b img,.collage-a picture,.collage-b picture{border-radius:3px}
.collage-a,.collage-b{border-radius:3px;overflow:hidden;
  box-shadow:0 18px 40px rgba(20,19,17,.22)}

/* ============================================================
   SECTION 73 — markup #15, Smita: "CTA requires a scroll - added friction."
   The form head was carrying hero-scale padding above it on a page whose
   only job is the form. Top padding and the head gap come down at desktop
   so the submit sits inside the first screen; phones are unchanged, where
   a scroll is expected anyway.
   ============================================================ */
@media (min-width:900px){
  body[data-page="schedule"] .sect.pad{padding-block:clamp(104px,11vh,140px) clamp(48px,5vw,72px)}
  body[data-page="schedule"] .sched-head .h1{margin-top:clamp(14px,1.6vw,20px)}
  body[data-page="schedule"] .sched-form-head{margin-bottom:clamp(16px,1.8vw,22px)}
}

/* ============================================================
   SECTION 74 — markup #101, Britt: "Let's try this as a horizontal
   navigation." The tour was already a real tablist; only the layout was
   vertical. At desktop the four steps now run as a row above the screen,
   with the progress rule and its diamonds turned horizontal. The markup,
   the JS and the whole stacked-phone behaviour below 1000px are untouched.
   ============================================================ */
@media (min-width:1000px){
  .tour{grid-template-columns:1fr;gap:clamp(28px,3vw,44px)}
  .tour-side{display:block}
  /* the rail no longer needs to pace the stage, and the stage no longer
     needs to stick: everything is in document order top to bottom now.
     12 Oct: and it has to centre. The frame is capped at 1060 inside a 1296
     column, so flush-left left 236px of dead space to its right and the
     mockup read as off-axis under a row of four evenly spaced steps. The
     stage is a flex column, so align-items does it -- and the stage's centre
     line is the wrap's centre line, so this centres on the page too. */
  .tour-stage{position:static;padding-top:0;align-items:center}
  .tour-steps{grid-template-columns:repeat(4,minmax(0,1fr));
    gap:clamp(14px,1.5vw,24px);
    padding-left:0;padding-top:clamp(30px,3vw,42px);
    margin-top:clamp(16px,1.8vw,24px)}
  /* rule runs across the top of the row instead of down its left edge */
  .tour-steps::before,.tour-steps::after{left:0;right:auto;top:5px;bottom:auto;
    width:100%;height:1px}
  .tour-steps::after{width:var(--fill,0%);height:1px;
    transition:width var(--fill-t,.45s) linear}
  .tour-steps > li{flex-direction:column}
  .tour-steps > li > button{height:100%}
  /* diamond sits on the rule above its own step */
  .tour-steps > li::before{top:calc(clamp(30px,3vw,42px) * -1 + 0.5px);
    left:0;transform:rotate(45deg)}
  .tour-steps .h{min-height:2.6em}
}
/* Between 1000 and 1200 four columns get tight, so the descriptions step
   down rather than wrapping to six lines each. */
@media (min-width:1000px) and (max-width:1200px){
  .tour-steps .d{font-size:.82rem;line-height:1.5}
}

/* ============================================================
   SECTION 75 — markup #89, Britt: "Edit this component to a horizontal click
   through slider/nav." Same pattern as the /mass-tort tour in Section 74, so
   the two product pages now teach the same interaction. The four steps run
   across the top with a progress rule, and the product panel sits underneath
   at full width instead of beside a column of them.
   Scoped to .dm-how only -- /mass-tort's .engine chain is still the vertical
   spine it has always been.
   ============================================================ */
@media (min-width:1001px){
  .dm-how .how-body{grid-template-columns:1fr;gap:clamp(30px,3.4vw,48px)}
  .dm-how .chain{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
    gap:clamp(14px,1.6vw,26px);
    padding:clamp(30px,3vw,42px) 0 0;margin-top:clamp(22px,2.4vw,34px);
    position:relative}
  /* the drawn spine is vertical by construction; the row gets a rule instead */
  .dm-how .chain .chain-svg{display:none}
  .dm-how .chain::before,.dm-how .chain::after{content:"";position:absolute;
    left:0;top:5px;height:1px;pointer-events:none}
  .dm-how .chain::before{width:100%;background:var(--line-light)}
  .dm-how .chain::after{width:var(--fill,25%);background:var(--sand);
    transition:width .45s var(--ease)}
  .dm-how .chain > li{z-index:1}
  .dm-how .node{padding-bottom:0;cursor:pointer}
  .dm-how .node::before{top:calc(clamp(30px,3vw,42px) * -1 + 0.5px);left:0}
  .dm-how .node-q{min-height:2.5em}
  .dm-how .node-b{max-width:none}
  /* panel below the row, no longer sticky beside it */
  .dm-how .stage{position:static;margin-top:0}
  /* the keyboard focus ring needs somewhere to sit now the node is the target */
  .dm-how .node:focus-visible{outline:2px solid var(--sand);outline-offset:8px}
}
@media (min-width:1001px) and (max-width:1240px){
  .dm-how .node-b{font-size:.86rem;line-height:1.55}
}

/* ============================================================
   SECTION 76 — 12 Oct fixes on /demands
   ============================================================ */

/* The dark slab and the stray gold lines. .dm-how .stage carries
   max-width:none, which was right when the panel lived in its own narrow
   column beside the steps. Once Section 75 stacked the layout the stage
   became full-bleed, and two things that are sized RELATIVE to it blew up
   with it: .stage-plate is inset 46% from the left, so it became a half-page
   Ocean rectangle, and .stage .deco sits at the stage's own corners, so the
   business-card corner drifted out to the section edges and read as a frame
   round the whole band. Giving the stage a real width puts both back in
   proportion to the panel they belong to. */
@media (min-width:1001px){
  .dm-how .stage{max-width:min(100%,980px);margin-inline:auto}
  /* And the plate goes. It is graphite at 42% -- on the Graphite ground this
     section used to sit on it read as a shadow the panel rested on. On Ocean
     it is just a dirty rectangle, and because it is anchored to the stage it
     slides around as the section scrolls, which is the "glitching" Jacob kept
     seeing. The panel is 980px and centred now; it does not need something to
     sit on. */
  .dm-how .stage-plate{display:none}
  /* The business-card corners go with it, for the same reason. They are
     positioned OUTSIDE the panel -- the top-left one hangs 35px above it --
     which worked when the panel was a tall block in its own column with empty
     space around it. Stacked, that 35px lands in the step copy above, so the
     gold hairlines cross the text and travel over it as the section scrolls.
     That is the gold framing Jacob kept seeing glitch. The panel already has
     its own hairline and shadow; it does not need corners as well, and one
     framing device per block is the rule anyway. */
  .dm-how .stage .deco{display:none}
}

/* markup #86 and #87, Britt: "increase # size across this component" and
   "increase left line weight & diamond", plus Jacob 12 Oct: "increase the
   size of the numbers and make them ocean colour a bit."
   The numbers were at --t-eyebrow, the same size as the label above them, so
   they read as a tag rather than a step. Ocean on Stone measures 5.9:1. */
.dm-why .prob-n,
body[data-page="demands"] .prob-n{
  font-size:clamp(1.1rem,1.5vw,1.45rem);
  letter-spacing:.02em;
  color:var(--ocean)}
/* the resting/dimmed state has to follow, or the colour snaps on hover */
.js body[data-page="demands"] .prob-row:not(.active) .prob-n{
  color:rgba(0,111,129,.62)}
.js body[data-page="demands"] .prob-row:hover .prob-n,
.js body[data-page="demands"] .prob-row.active .prob-n{color:var(--ocean)}

/* the CTA now sits under the section headline rather than after the steps */
/* .how-cta carried the chain's left padding so it lined up with the step
   nodes. Under the headline it has to sit flush with the eyebrow and the h2
   instead -- it was 40px in from both. */
.how-cta--head{margin:clamp(24px,2.8vw,36px) 0 0;padding-left:0}

/* ============================================================
   SECTION 77 — the form panel. 12 Oct, Jacob: "Can we highlight the form
   better? Maybe make it on white or something? It just feels a little
   jarring here."
   The form sat on the same graphite as the copy beside it with nothing
   around it, so it read as loose fields rather than as one thing to fill
   in. It gets an Ivory panel.

   The panel carries .on-ivory, so --fg, --soft, --faint, --line and
   --accent all flip with the ground and the headings inside it need no
   rules of their own. What does need rules is the HubSpot skin above:
   it is written for a dark panel and hardcodes Ivory field text,
   rgba(255,255,250,..) labels and placeholders, a graphite dropdown and
   a Sand focus. Every one of those is reversed below.

   All of it is scoped to .form-panel. The Mass Torts consult modal is
   still on graphite and is deliberately untouched -- it opens over a dark
   page and a white card inside it would be a second window.

   Side effect worth having: the reCAPTCHA on the eBook form is a white
   Google iframe that cannot be themed. On graphite it read as a hole.
   On Ivory it simply sits there.
   ============================================================ */
.form-panel{padding:clamp(24px,2.8vw,38px);border-radius:3px;
  box-shadow:0 26px 56px rgba(20,19,17,.26)}

/* ---- the --hsf-* variable layer ---- */
.form-panel #hs-form-mount [data-hsfc-id="Renderer"]{
  --hsf-default-field-input__border-color:var(--line-dark);
  --hsf-default-field-input__placeholder-color:rgba(35,35,35,.38);
  --hsf-default-field-textarea__border-color:var(--line-dark)}

/* ---- labels. The inline black HubSpot bakes in is finally the right
       colour family here, but it is #000 flat, so it still gets reset. ---- */
.form-panel #hs-form-mount .hsfc-FieldLabel,
.form-panel #hs-form-mount .hsfc-FieldLabel span{color:rgba(35,35,35,.72)}
.form-panel #hs-form-mount .hsfc-FieldLabel span:not(.hsfc-FieldLabel__RequiredIndicator){
  color:rgba(35,35,35,.72)!important}
.form-panel #hs-form-mount .hsfc-FieldLabel__RequiredIndicator,
.form-panel #hs-form-mount .hsfc-FieldLabel span.hsfc-FieldLabel__RequiredIndicator{
  color:var(--ocean)}

/* ---- text, email, textarea ---- */
.form-panel #hs-form-mount .hsfc-TextInput,
.form-panel #hs-form-mount .hsfc-TextareaInput{
  color:var(--graphite);border-bottom-color:var(--line-dark)}
.form-panel #hs-form-mount .hsfc-TextInput:focus,
.form-panel #hs-form-mount .hsfc-TextareaInput:focus{border-bottom-color:var(--ocean)}
.form-panel #hs-form-mount .hsfc-TextInput::placeholder,
.form-panel #hs-form-mount .hsfc-TextareaInput::placeholder{color:rgba(35,35,35,.38)}
/* the autofill repaint has to follow the panel, or Chrome fills graphite */
.form-panel #hs-form-mount .hsfc-TextInput:-webkit-autofill{
  -webkit-text-fill-color:var(--graphite);
  -webkit-box-shadow:0 0 0 1000px var(--ivory) inset;
  caret-color:var(--graphite)}

/* ---- the custom dropdown, including its popover ---- */
.form-panel #hs-form-mount .hsfc-DropdownInput{
  color:var(--graphite);border-bottom-color:var(--line-dark)}
.form-panel #hs-form-mount .hsfc-DropdownInput:focus-within{border-bottom-color:var(--ocean)}
.form-panel #hs-form-mount .hsfc-DropdownInput__Caret,
.form-panel #hs-form-mount .hsfc-DropdownInput__Caret *{color:var(--ocean)}
.form-panel #hs-form-mount .hsfc-DropdownInput__Caret svg{fill:var(--ocean);stroke:var(--ocean)}
.form-panel #hs-form-mount .hsfc-TextInput--button{color:var(--graphite)}
.form-panel #hs-form-mount .hsfc-DropdownOptions{
  background:var(--ivory);border-color:var(--line-dark);color:var(--graphite)}
.form-panel #hs-form-mount .hsfc-DropdownOptions__List__ListItem{color:var(--graphite)}
.form-panel #hs-form-mount .hsfc-DropdownOptions__List__ListItem:hover,
.form-panel #hs-form-mount .hsfc-DropdownOptions__List__ListItem[aria-selected="true"]{
  background:rgba(0,111,129,.12);color:var(--graphite)}
.form-panel #hs-form-mount .hsfc-DropdownOptions__Search input{
  color:var(--graphite);border-bottom-color:var(--line-dark)}

/* ---- checkboxes and radios ---- */
.form-panel #hs-form-mount .hsfc-CheckboxFieldGroup__Options .hsfc-FieldLabel,
.form-panel #hs-form-mount .hsfc-RadioFieldGroup__Options .hsfc-FieldLabel{color:rgba(35,35,35,.84)}
.form-panel #hs-form-mount .hsfc-CheckboxFieldGroup__Options .hsfc-FieldLabel span,
.form-panel #hs-form-mount .hsfc-RadioFieldGroup__Options .hsfc-FieldLabel span,
.form-panel #hs-form-mount .hsfc-CheckboxFieldGroup__Options .hsfc-FieldLabel span:not(.hsfc-FieldLabel__RequiredIndicator),
.form-panel #hs-form-mount .hsfc-RadioFieldGroup__Options .hsfc-FieldLabel span:not(.hsfc-FieldLabel__RequiredIndicator){
  color:rgba(35,35,35,.84)!important}
.form-panel #hs-form-mount .hsfc-CheckboxInput,
.form-panel #hs-form-mount .hsfc-RadioInput{accent-color:var(--ocean)}

/* ---- submit. The base hover goes to Ivory, which on an Ivory panel is an
       invisible button. Graphite instead, which is the same inversion the
       site's own buttons use on light grounds. ---- */
.form-panel #hs-form-mount .hsfc-Button:hover{background:var(--graphite);color:var(--ivory)}

/* ---- errors and RichText ---- */
.form-panel #hs-form-mount .hsfc-ErrorAlert,
.form-panel #hs-form-mount [data-hsfc-id="ErrorAlert"]{color:var(--ocean)}
.form-panel #hs-form-mount [data-hsfc-id="RichText"] *{color:var(--graphite)!important}
.form-panel #hs-form-mount .hsfc-ReCaptchaV2 iframe{border-color:var(--line-dark)}

/* ---- the hairline note under the form follows the panel ---- */
.form-panel .sched-note,
.form-panel .gate-note{color:rgba(35,35,35,.66);border-top-color:var(--line-dark)}
.form-panel .sched-note a,
.form-panel .gate-note a{color:var(--ocean)}

/* 12 Oct: the event names link out now, "for backlinking". They sit on Stone,
   so Ocean, and they keep the rail's own type -- only the underline is added,
   held off the baseline so the hairline rail stays the loudest line here. */
.res-rail-t a{color:inherit;text-decoration:underline;text-decoration-thickness:1px;
  text-underline-offset:4px;text-decoration-color:rgba(0,111,129,.38);
  transition:color var(--dur-int) var(--ease),text-decoration-color var(--dur-int) var(--ease)}
.res-rail-t a:hover{color:var(--ocean);text-decoration-color:var(--ocean)}

/* ============================================================
   SECTION 78 — the secondary button on light grounds.
   12 Oct, Jacob: "Button is hard to see here. lets either do solid or a
   blue or something."
   .btn-secondary is Sand text on a Sand hairline with no fill. On Graphite
   and Ocean that reads clearly, which is where the other three on the site
   sit. On Stone it does not: Sand #c8aa6e against Stone #f2f0e7 measures
   1.95:1, against a 4.5:1 minimum for text this size. It was failing to be
   readable, not just failing to pop.
   Solid Ocean with Ivory type instead: 5.84:1. Blue also keeps it distinct
   from the solid Sand primary a few hundred pixels above it, so the page
   does not read as two identical buttons stacked.
   Scoped to light grounds, so the dark-ground secondaries are untouched.
   ============================================================ */
.on-stone .btn-secondary,
.on-ivory .btn-secondary,
.on-seaglass .btn-secondary{
  background:var(--ocean);color:var(--ivory);border-color:var(--ocean)}
.on-stone .btn-secondary:hover,
.on-ivory .btn-secondary:hover,
.on-seaglass .btn-secondary:hover{
  background:var(--graphite);color:var(--ivory);border-color:var(--graphite)}

/* 12 Oct: the done-view inside a .form-panel. .form-done p is Ivory at 72%,
   written for the Mass Torts modal, which is on Graphite. On the Ivory panel
   that is white on white -- the confirmation sentence was rendering and
   invisible, so a submit showed "Thank you." and nothing else. Missed when
   section 77 built the panel; the skin overrides covered the fields and the
   note and not this. The modal is untouched and stays light-on-dark. */
.form-panel .form-done p{color:rgba(35,35,35,.72)}
.form-panel .form-done .mk{color:var(--ocean)}

/* ============================================================
   SECTION 79 — line breaking. From the 12 Oct spacing audit.
   The audit measured the last line of every heading and paragraph on every
   page against the line above it. Headings were breaking with a stub last
   line -- the homepage h2 ended on 139px against a full measure, the /about
   origin paragraphs each ended on a word or two, and the footer tagline split
   as "...Mass / Tort Firms" on all thirteen pages.

   text-wrap:balance evens the lines of a heading; text-wrap:pretty stops a
   paragraph ending on a single word. Both verified supported in the browser
   before shipping, and both degrade to normal wrapping where they are not,
   so nothing depends on them.

   Headings only for balance: the spec limits it to short blocks, and applying
   it to body copy would do nothing useful anyway.
   ============================================================ */
h1,h2,h3,.h1,.h1-sm,.h2,.h3,.lead,
.res-feat-t,.res-band-t,.idx-t,.steps-row b,.prod-name h3{
  text-wrap:balance}
p,li,blockquote,figcaption{text-wrap:pretty}
/* the footer tagline is a brand line and should never break badly */
.foot-a p{text-wrap:balance;max-width:34ch}

/* ============================================================
   SECTION 80 — mobile pass, 12 Oct. Britt on her phone, plus Jacob:
   "Mass tort images are cut off", "nav CTA in Mobile is different than
   desktop", "Logo carousel seems to not be working on mobile", "Events
   section on mobile need some adjustment".

   The audit that found these ran at 375 and looked for elements CLIPPED
   INSIDE a container, not just elements that scroll the page. The earlier
   mobile check only tested document.scrollWidth, which is why it came back
   clean on every page while four things were visibly broken. A clipped
   child does not widen the document.
   ============================================================ */

/* ---- 1. the nav CTA. It read "Start" below 768 while desktop said "Get
     Started". Measured at 375: logo 128 + "Get Started" 134 + burger 40 = 302
     of 375, with 24px to spare. The abbreviation was never needed. Kept only
     below 360, where an SE genuinely runs out of room. ---- */
@media (max-width:768px){
  .nav-btn-full{display:inline}
  .nav-btn-short{display:none}
}
@media (max-width:359px){
  .nav-btn-full{display:none}
  .nav-btn-short{display:inline}
}

/* ---- 2. the events rail. grid-auto-flow:column with a 190px minimum put
     820px of content in a 335px box, so ONE of four events was visible, and
     scrollbar-width:none meant there was nothing to say it scrolled. It was
     not broken, it was invisible. Four short items do not need a rail on a
     phone: two columns, two rows, everything on screen, no scrolling. ---- */
/* The .res-rail override that belongs here instead lives in the page's own
   <style> block on /resources. That block is declared after this stylesheet in
   the document, so a rule written here at equal specificity loses to it --
   which is exactly what happened on the first attempt, and the grid silently
   stayed in column flow. */

/* ---- 3. the trust strip. Was a 3x3 static grid here earlier today, which
     fixed the orphaned mark but left it static. Jacob asked for motion, so the
     marquee now runs at every width and the grid is gone. ---- */

/* ---- 4. the product UI fragments. These are deliberately NOT reflowed --
     see section 06: an interface does not reflow to 350px, so each scrolls
     inside its own plate instead of shrinking to illegibility. That decision
     stands. What was missing is any sign that it scrolls, so it read as cut
     off to two people independently. Give it a real scrollbar. ---- */
@media (max-width:899px){
  .ben-vis{scrollbar-width:thin;scrollbar-color:var(--sand) transparent;
    padding-bottom:calc(clamp(13px,1.4vw,19px) + 6px)}
  .ben-vis::-webkit-scrollbar{height:6px}
  .ben-vis::-webkit-scrollbar-track{background:rgba(35,35,35,.07)}
  .ben-vis::-webkit-scrollbar-thumb{background:var(--sand)}
  /* the settlement bar pushed its action out with margin-left:auto, which is
     what put the button past the edge. Let it drop to its own line. */
  .ben-vis .ui-settle{flex-wrap:wrap}
  .ben-vis .ui-settle .b{margin-left:0}
}

/* ============================================================
   SECTION 81 — tap targets, from the full mobile sweep.
   Nine pages came back clean. Two things did not, and both are hit areas
   rather than layout, which is why nothing looked wrong in a screenshot.
   ============================================================ */
@media (max-width:768px){
  /* The footer list items already carry min-height:44px, but the ANCHOR inside
     stayed 23px tall, and the anchor is what you tap. Measured "Schedule a
     demo" at 115x23 on every page. 23px fails even the WCAG 2.2 minimum of 24,
     let alone the 44 Apple asks for. Fill the row instead. */
  .foot-col li a{display:flex;align-items:center;min-height:44px;width:100%}
  /* the address is not a link and should not pick up the row treatment */
  .foot-addr{min-height:0}
  /* The legal row on the copyright bar is the same problem at a smaller size. */
  .foot-legal a{display:inline-flex;align-items:center;min-height:44px}

  /* The mobile nav panel's "Get Started" is the primary conversion CTA on a
     phone and it was a 26px-tall text link, quieter and smaller than the four
     nav items above it. Give it the button it already is everywhere else. */
  .nav-panel .nav-panel-cta{display:inline-flex;align-items:center;gap:.6em;
    min-height:48px;padding:14px 26px;border-radius:2px;
    background:var(--sand);color:var(--graphite);
    margin-top:clamp(18px,3vh,28px)}
}


/* ============================================================
   SECTION 82 — 12 Oct, Jacob's mobile round two.
   ============================================================ */
/* "When you click on the menu there's no way to X out of it." The X was
   working; nobody could see it. .nav-panel is a CHILD of .nav and carries
   z-index 99, while .nav-in carried none, so the panel painted over the whole
   bar -- logo and burger both gone. Lift the bar above its own panel. */
.nav-in{position:relative;z-index:101}

@media (max-width:768px){
  /* "The form looks okay. Maybe it could use a little bit more padding." */
  .form-panel{padding:clamp(26px,7vw,34px) clamp(22px,6vw,28px)}
  /* "Want to meet with us at an event... looks a little weird on mobile."
     It ran as one line with the link trailing off the end of the question.
     Stack it: question, then the action under it. */
  .res-events-note{display:flex;flex-direction:column;align-items:flex-start;
    gap:10px;line-height:1.5}
}

/* ============================================================
   SECTION 83 — the product UI fragments stop scrolling on phones.
   12 Oct, Jacob: "Still got some scrolling image issues on the mass tort
   page, especially under the Smarter Claims, Stronger Case value."

   Section 06 decided these should scroll inside their own plate rather than
   reflow, and section 80 gave that scroll a visible bar. Both were wrong about
   what he wanted: he does not want to be told it scrolls, he wants to see the
   whole thing. Measured at 375, each .ben-vis held 466px of interface in a
   333px box, three times down the section.

   zoom, not transform:scale -- zoom affects layout, so the plate's height
   shrinks with its contents and there is no dead space underneath. The
   container query makes it fluid: whatever width the plate ends up, the
   interface is scaled to exactly fit it.
   ============================================================ */
@media (max-width:899px){
  .ben-vis{overflow-x:hidden;container-type:inline-size}
  /* 440px is the min-width section 06 established as the narrowest the
     interface stays coherent at. Scale to the plate rather than past it. */
  /* divided by 440PX, not 440. length / number is a length, which zoom
     rejects, so the declaration was dropped and the plates kept scrolling.
     length / length gives the unitless ratio zoom wants. */
  .ben-vis>*{zoom:calc(100cqw / 440px)}
  /* the scrollbar from section 80 has nothing left to scroll */
  .ben-vis{scrollbar-width:auto;padding-bottom:clamp(13px,1.4vw,19px)}
  .ben-vis::-webkit-scrollbar{height:0}
}

/* ============================================================
   SECTION 84 — /demands steps get their picture, on phones.
   12 Oct, Jacob: "The simpler path to demands is rough because you can't even
   see any of the animations without the text... I like the How It Works
   section on mass torts, each section and then the animation after it."

   The scenes stack in a grid inside .stage and are revealed by
   .stage[data-step]. Once a scene is moved under its own step that selector
   no longer matches it, so the inline copy needs its own visible state.
   ============================================================ */
@media (max-width:999px){
  /* the shared stage is redundant once every step carries its own scene */
  .dm-how .stage{display:none}
  .node-scene{margin-top:clamp(16px,3.4vw,24px);
    background:var(--ivory);border:1px solid rgba(35,35,35,.12);
    border-radius:3px;overflow:hidden;
    box-shadow:0 14px 34px rgba(20,19,17,.16)}
  /* .stage .scene is grid-area 1/1 and hidden until its step is active. Inline,
     each one is the only thing in its frame and is always on. */
  .node-scene .scene{opacity:1;visibility:visible;position:static;
    display:flex;flex-direction:column;grid-area:auto;
    padding:clamp(14px,3.4vw,20px)}
  /* the generator panel inside a scene is built for the 660px stage */
  .node-scene{container-type:inline-size}
  .node-scene .scene>*{max-width:100%}
  /* sc-up carries a .ui-table that measures 326px inside a 307px frame -- the
     one scene of the four that does not fit. Same trick as the .ben-vis plates
     in section 83: scale it to the frame rather than clip or scroll it. */
  .node-scene .sc-up{overflow-x:hidden;zoom:calc(100cqw / 365px)}
}

/* ============================================================
   SECTION 85 — the footer on phones. 12 Oct, Jacob: "The footer looks like
   absolute horse shit. There's way too much information."
   Measured 969px tall against an 812px screen: you scroll a full screen of
   footer. Part of that is mine -- section 81 gave every row a 44px tap target,
   which was right and also added about 130px.

   This is layout only. Nothing is removed: the columns were set by Aaron and
   Britt on 22-23 Sep and cutting items is their call, not a CSS fix.
   ============================================================ */
@media (max-width:768px){
  /* three stacked columns become two across. The brand block spans. */
  .foot-in--cols{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
    column-gap:clamp(16px,5vw,28px);row-gap:clamp(26px,6vw,34px)}
  .foot-a{grid-column:1 / -1}
  .foot-h{margin-bottom:6px}
  /* the address is a block of text, not a 44px tap row */
  .foot-addr{line-height:1.5;padding-block:6px}
  /* the four legal links were stacking at 44px each, 176px of copyright bar.
     Two across, which keeps the target honest and halves the height. */
  .foot-legal{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
    gap:0 clamp(14px,4vw,22px)}
  .foot-bar{display:flex;flex-direction:column;gap:14px;align-items:flex-start}
}

/* ============================================================
   SECTION 86 — the trust marquee on phones. 12 Oct, Jacob: "The Arches logos
   trusted by PI Firms look like shit on mobile."

   Two faults, both from switching this on at mobile in section 80 without
   re-sizing it for the width. Measured at 375: every mark was 96px wide, so
   "AITKEN · AITKEN · COHN" rendered 15px tall and illegible. And with no edge
   treatment the row was slicing wordmarks in half at the viewport edge --
   "GIBSON&HUGHE", "ELLISLAW" -- which reads as broken rather than as motion.
   ============================================================ */
@media (max-width:899px){
  /* big enough to read. Fewer on screen at once is the correct trade for a
     marquee: they are moving, so you get each one in turn. */
  /* .firm-row .firm is two classes and wins over a bare .firm -- it sets
     clamp(96px,8vw,128px) in the marquee block, which at 375 floors at 96 and
     is why the first attempt at this changed the height and not the width.
     Match the specificity. */
  .firm-row .firm{width:clamp(132px,38vw,168px);height:54px}
  .firm-row{gap:clamp(26px,7vw,40px)}
  .firm-row+.firm-row{margin-top:clamp(20px,5vw,30px)}
  /* A mask, not a painted gradient -- nothing is drawn on the ground, the
     marks simply stop being revealed near the edge. That turns a sliced
     wordmark into one leaving the frame, which is what the motion implies. */
  .firms{-webkit-mask-image:linear-gradient(to right,transparent 0,#000 11%,#000 89%,transparent 100%);
          mask-image:linear-gradient(to right,transparent 0,#000 11%,#000 89%,transparent 100%)}
}

/* ============================================================
   SECTION 87 — SITE RULES: leading and vertical rhythm.
   12 Oct, Jacob: "Still got some weird spacing issues throughout the site.
   I feel like it should have site rules."

   He is right, and the audit says why. The site has type SIZE tokens and no
   RHYTHM tokens, so every instance set its own numbers inline in the markup.
   Measured across the live pages:
     - the same h1 role rendered at leading 1.02, 1.04, 1.05 and 1.06
     - the gap under a heading came out 32px here, 38px there, 12px elsewhere
     - 50 inline margin overrides in the HTML, including SIX variants of the
       single relationship "space between an eyebrow and the heading under it"
     - 25+ distinct line-height values in this stylesheet

   Two scales below. Everything that follows them stops needing inline numbers.
   ============================================================ */
:root{
  /* LEADING. Display type gets tighter as it gets bigger; that is the whole
     rule. Three bands, not twenty-five values. */
  --lead-display-xl:1.03;   /* the hero band, 48px and up */
  --lead-display:1.06;      /* section headlines, roughly 32-48px */
  --lead-display-sm:1.16;   /* small display, h3 and card titles */

  /* RHYTHM. One step for each relationship, used everywhere that relationship
     occurs. These are the values the inline overrides were approximating. */
  --space-eyebrow-to-head:clamp(26px,3vw,38px);
  --space-head-to-body:clamp(16px,1.8vw,24px);
  --space-body-to-action:clamp(26px,3vw,36px);
}

/* ---- leading, applied by size band rather than per instance ---- */
.h1,h1{line-height:var(--lead-display-xl)}
.h1-sm,.h1.t2,h2.h1{line-height:var(--lead-display)}
.h3,h3{line-height:var(--lead-display-sm)}

/* ---- the eyebrow-to-headline step, which was six different inline values.
     Declared as a relationship so new sections inherit it for free. ---- */
.eyebrow + .h1,.eyebrow + .h1-sm,.eyebrow + h1,.eyebrow + h2,
.eyebrow + .h2,.eyebrow + .h3{margin-top:var(--space-eyebrow-to-head)}

/* 12 Oct: one track on phones, so the second row's spacing rule must not
   leave a gap where a hidden row used to be. */
@media (max-width:899px){
  .firm-row[hidden]{display:none}
  .firm-row+.firm-row{margin-top:0}
}

/* ============================================================
   SECTION 88 — HubSpot phone field and dropdown padding.
   12 Oct, Jacob: "Kill the country code on all forms, it's fucking with me" --
   "I go to press Tab and it freaks it out."

   HubSpot renders its phone field as a country flag + caret, a prefix input
   holding "+1", and then the real input. The prefix is its own focusable
   field, which is why Tab landed somewhere unexpected. Arches is US-only, so
   the selector is hidden rather than removed: HubSpot keeps its default
   country and the submitted value is unchanged. Nothing about the data moves,
   only what a person has to tab through.
   ============================================================ */
#hs-form-mount .hsfc-PhoneInput__FlagAndCaret{display:none}
/* DO NOT hide the unnamed input here. I did, and it took the phone field out
   entirely -- HubSpot hides the NAMED input (0-1/phone), which only holds the
   value for submission, and uses an unnamed .hsfc-TextInput as the field people
   actually type into. ":not([name])" therefore matched the typing field.
   Hiding the flag and caret above is enough: that is the country selector and
   the thing that was eating the Tab key. */
#hs-form-mount .hsfc-PhoneInput{gap:0}
#hs-form-mount .hsfc-PhoneInput > .hsfc-TextInput{width:100%;padding-left:0}

/* "can we get like on the dropdowns... it's just right up against that. Get a
   little padding in there. Case types, the same thing. Job titles, the same."
   The value sat hard against the caret and the underline. */
#hs-form-mount .hsfc-DropdownInput{padding:11px 0 12px}
#hs-form-mount .hsfc-TextInput--button{padding-right:26px}
#hs-form-mount .hsfc-DropdownOptions__List__ListItem{padding-block:10px}

/* the footer address became a link on 12 Oct, so it needs a hit area again --
   section 85 had taken min-height off it while it was plain text. */
.foot-addr a{color:inherit;text-decoration:none;display:inline-block;
  padding-block:4px;min-height:44px}
.foot-addr a:hover{color:var(--ivory);text-decoration:underline;text-underline-offset:3px}

/* ============================================================
   SECTION 89 — the footer columns as a menu on phones.
   Jacob, from the call with Britt: "dropdown fields for company and get in
   touch... now this is a footer menu. I like that. That'll help clean it up
   because it is quite extensive."
   Native <details>, so this needs no JS to work and stays keyboard accessible.
   ============================================================ */
.foot-col > summary{list-style:none;cursor:default}
.foot-col > summary::-webkit-details-marker{display:none}
/* desktop: a heading, not a control. Inert so it cannot be collapsed. */
@media (min-width:769px){
  .foot-col > summary{pointer-events:none}
}
@media (max-width:768px){
  .foot-col{border-top:1px solid rgba(255,255,250,.10)}
  .foot-col > summary{cursor:pointer;display:flex;align-items:center;
    justify-content:space-between;min-height:48px;margin-bottom:0;
    padding-right:2px;-webkit-tap-highlight-color:transparent}
  /* the caret is drawn, not a character, so it matches the site's linework */
  .foot-col > summary::after{content:"";width:8px;height:8px;flex:0 0 auto;
    border-right:1.5px solid var(--sand);border-bottom:1.5px solid var(--sand);
    transform:rotate(45deg) translate(-2px,-2px);
    transition:transform var(--dur-int) var(--ease)}
  .foot-col[open] > summary::after{transform:rotate(-135deg) translate(-3px,-3px)}
  .foot-col > ul{padding-bottom:10px}
  /* a menu reads as one column, not two */
  .foot-in--cols{grid-template-columns:1fr;row-gap:0}
  .foot-a{margin-bottom:clamp(22px,6vw,30px)}
}
