:root{
  color-scheme:dark;
  --bg:#07090b; --bg-soft:#0d1114; --card:#12171a; --card-hi:#171d21;
  --line:#232b2f; --line-soft:#171e21;
  --teal:#4ECDC4; --teal-2:#7ee8e0; --teal-dim:#2f7871; --amber:#d4ab6b;
  /* --text-faint was #5b6568: 3.3:1 on the page, under AA for the small labels it colours */
  --text:#f1efe8; --text-dim:#9aa3a6; --text-faint:#80898c;
  --serif:'Figtree',sans-serif; --mono:'JetBrains Mono',monospace;

  /* --- theme-dependent pieces the two palettes swap out ---------------------
     accent-rgb feeds every teal glow, tint feeds the near-invisible fills,
     glass feeds the blurred panels, on-teal is whatever reads on a teal fill. */
  --accent-rgb:78,205,196;
  --accent2-rgb:126,232,224;
  --on-teal:#07090b;
  --tint:rgba(255,255,255,0.02);
  --tint-2:rgba(255,255,255,0.015);
  --glass:rgba(7,9,11,0.7);
  --glass-header:rgba(7,9,11,0.6);
  --glass-testi:rgba(23,29,33,0.55);
  --text-bright:#b6bec1;
  --grain-opacity:0.035;
  --shadow-card:0 22px 50px rgba(0,0,0,0.45);
  --shadow-panel:0 22px 50px rgba(0,0,0,0.4);
  --shadow-visual:0 30px 60px rgba(0,0,0,0.4);
  --shadow-chip:0 10px 24px rgba(0,0,0,0.35);
  --shadow-testi:0 20px 40px rgba(0,0,0,0.35);
  /* the FBR card is teal-tinted, so its text has its own ramp */
  --avatar-bg:#368b81;
  --on-feat:#c2d3d1; --on-feat-dim:#9fb7b4; --on-feat-bright:#d7e6e4; --on-feat-head:#a9f2ec;
  --feat-tag-text:#07211f;
}

/* ---------- light theme ----------
   not an inversion: the accent drops to a teal dark enough to read as text on
   white (#0f766e clears AA on the page background), and the glows lose most of
   their alpha because bloom on a light ground turns to mud. */
:root[data-theme="light"]{
  color-scheme:light;
  --bg:#f7f6f3; --bg-soft:#fdfdfb; --card:#ffffff; --card-hi:#fbfbf8;
  --line:#dfdfd8; --line-soft:#ebeae4;
  --teal:#0f766e; --teal-2:#0b5952; --teal-dim:#8ad3cb; --amber:#a97c30;
  --text:#11181a; --text-dim:#4d585b; --text-faint:#667174;

  --accent-rgb:15,118,110;
  --accent2-rgb:11,89,82;
  --on-teal:#ffffff;
  --tint:rgba(17,24,26,0.025);
  --tint-2:rgba(17,24,26,0.018);
  --glass:rgba(255,255,255,0.75);
  --glass-header:rgba(247,246,243,0.72);
  --glass-testi:rgba(255,255,255,0.7);
  --text-bright:#2c383b;
  --grain-opacity:0.022;
  --shadow-card:0 18px 40px rgba(17,40,44,0.10);
  --shadow-panel:0 18px 40px rgba(17,40,44,0.09);
  --shadow-visual:0 24px 50px rgba(17,40,44,0.10);
  --shadow-chip:0 10px 22px rgba(17,40,44,0.09);
  --shadow-testi:0 16px 34px rgba(17,40,44,0.08);
  --avatar-bg:#0f766e;
  --on-feat:#2a4744; --on-feat-dim:#3d5b57; --on-feat-bright:#16302d; --on-feat-head:#0b5952;
  --feat-tag-text:#ffffff;
}
*{margin:0;padding:0;box-sizing:border-box;}
html{scroll-behavior:smooth;}
body{
  background:var(--bg); color:var(--text); font-family:var(--serif);
  line-height:1.55; overflow-x:hidden; font-size:16px; cursor:none;
}
@media (hover:none), (pointer:coarse){ body{cursor:auto;} .cursor-dot,.cursor-ring{display:none;} }
@media (prefers-reduced-motion: reduce){
  html{scroll-behavior:auto;}
  *{animation-duration:0.01ms !important; transition-duration:0.01ms !important;}
}
a{color:inherit; text-decoration:none;}
img{max-width:100%;}
.wrap{max-width:1180px; margin:0 auto; padding:0 32px; position:relative; z-index:2;}
section{position:relative;}

.cursor-dot{position:fixed; width:6px; height:6px; background:var(--teal); border-radius:50%; pointer-events:none; z-index:9999; transform:translate(-50%,-50%);}
.cursor-ring{position:fixed; width:34px; height:34px; border:1px solid rgba(var(--accent-rgb),0.5); border-radius:50%; pointer-events:none; z-index:9998; transform:translate(-50%,-50%); transition:width .25s,height .25s,border-color .25s;}
.cursor-ring.hovering{width:60px; height:60px; border-color:var(--teal);}

