/* ═════════════════════════════════════════════════════════════
   SEO LOCALE — INTERIOR DESIGN SYSTEM
   Loaded on every page EXCEPT the front page, after the
   per-template stylesheet and after global.css.

   Why this file exists
   ────────────────────
   The ~40 interior templates were each extracted verbatim from a
   standalone mockup, so every one ships its own copy of the old
   visual language: heavy Urbanist headings, glow shadows, pill
   chips, gradient text. Editing 40 files by hand would guarantee
   drift. Instead this layer restyles the component vocabulary
   those templates already share — the classes that recur across
   dozens of pages:

     sections   .hero .metrics-section .pain .services .cases
                .seo-content .platforms .video-block .faq .cta
     components .svc-card .pain-card .metric-box .case-card
                .faq-item .eyebrow .btn

   Anything defined here therefore reaches every interior page at
   once, and the homepage keeps its own front-page.css.

   Cascade note: per-page CSS is enqueued BEFORE global.css, and
   this file after it, so plain class selectors here already win.
   !important appears only where a per-page rule uses it first.
   ═════════════════════════════════════════════════════════════ */

/* ─────────────────────────────────────────────────────────────
   1 · DISPLAY TYPE
   Section headings take the Archivo Black display face. Sizes
   are deliberately a step below the homepage's: interior
   headings run longer, and Archivo Black sets much wider than
   Urbanist at the same nominal size.
   ───────────────────────────────────────────────────────────── */
.hero h1,
.hero .hero-h1,
main h2,
.section-h,
.cta h2,
.faq h2{
  font-family:var(--disp);
  font-weight:400;
  text-transform:uppercase;
  letter-spacing:-0.4px;
  line-height:1.06;
}
.hero h1,
.hero .hero-h1{font-size:clamp(30px,3.6vw,50px);}
main h2,
.section-h,
.cta h2,
.faq h2{font-size:clamp(25px,2.7vw,38px);}

/* A TWO-COLUMN HERO GETS A SMALLER HEADLINE
 *
 * The rule further down sets hero headlines to clamp(33px,4.4vw,62px),
 * which is right for a hero whose headline owns the full width. Thirty
 * interior pages do not: they put the headline in one column of a grid
 * and a demo panel — a SERP mock, an ads dashboard, a phone — in the
 * other, so the headline gets 410–560px and was still being set at
 * 56px. Facebook ran to six lines, TikTok to eight and 576px tall,
 * which pushed the supporting copy and both buttons below the fold on
 * a laptop.
 *
 * Three classes deep so it beats `.hero .hero-h1` at (0,2,0). The
 * attribute selector catches .hero-grid and .ind-hero-grid together;
 * the bare h1 is there because two templates never got the class. */
.hero [class*="hero-grid"] h1,
.hero [class*="hero-grid"] .hero-h1,
.ind-hero [class*="hero-grid"] h1,
.ind-hero [class*="hero-grid"] .ind-hero-h1{
  font-size:clamp(30px,3.1vw,44px);
  letter-spacing:-1.1px;
  line-height:1.06;
}

/* ARTICLE TITLES ARE NOT SECTION HEADINGS
 *
 * A post card's title is an h2, so `main h2` above handed it the
 * section-heading treatment: Archivo Black, uppercase, display face.
 * At the 19px a card actually has room for, that reads as shouting in
 * a small voice — and article titles are sentences, six to nine words
 * long, which uppercase makes markedly harder to scan than a section
 * heading of two or three.
 *
 * The color was the louder half of the problem. The title link took
 * the teal used for every link and every CTA on the site, so a grid of
 * six cards was six teal headlines above six teal "Read Article"
 * links, with nothing to rank them. Ink for the headline puts the
 * accent back where it means something: the one thing you click.
 *
 * Real specificity rather than :where(), because it has to beat the
 * `main h2` rule above. */
.post-card .post-title{
  font-family:var(--font);
  font-weight:800;
  text-transform:none;
  font-size:20.5px;
  line-height:1.3;
  letter-spacing:-0.35px;
}
.post-card .post-title a{
  text-decoration:none;
  transition:color 0.2s ease;
}
/* The headline's color is set further down, beside the light-band
   link rule it has to outrank — see "A HEADLINE IS NOT A LINK". */

/* h3 stays in the body face — at card size the display face is
   too heavy and eats the line. */
main h3{
  font-family:var(--font);
  font-weight:800;
  letter-spacing:-0.3px;
}

/* Leftover gradient-clipped heading accents.
 *
 * The site-wide accent rule in global.css is element-only
 * (0,0,3), so a handful of per-page selectors written as
 * `.reels-head h2 em` (0,1,2) still won the background and
 * background-clip properties and kept rendering gradient text —
 * instagram.css and team.css between them carry nine. Rather
 * than edit those files (and miss the next one), this reasserts
 * the accent with !important on just the properties involved.
 *
 * Deliberately NOT applied to gradient text inside the client
 * website mockups (.after-feature-n, .ig-header-icon and
 * friends): those are artwork standing in for a customer's
 * brand, not our headings. */
main h1 em, main h2 em, main h3 em,
.team-hero h1 span{
  font-family:'Instrument Serif','Instrument Serif Fallback',serif !important;
  font-style:italic !important;
  font-weight:400 !important;
  text-transform:none !important;
  background:none !important;
  -webkit-background-clip:initial !important;
  background-clip:initial !important;
  color:var(--teal) !important;
}
.seo-content h2 em,
.seo-content h3 em,
.faq h2 em{color:var(--teal-ink) !important;}

/* Long-form prose inside content sections keeps a comfortable
   measure and a slightly larger body size than the mockups used. */
.seo-content p,
.seo-content li{font-size:17px;line-height:1.8;}

/* ─────────────────────────────────────────────────────────────
   2 · SECTION RHYTHM & SEAMS
   Interiors get the same chapter logic as the homepage: a
   hairline plus a soft teal wash where a new band starts, and a
   hexagon sitting on the seam. Without this the dark sections
   run together exactly as they did on the old homepage.
   ───────────────────────────────────────────────────────────── */
main > section,
main > div > section{position:relative;}

.metrics-section,
.pain,
.services,
.svc-section,
.cases,
.case-studies,
.platforms,
.video-block,
.seo-content,
.included,
.engines,
.faq,
.cta{
  position:relative;
  border-top:1px solid rgba(255,255,255,0.1);
}
.pain::after,
.services::after,
.cases::after,
.seo-content::after,
.faq::after,
.cta::after{
  content:"";
  position:absolute;
  top:-6px;left:50%;
  transform:translateX(-50%);
  width:11px;height:12px;
  background:var(--teal);
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
  opacity:0.5;
  z-index:2;
}
.pain::before,
.services::before,
.cases::before,
.faq::before{
  content:"";
  position:absolute;
  left:0;right:0;top:0;
  height:130px;
  background:linear-gradient(180deg,rgba(22,192,183,0.05) 0%,transparent 100%);
  pointer-events:none;
}
/* Alternating depth so neighboring dark bands separate. */
.services,
.platforms{background:rgba(12,26,38,0.45);}
/* …except when the two land next to each other, as they do on the
   podcast page: both lifted to the same depth, they merge into one
   long band and the alternation stops working. The second one drops
   back to the page tone so the pair still steps. */
.services + .platforms,
.platforms + .services{background:transparent;}

/* ─────────────────────────────────────────────────────────────
   3 · WARM BANDS
   Long-form content sections flip to the warm paper tone, the
   same move that breaks up the homepage. .seo-content is the
   safest candidate site-wide: it's prose and headings, so there
   are no bespoke card treatments to re-ink.
   ───────────────────────────────────────────────────────────── */
.seo-content{
  background:var(--sand);
  border-top:1px solid rgba(30,52,72,0.14);
  color:var(--ink);
}
.seo-content::before{content:none;}
.seo-content::after{background:var(--teal-ink);opacity:0.6;}
.seo-content h2,
.seo-content h3,
.seo-content h4,
.seo-content strong{color:var(--ink);}
.seo-content p,
.seo-content li,
.seo-content td{color:var(--ink-soft);}
.seo-content .eyebrow,
.seo-content .eyebrow-t{color:var(--teal-ink);}
.seo-content h2 em,
.seo-content h3 em{color:var(--teal-ink) !important;}
.seo-content a:not(.btn){color:var(--teal-ink);}
.seo-content .btn-ghost{
  color:var(--ink);
  border-color:rgba(30,52,72,0.3);
}
.seo-content .btn-ghost:hover{
  color:var(--teal-ink);
  border-color:var(--teal-ink);
}
/* Any card-ish surface inside a warm band flips to paper. On the
   cream band that means the warm off-white; on the sand band, which
   is now plain white, a card the same color is no card at all, so
   the roles invert and the card takes the cool tint the band itself
   used to be. */
.faq .card,
.faq .svc-card,
.faq .pain-card{
  background:var(--cream-card);
  border-color:rgba(30,52,72,0.12);
  color:var(--ink);
}
.seo-content .card,
.seo-content .svc-card,
.seo-content .pain-card{
  background:var(--sand-card);
  border-color:rgba(30,52,72,0.1);
  color:var(--ink);
}

/* The FAQ band — present on 31 templates — is the second warm
   stop, so interiors land on the same dark → warm → dark cadence
   as the homepage instead of running dark end to end. Text-only,
   so nothing bespoke needs re-inking. */
.faq{
  background:var(--cream);
  border-top:1px solid rgba(30,52,72,0.14);
  color:var(--ink);
}
.faq::before{content:none;}
.faq::after{background:var(--teal-ink);opacity:0.6;}
.faq h2,
.faq h3{color:var(--ink);}
.faq h2 em{color:var(--teal-ink) !important;}
.faq .eyebrow,
.faq .eyebrow-t,
/* The per-page eyebrow variants restyled in 9b keep whatever color
 * their own stylesheet set — brand teal, which is 2.11:1 on this
 * band. --teal-ink is the darkened accent that exists for exactly
 * this, and it has to be listed here because these are separate
 * class names, not .eyebrow. */
.faq .pain-eyebrow,
.faq .faq-eyebrow,
.faq .cs-eyebrow,
.faq .video-eyebrow,
.faq .included-eyebrow,
.faq .svc-eyebrow,
.faq .metrics-eyebrow,
.seo-content .pain-eyebrow,
.seo-content .faq-eyebrow,
.seo-content .cs-eyebrow,
.seo-content .video-eyebrow,
.seo-content .included-eyebrow,
.seo-content .svc-eyebrow,
.seo-content .metrics-eyebrow,
.statement-cream .eyebrow,
.statement-sand .eyebrow{color:var(--teal-ink);}
.faq > .container > p,
.faq .section-sub,
.faq p{color:var(--ink-soft);}
.faq-item{border-bottom-color:rgba(30,52,72,0.14) !important;}
.faq .faq-q{color:var(--ink);}
.faq .faq-a{color:var(--ink-soft);}
.faq .faq-plus{color:var(--teal-ink);}
.faq .faq-item:hover .faq-q{color:var(--teal-ink);}
.faq a:not(.btn){color:var(--teal-ink);}
.faq .btn-ghost{
  color:var(--ink);
  border-color:rgba(30,52,72,0.3);
}
.faq .btn-ghost:hover{
  color:var(--teal-ink);
  border-color:var(--teal-ink);
}

/* RE-INKING PROSE THAT PER-PAGE CSS OWNS
 *
 * The per-page stylesheets set this copy with selectors like
 * `.seo-inner ul li` (0,2,2) and `.ind-extra-inner .seo-expandable p`
 * (0,3,1), which outscore anything sane this layer can write — and
 * every one of them is a light-on-dark color, because that's what
 * these sections used to be. Left alone, the list items on Local SEO
 * rendered #DFEFFD on a near-white band: 1.09:1, invisible.
 *
 * !important is the only thing that reaches all 40 files at once.
 * The dark-island block below re-asserts itself the same way so it
 * still wins inside its own subtree. */
