/* ═════════════════════════════════════════════════════════════
   SEO LOCALE — GLOBAL STYLES
   Loaded on every page: base, buttons, top-bar, nav, footer,
   mobile drawer, reveal animation, responsive.
   ═════════════════════════════════════════════════════════════ */

/* ── SELF-HOSTED URBANIST ──
   Six weights (Latin subset). Files originally pulled from the
   @fontsource/urbanist package (Apache 2.0; sourced from Google Fonts).
   Loaded with font-display:swap so text renders immediately in the
   system fallback and re-paints once the WOFF2 arrives.
   font-style:italic is intentionally omitted — the theme uses
   synthetic italics (browser-skewed) for the few italic spots,
   matching the existing site behavior. */
@font-face{
  font-family:'Urbanist';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('../fonts/urbanist-latin-400-normal.woff2') format('woff2');
}
@font-face{
  font-family:'Urbanist';
  font-style:normal;
  font-weight:600;
  font-display:swap;
  src:url('../fonts/urbanist-latin-600-normal.woff2') format('woff2');
}
@font-face{
  font-family:'Urbanist';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('../fonts/urbanist-latin-700-normal.woff2') format('woff2');
}
@font-face{
  font-family:'Urbanist';
  font-style:normal;
  font-weight:800;
  font-display:swap;
  src:url('../fonts/urbanist-latin-800-normal.woff2') format('woff2');
}
@font-face{
  font-family:'Urbanist';
  font-style:normal;
  font-weight:900;
  font-display:swap;
  src:url('../fonts/urbanist-latin-900-normal.woff2') format('woff2');
}

/* ── ARCHIVO BLACK (display) + SPACE MONO (labels) ──
   The V6 concept's voice: uppercase Archivo Black for display
   headlines and Space Mono for kickers, labels, and fine print.
   Latin subsets, self-hosted (OFL). Referenced by the homepage
   (and future V6-styled templates) via the --disp / --mono2
   tokens below; pages that never use them download nothing. */
@font-face{
  font-family:'Archivo Black';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('../fonts/archivo-black-latin-normal.woff2') format('woff2');
}
@font-face{
  font-family:'Space Mono';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('../fonts/space-mono-latin-400-normal.woff2') format('woff2');
}
@font-face{
  font-family:'Space Mono';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('../fonts/space-mono-latin-700-normal.woff2') format('woff2');
}

/* ── INSTRUMENT SERIF ITALIC (serif accent) ──
   Latin subset, italic 400 — the face's only weight (sourced
   from Google Fonts; OFL). The elegant editorial italic used
   for highlighted words inside headlines via .script-accent —
   the same accent voice as the Concept V6 mockups. Browsers
   don't download it on pages that never render the class, so
   pages without highlights pay zero font cost. */
@font-face{
  font-family:'Instrument Serif';
  font-style:italic;
  font-weight:400;
  font-display:swap;
  src:url('../fonts/instrument-serif-latin-italic.woff2') format('woff2');
}

/* ── Metric-matched fallbacks ──
   Every web font above swaps in over a system font, and the system
   font is a different width: a headline in Arial is 12% narrower
   than in Archivo Black, so when Archivo arrives the headline grows,
   wraps differently, and pushes everything under it down. That was
   a 0.20 layout shift on the homepage hero. These faces wrap the
   system fonts with size-adjust and vertical overrides so the
   fallback occupies the same space the web font will, and the swap
   changes the letterforms but moves nothing. Ratios were measured
   by rendering the same strings in both fonts (Liberation Sans /
   Mono / Serif are metric-identical to Arial / Courier New / Times
   New Roman). Vertical overrides are the web font's hhea metrics
   divided by size-adjust. ── */
@font-face{
  font-family:'Archivo Black Fallback';
  font-style:normal;font-weight:400;
  src:local('Arial Bold'),local('Arial-BoldMT'),local('Helvetica Bold'),local('Helvetica-Bold'),local('Arial');
  size-adjust:111.9%;ascent-override:78.5%;descent-override:18.8%;line-gap-override:0%;
}
@font-face{
  font-family:'Space Mono Fallback';
  font-style:normal;font-weight:400;
  src:local('Courier New'),local('CourierNewPSMT'),local('Courier');
  size-adjust:102%;ascent-override:109.8%;descent-override:35.4%;line-gap-override:0%;
}
@font-face{
  font-family:'Space Mono Fallback';
  font-style:normal;font-weight:700;
  src:local('Courier New Bold'),local('CourierNewPS-BoldMT'),local('Courier Bold'),local('Courier New');
  size-adjust:102%;ascent-override:109.8%;descent-override:35.4%;line-gap-override:0%;
}
@font-face{
  font-family:'Urbanist Fallback';
  font-style:normal;font-weight:400;
  src:local('Arial'),local('ArialMT'),local('Helvetica');
  size-adjust:97.4%;ascent-override:97.5%;descent-override:25.7%;line-gap-override:0%;
}
@font-face{
  font-family:'Urbanist Fallback';
  font-style:normal;font-weight:600;
  src:local('Arial'),local('ArialMT'),local('Helvetica');
  size-adjust:101%;ascent-override:94.1%;descent-override:24.8%;line-gap-override:0%;
}
@font-face{
  font-family:'Urbanist Fallback';
  font-style:normal;font-weight:700;
  src:local('Arial Bold'),local('Arial-BoldMT'),local('Helvetica Bold'),local('Helvetica-Bold');
  size-adjust:91.1%;ascent-override:104.3%;descent-override:27.4%;line-gap-override:0%;
}
@font-face{
  font-family:'Urbanist Fallback';
  font-style:normal;font-weight:800;
  src:local('Arial Bold'),local('Arial-BoldMT'),local('Helvetica Bold'),local('Helvetica-Bold');
  size-adjust:92.6%;ascent-override:102.6%;descent-override:27%;line-gap-override:0%;
}
@font-face{
  font-family:'Urbanist Fallback';
  font-style:normal;font-weight:900;
  src:local('Arial Bold'),local('Arial-BoldMT'),local('Helvetica Bold'),local('Helvetica-Bold');
  size-adjust:93.7%;ascent-override:101.4%;descent-override:26.7%;line-gap-override:0%;
}
@font-face{
  font-family:'Instrument Serif Fallback';
  font-style:italic;font-weight:400;
  src:local('Times New Roman Italic'),local('TimesNewRomanPS-ItalicMT'),local('Times Italic'),local('Times-Italic'),local('Times New Roman');
  size-adjust:89.2%;ascent-override:111%;descent-override:34.8%;line-gap-override:0%;
}

/* Serif-italic highlight word inside a headline:
 *   <h2>Results we'd put our <em class="script-accent">name</em> on.</h2>
 * The 1.1em scale is calibrated so the serif's lowercase height
 * optically matches the surrounding Urbanist. Weight stays 400 —
 * it's the face's only weight; synthetic bolding would muddy the
 * strokes. Color defaults to the teal accent and can be
 * overridden by section-scoped rules (e.g. cream sections use a
 * darker teal for contrast). One word per headline, max. */
.script-accent{
  font-family:'Instrument Serif','Instrument Serif Fallback',serif;
  font-style:italic;
  font-weight:400;
  font-size:1.1em;
  line-height:1;
  letter-spacing:0;
  /* Stays lowercase inside the uppercase Archivo Black display
   * headlines — that contrast is the whole V6 move. */
  text-transform:none;
  padding:0 0.04em;
  /* Opt out of the site-wide gradient-text treatment on heading
   * <em> (the `h1 em, h2 em, h3 em` rule below) — the script
   * accent replaces the gradient look, so the background clip is
   * reset and the color needs its own !important to beat that
   * rule's `color:transparent !important`. Section-scoped color
   * overrides (e.g. cream bands) must also carry !important. */
  background:none;
  -webkit-background-clip:initial;
  background-clip:initial;
  color:var(--teal) !important;
}

:root{
  --teal:#16C0B7;--teal-dim:rgba(22,192,183,0.1);--teal-glow:rgba(22,192,183,0.35);
  --navy:#213E59;--navy-deep:#0d1f2d;
  --obsidian:#050b12;--surface:#0c1a26;--surface2:#0f2133;
  --text:#F8FAFC;--muted:#dfeffd;--border:rgba(22,192,183,0.13);
  --font:'Urbanist','Urbanist Fallback',sans-serif;

  /* Two-color accent system. Teal stays the interaction color
   * (links, buttons, hover states, anything clickable) and the
   * warm amber takes over for data — stats, metric numbers,
   * achievement badges, hero highlights, anywhere a number or
   * "this is impressive" needs to land. The split gives the
   * design two distinct visual roles so it stops feeling
   * monochromatic. */
  /* Gradient text token — teal → sky. Applied to heading <em>
   * tags and stat numbers via background-clip:text. The team
   * prefers this over solid amber or solid teal on accents. */
  --text-grad:linear-gradient(135deg, #16C0B7 0%, #7dd3fc 100%);
  --accent:#16C0B7;
  --accent-glow:rgba(22,192,183,0.35);

  /* Display font for statistics — a monospace system stack
   * (SF Mono / JetBrains Mono / Cascadia / Menlo / Consolas)
   * that reads as "data / scoreboard" and is visibly distinct
   * from the Urbanist body font. Zero webfont load — every
   * modern OS has at least one font in this stack installed.
   *
   * Applied to every big-number element via the stat rollup
   * selector just below :root. */
  --display-stat:ui-monospace,'SF Mono','JetBrains Mono','Cascadia Mono',Menlo,Consolas,monospace;

  /* ── LIGHT SECTION TOKENS ──
   * Light bands that break up the dark base so pages alternate
   * instead of running obsidian top to bottom. Ink is the
   * navy-leaning text color for copy on them; --teal-ink is a
   * darkened accent that keeps AA contrast where the brand teal
   * (#16C0B7) would wash out on a light background. Shared here so
   * the homepage and interior templates use identical values.
   *
   * These were warm — cream #F6F1E7 over beige #E7DECB — and the
   * names stuck around after the colors went cool, because they
   * are referenced from four stylesheets and forty templates.
   * Read "cream" and "sand" as "light band A" and "light band B".
   *
   * The two bands are one cool value and white, and they INVERT:
   * band A is tinted with white cards, band B is white with tinted
   * cards. That keeps a card legible on either one, and keeps two
   * light bands distinguishable from each other by more than the
   * ~4/255 that separates their backgrounds. */
  /* The full team photo. Declared once here and referenced by every
   * section that uses it as a ground, so a new shoot is a one-line
   * change rather than a search across four stylesheets. */
  /* ── ACCENT PALETTE ──
   * Hoisted from the per-page stylesheets, where each of ~20 files
   * declared its own identical copy. The accent utility classes at
   * the bottom of this file reference these, and a class in
   * global.css cannot depend on a token that only exists in some
   * page's stylesheet — .chip-red-soft rendered colorless on
   * AI Overviews for precisely that reason.
   *
   * Values verified identical in every file that declared them
   * before being hoisted; the page copies still win where present,
   * so nothing downstream changes. */
  /* Declared by nine page stylesheets and by none of ours, so any
   * page that used var(--mono) without its own copy fell back to
   * nothing. Same shape as the --red bug. */
  --mono:'JetBrains Mono',monospace;
  --green:#34d399;
  --red:#f87171;
  --amber:#fbbf24;
  --purple:#a78bfa;
  --blue:#60a5fa;
  --pink:#f472b6;
  --orange:#fb923c;
  --team-photo:url('../img/team-photo.webp');
  --work-photo:url('/wp-content/uploads/2026/08/seo-team-working.jpg');
  /* The developers at work — 2000px wide, so it holds up as a
   * full-bleed hero as well as a statement band. Used on the pages
   * about how the work gets built rather than the ones about search. */
  --dev-photo:url('/wp-content/uploads/2026/08/devs-working.jpg');
  /* The office set. Registered as tokens so any template can reach
     them the way it reaches the team and dev photos, rather than
     each one hardcoding an uploads path that breaks on a migration.
     The exterior is the one built for hero and statement duty — it
     is the widest of the set and has sky at the top, so a scrim over
     it keeps a headline readable where an interior shot would not. */
  --office-photo:url('/wp-content/uploads/2026/08/office-outside.jpg');
  --workspace-photo:url('/wp-content/uploads/2026/08/open-workspace.jpg');
  --podcast-photo:url('/wp-content/uploads/2026/08/podcast.jpg');
  --arcade-photo:url('/wp-content/uploads/2026/08/arcade-machine.jpg');
  --greenscreen-photo:url('/wp-content/uploads/2026/08/green-screen.jpg');
  --cream:#F4F7FB;
  --cream-card:#FFFFFF;
  --sand:#FFFFFF;
  --sand-card:#F4F7FB;
  --ink:#1E3448;
  --ink-soft:rgba(30,52,72,0.72);
  /* Was 0.5, which composites to rgb(137,150,162) on a light band —
   * 2.87:1 on white, well under AA, and every use of this token is
   * small text: fact labels, testimonial roles, the client-strip
   * label, price footnotes. 0.68 clears 4.5:1 on both light bands
   * while staying visibly lighter than --ink-soft, which is the
   * distinction the token exists to make. */
  --ink-faint:rgba(30,52,72,0.68);
  /* Darkened from #0B8A82. On the lighter of the two warm bands it
   * measured 3.93:1 against small text — under the 4.5:1 floor. This
   * value clears 4.5 on cream (4.74) and on sand (4.97). */
  --teal-ink:#0A7870;

  /* V6 type-system tokens (see @font-face block above). */
  --disp:'Archivo Black','Archivo Black Fallback',sans-serif;
  --mono2:'Space Mono','Space Mono Fallback',ui-monospace,monospace;

  /* One button shape for the whole site. The nav's "Get a
   * Proposal" sticker button set the standard — rounded
   * rectangle, not a pill — so every .btn now matches it and
   * page-level pill overrides lose the cascade. */
  --btn-radius:12px;
}

/* Stat number display treatment — applied to every large
 * metric / number element across the homepage, service
 * pages, about page, and interior templates. Uses the
 * monospace --display-stat stack for distinctive editorial
 * contrast against the Urbanist body font, plus tabular
 * lining numerals so different numbers line up vertically
 * in a grid of stat cards (e.g. "+138%" and "+271%" have
 * identical digit widths). */
.hero-stat-val,
.ft-metric-big,
.cs-stat-number,
.a-stat-n,
.ss-n,
.ms-stat-val,
.metric-num,
.stat-val,
.big-num{
  font-family:var(--display-stat);
  font-feature-settings:"tnum" 1, "lnum" 1;
  letter-spacing:-1.5px;
  font-weight:800;
}
*{margin:0;padding:0;box-sizing:border-box;}
html{scroll-behavior:smooth;}

/* ── BODY + SUBTLE GRAIN TEXTURE ──
 *
 * Layers a whisper-thin SVG fractal-noise pattern on top of
 * the obsidian background via background-image + blend-mode.
 * No pseudo-element, no z-index gymnastics — the grain lives
 * on the body's own background so it's guaranteed to sit
 * behind every piece of content without fighting section
 * stacking contexts.
 *
 * Why it matters against the "AI-generated design" tell:
 * perfectly flat color fields are a dead giveaway that a
 * machine did the comping. Real photos, real print, and
 * every hand-designed landing page of the last 10 years has
 * SOME grain — even if you don't consciously notice it.
 * Apple, Vercel, Anthropic, and Stripe all use variants of
 * this trick on their dark marketing sites.
 *
 * The noise is inlined as an SVG data URI (no extra HTTP
 * request) at 220×220 tile, soft-light blended at a very
 * low perceived intensity — below-threshold for conscious
 * perception, you only notice when it's removed.
 *
 * prefers-contrast: more drops the grain entirely so
 * high-contrast-mode users aren't fighting a noise texture
 * against their accessibility settings. Many sections have
 * their own background color — in those cases the grain
 * lives only in the body gaps (between sections), so it
 * reads as ambient atmosphere rather than overlay.
 */
body{
  font-family:var(--font);
  color:var(--text);
  overflow-x:clip;
  font-size:19px;line-height:1.65;font-weight:400;
  background-color:var(--obsidian);
  background-image:url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 220 220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.4 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-repeat:repeat;
  background-size:220px 220px;
  background-blend-mode:soft-light;
}
@media (prefers-contrast: more){
  body{background-image:none;}
}

/* ── LAYOUT ── */
.container{max-width:1360px;margin:0 auto;padding:0 2.5rem;}
/* Header + footer use a wider container so the chrome
 * doesn't feel cramped on big monitors. Matched widths
 * (1600px) so the top and bottom of the page line up.
 * Earlier iteration used max-width:none for the footer
 * (true full bleed) but on 27"+ monitors the content
 * columns stretched uncomfortably wide.
 * The global 1360 .container stays as-is because every
 * other section was composed against that measure. */
#main-nav > .container{max-width:1600px;}
.site-footer > .container{max-width:1600px;}
.section-pad{padding:100px 0;}
/* Mobile section rhythm.
 *
 * 100px of padding at each end of a section is right on a 1440px
 * screen and wrong on a 390px one, where it is a fifth of the
 * viewport at every boundary — with fourteen sections that alone
 * was several screens of nothing. The homepage measured 23.5 screens
 * tall on a phone against 15.4 on desktop, and this was most of the
 * difference.
 *
 * Applies site-wide: the interior templates use .section-pad too,
 * and their own bespoke section paddings are clamped, so they
 * already scale. This is the one that was not. */
@media (max-width:760px){
  .section-pad{padding:54px 0;}
}
/* Mobile side gutters.
 *
 * The same argument horizontally: 2.5rem on each side is 80px of a
 * 390px viewport, so a fifth of every phone screen was gutter and
 * every line of copy was set 20% narrower than it needed to be. The
 * hero eyebrow ("SEO · Paid Media · Web Design — Philadelphia")
 * wrapped to two lines purely because of it. 20px still reads as a
 * margin and is the width most phone layouts settle on. */
@media (max-width:600px){
  .container{padding:0 1.25rem;}
}
.section-sm{padding:72px 0;}
.center{text-align:center;}
.section-h{font-size:clamp(34px,4vw,54px);font-weight:900;margin-bottom:14px;letter-spacing:-0.5px;}
.section-sub{color:var(--muted);font-size:18px;font-weight:400;line-height:1.7;max-width:620px;}
.section-head{margin-bottom:56px;}
.section-head.center .section-sub{margin:0 auto;}
/* Eyebrow — plain uppercase marker, no pill.
 *
 * Every page CSS file (extracted from the standalone mockups)
 * has its own .eyebrow + .eyebrow-t variants that wrap the
 * label in a rounded pill with a teal-tinted bg and border.
 * That "chip" treatment is a classic AI-generated design tell
 * — every Lovable / v0 / Cursor-AI landing page has it.
 *
 * These rules use !important on the bg / border / padding so
 * they win the cascade no matter where in the page CSS layer
 * the conflicting rule lives. The label becomes what it should
 * be: a plain uppercase marker above the H2, not a decorative
 * chip. */
.eyebrow,
.eyebrow-t{
  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;
  color:var(--teal);
  margin-bottom:14px;
  background:none !important;
  border:none !important;
  padding:0 !important;
  border-radius:0 !important;
}
/* Hexagon marker in place of the old icon — the brand mark used
 * as punctuation. currentColor keeps it correct on dark and
 * cream bands alike. */
.eyebrow::before,
.eyebrow-t::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%);
}
/* Drop the optional icon inside eyebrow labels — on a plain
 * text label, a leading icon reads as decoration and brings
 * back the chip feel. Leaving the <i> in the markup so future
 * edits can re-enable it per-page by overriding the rule. */
.eyebrow > i,
.eyebrow-t > i{display:none;}
h1,h2,h3,h4,h5,h6{font-family:var(--font);line-height:1.1;font-weight:900;}
/* Heading accent — site-wide. The highlighted phrase inside a
 * heading renders in Instrument Serif italic against the heavy
 * display sans around it. This replaces the old teal-to-sky
 * gradient fill, which read as an AI-template tell and clashed
 * with the accent treatment used on the homepage.
 *
 * !important on the color is inherited from the rule this
 * replaces: dozens of per-page CSS files set color:var(--teal)
 * on individual h2-em selectors at (0,1,1) specificity, and
 * this needs to beat all of them without editing 30+ files.
 * Section-scoped overrides (cream bands) must therefore also
 * carry !important — see .il-warm below. */
h1 em, h2 em, h3 em{
  font-family:'Instrument Serif','Instrument Serif Fallback',serif;
  font-style:italic;
  font-weight:400;
  font-size:1.1em;
  line-height:1;
  letter-spacing:0;
  text-transform:none;
  background:none;
  -webkit-background-clip:initial;
  background-clip:initial;
  color:var(--teal) !important;
}

/* ── FAQ TOGGLE ──
 * The hexagon badge, promoted site-wide from the Local SEO page
 * where it was a one-off. Replaces the bare "+" glyph so the
 * accordion carries the brand mark like the eyebrows and seam
 * markers do. Rotating 45deg on open turns the plus into a
 * cross and stands the hexagon on its point. */
.faq-plus{
  width:30px;height:34px;flex-shrink:0;
  clip-path:polygon(50% 0%,100% 25%,100% 75%,50% 100%,0% 75%,0% 25%);
  background:rgba(22,192,183,0.12);
  display:flex;align-items:center;justify-content:center;
  color:var(--teal);
  font-size:14px;font-weight:400;line-height:1;
  transition:transform 0.3s ease,background 0.3s ease,color 0.3s ease;
}
.faq-item.open .faq-plus{
  transform:rotate(45deg);
  background:var(--teal);
  color:#050b12;
}

/* ── BUTTONS ── */
.btn{display:inline-flex;align-items:center;gap:10px;font-family:var(--font);font-weight:800;font-size:16px;border:none;cursor:pointer;text-decoration:none;transition:all 0.25s ease;border-radius:var(--btn-radius);padding:15px 32px;}

/* Primary "Get a Proposal" button — sticker style.
 *
 * Hand-designed press-into-shadow effect instead of the flat
 * teal fill with ambient glow. Three reasons to use this
 * pattern here:
 *
 *   1. It's distinctive. Modern but not AI-default — you
 *      don't see it on every ChatGPT-generated landing page,
 *      but Notion, Linear, and most indie-agency sites use
 *      variants of it. Reads as "a human picked this."
 *
 *   2. The tactile affordance is real. Clicking physically
 *      moves the button INTO its shadow — a metaphor the
 *      user recognizes without thinking. Compare to a
 *      flat hover glow which communicates nothing about
 *      what clicking does.
 *
 *   3. It still works on every background. The offset
 *      shadow is obsidian so it casts on any light hero
 *      tone; on dark heroes it reads as a subtle pressed
 *      border. The gradient-free fill means no AI shimmer.
 *
 * The arrow icon inside the button slides 3px right on
 * hover — a classic "proceed" cue, composed on top of the
 * parent's press transform so both motions play together.
 */
.btn-primary{
  position:relative;
  background:var(--teal);
  color:var(--navy-deep);
  border:2px solid var(--teal);
  box-shadow:4px 4px 0 0 rgba(5,11,18,0.85);
  transition:transform 0.18s cubic-bezier(0.2,0,0,1), box-shadow 0.18s cubic-bezier(0.2,0,0,1), background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
  will-change:transform;
}
.btn-primary i{
  transition:transform 0.25s cubic-bezier(0.2,0,0,1);
}
/* The fill lightens on hover, so the label goes the other way:
 * down from --navy-deep to the obsidian the rest of the palette
 * uses, which takes the contrast from 9.0:1 to 10.6:1 and makes
 * the text sharpen as the background brightens rather than sit
 * still. The per-page stylesheets already set the resting label
 * to #050b12, so this is the one place where the hover color
 * has anything to move. */
.btn-primary:hover{
  background:#1ad4ca;
  border-color:#1ad4ca;
  color:#050b12;
  transform:translate(2px,2px);
  box-shadow:2px 2px 0 0 rgba(5,11,18,0.85);
}
.btn-primary:hover i{
  transform:translateX(3px);
}
.btn-primary:active{
  transform:translate(4px,4px);
  box-shadow:0 0 0 0 rgba(5,11,18,0.85);
}
.btn-ghost{background:transparent;color:var(--text);border:2px solid rgba(248,250,252,0.2);}
.btn-ghost:hover{border-color:var(--teal);color:var(--teal);}

/* ══════════════════════════════════════════════════
   ACCESSIBILITY — skip link + focus-visible defaults
   ══════════════════════════════════════════════════
   Skip link is visually offscreen until it gets keyboard focus,
   then it slides into the top-left corner so screen-reader and
   keyboard-only users can jump straight to #main.

   :focus-visible adds the teal ring on every interactive element
   for keyboard users while leaving mouse-click focus alone.
*/
.skip-link{
  position:fixed;top:-100px;left:8px;z-index:9999;
  padding:12px 20px;border-radius:8px;
  background:var(--teal);color:#050b12;
  font-family:var(--font);font-weight:800;font-size:14px;
  text-decoration:none;
  box-shadow:0 8px 24px rgba(0,0,0,0.4);
  transition:top 0.2s ease;
}
.skip-link:focus,.skip-link:focus-visible{top:8px;outline:none;}

#main{outline:none;}

:focus-visible{
  outline:2px solid var(--teal);
  outline-offset:3px;
  border-radius:3px;
}
.btn:focus-visible,
.nav-item-btn:focus-visible,
.mob-toggle:focus-visible,
.mob-close:focus-visible,
.mob-acc-toggle:focus-visible,
.mega-link:focus-visible,
.mob-link:focus-visible,
.mob-sublink:focus-visible{
  outline:2px solid var(--teal);
  outline-offset:3px;
  box-shadow:0 0 0 4px rgba(22,192,183,0.18);
}
/* Mouse users (no keyboard focus) shouldn't see the ring on click. */
.btn:focus:not(:focus-visible),
.nav-item-btn:focus:not(:focus-visible),
.mob-toggle:focus:not(:focus-visible),
.mob-acc-toggle:focus:not(:focus-visible){outline:none;box-shadow:none;}