.grain{position:fixed; inset:0; z-index:1; pointer-events:none; opacity:var(--grain-opacity);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

header{position:fixed; top:0; left:0; right:0; z-index:100; background:var(--glass-header); backdrop-filter:blur(16px); border-bottom:1px solid var(--line-soft);}
.nav-inner{max-width:1180px; margin:0 auto; padding:20px 32px; display:flex; align-items:center; justify-content:space-between;}
.brand{display:flex; align-items:center; gap:11px; line-height:1;}
.brand img{display:block; height:44px; width:auto;}
/* the logo PNGs are one flat colour (#6EC7AD) on transparency, so a box masked by
   the PNG and filled with the site teal recolours them losslessly. The img element stays
   in the markup and renders in its original brand green wherever mask is unsupported. */
@supports ((-webkit-mask-image:url()) or (mask-image:url())){
  .brand img{display:none;}
  .brand::before{content:''; display:block; width:44px; height:44px; flex:none;
    background-color:var(--teal);
    -webkit-mask:url('/assets/smshah-emblem.png') center/contain no-repeat;
    mask:url('/assets/smshah-emblem.png') center/contain no-repeat;
    transition:background-color .35s ease;}
  .brand:hover::before{background-color:var(--teal-2);}
}
.brand-name{display:flex; flex-direction:column; justify-content:center; align-items:flex-start; color:var(--text); white-space:nowrap;
  /* tracking makes .brand-sub render exactly as wide as .brand-title; this is the
     no-JS fallback — the brand-tracking IIFE re-measures it for the actual font */
  --sub-track:0.0488em;}
.brand-title{font-weight:800; font-size:1.35rem; line-height:1.08; letter-spacing:-0.015em;}
.brand-sub{font-weight:600; font-size:0.72rem; line-height:1.25; letter-spacing:var(--sub-track);
  text-transform:uppercase;
  margin-right:calc(-1 * var(--sub-track)); color:var(--text-dim);}
.foot-brand{display:inline-flex; align-items:center; margin-bottom:14px; opacity:0.85; transition:opacity .25s;}
.foot-brand:hover{opacity:1;}
.foot-brand img{display:block; height:56px; width:auto;}
@supports ((-webkit-mask-image:url()) or (mask-image:url())){
  .foot-brand img{display:none;}
  .foot-brand::before{content:''; display:block; width:112px; height:56px; flex:none;
    background-color:var(--teal);
    -webkit-mask:url('/assets/smshah-logo-web.png') center/contain no-repeat;
    mask:url('/assets/smshah-logo-web.png') center/contain no-repeat;}
}
.nav-right{display:flex; align-items:center; gap:26px; flex:none;}
@media (max-width:880px){ .nav-right{gap:16px;} }
.nav-cta{background:var(--teal); color:var(--on-teal); padding:10px 22px; border-radius:100px; font-size:0.88rem; font-weight:700; transition:transform .3s cubic-bezier(.2,.8,.2,1), box-shadow .3s;}
.nav-cta:hover{transform:translateY(-2px) scale(1.03); box-shadow:0 8px 24px rgba(var(--accent-rgb),0.35);}

.hero{min-height:100svh; display:flex; align-items:center; padding-top:100px; padding-bottom:60px; position:relative; overflow:hidden;}
#hero-canvas{position:absolute; inset:0; width:100%; height:100%; opacity:0; z-index:0;}
.hero-glow{position:absolute; top:10%; left:50%; width:900px; height:900px; transform:translateX(-50%);
  background:radial-gradient(circle, rgba(var(--accent-rgb),0.14) 0%, rgba(var(--accent-rgb),0) 65%); z-index:0; pointer-events:none;}
.hero-content{position:relative; z-index:2; max-width:900px; text-align:center; margin:0 auto;}
.eyebrow-line{display:inline-flex; align-items:center; gap:10px; margin-bottom:30px; color:var(--text-dim); font-size:0.85rem;
  border:1px solid var(--line); padding:7px 16px; border-radius:100px; background:var(--tint);}
.eyebrow-line .dot{width:6px; height:6px; border-radius:50%; background:var(--teal); box-shadow:0 0 12px var(--teal); animation:pulse 2s ease-in-out infinite;}
@keyframes pulse{0%,100%{opacity:1;} 50%{opacity:0.4;}}
h1{font-size:clamp(2.6rem, 6vw, 5rem); font-weight:800; letter-spacing:-0.03em; line-height:1.04; margin-bottom:28px;}
h1 .line{display:block; overflow:hidden;}
h1 .line span{display:inline-block; will-change:transform;}
h1 em{font-style:normal; background:linear-gradient(120deg, var(--teal), var(--teal-2)); -webkit-background-clip:text; background-clip:text; color:transparent;}
.hero p.lede{font-size:1.2rem; color:var(--text-dim); max-width:52ch; margin:0 auto 40px; }
.btn-row{display:flex; gap:16px; flex-wrap:wrap; margin-bottom:64px; justify-content:center;}
.btn{display:inline-flex; align-items:center; gap:8px; padding:16px 30px; border-radius:100px; font-size:0.96rem; font-weight:700;
  transition:transform .35s cubic-bezier(.2,.9,.2,1), box-shadow .35s; position:relative; will-change:transform;}
.btn-primary{background:var(--teal); color:var(--on-teal);}
.btn-primary:hover{box-shadow:0 10px 30px rgba(var(--accent-rgb),0.4);}
.btn-ghost{border:1px solid var(--line); color:var(--text); background:var(--tint);}
.btn-ghost:hover{border-color:var(--teal); color:var(--teal);}

.hero-stats{display:flex; gap:44px 40px; flex-wrap:wrap; justify-content:center;}
.stat .num{font-family:var(--mono); font-size:2rem; font-weight:600; color:var(--teal);
  white-space:nowrap; display:inline-flex; align-items:flex-end; line-height:1;}

/* odometer: each digit is a 1em window over a strip of 0-9 that rolls upward.
   The mono face keeps every column the same width, so nothing shifts as it spins. */
.odo{display:inline-flex; align-items:flex-end; vertical-align:bottom;}
.odo-col{display:block; height:1em; overflow:hidden;}
.odo-strip{display:block; will-change:transform;}
.odo-strip span{display:block; height:1em; line-height:1;}
.odo-sep{display:block; line-height:1;}
/* the real value, for screen readers — the rolling strips are decoration */
.odo-sr{position:absolute; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap; border:0;}
.stat .num .pre{font-size:0.62em; margin-right:3px; opacity:0.75;}
.stat .num .suf{font-size:0.72em;}
.stat .lbl{font-size:0.82rem; line-height:1.5; color:var(--text-faint); margin:6px auto 0; max-width:26ch; text-wrap:balance;}
/* the "i" that opens a stat's footnote, and the popover it opens ------------- */
.stat{position:relative; width:230px;}
.stat-ref{display:inline-flex; align-items:center; justify-content:center; width:14px; height:14px;
  margin-left:5px; vertical-align:1px; padding:0; border:1px solid var(--line); border-radius:50%;
  background:var(--tint); color:var(--text-faint); font:600 0.6rem/1 var(--mono); cursor:pointer;
  transition:color 0.2s, border-color 0.2s, background 0.2s;}
.stat-ref:hover, .stat-ref[aria-expanded="true"]{color:var(--teal); border-color:var(--teal); background:rgba(var(--accent-rgb),0.12);}
.stat-ref:focus-visible{outline:2px solid var(--teal); outline-offset:2px;}
/* light --text-faint clears 4.5:1 on the page ground but not over the button's
   own tint (effective #f1f1ee); at 9.6px mono this is small text, so it gets a
   darker gray of the same family (5.4:1) rather than a global --text-faint shift */
:root[data-theme="light"] .stat-ref{color:#596466;}

.stat-pop{position:absolute; bottom:calc(100% + 14px); left:50%; transform:translateX(-50%);
  width:min(330px, 78vw); z-index:20; text-align:left; padding:16px 18px 15px;
  border:1px solid var(--line); border-radius:12px; background:var(--card); box-shadow:var(--shadow-panel);}
.stat-pop::after{content:""; position:absolute; top:100%; left:50%; margin-left:-7px; width:0; height:0;
  border:7px solid transparent; border-top-color:var(--card);}
.stat-pop h2{font-size:0.72rem; letter-spacing:0.06em; text-transform:uppercase; color:var(--teal); margin-bottom:8px;}
.stat-pop p{font-size:0.76rem; line-height:1.6; color:var(--text-dim);}
.stat-pop p + p{margin-top:8px;}
.stat-pop em{font-style:italic;}
.stat-pop-x{position:absolute; top:8px; right:9px; width:20px; height:20px; padding:0; border:0; border-radius:6px;
  background:none; color:var(--text-faint); font-size:1.05rem; line-height:1; cursor:pointer;}
.stat-pop-x:hover{color:var(--teal); background:var(--tint);}
@media (max-width:560px){ .stat-pop{left:0; transform:none; width:min(330px, 86vw);} .stat-pop::after{left:34px;} }

.trust-strip{border-top:1px solid var(--line-soft); border-bottom:1px solid var(--line-soft); padding:22px 0; overflow:hidden; white-space:nowrap; position:relative; z-index:2;}
.trust-strip .track{display:inline-block; animation:scrollx 30s linear infinite;}
.trust-strip span{font-size:0.85rem; color:var(--text-faint); padding:0 24px; font-family:var(--mono);}
@keyframes scrollx{from{transform:translateX(0);} to{transform:translateX(-50%);}}

.section-pad{padding:140px 0;}
.section-head{max-width:640px; margin-bottom:70px;}
.section-head .kicker{color:var(--teal); font-size:0.9rem; font-weight:700; margin-bottom:16px; letter-spacing:0.01em;}
.section-head h2{font-size:clamp(1.9rem, 3.4vw, 2.8rem); font-weight:800; letter-spacing:-0.02em; margin-bottom:18px;}
.section-head p{color:var(--text-dim); font-size:1.06rem; max-width:52ch;}

.svc-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:20px; grid-auto-rows:1fr; align-items:stretch;}

/* every card shares the grid's rows, so the divider above each list sits on one line
   across the row no matter how long the heading or copy runs */
@supports (grid-template-rows: subgrid){
  .svc-grid{grid-auto-rows:auto; row-gap:0; margin-bottom:-20px;}
  .svc-card{display:grid; grid-template-rows:subgrid; grid-row:span 4; align-content:start; margin-bottom:20px;}
  .svc-card .svc-list{align-self:start;}
}
.svc-head{display:contents;}
@supports (grid-template-rows: subgrid){ .svc-head{display:block;} }
.svc-card{
  background:linear-gradient(160deg, var(--card) 0%, var(--bg-soft) 100%);
  border:1px solid var(--line); border-radius:18px; padding:36px 30px;
  transform-style:preserve-3d;
  transition:transform .12s ease-out, border-color .45s ease, background .5s ease;
  will-change:transform; position:relative; overflow:hidden; isolation:isolate;
  --mx:50%; --my:50%;
}
/* traced gradient rim — the highlight rotates once around the card on hover */
@property --svc-ang{ syntax:'<angle>'; inherits:false; initial-value:0deg; }
.svc-card::before{content:''; position:absolute; inset:0; border-radius:18px; padding:1px;
  background:conic-gradient(from var(--svc-ang),
    transparent 0deg, rgba(var(--accent-rgb),0.65) 60deg, rgba(212,171,107,0.35) 110deg, transparent 190deg, transparent 360deg);
  opacity:0; transition:opacity .45s ease;
  -webkit-mask:linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite:xor; mask-composite:exclude; pointer-events:none; z-index:2;}
.svc-card:hover::before{opacity:0.45; animation:svc-trace 4.2s linear infinite;}
@keyframes svc-trace{ to{ --svc-ang:360deg; } }

/* spotlight that follows the pointer */
.svc-card::after{content:''; position:absolute; inset:0; border-radius:18px; pointer-events:none; z-index:0;
  background:radial-gradient(320px circle at var(--mx) var(--my), rgba(var(--accent-rgb),0.065), rgba(var(--accent-rgb),0.02) 40%, transparent 66%);
  opacity:0; transition:opacity .5s ease;}
.svc-card:hover::after{opacity:1;}

.svc-card > *{position:relative; z-index:1;}
.svc-card:hover{border-color:var(--teal-dim); background:linear-gradient(160deg, var(--card-hi) 0%, var(--bg-soft) 100%);}

.svc-card .idx{font-family:var(--mono); color:var(--teal); font-size:0.85rem; margin-bottom:22px; display:block;
  transition:letter-spacing .5s cubic-bezier(.2,.8,.2,1), text-shadow .5s ease;}
.svc-card:hover .idx{letter-spacing:0.22em; text-shadow:0 0 18px rgba(var(--accent-rgb),0.55);}

/* the number ghosts up in the corner as a big watermark */
.svc-card .idx::after{content:attr(data-num); position:absolute; top:-26px; right:-8px;
  font-size:5.4rem; font-weight:700; line-height:1; letter-spacing:-0.04em;
  color:rgba(var(--accent-rgb),0.09); opacity:0; transform:translateY(14px) scale(0.94);
  transition:opacity .6s ease, transform .7s cubic-bezier(.2,.8,.2,1); pointer-events:none;}
.svc-card:hover .idx::after{opacity:1; transform:translateY(0) scale(1);}

.svc-card h3{font-size:1.24rem; font-weight:700; margin-bottom:12px; letter-spacing:-0.01em;
  transition:transform .55s cubic-bezier(.2,.8,.2,1), color .4s ease;}
.svc-card:hover h3{transform:translateY(-3px); color:var(--teal-2);}
.svc-card .tag{display:inline-block; margin-bottom:12px; font-size:0.74rem; color:var(--teal); border:1px solid var(--teal-dim); padding:2px 10px; border-radius:20px;
  transition:background .45s ease, box-shadow .45s ease;}
.svc-card:hover .tag{background:rgba(var(--accent-rgb),0.1); box-shadow:0 0 18px rgba(var(--accent-rgb),0.18);}
.svc-card p{color:var(--text-dim); font-size:0.95rem;
  transition:transform .55s cubic-bezier(.2,.8,.2,1) .04s, color .4s ease;}
.svc-card:hover p{transform:translateY(-2px); color:var(--text-bright);}

/* a hairline that draws itself across the foot of the card */
@property --svc-fill{ syntax:'<angle>'; inherits:false; initial-value:0deg; }
.svc-card .sweep{position:absolute; inset:0; border-radius:18px; padding:1px; z-index:3; pointer-events:none;
  --svc-fill:0deg;
  background:conic-gradient(from 135deg, var(--teal) 0deg, var(--teal-2) calc(var(--svc-fill) * 0.5), rgba(212,171,107,0.85) var(--svc-fill), transparent 0);
  -webkit-mask:linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite:xor; mask-composite:exclude;
  transition:--svc-fill .85s cubic-bezier(.25,.8,.3,1);}
.svc-card:hover .sweep{--svc-fill:360deg;}

@media (prefers-reduced-motion: reduce){
  .svc-card:hover::before{animation:none;}
  .svc-card .sweep{transition:none;}
}
.svc-card.wide{grid-column:span 1;}
.svc-card .svc-list{list-style:none; margin-top:18px; padding-top:16px; border-top:1px solid var(--line-soft);}
.svc-card .svc-list li{position:relative; padding-left:16px; font-size:0.845rem; color:var(--text-faint);
  line-height:1.5; margin-bottom:6px; transition:color .4s ease;}
.svc-card .svc-list li::before{content:''; position:absolute; left:0; top:0.62em; width:5px; height:1px; background:var(--teal-dim);
  transition:width .4s ease, background .4s ease;}
.svc-card:hover .svc-list li{color:var(--text-dim);}
.svc-card:hover .svc-list li::before{width:9px; background:var(--teal);}
.svc-card.featured .svc-list{border-top-color:rgba(var(--accent-rgb),0.22);}
.svc-card.featured .svc-list li{color:var(--on-feat-dim);}
.svc-card.featured:hover .svc-list li{color:var(--on-feat);}

.approach-grid{display:grid; grid-template-columns:minmax(0,1fr) 330px; gap:70px; align-items:start;}
@media (max-width:1000px){ .approach-grid{grid-template-columns:1fr; gap:44px;} }

/* the commitments panel that rides alongside the rail */
.commit-card{position:sticky; top:120px; background:var(--glass); backdrop-filter:blur(6px);
  border:1px solid var(--line); border-radius:16px; padding:26px 24px; overflow:hidden;
  --mx:50%; --my:50%; transition:border-color .5s ease, box-shadow .5s ease;}
.commit-card::after{content:''; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(280px circle at var(--mx) var(--my), rgba(var(--accent-rgb),0.07), transparent 66%);
  opacity:0; transition:opacity .5s ease;}
.commit-card:hover{border-color:var(--teal-dim); box-shadow:var(--shadow-panel);}
.commit-card:hover::after{opacity:1;}
.commit-card > *{position:relative; z-index:1;}
@media (max-width:1000px){ .commit-card{position:static; max-width:520px;} }

.cc-head{display:flex; align-items:baseline; justify-content:space-between; gap:12px;
  padding-bottom:16px; margin-bottom:6px; border-bottom:1px solid var(--line-soft);}
.cc-kicker{color:var(--teal); font-size:0.78rem; font-weight:700; letter-spacing:0.06em; text-transform:uppercase;}
.cc-prog{font-family:var(--mono); font-size:0.76rem; color:var(--text-faint);}
.cc-prog b{color:var(--teal); font-weight:400;}

.cc-list{list-style:none;}
.cc-list li{display:flex; gap:12px; align-items:flex-start; padding:13px 0; font-size:0.92rem;
  color:var(--text-faint); border-bottom:1px solid var(--line-soft);
  transition:color .5s ease, transform .5s cubic-bezier(.2,.8,.2,1);}
.cc-list li:last-child{border-bottom:0;}

/* the tick draws itself when the rail reaches that commitment */
.cc-tick{flex:none; width:15px; height:15px; margin-top:2px; border-radius:50%;
  border:1px solid var(--line); position:relative;
  transition:border-color .45s ease, background .45s ease, box-shadow .45s ease;}
.cc-tick::before{content:''; position:absolute; left:4px; top:1px; width:4px; height:8px;
  border:solid var(--on-teal); border-width:0 1.5px 1.5px 0; transform:rotate(45deg) scale(0);
  transition:transform .4s cubic-bezier(.3,1.4,.5,1);}
.cc-list li.on{color:var(--text-dim);}
.cc-list li.on .cc-tick{background:var(--teal); border-color:var(--teal); box-shadow:0 0 14px rgba(var(--accent-rgb),0.45);}
.cc-list li.on .cc-tick::before{transform:rotate(45deg) scale(1);}

.cc-foot{margin-top:18px; padding-top:16px; border-top:1px solid var(--line-soft);
  color:var(--text-faint); font-size:0.8rem; line-height:1.5;}

@media (prefers-reduced-motion:reduce){
  .cc-list li, .cc-tick, .cc-tick::before, .commit-card{transition:none !important;}
}

/* the "how we work" principles hang off a rail that fills as the section scrolls */
.principles{position:relative; max-width:900px; padding-left:56px;}
.principles .rail{position:absolute; left:15px; top:8px; bottom:8px; width:1px; background:var(--line);}
.principles .rail-fill{position:absolute; inset:0; transform:scaleY(0); transform-origin:top;
  background:linear-gradient(180deg, var(--teal), var(--teal-dim));
  box-shadow:0 0 12px rgba(var(--accent-rgb),0.35);}

.principle{position:relative; padding:26px 28px 26px 0; border-top:1px solid var(--line-soft);
  transition:padding-left .5s cubic-bezier(.2,.8,.2,1);}
.principle:first-of-type{border-top:0;}
.principle:hover{padding-left:10px;}

/* the marker that sits on the rail */
.principle::before{content:''; position:absolute; left:-47px; top:34px; width:9px; height:9px; border-radius:50%;
  background:var(--bg); border:1px solid var(--line); z-index:1;
  transition:border-color .45s ease, background .45s ease, box-shadow .45s ease, transform .45s cubic-bezier(.2,.8,.2,1);}
.principle:hover::before{background:var(--teal); border-color:var(--teal); transform:scale(1.35);
  box-shadow:0 0 16px rgba(var(--accent-rgb),0.55);}

.principle .p-num{display:block; font-family:var(--mono); font-size:0.74rem; letter-spacing:0.14em;
  color:var(--text-faint); margin-bottom:10px; transition:color .45s ease, letter-spacing .5s cubic-bezier(.2,.8,.2,1);}
.principle:hover .p-num{color:var(--teal); letter-spacing:0.24em;}

.principle h3{font-size:1.06rem; margin-bottom:10px; letter-spacing:-0.01em;
  transition:color .4s ease;}
.principle:hover h3{color:var(--teal-2);}
.principle p{color:var(--text-dim); font-size:1rem; max-width:62ch; transition:color .4s ease;}
.principle:hover p{color:var(--text-bright);}

@media (max-width:880px){
  .principles{padding-left:34px;}
  .principles .rail{left:5px;}
  .principle::before{left:-33px;}
  .principle{padding-right:0;}
}
@media (prefers-reduced-motion:reduce){
  .principle, .principle *, .principle::before{transition:none !important;}
  .principles .rail-fill{transform:scaleY(1);}
}

/* the specialty card carries the brand colour */
.svc-card.featured{
  background:linear-gradient(160deg, rgba(var(--accent-rgb),0.14) 0%, rgba(var(--accent-rgb),0.07) 55%, var(--bg-soft) 100%);
  border-color:var(--teal-dim);
}
.svc-card.featured:hover{
  background:linear-gradient(160deg, rgba(var(--accent-rgb),0.19) 0%, rgba(var(--accent-rgb),0.10) 55%, var(--bg-soft) 100%);
  border-color:var(--teal);
}
.svc-card.featured::after{
  background:radial-gradient(320px circle at var(--mx) var(--my), rgba(var(--accent2-rgb),0.10), rgba(var(--accent-rgb),0.03) 40%, transparent 66%);
}
.svc-card.featured .idx{color:var(--teal-2);}
.svc-card.featured .idx::after{color:rgba(var(--accent2-rgb),0.14);}
.svc-card.featured .tag{
  background:var(--teal); border-color:var(--teal); color:var(--feat-tag-text); font-weight:600;
  box-shadow:0 4px 16px rgba(var(--accent-rgb),0.22);
}
.svc-card.featured:hover .tag{background:var(--teal-2); border-color:var(--teal-2); box-shadow:0 6px 22px rgba(var(--accent2-rgb),0.3);}
.svc-card.featured h3{color:var(--teal-2);}
.svc-card.featured:hover h3{color:var(--on-feat-head);}
.svc-card.featured p{color:var(--on-feat);}
.svc-card.featured:hover p{color:var(--on-feat-bright);}

.di-feature{
  background:radial-gradient(circle at 15% 15%, rgba(var(--accent-rgb),0.09), transparent 55%), linear-gradient(155deg, var(--card) 0%, var(--bg-soft) 100%);
  border:1px solid var(--line); border-radius:24px; padding:70px; overflow:hidden; position:relative;
}
/* Both columns are stretched to the row height and each anchors its last element
   to the bottom, so the CTA and the 28/28 button sit on one line no matter how the
   copy wraps. Aligning by hand — matching paddings, counting lines — breaks the
   moment the text reflows at another width. `.di-visual` takes flex:1 and absorbs
   whatever slack is left, which keeps the mock and the button it sits above from
   drifting apart. */
.di-grid{display:grid; grid-template-columns:1fr 1fr; gap:60px; align-items:stretch;}
.di-copy{display:flex; flex-direction:column;}
.di-visual{flex:1;}
.di-badge{display:inline-flex; align-items:center; gap:8px; font-family:var(--mono); font-size:0.78rem; color:var(--teal); border:1px solid var(--teal-dim); padding:5px 14px; border-radius:100px; margin-bottom:26px;}
.di-feature h3{font-size:2.1rem; font-weight:800; margin-bottom:20px; letter-spacing:-0.02em;}
/* 50ch, not 44: the column is ~490px wide, so 44ch left the paragraph wrapping
   well short of the heading above it and the edge read as ragged */
.di-feature p.desc{color:var(--text-dim); margin-bottom:0; max-width:50ch; font-size:1.02rem;}
/* the desc used to carry margin-bottom:32px and the row an inline margin-top:32px;
   together that was a 64px hole where the bullet list used to sit. margin-top:auto
   now pushes the row to the bottom of the column; padding-top keeps a floor under
   the gap for the case where the two columns come out near equal. */
/* The CTA and the 28/28 trigger both sit at the foot of their column, but the pill
   is ~48px tall and the trigger ~70px, so bottom-anchoring alone left the button
   riding low against it. The button row is given the trigger's exact height and the
   button is centred inside it, so the two share a centre line. Both heights come
   from one --rail-h on the card, so they cannot drift apart in a later edit.
   The pill keeps its own size — stretching it to 70px to force the tops and bottoms
   to match as well would make the CTA heavier than the thing it points at. */
.di-feature{--rail-h:70px;}
/* The row is exactly --rail-h tall and holds the button centred, with nothing
   else in the box to confuse the maths. The previous attempt used padding +
   min-height on a `flex-wrap:wrap` row inherited from .btn-row: with wrapping on,
   the single flex line is content-sized rather than stretched to the container,
   so `align-items:center` centred the button in a 56px line instead of the 70px
   box, and it came out 16px low and overflowing the bottom. Measured, not guessed
   — see the Playwright numbers in the note below. */
.di-feature .btn-row{margin:0; margin-top:auto; padding:0; height:var(--rail-h);
  flex-wrap:nowrap; align-items:center; justify-content:flex-start;}
.di-visual-col .sn-trigger{min-height:var(--rail-h);}
.di-visual{background:var(--glass); backdrop-filter:blur(6px); border:1px solid var(--line); border-radius:16px; padding:28px;
  font-family:var(--mono); font-size:0.83rem; transform-style:preserve-3d; transition:transform .15s ease-out;
  box-shadow:var(--shadow-visual);}
.di-visual .top-row{display:flex; justify-content:space-between; margin-bottom:22px; color:var(--text-faint);}
.di-visual .status-ok{color:var(--teal);}
.di-line{display:flex; justify-content:space-between; padding:12px 0; border-top:1px solid var(--line-soft); color:var(--text-dim);}
.di-line:first-of-type{border-top:none;}
.di-line b{color:var(--text); font-weight:500;}
.di-line .accepted{color:var(--teal);}
.di-line .accepted::before{content:'● '; font-size:0.6em;}

/* Invoicing, the ledger and payroll are one system on one login, so they are
   three pillars *inside* the platform card rather than cards of their own.
   Separate cards read as separate products with separate prices. */
.plat-pillars{display:grid; grid-template-columns:repeat(3,1fr); gap:34px;
  margin-top:54px; padding-top:40px; border-top:1px solid var(--line-soft);}
.pillar h4{font-size:1.06rem; font-weight:700; letter-spacing:-0.01em; margin-bottom:9px; color:var(--teal);}
.pillar p{color:var(--text-dim); font-size:0.9rem; line-height:1.6;}
.mod-tags{display:flex; flex-wrap:wrap; gap:6px; margin-top:16px;}
.mod-tags span{font-family:var(--mono); font-size:0.7rem; color:var(--text-faint);
  border:1px solid var(--line-soft); background:var(--tint-2); padding:4px 9px; border-radius:100px;}

/* POS sits directly under the DI feature and was a flat text bar next to it, which
   read as an afterthought rather than the second product. It now borrows the DI
   card's shape — badge, gradient ground, a mono mock on the right — at a smaller
   scale, so the two are visibly siblings without POS outweighing the platform. */
.pos-mini{
  display:grid; grid-template-columns:1.1fr 0.9fr; gap:48px; align-items:center;
  margin-top:24px; padding:46px 52px; border:1px solid var(--line); border-radius:20px;
  background:radial-gradient(circle at 88% 12%, rgba(var(--accent2-rgb),0.10), transparent 58%),
             linear-gradient(155deg, var(--card) 0%, var(--bg-soft) 100%);
}
.pos-badge{display:inline-flex; align-items:center; gap:8px; font-family:var(--mono); font-size:0.72rem;
  letter-spacing:0.06em; color:var(--teal); border:1px solid var(--teal-dim); padding:4px 12px;
  border-radius:100px; margin-bottom:18px;}
.pos-mini h4{font-size:1.5rem; font-weight:800; letter-spacing:-0.018em; margin-bottom:12px;}
.pos-mini p{color:var(--text-dim); font-size:0.96rem; max-width:46ch;}
.pos-tags{display:flex; flex-wrap:wrap; gap:8px; margin:22px 0 26px;}
.pos-tags span{font-family:var(--mono); font-size:0.74rem; color:var(--text-faint);
  border:1px solid var(--line-soft); background:var(--tint-2); padding:5px 11px; border-radius:100px;}
.pos-mini a{display:inline-flex; align-items:center; gap:8px; color:var(--teal); font-size:0.94rem;
  font-weight:700; white-space:nowrap; border:1px solid var(--teal-dim); border-radius:100px;
  padding:11px 22px; transition:background .3s ease, border-color .3s ease, transform .3s cubic-bezier(.22,1,.36,1);}
.pos-mini a:hover{background:rgba(var(--accent-rgb),0.1); border-color:var(--teal); transform:translateY(-2px);}

/* the order ticket — same mono language as .di-visual, one notch quieter */
.pos-visual{background:var(--glass); backdrop-filter:blur(6px); border:1px solid var(--line);
  border-radius:14px; padding:22px 24px; font-family:var(--mono); font-size:0.8rem;
  box-shadow:var(--shadow-visual); transform-style:preserve-3d; transition:transform .15s ease-out;}
/* one ticket per sector — the product is not restaurant-only, and a karahi
   receipt was quietly saying it was. Every ticket holds the same number of rows
   so switching does not resize the card. */
.pos-tabs{display:flex; flex-wrap:wrap; gap:6px; margin-bottom:16px;}
.pos-tabs button{font-family:var(--mono); font-size:0.7rem; letter-spacing:0.03em; cursor:pointer;
  color:var(--text-faint); background:none; border:1px solid transparent; border-radius:100px;
  padding:5px 11px; transition:color .25s ease, border-color .25s ease, background .25s ease;}
.pos-tabs button:hover{color:var(--teal);}
.pos-tabs button.is-on{color:var(--teal); border-color:var(--teal-dim); background:rgba(var(--accent-rgb),0.09);}
.pos-tabs button:focus-visible{outline:2px solid var(--teal); outline-offset:2px;}
.pos-ticket[hidden]{display:none;}
.pos-ticket{animation:posFade .32s ease both;}
@keyframes posFade{from{opacity:0; transform:translateY(6px);} to{opacity:1; transform:none;}}
@media (prefers-reduced-motion:reduce){ .pos-ticket{animation:none;} }
.pos-rcpt-top{display:flex; justify-content:space-between; color:var(--text-faint);
  font-size:0.72rem; letter-spacing:0.05em; padding-bottom:14px; border-bottom:1px solid var(--line-soft);}
.pos-row{display:flex; justify-content:space-between; gap:14px; padding:9px 0; color:var(--text-dim);}
.pos-row b{color:var(--text); font-weight:500;}
/* dashed rule reads as a receipt tear without any mask trickery */
.pos-row.sub{margin-top:6px; padding-top:13px; border-top:1px dashed var(--line);}
.pos-row.total b{color:var(--teal); font-size:0.95rem;}
.pos-stamp{display:flex; align-items:center; gap:7px; margin-top:14px; padding-top:13px;
  border-top:1px solid var(--line-soft); color:var(--teal); font-size:0.72rem;}
.pos-stamp .dot{width:6px; height:6px; border-radius:50%; background:var(--teal);
  box-shadow:0 0 10px var(--teal); animation:pulse 2s ease-in-out infinite;}

.process-list{display:grid; grid-template-columns:repeat(4,1fr); gap:20px;}
.proc-cell{border:1px solid var(--line); border-radius:16px; padding:38px 30px; background:var(--card); transition:transform .3s, border-color .3s;}
.proc-cell:hover{transform:translateY(-6px); border-color:var(--teal-dim);}
.proc-cell .n{font-family:var(--mono); color:var(--teal); font-size:1.6rem; font-weight:600; margin-bottom:20px; opacity:0.5;}
.proc-cell h3{font-size:1.1rem; margin-bottom:10px;}
.proc-cell p{color:var(--text-dim); font-size:0.9rem;}

.why-grid{display:grid; grid-template-columns:repeat(2,1fr); gap:1px; background:var(--line-soft); border:1px solid var(--line-soft); border-radius:18px; overflow:hidden;}
.why-cell{background:var(--card); padding:36px; transition:background .3s;}
.why-cell:hover{background:var(--card-hi);}
.why-cell h3{font-size:1.06rem; margin-bottom:10px;}
.why-cell p{color:var(--text-dim); font-size:0.93rem;}

.about-grid{display:grid; grid-template-columns:1.1fr 0.9fr; gap:64px; align-items:start;}

/* ---------- FAQ ------------------------------------------------------------
   A one-page site has one URL to rank, so the only way to cover more of what
   people actually search for is to answer more of it on that page. These are the
   questions the practice is asked, and they are the source the FAQPage JSON-LD is
   written from — the two must stay in step, or the rich result quotes an answer
   the page does not show.

   Plain <details>: no JS, works with the CDN down, and collapsed by default so
   twelve answers cost twelve lines of page height rather than two screens. */
.faq-grid{display:grid; grid-template-columns:0.8fr 1.2fr; gap:64px; align-items:start;}
.faq-grid .section-head{margin-bottom:0; position:sticky; top:112px;}
.faq-list{border-top:1px solid var(--line-soft);}
.faq-list details{border-bottom:1px solid var(--line-soft);}
.faq-list summary{cursor:pointer; list-style:none; padding:21px 40px 21px 0; position:relative;
  font-weight:600; font-size:1rem; line-height:1.45; color:var(--text); transition:color .3s;}
.faq-list summary::-webkit-details-marker{display:none;}
.faq-list summary:hover{color:var(--teal);}
/* Optical, not geometric, centring: the box is centred on the row, but a chevron
   drawn from two borders carries its ink toward the apex, so a downward one reads
   low and an upward one reads high. Two pixels each way settles it. */
.faq-list summary::after{content:''; position:absolute; right:8px; top:50%; width:11px; height:11px;
  margin-top:-8px; border-right:1.8px solid var(--teal); border-bottom:1.8px solid var(--teal);
  transform:rotate(45deg); transition:transform .32s cubic-bezier(.2,.9,.2,1);}
.faq-list details[open] summary::after{transform:rotate(-135deg); margin-top:-3px;}
.faq-list details p{color:var(--text-dim); font-size:0.97rem; line-height:1.72;
  padding:0 40px 24px 0; margin:0;}
.faq-list details[open] p{animation:faqIn .38s ease both;}
@keyframes faqIn{from{opacity:0; transform:translateY(-6px);} to{opacity:1; transform:none;}}
@media (prefers-reduced-motion:reduce){
  .faq-list summary::after{transition:none;}
  .faq-list details[open] p{animation:none;}
}
@media (max-width:1000px){
  .faq-grid{grid-template-columns:1fr; gap:44px;}
  .faq-grid .section-head{position:static;}
}
.about-grid p{color:var(--text-dim); margin-bottom:20px; font-size:1.04rem;}
.hp{position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden;}
.form-status{margin-top:14px; font-size:0.88rem; line-height:1.5; min-height:1.2em;}
.form-status.ok{color:var(--teal);}
.form-status.err{color:var(--text);}
.form-status a{color:var(--teal); text-decoration:underline;}
.about-side{display:flex; flex-direction:column; gap:30px;}
/* the firm sells "a named practitioner on every file" — so the name has to be
   on the page. The card is the name and the role, nothing else. */
.principal{border:1px solid var(--line); border-radius:16px; padding:22px 24px; background:var(--card);}
.principal-top{display:flex; align-items:center; gap:14px;}
/* the emblem stands on its own — a tile behind it just boxes in a mark that is
   already a shape, and nowhere else on the page does the logo sit in a container */
.principal-mark{display:flex; align-items:center; justify-content:center; width:46px; height:46px; flex-shrink:0;}
.principal-mark img{display:block; height:46px; width:auto;}
/* same lossless recolour as .brand — mask the box with the emblem, fill with the
   theme teal, and leave the img element as the fallback where mask is unsupported */
@supports ((-webkit-mask-image:url()) or (mask-image:url())){
  .principal-mark img{display:none;}
  .principal-mark::before{content:''; display:block; width:46px; height:46px; flex:none;
    background-color:var(--teal);
    -webkit-mask:url('/assets/smshah-emblem.png') center/contain no-repeat;
    mask:url('/assets/smshah-emblem.png') center/contain no-repeat;}
}
.principal-id b{display:block; font-size:1.06rem; font-weight:700; letter-spacing:-0.01em;}
.principal-id span{display:block; font-size:0.8rem; color:var(--text-faint); margin-top:2px;}
.about-facts{display:grid; grid-template-columns:1fr 1fr; gap:26px;}
.fact{border-top:1px solid var(--line-soft); padding-top:16px;}
.fact .k{font-size:0.8rem; color:var(--text-faint); margin-bottom:6px;}
.fact .v{font-weight:700; font-size:1.05rem;}

.contact-grid{display:grid; grid-template-columns:0.85fr 1.15fr; gap:64px;}
.contact-links a{display:block; margin-bottom:16px; font-size:1.05rem; color:var(--text); transition:color .2s;}
.contact-links a:hover{color:var(--teal);}
.contact-links .lbl{display:block; font-size:0.8rem; color:var(--text-faint); margin-top:28px; margin-bottom:8px;}
form{display:flex; flex-direction:column; gap:16px;}
.field-row{display:grid; grid-template-columns:1fr 1fr; gap:16px;}
input, textarea{background:var(--tint); border:1px solid var(--line); border-radius:10px; padding:15px 18px; color:var(--text); font-family:var(--serif); font-size:0.95rem; width:100%; transition:border-color .25s;}
input:focus, textarea:focus{outline:none; border-color:var(--teal);}
textarea{min-height:130px; resize:vertical;}
form .btn{align-self:flex-start; margin-top:8px; border:none; cursor:none;}

footer{border-top:1px solid var(--line-soft); padding:60px 0 32px;}
.foot-grid{display:grid; grid-template-columns:1.4fr 1fr 1fr; gap:40px; margin-bottom:44px;}
.foot-grid h3{font-size:0.82rem; color:var(--text-faint); margin-bottom:16px;}
.foot-grid a, .foot-grid p{display:block; font-size:0.92rem; color:var(--text-dim); margin-bottom:10px;}
.foot-grid a:hover{color:var(--teal);}
.foot-bottom{display:flex; justify-content:space-between; padding-top:26px; border-top:1px solid var(--line-soft); font-size:0.82rem; color:var(--text-faint); flex-wrap:wrap; gap:12px;}

/* Only hide the reveal targets once we know the animation can actually run.
   These rules used to be unconditional, so every section stayed at opacity:0
   until three.js + GSAP + ScrollTrigger had all come back from cdnjs — measured
   at 2.2s to DOMContentLoaded, and forever if the CDN is blocked or down.
   The head script adds .anim-ready, and takes it straight back off if GSAP has
   not arrived in 1.2s, so the page is readable either way. */
html.anim-ready .reveal{opacity:0; transform:translateY(30px);}
[data-tilt]{will-change:transform;}

/* ---------- theme switch: light / system / dark ---------- */
/* Collapsed by default: only the active mode shows, and clicking it opens the
   other two. Three permanent pills next to the CTA competed with it for a control
   most people set once and never touch again. The buttons are unchanged and still
   a radiogroup — the closed state just gives the inactive ones zero width, so the
   same markup and the same JS drive both states and nothing is hidden from
   assistive tech (they stay focusable and labelled). */
.theme-switch{display:inline-flex; align-items:center; gap:2px; padding:3px; flex:none;
  border:1px solid var(--line); border-radius:100px; background:var(--tint);
  transition:background .3s ease, border-color .3s ease;}
.theme-switch:not(.is-open) button[aria-checked="false"]{
  width:0; opacity:0; pointer-events:none; overflow:hidden;}
.theme-switch button{overflow:hidden;
  transition:color .3s ease, background .35s ease, box-shadow .35s ease,
             width .32s cubic-bezier(.22,1,.36,1), opacity .22s ease;}
.theme-switch.is-open{border-color:var(--teal-dim);}
@media (prefers-reduced-motion:reduce){ .theme-switch button{transition:none;} }
.theme-switch button{width:32px; height:32px; padding:0; border:0; border-radius:100px;
  background:transparent; color:var(--text-faint); cursor:inherit; flex:none;
  display:flex; align-items:center; justify-content:center;}
.theme-switch button:hover{color:var(--text-dim);}
.theme-switch button:focus-visible{outline:2px solid var(--teal); outline-offset:2px;}
.theme-switch button[aria-checked="true"]{background:var(--teal); color:var(--on-teal);
  box-shadow:0 4px 14px rgba(var(--accent-rgb),0.35);}

/* the bloom behind the hero reads as mud at full strength on a light ground */
:root[data-theme="light"] .hero-glow{
  background:radial-gradient(circle, rgba(var(--accent-rgb),0.07) 0%, rgba(var(--accent-rgb),0) 65%);}

/* a short cross-fade so the swap doesn't snap */
html.theme-anim, html.theme-anim *{
  transition:background-color .32s ease, color .32s ease, border-color .32s ease !important;}
@media (prefers-reduced-motion:reduce){ html.theme-anim, html.theme-anim *{transition:none !important;} }

/* ---------- PillNav — mode: morph ---------- */
.pn-morph{display:flex; align-items:center; gap:10px;}
.pn-morph a{
  --w:150px;                      /* fallback — js measures the real one */
  position:relative; isolation:isolate; overflow:hidden;
  width:42px; height:42px; border-radius:100px;
  display:flex; align-items:center; justify-content:center;
  border:1px solid var(--line); background:var(--tint);
  transition:width .5s cubic-bezier(.22,1,.36,1),
             border-color .4s ease, background .4s ease;
}
.pn-morph a::after{               /* the bloom under the pill */
  content:''; position:absolute; left:6px; right:6px; top:10px; bottom:-6px;
  border-radius:100px; z-index:-2;
  background:linear-gradient(115deg,var(--teal),var(--teal-2));
  filter:blur(15px); opacity:0; transition:opacity .5s ease;
}
.pn-morph .ic{
  position:absolute; display:flex; color:var(--text-dim);
  transition:opacity .3s ease, transform .4s cubic-bezier(.22,1,.36,1);
}
.pn-morph .lb{
  position:absolute; white-space:nowrap;
  font-size:.78rem; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
  color:var(--on-teal); opacity:0; transform:scale(.7);
  transition:opacity .3s ease .12s, transform .4s cubic-bezier(.22,1,.36,1) .12s;
}
/* .peek is the load-reveal — same look as hover */
.pn-morph a:hover,
.pn-morph a:focus-visible,
.pn-morph a.peek{
  width:var(--w); border-color:transparent;
  background:linear-gradient(115deg,var(--teal),var(--teal-2));
}
.pn-morph a:hover::after,
.pn-morph a:focus-visible::after,
.pn-morph a.peek::after{opacity:.5;}
.pn-morph a:hover .ic,
.pn-morph a:focus-visible .ic,
.pn-morph a.peek .ic{opacity:0; transform:scale(.4);}
.pn-morph a:hover .lb,
.pn-morph a:focus-visible .lb,
.pn-morph a.peek .lb{opacity:1; transform:scale(1);}


/* ---------- FBR sandbox scenario coverage ---------- */
/* The 28 chips used to sit on the page. They are a reference list, not a sales
   argument — as a wall under the DI feature they buried everything after them.
   Now the invoice mock is followed by a 28/28 counter that opens them in a modal. */
.di-visual-col{display:flex; flex-direction:column; gap:16px;}
.sn-trigger{
  position:relative; display:flex; align-items:center; gap:16px; width:100%; text-align:left; cursor:pointer;
  padding:16px 20px; border:1px solid var(--line); border-radius:14px; background:var(--tint-2);
  transition:border-color .3s ease, background .3s ease, transform .3s cubic-bezier(.22,1,.36,1);
}
.sn-trigger:hover{border-color:var(--teal-dim); background:rgba(var(--accent-rgb),0.07); transform:translateY(-2px);}
.sn-trigger:focus-visible{outline:2px solid var(--teal); outline-offset:3px;}
.sn-trigger-num{display:inline-flex; align-items:flex-end; line-height:1; flex-shrink:0;
  font-family:var(--mono); font-size:1.9rem; font-weight:600; color:var(--teal);}
.sn-slash{font-size:0.62em; opacity:0.65;}
.sn-trigger-txt{display:block; flex:1;}
.sn-trigger-txt b{display:block; font-size:0.9rem; font-weight:600;}
.sn-trigger-txt em{display:block; font-style:normal; font-size:0.78rem; color:var(--text-faint); margin-top:3px;}
.sn-trigger-go{flex-shrink:0; color:var(--teal); font-size:1.1rem; transition:transform .3s cubic-bezier(.22,1,.36,1);}
.sn-trigger:hover .sn-trigger-go{transform:translateX(4px);}

.sn-modal{position:fixed; inset:0; z-index:200; display:flex; align-items:center; justify-content:center; padding:24px;}
.sn-modal[hidden]{display:none;}
.sn-modal-back{position:absolute; inset:0; background:rgba(0,0,0,0.62); backdrop-filter:blur(3px);
  opacity:0; transition:opacity .22s ease;}
.sn-modal-panel{position:relative; width:min(920px, 100%); max-height:86vh; overflow-y:auto;
  border:1px solid var(--line); border-radius:18px; padding:38px 34px; background:var(--card);
  box-shadow:var(--shadow-panel); opacity:0; transform:translateY(12px) scale(0.98);
  transition:opacity .22s ease, transform .28s cubic-bezier(.22,1,.36,1);}
.sn-modal.is-open .sn-modal-back{opacity:1;}
.sn-modal.is-open .sn-modal-panel{opacity:1; transform:none;}
.sn-modal-x{position:absolute; top:14px; right:16px; width:30px; height:30px; padding:0; border:0; border-radius:8px;
  background:var(--tint); color:var(--text-faint); font-size:1.4rem; line-height:1; cursor:pointer;}
.sn-modal-x:hover{color:var(--teal); background:rgba(var(--accent-rgb),0.12);}
.sn-modal-head{margin-bottom:30px; padding-right:36px;}
.sn-kicker{font-family:var(--mono); font-size:0.72rem; letter-spacing:0.1em; color:var(--teal); margin-bottom:12px;}
.sn-modal-head h4{font-size:1.35rem; font-weight:700; letter-spacing:-0.015em; margin-bottom:10px;}
.sn-modal-head p{color:var(--text-dim); font-size:0.95rem; max-width:56ch;}
.sn-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(196px,1fr)); gap:10px;}
.sn{
  position:relative; display:block; padding:12px 14px; border-radius:11px;
  border:1px solid var(--line-soft); background:var(--tint-2);
  transition:border-color .35s ease, background .35s ease, transform .35s cubic-bezier(.22,1,.36,1), box-shadow .35s ease;
}
.sn i{display:block; font-family:var(--mono); font-style:normal; font-size:0.76rem; color:var(--teal); margin-bottom:4px;}
.sn em{display:block; font-style:normal; font-size:0.8rem; color:var(--text-dim); line-height:1.35; transition:color .35s ease;}
.sn::after{
  content:'\2713'; position:absolute; top:11px; right:12px;
  font-size:0.72rem; color:var(--teal); opacity:0; transform:scale(.5);
  transition:opacity .35s ease, transform .4s cubic-bezier(.22,1,.36,1);
}
.sn:hover{
  border-color:var(--teal-dim); background:rgba(var(--accent-rgb),0.06);
  transform:translateY(-3px); box-shadow:var(--shadow-chip);
}
.sn:hover em{color:var(--text);}
.sn:hover::after{opacity:1; transform:scale(1);}