.seo-content :is(p,li,td,dd,figcaption),
.faq :is(p,li,td,dd,figcaption){color:var(--ink-soft) !important;}
.seo-content :is(h2,h3,h4,h5,dt,strong,b),
.faq :is(h2,h3,h4,h5,dt,strong,b){color:var(--ink) !important;}
.seo-content a:not(.btn),
.faq a:not(.btn){color:var(--teal-ink) !important;}

/* The "read more" toggle under the long-form copy is a <button>,
   so the link rule above misses it. Eight page stylesheets each
   ship their own copy of it in brand teal on a translucent teal
   tint — 2.11:1 once the band went light. */
.seo-content .seo-read-more{
  color:var(--teal-ink) !important;
  background:rgba(10,120,112,0.08) !important;
  border-color:rgba(10,120,112,0.3) !important;
  border-radius:var(--btn-radius) !important;
}
.seo-content .seo-read-more:hover{
  background:rgba(10,120,112,0.14) !important;
  border-color:rgba(10,120,112,0.5) !important;
}

/* DARK ISLANDS INSIDE WARM BANDS
 *
 * A few templates park a dark card inside a section this layer
 * turns warm — Local SEO's .faq-snap performance card is the
 * one that bit us: the band's ink color cascaded into it and
 * every value went dark-on-dark. Any dark surface inside a warm
 * band re-asserts light text for its own subtree.
 *
 * Add new dark-card classes to this selector list rather than
 * lightening the band, or the same bug comes back. */
.faq .faq-snap,
.seo-content .faq-snap{color:var(--text) !important;}
.faq .faq-snap :is(p,div,span,strong,b,li,td,dd,dt,h2,h3,h4,h5),
.seo-content .faq-snap :is(p,div,span,strong,b,li,td,dd,dt,h2,h3,h4,h5){color:inherit !important;}
.faq .faq-snap .faq-snap-label{color:var(--muted) !important;}
.faq .faq-snap .faq-snap-val{color:var(--text) !important;}
.faq .faq-snap .faq-snap-head span{color:var(--teal) !important;}
.faq .faq-snap a:not(.btn){color:var(--teal) !important;}
/* …except the card's own CTA, which is a solid teal button: the
   link rule above would paint its label teal-on-teal. */
.faq .faq-snap .faq-snap-cta a{
  color:var(--obsidian) !important;
  border-radius:var(--btn-radius);
}

/* ─────────────────────────────────────────────────────────────
   4 · SHARED CARD COMPONENTS
   Flatter surfaces, thinner borders, no ambient glow — the
   language the redesigned homepage established.
   ───────────────────────────────────────────────────────────── */
.svc-card,
.pain-card,
.case-card{
  border-radius:16px;
  box-shadow:none;
  transition:transform 0.25s ease,border-color 0.25s ease;
}
.svc-card:hover,
.pain-card:hover,
.case-card:hover{
  transform:translateY(-5px);
  border-color:rgba(22,192,183,0.45);
  box-shadow:0 18px 40px rgba(0,0,0,0.35);
}
/* Service card icons: hexagon tiles instead of rounded squares. */
.svc-card-icon{
  border-radius:0 !important;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}
/* Numbered pain cards pick up the display face for the numeral. */
.pain-card-num{
  font-family:var(--disp);
  font-weight:400;
  letter-spacing:-1px;
}
/* Service tags lose the pill-chip look. */
.svc-tag{
  border-radius:5px !important;
  font-size:11px;
  letter-spacing:0.04em;
}

/* Metric band: the divider rules already separate it, so drop
   the per-cell borders that made it look like a spreadsheet. */
.metrics-section{background:transparent;}

/* ─────────────────────────────────────────────────────────────
   5 · FAQ
   Present on 31 templates. Matches the homepage treatment: rules
   rather than boxes, and a plus that rotates into a minus.
   ───────────────────────────────────────────────────────────── */
.faq-item{
  background:none !important;
  border:none !important;
  border-bottom:1px solid rgba(255,255,255,0.1) !important;
  border-radius:0 !important;
  box-shadow:none !important;
}
.faq-q{
  font-size:18px;
  font-weight:700;
  letter-spacing:-0.2px;
}
/* Hexagon toggle is defined once in global.css; on the cream FAQ
   band it only needs the darker teal for contrast. */
.faq .faq-plus{background:rgba(11,138,130,0.12);}
.faq .faq-item.open .faq-plus{background:var(--teal-ink);color:#fff;}

/* ─────────────────────────────────────────────────────────────
   6 · HERO
   Interiors share the .hero-has-image pattern. Deepen the
   vignette so display type stays readable over any uploaded
   featured image.
   ───────────────────────────────────────────────────────────── */
/* Base hero, for templates that do not bring their own.
 *
 * .hero was never a global component — each of the ~40 older
 * interior stylesheets defines it, with its own padding, background
 * and overflow. Templates added since then reused the class without
 * that CSS behind them, so their heroes had zero padding (the
 * headline sat under the fixed nav) and no background of their own.
 *
 * :where() so this carries zero specificity: every page that already
 * styles .hero still wins outright, and only the templates with no
 * rule of their own pick these up. */
:where(.hero){
  position:relative;
  /* 140/100 to match the established breadcrumb heroes exactly
     (local-seo and friends) rather than introducing a second,
     slightly-roomier value alongside them. The fixed nav is 118px
     tall, so 140 leaves 22px of clearance under it. */
  padding:140px 0 100px;
  overflow:hidden;
  background:var(--obsidian);
}

/* ...except where the hero sits inside a .hero-wrap.
 *
 * Eight templates (case studies, blog, awards, contact, services,
 * testimonials, locale lounge, category archives) put the photo and
 * its scrim on a wrapper and leave .hero itself unstyled. The base
 * background above therefore painted flat obsidian straight over that
 * photo, and the only part of the image still visible was the thin
 * strip of wrapper beside the breadcrumb — which read as an image
 * that had been cropped to a sliver rather than one being covered.
 *
 * Specificity, not order, is what settles this: :where() contributes
 * nothing, so `.hero` here scores 0,1,0 against the base rule's
 * 0,0,0 and wins wherever it appears in the file. */
:where(.hero-wrap) .hero{background:transparent;}

/* The scrim is absolutely positioned with z-index:0, which puts it
 * above static content in the same stacking context — so on a hero
 * whose copy is not itself positioned, the gradient painted straight
 * over the headline and washed it out to near-invisible. The older
 * templates each solved this on their own inner grid; this does it
 * once, for the wrappers the shared markup uses. */
.hero > .container,
.hero-inner,
.hero-copy{position:relative;z-index:1;}

.hero-has-image::before{
  background:
    linear-gradient(to top,var(--obsidian) 0%,rgba(5,11,18,0.62) 55%,rgba(5,11,18,0.5) 100%),
    linear-gradient(100deg,rgba(5,11,18,0.85) 0%,rgba(5,11,18,0.5) 55%,rgba(5,11,18,0.28) 100%) !important;
}

/* ─────────────────────────────────────────────────────────────
   7 · SHARED COMPONENT BASE
   
   The interior "shared vocabulary" was never actually shared. .hero,
   .hero-p, .seo-inner, the FAQ collapse and the post card are each
   defined in the ~40 older per-page stylesheets, separately, and the
   templates added since then used those class names with nothing
   behind them.

   The visible symptoms were all the same bug: FAQ accordions that
   would not collapse (the max-height rule lives per-page, so every
   answer rendered permanently open and clicking did nothing), body
   copy running the full 1360px because .seo-inner had no measure,
   and blog cards with no card.

   Every rule here is wrapped in :where() so it carries zero
   specificity. Any page with its own version still wins outright;
   only templates with no rule of their own pick these up.
   ───────────────────────────────────────────────────────────── */

/* Hero headings had no margin of their own on interiors — that came
 * from each page's stylesheet too. With the boxed accent the miss was
 * visible: the box's border and rotation carry it below the line box,
 * so the paragraph started 5px above the bottom of the box and
 * overlapped it. */
:where(.hero h1,.hero .hero-h1){margin:14px 0 30px;}
:where(.hero .eyebrow){display:inline-flex;}

:where(.hero-p){
  font-size:18px;
  line-height:1.75;
  color:var(--muted);
  max-width:60ch;
  margin-bottom:28px;
}

/* Long-form copy needs a measure. Without one it set to the full
   container width, which is roughly 150 characters a line. */
/* Section padding. Like .hero, .seo-content's padding lives in each
   page's own stylesheet, so templates without one had zero — which
   is why the read-more button sat flush against the band edge with
   nothing under it. */
:where(.seo-content){padding:clamp(60px,6.5vw,92px) 0;}
/* Not :where() — the auto margins have to outrank global.css's
   `*{margin:0}` reset, and a zero-specificity rule loses to it on
   order, so the measure applied but the column sat flush left on
   every template without a .seo-inner rule of its own. The twelve
   pages that do declare one all declare exactly these two values,
   so raising the specificity here changes nothing for them. */
.seo-inner{max-width:860px;margin:0 auto;}

/* Subheads inside long-form copy were the same size as the body text
   and separated only by weight, which is why the section read as the
   font changing rather than as a new sub-section starting. Sized up
   and given room above it, so the hierarchy is visible. Normal
   specificity on purpose: this is worth having consistently rather
   than only on the templates that happen to lack a rule of their
   own. */
.seo-inner h3,
.seo-content .seo-inner h3{
  font-size:clamp(21px,2vw,27px);
  line-height:1.3;
  margin:38px 0 12px;
}
.seo-inner h3:first-child{margin-top:0;}

/* Read-more collapse, applied by global.js to any long-form block
   that runs past a screenful. The gradient is the affordance — a
   hard cut reads as a broken layout, a fade reads as "there is more
   here". */
/* The fade is a mask on the content, not a gradient overlay in a
   band color. The overlay version was hardcoded to fade to
   --obsidian, which is right on the dark service pages and very
   wrong on .seo-content, whose background is --sand — white — so on
   a team profile the copy dissolved into a black bar.
   A mask fades the text itself and is correct on any background. */
.seo-clamp{
  max-height:var(--seo-clamp,560px);
  overflow:hidden;
  -webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 130px),transparent 100%);
          mask-image:linear-gradient(to bottom,#000 calc(100% - 130px),transparent 100%);
}
.seo-clamp.expanded{
  max-height:none;
  -webkit-mask-image:none;
          mask-image:none;
}
.seo-read-more{
  display:inline-flex;align-items:center;gap:10px;
  margin:26px auto 0;
  padding:14px 28px;
  background:rgba(22,192,183,0.08);
  border:1px solid rgba(22,192,183,0.25);
  border-radius:var(--btn-radius);
  cursor:pointer;
  font-family:var(--font);font-size:15px;font-weight:800;
  color:var(--teal);
  transition:background 0.25s ease,border-color 0.25s ease;
}
.seo-read-more:hover{background:rgba(22,192,183,0.14);border-color:rgba(22,192,183,0.45);}
.seo-read-more i{font-size:12px;transition:transform 0.3s ease;}
.seo-read-more.active i{transform:rotate(180deg);}
/* The button is inserted after .seo-inner, which is centerd, so it
   needs the same treatment to sit under the column rather than at
   the container's left edge. */
.seo-content .seo-read-more{
  display:flex;
  width:max-content;
  /* max-content alone ran past a 390px viewport once the label and
     the 28px side padding were added up. */
  max-width:100%;
  justify-content:center;
  text-align:center;
}
@media (max-width:480px){
  .seo-read-more{padding:13px 18px;font-size:14px;}
}