/* ══════════════════════════════════════════════════
   INTERIOR PAGE BREADCRUMB
   ══════════════════════════════════════════════════
   Consolidated from 14 per-page CSS files that each had an
   identical .crumbs block. The only per-page variation was the
   accent color on the current-page label — that's now driven by
   the `--crumb-accent` custom property, which per-page CSS can
   override via a body rule (see pages/instagram.css, podcast.css,
   hosting.css, youtube.css).

   Padding clearance: top-bar (0–40) + fixed nav (36–106) combined
   with the nav's `box-shadow:0 12px 40px rgba(0,0,0,0.5)` bleeds
   visually to about y=150. 140px top padding places the breadcrumb
   text well clear of the shadow zone (~34px safety margin). */
.crumbs{padding:140px 0 20px;font-size:13px;color:var(--muted);}
/* Featured-image heroes wash out the muted breadcrumb color —
 * boost contrast with a stronger color + text-shadow so the
 * crumbs remain legible over any uploaded image. */
.hero-has-image .crumbs,
.loc-hero .crumbs,
.ind-hero.hero-has-image .crumbs{
  color:rgba(255,255,255,0.9);
  text-shadow:0 1px 6px rgba(0,0,0,0.6);
}
.hero-has-image .crumbs a,
.loc-hero .crumbs a,
.ind-hero.hero-has-image .crumbs a{color:rgba(255,255,255,0.9);}
.hero-has-image .crumbs a:hover,
.loc-hero .crumbs a:hover,
.ind-hero.hero-has-image .crumbs a:hover{color:var(--teal);}
.hero-has-image .crumbs i,
.loc-hero .crumbs i,
.ind-hero.hero-has-image .crumbs i{color:rgba(255,255,255,0.7);opacity:0.9;}
.hero-has-image .crumbs span,
.loc-hero .crumbs span,
.ind-hero.hero-has-image .crumbs span{color:var(--teal);text-shadow:0 1px 6px rgba(0,0,0,0.5);}
/* When the breadcrumb lives inside the hero section (the
 * standard layout), the hero's own top padding already
 * partially clears the fixed nav, so the crumbs need less
 * padding-top. z-index:1 sits above the ::before overlay. */
.hero .crumbs{padding-top:110px;position:relative;z-index:1;}
.crumbs a{color:var(--muted);text-decoration:none;}
.crumbs a:hover{color:var(--teal);}
.crumbs i{font-size:9px;margin:0 8px;opacity:0.5;}
.crumbs span{color:var(--crumb-accent,var(--teal));}

/* ══════════════════════════════════════════════════
   INTERIOR HERO — FEATURED-IMAGE BACKGROUND
   ══════════════════════════════════════════════════
   Any interior template can opt into a featured-image hero by:
     1. Setting a Featured Image on the WP page in /wp-admin/
     2. Adding `hero-has-image` to the <section class="hero"> tag
        and an inline `style="background-image:url(...)"` from
        get_the_post_thumbnail_url( get_the_ID(), 'full' )

   The dark vignette + subtle teal radial below keep hero text
   readable on top of any uploaded image. The vignette is darker
   at the top (.88) and bottom (.92) than in the middle (.75) so
   the image peeks through where the eye expects detail and the
   text edges fade into solid darkness.

   Per-page .hero::before accent gradients (e.g. local-seo's
   corner teal/navy radials) get overridden by .hero-has-image's
   higher specificity, so this class also acts as a clean reset
   for the hero background.
*/
/* ── HERO COPY SITS HIGH ──
   Every interior hero is a two-column grid with align-items:center
   and a tall demo on the right (a state card, a toggle, then a
   simulated pack, profile or SERP). Centering put the eyebrow level
   with the demo's middle and the headline a screen below its head.
   Above the stacking breakpoint the copy column starts at the top
   with a small offset instead, beside the demo's head. Local SEO got
   this first; it belongs to all of them. The attribute selector
   catches .hero-grid, .ind-hero-grid and .aiopt-hero-inner.hero-grid
   alike; stacked layouts (≤960px, see the responsive block) are
   untouched. */
@media(min-width:961px){
  .hero [class*="hero-grid"]:not(.tm-hero-grid) > :first-child,
  .ind-hero [class*="hero-grid"] > :first-child,
  .loc-hero [class*="hero-grid"] > :first-child{
    align-self:start;
    padding-top:clamp(8px,2.5vw,40px);
  }
}
/* Not the team member hero: its first column is the hexagon portrait,
   and padding on it pushed the photo down inside the teal frame so the
   frame read as a thick band along the top edges. */

.hero-has-image{
  position:relative;                /* anchor ::before overlay */
  background-size:cover;
  background-position:center;
  background-repeat:no-repeat;
  isolation:isolate;                /* so the photo's z-index:-1 stays inside */
}
/* The photo itself (inc/hero-image.php, seolocale_hero_img()). A real
   <img> so the browser can fetch it at high priority, pinned under
   the ::before scrim and above the section's own background. The
   .hero-wrap pages place theirs the same way, below their z-index:1
   scrim and clear of the z-index:3 the page CSS gives their copy. */
.hero-has-image > .hero-photo,
.hero-wrap > .hero-photo{
  position:absolute;inset:0;z-index:-1;
  width:100%;height:100%;max-width:none;margin:0;
  object-fit:cover;object-position:center;
  border-radius:0;pointer-events:none;user-select:none;
}
.hero-wrap{isolation:isolate;}
.hero-wrap > .hero-photo{object-position:center 62%;}
/* An image that states its size (width + height attributes) only
   states its ratio: the stylesheet still decides the box, and a
   CSS width never squashes it against an attribute height. Zero
   specificity so every class rule wins. */
:where(img[width][height]){height:auto;}
.hero-has-image::before{
  content:'';position:absolute;inset:0;
  background:
    radial-gradient(ellipse 60% 50% at 50% 60%, rgba(22,192,183,0.06), transparent 60%),
    linear-gradient(180deg, rgba(5,11,18,0.88) 0%, rgba(5,11,18,0.75) 40%, rgba(5,11,18,0.92) 100%);
  pointer-events:none;
  z-index:0;
}

/* ══════════════════════════════════════════════════
   WORDPRESS ADMIN BAR COMPATIBILITY
   ══════════════════════════════════════════════════
   Logged-in users see WP's admin bar — 32px on desktop, 46px
   on screens ≤782px. WP adds `html{margin-top:32px!important}`
   and a `.admin-bar` class on body, but our theme's fixed
   top-bar and nav are positioned in viewport coordinates, so
   they sit underneath the admin bar until we push them down.

   The numbers:
     body.admin-bar .top-bar       → top: 32px (was 0)
     body.admin-bar nav            → top: 68px (32 + original 36)
     body.admin-bar #main-nav.scrolled  → top: 32px (sticks under admin bar)
*/
body.admin-bar .top-bar{top:32px;}
body.admin-bar #main-nav{top:68px;}
body.admin-bar #main-nav.scrolled{top:68px;}
@media screen and (max-width:782px){
  body.admin-bar .top-bar{top:46px;}
  body.admin-bar #main-nav{top:82px;}
  body.admin-bar #main-nav.scrolled{top:82px;}
}

/* ══════════════════════════════════════════════════
   TOP BAR — modern gradient announcement strip
   ══════════════════════════════════════════════════ */
.top-bar{
  position:fixed;top:0;left:0;width:100%;z-index:310;
  height:40px;
  background:linear-gradient(90deg, #011931 0%, #0a2947 40%, #083152 70%, #011931 100%);
  border-bottom:1px solid rgba(22,192,183,0.18);
  display:flex;align-items:center;
  transition:transform 0.35s ease;
}
.top-bar.hidden{transform:translateY(-100%);}
.top-bar-inner{
  display:flex;align-items:center;justify-content:space-between;
  width:100%;padding:0 2.5rem;max-width:1600px;margin:0 auto;
}

/* Left: credibility row — clean inline icons.
 *
 * Restraint pass after iterating through boxed chips, full-
 * height tilted icons, and clipped bleed-bounds. The right
 * answer was the simplest one: inline glyphs at label size,
 * brand-tinted per badge, opacity tuned to feel like part of
 * the label rather than a separate element.
 *
 * No tilt, no box, no bleed — just a quiet proof-marker row
 * that lets the labels do the work. */
.top-bar-left{display:flex;align-items:center;gap:24px;}
.tb-pill{
  display:inline-flex;align-items:center;gap:8px;
  font-size:11px;font-weight:700;color:rgba(248,250,252,0.85);
  padding:0;background:transparent;border:none;
  white-space:nowrap;letter-spacing:0.02em;
  transition:color 0.2s;
}
.tb-pill:hover{color:#fff;}
.tb-pill > i{
  font-size:13px;
  line-height:1;
  background:none;
  border:none;
  padding:0;
  width:auto;height:auto;
  opacity:0.9;
  transition:opacity 0.2s ease;
}
.tb-pill:hover > i{opacity:1;}
/* Per-badge brand color on the icon only — gives the row
 * subtle personality without adding any chip chrome. */
.tb-pill:nth-child(1) > i{color:#fbbf24;}
.tb-pill:nth-child(3) > i{color:#4285F4;}
.tb-pill:nth-child(5) > i{color:#16C0B7;}
.tb-pill:nth-child(7) > i{color:#fb923c;}
.tb-pill .tb-stars{color:#fbbf24;letter-spacing:1.5px;font-size:11px;}
.tb-sep{width:1px;height:14px;background:rgba(255,255,255,0.1);margin:0;flex-shrink:0;align-self:center;}

/* Right: socials + login */
.top-bar-right{display:flex;align-items:center;gap:12px;}

.tb-socials{display:flex;align-items:center;gap:2px;}
.tb-soc{
  width:30px;height:30px;border-radius:7px;
  display:flex;align-items:center;justify-content:center;
  color:rgba(248,250,252,0.5);font-size:13px;
  text-decoration:none;
  transition:all 0.2s;
}
.tb-soc:hover{color:#fff;background:rgba(255,255,255,0.12);}
/* Brand colors on hover */
.tb-soc.fb:hover{color:#1877f2;background:rgba(24,119,242,0.15);}
.tb-soc.ig:hover{color:#e1306c;background:rgba(225,48,108,0.15);}
.tb-soc.li:hover{color:#0a66c2;background:rgba(10,102,194,0.15);}
.tb-soc.yt:hover{color:#ff0000;background:rgba(255,0,0,0.12);}
.tb-soc.tw:hover{color:#fff;background:rgba(255,255,255,0.15);}

.tb-sep-v{width:1px;height:20px;background:rgba(255,255,255,0.12);}

.tb-login{
  display:flex;align-items:center;gap:6px;
  font-size:11px;font-weight:800;
  color:var(--teal);
  text-decoration:none;
  padding:5px 12px;border-radius:6px;
  border:1px solid rgba(22,192,183,0.35);
  background:rgba(22,192,183,0.08);
  letter-spacing:0.04em;text-transform:uppercase;
  transition:all 0.2s;white-space:nowrap;
}
.tb-login i{font-size:10px;}
.tb-login:hover{background:rgba(22,192,183,0.18);border-color:var(--teal);color:#fff;}

/* Simplified top bar — one credential rather than a badge wall.
 * The Google Partner / Inc. 5000 / Philly Fast 50 chips that used
 * to sit beside this were four competing claims above the fold;
 * they now live on the homepage hero and the awards page where
 * they have room to mean something. .tb-pill / .tb-sep survive
 * below for any template still rendering them. */
.tb-rating{
  display:inline-flex;
  align-items:center;
  gap:10px;
  text-decoration:none;
  color:rgba(223,239,253,0.82);
  font-size:13px;
  font-weight:600;
  transition:color 0.2s;
}
.tb-rating:hover{color:var(--text);}
.tb-rating .tb-stars{color:#F4B400;letter-spacing:1px;font-size:12px;}
.tb-rating strong{color:var(--text);font-weight:800;}

/* ══════════════════════════════════════════════════
   MAIN NAV — two states: dark (top) + white (scrolled)
   ══════════════════════════════════════════════════ */
/* NOTE: these rules are intentionally scoped to #main-nav rather than
 * the bare `nav` element. Any other <nav> on the page (breadcrumbs,
 * the mobile drawer's inner nav, future widgets) must NOT inherit the
 * fixed positioning, full-width background, blur, or box-shadow —
 * that's what was clobbering the breadcrumb before this scope change. */
#main-nav{
  position:fixed;top:36px;left:0;width:100%;z-index:300;
  /* Opaque, not frosted. At 94% opacity the blur was doing almost
   * nothing visible while the saturate(1.4) tinted whatever scrolled
   * under it — cost without benefit, and the frosted-bar look is the
   * single most recognizable stock-template tell. The inset teal
   * highlight went for the same reason. */
  background:#011931;
  border-bottom:1px solid rgba(255,255,255,0.09);
  box-shadow:0 10px 30px rgba(0,0,0,0.32);
  transition:background 0.35s ease, box-shadow 0.35s ease, border-color 0.35s ease, top 0.35s ease;
}
/* The glowing center-weighted teal hairline under the bar is gone:
 * a rule that fades out at both ends reads as decoration rather than
 * structure. The plain border-bottom above is the divider now. */
#main-nav.scrolled{
  top:36px; /* the top bar stays; the nav keeps its place under it */
  background:#fff;
  border-bottom:1px solid rgba(30,52,72,0.12);
  box-shadow:0 4px 20px rgba(0,0,0,0.09);
}
#main-nav.scrolled::after{display:none;}
.nav-inner{display:flex;align-items:center;justify-content:space-between;height:78px;gap:16px;}

/* LOGO */
.nav-logo{display:flex;align-items:center;text-decoration:none;flex-shrink:0;position:relative;height:46px;min-width:196px;}
.nav-logo img{height:46px;width:auto;max-width:none;transition:opacity 0.3s ease;position:absolute;top:0;left:0;}
/* A phone has no room for the wider mark beside the toggle and the
   phone block; back to the smaller size there. */
@media(max-width:640px){.nav-logo{height:38px;min-width:160px;}.nav-logo img{height:38px;}}
.logo-white{opacity:1;}
.logo-color{opacity:0;}
#main-nav.scrolled .logo-white{opacity:0;}
#main-nav.scrolled .logo-color{opacity:1;}

/* NAV ITEMS — bigger type, no background fill, animated gradient underline */
.nav-items{display:flex;align-items:center;gap:6px;flex:1;justify-content:center;}
.nav-item{position:relative;}

/* Hover bridge — invisible 20px-tall pseudo-element that sticks out
 * BELOW the .nav-item to span the gap between the trigger button
 * and the mega-menu's visual top. Without this the cursor briefly
 * hovers over neither element during the transit and mouseleave
 * fires on .nav-item, scheduling a close that fires before the
 * cursor reaches the mega-menu — that was the "menu sometimes
 * doesn't come up / disappears as I move toward it" bug.
 *
 * Conditioned on :hover / :focus-within / .open so the bridge
 * only exists DURING interaction. When nothing is open, no bridge
 * is rendered and no page content below the nav is blocked from
 * receiving its own click/hover events.
 *
 * Hover persists across frames via :hover bubbling — once the
 * cursor enters the trigger button, .nav-item:hover is true,
 * the bridge renders, and as the cursor traverses the bridge
 * the hover stays true (cursor is still on a descendant of
 * .nav-item), keeping the bridge rendered until the cursor
 * leaves the menu entirely. */
.nav-item:hover::after,
.nav-item:focus-within::after,
.nav-item.open::after{
  content:'';
  position:absolute;
  top:100%;left:-12px;right:-12px;
  height:32px;
  pointer-events:auto;
}

.nav-item-btn{
  position:relative;
  display:flex;align-items:center;gap:7px;
  padding:11px 20px;border-radius:9px;
  font-family:var(--font);font-size:18px;font-weight:700;
  letter-spacing:-0.2px;
  color:rgba(248,250,252,0.92);
  background:none;border:none;cursor:pointer;text-decoration:none;
  transition:color 0.22s ease, transform 0.22s ease;
  white-space:nowrap;
}

/* Animated gradient underline — the only visual hover signal now
 * that the bg fill is gone. 2px teal→sky bar that scaleX(0→1)'s
 * from center. Same gradient as --text-grad on hero H1s, so the
 * nav and the page headlines visually rhyme. scaleX is composite-
 * only so the animation stays GPU-bound and never triggers layout. */
.nav-item-btn::after,
.nav-plain::after{
  content:'';
  position:absolute;
  left:20px;right:20px;bottom:6px;
  height:2px;border-radius:2px;
  background:linear-gradient(90deg,var(--teal) 0%,#7dd3fc 100%);
  transform:scaleX(0);transform-origin:center;
  transition:transform 0.32s cubic-bezier(0.16,1,0.3,1);
  pointer-events:none;
}
.nav-item-btn:hover::after,
.nav-plain:hover::after,
.nav-item.open > .nav-item-btn::after{
  transform:scaleX(1);
}

.nav-item-btn:hover{
  color:#fff;
}
.nav-item.open > .nav-item-btn{
  color:var(--teal);
}
#main-nav.scrolled .nav-item-btn{color:#1a2e42;}
#main-nav.scrolled .nav-item-btn:hover{
  color:var(--teal);
}
#main-nav.scrolled .nav-item.open > .nav-item-btn{
  color:var(--teal);
}

.nav-chevron{
  width:14px;height:14px;flex-shrink:0;opacity:0.6;
  transition:transform 0.25s, opacity 0.2s;
  fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;
}
.nav-item-btn:hover .nav-chevron{opacity:0.95;}
.nav-item.open .nav-chevron{transform:rotate(180deg);opacity:1;}

/* ── MEGA MENU — glassmorphism, wider ──
 *
 * Every selector is scoped under #main-nav to bump specificity
 * from (0,0,1,0) to (0,1,1,0). The 21+ per-page CSS files extracted
 * from the legacy standalone mockups all carry rules like
 *   .nav-items a { color: rgba(248,250,252,0.88); }
 * which has specificity (0,0,1,1). When the mega-menu opens on
 * an interior page, that rule was winning the cascade and turning
 * the dark mega-link text light → invisible against the white
 * mega-menu background. Adding the #main-nav ID ancestor here
 * guarantees these rules always beat any class-only bleed from
 * the page-CSS layer.
 */
#main-nav .mega-menu{
  position:absolute;top:calc(100% + 12px);left:50%;
  transform:translateX(-50%) translateY(-8px);
  /* Solid white with one shadow and a real border. Was a 99%-opaque
   * frosted panel with a white 70% border, a triple box-shadow and an
   * inset white highlight along the top edge — four effects stacked to
   * imitate a pane of glass that nothing behind it was ever visible
   * through. */
  background:#fff;
  border:1px solid rgba(30,52,72,0.12);
  border-radius:14px;
  box-shadow:0 24px 60px rgba(9,25,41,0.18);
  padding:32px 32px 28px;
  /* Always display:flex so flex layout is computed. Hidden via
   * opacity + visibility + pointer-events. The old display:none→flex
   * toggle caused animation restarts and mouse-event flicker. */
  display:flex;gap:0;z-index:400;
  opacity:0;
  visibility:hidden;
  pointer-events:none;
  transition:opacity 0.2s ease,transform 0.2s ease,visibility 0s 0.2s;
}
/* w1 — single-column dropdown (About). Narrower than the multi-column
 * megas and left-aligned to its trigger rather than centered, so it
 * doesn't hang off the edge on the right-hand side of the bar. */
#main-nav .mega-menu.w1{
  min-width:330px;
  left:0;
  transform:translateX(0) translateY(-8px);
}
#main-nav .nav-item.open .mega-menu.w1{transform:translateX(0) translateY(0);}
#main-nav .mega-menu.w1::before{left:44px;transform:none;}
#main-nav .mega-menu.w1 .mega-col{
  padding-right:0;
  margin-right:0;
  border-right:none;
}
/* ── CARD MEGA MENU ──
 * Wide, card-based menu: each column is a bordered card with a
 * titled header and a plain text link list, plus a tinted promo
 * card carrying a real client stat. Denser than the old
 * icon-per-link layout, which lets each menu carry the full
 * service tree instead of a sample of it.
 */
/* The wide menus anchor to the nav bar rather than their trigger:
 * their parent .nav-item drops to position:static, so the menu's
 * containing block becomes #main-nav (position:fixed) and it can
 * center itself across the bar without overflowing the viewport
 * the way a trigger-centered menu does. */
#main-nav .nav-item-wide{position:static;}
#main-nav .mega-menu.mega-wide{
  display:grid;
  grid-auto-flow:column;
  grid-auto-columns:1fr;
  gap:14px;
  left:0;
  right:0;
  margin:0 auto;
  width:max-content;
  max-width:min(1400px,94vw);
  transform:translateX(0) translateY(-8px);
  padding:26px;
  /* A light panel on a dark site is the contrast that makes it pop;
     what it lacked was any texture of its own. The brand hexagon,
     tiled faint in teal, and a soft teal glow in one corner give the
     white cards something to sit on without competing with forty
     links. A photo back here would. */
  background:
    radial-gradient(ellipse 40% 60% at 0% 0%, rgba(22,192,183,0.16), transparent 70%),
    radial-gradient(ellipse 36% 50% at 100% 100%, rgba(22,192,183,0.1), transparent 70%),
    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.14)' stroke-width='1.5'/></svg>") 0 0 / 56px 64px,
    linear-gradient(180deg,#F4F8F9 0%,#EEF4F6 100%);
}
#main-nav .nav-item.open .mega-menu.mega-wide{transform:translateX(0) translateY(0);}
/* No pointer arrow — the menu spans the bar, so an arrow would
 * point at nothing in particular. */
#main-nav .mega-menu.mega-wide::before{display:none;}
#main-nav .mega-card{
  position:relative;
  background:#fff;
  border:1px solid rgba(16,21,27,0.09);
  border-radius:14px;
  padding:20px 20px 14px;
  min-width:252px;
  display:flex;
  flex-direction:column;
  box-shadow:0 10px 30px -18px rgba(16,21,27,0.35);
  transition:transform 0.22s cubic-bezier(0.2,0,0,1),box-shadow 0.22s,border-color 0.22s;
}
/* The column under the cursor lifts and a teal rule draws across its
   top, so the menu answers the hand moving over it. */
#main-nav .mega-card::before{
  content:"";
  position:absolute;left:18px;right:18px;top:-1px;
  height:3px;border-radius:0 0 3px 3px;
  background:var(--teal);
  transform:scaleX(0);
  transform-origin:left;
  transition:transform 0.3s cubic-bezier(0.2,0,0,1);
}
#main-nav .mega-card:hover{
  transform:translateY(-3px);
  border-color:rgba(22,192,183,0.4);
  box-shadow:0 22px 44px -20px rgba(16,21,27,0.45),0 0 0 1px rgba(22,192,183,0.12);
}
#main-nav .mega-card:hover::before{transform:scaleX(1);}
#main-nav .mega-card-head{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:12px;
  margin-bottom:14px;
  padding-bottom:12px;
  border-bottom:1px solid rgba(16,21,27,0.07);
}
/* 17px and 15.5px, up from 15 and 13.5: the dropdown is where a
   visitor picks a service, and its links were the smallest text in
   the header, smaller than the body copy under it. */
#main-nav .mega-card-title{
  font-size:17px;
  font-weight:800;
  letter-spacing:-0.2px;
  color:var(--ink);
  line-height:1.25;
}
#main-nav .mega-card-icon{
  width:34px;height:38px;
  flex-shrink:0;
  display:flex;
  align-items:center;
  justify-content:center;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
  background:var(--teal);
  color:var(--obsidian);
  font-size:14px;
}
#main-nav .mega-card > a{
  display:block;
  font-size:15.5px;
  font-weight:600;
  color:#33475b;
  text-decoration:none;
  padding:8px 8px;
  margin:0 -8px;
  border-radius:8px;
  transition:background 0.15s,color 0.15s,padding-left 0.15s;
}
#main-nav .mega-card > a{position:relative;}
#main-nav .mega-card > a::before{
  content:"";
  position:absolute;left:8px;top:50%;
  width:7px;height:8px;margin-top:-4px;
  background:var(--teal);
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
  opacity:0;
  transform:translateX(-6px);
  transition:opacity 0.15s,transform 0.2s cubic-bezier(0.2,0,0,1);
}
#main-nav .mega-card > a:hover{
  background:rgba(11,138,130,0.08);
  color:var(--teal-ink);
  padding-left:22px;
}
#main-nav .mega-card > a:hover::before{opacity:1;transform:none;}
/* The "view all" line at the foot of a card: teal, a rule above it,
   no hexagon marker since it is not one of the list. */
#main-nav .mega-card > a.mega-card-all{
  margin-top:auto;padding-top:12px;padding-left:8px;
  border-top:1px solid rgba(16,21,27,0.08);border-radius:0;
  font-family:var(--mono2);font-size:11px;font-weight:700;letter-spacing:0.12em;text-transform:uppercase;color:var(--teal-ink);
  display:inline-flex;align-items:center;gap:8px;
}
#main-nav .mega-card > a.mega-card-all::before{display:none;}
#main-nav .mega-card > a.mega-card-all:hover{background:none;padding-left:8px;gap:12px;}
#main-nav .mega-card > a.mega-card-all i{font-size:10px;}
/* Promo card — the one dark tile in the menu.
 *
 * It used to open cold with a bare number while the three cards
 * beside it each had a titled head and a divider, so it read as an
 * afterthought rather than the fourth column. It now takes the same
 * head treatment (label, rule), the number gets a caption so it
 * means something before you read the sentence, and a hexagon
 * watermark gives the empty lower half something to be. */