/* ---------- word-by-word heading reveal ---------- */
[data-split]{line-height:1.2;}
.w-mask{display:inline-block; overflow:hidden; vertical-align:bottom; line-height:1.2;
  /* the padding keeps descenders out of the clip, the negative margin keeps the leading tight */
  padding-bottom:0.16em; margin-bottom:-0.16em;}
.w-mask > span{display:inline-block; will-change:transform;}

/* a softer lift on the cards that already carry a gradient border */
.svc-card:hover{box-shadow:var(--shadow-card), 0 0 46px rgba(var(--accent-rgb),0.10);}
.why-cell{position:relative; overflow:hidden; --mx:50%; --my:50%;
  transition:background .45s ease, box-shadow .45s ease;}

/* cursor-follow glow, same idea as the service cards but dialled back */
.why-cell::after{content:''; position:absolute; inset:0; pointer-events:none; z-index:0;
  background:radial-gradient(260px circle at var(--mx) var(--my), rgba(var(--accent-rgb),0.055), rgba(var(--accent-rgb),0.015) 42%, transparent 68%);
  opacity:0; transition:opacity .5s ease;}
.why-cell:hover::after{opacity:1;}

/* a teal hairline that draws itself along the top edge */
.why-cell::before{content:''; position:absolute; top:0; left:0; right:0; height:1px; z-index:2;
  background:linear-gradient(90deg, var(--teal), rgba(var(--accent2-rgb),0));
  transform:scaleX(0); transform-origin:left; transition:transform .6s cubic-bezier(.2,.8,.2,1);}