/* ── FAQ ACCORDION ──
   The collapse, not just the colors. .faq-a with no max-height is
   an open answer, and .faq-item.open then has nothing to change —
   which is exactly how "the accordions do not work" looks. */
:where(.faq-items){display:flex;flex-direction:column;max-width:860px;margin:0 auto;}
/* The question row: label left, hexagon toggle hard right. Without
   this the toggle is a block element and drops onto its own line
   under the question, which is what "the accordion still looks bad"
   was — the collapse worked, the row did not. */
:where(.faq-q){
  display:flex;
  justify-content:space-between;
  align-items:center;
  gap:20px;
  font-size:17px;
  font-weight:700;
  cursor:pointer;
}
:where(.faq-item){
  border-bottom:1px solid rgba(30,52,72,0.14);
  padding:20px 0;
}
:where(.faq-a){
  max-height:0;
  overflow:hidden;
  font-size:15px;
  line-height:1.7;
  transition:max-height 0.4s ease,padding 0.3s ease;
}
/* Generous ceiling on purpose: the older pages use 300px and a long
   answer silently clips at it. */
:where(.faq-item.open .faq-a){max-height:900px;padding-top:16px;}

/* ── POST CARD ──
   Used by the blog-resources rail and the spotlight listing. */
:where(.blog-grid){
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:22px;
}
:where(.post-card){
  display:flex;
  flex-direction:column;
  background:var(--surface);
  border:1px solid rgba(255,255,255,0.09);
  border-radius:16px;
  overflow:hidden;
  text-decoration:none;
  transition:transform 0.25s ease,border-color 0.25s ease;
}
:where(.post-card:hover){transform:translateY(-4px);border-color:rgba(22,192,183,0.4);}
:where(.post-card-img){aspect-ratio:16/9;overflow:hidden;background:rgba(22,192,183,0.08);}
:where(.post-card-img img){width:100%;height:100%;object-fit:cover;display:block;}
:where(.post-card-body){padding:22px 22px 24px;display:flex;flex-direction:column;gap:9px;flex:1;}
/* The mono/uppercase/wide-tracking treatment belongs to the category
   chip, which is a label. It was set on .post-meta, so it inherited to
   the date and the read time as well and turned an ordinary byline into
   "MARCH 4, 2026   16 MIN" — machine output rather than a line under a
   headline. The row keeps the layout and the chip keeps its badge; the
   two facts beside it read as text. */
:where(.post-meta){
  font-size:12.5px;
  color:var(--muted);
}
:where(.post-meta .post-cat){
  font-family:var(--mono2);
  font-size:10px;
  letter-spacing:0.14em;
  text-transform:uppercase;
  color:var(--teal);
}
:where(.post-title){font-size:17px;line-height:1.35;margin:0;color:var(--text);}
:where(.post-excerpt){font-size:14px;line-height:1.65;color:var(--muted);margin:0;}
:where(.post-date){font-size:12.5px;color:var(--muted);margin-top:auto;}

/* ── SPOTLIGHT LISTING ── */
:where(.spotlight){padding:clamp(64px,7vw,104px) 0;border-top:1px solid rgba(255,255,255,0.1);}
:where(.spot-grid){margin-top:38px;}
:where(.spot-more){margin-top:34px;}

/* ── TEAM PROFILE HERO ── */
:where(.tm-hero){padding:140px 0 90px;}
:where(.tm-hero-copy){min-width:0;}

@media (max-width:1000px){
  :where(.blog-grid){grid-template-columns:repeat(2,1fr);}
}
@media (max-width:680px){
  :where(.blog-grid){grid-template-columns:1fr;}
}

/* ─────────────────────────────────────────────────────────────
   8 · BIG-TYPE MOMENTS
   Interior pages are long and word-dense by necessity — we sell
   SEO, so the service breakdowns, methodology and local copy all
   have to be there. The cost is that someone scrolling fast never
   hits a line that lands. Two moments per page fix that without
   touching a single template:

     · the opening headline of .seo-content, which is where the
       long-form copy starts and where a reader most needs to be
       told what the section is about; and
     · the closing .cta headline, present on 22 templates.

   Both are existing markup — this just gives them display scale
   and the air to use it. Pages that want a third moment can drop
   in a <section class="statement"> (see global.css); nothing here
   depends on that.
   ───────────────────────────────────────────────────────────── */

/* Long-form opener. :first-of-type so only the section's own lede
   scales — the h2s further down stay at body-section size and keep
   the document outline readable. */
.seo-content .seo-inner > h2:first-of-type,
.seo-content > .container > h2:first-of-type{
  font-size:clamp(30px,4.1vw,56px);
  line-height:1.05;
  max-width:19ch;
  margin-bottom:26px;
}

/* Every h2 after the opener starts a new section of the same
   document, and the rule above deliberately does not reach them —
   they keep body-section size so the outline stays readable. What
   they also keep is the global reset's margin of nothing at all, so
   a second section's heading sits 16px under the previous
   paragraph and touches its own. Measured on
   /ai-optimization-in-philadelphia/ and /beauty-salon-seo/, the two
   pages in the theme whose long-form is more than one h2 deep:
   margin-top 0, margin-bottom 0, 16px above.

   The sibling combinator rather than :not(:first-of-type) because
   it only fires where there IS an earlier h2 in the same block — a
   page with one h2 per wrapper is untouched, which the sweep
   confirmed. */
.seo-content .seo-inner > h2 ~ h2,
.seo-content > .container > h2 ~ h2{
  margin-top:46px;
  margin-bottom:14px;
}
/* The lede is the paragraph that opens the section — the one
   directly after its h2 — not merely the first <p> in the block.
   :first-of-type matched whichever paragraph happened to come first
   even when a subheading came before it, so on a page that opens
   h2 → h3 → p (a team bio does) a paragraph in the middle of the
   copy got lede treatment and every paragraph after it looked
   shrunken by comparison. That is what "the font is messed up"
   looked like. h2 + p matches only a real opener, and matches
   nothing when there is not one. */
.seo-content .seo-inner > h2 + p,
.seo-content > .container > h2 + p{
  font-size:clamp(18px,1.55vw,22px);
  line-height:1.62;
  /* !important to re-assert over the blanket re-inking rule above,
     which carries it to reach the ~40 per-page stylesheets at once.
     Without this the lede kept body copy's softer ink while taking
     the larger size, so it read as the same text set bigger for no
     reason rather than as an opening paragraph — the "fonts are
     different in this template" complaint. Specificity alone does not
     win against !important. */
  color:var(--ink) !important;
}
/* Only the bare-container variant sets its own measure. .seo-inner
   already caps the column, so capping again in ch at the lede's
   larger size made the opening paragraph narrower than the body copy
   beneath it — the column edge stepped in for one paragraph and back
   out for the rest, which is most of why this section read as three
   different treatments rather than one. */
.seo-content > .container > h2 + p{max-width:62ch;}

/* …except in a policy document, where every paragraph is body text.
 *
 * The lede treatment assumes a marketing band: one heading, one
 * opening paragraph that earns emphasis, then supporting copy. A
 * privacy or accessibility statement is the opposite shape — eight or
 * nine short sections, each a heading and one or two paragraphs — so
 * the rule fired on most of them and the page alternated between two
 * sizes and two inks with nothing meaningful separating them.
 *
 * Equal specificity to the lede rule above (0,2,2) and placed after
 * it, so this wins on order. The !important is there to answer the
 * lede's own !important, which exists to answer the blanket re-inking
 * rule further up. */
.seo-content .lg-body > h2 + p{
  font-size:17px;
  line-height:1.8;
  color:var(--ink-soft) !important;
}

/* …and not in any other document-shaped block either.
 *
 * .lg-body fixed this for policy pages by naming one template. The
 * shape is what matters, not the page: a long-form block with several
 * h2 sections, each carrying two or three paragraphs, gets the lede
 * treatment on EVERY section, so the copy alternates 22px / 17px all
 * the way down with nothing meaningful separating the two. Reported
 * on the AI Optimization page as "bigger and smaller in the paragraph
 * fonts", which is exactly what it is.
 *
 * .seo-doc is the opt-out for that shape. Put it on .seo-inner in a
 * template whose long-form is a document rather than a marketing band
 * with a single opener. The heading scale above is untouched: the
 * first h2 still opens larger, which is what carries the section now
 * that its paragraph does not.
 *
 * Equal specificity to the lede rule (0,2,2) and placed after it, so
 * it wins on order — and the !important answers the lede's own, which
 * answers the blanket re-inking rule further up. */
.seo-content .seo-doc > h2 + p{
  font-size:17px;
  line-height:1.8;
  color:var(--ink-soft) !important;
}

/* Closing statement. The CTA is the only centerd block on the page,
   so it can carry the widest type without fighting anything — and
   it gets the team photo behind it, the same as the homepage, so
   every page ends on people rather than on another dark rectangle.
   The overlay is heavy: this block is nothing but type, and the
   photo is a bright wall. */
.cta{
  padding:clamp(88px,9.5vw,148px) 0;
  background-image:
    linear-gradient(180deg,rgba(5,11,18,0.86) 0%,rgba(5,11,18,0.74) 52%,rgba(5,11,18,0.88) 100%),
    var(--team-photo);
  background-size:cover;
  background-position:center 42%;
  background-repeat:no-repeat;
}
/* The heading and paragraph both center themselves with margin:0
   auto, but the button row never did, so it sat hard left under
   centerd copy. Center the block once instead of per child. */
.cta .cta-inner{max-width:1000px;margin:0 auto;text-align:center;}
.cta h2{
  font-size:clamp(32px,4.6vw,64px);
  line-height:1.04;
  max-width:19ch;
  margin:0 auto 22px;
}
.cta .cta-inner > p{
  /* Lightened from the muted slate so the overlay above can stay
     open enough for the photo to read. See front-page.css. */
  color:rgba(255,255,255,0.86);
  max-width:54ch;
  margin:0 auto;
  font-size:clamp(16px,1.15vw,18.5px);
  line-height:1.7;
}
.cta .cta-btns{
  margin-top:34px;
  display:flex;
  justify-content:center;
  flex-wrap:wrap;
  gap:14px;
}

/* Heroes and section headings both came in a size below where they
   should sit for a page this long. */
.hero h1,
.hero .hero-h1{font-size:clamp(33px,4.4vw,62px);}
main h2,
.section-h,
.faq h2{font-size:clamp(27px,3.2vw,46px);}

/* ─────────────────────────────────────────────────────────────
   9 · STOCK-TEMPLATE CLEANUP
   The interior templates were each extracted from a standalone
   mockup, and they all reach for the same handful of effects that
   read as generic AI/stock output rather than as our design:

     · frosted translucent panels (backdrop-filter)
     · pill chips and 50%-round buttons for everything
     · ambient colored glow shadows (0 0 Npx teal)
     · pulsing keyframe rings

   This layer neutralises those on OUR chrome. It deliberately does
   NOT touch the client-website and platform mockups — .after-*,
   .legacy-mockup-*, .ig-*, .serp-*, .map-*, .reel-*, .pdp-*, .yt-*,
   .tk-*, .live-feed and friends. A frosted nav bar or a pill badge
   inside a picture of somebody else's website is that website's
   design, and flattening it would make the artwork read as ours.
   ───────────────────────────────────────────────────────────── */

/* ── 9a · Eyebrows ──
   Six templates ship their own eyebrow as a bordered teal pill.
   The site's eyebrow is Space Mono with a hexagon marker (global
   .eyebrow) — these are the same element, so they get the same
   treatment rather than a second visual language for one label. */