#main-nav .mega-card.mega-promo{
  position:relative;
  overflow:hidden;
  background:linear-gradient(160deg,#0f2a3d 0%,#0a1a28 100%);
  border-color:rgba(22,192,183,0.35);
  justify-content:flex-start;
  text-align:left;
  min-width:250px;
}
#main-nav .mega-promo > *{position:relative;z-index:1;}
#main-nav .mega-promo::after{
  content:"";
  position:absolute;
  right:-34px;bottom:-40px;
  width:158px;height:180px;
  background:var(--teal);
  opacity:0.07;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
  pointer-events:none;
  z-index:0;
}
/* Photo band across the top of the promo tile. The About menu earns
 * its visual weight from the real team faces below; the other three
 * menus were a stat on a dark rectangle, which left the widest
 * column of the menu as the emptiest thing in it.
 *
 * Negative margins pull the image out through the card's padding so
 * it bleeds to all three edges (the card sets overflow:hidden, so
 * the corner radius still clips it). The gradient over the photo is
 * what lets the label sit under it without a hard horizontal seam.
 *
 * Each <img> carries an onerror that removes this wrapper, so a URL
 * that 404s collapses the band instead of leaving a broken-image
 * glyph in the navigation. */
#main-nav .mega-promo-img{
  position:relative;
  z-index:1;
  margin:-20px -20px 16px;
  height:112px;
  overflow:hidden;
}
#main-nav .mega-promo-img img{
  display:block;
  width:100%;
  height:100%;
  object-fit:cover;
  /* object-position defaults to center, which on a 112px-tall crop of
   * a portrait-ish group shot slices the tops of heads off. Anchoring
   * near the top keeps faces in the band — the gradient below already
   * darkens the lower half where the copy sits, so there is nothing
   * worth protecting down there. */
  object-position:center 22%;
}
#main-nav .mega-promo-img::after{
  content:"";
  position:absolute;
  inset:0;
  background:linear-gradient(180deg,rgba(10,26,40,0.12) 0%,rgba(10,26,40,0.9) 100%);
}
#main-nav .mega-promo-label{
  display:flex;
  align-items:center;
  gap:8px;
  margin-bottom:16px;
  padding-bottom:12px;
  border-bottom:1px solid rgba(22,192,183,0.22);
  font-family:var(--mono2);
  font-size:10px;
  letter-spacing:0.14em;
  text-transform:uppercase;
  color:var(--teal);
}
#main-nav .mega-promo-label::before{
  content:"";
  width:8px;height:9px;
  flex-shrink:0;
  background:var(--teal);
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}
#main-nav .mega-promo-cap{
  font-family:var(--mono2);
  font-size:10px;
  letter-spacing:0.1em;
  text-transform:uppercase;
  color:rgba(223,239,253,0.5);
  margin:-4px 0 14px;
}
/* Hexagon portraits, overlapped into a row — the same motif as the
   homepage faces strip, at menu scale. */
#main-nav .mega-promo-faces{
  display:flex;
  align-items:center;
  margin:0 0 16px;
}
#main-nav .mega-promo-face{
  width:40px;height:46px;
  margin-right:-9px;
  flex-shrink:0;
  padding:2px;
  background:rgba(22,192,183,0.4);
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}
#main-nav .mega-promo-face img{
  width:100%;height:100%;
  object-fit:cover;
  display:block;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}
#main-nav .mega-promo-face-more{
  display:flex;
  align-items:center;
  justify-content:center;
  background:var(--teal);
  color:#052e2c;
  font-family:var(--mono2);
  font-size:11px;
  font-weight:700;
  padding:0;
}
#main-nav .mega-promo-stat{
  font-family:var(--disp,'Urbanist','Urbanist Fallback',sans-serif);
  font-size:44px;
  line-height:1;
  color:var(--teal);
  letter-spacing:-1px;
  margin-bottom:12px;
}
#main-nav .mega-promo-unit{font-size:18px;letter-spacing:0;margin-left:4px;color:var(--teal);}
#main-nav .mega-promo-text{
  font-size:13.5px;
  line-height:1.6;
  color:rgba(223,239,253,0.78);
  margin-bottom:20px;
}
#main-nav .mega-promo-text strong{color:var(--text);font-weight:800;}
/* Card is top-aligned now, so the button pins to the bottom edge
   instead of leaving a gap under it. */
#main-nav .mega-card > a.mega-promo-btn,
#main-nav .mega-promo-btn{margin-top:auto;}
/* Written as `.mega-card > a.mega-promo-btn` on purpose: the
 * generic `#main-nav .mega-card > a` rule above scores (1,1,1) and
 * was beating a plain `.mega-promo-btn` (1,1,0), painting the
 * button's label link-slate on teal and giving it the link hover's
 * padding shift. */
#main-nav .mega-card > a.mega-promo-btn,
#main-nav .mega-promo-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:8px;
  background:var(--teal);
  color:#052e2c;
  font-weight:800;
  font-size:13px;
  padding:11px 16px;
  border-radius:10px;
  text-decoration:none;
  transition:background 0.2s;
}
#main-nav .mega-card > a.mega-promo-btn:hover,
#main-nav .mega-promo-btn:hover{background:#1ad4ca;color:#052e2c;padding-left:16px;}
#main-nav .mega-promo-btn i{font-size:11px;}
/* The wide menu stays ONE row at every desktop width.
 *
 * It used to wrap to a 3-column grid under 1500px, which looked
 * broken on the menus that don't divide by three: About has four
 * children, so the dark promo tile dropped to a second row on its
 * own with two empty cells beside it. Shrinking the cards instead
 * keeps the menu reading as a single deliberate band — the nav
 * itself collapses to the drawer at 960px, so this only has to
 * survive down to there (5 cards still clear 170px each). */
@media (max-width:1440px){
  #main-nav .mega-menu.mega-wide{max-width:96vw;padding:20px;gap:10px;}
  #main-nav .mega-card{min-width:0;padding:16px 16px 12px;}
  #main-nav .mega-card-head{margin-bottom:11px;padding-bottom:10px;}
  #main-nav .mega-card-title{font-size:14px;}
  #main-nav .mega-card > a{font-size:13px;padding:6px 8px;}
  #main-nav .mega-card.mega-promo{min-width:0;}
  #main-nav .mega-promo-stat{font-size:36px;margin-bottom:9px;}
  #main-nav .mega-promo-text{font-size:12.5px;margin-bottom:14px;}
  #main-nav .mega-promo-label{margin-bottom:12px;padding-bottom:9px;}
  #main-nav .mega-promo-faces{margin-bottom:12px;}
  #main-nav .mega-promo-img{margin:-16px -16px 12px;height:92px;}
  #main-nav .mega-promo-face{width:35px;height:40px;margin-right:-8px;}
}

#main-nav .mega-menu.w3{min-width:900px;}
#main-nav .mega-menu.w4{min-width:1100px;}
/* Open state: transition IN (visibility fires instantly, opacity+
 * transform animate over 200ms). Pointer-events go auto so the
 * mega can receive hover/click while visible. */
#main-nav .nav-item.open .mega-menu{
  opacity:1;
  visibility:visible;
  pointer-events:auto;
  transform:translateX(-50%) translateY(0);
  transition:opacity 0.2s ease,transform 0.2s ease,visibility 0s;
}
/* Extra top padding + negative margin creates an invisible
 * "hot zone" at the top of the mega element. The cursor stays
 * inside the mega's hit area while traversing the visual gap
 * between the nav button and the visible mega content. */
#main-nav .mega-menu{padding-top:24px;margin-top:-20px;}
#main-nav .mega-menu::before{
  content:'';position:absolute;top:17px;left:50%;transform:translateX(-50%);
  width:14px;height:7px;background:rgba(255,255,255,0.99);
  clip-path:polygon(50% 0%,0% 100%,100% 100%);
}
#main-nav .mega-col{flex:1;padding-right:30px;margin-right:30px;border-right:1px solid rgba(0,0,0,0.07);}
#main-nav .mega-col:last-of-type{border-right:none;margin-right:0;padding-right:0;}
#main-nav .mega-col-label{
  display:flex;align-items:center;gap:8px;
  font-size:10px;font-weight:800;letter-spacing:0.16em;
  text-transform:uppercase;color:#475569;
  margin-bottom:16px;padding-bottom:12px;
  border-bottom:1px solid rgba(0,0,0,0.07);
}
#main-nav .mega-col-label i{font-size:11px;color:var(--teal);}
#main-nav .mega-link{
  display:flex;align-items:center;gap:12px;
  padding:9px 8px;font-size:14px;font-weight:600;
  color:#1e3a52;text-decoration:none;border-radius:9px;
  transition:all 0.15s;
}
#main-nav .mega-link:hover{background:rgba(22,192,183,0.08);color:var(--teal);padding-left:12px;}
#main-nav .mega-link i{
  width:30px;height:30px;border-radius:8px;
  background:#f0fffe;display:flex;align-items:center;justify-content:center;
  font-size:12px;color:var(--teal);flex-shrink:0;transition:background 0.15s;
}
#main-nav .mega-link:hover i{background:rgba(22,192,183,0.2);}
#main-nav .mega-link-sub{font-size:11px;color:#475569;font-weight:400;display:block;margin-top:1px;}
#main-nav .mega-cta-card{
  flex-shrink:0;width:230px;border-radius:16px;padding:24px;
  display:flex;flex-direction:column;justify-content:space-between;min-height:280px;
}
#main-nav .mega-cta-card.navy-card{background:linear-gradient(150deg,#213E59 0%,#0d1f2d 100%);}
#main-nav .mega-cta-card.teal-card{background:linear-gradient(150deg,#0d5c58 0%,#062b29 100%);}
#main-nav .mega-cta-icon{font-size:26px;margin-bottom:12px;display:block;}
#main-nav .mega-cta-h{font-size:17px;font-weight:900;line-height:1.25;margin-bottom:8px;color:#fff;letter-spacing:-0.2px;}
#main-nav .mega-cta-h em{font-style:normal;color:var(--teal);}
#main-nav .mega-cta-p{font-size:12px;color:rgba(255,255,255,0.72);line-height:1.6;margin-bottom:14px;}
#main-nav .mega-cta-stat{display:flex;align-items:flex-end;gap:8px;margin-bottom:14px;}
#main-nav .mega-cta-stat-num{font-size:34px;font-weight:900;color:var(--teal);line-height:0.85;}
#main-nav .mega-cta-stat-lbl{font-size:11px;color:rgba(255,255,255,0.68);font-weight:600;line-height:1.3;padding-bottom:3px;}
#main-nav .mega-cta-btn{
  display:flex;align-items:center;justify-content:center;gap:6px;
  background:var(--teal);color:#050b12;
  font-family:var(--font);font-weight:800;font-size:13px;
  padding:11px 14px;border-radius:9px;text-decoration:none;transition:all 0.2s;
}
#main-nav .mega-cta-btn i{font-size:11px;}
#main-nav .mega-cta-btn:hover{background:#1ad4ca;box-shadow:0 0 18px rgba(22,192,183,0.5);}

/* Simple plain nav links — Home, Blog, etc. Share the animated
 * gradient underline defined alongside .nav-item-btn above (the
 * combined .nav-item-btn::after, .nav-plain::after rule). */
.nav-plain{
  position:relative;
  display:flex;align-items:center;
  padding:11px 20px;border-radius:9px;
  font-family:var(--font);font-size:18px;font-weight:700;
  letter-spacing:-0.2px;
  color:rgba(248,250,252,0.92);text-decoration:none;
  transition:color 0.22s ease, transform 0.22s ease;
  white-space:nowrap;
}
.nav-plain:hover{
  color:#fff;
}
#main-nav.scrolled .nav-plain{color:#1a2e42;}
#main-nav.scrolled .nav-plain:hover{
  color:var(--teal);
}

/* ── NAV CTA RIGHT ── */
.nav-cta{display:flex;gap:12px;align-items:center;flex-shrink:0;}

/* Phone block with CALL US label */
.nav-phone-block{
  display:flex;flex-direction:column;align-items:flex-end;
  padding-right:16px;margin-right:4px;
  border-right:1px solid rgba(255,255,255,0.14);
}
#main-nav.scrolled .nav-phone-block{border-right-color:rgba(0,0,0,0.1);}
.nav-phone-eyebrow{
  font-size:9px;font-weight:900;letter-spacing:0.2em;
  text-transform:uppercase;color:var(--teal);line-height:1;margin-bottom:3px;
}
.nav-phone{
  display:flex;align-items:center;gap:7px;
  font-size:17px;font-weight:900;color:#fff;
  text-decoration:none;letter-spacing:-0.4px;line-height:1;transition:color 0.2s;
}
.nav-phone i{font-size:13px;color:var(--teal);transition:transform 0.2s;}
.nav-phone:hover{color:var(--teal);}
.nav-phone:hover i{transform:rotate(-15deg);}
#main-nav.scrolled .nav-phone{color:var(--navy);}
#main-nav.scrolled .nav-phone:hover{color:var(--teal);}

/* Nav CTA button — same sticker language as .btn-primary.
 *
 * The flat-fill version was the safe "restraint pass" choice
 * but read as flat next to the distinctive sticker-style
 * .btn-primary elsewhere on the page. Both "Get Proposal"
 * CTAs now share the same press-into-shadow affordance so
 * the user's muscle memory carries across the site.
 *
 * Shadow color is tuned per state:
 *   Dark nav        → near-black opaque (wins against the
 *                      semi-transparent dark nav bg)
 *   Scrolled white  → obsidian (standard sticker cast)
 *
 * The arrow icon inside slides 3px right on hover, matching
 * the .btn-primary motion.
 */
.nav-cta-btn{
  position:relative;
  display:inline-flex;align-items:center;gap:9px;
  background:var(--teal);
  color:var(--navy-deep);
  font-family:var(--font);font-weight:900;font-size:15px;
  letter-spacing:-0.1px;
  padding:13px 26px;
  border-radius:12px;
  border:2px solid var(--teal);
  text-decoration:none;cursor:pointer;
  white-space:nowrap;
  box-shadow:4px 4px 0 0 #020814;
  transition:transform 0.18s cubic-bezier(0.2,0,0,1), box-shadow 0.18s cubic-bezier(0.2,0,0,1), background 0.18s ease, border-color 0.18s ease;
}
.nav-cta-btn i{
  font-size:14px;
  transition:transform 0.25s cubic-bezier(0.2,0,0,1);
}
.nav-cta-btn:hover{
  background:#1ad4ca;
  border-color:#1ad4ca;
  transform:translate(2px,2px);
  box-shadow:2px 2px 0 0 #020814;
}
.nav-cta-btn:hover i{transform:translateX(3px);}
/* The Let's Talk menu: a dark panel under the button, bold tiles, no
   copy to read. The audit is the one teal tile. */