.why-cell:hover::before{transform:scaleX(1);}

.why-cell > *{position:relative; z-index:1;}
.why-cell:hover{background:linear-gradient(160deg, var(--card-hi) 0%, var(--bg-soft) 100%);}

.why-cell .idx{display:block; font-family:var(--mono); font-size:0.78rem; color:var(--text-faint);
  margin-bottom:16px; transition:color .45s ease, letter-spacing .5s cubic-bezier(.2,.8,.2,1), text-shadow .5s ease;}
.why-cell:hover .idx{color:var(--teal); letter-spacing:0.2em; text-shadow:0 0 16px rgba(var(--accent-rgb),0.45);}

.why-cell h3{transition:transform .55s cubic-bezier(.2,.8,.2,1), color .4s ease;}
.why-cell:hover h3{transform:translateY(-2px); color:var(--teal-2);}
.why-cell p{transition:color .4s ease;}
.why-cell:hover p{color:var(--text-dim);}

/* ================= GHOST COMPONENT (ghost.css) =================
   Placed at the end of the sheet, ahead of the media queries, so its rules
   win any equal-specificity tie with what came before. */
/* ============ GHOST COMPONENT ============ */
.gh{display:inline-block;width:var(--gh-w,180px);transform-origin:top center;
  animation:gh-float 2.8s ease-in-out infinite;}