.pain-eyebrow,
.faq-eyebrow,
.cs-eyebrow,
.video-eyebrow,
.included-eyebrow,
.svc-eyebrow,
.metrics-eyebrow{
  display:inline-flex;
  align-items:center;
  gap:10px;
  font-family:var(--mono2);
  font-size:12px;
  font-weight:700;
  letter-spacing:0.18em;
  text-transform:uppercase;
  background:none;
  border:none;
  padding:0;
  border-radius:0;
  margin-bottom:14px;
}
.pain-eyebrow::before,
.faq-eyebrow::before,
.cs-eyebrow::before,
.video-eyebrow::before,
.included-eyebrow::before,
.svc-eyebrow::before,
.metrics-eyebrow::before{
  content:"";
  width:9px;height:10px;
  flex-shrink:0;
  background:currentColor;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}
.pain-eyebrow > i,
.faq-eyebrow > i,
.cs-eyebrow > i,
.video-eyebrow > i,
.included-eyebrow > i,
.svc-eyebrow > i,
.metrics-eyebrow > i{display:none;}

/* ── 9b · Hero proof ticket ──
   On 29 templates. Was a translucent pill, in several cases tinted
   an off-brand purple or green borrowed from whichever platform the
   page is about; then a caption with a teal rule down its left edge,
   which read as the default blockquote of every page builder.

   Now a ticket in the site's own paper-and-ink vocabulary: a thin
   teal outline, the flat offset shadow the buttons and the boxed
   keyword carry, a hexagon tile for the icon (the brand mark as
   punctuation, as in the eyebrows), and a one-degree tilt so it
   reads as set down on the page rather than laid out by a grid. */
.hero-proof,
.ind-hero-proof,
.loc-hero-proof{
  position:relative;
  display:inline-flex;
  align-items:center;
  gap:14px;
  width:fit-content;
  max-width:100%;
  margin-bottom:30px;
  padding:9px 20px 9px 10px;
  background:rgba(5,11,18,0.55);
  backdrop-filter:none;
  -webkit-backdrop-filter:none;
  border:1.5px solid var(--teal);
  border-radius:10px;
  box-shadow:5px 5px 0 rgba(22,192,183,0.22);
  transform:rotate(-1deg);
  transform-origin:left center;
}
.hero-proof > i,
.ind-hero-proof > i,
.loc-hero-proof > i{
  width:34px;height:36px;
  flex-shrink:0;
  display:flex;
  align-items:center;
  justify-content:center;
  background:var(--teal);
  color:var(--obsidian);
  font-size:14px;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}
.hero-proof > span,
.ind-hero-proof > span,
.loc-hero-proof > span{
  font-size:14.5px;
  font-weight:600;
  line-height:1.4;
  color:rgba(248,250,252,0.9);
}
.hero-proof strong,
.ind-hero-proof strong,
.loc-hero-proof strong{color:var(--teal);font-weight:800;}

/* ── 9b2 · Two template tells, removed site-wide ──
 *
 * Both of these came from the original page mockups and were copied
 * into every stylesheet that inherited them, so they now read as the
 * house style when they are really just the same gimmick 29 times.
 *
 * 1. The struck-through accent word. A red bar rotated across the
 *    one word in the headline that is set in the display serif — it
 *    obscures the word it is decorating, and "cross out the bad
 *    thing" is the most recognizable stock-template move there is.
 *    On 29 pages.
 *
 * 2. The red bar down the left edge of every problem card. The card
 *    already has a red-tinted surface, a red border and a red
 *    number; the fourth red element is the one that tips it from
 *    "this is a problem list" into "this is a template". On 18.
 *    The number keeps the accent, the surface goes neutral like
 *    every other card on the site.
 */
.pain-left h2 em::after,
.pain h2 em::after,
h2 em::after{content:none !important;}

.pain-card,
.pain-row{
  background:var(--surface) !important;
  border-color:rgba(255,255,255,0.09) !important;
}
.pain-card::before,
.pain-row::before{content:none !important;}
.pain-card:hover,
.pain-row:hover{
  border-color:rgba(22,192,183,0.4) !important;
  transform:translateY(-3px);
}

/* ── 9c · De-glass our own panels ──
   Every one of these is a solid surface sitting on a solid
   background — the blur never had anything to blur. */
.faq-snap,
.cs-card,
.cs-tag,
.cs-mini,
.video-tmembr,
.video-badge,
.video-play-btn,
.faqhub-filters,
.ind-toggle-btn,
.reel-side-btn,
.lex-card,
.mt-card-tag,
.feed-stat,
.seo-float,
.pc-dept-badge,
.svc-snap-play,
.bento-tag,
.ps-meter,
.testi-play,
.anchorbar,
.dossier-overlay{
  backdrop-filter:none !important;
  -webkit-backdrop-filter:none !important;
}

/* ── 9d · Kill ambient colored glows ──
   A `0 0 Npx teal` shadow is light with no source. Where a surface
   needs lift it gets a grounded shadow; where it needs emphasis it
   gets a border. */
.pain-audit-badge,
.pain-audit-badge:hover,
.video-play-btn,
.video-tmembr-dot,
.included-stamp,
.wl-brand-chip,
.wl-brand-chip.active,
.hero-year-dot,
.aio-source,
.aio-source-badge,
.aio-source-you,
.map-legend-dot,
.f-loc-icon{box-shadow:none;}
.video-frame:hover,
.cs-card:hover,
.bento:hover,
.serp-card:hover{box-shadow:0 18px 40px rgba(0,0,0,0.35);}
.form-input:focus,
.form-select:focus,
.form-textarea:focus,
.err-search:focus-within{box-shadow:none;border-color:var(--teal);}
/* Pulsing halos and blinking badges — a keyframe ring expanding out
   of a control forever, or a "you got cited" badge that throbs. Both
   are attention effects with nothing to report; the state they mark
   is already visible without them. */
.video-play-btn,
.aio-source-you .aio-source-badge,
.pain-audit-badge,
.hero-year.active .hero-year-dot{animation:none !important;}
/* Specificity note: the glow rules in 9d are single-class, and a few
   templates set their glow from a two-class state selector — these
   need to match it. */
.hero-year.active .hero-year-dot,
.aio-source.aio-source-you,
.wl-brand-chip.active,
.cs-card.featured{box-shadow:none;}

/* ── 9e · Squared chrome ──
   Pill radii on our own components go to the shared button radius.
   Round play buttons stay round; a circular play control is a
   convention, not a tell. */
.video-tmembr,
.video-badge,
.bento-tag,
.cat-pill,
.faqhub-pill,
.form-submit,
.cs-tag,
.mt-card-tag,
.pc-dept-badge{border-radius:var(--btn-radius) !important;}

/* ── 9f · Solid surfaces for the de-glassed panels ──
   Removing the blur leaves the translucent fill behind, which on a
   dark band reads as a smudge. These take the opaque card color. */
.video-tmembr,
.video-badge,
.ps-meter,
.bento-tag{background:rgba(5,11,18,0.96);border:1px solid rgba(255,255,255,0.12);}
.video-play-btn{background:rgba(22,192,183,0.18);}

/* ── 9g · Browser chrome ──
   Fourteen templates draw a faux browser or dashboard window and
   title it with the three macOS traffic lights. It is the single
   most recognizable stock-mockup detail there is, and the homepage
   already answered it: one brand hexagon where the lights would go
   (.fm-hex in front-page.css). Same move here, done in CSS so the
   forty templates keep their markup — the first dot becomes the
   hexagon, the other two are dropped.

   Every one of these frames one of OUR mockups, including the ones
   showing a client site, because the frame is our drawing of a
   browser either way. The chrome that belongs to somebody else's
   interface — .ig-post-dots, .yt-*, .tk-* — is left alone. */
.pain-report-dots > :nth-child(n+2),
.ent-dots > :nth-child(n+2),
.emd-dots > :nth-child(n+2),
.dash-dots > :nth-child(n+2),
.error-log-dots > :nth-child(n+2),
.lsa-topbar-dots > :nth-child(n+2),
.studio-dots > :nth-child(n+2),
.rep-dots > :nth-child(n+2),
.store-dots > :nth-child(n+2),
.builder-dots > :nth-child(n+2),
.browser-dots > :nth-child(n+2),
.wl-dots > :nth-child(n+2){display:none !important;}
.pain-report-dots > :first-child,
.ent-dots > :first-child,
.emd-dots > :first-child,
.dash-dots > :first-child,
.error-log-dots > :first-child,
.lsa-topbar-dots > :first-child,
.studio-dots > :first-child,
.rep-dots > :first-child,
.store-dots > :first-child,
.builder-dots > :first-child,
.browser-dots > :first-child,
.wl-dots > :first-child{
  width:11px !important;
  height:12px !important;
  border-radius:0 !important;
  background:var(--teal) !important;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}

/* ── 9h · Card icon tiles ──
   On 14 templates the same element — a card's icon tile — renders as
   a hexagon in one section and a rounded square in another, because
   .svc-card-icon was converted to the brand shape (section 4) and
   each template's other icon class was not. Two shapes for one
   component on one page is what makes a layout look unfinished.

   Scoped to the icon-wall family only. Left as squares: the footer
   and contact social buttons, which are brand marks and read better
   in their own container, and every tile that holds an image or a
   platform logo rather than a glyph — a hexagon would crop those. */
.eng-card-icon,
.algo-card-icon,
.eco-card-icon,
.feat-card-icon,
.plat-card-icon,
.mon-why-icon,
.scale-tier-icon,
.milestone-icon,
.value-icon,
.method-icon,
.office-icon,
.emd-campaign-icon,
.auto-node-icon,
.funnel-feat-icon,
.stack-layer-icon,
.stories-feat-icon,
.loc-svc-icon,
.lf-feat-icon,
.lf-stage-icon,
.why-feat-icon,
.shorts-feat-icon,
.inc-layer-icon,
.svc-sec-icon{
  border-radius:0 !important;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}

/* ── 9i · Boxed hero accent ──
   The homepage statement bands put their keyword in an outlined box;
   the hero accent is the same idea one level up, so it takes the same
   treatment and the two read as one device.

   display:inline with box-decoration-break:clone rather than
   inline-block, because these accents are not all one word: they run
   from "recommended" to "Philadelphia & Nationally" to seven-word
   phrases. inline-block would refuse to wrap and push the box out of
   the column; cloning gives each wrapped line its own box, which
   reads as deliberate. The tilt from .boxed is dropped for the same
   reason — transforms do not apply to inline boxes, and a rotated
   slab at 60px would be shouting anyway. */
.hero h1 em,
.hero .hero-h1 em,
.hero-h1 em,
/* The team hero writes its accent as a <span> subtitle rather than an
   <em>, and as display:block, so neither the element selector nor the
   inline-block layout below reached it — the boxed outline was simply
   absent on that one page. */
.team-hero h1 span{
  /* inline-block with max-width:100%, not plain inline.
   *
   * The tilt is the reason. transform does not apply to inline
   * boxes, so a tilted accent has to be inline-block — but a bare
   * inline-block refuses to wrap and shoves a long accent out of the
   * column ("Our entire SEO team behind the curtain." is seven
   * words). max-width:100% lets it wrap INTERNALLY instead: the text
   * breaks inside the box and one box encloses all its lines, which
   * is what we want anyway now that it is tilted — per-line boxes at
   * different angles would read as a mistake. */
  display:inline-block;
  max-width:100%;
  padding:0.14em 0.34em 0.18em 0.28em;
  border:2px solid var(--teal);
  border-radius:7px;
  transform:rotate(-1.2deg);
}
/* Outline only — no offset shadow, unlike .boxed on the statement
   bands. There the keyword is deliberately one or two words, so the
   shadow lands once. A hero accent can run to eight ("Make sure your
   brand is one of them."), and a wrapped accent stacks three boxes
   whose shadows then collide with the line beneath. The outline
   alone survives any length. */