.nav-talk{position:relative;}
.nav-talk-btn{cursor:pointer;border:2px solid var(--teal);}
.nav-talk-btn i{font-size:11px;transition:transform 0.25s cubic-bezier(0.2,0,0,1);}
.nav-talk-btn:hover i{transform:none;}
.nav-talk-btn[aria-expanded="true"] i{transform:rotate(180deg);}
.nav-talk-menu{
  position:absolute;right:0;top:calc(100% + 14px);z-index:60;
  width:360px;padding:16px;
  background:#0c1a26;border:1px solid rgba(22,192,183,0.3);border-radius:18px;
  box-shadow:0 30px 60px -12px rgba(0,0,0,0.6),0 0 0 1px rgba(5,11,18,0.6);
  animation:navTalkIn 0.18s cubic-bezier(0.2,0,0,1);
}
.nav-talk-menu[hidden]{display:none;}
.nav-talk-menu::before{
  content:"";position:absolute;right:28px;top:-7px;width:12px;height:12px;
  background:#0c1a26;border-left:1px solid rgba(22,192,183,0.3);border-top:1px solid rgba(22,192,183,0.3);
  transform:rotate(45deg);
}
@keyframes navTalkIn{from{opacity:0;transform:translateY(-6px);}to{opacity:1;transform:none;}}
.nav-talk-kicker{display:block;font-family:var(--mono2);font-size:10.5px;letter-spacing:0.16em;text-transform:uppercase;color:var(--teal);margin:0 0 12px 2px;}
.nav-talk-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;}
.nav-talk-item{
  position:relative;display:flex;flex-direction:column;align-items:flex-start;gap:12px;
  padding:14px;border-radius:12px;text-decoration:none;
  background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.1);
  transition:background 0.15s,border-color 0.15s,transform 0.15s;
}
.nav-talk-item:hover,.nav-talk-item:focus-visible{background:rgba(22,192,183,0.12);border-color:rgba(22,192,183,0.45);transform:translateY(-2px);outline:none;}
.nav-talk-item b{font-size:15px;font-weight:800;color:#fff;line-height:1.2;}
.nav-talk-icon{
  flex-shrink:0;width:34px;height:38px;display:inline-flex;align-items:center;justify-content:center;
  background:rgba(22,192,183,0.16);color:var(--teal);font-size:14px;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}
.nav-talk-primary,.nav-talk-wide{grid-column:span 2;flex-direction:row;align-items:center;}
.nav-talk-primary{background:var(--teal);border-color:var(--teal);}
.nav-talk-primary:hover,.nav-talk-primary:focus-visible{background:#1ad4ca;border-color:#1ad4ca;}
.nav-talk-primary b{color:#050b12;font-size:17px;}
.nav-talk-primary .nav-talk-icon{background:#050b12;color:var(--teal);}
.nav-talk-go{margin-left:auto;color:#050b12;font-size:16px;}
.nav-talk-note{display:block;margin:12px 2px 0;font-size:12.5px;color:var(--muted);}
.nav-talk-note i{color:var(--teal);margin-right:6px;font-size:11px;}
.nav-cta-btn:active{
  transform:translate(4px,4px);
  box-shadow:0 0 0 0 #020814;
}

/* Scrolled (white) nav — obsidian shadow reads cleanly
 * against the light background. */
#main-nav.scrolled .nav-cta-btn{
  box-shadow:4px 4px 0 0 rgba(5,11,18,0.88);
}
#main-nav.scrolled .nav-cta-btn:hover{
  box-shadow:2px 2px 0 0 rgba(5,11,18,0.88);
}
#main-nav.scrolled .nav-cta-btn:active{
  box-shadow:0 0 0 0 rgba(5,11,18,0.88);
}

/* Overlay */
#nav-overlay{display:none;position:fixed;inset:0;z-index:299;}
#nav-overlay.active{display:block;}


/* ── FOOTER ──
 *
 * Scoped to .site-footer (a class added to the <footer> element
 * in footer.php) instead of the bare `footer` element selector.
 * The 23 per-page CSS files extracted from the legacy standalone
 * mockups all carry rules like
 *   footer { text-align:center; color:var(--muted); font-size:13px; }
 * which have the same (0,0,0,1) specificity as a bare `footer{}`
 * rule here but set properties global.css doesn't — so things
 * like text-align, color, and font-size were leaking through and
 * breaking the WP footer's left-aligned long-form layout. Using
 * a class bumps specificity to (0,0,1,0) and beats the page bleed.
 *
 * Also explicitly resets text-align, color, and font-size so any
 * inheritance or future bare `footer` bleed lands on the right
 * defaults rather than whatever the page CSS happened to set.
 */
.site-footer{
  position:relative;z-index:2;
  background:linear-gradient(180deg,#011931 0%,var(--obsidian) 80%);
  border-top:1px solid rgba(22,192,183,0.2);
  padding:80px 0 0;overflow:hidden;
  text-align:left;
  color:var(--text);
  font-size:16px;
}
.site-footer::before{
  content:'';position:absolute;inset:0;
  background:
    radial-gradient(ellipse 40% 60% at 10% 20%,rgba(22,192,183,0.06) 0%,transparent 60%),
    radial-gradient(ellipse 30% 50% at 90% 10%,rgba(33,62,89,0.3) 0%,transparent 60%);
}
.site-footer .container{position:relative;z-index:1;}

/* Top row: big CTA strip inside the footer */
.f-top-cta{
  display:grid;grid-template-columns:1.3fr 1fr;gap:40px;align-items:center;
  padding:32px 40px;margin-bottom:60px;
  background:rgba(22,192,183,0.05);
  border:1px solid rgba(22,192,183,0.2);border-radius:20px;
  position:relative;overflow:hidden;
}
.f-top-cta::before{
  content:'';position:absolute;top:0;left:0;right:0;height:1px;
  background:linear-gradient(90deg,transparent 0%,rgba(22,192,183,0.5) 50%,transparent 100%);
}
.f-cta-head{font-size:clamp(22px,2.4vw,32px);font-weight:900;letter-spacing:-0.3px;line-height:1.15;margin-bottom:6px;}
.f-cta-head em{font-style:normal;color:var(--teal);}
.f-cta-sub{font-size:14px;color:var(--muted);}
.f-newsletter{display:flex;gap:8px;}
.f-newsletter input{
  flex:1;font-family:var(--font);font-size:14px;
  background:rgba(5,11,18,0.55);color:var(--text);
  border:1px solid rgba(22,192,183,0.2);border-radius:10px;
  padding:13px 16px;outline:none;
  transition:border-color 0.2s;
}
.f-newsletter input::placeholder{color:var(--muted);}
.f-newsletter input:focus{border-color:var(--teal);}
.f-newsletter button{
  font-family:var(--font);font-size:13px;font-weight:800;
  background:var(--teal);color:#050b12;
  border:none;border-radius:10px;padding:13px 22px;
  cursor:pointer;transition:all 0.2s;
  display:flex;align-items:center;gap:6px;
}
.f-newsletter button:hover{background:#1ad4ca;box-shadow:0 0 18px rgba(22,192,183,0.4);}

/* Main footer grid — 4 columns */
.footer-top{
  display:grid;grid-template-columns:1.5fr 1fr 1fr 1.1fr;
  gap:50px;margin-bottom:50px;
}
/* Brand column — explicit flex layout so the children always stack
 * cleanly with uniform spacing (was relying on per-element margins,
 * which produced an overlap with the logo when the parent was treated
 * as a stretched grid item by .footer-top). */
.f-brand{
  display:flex;flex-direction:column;align-items:flex-start;
  gap:22px;
}
.f-brand > img{
  display:block;width:280px;height:auto;max-width:100%;margin:0;
}
.f-desc{color:var(--muted);font-size:15px;line-height:1.7;margin:0;}
/* Partner badges on white tiles: both are drawn for a light ground. */
.f-awards{display:flex;gap:12px;align-items:stretch;margin:0;flex-wrap:wrap;}
.f-awards a{
  display:inline-flex;align-items:center;justify-content:center;
  height:84px;padding:8px 16px;border-radius:12px;
  background:#fff;border:1px solid rgba(255,255,255,0.12);
  transition:transform 0.2s,box-shadow 0.2s;
}
.f-awards a:hover{transform:translateY(-2px);box-shadow:0 10px 24px rgba(0,0,0,0.35);}
.f-awards img{display:block;height:66px;width:auto;max-width:200px;opacity:1;filter:none;}
.f-socials{display:flex;gap:8px;margin:0;}
.f-soc{
  width:38px;height:38px;border-radius:10px;
  background:rgba(22,192,183,0.05);border:1px solid rgba(22,192,183,0.15);
  display:flex;align-items:center;justify-content:center;
  color:var(--muted);font-size:15px;text-decoration:none;transition:all 0.25s;
}
.f-soc:hover{border-color:var(--teal);color:var(--teal);background:rgba(22,192,183,0.12);}

/* Footer column headings — link columns and the contact column share
   the same look. Used to be <h6> rendered via inline styles, now <h2>
   for correct heading order (page H1 → footer H2 landmarks).
   Bumped from 12px to 15px — 12 was undersized for the footer's
   generous type scale below and read as a label not a heading. */
.f-col h2,
.f-contact-col h2{
  font-size:15px;font-weight:800;letter-spacing:0.14em;text-transform:uppercase;
  color:#fff;margin-bottom:22px;
  position:relative;padding-bottom:14px;
}
.f-col h2::after,
.f-contact-col h2::after{
  content:'';position:absolute;bottom:0;left:0;width:36px;height:2px;background:var(--teal);
}
/* Footer links: the 11px gap between rows is padding, not margin,
 * so the whole row is the tap target rather than just the 23px text
 * line. Same pitch, same look — a 34px target instead of a 23px one,
 * which clears the 24px floor WCAG 2.2 sets for every pointer, not
 * just touch. There are seventeen of these per column on 46 pages,
 * so it is the single most-repeated control on the site. */
.f-col a{
  display:flex;align-items:center;gap:6px;
  color:var(--muted);text-decoration:none;font-size:14px;font-weight:400;
  padding:5.5px 0;margin-bottom:0;transition:all 0.2s;
}
.f-col a:hover{color:var(--teal);transform:translateX(4px);}
.f-col a i{font-size:9px;opacity:0;transition:opacity 0.2s;}
.f-col a:hover i{opacity:1;}

/* Contact column with icons */
.f-contact-item{
  display:flex;gap:12px;align-items:flex-start;
  margin-bottom:18px;
}
.f-contact-icon{
  flex-shrink:0;
  width:36px;height:40px;
  clip-path:polygon(50% 0%,100% 25%,100% 75%,50% 100%,0% 75%,0% 25%);
  background:rgba(22,192,183,0.12);
  display:flex;align-items:center;justify-content:center;
  color:var(--teal);font-size:13px;
}
.f-contact-label{font-size:11px;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:1px;margin-bottom:2px;}
.f-contact-value{font-size:14px;font-weight:600;color:var(--text);text-decoration:none;display:block;transition:color 0.2s;line-height:1.4;padding:6px 0;}
.f-contact-value:hover{color:var(--teal);}

/* ══════════════════════════════════════════════════
   METRICS ROW — 5-column stat band with hex hover effect
   ══════════════════════════════════════════════════
   Used by the homepage (section.metrics-section) and interior
   templates that want a stat band (local-seo currently). On hover,
   two pseudo-elements scale up behind the number: a filled hex
   shape (::before) and a thin hex outline (::after), creating the
   layered "SVG hex appears behind each stat" effect the design
   language is built around.

   Moved here from front-page.css so interior templates can use it
   without duplicating ~40 lines of CSS. Mobile breakpoints for the
   grid live further down in the global responsive block. */
.metrics-section{position:relative;z-index:2;background:var(--surface);padding:0;}
.metrics-grid{display:grid;grid-template-columns:repeat(5,1fr);}
.metric-box{
  padding:40px 28px;text-align:center;
  border-right:1px solid rgba(255,255,255,0.06);
  position:relative;overflow:hidden;transition:transform 0.3s ease;
}
.metric-box:last-child{border-right:none;}
.metric-box:hover{transform:translateY(-3px);}
/* Hexagon background shape on hover */
.metric-box::before{
  content:'';position:absolute;top:50%;left:50%;
  width:140px;height:160px;
  transform:translate(-50%,-50%) scale(0) rotate(0deg);
  background:rgba(22,192,183,0.07);
  clip-path:polygon(50% 0%,100% 25%,100% 75%,50% 100%,0% 75%,0% 25%);
  transition:transform 0.45s cubic-bezier(0.16,1,0.3,1), opacity 0.3s;
  opacity:0;
}
.metric-box:hover::before{transform:translate(-50%,-50%) scale(1.6) rotate(12deg);opacity:1;}
/* Hexagon outline via SVG background on hover */
.metric-box::after{
  content:'';position:absolute;top:50%;left:50%;
  width:100px;height:115px;
  transform:translate(-50%,-50%) scale(0) rotate(-8deg);
  background:transparent;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 115'%3E%3Cpolygon points='50,2 98,29 98,86 50,113 2,86 2,29' fill='none' stroke='%2316C0B7' stroke-width='2' opacity='0.4'/%3E%3C/svg%3E");
  background-size:contain;background-repeat:no-repeat;
  transition:transform 0.55s cubic-bezier(0.16,1,0.3,1), opacity 0.35s;
  opacity:0;
}
.metric-box:hover::after{transform:translate(-50%,-50%) scale(2) rotate(-8deg);opacity:1;}
.metric-box.accent{background:linear-gradient(135deg,rgba(22,192,183,0.15) 0%,rgba(22,192,183,0.05) 100%);}
.metric-num{
  font-family:var(--disp);
  font-size:clamp(36px,3.4vw,50px);font-weight:400;line-height:1;display:block;letter-spacing:-1px;
  background:none;
  -webkit-background-clip:initial;
  background-clip:initial;
  color:var(--teal);
}
.metric-label{font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:var(--text);margin-top:8px;display:block;}
.metric-sub{font-size:12px;color:var(--muted);margin-top:4px;font-weight:400;}

/* ══════════════════════════════════════════════════
   SHARED BLOG RESOURCES — editorial card grid
   Used by template-parts/section-blog-resources.php
   across all service pages.
   ══════════════════════════════════════════════════ */
/* Resources sits between seo-content (--surface) and the
 * CTA/footer. Using --surface2 (lighter navy) creates a
 * clear visual step between the three tones so the sections
 * don't blend together. */
.resources{padding:100px 0 120px;background:var(--surface2);position:relative;z-index:2;}
.resources::before{
  content:'';position:absolute;top:0;left:0;right:0;height:1px;
  background:linear-gradient(90deg,transparent 0%,rgba(22,192,183,0.35) 50%,transparent 100%);
}
.res-head{text-align:center;max-width:640px;margin:0 auto 56px;}
.res-head h2{font-size:clamp(30px,3.2vw,46px);font-weight:900;letter-spacing:-0.5px;line-height:1.1;margin-bottom:14px;}
.res-head p{color:var(--muted);font-size:17px;line-height:1.6;}
.res-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;}
.res-card{
  display:flex;flex-direction:column;
  text-decoration:none;color:inherit;
  background:var(--surface);
  border:1px solid rgba(22,192,183,0.12);
  border-radius:16px;
  overflow:hidden;
  transition:transform 0.3s ease,border-color 0.3s ease,box-shadow 0.3s ease;
}
.res-card:hover{
  border-color:rgba(22,192,183,0.4);
  transform:translateY(-5px);
  box-shadow:0 20px 40px rgba(0,0,0,0.35);
}
.res-card-media{
  position:relative;width:100%;
  aspect-ratio:16/9;
  background:#0a1520;
  overflow:hidden;
}
.res-card-media img{
  width:100%;height:100%;object-fit:cover;display:block;
  transition:transform 0.5s cubic-bezier(0.2,0.8,0.2,1);
}
.res-card:hover .res-card-media img{transform:scale(1.06);}
.res-card-media-fallback{
  position:absolute;inset:0;
  display:flex;align-items:center;justify-content:center;
  background:linear-gradient(135deg,rgba(22,192,183,0.10) 0%,rgba(22,192,183,0.02) 100%),#0a1520;
  color:rgba(22,192,183,0.5);font-size:52px;
}
.res-card-body{
  display:flex;flex-direction:column;
  padding:22px 22px 24px;
  flex:1 1 auto;min-height:0;
}
.res-card-meta{
  display:flex;align-items:center;gap:10px;
  margin-bottom:14px;font-size:11px;line-height:1;
}
.res-tag{
  display:inline-block;font-size:10px;font-weight:800;
  letter-spacing:1.5px;text-transform:uppercase;color:var(--teal);
  background:rgba(22,192,183,0.14);
  padding:5px 10px;border-radius:4px;
}
.res-date{
  color:rgba(248,250,252,0.5);font-weight:700;
  letter-spacing:0.6px;text-transform:uppercase;font-size:10px;
  position:relative;padding-left:12px;
}
.res-date::before{
  content:'';position:absolute;left:0;top:50%;transform:translateY(-50%);
  width:3px;height:3px;border-radius:50%;background:rgba(22,192,183,0.5);
}
.res-card h3{
  font-size:19px;font-weight:800;line-height:1.25;letter-spacing:-0.3px;
  margin-bottom:12px;color:#fff;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.res-card:hover h3{color:var(--teal);}
.res-card p{
  font-size:14px;color:var(--muted);line-height:1.6;
  margin-bottom:18px;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;
}
.res-link{
  font-size:13px;font-weight:800;color:var(--teal);
  display:inline-flex;align-items:center;gap:8px;
  letter-spacing:0.3px;margin-top:auto;padding-top:4px;
}
.res-link i{font-size:11px;transition:transform 0.25s ease;}
.res-card:hover .res-link i{transform:translateX(4px);}
@media(max-width:860px){.res-grid{grid-template-columns:1fr 1fr;}}
@media(max-width:560px){.res-grid{grid-template-columns:1fr;}}

/* ══════════════════════════════════════════════════
   SHARED CTA — bordered card + button that breaks out
   Used by template-parts/section-cta-standard.php.

   Also: .cs-footer centers the "See All Case Studies" CTA
   button that appears below the case-studies grid on most
   service pages.

   Layout: bordered white card (left) with the button
   extending PAST the card's right edge, contact info
   floats outside the card (right). The button overflow
   is the visual hook — it "breaks the box."
   ══════════════════════════════════════════════════ */
.cta{
  padding:100px 0 120px;
  position:relative;z-index:3;
  background:linear-gradient(180deg, var(--obsidian) 45%, #011931 100%);
}
.cta .container{position:relative;z-index:1;}

/* Case studies "See All" footer — shared across service pages */
.cs-footer{text-align:center;margin-top:48px;}

/* Outer layout: card + contact side by side */
.cta-layout{
  display:grid;grid-template-columns:1.3fr 1fr;
  gap:60px;align-items:center;
  max-width:1140px;margin:0 auto;
}

/* The bordered card — thick dark border, white fill.
 * overflow:visible lets the button extend past the edge. */
.cta-card{
  position:relative;
  background:#fff;
  border:4px solid #0a1220;
  border-radius:6px;
  padding:52px 48px 68px;
  overflow:visible;
}
.cta-card h2{
  font-size:clamp(32px,3.6vw,50px);
  font-weight:900;letter-spacing:-1.2px;line-height:1.06;
  color:#0a1220;
  margin-bottom:16px;
}
.cta-card h2 em{font-style:normal;color:var(--teal);}
.cta-card p{
  font-size:17px;color:#52647a;line-height:1.7;
  max-width:460px;margin-bottom:36px;
}

/* The button starts inside the card but extends ~40%
 * past the right border. width > 100% + negative right
 * margin-right is absorbed by overflow:visible. */
.cta-card-btn{
  display:flex;align-items:center;justify-content:space-between;
  width:calc(100% + 120px);
  padding:22px 36px;
  background:var(--teal);color:#050b12;
  font-family:var(--font);font-size:18px;font-weight:800;
  text-decoration:none;border-radius:12px;
  transition:all 0.25s ease;
  position:relative;z-index:2;
  cursor:pointer;
  box-shadow:0 12px 36px rgba(22,192,183,0.3);
}
.cta-card-btn:hover{
  background:#14d4ca;
  box-shadow:0 16px 44px rgba(22,192,183,0.4);
  transform:translateY(-2px);
}
.cta-card-btn:active{
  transform:translateY(0);
  box-shadow:0 8px 24px rgba(22,192,183,0.25);
}
.cta-btn-arrow{
  display:flex;align-items:center;
  font-size:20px;
  transition:transform 0.25s;
}
.cta-card-btn:hover .cta-btn-arrow{transform:translateX(8px);}

/* Contact info — sits outside the card on a subtle
 * dark panel so it doesn't blend into the bg */
.cta-contact{
  display:flex;flex-direction:column;
  gap:18px;
  padding:40px 36px;
  background:rgba(22,192,183,0.04);
  border:1px solid rgba(22,192,183,0.15);
  border-radius:14px;
  align-self:center;
}
.cta-contact-head{
  font-size:13px;font-weight:800;letter-spacing:2px;text-transform:uppercase;
  color:var(--teal);margin-bottom:6px;
}
.cta-contact-item{
  display:flex;align-items:center;gap:14px;
  font-size:17px;font-weight:600;color:#e6edf5;
}
.cta-contact-item i{
  color:var(--teal);font-size:16px;
  width:22px;text-align:center;flex-shrink:0;
}
.cta-contact-item a{
  color:#e6edf5;text-decoration:none;
  transition:color 0.2s;
}
.cta-contact-item a:hover{color:var(--teal);}

@media(max-width:960px){
  .cta-layout{grid-template-columns:1fr;gap:40px;}
  .cta-card-btn{width:100%;}
}
@media(max-width:768px){
  .cta-card{padding:36px 28px 56px;}
  .cta-card-btn{padding:20px 28px;font-size:16px;}
  .cta-contact{padding-left:0;}
}

/* Locations row */
.f-locations{
  /* Two offices, each hugs its own edge. Was a 1fr 1fr grid
   * which meant the right location's content started at the
   * midpoint of the footer and read as "floating in the
   * middle" instead of bookending the left one. Flex +
   * space-between pins them to the outer edges so the two
   * offices balance the frame. */
  display:flex;justify-content:space-between;align-items:flex-start;
  gap:24px;flex-wrap:wrap;
  padding:32px 36px;margin-bottom:40px;
  background:rgba(22,192,183,0.03);
  border:1px solid rgba(22,192,183,0.14);border-radius:18px;
}
.f-loc{display:flex;gap:18px;align-items:flex-start;flex:0 1 auto;max-width:48%;min-width:0;}
.f-loc-body{
  display:flex;flex-direction:column;align-items:flex-start;
  gap:10px;min-width:0;flex:1;
}
.f-loc-icon{
  flex-shrink:0;width:54px;height:62px;
  clip-path:polygon(50% 0%,100% 25%,100% 75%,50% 100%,0% 75%,0% 25%);
  background:var(--teal);color:#050b12;
  display:flex;align-items:center;justify-content:center;font-size:20px;
}
.f-loc-title{
  font-size:13px;font-weight:900;color:var(--teal);
  text-transform:uppercase;letter-spacing:1.4px;margin-bottom:0;
}
.f-loc-addr{
  font-size:14px;color:var(--text);font-weight:400;line-height:1.55;
  margin-bottom:2px;
}
.f-loc-dir{
  display:inline-flex;align-items:center;gap:8px;
  font-size:12px;font-weight:700;color:var(--muted);
  text-transform:uppercase;letter-spacing:0.06em;
  text-decoration:none;
  padding:8px 0 6px;
  transition:color 0.2s,gap 0.2s;
}
.f-loc-dir i{font-size:13px;color:var(--teal);}
.f-loc-dir:hover{color:var(--teal);gap:10px;}
/* Third card: the page-1 figure from SEO App rank tracking. With it
   the strip is three equal columns instead of two offices bookending
   the frame; the figure takes the display stat face the metric boxes
   use. The logo is SEO App's own, which is drawn for a
   dark footer. */
.f-locations.has-proof .f-loc{flex:1 1 0;max-width:none;}
.f-locations.has-proof .f-loc-proof{
  padding-left:28px;
  border-left:1px solid rgba(22,192,183,0.16);
}
.f-proof-n{
  font-family:var(--display-stat);
  font-size:40px;
  font-weight:900;
  line-height:1;
  letter-spacing:-0.03em;
  color:#fff;
  font-variant-numeric:tabular-nums;
}
.f-proof-gain{
  display:inline-flex;align-items:center;gap:8px;
  font-size:13px;font-weight:700;color:var(--green);
  padding:5px 10px;border-radius:999px;background:rgba(52,211,153,0.12);
}
.f-proof-gain i{font-size:12px;}
.f-proof-sub{font-size:13px;line-height:1.5;color:var(--muted);max-width:30ch;}
.f-proof-by{
  display:inline-flex;align-items:center;gap:10px;
  margin-top:2px;padding:6px 10px 6px 0;
  text-decoration:none;
  font-size:11px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;
  color:var(--muted);
}
/* The logo is made for a dark ground; no chip behind it. */
.f-proof-by img{height:26px;width:auto;display:block;}
.f-proof-by:hover{color:var(--teal);}

/* Bottom bar */
.footer-bottom{
  border-top:1px solid rgba(22,192,183,0.12);
  padding:24px 0 30px;margin-top:20px;
  display:flex;justify-content:space-between;align-items:center;
  color:var(--muted);font-size:13px;flex-wrap:wrap;gap:14px;
}
/* The full notice runs to two lines at most widths; it takes the
   room and the links sit at its right, dropping under it when the
   bar wraps. */
.f-copy{margin:0;flex:1 1 560px;max-width:72ch;line-height:1.6;}
.f-btm-links{display:flex;gap:26px;flex-wrap:wrap;}
.f-btm-links a{color:var(--muted);text-decoration:none;font-size:13px;transition:color 0.2s;display:inline-block;padding:6px 0;}
.f-btm-links a:hover{color:var(--teal);}

/* ══════════════════════════════════════════════════
   GOOGLE REVIEWS — live cards from Places API
   ══════════════════════════════════════════════════
   Server-rendered HTML driven by inc/google-reviews.php → 24-hour
   transient cache. No client JS, no third-party origin. Slots into
   any template via:
     <?php get_template_part( 'template-parts/section-google-reviews' ); ?>
   The template part renders nothing if reviews aren't configured,
   so the section is invisible until the API key + Place ID are set
   in wp-config.php.
*/
.gr-section{
  position:relative;padding:90px 0;
  background:var(--obsidian);
}
.gr-section::before{
  content:'';position:absolute;inset:0;
  background:radial-gradient(ellipse 60% 70% at 50% 0%,rgba(66,133,244,0.06) 0%,transparent 60%);
  pointer-events:none;
}
.gr-head{
  display:grid;grid-template-columns:1fr auto;gap:48px;align-items:center;
  margin-bottom:50px;position:relative;z-index:1;
}
.gr-head-text h2{
  font-size:clamp(28px,3.2vw,44px);font-weight:900;line-height:1.12;
  letter-spacing:-0.5px;margin-bottom:12px;
}
.gr-head-text h2 em{font-style:normal;color:var(--teal);}
.gr-head-text p{font-size:15px;color:var(--muted);line-height:1.65;max-width:520px;}

.gr-summary{
  display:flex;flex-direction:column;align-items:flex-end;gap:6px;
  padding:24px 32px;border-radius:14px;
  background:rgba(22,192,183,0.04);
  border:1px solid rgba(22,192,183,0.18);
  min-width:240px;
}
.gr-summary-stars{display:flex;align-items:center;}
.gr-summary-stars .g-stars svg{width:20px;height:20px;}
.gr-summary-rating{font-size:38px;font-weight:900;color:var(--text);line-height:1;letter-spacing:-1px;}
.gr-summary-count{font-size:13px;color:var(--muted);font-weight:400;}
.gr-summary-cta{
  margin-top:8px;font-size:12px;font-weight:700;color:var(--teal);
  text-decoration:none;display:inline-flex;align-items:center;gap:6px;
  text-transform:uppercase;letter-spacing:0.08em;
  transition:color 0.2s;
}
.gr-summary-cta i{font-size:10px;}
.gr-summary-cta:hover{color:#1ad4ca;}

.gr-grid{
  display:grid;grid-template-columns:repeat(3,1fr);gap:20px;
  position:relative;z-index:1;
}
.gr-card{
  background:rgba(15,33,51,0.55);
  backdrop-filter:blur(12px);
  -webkit-backdrop-filter:blur(12px);
  border:1px solid rgba(22,192,183,0.12);
  border-radius:16px;
  padding:24px 24px 20px;
  display:flex;flex-direction:column;gap:14px;
  transition:all 0.3s;
}
.gr-card:hover{
  background:rgba(15,33,51,0.85);
  border-color:rgba(22,192,183,0.28);
  transform:translateY(-3px);
}
.gr-card-head{display:grid;grid-template-columns:auto 1fr auto;gap:12px;align-items:center;}
.gr-avatar{
  width:44px;height:44px;border-radius:50%;
  object-fit:cover;background:rgba(22,192,183,0.12);
}
.gr-avatar-fallback{
  display:flex;align-items:center;justify-content:center;
  color:var(--teal);font-weight:900;font-size:18px;text-transform:uppercase;
  border:1px solid rgba(22,192,183,0.25);
}
.gr-card-meta{min-width:0;}
.gr-card-name{font-size:14px;font-weight:800;color:var(--text);line-height:1.2;}
.gr-card-time{font-size:11px;color:var(--muted);font-weight:400;margin-top:2px;}
.gr-card-stars{display:flex;align-items:center;margin-left:auto;}
.gr-card-stars .g-stars svg{width:13px;height:13px;}
.gr-card-text{
  font-size:14px;color:rgba(248,250,252,0.85);line-height:1.6;
  flex:1;margin:0;
}
.gr-card-source{
  font-size:11px;color:var(--muted);font-weight:600;
  display:flex;align-items:center;gap:6px;
  padding-top:14px;border-top:1px solid rgba(22,192,183,0.08);
}

.gr-card-location{
  display:inline-flex;align-items:center;
  padding:3px 10px;
  background:rgba(22,192,183,0.08);
  border:1px solid rgba(22,192,183,0.22);
  border-radius:30px;
  font-weight:700;color:var(--teal);
  font-size:11px;letter-spacing:0.02em;
}

@media (max-width:960px){
  .gr-head{grid-template-columns:1fr;}
  .gr-summary{align-items:flex-start;}
  .gr-grid{grid-template-columns:1fr 1fr;}
}
@media (max-width:640px){
  .gr-section{padding:60px 0;}
  .gr-grid{grid-template-columns:1fr;}
}

/* ══════════════════════════════════════════════════
   GOOGLE REVIEWS BADGES
   ══════════════════════════════════════════════════
   Small reusable components that surface the combined rating
   without the full grid from .gr-section. Three variants driven
   by a modifier class on the same base .gr-badge:

     .gr-badge-inline   → one-line horizontal pill
     .gr-badge-compact  → boxed card with arrow CTA
     .gr-badge-stacked  → vertical badge for sidebars

   When seolocale_google_reviews_url() returns a URL the outer
   element renders as an <a> that opens the public Google Reviews
   tab in a new tab — the base class has the hover states plumbed
   to work for both <a> and <div>.
*/
.gr-badge{
  text-decoration:none;color:var(--text);
  font-family:var(--font);
  display:inline-flex;align-items:center;
  transition:all 0.25s ease;
}
.gr-badge .gr-badge-stars{display:inline-flex;gap:2px;color:#f59e0b;}
.gr-badge .gr-star-empty{color:rgba(245,158,11,0.25);}
.gr-badge .gr-badge-g{color:#4285f4;}

/* ── INLINE: compact horizontal pill ── */
.gr-badge-inline{
  gap:10px;padding:8px 14px;border-radius:30px;
  background:rgba(22,192,183,0.06);
  border:1px solid rgba(22,192,183,0.18);
  font-size:13px;
}
.gr-badge-inline .gr-badge-g{font-size:13px;}
.gr-badge-inline .gr-badge-stars{font-size:12px;}
.gr-badge-inline .gr-badge-rating{font-weight:900;color:var(--teal);}
.gr-badge-inline .gr-badge-sep{color:rgba(248,250,252,0.25);}
.gr-badge-inline .gr-badge-count{color:var(--muted);font-weight:400;}
a.gr-badge-inline:hover{
  background:rgba(22,192,183,0.12);
  border-color:rgba(22,192,183,0.35);
  transform:translateY(-1px);
}
/* When dropped inline below the hero CTA buttons, give it breathing room. */
.hero-btns + .gr-badge-inline{margin-top:24px;}

/* Footer office-card placement — each .f-loc gets its own per-location
 * inline badge rendered into .f-loc-body below the address. The badge
 * is full-width within its column and matches the card's left margin. */
.f-loc .gr-badge-inline{
  display:inline-flex;
  margin-top:14px;
  background:rgba(15,33,51,0.7);
  border-color:rgba(22,192,183,0.22);
}
.f-loc .gr-badge-inline:hover{
  background:rgba(22,192,183,0.12);
  border-color:rgba(22,192,183,0.45);
}

/* ── COMPACT: boxed card, stats on the left, arrow on the right ── */
.gr-badge-compact{
  display:inline-grid;grid-template-columns:auto 1fr auto;
  align-items:center;gap:16px;
  padding:16px 20px;border-radius:14px;
  background:rgba(15,33,51,0.7);
  border:1px solid rgba(22,192,183,0.18);
  backdrop-filter:blur(12px);
  -webkit-backdrop-filter:blur(12px);
  min-width:260px;
}
.gr-badge-compact .gr-badge-left{
  width:42px;height:48px;
  clip-path:polygon(50% 0%,100% 25%,100% 75%,50% 100%,0% 75%,0% 25%);
  background:rgba(66,133,244,0.12);
  display:flex;align-items:center;justify-content:center;
}
.gr-badge-compact .gr-badge-g{font-size:18px;}
.gr-badge-compact .gr-badge-body{min-width:0;}
.gr-badge-compact .gr-badge-rating-row{
  display:flex;align-items:baseline;gap:8px;
}
.gr-badge-compact .gr-badge-rating{
  font-size:24px;font-weight:900;color:var(--text);
  line-height:1;letter-spacing:-0.5px;
}
.gr-badge-compact .gr-badge-stars{font-size:13px;}
.gr-badge-compact .gr-badge-count{
  font-size:12px;color:var(--muted);
  font-weight:600;margin-top:3px;
}
.gr-badge-compact .gr-badge-arrow{
  color:var(--teal);font-size:14px;
  transition:transform 0.25s;
}
a.gr-badge-compact:hover{
  background:rgba(15,33,51,0.95);
  border-color:rgba(22,192,183,0.35);
  transform:translateY(-2px);
}
a.gr-badge-compact:hover .gr-badge-arrow{transform:translateX(3px);}

/* ── STACKED: vertical badge for sidebars ── */
.gr-badge-stacked{
  display:inline-flex;flex-direction:column;align-items:center;
  gap:6px;padding:22px 28px;border-radius:16px;
  background:rgba(15,33,51,0.6);
  border:1px solid rgba(22,192,183,0.18);
  backdrop-filter:blur(12px);
  -webkit-backdrop-filter:blur(12px);
  text-align:center;min-width:180px;
  position:relative;
}
.gr-badge-stacked::before{
  content:'';position:absolute;top:-14px;left:50%;
  transform:translateX(-50%);
  width:36px;height:40px;
  clip-path:polygon(50% 0%,100% 25%,100% 75%,50% 100%,0% 75%,0% 25%);
  background:#0c1a26;
  border:1px solid rgba(22,192,183,0.25);
}
.gr-badge-stacked .gr-badge-g{
  position:relative;z-index:1;
  font-size:16px;margin-top:-4px;margin-bottom:4px;
}
.gr-badge-stacked .gr-badge-rating{
  font-size:42px;font-weight:900;color:var(--teal);
  line-height:1;letter-spacing:-1.5px;
}
.gr-badge-stacked .gr-badge-stars{font-size:14px;}
.gr-badge-stacked .gr-badge-count{
  font-size:11px;color:var(--muted);
  text-transform:uppercase;letter-spacing:1px;
  font-weight:700;margin-top:2px;
}
.gr-badge-stacked .gr-badge-link{
  margin-top:10px;padding-top:10px;
  border-top:1px solid rgba(22,192,183,0.12);
  width:100%;
  font-size:11px;font-weight:800;color:var(--teal);
  text-transform:uppercase;letter-spacing:0.08em;
  display:flex;align-items:center;justify-content:center;gap:6px;
}
.gr-badge-stacked .gr-badge-link i{font-size:9px;}
a.gr-badge-stacked:hover{
  background:rgba(15,33,51,0.9);
  border-color:rgba(22,192,183,0.35);
  transform:translateY(-3px);
}


/* ── REVEAL / MOBILE DRAWER / PROOF BADGE / HEX TAGS ── */
/* ── REVEAL ── */
.reveal{opacity:0;transform:translateY(22px);transition:opacity 0.6s ease,transform 0.6s ease;}
.reveal.visible{opacity:1;transform:translateY(0);}

/* ── AWARDS BAR ──
 *
 * Third-party badges under the client strip. Cream band, because
 * every one of these badges is drawn for a light background and
 * would need a knockout treatment to survive on the dark chapters.
 *
 * Badge files arrive at wildly different sizes and aspect ratios —
 * a square Inc. mark next to a wide Google Partner lockup — so the
 * row caps height and lets width do what it likes. That keeps the
 * optical weight even without anyone re-cropping the source files.
 *
 * .award-img is scoped to the bar: the awards page defines its own
 * .award-img at a much larger size, and global.css is enqueued
 * after the page CSS, so an unscoped rule here would shrink every
 * badge on /accolades-awards/.
 */
.awards-bar{
  background:var(--cream);
  border-bottom:1px solid rgba(30,52,72,0.1);
  padding:20px 0;
}
.awards-inner{
  display:flex;
  align-items:center;
  justify-content:center;
  flex-wrap:wrap;
  gap:14px 34px;
}
.awards-label{
  font-size:11px;
  font-weight:800;
  letter-spacing:0.16em;
  text-transform:uppercase;
  color:var(--ink-faint);
  white-space:nowrap;
  margin-right:6px;
}
.award-cell{
  display:flex;
  align-items:center;
  justify-content:center;
  text-decoration:none;
  /* Badges are third-party artwork at mixed quality. A shared
     opacity at rest pulls them into one set; hover restores the
     real thing for anyone actually reading them. */
  opacity:0.82;
  transition:opacity 0.25s ease,transform 0.25s ease;
}
.award-cell:hover{opacity:1;transform:translateY(-2px);}
.awards-bar .award-img{
  height:72px;
  width:auto;
  max-width:220px;
  object-fit:contain;
  display:block;
}
.awards-more{
  display:inline-flex;
  align-items:center;
  gap:7px;
  font-size:12.5px;
  font-weight:800;
  color:var(--teal-ink);
  text-decoration:none;
  border-bottom:1px solid rgba(11,138,130,0.35);
  padding-bottom:2px;
  white-space:nowrap;
  transition:gap 0.2s ease,border-color 0.2s ease;
}
.awards-more:hover{gap:11px;border-bottom-color:var(--teal-ink);}
.awards-more i{font-size:10px;}

/* Seven wrapped badges came to 155px of vertical space on a phone,
   directly above the first thing anyone reads. Same answer as the
   client strip: one row that scrolls sideways instead. */
/* 1300, not a phone breakpoint: seven badges plus the label need
   ~1280px of content width, so everything below a wide desktop was
   wrapping to two rows. */
@media(max-width:1300px){
  .awards-bar{padding:14px 0;}
  .awards-label{
    display:block;
    width:100%;
    text-align:center;
    margin:0 0 10px;
  }
  .awards-inner{
    flex-wrap:nowrap;
    justify-content:flex-start;
    gap:22px;
    overflow-x:auto;
    -webkit-overflow-scrolling:touch;
    scroll-snap-type:x proximity;
    scrollbar-width:none;
    /* Bleed the row to the screen edge so the last badge is visibly
       cut off — that is the only affordance telling a visitor the
       row scrolls. */
    margin:0 -1.25rem;
    padding:0 1.25rem;
  }
  .awards-inner::-webkit-scrollbar{display:none;}
  .award-cell{flex:0 0 auto;scroll-snap-align:start;}
  .awards-bar .award-img{height:56px;max-width:170px;}
}

@media(max-width:960px){
  /* minmax(0,1fr), not 1fr: a grid column's default minimum is auto,
     so it refuses to shrink below its content. Any hero that holds
     something intrinsically wide — a simulated local pack, a SERP, a
     business card — then keeps that width, pushing the whole column
     past the viewport where the hero's overflow:hidden clips it.
     Local SEO hit this first and carried its own copy of the fix;
     every page here shares the same class names, so it belongs here.
     Identical to 1fr in every case that was already fitting. */
  .hero-grid,.story-grid,.ai-grid,.intro-grid,.future-grid,.analyzer-inner,.ai-banner-inner{grid-template-columns:minmax(0,1fr);}
  .hero-grid > *,.story-grid > *,.intro-grid > *{min-width:0;}
  .process-grid,.vt-grid,.testi-grid{grid-template-columns:1fr;}
  .footer-top{grid-template-columns:1fr 1fr;gap:36px;}
  .f-top-cta{grid-template-columns:1fr;padding:28px 24px;gap:20px;}
  .f-locations{flex-direction:column;gap:24px;padding:24px;}
  .f-locations .f-loc{max-width:100%;}
  .f-locations.has-proof .f-loc-proof{padding-left:0;border-left:none;padding-top:24px;border-top:1px solid rgba(22,192,183,0.16);}
  .metrics-grid{grid-template-columns:repeat(3,1fr);}
  .metric-box:nth-child(4),.metric-box:nth-child(5){border-top:1px solid rgba(255,255,255,0.06);}
  .ai-banner-right{display:none;}
  .faq-wrap{grid-template-columns:1fr;}
  .faq-sidebar{position:static;}
  /* Hide desktop nav items, show hamburger */
  .top-bar-left{display:none;}
}

/* ── NAV SHRINK LADDER ──
 *
 * The desktop nav row (logo + five items + phone block + CTA
 * button) needs 1360px and was flush to the pixel at 1440. Between
 * the old 960px hamburger breakpoint and ~1250px it therefore ran
 * off the right edge, invisible only because the body clips
 * overflow — the "Get a Proposal" button and the phone number were
 * simply off-screen on every laptop and tablet in that range.
 *
 * Two steps down instead of one cliff: drop the phone block first
 * (the drawer still carries the number), then hand off to the
 * hamburger while there is still room to spare. */
@media(max-width:1340px){
  .nav-phone-block{display:none;}
}
@media(max-width:1120px){
  .nav-items{display:none;}
  .nav-cta-btn,.nav-talk{display:none;}
}
@media(max-width:640px){
  .metrics-grid{grid-template-columns:repeat(2,1fr);}
  .testi-grid,.vt-grid{grid-template-columns:1fr;}
  .footer-top{grid-template-columns:1fr;gap:32px;}
  .f-brand > img{width:240px;}
  .f-awards a{height:72px;padding:6px 12px;}
  .f-awards img{height:56px;}
  .f-cta-head{font-size:20px;}
  .f-newsletter{flex-direction:column;}
  .site-footer{padding-top:60px;}
}

/* ── MOBILE NAV HAMBURGER + DRAWER ──
   A dialog that slides in from the right: header, a Call / Text /
   Email row, the scrolling list, and a footer with the audit and
   call buttons that stays put while the list scrolls. Sections open
   one at a time to their full height. ── */
.mob-toggle{
  display:none;
  align-items:center;justify-content:center;
  width:42px;height:42px;border-radius:10px;
  background:rgba(22,192,183,0.12);border:1px solid rgba(22,192,183,0.25);
  cursor:pointer;color:var(--teal);font-size:18px;
  transition:all 0.2s;flex-shrink:0;
}
.mob-toggle:hover{background:rgba(22,192,183,0.2);}
#main-nav.scrolled .mob-toggle{background:rgba(22,192,183,0.08);}
@media(max-width:1120px){.mob-toggle{display:flex;}}

.mob-drawer{
  /* Above the fixed mobile call bar (z-index 900). */
  position:fixed;inset:0;z-index:950;
  display:none;
}
.mob-drawer.open{display:block;}
.mob-backdrop{
  position:absolute;inset:0;
  background:rgba(5,11,18,0.72);
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
  animation:fadeIn 0.2s ease;
}
@keyframes fadeIn{from{opacity:0;}to{opacity:1;}}
.mob-panel{
  position:absolute;top:0;right:0;bottom:0;
  width:min(380px,92vw);
  background:#0c1a26;
  border-left:1px solid rgba(22,192,183,0.15);
  box-shadow:-24px 0 60px rgba(0,0,0,0.45);
  display:flex;flex-direction:column;
  animation:slideIn 0.28s cubic-bezier(0.16,1,0.3,1);
  overflow:hidden;
}
@keyframes slideIn{from{transform:translateX(100%);}to{transform:translateX(0);}}
.mob-header{
  display:flex;align-items:center;justify-content:space-between;
  padding:calc(16px + env(safe-area-inset-top)) 20px 14px;
  flex-shrink:0;
}
.mob-header img{height:28px;width:auto;max-width:none;}
.mob-close{
  width:40px;height:40px;border-radius:10px;
  background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);
  display:flex;align-items:center;justify-content:center;
  color:var(--text);font-size:17px;cursor:pointer;transition:all 0.2s;
}
.mob-close:hover{background:rgba(255,255,255,0.12);}

/* Call / Text / Email, the three things a phone is for. */
.mob-quick{
  display:grid;grid-template-columns:repeat(3,1fr);gap:8px;
  padding:0 20px 14px;flex-shrink:0;
}
.mob-quick-btn{
  display:flex;flex-direction:column;align-items:center;gap:5px;
  padding:10px 6px 9px;border-radius:12px;
  background:rgba(22,192,183,0.08);border:1px solid rgba(22,192,183,0.18);
  color:var(--text);text-decoration:none;
  font-family:var(--font);font-size:12px;font-weight:700;letter-spacing:0.2px;
  transition:background 0.15s,border-color 0.15s;
}
.mob-quick-btn i{font-size:17px;color:var(--teal);}
.mob-quick-btn:hover,.mob-quick-btn:active{background:rgba(22,192,183,0.16);border-color:rgba(22,192,183,0.4);}

/* The list scrolls on its own; header and footer stay. */
.mob-nav{
  flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;
  padding:4px 0 12px;border-top:1px solid rgba(22,192,183,0.1);
}
.mob-link{
  display:flex;align-items:center;gap:14px;
  width:100%;padding:12px 20px;
  font-family:var(--font);font-size:16px;font-weight:700;color:rgba(248,250,252,0.92);
  text-decoration:none;text-align:left;
  background:none;border:none;border-bottom:1px solid rgba(255,255,255,0.04);
  cursor:pointer;transition:background 0.15s,color 0.15s;
}
.mob-link:hover,.mob-link:active{color:var(--teal);background:rgba(22,192,183,0.06);}
.mob-ico{
  width:34px;height:34px;border-radius:9px;flex-shrink:0;
  display:grid;place-items:center;
  background:rgba(22,192,183,0.1);color:var(--teal);font-size:14px;
  transition:background 0.15s;
}
.mob-link:hover .mob-ico,.mob-accordion.open .mob-ico{background:rgba(22,192,183,0.2);}
.mob-go,.mob-acc-icon{margin-left:auto;font-size:12px;color:var(--teal);opacity:0.7;}
.mob-acc-icon{transition:transform 0.25s;}
.mob-accordion.open .mob-acc-icon{transform:rotate(180deg);opacity:1;}
.mob-tag{
  font-family:var(--mono2);font-size:9px;letter-spacing:0.12em;text-transform:uppercase;
  padding:3px 7px;border-radius:999px;
  background:var(--teal);color:#050b12;
}
/* Sections grow to whatever they hold; nothing is clipped. */
.mob-acc-panel{display:grid;grid-template-rows:0fr;transition:grid-template-rows 0.3s ease;}
.mob-accordion.open .mob-acc-panel{grid-template-rows:1fr;}
.mob-acc-inner{min-height:0;overflow:hidden;background:rgba(5,11,18,0.35);}
.mob-accordion.open .mob-acc-inner{border-bottom:1px solid rgba(22,192,183,0.1);}
.mob-sublink{
  display:flex;align-items:center;gap:8px;
  padding:11px 20px 11px 68px;
  font-size:14.5px;font-weight:600;color:rgba(248,250,252,0.72);
  text-decoration:none;border-bottom:1px solid rgba(255,255,255,0.03);
  position:relative;transition:color 0.15s,background 0.15s;
}
.mob-sublink::before{
  content:'';position:absolute;left:52px;top:50%;width:5px;height:5px;border-radius:50%;
  background:rgba(22,192,183,0.35);transform:translateY(-50%);
}
.mob-sublink:hover,.mob-sublink:active{color:var(--teal);background:rgba(22,192,183,0.05);}
.mob-sublink:hover::before{background:var(--teal);}
.mob-sublink-all{color:var(--teal);font-weight:800;}
.mob-sublink-all i{font-size:12px;}
.mob-sublink-case b{
  margin-left:auto;font-family:var(--mono2);font-size:11px;font-weight:700;
  color:var(--teal);letter-spacing:0.02em;
}
/* Column headings from the desktop mega menus. */
.mob-subhead{
  display:block;padding:14px 20px 4px 52px;
  font-family:var(--mono2);
  font-size:10px;letter-spacing:0.14em;text-transform:uppercase;
  color:var(--teal);opacity:0.85;
}
/* The page the visitor is already on. */
.mob-link[aria-current="page"],.mob-sublink[aria-current="page"]{color:var(--teal);}
.mob-sublink[aria-current="page"]::before{background:var(--teal);box-shadow:0 0 0 3px rgba(22,192,183,0.2);}

.mob-footer{
  flex-shrink:0;
  padding:12px 20px calc(16px + env(safe-area-inset-bottom));
  border-top:1px solid rgba(22,192,183,0.12);
  background:#0c1a26;
  display:flex;flex-direction:column;gap:10px;
}
.mob-proof{
  display:flex;align-items:center;justify-content:center;gap:8px;
  font-size:12.5px;color:var(--muted);text-decoration:none;
}
.mob-proof b{color:var(--text);}
.mob-proof-stars{display:inline-flex;gap:2px;color:#fbbf24;font-size:11px;}
.mob-footer-btns{display:grid;grid-template-columns:1fr 52px;gap:8px;}
.mob-cta-primary{
  display:flex;align-items:center;justify-content:center;gap:8px;
  background:var(--teal);color:#050b12;font-family:var(--font);
  font-weight:900;font-size:15px;min-height:50px;padding:0 14px;border-radius:12px;
  text-decoration:none;transition:background 0.2s;
}
.mob-cta-primary:hover{background:#1ad4ca;}
.mob-cta-phone{
  display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,0.05);color:var(--teal);font-size:18px;
  min-height:50px;border-radius:12px;
  text-decoration:none;border:1px solid rgba(22,192,183,0.3);transition:all 0.2s;
}
.mob-cta-phone:hover{border-color:var(--teal);background:rgba(22,192,183,0.12);}
.mob-socials{display:flex;justify-content:center;gap:8px;}
.mob-soc{
  width:34px;height:34px;border-radius:8px;
  background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.08);
  display:flex;align-items:center;justify-content:center;
  color:var(--muted);font-size:13px;text-decoration:none;transition:all 0.2s;
}
.mob-soc:hover{color:#fff;background:rgba(255,255,255,0.12);}
.mob-accordion{border-bottom:1px solid rgba(255,255,255,0.04);}
.mob-acc-toggle{border-bottom:none;}
@media (prefers-reduced-motion:reduce){
  .mob-panel,.mob-backdrop{animation:none;}
  .mob-acc-panel,.mob-acc-icon{transition:none;}
}
/* Very small phones: the footer's trust line is the first to go. */
@media (max-height:620px){.mob-proof,.mob-socials{display:none;}}


/* ── PROOF BADGE (fixed) ── */
.proof-badge{
  position:fixed;bottom:24px;left:24px;z-index:400;
  display:flex;align-items:center;gap:10px;
  padding:10px 18px;
  background:rgba(8,18,28,0.92);backdrop-filter:blur(12px);
  border:1px solid rgba(22,192,183,0.2);border-radius:12px;
  text-decoration:none;
  transition:all 0.25s;
  box-shadow:0 8px 24px rgba(0,0,0,0.4);
  animation:proofBadgeIn 0.6s 3s both;
}
.proof-badge:hover{border-color:var(--teal);background:rgba(22,192,183,0.1);transform:translateY(-2px);}
.proof-badge-icon{
  width:32px;height:32px;border-radius:50%;flex-shrink:0;
  background:rgba(22,192,183,0.12);
  display:flex;align-items:center;justify-content:center;
  color:var(--teal);font-size:13px;
}
.proof-badge-text{font-size:12px;font-weight:700;color:var(--text);line-height:1.3;}
.proof-badge-text span{display:block;font-size:10px;font-weight:400;color:var(--muted);margin-top:1px;}
@keyframes proofBadgeIn{from{opacity:0;transform:translateY(20px);}to{opacity:1;transform:translateY(0);}}

/* ── PROOF CHIP PULSE ── */
.proof-chip{animation:chipPulse 4s ease-in-out infinite;}
.proof-chip:nth-child(1){animation-delay:0s;}
.proof-chip:nth-child(2){animation-delay:1s;}
.proof-chip:nth-child(3){animation-delay:2s;}
.proof-chip:nth-child(4){animation-delay:3s;}
@keyframes chipPulse{
  0%,100%{border-color:rgba(22,192,183,0.12);box-shadow:none;}
  50%{border-color:rgba(22,192,183,0.35);box-shadow:0 0 12px rgba(22,192,183,0.1);}
}

/* ── HEX INDUSTRY TAGS ── */
.hex-tags{
  display:flex;gap:4px;flex-wrap:wrap;justify-content:center;
  position:relative;z-index:1;margin-top:6px;
}
.hex-tag{
  font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:0.5px;
  padding:4px 9px;border-radius:4px;
  background:rgba(22,192,183,0.15);color:var(--teal);
  transition:all 0.3s;
}
.hex-card:hover .hex-tag{background:rgba(5,11,18,0.85);color:var(--teal);}

/* ── HEX BUILDER (scroll reveal) ── */
.hex-builder{
  position:relative;height:320px;
  display:flex;align-items:center;justify-content:center;
  overflow:hidden;
}
.hex-builder-grid{
  display:grid;grid-template-columns:repeat(5,64px);gap:4px;
  justify-content:center;
}
.hex-builder-cell{
  width:64px;height:74px;
  clip-path:polygon(50% 0%,100% 25%,100% 75%,50% 100%,0% 75%,0% 25%);
  transition:all 0.8s cubic-bezier(0.16,1,0.3,1);
  opacity:0;transform:scale(0.3) rotate(60deg);
}
.hex-builder-cell.revealed{opacity:1;transform:scale(1) rotate(0deg);}
.hex-builder-cell:nth-child(odd){background:rgba(22,192,183,0.35);border:1px solid rgba(22,192,183,0.5);}
.hex-builder-cell:nth-child(even){background:rgba(15,33,51,0.95);border:1px solid rgba(33,62,89,0.8);}
.hex-builder-cell:nth-child(3n){background:var(--teal);opacity:0;transform:scale(0.3) rotate(60deg);border:none;}
.hex-builder-cell:nth-child(3n).revealed{opacity:0.55;}
.hex-builder-cell:nth-child(5n+2){background:rgba(22,192,183,0.2);border:1px solid rgba(22,192,183,0.4);}
/* Stagger the reveal */
.hex-builder-cell:nth-child(1){transition-delay:0s;}
.hex-builder-cell:nth-child(2){transition-delay:0.06s;}
.hex-builder-cell:nth-child(3){transition-delay:0.12s;}
.hex-builder-cell:nth-child(4){transition-delay:0.18s;}
.hex-builder-cell:nth-child(5){transition-delay:0.24s;}
.hex-builder-cell:nth-child(6){transition-delay:0.1s;}
.hex-builder-cell:nth-child(7){transition-delay:0.16s;}
.hex-builder-cell:nth-child(8){transition-delay:0.22s;}
.hex-builder-cell:nth-child(9){transition-delay:0.28s;}
.hex-builder-cell:nth-child(10){transition-delay:0.34s;}
.hex-builder-cell:nth-child(11){transition-delay:0.2s;}
.hex-builder-cell:nth-child(12){transition-delay:0.26s;}
.hex-builder-cell:nth-child(13){transition-delay:0.32s;}
.hex-builder-cell:nth-child(14){transition-delay:0.38s;}
.hex-builder-cell:nth-child(15){transition-delay:0.44s;}
.hex-builder-cell:nth-child(n+6){margin-top:-20px;}
.hex-builder-cell:nth-child(n+11){margin-top:-20px;}
/* Row offsets for honeycomb */
.hex-builder-grid>:nth-child(n+6):nth-child(-n+10){transform-origin:center;margin-left:32px;}
.hex-builder-cell:nth-child(n+6):nth-child(-n+10).revealed{margin-left:32px;}
.hex-builder-center-text{
  position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  text-align:center;z-index:2;opacity:0;transition:opacity 0.6s 0.5s;
  pointer-events:none;
}
.hex-builder.active .hex-builder-center-text{opacity:1;}
.hex-builder-center-text h3{font-size:22px;font-weight:900;letter-spacing:-0.3px;margin-bottom:4px;}
.hex-builder-center-text p{font-size:12px;color:var(--muted);}


/* ── MOBILE RESPONSIVE ── */
/* ── MOBILE RESPONSIVE ── */
@media(max-width:767px){
  .hex-card{width:46%;height:auto;min-height:140px;clip-path:none;border-radius:14px;padding:20px 16px;margin-top:0 !important;}
  .hex-card:nth-child(odd){background:rgba(22,192,183,0.06);border:1px solid rgba(22,192,183,0.1);}
  .hex-card:nth-child(even){background:rgba(33,62,89,0.25);border:1px solid rgba(33,62,89,0.2);}
  .hex-card::before{display:none;}
  .hex-card:hover{transform:none;box-shadow:none;}
  .hex-desc{opacity:1;transform:none;color:var(--muted);}
  .honeycomb{flex-direction:row;flex-wrap:wrap;justify-content:center;gap:10px;padding:0 10px;}
  .hex-row{display:contents;}
  .hex-row + .hex-row{margin-top:0;}
  .hex-callout{width:200px;height:220px;padding:1.3rem 1rem;}
  .hex-callout .callout-big{font-size:36px;}
  .intro-grid{grid-template-columns:1fr;gap:40px;}
  .intro-hex-pair{width:360px;height:310px;}
  .hex-callout-secondary{top:110px;left:160px;}
  .metrics-grid{grid-template-columns:repeat(2,1fr);}
  .metric-box:last-child{grid-column:span 2;}
  .future-grid,.ai-grid,.analyzer-inner{grid-template-columns:1fr;}
  .ai-banner-inner{flex-direction:column;padding:28px 20px;}
  .story-section-v2{min-height:auto;padding:60px 0;}
  .cta-section .reveal{grid-template-columns:1fr !important;text-align:center;}
  .cta-section .reveal div:first-child{text-align:center;}
  .cta-section .reveal .cta-h{text-align:center !important;}
  .big-quote{font-size:22px;padding-left:20px;}
  .quote-break .container{grid-template-columns:1fr !important;}
  .hex-builder{display:none;}
  .proof-badge{bottom:12px;left:12px;padding:8px 14px;}
  .hex-tags{display:none;}
  .vt-grid{grid-template-columns:1fr;}
  .process-grid{grid-template-columns:1fr;}
  .hero-social-proof{padding:8px 14px;gap:8px;}
  .hero-proof-sep{display:none;}
  .ft-watch{display:none;}
  .ft-quote{font-size:13px;}
}
@media(max-width:480px){
  .hex-card{width:100%;}
  .honeycomb{flex-direction:column;align-items:stretch;}
  .hex-callout{width:170px;height:187px;padding:1rem 0.8rem;}
  .hex-callout .callout-big{font-size:30px;}
  .intro-hex-pair{width:310px;height:260px;}
  .hex-callout-secondary{top:93px;left:140px;}
}

/* ══════════════════════════════════════════════════
   VIDEO MODAL
   ══════════════════════════════════════════════════
   The previous version inlined position/background/display
   styles directly on the markup. They live here now so JS can
   open/close via the [hidden] attribute + .is-open class.
*/
.video-modal{
  position:fixed;inset:0;z-index:999;
  background:rgba(0,0,0,0.9);
  display:flex;align-items:center;justify-content:center;
}
.video-modal[hidden]{display:none;}
.video-modal-frame{
  position:relative;width:90%;max-width:900px;aspect-ratio:16/9;
}
.video-modal-frame iframe{
  width:100%;height:100%;border:none;border-radius:12px;
}
.video-modal-close{
  position:absolute;top:-44px;right:0;
  background:none;border:none;
  color:#fff;font-size:20px;font-family:var(--font);
  cursor:pointer;
  display:flex;align-items:center;gap:6px;
}
.video-modal-close:hover{color:var(--teal);}

/* ══════════════════════════════════════════════════
   NEWSLETTER MESSAGE — inline status under the form
   ══════════════════════════════════════════════════ */
.f-newsletter-msg{
  width:100%;
  margin-top:10px;
  font-size:13px;
  color:var(--teal);
}

/* ══════════════════════════════════════════════════
   STATEMENT BAND — the big-type breather
   ══════════════════════════════════════════════════
   We sell SEO, so almost every page is long and word-dense by
   necessity: service breakdowns, methodology, FAQ, local copy. The
   cost is that a visitor scrolling fast never hits a moment that
   says one thing loudly. This is that moment — a full band carrying
   a single short sentence at display scale with a lot of air around
   it, dropped between chapters to reset the eye.

   Rules that keep it working:
     · One sentence. If it needs two, it isn't a statement.
     · The supporting line is optional and never more than a line
       or two — it exists to catch the reader the headline hooked.
     · At most two per page, and never back to back.

   Markup:
     <section class="statement statement-cream">
       <div class="container"><div class="statement-inner">
         <span class="eyebrow">…</span>
         <h2>Rankings aren't the <span class="boxed">product</span>.</h2>
         <p>…optional supporting line…</p>
         <a href="…" class="btn">…optional…</a>
       </div></div>
     </section>
   ══════════════════════════════════════════════════ */
.statement{
  position:relative;
  padding:clamp(84px,10.5vw,168px) 0;
  border-top:1px solid rgba(255,255,255,0.1);
}
.statement h2{
  font-family:var(--disp);
  font-weight:400;
  text-transform:uppercase;
  font-size:clamp(34px,6vw,86px);
  /* 1.04 rather than the ~0.95 a display headline would normally
     take: the boxed keyword's 3px border and offset shadow need the
     extra leading, or the box clips the line above it. */
  line-height:1.04;
  letter-spacing:-0.02em;
  margin:0;
  /* 16ch forces a break every three or four words, which is what
     gives the band its stacked, poster-like shape. Wider and it
     reads as an ordinary section heading. */
  max-width:16ch;
  /* At 34px a long word can be wider than a 390px phone, and this
     heading is uppercase, which makes every word wider still.
     Without this the page scrolls sideways: "entrepreneurship" on
     /seo-company-in-los-angeles/ overran by 7px. Breaking a word
     is only a last resort here — normal wrapping is tried first. */
  overflow-wrap:break-word;
}
.statement h2 em{font-size:1.04em;}
.statement > .container > .statement-inner > .eyebrow{margin-bottom:22px;}
.statement p{
  margin:30px 0 0;
  max-width:46ch;
  font-size:clamp(16px,1.15vw,18.5px);
  line-height:1.72;
  color:var(--muted);
}
.statement .btn{margin-top:34px;}

/* The boxed keyword. An outline plus a flat offset shadow — the same
   paper-and-ink move as the tilted local pack and the polaroids,
   rather than a glow or a gradient. The tilt is small on purpose:
   enough to read as drawn by hand, not enough to look broken. */
.boxed{
  display:inline-block;
  /* The keyword drops out of the uppercase display face into the
     serif italic the headline accents already use, so the box reads
     as a hand-drawn note over machine type rather than as more of
     the same. 1.16em brings the serif's smaller x-height back up to
     the cap height of the Archivo Black around it, and the extra
     right padding gives the italic lean somewhere to go before it
     touches the border. */
  font-family:'Instrument Serif','Instrument Serif Fallback',serif;
  font-style:italic;
  font-weight:400;
  font-size:1.16em;
  text-transform:none;
  letter-spacing:0;
  line-height:0.86;
  padding:0.06em 0.26em 0.08em 0.16em;
  border:3px solid var(--teal);
  border-radius:6px;
  color:var(--teal);
  transform:rotate(-1.1deg);
  box-shadow:7px 7px 0 rgba(22,192,183,0.16);
}
/* Solid variant, for when the keyword should carry the weight. */
.boxed-fill{
  background:var(--teal);
  color:var(--obsidian);
  box-shadow:7px 7px 0 rgba(22,192,183,0.2);
}

/* Warm variant. Inherits everything above and re-inks it — same
   band, opposite tone, so two statements on one page can sit in
   different chapters without repeating themselves. */
.statement-cream{
  background:var(--cream);
  color:var(--ink);
  border-top:1px solid rgba(30,52,72,0.14);
}
.statement-sand{
  background:var(--sand);
  color:var(--ink);
  border-top:1px solid rgba(30,52,72,0.14);
}
.statement-cream h2,
.statement-sand h2{color:var(--ink);}
.statement-cream p,
.statement-sand p{color:var(--ink-soft);}
.statement-cream .eyebrow,
.statement-sand .eyebrow{color:var(--teal-ink);}
.statement-cream h2 em,
.statement-sand h2 em{color:var(--teal-ink) !important;}
.statement-cream .boxed,
.statement-sand .boxed{
  border-color:var(--teal-ink);
  color:var(--teal-ink);
  box-shadow:7px 7px 0 rgba(11,138,130,0.14);
}
.statement-cream .boxed-fill,
.statement-sand .boxed-fill{
  background:var(--teal-ink);
  color:#fff;
}

/* ── PHOTO VARIANT ──
 * A statement band is one short sentence against a lot of air, which
 * is the point — but at 16ch the headline only occupies the left
 * third and the right two-thirds sit empty. This fills that half with
 * a photograph that dissolves before it reaches the type.
 *
 * The fade is a mask, not an opacity ramp over a color: masking to
 * transparent lets the band's own background show through, so one
 * rule works on the dark variant and the two light ones without
 * needing a matching gradient color for each. Nothing is composited
 * behind the text at all — the mask is fully transparent across the
 * left 40% — so this cannot affect contrast, which is why it can be
 * this open where the CTA photo had to sit under a heavy overlay.
 *
 * Applied to every statement band, with the image cycling across
 * three photographs so a page with several of them does not repeat
 * the same shot down the scroll. */
.statement::before,
.statement-photo::before{
  content:"";
  position:absolute;
  inset:0;
  background-image:
    linear-gradient(90deg,
      var(--stmt-scrim) 0%,
      var(--stmt-scrim) 54%,
      var(--stmt-scrim-mid) 70%,
      var(--stmt-scrim-out) 84%,
      transparent 94%),
    var(--statement-photo,var(--statement-photo-auto,var(--work-photo)));
  background-size:cover,cover;
  background-position:center 42%,center 42%;
  background-repeat:no-repeat,no-repeat;
  pointer-events:none;
  z-index:0;
}
/* The scrim is the band's own color at high opacity over the text and
   nothing at all past it, so the photograph runs edge to edge and only
   dims where words sit. Replaces the earlier approach, which masked the
   IMAGE away on the left — that left a hard boundary where the picture
   started and confined it to a strip. Here the picture is continuous
   and the readability comes from what is laid over it.
   
   Each variant scrims in its own color; black over a light band would
   read as a grey smear rather than a fade. */
/* Every statement band carries a photo now, not just the ones marked
   .statement-photo. 45 of them were flat color, and a full-width
   moment with nothing behind it is the weakest thing on the page —
   the scrim already exists to make the type readable over an image,
   so there is no reason to withhold it.
   .statement-photo is kept as an explicit marker (same result) so
   existing markup and per-section --statement-photo overrides keep
   working; .statement-flat opts a band out. */
.statement,
.statement-photo{
  --stmt-scrim:rgba(5,11,18,0.97);
  --stmt-scrim-mid:rgba(5,11,18,0.62);
  --stmt-scrim-out:rgba(5,11,18,0.16);
}
/* Cycle the three photos so a page with several bands does not
   repeat the same image down the scroll. */
/* Six-deep, not three. With three photos a page carrying more than a
   couple of statement bands started repeating, and every page repeated
   in the same order — so the bands read as one image reused rather
   than as a set. The office photos widen the pool.

   Counting is by nth-of-type, so the index is the section's position
   among its <section> siblings rather than among .statement elements.
   That is what the three-cycle already did, and it is the better
   behavior here: two statement bands with other sections between them
   land on different photos instead of the same one. */
.statement:nth-of-type(6n+1){--statement-photo-auto:var(--work-photo);}
.statement:nth-of-type(6n+2){--statement-photo-auto:var(--team-photo);}
.statement:nth-of-type(6n+3){--statement-photo-auto:var(--dev-photo);}
.statement:nth-of-type(6n+4){--statement-photo-auto:var(--office-photo);}
.statement:nth-of-type(6n+5){--statement-photo-auto:var(--workspace-photo);}
.statement:nth-of-type(6n+6){--statement-photo-auto:var(--podcast-photo);}
.statement-flat::before{content:none !important;}
.statement-cream,
.statement-cream.statement-photo{
  --stmt-scrim:rgba(244,247,251,0.97);
  --stmt-scrim-mid:rgba(244,247,251,0.66);
  --stmt-scrim-out:rgba(244,247,251,0.18);
}
.statement-sand,
.statement-sand.statement-photo{
  --stmt-scrim:rgba(255,255,255,0.97);
  --stmt-scrim-mid:rgba(255,255,255,0.66);
  --stmt-scrim-out:rgba(255,255,255,0.18);
}
.statement-cream::before,
.statement-sand::before{filter:saturate(0.9);}
.statement > .container,
.statement-photo > .container{position:relative;z-index:1;}
/* The measure can go back to normal now that the photo runs under the
   text rather than starting beside it — the scrim, not the gap, is
   what keeps the words readable. */
.statement h2,
.statement-photo h2{max-width:15ch;}
.statement p,
.statement-photo p{max-width:42ch;}

@media (max-width:1100px){
  /* Below this the headline's 16ch measure starts reaching into the
     photo's half. Rather than shrink one or crop the other, the photo
     drops out — the band still works as pure type, which is how the
     other 40 of them work. */
  .statement::before,
  .statement-photo::before{display:none;}
}

/* Hexagon on the seam, matching every other chapter break. */
.statement::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;
}
.statement-cream::after,
.statement-sand::after{background:var(--teal-ink);opacity:0.6;}

@media (max-width:900px){
  .statement{padding:64px 0;}
  .statement h2{font-size:clamp(30px,8.4vw,44px);max-width:none;}
  .statement p{margin-top:22px;}
  .boxed{box-shadow:4px 4px 0 rgba(22,192,183,0.16);}
}

/* ══════════════════════════════════════════════════
   AUDIT DOMAIN FIELD
   ══════════════════════════════════════════════════
   Moved here from front-page.css when the Free Audit page started
   using the same component. It was homepage-only, so the field
   would have rendered completely unstyled on the new page — the
   markup and the JS were shared but the CSS was not.
   ══════════════════════════════════════════════════ */

.domain-input-wrap{
  display:flex;
  gap:0;
  border:1px solid rgba(30,52,72,0.25);
  border-radius:12px;
  overflow:hidden;
  background:#fff;
  transition:border-color 0.2s;
}
.domain-input-wrap:focus-within{border-color:var(--teal-ink);}
.domain-input{
  flex:1;
  min-width:0;
  background:transparent;
  border:none;
  outline:none;
  color:var(--ink);
  font-family:var(--font);
  font-size:16px;
  padding:18px 20px;
}
.domain-input::placeholder{color:var(--ink-faint);}
.domain-submit{
  flex-shrink:0;
  background:var(--teal);
  color:#050b12;
  border:none;
  cursor:pointer;
  font-family:var(--font);
  font-weight:800;
  font-size:15px;
  padding:0 26px;
  transition:background 0.2s;
}
.domain-submit:hover{background:#1ad4ca;}
/* This component now appears in two tonal contexts, so the base is
 * the DARK one and the homepage's light band overrides it. It used
 * to be the other way round by accident — the rule was written when
 * the only instance sat in .audit-section, which is a light band,
 * so on the Free Audit page's dark hero the copy came out
 * dark-on-dark at 1.32:1.
 *
 * Getting this backwards is easy: --ink-soft and --teal-ink are for
 * light grounds, --muted and --teal for dark ones. */
.audit-fine{
  font-size:13px;
  color:var(--muted);
  margin-top:14px;
}
.audit-fine a{color:var(--teal);text-decoration:none;font-weight:700;}
.audit-fine a:hover{color:#1ad4ca;}

/* Homepage: the field sits inside the light .audit-section band. */
.audit-section .audit-fine{color:var(--ink-soft);}
.audit-section .audit-fine a{color:var(--teal-ink);}
.audit-section .audit-fine a:hover{color:var(--teal-ink);text-decoration:underline;}

/* Stacks on mobile. Was inside front-page.css's media block, which
   would have left the field side-by-side and overflowing on the
   Free Audit page. */
@media (max-width:900px){
  .domain-input-wrap{flex-direction:column;}
  .domain-input{padding:16px 18px;}
}

/* ══════════════════════════════════════════════════
   TEAM FACES
   ══════════════════════════════════════════════════
   Moved here from front-page.css when the strip became a shared
   template part. It now appears on the homepage, on every generated
   /teams/{slug}/ profile, and on the interiors that include it — one
   definition rather than a copy per surface.
   ══════════════════════════════════════════════════ */

/* ── FACES STRIP — real headshots from the team roster ── */
/* The strip as it appears inside an existing section — the homepage
 * uses this, via the team-faces part's `wrap => false`.
 *
 * A vertical stack, not a row. This was display:flex with
 * flex-wrap:wrap, which made the eyebrow, the portraits and the link
 * three items in one wrapping row, and — worse — left .faces-row
 * sized to its max-content as a flex item, so the portraits inside
 * it could never shrink to fit and simply overflowed the container. */
.people-faces{
  display:block;
  /* NOT overflow:hidden. This one sits inside the page container, so
   * clipping here would crop the comb's full-bleed breakout back to
   * the container and the band would stop short of the window edges
   * — which is the whole point of it. The comb fills exactly 100vw
   * and no more, so there is nothing to clip. */
  margin-top:88px;
  padding-top:44px;
  border-top:1px solid rgba(30,52,72,0.12);
}
/* Honeycomb rhythm: real gaps between portraits, with every other
 * one dropped so the row reads as a comb rather than a solid band.
 * The stagger lives in a per-item --y so the hover lift can compose
 * with it instead of overwriting the transform. */
/* One row, whatever the roster size.
 *
 * This used to wrap, which sounds safe and is not: the strip renders
 * every member with a headshot, and at fourteen people the last one
 * dropped to a second line on its own. A single orphan under a
 * staggered row reads as a bug, and it would come back every time
 * somebody joined.
 *
 * So the faces shrink to fit instead. flex-shrink on a flex-basis of
 * the ideal width lets fourteen or twenty share the row, with
 * min-width as the floor where shrinking stops being legible — past
 * that it wraps, which by then is the right answer. */
.faces-row{
  display:flex;
  align-items:center;
  /* No gap: the portraits interlock instead of sitting apart. See
   * the honeycomb note on .face below. */
  gap:0;
  row-gap:0;
  flex-wrap:wrap;
  min-width:0;
  /* The cell is sized from the viewport, NOT by letting flex-grow
   * divide up the row. That matters because the interlock is a
   * negative margin of a quarter of --fw, and a margin cannot
   * reference the width flex actually handed the element. While the
   * cells grew to fill the row, the two disagreed: at 1920 the cells
   * came out 131px and were still being pulled together by a quarter
   * of 104px, so the comb stopped nesting and opened white gaps
   * between the portraits. Sizing from vw keeps the rendered width
   * equal to --fw, which keeps the nesting exact at every width.
   *
   * 7.1vw is the width at which the current roster very nearly spans
   * the window; the clamp holds the cell legible on a phone and
   * stops it inflating on a very wide screen. */
  --fw:clamp(56px,7.1vw,132px);
  /* FULL BLEED. The band is a seam between two sections, so the comb
   * runs the width of the window and is clipped by the band's
   * overflow at both ends — it reads as a continuous ribbon rather
   * than a row that stops short of the edges. The eyebrow and the
   * link stay in the container with the rest of the page.
   *
   * The vertical margin is the clearance the stagger needs. Cells are
   * translated, which does not affect layout, so a cell's ink reaches
   * a quarter of its height past the row's box at top and bottom. At
   * the 170px cap that is about 49px, and this clears it. */
  margin:34px calc(-50vw + 50%);
  width:auto;
  justify-content:center;
  /* The row is already exactly the width of the window, so clipping
   * HERE is what cuts the comb at the window edges — and it works for
   * both bands, including the one on the homepage that cannot clip on
   * its own wrapper without cropping the breakout away. It also stops
   * a roster long enough to overrun the row from putting a horizontal
   * scrollbar on the page.
   *
   * clip rather than hidden, and on one axis only: the cells are
   * translated a quarter of their height up and down, and overflow
   * on both axes would slice the top and bottom off the portraits. */
  overflow-x:clip;
  overflow-y:visible;
}
/* nowrap is what makes the shrinking happen, and it is load-bearing
 * rather than cosmetic.
 *
 * Flex items are collected into lines using their FLEX BASIS, and
 * flex-shrink is applied per line only afterwards. So with wrapping
 * enabled the portraits break onto a second line at their full width
 * instead of shrinking to share one — the row never gets the chance
 * to compress. Letting the row wrap "as a last resort" therefore does
 * the opposite of what it sounds like: it guarantees the ragged
 * second line instead of preventing it.
 *
 * Below this width the honeycomb becomes a block of several rows,
 * which is the right shape on a phone. Above it, one row always. */
@media (min-width:760px){
  .faces-row{flex-wrap:nowrap;}
}
/* On a phone, a smaller cell so the block is three rows rather than
 * five, and a shallower stagger to match. */
@media (max-width:759px){
  .faces-row{margin:40px calc(-50vw + 50%);}

}
/* Hexagon portraits — the brand mark applied to the team strip.
 * clip-path crops borders, so the ring is faked by clipping the
 * anchor (which carries the ring color) and clipping the image
 * again inside its 3px padding. */
.face{
  /* HONEYCOMB.
   *
   * The portraits tessellate rather than sitting in a line with gaps
   * between them: each one overlaps its neighbour by a quarter of its
   * width and alternates half a cell up or down, which is the exact
   * nesting for this hexagon at 84x96. Two things come out of it.
   * The row carries about a third more people in the same width, so
   * the whole roster stays on one line as the team grows — the strip
   * used to overflow at eighteen on a 1000px screen. And the shape
   * reads as a deliberate beehive instead of a staggered row that
   * happens to be crowded.
   *
   * --fw is the ideal cell width and the overlap is derived from it,
   * so changing one number rescales the comb. flex takes the cells
   * above or below --fw to fill the row; min-width is where
   * shrinking stops being legible and max-width stops a small roster
   * from inflating to fill a wide window.
   *
   * The stagger is a PERCENTAGE rather than a pixel count, because
   * translateY percentages resolve against the element's own height.
   * A quarter up and a quarter down is half a cell between
   * neighbours, which is the nesting, and it stays exact at every
   * cell size without anyone recomputing it. It was ±24px, correct
   * only at the 84px cell it was written for — the comb stopped
   * nesting the moment the cells grew. */
  --y:-25%;
  display:block;
  /* Shrinkable rather than fixed, so the row above can fit the whole
   * roster. aspect-ratio keeps the hexagon in proportion as the width
   * changes — a fixed height here would squash the clip-path. */
  /* Shrinks but does not grow: the rendered width stays equal to
   * --fw, which is what keeps the interlock exact. Shrink is kept as
   * the safety valve for a roster long enough to overrun the row,
   * where a slightly tighter comb beats a horizontal scrollbar. */
  flex:0 1 var(--fw);
  width:var(--fw);
  min-width:44px;
  aspect-ratio:84 / 96;
  height:auto;
  padding:3px;
  background:rgba(30,52,72,0.22);
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
  --s:1;
  transform:translateY(var(--y)) scale(var(--s));
  transition:transform 0.2s ease,background 0.2s ease,filter 0.2s ease,opacity 0.2s ease;
  position:relative;
}
.face:nth-child(even){--y:25%;}
/* The quarter-width bite that makes the cells interlock. */
.face + .face{margin-left:calc(var(--fw) * -0.25);}
.face:hover{
  transform:translateY(calc(var(--y) - 6px)) scale(calc(var(--s) * 1.07));
  background:var(--teal-ink);
  z-index:2;
}

/* ── DEPARTMENT EMPHASIS ──
 *
 * A page about one discipline brings that department forward and
 * pushes the rest back, instead of showing only that department.
 * Filtering made an SEO page render three portraits and read as
 * though three people work here — the opposite of what a team strip
 * is for. The whole roster stays on the page; the relevant people
 * are simply the ones you notice.
 *
 * Carried by color and the ring, NOT by size.
 *
 * The emphasis used to scale the cells — leads to 1.16, everyone
 * else to 0.88 — which was free when the portraits sat in a row with
 * gaps between them. In a honeycomb it is not: the cells tessellate,
 * so a lead at 1.16 swells over the two it is wedged between and a
 * muted cell at 0.88 leaves a hole where the comb expects a full
 * one. A department page ended up with a comb that bulged in the
 * middle and was pitted everywhere else — four distinct baselines
 * across the row instead of the two the stagger intends.
 *
 * Greyscale at half opacity against full color inside a teal ring
 * is already the louder signal; the size change was only ever
 * reinforcing it. Dropping it costs nothing and keeps every cell on
 * the comb. Hover still lifts and scales, because that is momentary
 * and reads as the row responding rather than as its shape. */
.face-lead{
  background:var(--teal);
  z-index:1;
}
.face-muted{
  filter:grayscale(1);
  opacity:0.5;
}
/* Hovering a dimmed face restores it — the muting is emphasis, not a
 * disabled state, and every portrait is still a link to a profile. */
.face-muted:hover{
  filter:grayscale(0);
  opacity:1;
}
@media (prefers-reduced-motion:reduce){
  .face{transition:none;}
}
.face img{
  width:100%;height:100%;
  object-fit:cover;
  display:block;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}
.faces-link{
  display:inline-flex;
  align-items:center;
  gap:8px;
  font-size:15.5px;
  font-weight:700;
  color:var(--teal-ink);
  text-decoration:none;
  transition:gap 0.2s;
}
.faces-link:hover{gap:12px;}
.faces-link i{font-size:11px;}

/* Wrapper for the standalone section version (the homepage renders
   it inside its own About band, so it has no wrapper there). */
.faces-section{
  position:relative;
  /* Clips the full-bleed comb at the window edges, and keeps the
   * breakout from ever producing a horizontal scrollbar. */
  overflow:hidden;
  padding:clamp(26px,2.6vw,40px) 0;
  background:var(--cream);
  border-top:1px solid rgba(30,52,72,0.14);
}
.faces-section .eyebrow{color:var(--teal-ink);}
.faces-section .faces-link{color:var(--teal-ink);}
.faces-section .face{background:rgba(30,52,72,0.18);}
/* Beats the line above, which is more specific than .face-lead and
   would otherwise flatten the emphasis ring on the cream band. */
.faces-section .face-lead{background:var(--teal-ink);}

/* ══════════════════════════════════════════════════
   CLIENT STRIP
   ══════════════════════════════════════════════════
   Moved here from front-page.css. It was homepage-only, which meant
   a visitor landing on a service page from search — most of them —
   never saw a single client name. The interiors now carry it under
   the hero via template-parts/client-strip.php, and both draw on
   this one definition rather than a copy each.
   ══════════════════════════════════════════════════ */
/* ═════════════════════════════════════════════════════════════
   CLIENT STRIP — text wordmarks
   ═════════════════════════════════════════════════════════════ */
.client-strip{
  background:var(--cream);
  border-bottom:1px solid rgba(30,52,72,0.1);
  padding:34px 0;
}
/* On the homepage the strip now sits under Our Work rather than under
   the hero. Both bands are cream, so without a rule they read as one
   section that happens to have client names loose at the bottom. */
.work-section + .client-strip{border-top:1px solid rgba(30,52,72,0.1);}.client-strip-inner{
  display:flex;
  align-items:center;
  gap:40px;
  flex-wrap:wrap;
}.client-strip-label{
  font-size:11px;
  font-weight:800;
  letter-spacing:0.16em;
  text-transform:uppercase;
  color:var(--ink-faint);
  flex-shrink:0;
}.client-marks{
  display:flex;
  align-items:center;
  gap:12px 36px;
  flex-wrap:wrap;
}
.client-mark{
  font-size:16px;
  font-weight:700;
  letter-spacing:-0.2px;
  /* 0.6 composited to 3.67:1 on the light band — under AA, and this
     strip is now on 33 pages, which made it the most-repeated
     contrast failure on the site. Only surfaced once the checker
     started compositing the text's own alpha instead of measuring
     the rgba as though it were opaque. */
  color:var(--ink-soft);
  white-space:nowrap;
}
.client-mark-more{
  font-weight:600;
  font-size:14px;
  color:var(--teal-ink);
  white-space:nowrap;
}

/* ── LOGO TILES ──
 *
 * A client with an uploaded logo renders as a tile rather than a
 * wordmark. The old rule set a bare 26px-tall image, which suits a
 * long horizontal wordmark and ruins a 300x200 file — a 3:2 logo at
 * 26px tall is 39px wide and unreadable.
 *
 * So each logo gets a fixed 3:2 box matching the source ratio, the
 * image is contained inside it with padding so nothing crops, and
 * the box does the aligning. Mixed logo files — some tight crops,
 * some with whitespace baked in — end up optically the same size,
 * which is the thing that makes a logo row look deliberate rather
 * than pasted together.
 *
 * Grayscale at rest, full color on hover: the strip sits under the
 * hero on 33 pages and is proof, not decoration. It should not
 * compete with the headline above it. */
.client-mark-logo{
  /* Sized so the logo itself reads, not the tile. At 118px with
     14px of side padding a 3:2 logo rendered about 90px wide, which
     is a favicon rather than a client mark. */
  width:172px;
  aspect-ratio:3 / 2;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:8px 10px;
  border-radius:12px;
  background:rgba(30,52,72,0.04);
  border:1px solid rgba(30,52,72,0.08);
  transition:background 0.25s ease,border-color 0.25s ease,transform 0.25s ease;
}
.client-mark-logo:hover{
  background:rgba(30,52,72,0.02);
  border-color:rgba(22,192,183,0.4);
  transform:translateY(-2px);
}
.client-mark img{
  display:block;
  width:100%;
  height:100%;
  object-fit:contain;
  filter:grayscale(1) opacity(0.72);
  transition:filter 0.25s ease;
}
.client-mark:hover img{filter:grayscale(0) opacity(1);}

/* Tighter gap once the marks are tiles — 36px between boxes that
   already carry their own padding reads as a gap, not a row. */
.client-marks:has(.client-mark-logo){gap:12px;}

/* The strip sits under the hero on 33 pages, so its height is a tax
   on every one of them. Tiles are kept small and, on a phone, the
   row scrolls sideways rather than wrapping — six wrapped tiles came
   to 296px of vertical space before a visitor reached any content. */
.client-strip:has(.client-mark-logo){padding:22px 0;}
.client-strip:has(.client-mark-logo) .client-strip-inner{gap:14px 28px;}

@media (max-width:1200px){
  .client-marks:has(.client-mark-logo){
    flex-wrap:nowrap;
    overflow-x:auto;
    scroll-snap-type:x proximity;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
    padding-bottom:2px;
    /* Bleed to the screen edge so the row reads as scrollable
       rather than as a row that happens to be clipped. */
    margin-right:calc(var(--gutter,1.25rem) * -1);
    padding-right:var(--gutter,1.25rem);
  }
  .client-marks:has(.client-mark-logo)::-webkit-scrollbar{display:none;}
  .client-mark-logo{flex:0 0 auto;scroll-snap-align:start;}
}
@media (max-width:760px){
  .client-mark-logo{width:140px;padding:7px 9px;}
}.client-strip keeps its own border-bottom for the seam it
     shares with .work-section, which is the one place two bands of
     the identical value meet. */
.work-section,
.people-section,
.pack-section,
.testi-section{border-top:1px solid rgba(30,52,72,0.16);}.client-strip-inner{gap:18px;}.client-marks{gap:10px 24px;}.client-mark{font-size:14px;}

/* ══════════════════════════════════════════════════
   SCREEN-READER ONLY
   ══════════════════════════════════════════════════
   For headings that a page needs structurally but not visually.
   The awards grid is the case that prompted it: a bare grid of
   award cards whose h3 titles sat directly under the page h1, so
   the outline jumped a level. WordPress ships .screen-reader-text
   with the same intent; this is aliased to it so either works.
   ══════════════════════════════════════════════════ */
.sr-only,
.screen-reader-text{
  position:absolute;
  width:1px;height:1px;
  padding:0;margin:-1px;
  overflow:hidden;
  clip:rect(0 0 0 0);
  clip-path:inset(50%);
  white-space:nowrap;
  border:0;
}

/* ══════════════════════════════════════════════════
   ACCENT UTILITIES
   ══════════════════════════════════════════════════
   These replace inline style attributes that were repeated across
   the interior templates — 118 of them between the classes below.

   The reason is not tidiness. An inline style outranks every
   selector short of !important, so a color written into the markup
   cannot be re-inked when the section it sits in changes tone. That
   already bit us: flipping Contact and the FAQ hub to a light band
   left three paragraphs unreadable, and the only fix was to edit the
   markup. Anything expressed as a class here can be answered by one
   rule in the light-band layer instead.

   Values are copied verbatim from the inline styles they replace, so
   the rendered result is identical — verified by diffing computed
   color, background and border across all 45 templates before and
   after the swap.
   ══════════════════════════════════════════════════ */
.t-link{color:var(--teal);font-weight:700;text-decoration:none;}
.t-link:hover{color:#1ad4ca;}
.t-teal{color:var(--teal);}
.t-purple{color:var(--purple);}
.t-blue{color:var(--blue);}
.t-pink{color:var(--pink);}
.t-green{color:var(--green);}
.t-meta{color:#9aa0a6;font-size:12px;}

/* Tinted state chips. Each keeps the tint it had inline. */
.chip-red{
  background:rgba(248,113,113,0.06);
  border:1px solid rgba(248,113,113,0.15);
  color:var(--red);
}
.chip-teal{background:rgba(22,192,183,0.08);color:var(--teal);}
.chip-purple{background:rgba(167,139,250,0.08);color:var(--purple);}
.chip-blue{background:rgba(96,165,250,0.08);color:var(--blue);}
.chip-pink{background:rgba(244,114,182,0.08);color:var(--pink);}
.chip-green{background:rgba(52,211,153,0.08);color:var(--green);}
.chip-orange{background:rgba(251,146,60,0.08);color:var(--orange);}
.chip-red-soft{background:rgba(248,113,113,0.08);border:1px solid rgba(248,113,113,0.2);color:var(--red);}
.t-orange{color:var(--orange);}
.t-faint{color:rgba(255,255,255,0.4);}

/* Some templates wrote these chips at 0.1 alpha and others at 0.08.
 * Both fold into the 0.08 classes above: two points of alpha on a
 * tint this light is below the threshold of visible difference, and
 * carrying two near-identical classes to preserve it would defeat
 * the point of having classes at all. Everything else in this block
 * is byte-identical to the inline style it replaced. */

/* ══════════════════════════════════════════════════
   REDUCED MOTION
   ══════════════════════════════════════════════════
   WCAG 2.3.3 — when the OS exposes "reduce motion" we kill every
   animation, transition, and infinite keyframe loop site-wide. The JS
   side (front-page.js, global.js) also gates its scripted animations
   behind window.matchMedia('(prefers-reduced-motion: reduce)') so the
   typewriter, hex builder cascade, kickoff-hex spinner, and hero
   canvas particle loop never start.

   We use the standard duration-snap pattern (0.01ms) instead of
   `none` so :hover / state changes still feel responsive, but
   nothing tweens.
*/
@media (prefers-reduced-motion: reduce){
  *,
  *::before,
  *::after{
    animation-duration:0.01ms !important;
    animation-iteration-count:1 !important;
    animation-delay:0ms !important;
    transition-duration:0.01ms !important;
    transition-delay:0ms !important;
    scroll-behavior:auto !important;
  }
  html{scroll-behavior:auto;}
}


/* ══════════════════════════════════════════════════
   GOOGLE REVIEW PROOF BAND
   ══════════════════════════════════════════════════
   Live Places data on the interior pages. Light band, because it
   sits between two dark sections on most templates and the tonal
   break is part of what makes it register as a different kind of
   claim from the copy around it.
   ══════════════════════════════════════════════════ */
.rp-band{
  position:relative;
  padding:clamp(52px,5.5vw,80px) 0;
  background:var(--cream);
  border-top:1px solid rgba(30,52,72,0.14);
  color:var(--ink-soft);
}
.rp-inner{display:grid;grid-template-columns:250px 1fr;gap:clamp(28px,3.5vw,52px);align-items:start;}
.rp-band .eyebrow{color:var(--teal-ink);}

/* ── Google signals ──
 * The G, the gold stars and the reviewer's own avatar. Without them
 * this band reads as testimonials we wrote about ourselves, which is
 * exactly the thing a review is supposed to rule out. */
.rp-brand{
  display:flex;
  align-items:center;
  gap:9px;
  margin-top:14px;
  font-size:13px;
  font-weight:800;
  letter-spacing:-0.1px;
  color:var(--ink);
}
/* inline-block, not block: the mark also sits inline inside eyebrow
   text ("[G] Google Reviews"), where display:block would push the
   words onto their own line. Flex containers blockify their children
   anyway, so the card and badge layouts are unaffected. */
.g-mark{display:inline-block;vertical-align:-0.18em;flex-shrink:0;}
.g-stars{display:inline-flex;align-items:center;gap:2px;line-height:0;}
.g-stars svg{display:block;}

.rp-score-row{display:flex;align-items:center;gap:12px;margin-top:8px;}
.rp-score-num{
  font-family:var(--disp);
  font-size:clamp(38px,4vw,56px);
  line-height:1;
  color:var(--ink);
}
.rp-score-meta{margin-top:10px;font-size:13.5px;color:var(--ink-soft);}
.rp-all{
  display:inline-flex;align-items:center;gap:8px;margin-top:16px;padding:6px 0;
  font-size:14px;font-weight:800;color:var(--teal-ink);text-decoration:none;
}
.rp-all i{font-size:11px;}

.rp-list{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;}
.rp-compact .rp-list{grid-template-columns:1fr;}
.rp-card{
  margin:0;padding:20px;background:var(--cream-card);
  border:1px solid rgba(30,52,72,0.12);border-radius:14px;
  display:flex;flex-direction:column;
}

/* Head row: avatar, name over date, G pinned right — the order a
   Google review card puts them in. */
.rp-card-head{
  display:flex;
  align-items:center;
  gap:11px;
  margin-bottom:12px;
}
.rp-avatar{
  width:38px;
  height:38px;
  border-radius:50%;
  object-fit:cover;
  flex-shrink:0;
  display:block;
  background:rgba(30,52,72,0.08);
}
/* Google profile photos 404 fairly often once an account changes its
   picture, and a broken avatar undercuts the authenticity the photo
   was there to provide. The fallback is the initial on a disc, which
   is what Google itself shows for a reviewer with no photo. */
.rp-avatar-fb{
  display:flex;
  align-items:center;
  justify-content:center;
  background:var(--teal-ink);
  color:#fff;
  font-size:16px;
  font-weight:800;
  text-transform:uppercase;
  line-height:1;
}
.rp-who{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1;}
.rp-author{
  font-size:14px;
  font-weight:800;
  color:var(--ink);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.rp-when{font-size:12px;color:var(--ink-faint);}
.rp-card-head .g-mark{margin-left:auto;opacity:0.9;}

.rp-card-stars{display:block;margin-bottom:11px;}
.rp-card blockquote{
  margin:0;
  font-size:14.5px;
  line-height:1.75;
  color:var(--ink-soft);
  flex:1;
}

@media (max-width:1000px){
  .rp-inner{grid-template-columns:1fr;gap:26px;}
  .rp-list{grid-template-columns:1fr;}
}

/* ══════════════════════════════════════════════════
   SEARCH & ARCHIVE
   ══════════════════════════════════════════════════
   These templates did not exist; both fell through to index.php,
   which printed full post content unstyled. They share the blog's
   .posts-grid and .post-card, so only the header, the search field
   and the empty state need styling here.
   ══════════════════════════════════════════════════ */
.sr-hero,.ar-hero{padding-bottom:clamp(40px,5vw,64px);}
.sr-form{
  display:flex;align-items:center;gap:12px;max-width:620px;margin-top:28px;
  background:rgba(255,255,255,0.04);border:1px solid rgba(22,192,183,0.28);
  border-radius:var(--btn-radius);padding:8px 8px 8px 18px;
}
.sr-form-icon{color:var(--teal);font-size:15px;flex-shrink:0;}
.sr-form input{
  flex:1;background:transparent;border:none;outline:none;
  color:var(--text);font-family:var(--font);font-size:16px;padding:10px 0;min-width:0;
}
.sr-form input::placeholder{color:var(--muted);}
.sr-form-btn{
  flex-shrink:0;background:var(--teal);color:#052e2c;border:none;cursor:pointer;
  font-family:var(--font);font-weight:800;font-size:14.5px;
  padding:13px 22px;border-radius:calc(var(--btn-radius) - 2px);transition:background 0.2s;
}
.sr-form-btn:hover{background:#1ad4ca;}
.sr-results,.ar-results{
  position:relative;padding:clamp(56px,6vw,88px) 0;
  background:var(--cream);
  border-top:1px solid rgba(30,52,72,0.14);
  color:var(--ink-soft);
}
/* Same treatment the blog grid gets, so a post card looks identical
   whether it was found by browsing or by searching. */
.sr-results .post-card,
.ar-results .post-card{background:var(--cream-card);border-color:rgba(30,52,72,0.12);}
.sr-results :is(h1,h2,h3,strong),
.ar-results :is(h1,h2,h3,strong){color:var(--ink);}
.sr-results :is(p,span,li,time),
.ar-results :is(p,span,li,time){color:var(--ink-soft);}
.sr-results a:not(.btn),
.ar-results a:not(.btn){color:var(--teal-ink);}
.sr-results .post-cat,
.ar-results .post-cat{background:rgba(11,138,130,0.1);color:var(--teal-ink);}
.sr-results .pagination .page-numbers,
.ar-results .pagination .page-numbers{background:var(--cream-card);border-color:rgba(30,52,72,0.14);color:var(--ink);}
.sr-results .pagination .page-numbers.current,
.ar-results .pagination .page-numbers.current{background:var(--teal-ink);border-color:var(--teal-ink);color:#fff;}
.sr-results .post-card mark,
.ar-results .post-card mark{background:rgba(11,138,130,0.18);}
/* Search-term highlighting in results. */
.post-card mark{background:rgba(22,192,183,0.22);color:inherit;padding:0 2px;border-radius:3px;}
.sr-empty{max-width:60ch;}
.sr-empty h2{margin-bottom:14px;color:var(--ink);}
/* The serif accent inherits brand teal, which is 2.11:1 on this
   band. --teal-ink is the darkened value for light grounds. */
.sr-empty h2 em{color:var(--teal-ink) !important;}
.sr-empty p{color:var(--ink-soft);line-height:1.8;margin-bottom:24px;}
.sr-suggest{display:flex;flex-wrap:wrap;gap:10px;}
.sr-suggest a{
  padding:10px 18px;background:var(--cream-card);border:1px solid rgba(30,52,72,0.14);
  border-radius:var(--btn-radius);color:var(--ink) !important;text-decoration:none;
  font-size:14px;font-weight:700;transition:border-color 0.2s,color 0.2s;
}
.sr-suggest a:hover{border-color:var(--teal-ink);color:var(--teal-ink) !important;}
/* WordPress' own pagination markup, given the theme's look. */
.pagination{display:flex;justify-content:center;gap:8px;margin-top:44px;flex-wrap:wrap;}
.pagination .page-numbers{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:44px;min-height:44px;padding:0 14px;
  background:var(--surface);border:1px solid rgba(255,255,255,0.1);
  border-radius:var(--btn-radius);color:var(--text);text-decoration:none;
  font-weight:700;font-size:14px;transition:border-color 0.2s,color 0.2s;
}
.pagination .page-numbers:hover{border-color:var(--teal);color:var(--teal);}
.pagination .page-numbers.current{background:var(--teal);border-color:var(--teal);color:#052e2c;}
.pagination .screen-reader-text{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;}

/* ══════════════════════════════════════════════════
   MOBILE BUTTON ROWS
   ══════════════════════════════════════════════════
   Two buttons side by side need about 430px to hold their labels on
   one line. Below that they were splitting words across as many as
   four lines inside a 157px box — "Get a / Free / Visibility /
   Report" on the homepage was the worst of them. Stacking is the
   only honest fix; shrinking the type to fit would just move the
   problem into legibility.
   ══════════════════════════════════════════════════ */
@media (max-width:560px){
  .hero-btns,
  .cta-btns,
  .found-footer-btns,
  .pack-btns,
  .fp-form-card .hero-btns,
  .people-btns{
    flex-direction:column;
    align-items:stretch;
  }
  .hero-btns > .btn,
  .cta-btns > .btn,
  .found-footer-btns > .btn,
  .people-btns > .btn{
    width:100%;
    justify-content:center;
  }
}

/* ══════════════════════════════════════════════════
   TABLES IN EDITOR CONTENT
   ══════════════════════════════════════════════════
   A table pasted into the editor had no styling at all
   — browser defaults, no rules, no header treatment —
   and on a case study it is the block a visitor reads
   most closely.

   inc/content-tables.php tags every content table and
   wraps it in the scroll box these rules style. Both
   have to happen on output because the editor produces
   neither, and neither can be done in CSS alone.

   ONE SET OF RULES, TWO BACKGROUNDS
   Editor content lands on a white band on a case study
   and on a dark band in a blog post, so the borders and
   the muted text are drawn from currentColor rather
   than from a fixed ink or white. Only the accent has
   to be told which it is: #16C0B7 sits at about 2:1 on
   white, so light contexts take the deeper --teal-ink.
   ══════════════════════════════════════════════════ */
.rich-table-wrap{
  --rt-line:rgba(128,128,128,0.3);
  --rt-line:color-mix(in srgb, currentColor 22%, transparent);
  --rt-faint:rgba(128,128,128,0.12);
  --rt-faint:color-mix(in srgb, currentColor 7%, transparent);
  --rt-accent:var(--teal);
  --rt-strong:var(--text);

  margin:30px 0;
  overflow-x:auto;
  -webkit-overflow-scrolling:touch;
  border:1px solid var(--rt-line);
  border-radius:14px;
}
/* Keyboard focus on the scroll box — it is focusable so that a
   keyboard user can reach content that is only available by
   scrolling, which means it also has to show focus. */
.rich-table-wrap:focus-visible{
  outline:2px solid var(--rt-accent);
  outline-offset:2px;
}
/* Light content bands. */
.cs-single-body .rich-table-wrap,
.seo-inner .rich-table-wrap,
.seo-content .rich-table-wrap,
.legal-body .rich-table-wrap{
  --rt-accent:var(--teal-ink);
  --rt-strong:var(--ink);
}

.rich-table{
  width:100%;
  /* Three columns of numbers cannot compress to a phone; below this
     the wrapper scrolls instead of the columns collapsing into
     unreadable slivers. */
  min-width:540px;
  border-collapse:collapse;
  margin:0;
  font-size:15.5px;
  line-height:1.5;
  /* Figures line up column to column instead of drifting with the
     proportional digits. */
  font-variant-numeric:tabular-nums;
}
.rich-table caption{
  caption-side:top;
  text-align:left;
  padding:16px 18px 0;
  font-size:13px;
  font-weight:700;
  opacity:0.7;
}

/* Header. The pasted markup uses <td><strong> rather than <th>, which
   is what the editor produces, so both have to be covered. */
.rich-table thead td,
.rich-table th{
  font-family:var(--mono2),var(--mono),monospace;
  font-size:11px;
  font-weight:700;
  text-transform:uppercase;
  letter-spacing:0.08em;
  text-align:left;
  padding:16px 18px;
  border-bottom:2px solid var(--rt-line);
  white-space:nowrap;
}
.rich-table thead td strong,
.rich-table th strong{font-weight:700;}

.rich-table td{
  padding:13px 18px;
  border-top:1px solid var(--rt-faint);
  vertical-align:top;
}
.rich-table tbody tr:first-child td{border-top:0;}
.rich-table tbody tr:hover td{background:var(--rt-faint);}

/* The result cells. The editor marks the payoff column bold, so the
   accent follows the emphasis already in the content rather than a
   column position that may not hold for the next table.

   !important because interior.css carries
   `.seo-content :is(h2,h3,h4,h5,dt,strong,b){color:var(--ink)!important}`
   — deliberately, so one rule can reach forty page stylesheets. An
   ordinary declaration loses to it no matter how specific, so the tie
   has to be broken at the same level, where the higher specificity
   here wins. */
.rich-table tbody b,
.rich-table tbody strong{
  color:var(--rt-accent) !important;
  font-weight:800;
}
/* "Not Tracked" and friends — present, but not something to read. */
.rich-table tbody i,
.rich-table tbody em{opacity:0.55;font-style:italic;}

/* Group rows: a label in the first cell and nothing in the rest, which
   is how a section heading inside a table is written. Styled as a band
   rather than left to look like a row whose data failed to load.
   :has() is doing real work here — without it there is no way to tell
   a heading row from a data row, and a browser without :has() simply
   renders it as an ordinary row. */
.rich-table tbody tr:has(> td:first-child b):has(> td:nth-child(2):empty) td,
.rich-table tbody tr:has(> td:first-child strong):has(> td:nth-child(2):empty) td{
  background:var(--rt-faint);
  border-top:1px solid var(--rt-line);
  padding-top:14px;
  padding-bottom:14px;
}
.rich-table tbody tr:has(> td:first-child b):has(> td:nth-child(2):empty) b,
.rich-table tbody tr:has(> td:first-child strong):has(> td:nth-child(2):empty) strong{
  font-family:var(--disp);
  font-size:15px;
  font-weight:900;
  letter-spacing:-0.2px;
  /* Not the accent — a group row is a heading, not a result. Not
     `inherit` either: on a light band the cell itself is forced to
     the muted body color, so inheriting would render the section
     heading fainter than the rows beneath it. */
  color:var(--rt-strong) !important;
  text-transform:none;
}

@media (max-width:600px){
  .rich-table{font-size:14.5px;}
  .rich-table td,
  .rich-table thead td,
  .rich-table th{padding:11px 14px;}
}

/* ══════════════════════════════════════════════════
   CLIENT MARQUEE
   ══════════════════════════════════════════════════
   The strip used to show six clients and a counter,
   which meant the same six on every page of the site
   and no reason to ever add a seventh. The track is
   duplicated in markup and translated -50%, so the
   loop is seamless with no JS.
   ══════════════════════════════════════════════════ */
.client-strip-scroll .client-strip-inner{
  flex-wrap:nowrap;
  gap:0 28px;
}
.client-marquee{
  /* min-width:0 so the flex item can be narrower than its (very long)
     content, and overflow hidden so the track is clipped to it rather
     than widening the page. */
  flex:1;
  min-width:0;
  overflow:hidden;
  display:flex;
  /* The label and the counter sit on solid ground either side; the
     mask fades the marks into them instead of cutting them off mid
     letter. */
  mask-image:linear-gradient(90deg,transparent 0,#000 40px,#000 calc(100% - 40px),transparent 100%);
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 40px,#000 calc(100% - 40px),transparent 100%);
}
.client-marquee-track{
  flex:0 0 auto;
  flex-wrap:nowrap;
  animation:client-scroll var(--marquee-seconds,40s) linear infinite;
  will-change:transform;
}
.client-marquee:hover .client-marquee-track{animation-play-state:paused;}
@keyframes client-scroll{
  from{transform:translateX(0);}
  to{transform:translateX(-100%);}
}
.client-strip-more{
  flex-shrink:0;
  font-family:var(--mono2),var(--mono),monospace;
  font-size:11px;
  font-weight:700;
  letter-spacing:0.1em;
  text-transform:uppercase;
  color:var(--ink-faint);
  white-space:nowrap;
}

/* Motion here is decoration — the same names are readable stopped.
   Anyone who has asked the OS for less of it gets the static row, so
   the track parks at the start and simply overflows-scrolls instead. */
@media (prefers-reduced-motion:reduce){
  .client-marquee-track{animation:none;}
  .client-marquee{overflow-x:auto;}
  .client-marquee-track + .client-marquee-track{display:none;}
}

@media (max-width:700px){
  .client-strip-scroll .client-strip-inner{
    flex-wrap:wrap;
    gap:10px 20px;
  }
  .client-marquee{flex:1 1 100%;order:2;}
  .client-strip-more{order:3;}
}


/* ══════════════════════════════════════════════════
   CLIENT STORY — a named client on camera
   ══════════════════════════════════════════════════
   A real client video plus the notes the live service
   pages carry beside it. Shared rather than per-page:
   Local SEO and National SEO both use it and the other
   service templates each have a client video waiting.

   .video-frame is styled per page (each service CSS
   file has its own copy); this owns only the band. */
.client-story{padding:80px 0;background:var(--surface);position:relative;z-index:2;}
.cstory-head{text-align:center;max-width:720px;margin:0 auto 40px;}
.cstory-head h2{font-size:clamp(28px,3vw,42px);font-weight:900;letter-spacing:-0.5px;line-height:1.1;margin-top:10px;}
.cstory-head h2 em{font-style:normal;color:var(--teal);}
.cstory-grid{display:grid;grid-template-columns:1.15fr 1fr;gap:44px;align-items:center;}
/* No client video on this page: the notes take the full measure
   rather than sitting in a half-width column beside a gap. */
.cstory-grid.is-textonly{grid-template-columns:minmax(0,1fr);}
.cstory-notes{display:flex;flex-direction:column;gap:26px;}
.cstory-note{display:flex;gap:16px;align-items:flex-start;}
.cstory-note-icon{
  flex:0 0 auto;width:44px;height:48px;
  display:flex;align-items:center;justify-content:center;
  background:linear-gradient(90deg,#14beb5,#71d3cc);color:#050b12;font-size:18px;
  clip-path:polygon(50% 0%,100% 25%,100% 75%,50% 100%,0% 75%,0% 25%);
}
.cstory-note h3{font-size:19px;font-weight:900;letter-spacing:-0.3px;margin-bottom:6px;}
.cstory-note p{color:var(--muted);font-size:16px;line-height:1.7;}
.cstory-call{display:inline-flex;align-items:center;gap:14px;text-decoration:none;color:var(--text);align-self:flex-start;}
.cstory-call-icon{
  width:44px;height:44px;border-radius:50%;flex-shrink:0;
  display:flex;align-items:center;justify-content:center;
  background:var(--teal);color:#050b12;font-size:16px;transition:transform 0.2s;
}
.cstory-call:hover .cstory-call-icon{transform:scale(1.08);}
.cstory-call-label{display:block;font-size:11px;font-weight:800;letter-spacing:1.5px;text-transform:uppercase;color:var(--muted);}
.cstory-call strong{font-size:19px;font-weight:900;letter-spacing:-0.3px;}

/* The live "Other Services" sidebars, as a list rather than a wall
   of links inside a sentence. */
.seo-services-list{list-style:none;padding:0;margin:0 0 18px;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:8px 24px;}
.seo-services-list li{padding-left:18px;position:relative;}
.seo-services-list li::before{content:'\203A';position:absolute;left:0;color:var(--teal);font-weight:900;}

@media(max-width:900px){
  .cstory-grid{grid-template-columns:minmax(0,1fr);gap:30px;}
}

/* The shared strip (template-parts/metrics-strip.php) may have fewer
   than five figures while a source is unavailable. */
.metrics-grid-4{grid-template-columns:repeat(4,1fr);}
.metrics-grid-3{grid-template-columns:repeat(3,1fr);}

/* ══════════════════════════════════════════════════
   YOUTUBE FACADE  (template-parts/video-embed.php)
   ══════════════════════════════════════════════════
   The poster with a play button; the iframe arrives on click. Sized
   16:9 on its own so it fills any frame it is put in, with the
   frame's rounding and overflow doing the rest. */
.yt-lite{
  position:relative;
  width:100%;
  aspect-ratio:16/9;
  background:#000;
  cursor:pointer;
  overflow:hidden;
}
.yt-lite img{
  display:block;width:100%;height:100%;
  object-fit:cover;
  transition:transform 0.5s cubic-bezier(0.2,0,0,1),filter 0.3s;
}
.yt-lite:hover img{transform:scale(1.03);filter:brightness(0.85);}
.yt-lite-play{
  position:absolute;left:50%;top:50%;
  width:76px;height:84px;
  transform:translate(-50%,-50%);
  display:flex;align-items:center;justify-content:center;
  background:var(--teal);
  border:0;padding:0;cursor:pointer;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
  box-shadow:0 0 0 10px rgba(22,192,183,0.18);
  transition:transform 0.25s cubic-bezier(0.2,0,0,1),box-shadow 0.25s;
}
.yt-lite:hover .yt-lite-play{transform:translate(-50%,-50%) scale(1.08);}
.yt-lite-play:focus-visible{outline:3px solid #fff;outline-offset:3px;}
.yt-lite-play-icon{
  display:block;width:0;height:0;margin-left:5px;
  border-top:13px solid transparent;border-bottom:13px solid transparent;
  border-left:22px solid var(--obsidian);
}
.yt-lite iframe{position:absolute;inset:0;width:100%;height:100%;border:0;}
.yt-lite.is-playing img,.yt-lite.is-playing .yt-lite-play{display:none;}

/* ══════════════════════════════════════════════════
   RELATED SERVICES  (template-parts/related-services.php)
   ══════════════════════════════════════════════════ */
.rel-services{
  position:relative;
  padding:clamp(56px,6vw,88px) 0;
  background:var(--surface);
  border-top:1px solid rgba(255,255,255,0.08);
}
.rel-head{display:flex;align-items:flex-end;justify-content:space-between;gap:20px;flex-wrap:wrap;margin-bottom:28px;}
.rel-head h2{margin:0;font-size:clamp(26px,3vw,40px);line-height:1.14;}
.rel-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;}
.rel-card{
  display:flex;align-items:center;gap:16px;
  padding:20px 22px;
  background:var(--obsidian);
  border:1px solid var(--border);
  border-radius:14px;
  color:var(--text);text-decoration:none;
  transition:transform 0.22s cubic-bezier(0.2,0,0,1),border-color 0.22s,box-shadow 0.22s;
}
.rel-card:hover{transform:translateY(-3px);border-color:rgba(22,192,183,0.5);box-shadow:0 18px 40px -20px rgba(0,0,0,0.6);}
.rel-icon{
  width:44px;height:48px;flex-shrink:0;
  display:flex;align-items:center;justify-content:center;
  background:var(--teal);color:var(--obsidian);font-size:17px;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
}
.rel-body{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1;}
.rel-title{font-weight:800;font-size:17px;letter-spacing:-0.01em;color:#fff;}
.rel-sub{font-size:14px;color:var(--muted);line-height:1.4;}
.rel-arrow{color:var(--teal);font-size:14px;flex-shrink:0;transition:transform 0.22s;}
.rel-card:hover .rel-arrow{transform:translateX(4px);}
@media(max-width:900px){.rel-grid{grid-template-columns:minmax(0,1fr);}}

/* ── Form error brought back by a redirect (inc/leads.php) ── */
.form-error{
  margin:0 0 16px;padding:12px 14px;border-radius:var(--btn-radius);
  font-size:14px;line-height:1.5;color:#ffd7d2;
  background:rgba(255,92,74,0.12);border:1px solid rgba(255,92,74,0.35);
}

/* ── Sticky call / audit bar, phones only (footer.php) ──
   Stays off screen until the visitor has scrolled past the first
   screen (global.js adds .is-visible), and slides away again while
   a form field has focus (body.is-typing) so it never sits between
   the visitor and the keyboard. Without JS it simply shows. ── */
.m-cta-bar{display:none;}
@media (max-width:768px){
  body:has(.m-cta-bar){padding-bottom:calc(64px + env(safe-area-inset-bottom));}
  .m-cta-bar{
    position:fixed;left:0;right:0;bottom:0;z-index:900;
    display:grid;grid-template-columns:auto 1fr;gap:10px;
    padding:10px 14px calc(10px + env(safe-area-inset-bottom));
    background:rgba(5,11,18,0.92);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
    border-top:1px solid rgba(22,192,183,0.25);
    transition:transform .28s ease,visibility 0s linear .28s;
  }
  .js .m-cta-bar:not(.is-visible),
  .js body.is-typing .m-cta-bar{transform:translateY(110%);visibility:hidden;}
  .js .m-cta-bar.is-visible{transition:transform .28s ease,visibility 0s;}
  .m-cta-bar a{
    display:inline-flex;align-items:center;justify-content:center;gap:8px;
    min-height:44px;padding:0 18px;border-radius:var(--btn-radius);
    font-family:var(--font);font-weight:800;font-size:14px;text-decoration:none;
  }
  .m-cta-call{color:var(--text);border:1px solid rgba(255,255,255,0.22);}
  .m-cta-audit{background:var(--teal);color:#050b12;}
}
@media (prefers-reduced-motion:reduce){ .m-cta-bar{transition:none;} }

/* ══════════════════════════════════════════════════
   GRAVITY FORMS, in the theme's own clothes
   (inc/gravity-forms.php prints them inside .seolocale-gf). The
   plugin ships two front-end themes, "Gravity" (.gravity-theme)
   and "Orbital" (.gform-theme--orbital, the default since 2.7),
   and they style controls through different selectors and CSS
   variables. These rules cover both: the Orbital variables are
   set on the wrapper, and every control is also restyled directly
   with enough weight to beat either theme, so the fields, labels
   and button match the theme's own forms whichever is active.
   ══════════════════════════════════════════════════ */
.seolocale-gf .gform_wrapper{
  --gf-color-primary:#16C0B7;
  --gf-color-primary-contrast:#050b12;
  --gf-ctrl-bg-color:rgba(5,11,18,0.55);
  --gf-ctrl-bg-color-hover:rgba(5,11,18,0.65);
  --gf-ctrl-bg-color-focus:rgba(5,11,18,0.75);
  --gf-ctrl-border-color:rgba(255,255,255,0.16);
  --gf-ctrl-border-color-hover:rgba(255,255,255,0.28);
  --gf-ctrl-border-color-focus:#16C0B7;
  --gf-ctrl-color:#DFEFFD;
  --gf-ctrl-placeholder-color:rgba(223,239,253,0.4);
  --gf-ctrl-radius:var(--btn-radius);
  --gf-ctrl-font-size:15px;
  --gf-ctrl-padding-x:14px;
  --gf-ctrl-padding-y:12px;
  --gf-ctrl-shadow-focus:0 0 0 3px rgba(22,192,183,0.18);
  --gf-ctrl-select-bg-img: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='%2316C0B7' stroke-width='2'/%3E%3C/svg%3E");
  --gf-ctrl-btn-bg-color-primary:#16C0B7;
  --gf-ctrl-btn-bg-color-hover-primary:#1ad4ca;
  --gf-ctrl-btn-border-color-primary:#16C0B7;
  --gf-ctrl-btn-border-color-hover-primary:#1ad4ca;
  --gf-ctrl-btn-color-primary:#050b12;
  --gf-ctrl-btn-color-hover-primary:#050b12;
  --gf-ctrl-btn-radius:var(--btn-radius);
  --gf-ctrl-btn-font-size:16px;
  --gf-ctrl-btn-font-weight:800;
  --gf-ctrl-btn-padding-x:32px;
  --gf-ctrl-btn-padding-y:15px;
  --gf-ctrl-btn-size:auto;
  --gf-label-color-primary:#16C0B7;
  --gf-label-color-secondary:rgba(223,239,253,0.6);
  --gf-label-req-color:#16C0B7;
  --gf-label-font-size-primary:10.5px;
  --gf-label-font-weight-primary:400;
  --gf-label-space-y-primary:6px;
  --gf-form-gap-y:14px;
  --gf-field-gap-y:14px;
  --gf-field-gap-x:12px;
  --gf-desc-color:rgba(223,239,253,0.6);
  --gf-color-danger:#ff5c4a;
  --gf-ctrl-border-color-error:rgba(255,92,74,0.6);
  margin:0;
}
.seolocale-gf .gform_wrapper form{font-family:var(--font);}
/* Section breaks (the questionnaire's four groups): a rule, a
   heading, a line of help, like the theme's own q-block heads. */
.seolocale-gf .gform_wrapper .gsection{border:0;border-top:1px solid rgba(22,192,183,0.22);margin:28px 0 6px;padding:22px 0 0;}
.seolocale-gf .gform_wrapper .gsection:first-child{border-top:0;margin-top:0;padding-top:0;}
.seolocale-gf .gform_wrapper .gsection_title{font-size:20px;font-weight:800;letter-spacing:-0.01em;color:#fff;margin:0 0 4px;}
.seolocale-gf .gform_wrapper .gsection_description{font-size:14px;color:var(--muted);margin:0;}
.seolocale-gf .gform_wrapper .gform_heading,
.seolocale-gf .gform_wrapper .gform_required_legend,
.seolocale-gf .gform_wrapper .gform_ajax_spinner{display:none !important;}
.seolocale-gf .gform_wrapper .gform_fields{row-gap:14px;column-gap:12px;}
.seolocale-gf .gform_wrapper .gfield{margin:0;}
.seolocale-gf .gform_wrapper .gfield_label,
.seolocale-gf .gform_wrapper legend.gfield_label{
  display:block;font-family:var(--mono2) !important;font-size:10.5px !important;font-weight:400 !important;
  letter-spacing:0.16em;text-transform:uppercase;color:var(--teal) !important;margin:0 0 6px !important;padding:0;
}
.seolocale-gf .gform_wrapper .gfield_required{color:var(--teal) !important;font-size:inherit;}
.seolocale-gf .gform_wrapper .hidden_label .gfield_label,
.seolocale-gf .gform_wrapper .gfield--label-hidden .gfield_label{position:absolute !important;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);margin:0 !important;}
.seolocale-gf .gform_wrapper input:not([type=submit]):not([type=button]):not([type=checkbox]):not([type=radio]):not([type=hidden]),
.seolocale-gf .gform_wrapper select,
.seolocale-gf .gform_wrapper textarea{
  box-sizing:border-box;width:100% !important;min-height:0;
  font-family:var(--font) !important;font-size:15px !important;line-height:1.5 !important;color:var(--text) !important;
  background:rgba(5,11,18,0.55) !important;border:1px solid rgba(255,255,255,0.16) !important;border-radius:var(--btn-radius) !important;
  padding:12px 14px !important;margin:0;box-shadow:none !important;
  transition:border-color 0.2s ease,background 0.2s ease,box-shadow 0.2s ease;
}
.seolocale-gf .gform_wrapper select{
  appearance:none !important;-webkit-appearance:none !important;padding-right:38px !important;
  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='%2316C0B7' stroke-width='2'/%3E%3C/svg%3E") !important;
  background-repeat:no-repeat !important;background-position:right 14px center !important;background-size:12px 8px !important;
}
.seolocale-gf .gform_wrapper select option{color:#050b12;background:#fff;}
.seolocale-gf .gform_wrapper textarea{min-height:110px !important;height:auto;resize:vertical;}
.seolocale-gf .gform_wrapper ::placeholder{color:rgba(223,239,253,0.4) !important;opacity:1;}
.seolocale-gf .gform_wrapper input:not([type=submit]):focus,
.seolocale-gf .gform_wrapper select:focus,
.seolocale-gf .gform_wrapper textarea:focus{
  outline:none !important;border-color:var(--teal) !important;background-color:rgba(5,11,18,0.75) !important;
  box-shadow:0 0 0 3px rgba(22,192,183,0.18) !important;
}
.seolocale-gf .gform_wrapper .ginput_container{margin:0;}
.seolocale-gf .gform_wrapper .gfield_description{font-family:var(--font);font-size:13px;color:var(--muted);padding:6px 0 0;}
.seolocale-gf .gform_wrapper .gform_footer,
.seolocale-gf .gform_wrapper .gform-footer{margin:18px 0 0 !important;padding:0 !important;display:flex;}
.seolocale-gf .gform_wrapper .gform_button,
.seolocale-gf .gform_wrapper .gform-theme-button,
.seolocale-gf .gform_wrapper input[type=submit]{
  display:inline-flex !important;align-items:center;justify-content:center;gap:10px;width:100% !important;min-height:0;
  font-family:var(--font) !important;font-weight:800 !important;font-size:16px !important;line-height:1.2 !important;cursor:pointer;
  background:var(--teal) !important;color:#050b12 !important;border:2px solid var(--teal) !important;border-radius:var(--btn-radius) !important;
  padding:15px 32px !important;margin:0 !important;box-shadow:none !important;letter-spacing:0;text-transform:none;
  transition:background 0.2s,transform 0.2s;
}
.seolocale-gf .gform_wrapper .gform_button:hover,
.seolocale-gf .gform_wrapper input[type=submit]:hover{background:#1ad4ca !important;border-color:#1ad4ca !important;transform:translateY(-2px);}
.seolocale-gf .gform_wrapper .gform_validation_errors{
  margin:0 0 16px !important;padding:12px 14px !important;border-radius:var(--btn-radius) !important;
  background:rgba(255,92,74,0.12) !important;border:1px solid rgba(255,92,74,0.35) !important;box-shadow:none !important;
}
.seolocale-gf .gform_wrapper .gform_validation_errors h2,
.seolocale-gf .gform_wrapper .gform_validation_errors .gform_submission_error{
  font-family:var(--font) !important;font-size:14px !important;font-weight:600;color:#ffd7d2 !important;margin:0;padding:0;line-height:1.5;
}
.seolocale-gf .gform_wrapper .gform_validation_errors .gform-icon{color:#ff5c4a;}
.seolocale-gf .gform_wrapper .gform_validation_errors ol,
.seolocale-gf .gform_wrapper .gform_validation_errors ul{display:none;}
.seolocale-gf .gform_wrapper .gfield_validation_message,
.seolocale-gf .gform_wrapper .validation_message{
  font-family:var(--font) !important;font-size:13px !important;font-weight:600;color:#ffd7d2 !important;
  background:none !important;border:none !important;padding:6px 0 0 !important;margin:0 !important;
}
.seolocale-gf .gform_wrapper .gfield_error input,
.seolocale-gf .gform_wrapper .gfield_error select,
.seolocale-gf .gform_wrapper .gfield_error textarea{border-color:rgba(255,92,74,0.6) !important;}
.seolocale-gf .gform_wrapper .gfield_error .gfield_label{color:#ffd7d2 !important;}
.seolocale-gf .gform_confirmation_wrapper,
.seolocale-gf .gform_confirmation_message{font-family:var(--font);font-size:16px;color:var(--text);line-height:1.6;}
/* Footer newsletter: field and button on one line, no label. */
.f-newsletter-gf{display:block;}
.f-newsletter-gf .gform_wrapper form{display:flex;gap:10px;align-items:flex-start;flex-wrap:wrap;}
.f-newsletter-gf .gform_wrapper .gform_body,
.f-newsletter-gf .gform_wrapper .gform-body{flex:1 1 220px;min-width:0;}
.f-newsletter-gf .gform_wrapper .gform_footer,
.f-newsletter-gf .gform_wrapper .gform-footer{margin:0 !important;flex:0 0 auto;}
.f-newsletter-gf .gform_wrapper .gform_button,
.f-newsletter-gf .gform_wrapper input[type=submit]{width:auto !important;padding:12px 20px !important;font-size:14px !important;}
.f-newsletter-gf .gform_wrapper input[type=email]{padding:11px 14px !important;}
.f-newsletter-gf .gform_confirmation_message{font-size:14px;color:var(--teal);}
@media(max-width:640px){
  .f-newsletter-gf .gform_wrapper form{flex-direction:column;}
  .f-newsletter-gf .gform_wrapper .gform_button,.f-newsletter-gf .gform_wrapper input[type=submit]{width:100% !important;}
}

/* ══════════════════════════════════════════════════
   FREE AUDIT FORM + HERO PANEL (template-parts/hero-audit-form.php)
   Was the Free Audit page's own; the panel now sits in any hero
   that had nothing on its right, so the rules live here.
   ══════════════════════════════════════════════════ */
/* ── One-step lead form (replaced the lone domain field) ──
   Four fields and a button in a tight grid under the hero copy,
   styled like the proposal form so the two read as one system. */
.fa-form{margin:0;max-width:none;}
.fa-form-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;}
.fa-field{display:flex;flex-direction:column;gap:6px;min-width:0;}
.fa-field-wide{grid-column:1 / -1;}
.fa-field span{font-family:var(--mono2);font-size:10.5px;letter-spacing:0.16em;text-transform:uppercase;color:var(--teal);}
.fa-field span em{font-style:normal;text-transform:none;letter-spacing:0;color:var(--muted);}
.fa-field input{
  width:100%;font-family:var(--font);font-size:15px;line-height:1.5;color:var(--text);
  background:rgba(5,11,18,0.55);border:1px solid rgba(255,255,255,0.16);border-radius:var(--btn-radius);
  padding:12px 14px;transition:border-color 0.2s ease,background 0.2s ease;
}
.fa-field input::placeholder{color:rgba(223,239,253,0.4);}
.fa-field input:focus{outline:none;border-color:var(--teal);background:rgba(5,11,18,0.75);box-shadow:0 0 0 3px rgba(22,192,183,0.18);}
/* The button shares the last row with the phone field and sits on its
   baseline, so the grid closes with no empty cell. */
.fa-submit{justify-content:center;align-self:end;min-height:50px;}
@media (max-width:560px){.fa-form-grid{grid-template-columns:1fr;}.fa-field-wide{grid-column:auto;}.fa-submit{margin-top:4px;}}
/* The form on the right, in its own panel, so the hero reads copy
   then ask rather than one long column. */
.fa-hero-form{
  position:relative;min-width:0;padding:28px 28px 26px;
  background:rgba(12,26,38,0.82);border:1px solid rgba(22,192,183,0.2);border-radius:20px;
  box-shadow:0 30px 60px rgba(0,0,0,0.35);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
}
.fa-hero-form::before{content:"";position:absolute;left:28px;right:28px;top:0;height:2px;background:var(--text-grad);border-radius:0 0 2px 2px;}
/* In the panel the column is narrow: phone and the button each take a
   full row so the button's label stays on one line. */
.fa-hero-form .fa-field:last-of-type,
.fa-hero-form .fa-submit{grid-column:1 / -1;}
.hero-form-head{margin-bottom:18px;padding-bottom:16px;border-bottom:1px solid rgba(255,255,255,0.1);}
.hero-form-head .eyebrow{margin-bottom:8px;}
.hero-form-head p{margin:0;font-size:14px;line-height:1.5;color:var(--muted);}
/* The hero container as a two-column grid: breadcrumb across the top,
   copy left, panel right. Phones stack. */
.hero > .container.hero-with-form,
.loc-hero > .container.hero-with-form{
  display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,460px);gap:8px 56px;align-items:center;
}
.hero-with-form > .crumbs{grid-column:1 / -1;}
.hero-with-form > .hero-inner,
.hero-with-form > .loc-hero-inner{max-width:none;min-width:0;}
.hero-with-form > .hero-form-panel{margin-top:24px;}
@media (max-width:1000px){
  .hero > .container.hero-with-form,
  .loc-hero > .container.hero-with-form{grid-template-columns:1fr;gap:0;}
  .hero-with-form > .hero-form-panel{margin-top:32px;}
}

/* ═══ RANK TICKER ═══
   One real ranking move from the weekly SEO App pull, in the top
   bar above the main nav, rotating through the best climbs
   (inc/rank-ticker.php). Read left to right in one glance: the
   source, the move, the keyword, the gain, the link. On a wide screen
   it sits centred between the reviews line and the social links; on
   a narrower one it takes the whole bar for a few seconds, then slides
   away. Masked words are drawn as bars (.rt-x) by the server: the
   text is not in the page. */
.rank-ticker{
  position:fixed;top:0;left:0;right:0;height:40px;z-index:311;
  display:flex;align-items:center;justify-content:center;
  opacity:0;transform:translateY(-8px);
  transition:opacity .45s ease,transform .45s ease;
}
.rank-ticker[hidden]{display:none;}
.rank-ticker.is-in{opacity:1;transform:none;}
.rank-ticker.is-swap .rt-main{opacity:0;transform:translateY(4px);}
body.admin-bar .rank-ticker{top:32px;}
@media screen and (max-width:782px){body.admin-bar .rank-ticker{top:46px;}}
.rt-card{
  display:flex;align-items:center;gap:14px;height:40px;max-width:100%;
  padding:0 16px;text-decoration:none;color:#F8FAFC;
}
.rt-wm,.rt-when,.rt-by{display:none;}
/* Cell 1: the source. "Live from" and the mark; the full sentence in
   the markup is for the accessibility tree. */
.rt-top{display:flex;align-items:center;flex-shrink:0;padding-right:14px;border-right:1px solid rgba(255,255,255,0.14);}
.rt-live{
  display:inline-flex;align-items:center;gap:8px;
  font-family:var(--mono2);font-size:0;letter-spacing:0.12em;text-transform:uppercase;color:var(--teal);white-space:nowrap;
}
.rt-live::before{content:"Live from";font-size:9.5px;}
.rt-live img{height:13px;width:auto;display:block;filter:brightness(1.35);}
/* Cells 2 to 4: the move, the keyword, the gain. */
.rt-main{display:flex;align-items:center;gap:12px;min-width:0;transition:opacity .22s ease,transform .22s ease;}
.rt-jump{display:inline-flex;align-items:baseline;gap:7px;flex-shrink:0;}
.rt-from{font-family:var(--mono2);font-size:12px;color:rgba(248,250,252,0.5);text-decoration:line-through;text-decoration-color:rgba(248,250,252,0.45);}
.rt-jump i{font-size:11px;color:var(--teal);}
.rt-to{font-family:var(--disp);font-size:19px;line-height:1;letter-spacing:-0.5px;color:var(--teal);}
.rt-text{display:flex;align-items:center;gap:12px;min-width:0;}
.rt-kw{font-size:13px;font-weight:700;line-height:1.3;color:#fff;letter-spacing:-0.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:240px;}
.rt-x{
  display:inline-block;vertical-align:-1px;height:0.8em;width:calc(var(--n,6) * 0.5em);
  border-radius:3px;background:rgba(255,255,255,0.14);
}
.rt-kw-text::before{content:"\201C";}
.rt-end{white-space:nowrap;}
.rt-end::after{content:"\201D";}
.rt-gain{
  display:inline-flex;align-items:center;gap:6px;flex-shrink:0;
  padding:3px 8px;border-radius:999px;white-space:nowrap;
  font-size:11px;font-weight:700;color:#4fe3da;
  background:rgba(22,192,183,0.12);border:1px solid rgba(22,192,183,0.3);
}
.rt-gain i{font-size:10px;}
/* Cell 5: the link. */
.rt-foot{display:flex;align-items:center;flex-shrink:0;padding-left:14px;border-left:1px solid rgba(255,255,255,0.14);}
.rt-link{font-size:12px;font-weight:700;color:#fff;display:inline-flex;align-items:center;gap:7px;white-space:nowrap;}
.rt-link i{font-size:10px;color:var(--teal);transition:transform .2s ease;}
.rt-card:hover .rt-link i{transform:translateX(3px);}
.rt-close{
  position:absolute;top:50%;right:12px;margin-top:-9px;width:18px;height:18px;border-radius:50%;
  border:0;background:rgba(255,255,255,0.08);color:#fff;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;font-size:9px;
  opacity:0;transition:opacity .2s ease,background .2s ease;
}
.rank-ticker:hover .rt-close,.rt-close:focus-visible{opacity:1;}
.rt-close:hover{background:var(--teal);color:#052e2c;}
/* Wide: centred between the bar's own items, no ground of its own. */
@media (min-width:1280px){
  .rank-ticker{left:50%;right:auto;max-width:calc(100vw - 700px);transform:translate(-50%,-6px);}
  .rank-ticker.is-in{transform:translate(-50%,0);}
  .rt-close{right:-26px;}
}
@media (min-width:1280px) and (max-width:1500px){
  .rt-link span{display:none;}
  .rt-kw{max-width:170px;}
}
/* Narrower: the whole bar, on the bar's own ground, for a few seconds. */
@media (max-width:1279px){
  .rank-ticker{
    background:linear-gradient(90deg,#011931 0%,#0a2947 40%,#083152 70%,#011931 100%);
    border-bottom:1px solid rgba(22,192,183,0.18);
  }
  .rt-card{width:100%;justify-content:center;padding:0 44px 0 16px;}
  .rt-close{opacity:1;}
}
@media (max-width:700px){
  .rt-card{gap:10px;padding:0 40px 0 12px;justify-content:flex-start;}
  .rt-live::before{display:none;}
  .rt-top{padding-right:10px;}
  .rt-main{gap:9px;}
  .rt-text{gap:8px;}
  .rt-kw{max-width:none;flex:1;}
  .rt-gain-t,.rt-link span{display:none;}
  .rt-foot{padding-left:10px;}
}
@media (prefers-reduced-motion:reduce){
  .rank-ticker,.rt-main,.rt-close{transition:none;}
}