.gh-svg{display:block;width:100%;height:auto;overflow:visible;
  transform-origin:50% 18%;                      /* pivot near the head, so the hem swings */
  animation:gh-sway 4.3s ease-in-out infinite;   /* 4.3 against 2.8 — never lines up twice */
  filter:drop-shadow(0 14px 26px rgba(78,205,196,.16));}
/* A soft glow behind the ghost. The drop-shadow on .gh-svg above only darkens
   underneath it, so on a dark ground the ghost had nothing lifting it off the
   page. It lives on ::before inside the wrapper at z-index:-1 — .gh already
   makes a stacking context (it is animated), so the glow paints behind the SVG
   and nothing else. Being inside the wrapper it travels with the float and
   shrinks away with the errand, instead of being left hanging in mid-air. */
.gh{position:relative;}
.gh::before{content:''; position:absolute; left:50%; top:52%; width:165%; height:150%;
  transform:translate(-50%,-50%); z-index:-1; pointer-events:none; border-radius:50%;
  background:radial-gradient(closest-side,
    rgba(78,205,196,.26), rgba(78,205,196,.09) 55%, rgba(78,205,196,0) 78%);
  animation:gh-glow 4.3s ease-in-out infinite;}
/* 4.3s to match the sway, not the 2.8s float — the glow should breathe with the
   slower of the two or it reads as a flicker locked to the bob */
@keyframes gh-glow{
  0%,100%{opacity:.72; transform:translate(-50%,-50%) scale(1);}
  50%    {opacity:1;   transform:translate(-50%,-50%) scale(1.08);}
}
/* a sad ghost is dimmer as well as lower */
.gh[data-ghost="sad"]::before{background:radial-gradient(closest-side,
  rgba(78,205,196,.15), rgba(78,205,196,.05) 55%, rgba(78,205,196,0) 78%);}