/* The border needs leading a bare display headline does not. */
.hero h1,
.hero .hero-h1{line-height:1.3;}
/* Was display:block and full-bleed; the box has to hug the words. */
.team-hero h1 span{display:inline-block;margin-top:14px;letter-spacing:0;}
.team-hero h1{line-height:1.06;}

/* ── 9g · One radius scale ──
   A census across the 45 interiors found ten distinct corner radii
   on card-sized surfaces — 6, 7, 8, 10, 12, 14, 16, 18, 20 and 22px
   — because each template was drawn separately. The homepage uses
   three: 12 for controls, 16 for cards, 20 for the few large panels.
   These are the strays, pulled onto 16.

   Not included, on purpose: .boxed and the hero accent (their 6/7px
   is a drawn outline, not a card), anything with a percentage radius
   (avatars, play buttons), and the SERP/browser mockups — a Google
   result card has its own corner radius and matching it to ours
   would make the artwork look like our furniture. */
.pain-row,
.pain-cta,
.pain-report,
.pain-audit-badge,
.eng-card,
.cs-card,
.award-card,
.award-img-wrap,
.faq-snap,
.hero-stat,
.video-proof,
.video-frame,
.auto-node,
.feat-card,
.mt-card,
.mon-eng,
.chapter-content,
.sc-card,
.vid-card,
.bento,
.aio-pain-card,
.svc-snap{border-radius:16px;}

/* ── 9h · The all-dark utility pages ──
   Blog, Contact, FAQ hub and Sitemap ran obsidian top to bottom —
   they are index and utility pages, so they have no .seo-content or
   .faq band for §3 to flip, and a structural census put them at zero
   light sections against the homepage's six. They are also the four
   pages most made of lists, forms and links, which is exactly the
   content a light plane serves better.

   Each one's body section flips; the hero above it stays dark, so
   the page reads dark → light the way every other template does.

   Every explicit color inside these sections is re-inked below.
   That list is short because they mostly inherit from body — which
   is also why flipping them is safe, and why the few that DO set a
   color have to be caught by hand. The pattern that bit us on
   Local SEO applies here: if a new dark card appears inside one of
   these sections, add it to the dark-island rule in §3 rather than
   lightening the band. */
.blog-grid,
.contact,
.faqhub-body,
.sitemap-section{
  background:var(--cream);
  color:var(--ink-soft);
  border-top:1px solid rgba(30,52,72,0.14);
}
.blog-grid :is(h1,h2,h3,h4,h5,strong,b,dt),
.contact :is(h1,h2,h3,h4,h5,strong,b,dt),
.faqhub-body :is(h1,h2,h3,h4,h5,strong,b,dt),
.sitemap-section :is(h1,h2,h3,h4,h5,strong,b,dt){color:var(--ink);}
.blog-grid :is(p,li,span,td,dd,small,time,label),
.contact :is(p,li,span,td,dd,small,time,label),
.faqhub-body :is(p,li,span,td,dd,small,time,label),
.sitemap-section :is(p,li,span,td,dd,small,time,label){color:var(--ink-soft);}

/* Cards: transparent surfaces with a teal hairline read as nothing
   on a light ground, so they take the paper color and an ink edge. */
/* Scoped to their own light bands, not global.
 *
 * These were unscoped, which was fine while each class appeared on
 * exactly one page. It stopped being fine the moment search.php and
 * archive.php started rendering .post-card outside .blog-grid: the
 * card kept the white background from this rule while its text
 * stayed light, so the whole card was white-on-white. Scoping means
 * a card only turns to paper where the band around it is paper. */
.blog-grid .post-card,
.contact .form-card,
.contact .info-card,
.faqhub-body .faqhub-item,
.faqhub-body .faqhub-a-hero{
  background:var(--cream-card);
  border-color:rgba(30,52,72,0.12);
}

/* .faqhub-group-head was in that list and should not have been. It is
   a category heading with a count and a rule under it, not a card —
   faq.css gives it padding:0 0 14px because on the dark band it was
   only ever a line of type. Painting it var(--cream-card) turned it
   into a white bar with "AI MARKETING" flush against the left edge
   and "20 questions" flush against the right, and made the heading
   look like one more row in the list of white cards below it.

   It gets the ink hairline it needs on a light band and nothing else.
   The rule that followed set border-top-color on an element whose only
   border is the bottom one, so it never did anything and is gone. */
.faqhub-body .faqhub-group-head{
  background:none;
  border-bottom-color:rgba(30,52,72,0.16);
}
.sitemap-section .sitemap-col h2.sitemap-h2{border-bottom-color:rgba(30,52,72,0.2);color:var(--ink);}
.sitemap-section .sitemap-col h2.sitemap-h2 i{color:var(--teal-ink);}
/* Role after a name in the team column — secondary, so it reads as
   annotation rather than as part of the link label. */
.sitemap-section .sitemap-meta{
  font-family:var(--mono2);
  font-size:10.5px;
  letter-spacing:0.1em;
  text-transform:uppercase;
  /* --ink-soft, not --ink-faint. Faint composites to rgb(137,150,162)
     on this band — 2.81:1, and this is 10.5px type. The polaroid
     captions carried exactly this bug two rounds ago. */
  color:var(--ink-soft);
  margin-left:8px;
}
.hours-row{border-top-color:var(--ink);border-bottom-color:rgba(30,52,72,0.1);}

/* Accents: brand teal is 2.11:1 on this ground; --teal-ink is the
   darkened value that clears AA. */
.blog-grid a:not(.btn),
.contact a:not(.btn),
.faqhub-body a:not(.btn),
.sitemap-section a:not(.btn),
.blog-grid .post-link,
.blog-grid .post-cat,
.faqhub-group-count,
.faqhub-read-more,
.info-card-title{color:var(--teal-ink);}

/* A HEADLINE IS NOT A LINK
 *
 * The rule above paints every link in the light bands teal, which is
 * right for links and wrong for a post card's headline — that is an
 * h2 that happens to be clickable. Left alone it produced a grid of
 * six teal headlines sitting above six teal "Read Article" links, all
 * one color, nothing ranked. The headline takes ink and the accent
 * goes back to meaning "this is the thing you click".
 *
 * Same specificity as the rule above (0,2,1) and placed after it, so
 * it wins on order rather than by growing the selector. Keep the two
 * together: separating them puts this back to teal. */
/* inherit, not a fixed ink: the same card renders on the light blog
   band and on the dark Spotlight ground, and a hard-coded ink headline
   measured 1.54:1 there — invisible. Inheriting takes --ink from the
   light-band re-inking and --text from the dark section, so the
   headline follows whatever ground it lands on. Hover is the one place
   it takes the accent, and that flips with the ground too. */
.post-card .post-title a{color:inherit;}
.post-card .post-title a:hover,
.post-card .post-title a:focus-visible{color:var(--teal-ink);}
:where(.spotlight) .post-card .post-title a:hover,
:where(.spotlight) .post-card .post-title a:focus-visible{color:var(--teal);}
.blog-grid .post-read,
.contact .form-sub,
.contact .form-label,
.contact .hours-time{color:var(--ink-soft);}
/* Two classes deep so these beat the blanket :is(p,li,span,…) rule
   above, which is (0,1,1) — otherwise the emphasis they carry on the
   dark version is flattened away. */
.contact .form-title,
.contact .hours-day{color:var(--ink);}

/* Form fields were white-on-white translucency. */
.form-input,
.form-select,
.form-textarea{
  background:#fff;
  border-color:rgba(30,52,72,0.18);
  color:var(--ink);
}
.form-input::placeholder,
.form-textarea::placeholder{color:var(--ink-faint);}
.form-submit{border-radius:var(--btn-radius);}

/* The Gravity Forms version of the same form. global.css inks its
   controls for a dark band (translucent obsidian), which on this
   paper card comes out as solid grey boxes. White fields, an ink
   hairline, ink type, and the darker teal for labels and focus. */
.contact .seolocale-gf .gform_wrapper{
  --gf-ctrl-bg-color:#fff;
  --gf-ctrl-bg-color-hover:#fff;
  --gf-ctrl-bg-color-focus:#fff;
  --gf-ctrl-border-color:rgba(30,52,72,0.18);
  --gf-ctrl-border-color-hover:rgba(30,52,72,0.32);
  --gf-ctrl-border-color-focus:var(--teal-ink);
  --gf-ctrl-color:var(--ink);
  --gf-ctrl-placeholder-color:var(--ink-faint);
  --gf-ctrl-shadow-focus:0 0 0 3px rgba(10,120,112,0.16);
  --gf-label-color-primary:var(--teal-ink);
  --gf-label-req-color:var(--teal-ink);
  --gf-desc-color:var(--ink-soft);
}
.contact .seolocale-gf .gform_wrapper input:not([type=submit]):not([type=button]):not([type=checkbox]):not([type=radio]):not([type=hidden]),
.contact .seolocale-gf .gform_wrapper select,
.contact .seolocale-gf .gform_wrapper textarea{
  background-color:#fff !important;
  border-color:rgba(30,52,72,0.18) !important;
  color:var(--ink) !important;
}
.contact .seolocale-gf .gform_wrapper select,
.contact .seolocale-gf .gform_wrapper select:focus{
  background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%230A7870' stroke-width='2'/%3E%3C/svg%3E") !important;
  /* The global focus rule sets the background shorthand, which
     resets these three and tiled the arrow across the whole field
     while the menu was open. */
  background-repeat:no-repeat !important;
  background-position:right 14px center !important;
  background-size:12px 8px !important;
}
.contact .seolocale-gf .gform_wrapper ::placeholder{color:var(--ink-faint) !important;}
.contact .seolocale-gf .gform_wrapper input:not([type=submit]):focus,
.contact .seolocale-gf .gform_wrapper select:focus,
.contact .seolocale-gf .gform_wrapper textarea:focus{
  background-color:#fff !important;
  border-color:var(--teal-ink) !important;
  box-shadow:0 0 0 3px rgba(10,120,112,0.16) !important;
}
.contact .seolocale-gf .gform_wrapper .gfield_label,
.contact .seolocale-gf .gform_wrapper legend.gfield_label,
.contact .seolocale-gf .gform_wrapper .gfield_required{color:var(--teal-ink) !important;}
.contact .seolocale-gf .gform_wrapper .gfield_description{color:var(--ink-soft);}

/* Teal-tinted tiles keep their tint but need the darker glyph. */
.office-icon,
.faqhub-q-thumb,
.faqhub-q-toggle,
.post-cat,
.sitemap-count{
  background:rgba(11,138,130,0.1);
  color:var(--teal-ink);
}
.social-link{
  background:rgba(30,52,72,0.05);
  border-color:rgba(30,52,72,0.12);
  color:var(--ink);
}

/* ─────────────────────────────────────────────────────────────
   7 · RESPONSIVE
   ───────────────────────────────────────────────────────────── */
@media (max-width:900px){
  .hero h1,
  .hero .hero-h1{font-size:clamp(28px,7.6vw,38px);}
  main h2,
  .section-h,
  .faq h2{font-size:clamp(23px,5.8vw,31px);}
  .cta{padding:64px 0;}
  .cta h2{font-size:clamp(26px,7vw,34px);max-width:none;}
  .seo-content .seo-inner > h2:first-of-type,
  .seo-content > .container > h2:first-of-type{font-size:clamp(25px,6.6vw,33px);max-width:none;}
  .seo-content .seo-inner > h2 + p,
  .seo-content > .container > h2 + p{font-size:17px;}
}

/* ─────────────────────────────────────────────────────────────
   10 · TEAM MEMBER PROFILE (/teams/{slug}/)
   Generated from the roster — see templates/single-team-member.php.
   Deliberately small: the page reuses .hero, .seo-content, .cta and
   the shared faces strip, so it inherits every band, seam and type
   decision the rest of the interiors already make.
   ───────────────────────────────────────────────────────────── */
.tm-hero-grid{
  display:grid;
  grid-template-columns:300px 1fr;
  gap:clamp(28px,4vw,56px);
  align-items:center;
  position:relative;
  z-index:1;
}
/* Hexagon, matching the faces strip and the service icons rather
   than introducing a third portrait shape. */
.tm-portrait{
  width:100%;max-width:300px;
  aspect-ratio:1/1.16;
  padding:4px;
  background:var(--teal);
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}
.tm-portrait{position:relative;}
.tm-portrait img{
  width:100%;height:100%;
  object-fit:cover;
  object-position:center 18%;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}
/* ── FUNNY PHOTO ──
 *
 * Slides in over the headshot rather than cross-fading: a swap you
 * can see arrive reads as deliberate, where a fade between two
 * portraits of the same person just looks like a loading glitch.
 *
 * It runs on a loop on every device, not only on touch. Hovering is
 * the intended interaction but nobody discovers it by accident, so
 * the portrait shows the joke on its own every few seconds and the
 * label says the rest. Hovering pauses the loop and holds the funny
 * shot in place, so the visitor's intent always beats the timer.
 */
.tm-shot-funny{
  position:absolute;
  inset:0;
  transform:translateX(100%);
  animation:tm-funny-slide 9s cubic-bezier(0.16,1,0.3,1) infinite;
}
@keyframes tm-funny-slide{
  0%,52%    {transform:translateX(100%);}
  62%,86%   {transform:translateX(0);}
  96%,100%  {transform:translateX(100%);}
}
/* animation:none, not animation-play-state:paused. Pausing freezes
   the current keyframe, and an animated value outranks a plain
   declaration — so pausing mid-loop held the photo wherever it
   happened to be (usually off-screen) and hovering did nothing.
   Cancelling the animation hands control back to the transition. */
.tm-portrait-has-funny:hover .tm-shot-funny,
.tm-portrait-has-funny:focus-within .tm-shot-funny{
  animation:none;
  transform:translateX(0);
  transition:transform 0.4s cubic-bezier(0.16,1,0.3,1);
}

/* The label. Sits on the portrait, fades back while the funny shot
   is showing so it is not competing with the thing it pointed at. */
.tm-hover-hint{
  position:absolute;
  left:50%;
  bottom:8%;
  transform:translateX(-50%);
  z-index:2;
  display:inline-flex;
  align-items:center;
  gap:7px;
  padding:6px 13px;
  border-radius:999px;
  background:rgba(5,11,18,0.72);
  border:1px solid rgba(22,192,183,0.45);
  color:var(--teal);
  font-family:var(--mono2);
  font-size:9.5px;
  letter-spacing:0.14em;
  text-transform:uppercase;
  white-space:nowrap;
  pointer-events:none;
  transition:opacity 0.3s ease;
}
.tm-hover-hint::before{
  content:"";
  width:8px;height:9px;
  background:var(--teal);
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}
.tm-portrait-has-funny:hover .tm-hover-hint{opacity:0;}
/* No hover, no instruction to hover — the loop already tells the
   story on a phone. */
@media (hover:none){
  .tm-hover-hint{display:none;}
}

@media (prefers-reduced-motion:reduce){
  .tm-shot-funny{
    animation:none;
    transform:translateX(100%);
    transition:none;
  }
  .tm-portrait-has-funny:hover .tm-shot-funny{transform:translateX(0);}
}
.tm-role{
  font-family:var(--mono2);
  font-size:12px;
  letter-spacing:0.16em;
  text-transform:uppercase;
  color:var(--teal);
  margin:0 0 18px;
}
.tm-exp{
  position:relative;
  border-top:1px solid rgba(255,255,255,0.1);
  padding:clamp(56px,6vw,88px) 0;
}
.tm-exp-list{
  list-style:none;
  margin:26px 0 0;
  padding:0;
  display:flex;
  flex-wrap:wrap;
  gap:10px;
}
.tm-exp-list li{
  padding:11px 18px;
  border:1px solid rgba(22,192,183,0.3);
  border-radius:var(--btn-radius);
  font-size:14px;
  font-weight:700;
  color:var(--text);
}
@media (max-width:820px){
  .tm-hero-grid{grid-template-columns:1fr;gap:26px;}
  .tm-portrait{max-width:210px;}
}

/* ─────────────────────────────────────────────────────────────
   11 · MOBILE GRID COLLAPSE
   Each interior template was drawn as a desktop mockup and its
   grids were written as fixed column counts. Many were never given
   a mobile override, so on a 390px screen they held their shape and
   divided the width instead: .svc-grid rendered three 89px columns
   on seventeen pages, .cases-grid on thirteen, and the two-column
   feature rows squeezed their text side down to 154px, which is
   what was breaking button labels into four lines.

   Measured rather than guessed — 46 grids across the site kept a
   text column under 230px at 390px wide.

   This layer loads after every page stylesheet, so one rule per
   class fixes all of them. Grids that already had a working mobile
   rule are unaffected: they resolve to one column either way.
   ───────────────────────────────────────────────────────────── */
@media (max-width:760px){
  /* Card grids — three or four across becomes one. */
  .svc-grid,
  .cases-grid,
  .algo-grid,
  .eco-grid,
  .feat-grid,
  .eng-grid,
  .values,
  .mt-grid,
  .vid-grid,
  .sc-grid{grid-template-columns:1fr !important;}

  /* Two-column feature rows — the copy side was being squeezed to
     under 200px, which is narrower than a comfortable measure and
     is where the four-line buttons came from. */
  .scale-inner,
  .auto-inner,
  .wf-inner,
  .inc-inner,
  .lf-inner,
  .serp-inner,
  .why-inner,
  .pain-wrap,
  .conv-inner,
  .structure-inner{grid-template-columns:1fr !important;}

  /* Icon-plus-text rows keep their two columns — a 30px icon beside
     text is the intended shape and reads fine at this width. Listed
     here so a future sweep does not "fix" them by mistake:
     .pain-row, .err-row, .dental-result, .aio-pain-card. */
}


/* ═══════════════════════════════════════════════════════════════
   BEFORE / AFTER DEMO CHROME
   ═══════════════════════════════════════════════════════════════

   Four pages run the same interactive demo — Local SEO's map pack,
   Dental's SERP, Industry's SERP, GBP's business card. The demo
   bodies genuinely differ. The chrome around them did not: each had
   its own copy of the same badge and the same tab strip under a
   different prefix (lp-, dental-, ind-, gbp-), which meant fixing
   the badge's contrast on one page fixed it on exactly one page.

   This is that chrome, once. The bodies stay per-page.

   Two elements doing two jobs: the tabs pick which frame you are
   looking at, the badge says what that frame means. */

/* Tabs and card tilt together so they read as one object rather than
   a control that happens to sit near a card. */
.demo-stack{position:relative;transform:rotate(1.05deg);}

/* ─── Tabs ───────────────────────────────────────────────
   margin-bottom:-1px so the active tab's bottom border and the
   card's top border resolve to a single line — that shared edge is
   what makes the strip read as attached. */
.demo-toggle{
  display:flex;
  gap:4px;
  justify-content:flex-start;
  margin:0 0 -1px;
  padding-left:18px;
  position:relative;
  z-index:2;
}
.demo-toggle-btn{
  font-family:var(--font);
  font-size:12.5px;font-weight:700;
  padding:9px 18px 10px;
  border-radius:11px 11px 0 0;
  cursor:pointer;
  background:rgba(5,11,18,0.62);
  color:rgba(223,239,253,0.66);
  border:1px solid rgba(255,255,255,0.16);
  border-bottom:none;
  transition:all 0.2s;
  display:inline-flex;align-items:center;gap:7px;
}
.demo-toggle-btn i{font-size:11px;}
.demo-toggle-btn:hover{color:var(--text);border-color:rgba(22,192,183,0.5);}
.demo-toggle-btn.active{
  background:var(--teal);
  border-color:var(--teal);
  color:#052e2c;
  padding-bottom:11px;
}
/* "Before", active, is a solid red chip rather than a tint — the
   tinted version left its own label barely legible against the fill. */
.demo-toggle-btn[data-demo-state="before"].active{
  background:#ea4335;
  border-color:#ea4335;
  color:#fff;
}
.demo-toggle-btn.done{color:rgba(223,239,253,0.45);}
.demo-toggle-btn:focus-visible{outline:2px solid var(--teal);outline-offset:2px;}

@media(max-width:600px){
  .demo-toggle{padding-left:12px;gap:3px;}
  .demo-toggle-btn{font-size:11px;padding:8px 11px 9px;}
}
@media(max-width:400px){
  .demo-toggle-btn{padding:8px 9px 9px;font-size:10.5px;}
}

/* ─── Badge ──────────────────────────────────────────────
   White paper with a drawn edge, so the narration sits on its own
   surface instead of dissolving into the dark hero.

   On white every color has to change: the brand teal sits at about
   2:1 here, which fails even the 3:1 large type is allowed. The tag
   and the number take the deeper ink teal and a darker red; the copy
   takes the ink tokens. Measured against the composited background,
   not eyeballed — these carry alpha, and a checker that ignores it
   reports roughly double the real ratio. */