@keyframes gh-float{0%,100%{transform:translateY(0) scaleY(1);}50%{transform:translateY(-8px) scaleY(1.04);}}
@keyframes gh-sway{
  0%,100%{transform:translateY(var(--droop,0)) rotate(0)      skewX(0);}
  33%    {transform:translateY(var(--droop,0)) rotate(1.5deg) skewX(-1.3deg);}
  66%    {transform:translateY(var(--droop,0)) rotate(-1.3deg) skewX(1.1deg);}
}
.gh-b1{animation:gh-d1 11s ease-in-out infinite;}
.gh-b2{animation:gh-d2 13s ease-in-out infinite;}
.gh-b3{animation:gh-d3 9s  ease-in-out infinite;}
.gh-b4{animation:gh-d4 15s ease-in-out infinite;}
@keyframes gh-d1{0%,100%{transform:translate(0,0);}50%{transform:translate(22px,18px);}}
@keyframes gh-d2{0%,100%{transform:translate(0,0);}50%{transform:translate(-20px,24px);}}
@keyframes gh-d3{0%,100%{transform:translate(0,0);}50%{transform:translate(18px,-20px);}}
@keyframes gh-d4{0%,100%{transform:translate(0,0);}50%{transform:translate(-16px,-16px);}}
.gh-eyes{transition:transform .35s cubic-bezier(.22,1,.36,1);}
.gh-eye{transform-box:fill-box;transform-origin:center;animation:gh-blink 4.4s infinite ease-in-out;}
@keyframes gh-blink{0%,93%,100%{transform:scaleY(1);}96%{transform:scaleY(.06);}}
/* --- moods: idle is the default face, the others swap in --- */
.gh .f-happy,.gh .f-sad,.gh .gh-mouth{display:none;}
.gh[data-ghost="happy"] .f-idle{display:none;}
.gh[data-ghost="happy"] .f-happy,
.gh[data-ghost="happy"] .m-happy{display:block;}
.gh[data-ghost="sad"] .f-idle{display:none;}
.gh[data-ghost="sad"] .f-sad,
.gh[data-ghost="sad"] .m-sad{display:block;}
/* a sad ghost hangs lower and breathes slower */
.gh[data-ghost="sad"]{animation-duration:4.6s;}
.gh[data-ghost="sad"]{--droop:5px;}

/* --- the errand: it falls away into the distance, and comes back ---
   No panel edge involved — the whole thing is scale, so it reads as depth
   rather than as something sliding off a box. It leans TOWARDS you first;
   that half-beat of coming closer is what sells the going-away. --- */
.gh.is-errand{animation:gh-errand 2s linear forwards;}
@keyframes gh-errand{
  0%  {transform:translateY(0) scale(1); opacity:1;
       animation-timing-function:cubic-bezier(.3,.6,.4,1);}
  14% {transform:translateY(9px) scale(1.17); opacity:1;      /* leans in */
       animation-timing-function:cubic-bezier(.5,0,.95,.55);}
  44% {transform:translateY(-36px) scale(.05); opacity:0;}    /* gone */
  62% {transform:translateY(-36px) scale(.05); opacity:0;
       animation-timing-function:cubic-bezier(0,.6,.3,1);}
  88% {transform:translateY(-4px) scale(1.06); opacity:1;     /* back, overshoot */
       animation-timing-function:cubic-bezier(.3,0,.3,1);}
  100%{transform:translateY(0) scale(1); opacity:1;}
}

/* The body lags the trip. gh-errand above moves the ghost through depth;
   this turns its SHAPE a beat behind — recoiling as it gathers, tipping as
   it falls away, righting itself on the way back. Two overlapping
   animations on two elements is the whole difference between a living
   thing and a picture being resized. */
.gh.is-errand .gh-svg{animation:gh-whip 2s linear forwards;}
@keyframes gh-whip{
  0%  {transform:rotate(0) skewX(0) scale(1,1);
       animation-timing-function:cubic-bezier(.3,.6,.4,1);}
  13% {transform:rotate(-6deg) skewX(5deg) scale(.96,1.06);
       animation-timing-function:cubic-bezier(.5,0,.9,.6);}
  44% {transform:rotate(15deg) skewX(-7deg) scale(1.06,.94);}
  62% {transform:rotate(15deg) skewX(-7deg) scale(1.06,.94);
       animation-timing-function:cubic-bezier(0,.6,.3,1);}
  78% {transform:rotate(-8deg) skewX(7deg) scale(1.04,.96);}
  90% {transform:rotate(3deg) skewX(-3deg) scale(.98,1.03);
       animation-timing-function:cubic-bezier(.3,0,.3,1);}
  100%{transform:rotate(0) skewX(0) scale(1,1);}
}

/* The eyes move first — they glance back, then lead the body out, then
   find you again on the way home. An animation outranks the inline style
   the cursor-tracking sets, so this simply takes over for the trip. */
.gh.is-errand .gh-eyes{animation:gh-look 2s ease-in-out;}
@keyframes gh-look{
  0%  {transform:translate(0,0);}
  12% {transform:translate(0,4px);}       /* looks at you as it leans in */
  40% {transform:translate(5px,-4px);}    /* eyes go first, up and away */
  62% {transform:translate(5px,-4px);}
  80% {transform:translate(-3px,-2px);}
  100%{transform:translate(0,0);}
}

@media (prefers-reduced-motion:reduce){
  .gh,.gh-mesh ellipse,.gh-eye{animation:none;}
  .gh::before{animation:none; opacity:.85;}
  .gh-eyes{transition:none;}
  .gh-svg{animation:none;}
  .gh.is-errand,.gh.is-errand .gh-svg,.gh.is-errand .gh-eyes{animation:none;}
}

/* ---- the errand: form -> ghost runs the query over -> confirmation ----
   Both lines of copy sit in one fixed box and cross-fade, so the panel never
   changes height and nothing below it jumps. */
.m2-stage{display:flex; align-items:center; justify-content:center; overflow:hidden;}
.st{display:none; width:100%; flex-direction:column;}
.m2-stage[data-stage="form"] .st-form{display:flex;}
.m2-stage[data-stage="run"] .st-run{display:flex; align-items:center; text-align:center;}
.st-run{gap:0; padding:14px 0 6px;}
.run-copy{position:relative; width:100%; min-height:112px; margin-top:12px;}
.run-line,.run-done{position:absolute; inset:0; display:flex; flex-direction:column;
  align-items:center; opacity:0; transition:opacity .45s ease; pointer-events:none;}
.run-line.on,.run-done.on{opacity:1; pointer-events:auto;}
.run-line{justify-content:flex-start; font-size:0.95rem; color:var(--text-dim);}
.run-line .dots::after{content:''; animation:gh-dots 1.2s steps(4,end) infinite;}
@keyframes gh-dots{0%{content:'';}25%{content:'.';}50%{content:'..';}75%{content:'...';}}
.run-done #typeTitle{font-size:1.15rem; font-weight:700; min-height:1.5em;}
.run-done p{font-size:0.9rem; color:var(--text-dim); max-width:38ch; margin-top:6px; min-height:2.6em;}
.run-done.err #typeTitle{color:var(--text);}
.run-done p a{color:var(--teal); text-decoration:underline;}
.caret{display:inline-block; width:2px; height:1em; background:var(--teal);
  vertical-align:-2px; margin-left:2px; animation:gh-caret .9s step-end infinite;}
@keyframes gh-caret{0%,100%{opacity:1;}50%{opacity:0;}}
.run-done .m2-again{opacity:0; transition:opacity .4s ease;}
.run-done.typed .m2-again{opacity:1;}
/* Coming back from the confirmation, the fields arrive one after another rather
   than the whole panel snapping in. Only on the way back — on first load the form
   is simply there, and animating it then would delay a form nobody has asked to
   see yet. Each field is listed explicitly instead of using nth-child, so the
   honeypot (which must never be revealed) cannot pick up a delay by accident. */
/* 22px and 0.55s, stepped 0.11s apart. The first pass used 10px over 0.5s at
   0.07s steps: it measured correctly but was too small and too tightly spaced to
   read as anything — the form just looked like it appeared. The travel has to be
   far enough to see and the gap wide enough that the fields arrive as five
   separate events rather than one blur. */
@keyframes fieldIn{
  from{opacity:0; transform:translateY(22px);}
  to  {opacity:1; transform:none;}
}
.st-form.is-returning .field-row input,
.st-form.is-returning > input,
.st-form.is-returning > textarea,
.st-form.is-returning > .btn{animation:fieldIn .55s cubic-bezier(.22,1,.36,1) both;}
.st-form.is-returning .field-row input:nth-of-type(1){animation-delay:.03s;}
.st-form.is-returning .field-row input:nth-of-type(2){animation-delay:.14s;}
.st-form.is-returning > input[name="company"]{animation-delay:.25s;}
.st-form.is-returning > textarea{animation-delay:.36s;}
.st-form.is-returning > .btn{animation-delay:.47s;}
@media (prefers-reduced-motion:reduce){
  .st-form.is-returning .field-row input,
  .st-form.is-returning > input,
  .st-form.is-returning > textarea,
  .st-form.is-returning > .btn{animation:none;}
}
.m2-again{display:inline-block; font-family:var(--mono); font-size:0.78rem; color:var(--teal);
  margin-top:18px; border-bottom:1px solid var(--teal-dim); padding-bottom:2px; cursor:pointer;}
.m2-again:hover{color:var(--teal-2);}
@media (prefers-reduced-motion:reduce){
  .run-line,.run-done,.run-done .m2-again{transition:none;}
  .run-line .dots::after,.caret{animation:none;}
}

@media (prefers-reduced-motion:reduce){
  .why-cell, .why-cell *, .why-cell::before, .why-cell::after{transition:none !important;}
}

@media (max-width:880px){
  .nav-cta{display:none;}
  .pn-morph{gap:6px;}
  .pn-morph a{width:38px; height:38px;}
  .theme-switch button{width:30px; height:30px;}
  .brand img{height:34px;}
  .brand::before{width:34px; height:34px;}
  .brand-title{font-size:1.15rem;}
  .brand-sub{font-size:0.62rem;}
  .di-grid, .about-grid, .contact-grid{grid-template-columns:1fr;}
  .svc-grid, .process-list, .why-grid{grid-template-columns:1fr 1fr;}
  .di-feature{padding:36px 24px;}
  .field-row{grid-template-columns:1fr;}
  .plat-pillars{grid-template-columns:1fr; gap:30px; margin-top:38px; padding-top:32px;}
  .pos-mini{grid-template-columns:1fr; gap:34px; padding:34px 26px;}
  .sn-modal{padding:14px;}
  .sn-modal-panel{padding:30px 22px;}
  .sn-grid{grid-template-columns:repeat(auto-fill,minmax(170px,1fr)); gap:8px;}
  body{cursor:auto;}
}
@media (max-width:560px){
  .svc-grid, .process-list, .why-grid{grid-template-columns:1fr;}
  /* 28 chips in one column is a long scroll — hold two across on phones */
  .sn-grid{grid-template-columns:repeat(2,1fr); gap:8px;}
  .sn{padding:10px 11px;}
  .sn em{font-size:0.74rem;}
  .sn i{font-size:0.72rem;}
  .sn-trigger{gap:12px; padding:14px 16px;}
  .sn-trigger-num{font-size:1.6rem;}
  .pn-morph{gap:5px;}
  .pn-morph a{width:34px; height:34px;}
  .theme-switch{padding:2px;}
  .theme-switch button{width:28px; height:28px;}
  .theme-switch button svg{width:14px; height:14px;}
}
@media (max-width:400px){
  /* five pills plus the wordmark need the last 24px back on the narrowest phones */
  .nav-inner{padding-left:20px; padding-right:20px;}
}
.testi-wrap{
  perspective:1000px; overflow:hidden; position:relative;
  height:520px; background:transparent;
}
.testi-3d{
  position:absolute; inset:0; display:flex; gap:18px; justify-content:center; padding:40px 20px;
  transform:translateX(-40px) rotateX(18deg) rotateY(-14deg) rotateZ(14deg);
  transform-style:preserve-3d;
}
.testi-col{display:flex; flex-direction:column; gap:18px; width:230px; flex-shrink:0;}
.testi-col.up{animation:marqueeUp 34s linear infinite;}
.testi-col.down{animation:marqueeDown 34s linear infinite;}
.testi-col:nth-child(2){animation-duration:40s;}
.testi-col:nth-child(4){animation-duration:38s;}
@keyframes marqueeUp{from{transform:translateY(0);} to{transform:translateY(-50%);}}
@keyframes marqueeDown{from{transform:translateY(-50%);} to{transform:translateY(0);}}
.testi-card{
  background:var(--glass-testi); backdrop-filter:blur(6px); border:1px solid var(--line); border-radius:14px; padding:20px;
  box-shadow:var(--shadow-testi); width:100%;
}
.testi-head{display:flex; align-items:center; gap:10px; margin-bottom:12px;}
.testi-avatar{
  width:34px; height:34px; border-radius:50%; background:var(--avatar-bg);
  display:flex; align-items:center; justify-content:center; font-weight:700; font-size:0.8rem; color:var(--on-teal); flex-shrink:0;
}
.testi-name{font-size:0.88rem; font-weight:700;}
.testi-role{font-size:0.74rem; color:var(--text-faint);}
.testi-body{font-size:0.85rem; color:var(--text-dim); line-height:1.5;}
.testi-fade{position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(to bottom, var(--bg) 0%, transparent 15%, transparent 82%, var(--bg) 100%);}
@media (max-width:880px){
  .testi-wrap{height:440px;}
  .testi-3d{transform:translateX(-10px) rotateX(14deg) rotateY(-10deg) rotateZ(10deg);}
  .testi-col{width:190px;}
}
/* ---------- narrow-phone and touch corrections ---------- */