.demo-state{
  position:relative;
  margin:0 0 16px;
  padding:15px 18px;
  border-radius:14px;
  background:#fff;
  border:1px solid var(--demo-state-line,rgba(30,52,72,0.16));
  box-shadow:0 6px 20px rgba(0,0,0,0.18);
  font-family:var(--font);
  transition:border-color 0.4s ease;
}
.demo-state.state-before{--demo-state-line:rgba(197,34,31,0.4);}
.demo-state.state-after{--demo-state-line:rgba(11,138,130,0.4);}
.demo-state-inner{
  position:relative;z-index:1;
  display:flex;align-items:center;gap:16px;
}
.demo-state-text{min-width:0;flex:1;}
.demo-state-tag{
  display:inline-flex;align-items:center;gap:6px;
  font-family:var(--mono2);
  font-size:10px;font-weight:700;
  letter-spacing:0.14em;text-transform:uppercase;
  margin-bottom:6px;
}
.demo-state-tag i{font-size:10px;}
.state-before .demo-state-tag{color:#C5221F;}
.state-after .demo-state-tag{color:var(--teal-ink);}
.demo-state-headline{
  font-size:16px;font-weight:800;
  letter-spacing:-0.3px;line-height:1.25;
  color:var(--ink);
}
.demo-state-sub{
  font-size:13.5px;line-height:1.5;
  color:var(--ink-soft);
  margin-top:4px;
}
/* The number the whole demo is about gets its own compartment rather
   than trailing the end of a sentence. */
.demo-state-stat{
  display:flex;flex-direction:column;align-items:flex-end;gap:3px;
  padding-left:16px;
  border-left:1px solid rgba(30,52,72,0.14);
  flex-shrink:0;
}
.demo-state-stat-label{
  font-family:var(--mono2);
  font-size:9.5px;font-weight:700;
  letter-spacing:0.14em;text-transform:uppercase;
  color:var(--ink-faint);
  white-space:nowrap;
}
.demo-state-stat-value{
  font-family:var(--disp);
  font-size:30px;letter-spacing:-1px;line-height:1;
}
.state-before .demo-state-stat-value{color:#C5221F;}
.state-after .demo-state-stat-value{color:var(--teal-ink);}

@media(max-width:560px){
  .demo-state{padding:13px 15px;}
  .demo-state-inner{gap:13px;}
  .demo-state-headline{font-size:15px;}
  .demo-state-sub{font-size:12.5px;}
  .demo-state-stat{padding-left:13px;}
  .demo-state-stat-value{font-size:24px;}
}


/* ═══════════════════════════════════════════════════════════════
   THE AUDIT PANELS ARE NOT TERMINAL OUTPUT
   ═══════════════════════════════════════════════════════════════

   Eight service pages list the problems we find — thin product copy,
   an unclaimed profile, a site that takes nine seconds. The content is
   real and it is the most useful thing on those pages.

   The frame around it was not. Each one carried three macOS traffic
   lights and a monospace filename — "~ store-seo-audit.log — 5 revenue
   leaks" — which claims a machine scanned something and produced this.
   Nothing scanned anything; a person wrote the list. Eight pages
   running the identical conceit with the identical count of five is
   also, on its own, the thing that reads as generated.

   The dots are gone from the markup and the filenames are gone with
   them. This restyles what is left: a heading over a list, in the
   site's own voice, instead of a title bar. */
.pain-report-title,
.error-log-title,
.ind-pain-title-bar{
  position:static;
  font-family:var(--mono2);
  font-size:11px;
  font-weight:700;
  letter-spacing:0.14em;
  text-transform:uppercase;
  text-align:left;
  color:var(--teal);
  padding:16px 20px 6px;
  flex:none;
}
/* Any dots left behind by a template this pass did not reach. Belt and
   braces: the markup no longer emits them, and if one reappears it
   should not bring the terminal back with it. */
.pain-report-dots,
.error-log-dots,
.ind-pain-dots,
/* The same three grey traffic lights, in eleven more places: a fake
   browser over the portfolio screenshots, and a title bar on every
   dashboard, storefront and builder mockup. One stock-mockup cliche
   repeated a dozen times is its own tell, whatever the panel under it
   is showing. The markup no longer emits any of them; this catches one
   that comes back. */
.browser-dots,
.rep-dots,
.ent-dots,
.dash-dots,
.builder-dots,
.store-dots,
.emd-dots,
.wl-dots,
.lsa-topbar-dots,
.studio-dots,
.pf-chrome{display:none;}

/* The dots were balancing a centered title. With them gone the panel
   name floats in the middle of an empty bar, which still reads as a
   window. These are panel headings now: left, quiet, no centering.
   (.pain-report-title and .error-log-title are already handled by the
   audit-panel rule above.) */
.rep-title,
.emd-title,
.studio-title{
  flex:1;
  text-align:left;
  font-family:var(--mono2);
  letter-spacing:0.12em;
  text-transform:uppercase;
}

/* And these five were the address bar itself — a URL in a rounded pill
   in the middle of a title strip is the browser illusion, more so than
   three dots ever were. The information stays; the pill does not. */
.ent-url,
.builder-url,
.store-url,
.wl-url,
.lsa-topbar-url{
  flex:1;
  justify-content:flex-start;
  text-align:left;
  background:none;
  border:none;
  border-radius:0;
  padding:0;
  font-family:var(--mono2);
  letter-spacing:0.06em;
}
/* The panel kept top padding for a title bar that is no longer there. */
.pain-report{padding-top:0;}


/* ═══════════════════════════════════════════════════════════════
   ONE CASE-STUDY SECTION, TWENTY-TWO PAGES
   ═══════════════════════════════════════════════════════════════

   template-parts/case-wall.php replaces the hardcoded result grids
   that used to sit on each service page. Those grids named
   twenty-nine businesses that are not clients and closed most cards
   with a quote from an owner who does not exist.

   The prefix is .cw-, not .cs- or .case-, because twenty-one page
   stylesheets already define those two names differently and all of
   them load before this file. A shared component that inherits
   whichever page won the cascade is not shared. Nothing else in the
   theme claims .cw-, so this section looks the same everywhere and
   the old per-page rules can be deleted at leisure without it
   moving.

   IT STAYS A DARK BAND. The sections it replaces carried no
   background of their own, so they sat on the page's obsidian and
   the cream .faq below them was the step. A cream case band looked
   fine on its own and merged into .faq on all twenty-two pages —
   the alternation is what the seam system is for, so this keeps the
   band dark and the rhythm unchanged.

   There is no empty state here on purpose. When no published case
   study matches the page's service, the template returns before it
   prints anything and the band simply is not there. */
.cw-section{
  position:relative;
  padding:96px 0;
  color:var(--text);
  /* Same chapter seam .cases and .case-studies got: hairline plus a
     teal hexagon sitting on it. */
  border-top:1px solid rgba(255,255,255,0.1);
}
.cw-section::before{
  content:"";
  position:absolute;
  left:0;right:0;top:0;
  height:130px;
  background:linear-gradient(180deg,rgba(22,192,183,0.05) 0%,transparent 100%);
  pointer-events:none;
}
.cw-section::after{
  content:"";
  position:absolute;
  top:-6px;left:50%;
  transform:translateX(-50%);
  width:11px;height:12px;
  background:var(--teal);
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
  opacity:0.5;
  z-index:2;
}
.cw-section .container{position:relative;z-index:1;}

.cw-head{
  max-width:760px;
  margin:0 auto 46px;
  text-align:center;
}
.cw-head h2{
  margin:12px 0 0;
  font-family:var(--disp);
  font-size:clamp(27px,3.2vw,39px);
  line-height:1.08;
  letter-spacing:-1.2px;
  color:var(--text);
}
.cw-head p{
  margin:14px 0 0;
  font-size:17px;
  line-height:1.62;
  color:var(--muted);
}

.cw-grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(290px,1fr));
  gap:22px;
  align-items:stretch;
}

/* THE CARD. A photo face on top — the case study's hero image when
   it has one, the service gradient with an industry watermark when
   it does not — carrying the client's logo on a white chip and the
   one number worth leading with. The story, the other two metrics,
   the quote and the link sit in a body below. Cards are flex columns
   so the link lands on the bottom edge of every card in the row
   whatever the copy above it does. */
.cw-card{
  position:relative;
  display:flex;
  flex-direction:column;
  overflow:hidden;
  background:linear-gradient(180deg,rgba(12,26,38,0.92) 0%,rgba(5,11,18,0.8) 100%);
  border:1px solid rgba(22,192,183,0.18);
  border-radius:20px;
  box-shadow:0 20px 50px rgba(0,0,0,0.35);
  transition:transform .35s ease,box-shadow .35s ease,border-color .35s ease;
}
.cw-card:hover{
  transform:translateY(-5px);
  border-color:rgba(22,192,183,0.4);
  box-shadow:0 30px 70px rgba(0,0,0,0.5);
}

.cw-face{
  position:relative;
  overflow:hidden;
  display:flex;
  flex-direction:column;
  justify-content:space-between;
  gap:26px;
  min-height:280px;
  padding:20px 20px 22px;
  background:var(--cw-grad,linear-gradient(135deg,#1a2030,#0d1520));
  border-bottom:1px solid rgba(255,255,255,0.08);
}
/* The photo keeps its detail up top where the eye looks for it and
   fades to near-solid under the number, so the type always sits on
   something dark enough to read. */
.cw-face-photo{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:cover;
  object-position:center;
  z-index:0;
  transition:transform .6s ease;
}
.cw-card-photo .cw-face::before{
  content:"";
  position:absolute;inset:0;z-index:1;
  background:linear-gradient(180deg,rgba(5,11,18,0.12) 0%,rgba(5,11,18,0.42) 48%,rgba(5,11,18,0.9) 100%);
  pointer-events:none;
}
.cw-card-photo:hover .cw-face-photo{transform:scale(1.04);}
.cw-watermark{
  position:absolute;right:-18px;bottom:-22px;z-index:0;
  font-size:150px;
  color:#fff;
  opacity:0.04;
  transition:opacity .5s ease,transform .5s ease;
}
.cw-card:hover .cw-watermark{opacity:0.07;transform:scale(1.05) rotate(-5deg);}

.cw-face-top,
.cw-face-stat{position:relative;z-index:2;}
.cw-face-top{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:12px;
}
/* The logo sits on a white chip so a dark logo works as well as a
   light one. No logo: the client name as a wordmark in its place, so
   a card is never a broken-image box. */
.cw-mark{
  width:124px;
  aspect-ratio:3 / 2;
  flex-shrink:0;
  display:flex;align-items:center;justify-content:center;
  padding:10px 12px;
  background:#fff;
  border-radius:12px;
  box-shadow:0 8px 24px rgba(0,0,0,0.4);
}
.cw-mark img{
  max-width:100%;max-height:100%;
  width:auto;height:auto;
  object-fit:contain;
  display:block;
}
.cw-mark-word{
  font-family:var(--disp);
  font-size:13px;
  line-height:1.15;
  letter-spacing:-0.3px;
  text-align:center;
  color:var(--ink,#050b12);
}
.cw-tag{
  display:inline-flex;align-items:center;gap:7px;
  flex-shrink:1;
  min-width:0;
  padding:6px 11px;
  border-radius:999px;
  background:rgba(5,11,18,0.55);
  border:1px solid rgba(22,192,183,0.3);
  backdrop-filter:blur(6px);
  -webkit-backdrop-filter:blur(6px);
  font-family:var(--mono2);
  font-size:10px;
  font-weight:700;
  letter-spacing:0.1em;
  text-transform:uppercase;
  color:var(--teal);
  text-align:right;
}
.cw-tag i{font-size:10px;}

.cw-face-stat{display:flex;flex-direction:column;gap:6px;}
.cw-face-num{
  font-family:var(--display-stat);
  font-size:clamp(44px,5vw,60px);
  font-weight:700;
  line-height:0.95;
  letter-spacing:-2px;
  color:var(--cw-accent,var(--teal));
  text-shadow:0 4px 22px rgba(0,0,0,0.55);
}
.cw-face-label{
  font-family:var(--mono2);
  font-size:11px;
  font-weight:700;
  letter-spacing:0.11em;
  text-transform:uppercase;
  color:rgba(255,255,255,0.82);
}
.cw-face-label em{
  margin-left:6px;
  font-style:normal;
  text-transform:none;
  letter-spacing:0;
  color:rgba(255,255,255,0.5);
}

.cw-body{
  display:flex;
  flex-direction:column;
  flex:1 1 auto;
  gap:16px;
  padding:22px 24px 24px;
}
.cw-client{
  margin:0;
  font-family:var(--disp);
  font-size:21px;
  line-height:1.16;
  letter-spacing:-0.5px;
  color:var(--text);
}
.cw-summary{
  margin:0;
  font-size:15px;
  line-height:1.6;
  color:var(--muted);
}

/* The two supporting metrics side by side. One metric takes the
   row on its own. */
.cw-metrics{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(120px,1fr));
  gap:14px 18px;
  padding:16px 0 0;
  border-top:1px solid rgba(255,255,255,0.1);
}
.cw-metric{display:flex;flex-direction:column;gap:4px;min-width:0;}
.cw-metric-label{
  font-family:var(--mono2);
  font-size:10.5px;
  font-weight:700;
  letter-spacing:0.11em;
  text-transform:uppercase;
  color:var(--muted);
}
.cw-metric-vals{
  display:flex;align-items:baseline;gap:8px;
  flex-wrap:wrap;
}
.cw-before{
  font-family:var(--display-stat);
  font-size:15px;
  color:rgba(223,239,253,0.55);
  text-decoration:line-through;
  text-decoration-thickness:1px;
}
.cw-arrow{font-size:10px;color:var(--teal);}
.cw-after{
  font-family:var(--display-stat);
  font-size:24px;
  font-weight:700;
  letter-spacing:-0.6px;
  line-height:1;
  color:var(--text);
}

.cw-quote{
  margin:0;
  padding-left:16px;
  border-left:3px solid var(--teal);
  font-size:15px;
  line-height:1.62;
  color:var(--text);
}
.cw-quote cite{
  display:block;
  margin-top:9px;
  font-style:normal;
  font-size:13px;
  color:var(--muted);
}

/* margin-top:auto on the last item, not on the metrics block, so the
   link lands on the card's bottom edge in every card of the row
   whatever sits above it. Cards without a link just end where their
   content ends. */
.cw-link{
  display:inline-flex;align-items:center;gap:8px;
  align-self:flex-start;
  margin-top:auto;
  font-weight:700;
  font-size:14.5px;
  color:var(--teal);
  text-decoration:none;
}
.cw-link:hover{text-decoration:underline;}
.cw-link i{font-size:11px;transition:transform .18s ease;}
.cw-link:hover i{transform:translateX(3px);}

/* ONE CASE STUDY turns sideways and fills the band: the face takes
   the left column, the story the right, like a feature rather than
   a lone card with two thirds of the row empty. */
.cw-grid-solo{grid-template-columns:1fr;}
.cw-grid-solo .cw-card{
  display:grid;
  grid-template-columns:minmax(280px,0.9fr) 1.1fr;
  align-items:stretch;
  max-width:1040px;
  margin:0 auto;
}
.cw-grid-solo .cw-face{
  min-height:360px;
  padding:26px;
  border-bottom:none;
  border-right:1px solid rgba(255,255,255,0.08);
}
.cw-grid-solo .cw-mark{width:150px;}
.cw-grid-solo .cw-face-num{font-size:clamp(52px,6vw,76px);}
.cw-grid-solo .cw-watermark{font-size:220px;}
.cw-grid-solo .cw-body{justify-content:center;padding:32px 36px;gap:18px;}
.cw-grid-solo .cw-client{font-size:26px;}
.cw-grid-solo .cw-summary{font-size:16.5px;}
.cw-grid-solo .cw-after{font-size:28px;}
.cw-grid-solo .cw-link{margin-top:4px;}
@media(max-width:820px){
  .cw-grid-solo .cw-card{grid-template-columns:1fr;}
  .cw-grid-solo .cw-face{
    min-height:280px;
    border-right:none;
    border-bottom:1px solid rgba(255,255,255,0.08);
  }
  .cw-grid-solo .cw-body{padding:22px 24px 24px;}
}

.cw-foot{margin-top:42px;text-align:center;}

@media(max-width:760px){
  .cw-section{padding:68px 0;}
  .cw-head{margin-bottom:34px;}
  .cw-face{min-height:250px;padding:18px;}
  .cw-mark{width:108px;}
  .cw-body{padding:20px 20px 22px;}
}

/* ── Team video blocks: the video takes the right side ──
   Every service page's "meet the team" block is the same two-column
   grid (copy left, a 16:9 frame right) with the columns near equal,
   which left the video a modest card. The copy column narrows and
   the frame bleeds to the right edge of the viewport: on a wide
   screen it runs from the column's start to the screen's edge, on a
   narrow one to the edge of the container gutter. The outer right
   corners square off where it meets the edge. Stacked variants
   (.video-stack on TikTok and Social) bleed as a unit. Scoped to the
   block's own children so the client-story frames stay as they are.
   Later than every page stylesheet in the cascade, so no !important. */
.video-block-inner{
  grid-template-columns:minmax(0,0.8fr) minmax(0,1.3fr);
  gap:clamp(36px,4vw,64px);
}
.video-block-inner > .video-frame,
.video-block-inner > .video-stack{
  /* width:auto, not the page sheets' 100%: a block at 100% is the
     cell's width whatever its margin, while auto stretches to fill
     the cell plus the negative margin. */
  width:auto;
  margin-right:calc(-1 * max(2.5rem, (100vw - 1360px) / 2 + 2.5rem));
}
.video-block-inner > .video-frame,
.video-block-inner > .video-stack > .video-frame:first-child{
  border-top-right-radius:0;
  border-bottom-right-radius:0;
}
.video-block-inner > .video-stack .video-stack-row > div:last-child .video-frame{
  border-top-right-radius:0;
  border-bottom-right-radius:0;
}
@media(max-width:960px){
  .video-block-inner{grid-template-columns:minmax(0,1fr);}
  .video-block-inner > .video-frame,
  .video-block-inner > .video-stack{margin-right:0;}
  .video-block-inner > .video-frame,
  .video-block-inner > .video-stack > .video-frame:first-child,
  .video-block-inner > .video-stack .video-stack-row > div:last-child .video-frame{
    border-top-right-radius:22px;
    border-bottom-right-radius:22px;
  }
}

/* ── The hexagon tile, in two quiet places ──
   The same faint tiling the Services menu sits on, used where a band
   is flat and text-light so it earns it: the stat strip under every
   hero (dark, fading out toward both ends so the five figures sit on
   it and the edges stay clean) and the FAQ band (cream, the tile in
   its top right corner only, behind the heading). Nowhere else; the
   photo bands and the proof bands have their own backdrops and the
   long-form copy wants nothing behind it. */
.metrics-section{
  background:
    radial-gradient(ellipse 58% 140% at 50% 50%, rgba(12,26,38,0) 20%, var(--obsidian) 92%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='56' height='64' viewBox='0 0 56 64'><path d='M28 2 L52 16 L52 48 L28 62 L4 48 L4 16 Z' fill='none' stroke='rgba(22,192,183,0.13)' stroke-width='1.5'/></svg>") center / 56px 64px,
    var(--obsidian);
}
.faq{
  background:
    radial-gradient(ellipse 46% 90% at 100% 0%, rgba(244,247,251,0) 10%, var(--cream) 72%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='56' height='64' viewBox='0 0 56 64'><path d='M28 2 L52 16 L52 48 L28 62 L4 48 L4 16 Z' fill='none' stroke='rgba(10,120,112,0.16)' stroke-width='1.5'/></svg>") right top / 56px 64px,
    var(--cream);
}

/* ── Phones: the hero demos step aside ──
   Every service hero carries a simulated app on its right (a local
   pack, a profile card, an ad, a map, a dashboard): dozens of nodes
   and a few hundred lines of CSS each. On a phone it stacks under the
   copy and the buttons, so the visitor reaches it only by scrolling
   past the call to action, and it costs the same to build whether or
   not they do. Below 600px it is not rendered; the proof bands and
   the real screenshots carry the page. */
@media(max-width:600px){
  .hero .lp-wrapper, .ind-hero .lp-wrapper,
  .hero .gbp-wrap, .ind-hero .gbp-wrap,
  .hero .ad-wrap, .ind-hero .ad-wrap,
  .hero .map-wrap, .ind-hero .map-wrap,
  .hero .dental-serp-wrap, .ind-hero .dental-serp-wrap,
  .hero .ind-serp-wrap, .ind-hero .ind-serp-wrap,
  .hero .chat-wrap, .ind-hero .chat-wrap,
  .hero .ecom-wrap, .ind-hero .ecom-wrap,
  .hero .feed-wrap, .ind-hero .feed-wrap,
  .hero .ads-mgr, .ind-hero .ads-mgr,
  .hero .ig-profile, .ind-hero .ig-profile,
  .hero .tk-feed, .ind-hero .tk-feed,
  .hero .yt-player, .ind-hero .yt-player,
  .hero .gpt, .ind-hero .gpt,
  .hero .gem, .ind-hero .gem,
  .hero .grok, .ind-hero .grok,
  .hero .ppx, .ind-hero .ppx,
  .hero .dash-wrap, .ind-hero .dash-wrap,
  .hero .emd, .ind-hero .emd,
  .hero .rep, .ind-hero .rep,
  .hero .store, .ind-hero .store,
  .hero .builder-wrap, .ind-hero .builder-wrap,
  .hero .wix, .ind-hero .wix,
  .hero .wpa, .ind-hero .wpa,
  .hero .ent, .ind-hero .ent,
  .hero .studio, .ind-hero .studio,
  .hero .player-wrap, .ind-hero .player-wrap,
  .hero .mon-dash, .ind-hero .mon-dash,
  .hero .wl-dash, .ind-hero .wl-dash,
  .hero .lsa, .ind-hero .lsa,
  .hero .aio-serp, .ind-hero .aio-serp{display:none !important;}
}

/* ── Long-form "Read more": a teaser, not a void ──
   Ten pages collapse their long-form copy to zero height behind a
   button, which tells a reader (and a crawler) the copy is not meant
   to be read. Collapsed, the block now shows its first screenful and
   fades, the same mask .seo-clamp uses; the button still opens the
   rest. Later in the cascade than the page sheets' max-height:0. */
.seo-expandable{
  max-height:360px;
  opacity:1;
  overflow:hidden;
  -webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 120px),transparent 100%);
          mask-image:linear-gradient(to bottom,#000 calc(100% - 120px),transparent 100%);
}
.seo-expandable.expanded{
  max-height:none;
  -webkit-mask-image:none;
          mask-image:none;
}

/* ── Video proof strip (nine service pages carry the same three-item
   strip beside the team video). It was capped at 460px with three
   items side by side, so "Your brand only" and "White label reports"
   broke onto two lines next to their icons. It spans the column now,
   each item gets an equal track, and the titles stay on one line;
   under 600px the items stack. ── */
.video-proof{display:grid !important;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px 18px;max-width:none !important;padding:16px 18px;}
.video-proof-item{min-width:0;}
.video-proof-text{font-size:12.5px;}
.video-proof-text strong{font-size:14px;white-space:nowrap;}
@media(max-width:1100px){.video-proof-text strong{white-space:normal;}}
@media(max-width:600px){.video-proof{grid-template-columns:1fr;}.video-proof-text strong{white-space:nowrap;}}


/* ── Boxed accents on light bands ──
   .boxed is inked for a dark band. On the light sections it takes the
   deep teal the cream statements use. ── */
.engines .boxed,
.mon-track .boxed,
.audit-section .boxed,
.pack-section .boxed,
.work-section .boxed,
.testi-section .boxed,
.lg-body .boxed{
  border-color:var(--teal-ink);
  color:var(--teal-ink);
  box-shadow:7px 7px 0 rgba(11,138,130,0.14);
}

/* ═══════════════════════════════════════════════════════════════
   PHONE HEROES READ CENTERED
   On a desktop the hero copy sits left with a panel or a photo on
   its right. On a phone that right side stacks underneath or goes
   away, and a left-aligned block under a centered logo and over
   full-width buttons read as off-balance. Below 768px every interior
   hero centers its eyebrow, headline, copy, buttons and proof line.
   Text alignment only: grids and flex rows keep their shape, and a
   side panel that stacks underneath is unaffected.
   ═══════════════════════════════════════════════════════════════ */
@media (max-width:768px){
  .hero > .container,
  .hero-wrap > .container,
  .loc-hero > .container,
  .ind-hero > .container,
  .faqhub-hero > .container,
  .hero-inner,
  .hero-copy{text-align:center;}
  .hero .crumbs,
  .hero-wrap .crumbs,
  .loc-hero .crumbs,
  .ind-hero .crumbs,
  .faqhub-hero .crumbs{justify-content:center;}
  .hero .hero-btns,
  .hero-wrap .hero-btns,
  .loc-hero .hero-btns,
  .ind-hero .hero-btns,
  .faqhub-hero .hero-btns{justify-content:center;}
  .hero .hero-p,
  .hero-wrap .hero-p,
  .loc-hero .hero-p,
  .ind-hero .hero-p,
  .faqhub-hero .hero-p{margin-left:auto;margin-right:auto;}
  .aiopt-proof{justify-content:center;}
  .aiopt-proof-item{justify-content:center;}
  /* The rank chip overlaps the SERP card's left corner on a desktop;
     over a centered column it sits in the middle. */
  .aio-serp-badge{left:50%;transform:translateX(-50%);white-space:nowrap;}
}