/* The theme switch is a collapsed pill that expands on tap. It sits hard against
   the right padding edge, so on a phone it expanded straight off the screen and
   the Dark button — the last of the three — became unreachable: the page does not
   scroll sideways to it, so dark mode simply could not be selected on any handset
   narrower than about 430px. Open, it now leaves the flow and anchors its right
   edge to where it already sat, growing leftwards over the nav pills instead.
   .nav-right keeps its closed width so the pills do not jump when it opens. */
@media (max-width:460px){
  .nav-right{position:relative; min-width:38px; justify-content:flex-end;}
  .theme-switch.is-open{
    position:absolute; right:0; top:50%; margin-top:-17px; z-index:6;
    background:var(--bg-soft); box-shadow:0 8px 24px rgba(0,0,0,0.16);}
}

/* Below ~365px the wordmark, five pills and the switch wanted 341px of a 280px
   line and pushed the document to 360px wide — the whole page scrolled sideways.
   The pieces are trimmed until they fit: the 9.9px "Consulting" sub-line goes
   first, being too small to read at this size anyway. */
@media (max-width:365px){
  .nav-inner{padding-left:16px; padding-right:16px;}
  .brand{gap:9px;}
  .brand img{height:36px;}
  .brand::before{width:36px !important; height:36px !important;}
  .brand-sub{display:none;}
  .pn-morph{gap:4px;}
  .pn-morph a{width:31px; height:31px;}
  .theme-switch button{width:26px; height:26px;}
  .nav-right{min-width:34px;}
  .theme-switch.is-open{margin-top:-16px;}
}
@media (max-width:340px){
  .nav-inner{padding-left:12px; padding-right:12px;}
  .brand{gap:8px;}
  .brand img{height:32px;}
  .brand::before{width:32px !important; height:32px !important;}
  .pn-morph a{width:27px; height:27px;}
}

/* The rotated testimonial wall is a flourish that works at desk widths, where one
   card of sixteen falls outside the frame. On a phone the same rotation put
   fourteen of sixteen outside it, chopping sentences mid-word — the section read
   as broken rather than designed. Below 700px the cards run flat in one column.
   Each column holds its two testimonials twice so the marquee can loop; with the
   marquee off, the second pair is a visible duplicate, so it is hidden and the
   eight distinct testimonials remain. */
/* The wall only clears its own frame once .wrap reaches its 1180px ceiling.
   Below that the rotation walks the outer columns off the edge — one clipped card
   of sixteen at 1180px, seven at 900px, fourteen at 390px. So the wall is flat
   below 1150px, re-flowing 4 / 2 / 1 across as the room runs out. */
@media (max-width:1150px){
  .testi-wrap{height:auto; overflow:visible; perspective:none;}
  .testi-3d{position:static; transform:none; flex-wrap:wrap;
    gap:14px; padding:0; justify-content:flex-start;}
  .testi-col, .testi-col.up, .testi-col.down{
    width:calc(25% - 10.5px); gap:14px; animation:none;}
  .testi-col > .testi-card:nth-child(n+3){display:none;}
  .testi-fade{display:none;}
}
@media (max-width:880px){
  .testi-col, .testi-col.up, .testi-col.down{width:calc(50% - 7px);}
}
/* two across still leaves a readable measure on a tablet; on a phone it does not */
@media (max-width:640px){
  .testi-col, .testi-col.up, .testi-col.down{width:100%;}
}

/* The footer keeps three fixed fractions and a 40px gap at every width. On a small
   phone that leaves about 50px a column, and "Digital Invoicing (DI)" cannot fold
   that far — it was one of the two things pushing the document wider than the
   screen at 320px. The brand column takes its own row and the two link columns
   share the next. */
@media (max-width:640px){
  .foot-grid{grid-template-columns:1fr 1fr; gap:30px 24px;}
  .foot-grid > :first-child{grid-column:1 / -1;}
}

/* The other one: grid and flex children default to min-width:auto, so the POS
   receipt mock could not be squeezed below its own content width and carried the
   page out with it. */
.pos-mini > *, .pos-visual, .pos-tabs, .pos-ticket, .pos-rcpt-top, .pos-row{min-width:0;}
.pos-rcpt-top{gap:10px; flex-wrap:wrap;}
.pos-row{overflow-wrap:anywhere;}

/* "Visit pos.smshahconsulting.com" is held on one line by .pos-mini a, and at 289px
   that pill is wider than a 320px screen has room for. The domain stays unbroken;
   the line is simply allowed to fold, and the padding eases. */
@media (max-width:400px){
  .pos-mini a{white-space:normal; padding:11px 16px; text-align:center;}
}

/* Footer links were 23px of text with 10px between them. The spacing between one
   link and the next is unchanged — the gap simply moves inside the link, so the
   row you can actually hit is 33px instead of 23px. */
.foot-grid a{padding:5px 0; margin-bottom:0;}

/* A 14px circle is a fine footnote marker and an impossible touch target. The
   visible dot stays 14px; an invisible ring takes the tap out to 30px. */
.stat-ref{position:relative;}
.stat-ref::after{content:''; position:absolute; inset:-8px; border-radius:50%;}

/* ---------- Insights pages ----------
   /blog/ and its posts. Everything above is shared with the homepage; this block
   only adds what a text page needs, built from the same tokens. No class here is
   used on the homepage. */

/* Muted labels (dates, breadcrumb, facts labels, "Sources"). --faint-aa was a blog-only
   stand-in while the site's dark --text-faint (#5b6568) failed AA; that token is now
   #80898c itself, so this simply follows it in both themes. */
.page-top{--faint-aa:var(--text-faint);}
.page-top{padding:150px 0 110px;}
.page-top .section-head{margin-bottom:48px;}
.section-head h1{font-size:clamp(1.9rem, 3.4vw, 2.8rem); font-weight:800; letter-spacing:-0.02em; line-height:1.15; margin-bottom:18px;}

.post-list{display:flex; flex-direction:column; gap:20px; max-width:880px;}
.post-card{position:relative; display:block; padding:40px 44px; border:1px solid var(--line); border-radius:18px;
  background:var(--card); transition:border-color .3s, transform .3s cubic-bezier(.2,.8,.2,1), box-shadow .3s;}
.post-card:hover{border-color:var(--teal); transform:translateY(-3px); box-shadow:var(--shadow-card);}
.post-card:focus-visible{outline:2px solid var(--teal); outline-offset:3px;}
.post-date{display:block; font-family:var(--mono); font-size:0.78rem; color:var(--faint-aa); margin-bottom:14px; letter-spacing:0.02em;}
.post-card h2{font-size:clamp(1.35rem, 2.4vw, 1.75rem); font-weight:800; letter-spacing:-0.015em; line-height:1.25; margin-bottom:14px;}
.post-card p{color:var(--text-dim); font-size:1.02rem; max-width:36rem;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;}
.post-more{display:inline-flex; align-items:center; gap:8px; margin-top:22px; color:var(--teal); font-weight:700; font-size:0.92rem;}
.post-more svg{transition:transform .3s;}
.post-card:hover .post-more svg{transform:translateX(4px);}

.crumbs{font-size:0.84rem; color:var(--faint-aa); margin-bottom:34px;}
.crumbs ol{list-style:none; display:flex; flex-wrap:wrap; gap:6px 0;}
.crumbs li{display:inline;}
/* separator trails its item, so a wrapped trail never starts a line with a lone "/" */
.crumbs li:not(:last-child)::after{content:'/'; margin:0 10px; color:var(--line);}
.crumbs a{color:var(--text-dim); transition:color .2s;}
.crumbs a:hover{color:var(--teal);}
.crumbs [aria-current]{color:var(--faint-aa);}

/* measured, not ch-based: 1ch is the width of "0", wider than average text, so
   68ch gave ~87 characters a line. At 18px, 35rem renders 67 characters a line on
   average and 73 at most — inside 65–75. Re-measure if the size or face changes. */
.article{max-width:none;}
.article-head{max-width:none;}
.article-head h1{max-width:26ch; text-wrap:balance;}
.prose{max-width:35rem;}
.article-head h1{font-size:clamp(2rem, 4.2vw, 3.1rem); font-weight:800; letter-spacing:-0.025em; line-height:1.12; margin-bottom:18px;}
.article-head{margin-bottom:40px; padding-bottom:30px; border-bottom:1px solid var(--line-soft);}
.prose{font-size:18px; line-height:1.75; color:var(--text-bright);}
.prose p{margin-bottom:1.25em;}
.prose .lede{font-size:1.3rem; line-height:1.6; color:var(--text);}
.prose strong{color:var(--text); font-weight:700;}
.prose h2{font-size:clamp(1.3rem, 2.2vw, 1.6rem); font-weight:800; letter-spacing:-0.015em; line-height:1.3; color:var(--text); margin:2.1em 0 0.7em;}
.prose ul{margin:0 0 1.25em; padding-left:0; list-style:none;}
.prose li{position:relative; padding-left:26px; margin-bottom:0.6em;}
.prose li::before{content:''; position:absolute; left:4px; top:0.72em; width:7px; height:7px; border-radius:50%; background:var(--teal);}
.prose .post-note{margin-top:2.4em; padding:18px 22px; border:1px solid var(--line); border-radius:12px; background:var(--tint);
  font-size:0.9rem; line-height:1.65; color:var(--text-dim);}

.post-cta{max-width:35rem; margin-top:56px; padding:40px 44px; border:1px solid var(--line); border-radius:20px;
  background:linear-gradient(140deg, rgba(var(--accent-rgb),0.10), rgba(var(--accent-rgb),0) 60%), var(--card);}
.post-cta .kicker{color:var(--teal); font-size:0.9rem; font-weight:700; margin-bottom:12px;}
.post-cta h2{font-size:clamp(1.4rem, 2.6vw, 1.9rem); font-weight:800; letter-spacing:-0.02em; line-height:1.2; margin-bottom:12px;}
.post-cta p{color:var(--text-dim); margin-bottom:26px; max-width:52ch;}
.post-cta .btn-row{margin-bottom:0; justify-content:flex-start;}
.post-back{display:inline-block; margin-top:34px; color:var(--text-dim); font-size:0.92rem; transition:color .2s;}
.post-back:hover{color:var(--teal);}

@media (max-width:640px){
  .page-top{padding:120px 0 80px;}
  .post-card, .post-cta{padding:28px 24px;}
  .prose .lede{font-size:1.2rem;}
}

/* ---------- post layout: article | sticky rail ----------
   .post is one grid. The header block spans both columns; below its rule the article
   sits left at its own reading measure (.prose, 35rem at 18px ≈ 67 characters a line) and the
   rail right. Every rail selector is scoped under .post: the homepage has its own
   .rail (the process-step line) and an unscoped rule here hid it on mobile.
   The rail's grid area runs down beside the closing CTA as well, so it
   stays pinned for the whole article: a sticky item cannot leave its grid area. */
.post{--header-h:85px; display:grid; align-items:start; column-gap:100px;
  /* the rail takes whatever is left once the article column is 35rem + 56px (the
     text plus under 60px of slack), between 300px (below that the facts wrap) and
     400px. At the full 1116px: rail 400, column 616. */
  grid-template-columns:minmax(0,1fr) clamp(300px, calc(100% - 35rem - 156px), 400px);}
@media (max-width:1100px){
  .post{column-gap:64px; grid-template-columns:minmax(0,1fr) clamp(300px, calc(100% - 35rem - 120px), 400px);}
}
.post > .article-head{grid-column:1 / -1;}
.post > .article{grid-column:1; grid-row:2;}
.post > .post-end{grid-column:1; grid-row:3;}
.post > .rail{grid-column:2; grid-row:2 / span 2; align-self:stretch;}
.prose h2{scroll-margin-top:calc(var(--header-h) + 24px);}

/* The rail stretches over the article's grid rows, so its sticky part can travel the
   whole way down: a sticky element never leaves its parent's box. "At a glance" sits at
   the top, whole, and scrolls away with the page; contents + CTA (.rail-sticky) pin
   below the fixed header, not behind it. */
.post .rail{display:flex; flex-direction:column; gap:16px;}
.post .rail-sticky{position:sticky; top:calc(var(--header-h) + 24px); display:flex; flex-direction:column; gap:16px;}
.post .rail-box{border:1px solid var(--line); border-radius:16px; background:var(--card); padding:22px 24px;}
.post .rail-box[hidden]{display:none;}
.post .rail-h{font-family:var(--mono); font-size:0.72rem; font-weight:500; letter-spacing:0.14em; text-transform:uppercase; color:var(--teal); margin-bottom:12px;}

.facts > div{padding:11px 0; border-bottom:1px solid var(--line-soft);}
.facts > div:first-child{padding-top:2px;}
.facts > div:last-child{border-bottom:0; padding-bottom:0;}
.facts dt{font-size:11.5px; font-weight:600; letter-spacing:0.06em; text-transform:uppercase; color:var(--faint-aa); margin-bottom:3px;}
.facts dd{font-size:14px; font-weight:600; line-height:1.4; color:var(--text);}
.facts .is-accent dd{color:var(--teal);}

.post .rail-toc ol{list-style:none;}
.post .rail-toc a{display:block; padding:7px 0 7px 14px; border-left:1px solid var(--line); font-size:0.88rem; line-height:1.4; color:var(--text-dim); transition:color .2s, border-color .2s;}
.post .rail-toc a:hover{color:var(--text);}
.post .rail-toc a.is-active{border-left-color:var(--teal); color:var(--teal);}
/* The pinned contents + CTA always fit the screen: a list longer than that (the
   30-amendment circular) scrolls inside its box. --rail-cta-h is the CTA's measured
   height plus the gap above it, set by post.js; the TOC box's own heading and padding
   come off through the flex column. Only above the 980px stack point — on a phone the
   rail dissolves and its TOC is hidden. */
@media (min-width:981px){
  .post .rail-sticky{max-height:calc(100vh - var(--header-h) - 48px);}
  .post .rail-toc{display:flex; flex-direction:column; min-height:0;}
  .post .rail-cta{flex-shrink:0;}
  .post .rail-toc ol{max-height:calc(100vh - var(--header-h) - 48px - var(--rail-cta-h, 0px)); min-height:0; overflow-y:auto;
    scrollbar-width:thin; scrollbar-color:var(--line) transparent;}
  .post .rail-toc ol::-webkit-scrollbar{width:6px;}
  .post .rail-toc ol::-webkit-scrollbar-thumb{background:var(--line); border-radius:3px;}
  .post .rail-toc ol::-webkit-scrollbar-track{background:transparent;}
}

/* the rail CTA on every post and record: the closing .post-cta's surface, cut down
   to one line and a button */
.post .rail-cta{padding:18px 22px;
  background:linear-gradient(140deg, rgba(var(--accent-rgb),0.10), rgba(var(--accent-rgb),0) 60%), var(--card);}
.post .rail-cta-q{font-size:0.92rem; font-weight:700; line-height:1.4; letter-spacing:-0.005em; margin-bottom:12px;}
.post .rail-cta .btn{padding:11px 20px; font-size:0.86rem;}

/* one column under 980px: facts first — the new date without scrolling — then the
   small CTA, the article and the full CTA. The rail box itself dissolves (display:contents) so its
   boxes can be ordered among the article's siblings; nothing is sticky; no contents list. */
@media (max-width:980px){
  .post{display:flex; flex-direction:column; align-items:stretch;}
  .post .rail, .post .rail-sticky{display:contents; position:static;}
  .post > .article-head{order:0;}
  .post .rail-facts{order:1; margin-bottom:36px;}
  .post > .article{order:2;}
  /* the rail CTA follows the facts box (same order, later in the source): on a phone
     the closing CTA is thousands of pixels down */
  .post .rail-cta{order:1; margin-bottom:36px;}
  .post > .post-end{order:4;}
  .post .rail-toc{display:none !important;}
}

/* ---------- .post--wide: a post with no facts ----------
   No rail; the header block and the article share one centred column at the reading
   measure, left-aligned inside it. */
.post.post--wide{grid-template-columns:minmax(0,35rem); justify-content:center;}
.post--wide > .rail{display:none;}
.post--wide > .article, .post--wide > .post-end, .post--wide > .article-head{grid-column:1;}
.post--wide .article-head h1{font-size:clamp(1.9rem, 3.4vw, 2.5rem);}


.prose .post-sources{margin-top:2.4em; padding-top:22px; border-top:1px solid var(--line-soft); font-size:14px; line-height:1.6; color:var(--text-dim);}
.prose .post-sources h3{font-family:var(--mono); font-size:0.72rem; font-weight:500; letter-spacing:0.14em; text-transform:uppercase; color:var(--faint-aa); margin-bottom:10px;}
.prose .post-sources ul{margin:0;}
.prose .post-sources li{padding-left:0; margin-bottom:6px;}
.prose .post-sources li::before{content:none;}
.prose .post-sources a{color:var(--text-dim); text-decoration:underline; text-decoration-color:var(--line); text-underline-offset:3px; transition:color .2s, text-decoration-color .2s;}
.prose .post-sources a:hover{color:var(--teal); text-decoration-color:var(--teal);}
.prose .post-sources + .post-note{margin-top:1.6em;}

/* ---------- listing: the post's share card as its thumbnail ----------
   The whole card stays one link. The frame carries the radius and border and clips
   the image, so the hover scale stays inside it. width/height on the <img> give the
   browser the 1200:630 ratio before the file arrives, so nothing shifts. */
.post-card.has-thumb{display:grid; grid-template-columns:300px minmax(0,1fr); gap:28px; align-items:center;}
.post-card.has-thumb:not(:has(.post-thumb)){display:block;}   /* image removed by onerror */
.post-thumb{display:block; border-radius:10px; border:1px solid var(--line); overflow:hidden; background:var(--bg-soft);}
.post-thumb img{display:block; width:100%; height:auto; transition:transform .4s cubic-bezier(.2,.8,.2,1);}
.post-card:hover .post-thumb img{transform:scale(1.02);}
.post-card.has-thumb h2{font-size:clamp(1.25rem, 2vw, 1.55rem);}
@media (prefers-reduced-motion:reduce){ .post-thumb img{transition:none;} }
@media (max-width:640px){
  .post-card.has-thumb{grid-template-columns:1fr; gap:22px;}
}

/* ---------- a scanned document inside a post (e.g. the circular's record page) ----------
   Shown as it is: the scan is white paper in either theme, so no padding or backdrop —
   just the boxes' border and radius. The link opens the full-size file; width/height
   on the <img> keep its box reserved while it loads. */
.prose .post-scan{margin:1.4em 0 2em;}
.prose > .rail-box{margin-bottom:1.4em;}   /* a facts box inside the text column (record pages) */
.prose .post-scan a{display:block; border-radius:16px;}
.prose .post-scan a:focus-visible{outline:2px solid var(--teal); outline-offset:3px;}
.prose .post-scan img{display:block; width:100%; max-width:100%; height:auto; border:1px solid var(--line); border-radius:16px;}
.prose .post-scan figcaption{margin-top:10px; font-size:14px; line-height:1.55; color:var(--text-dim);}

/* ---------- circular record pages (/insights/circulars/<slug>/) ----------
   scoped under .post: the amendment jump-list, the per-heading statute refs,
   and the rate tables lifted from a circular */
.post .toc{margin:0; padding-left:0; list-style:none; counter-reset:toc;}
.post .toc li{position:relative; padding-left:34px; margin-bottom:0.45em; counter-increment:toc; font-size:0.92rem;}
.post .toc li::before{content:counter(toc); position:absolute; left:0; top:0.1em; width:22px; height:22px; border-radius:50%; background:var(--tint); border:1px solid var(--line); color:var(--text-dim); font:600 11px/22px var(--mono); text-align:center;}
.post .toc a{color:var(--text-dim); text-decoration:none;}
.post .toc a:hover{color:var(--teal);}
.post .toc-title{margin-bottom:0.8em;}
.post .prose h2 .secs{display:block; font-size:0.72em; font-weight:600; color:var(--text-faint); letter-spacing:0; margin-top:2px;}
.post .facts-table{overflow-x:auto; margin:0 0 1.25em;}
.post .facts-table table{width:100%; border-collapse:collapse; font-size:0.88rem;}
.post .facts-table th{text-align:left; font-size:11.5px; letter-spacing:0.06em; text-transform:uppercase; color:var(--faint-aa); padding:8px 12px; border-bottom:1px solid var(--line);}
.post .facts-table td{padding:8px 12px; border-bottom:1px solid var(--line-soft); color:var(--text-dim);}

/* links inside running prose and the facts rows: teal with a quiet underline —
   the global a{color:inherit} left body links indistinguishable from text.
   Structures with their own link look (.post-sources, .toc) outrank this. */
.prose p a, .prose li a, .facts dd a{color:var(--teal); text-decoration:underline; text-decoration-color:rgba(var(--accent-rgb),0.4); text-underline-offset:3px;}
.prose p a:hover, .prose li a:hover, .facts dd a:hover{text-decoration-color:var(--teal);}

/* a service card's one-line pointer into a circular record (homepage deep links).
   It lives INSIDE .svc-list: the subgrid card spans exactly four rows, so a fifth
   direct child would land outside them and overlap the list. */
.svc-card .svc-list li.svc-read{padding-left:0; margin-top:12px; padding-top:12px; border-top:1px solid var(--line-soft);}
.svc-card .svc-list li.svc-read::before{content:none;}
.svc-card .svc-read a{color:var(--teal);}
.svc-card .svc-read a:hover{text-decoration:underline;}
.svc-card.featured .svc-list li.svc-read{border-top-color:rgba(var(--accent-rgb),0.22);}
.svc-card.featured .svc-read a{color:var(--on-feat-head);}

/* the "Start here" marker a listing card can carry (set by <meta name="listing-flag">) */
.post-date .post-flag{color:var(--teal); font-weight:600;}
