/* ═══════════════════════════════════════════════════════════════════════════
   AC STUDIOS — SHARED STYLESHEET
   The design system is Angie's portfolio (my-portfolio/index.html). Values here
   are copied from it, not re-invented. Where this file departs from the
   portfolio it says so and why.

   Load order in every page:
     <link rel="stylesheet" href="assets/css/ac.css">
     <link rel="stylesheet" href="assets/css/lockup.css">
     <style> ...page-specific rules only... </style>

   ── COLOUR ────────────────────────────────────────────────────────────────
   AC Studios is a much longer site than the portfolio: six card grids instead
   of one grid of photographs. A rule that works on one page of imagery does not
   survive being repeated down seven sections. Two failed attempts are recorded
   here so they are not repeated:

     1. One shadow colour everywhere (black, then red). Whichever colour it was
        became a wall of that colour, and the other two disappeared.
     2. Cycling red/blue/yellow by :nth-child. This "balanced" each row but the
        colour meant nothing — the same card was red here and blue there. The
        neo-brutalist literature names this exact failure: using all the accent
        colours everywhere destroys the system.

   What actually holds, and the proportions come from the 60-30-10 rule:

     60%  WHITE          the ground. Most of the page.
     30%  BLACK + PALE   structure (2px borders, text) and the pale section
                         bands that break the page up.
     10%  FULL COLOUR    and every one of the three has ONE job:

     BLUE   = you can act here.      Buttons, links, focus, the active nav, and
                                     the shadow on every card that leads
                                     somewhere: services, case studies, clients,
                                     FAQ items, linked sub-pages.
     RED    = look here, but it is   Heading squiggles, eyebrow dots, and the
              not a control.         shadow on cards about PEOPLE and VOICE:
                                     the team, the About photo, notes,
                                     testimonials, callouts.
     YELLOW = money and the ask.     Pricing card shadows, the CTA band, the
                                     logo band, marker highlights, status pills.

   So the shadow colour is information: blue means this card goes somewhere,
   red means it is telling you something, yellow means it is about cost.
   Balance then falls out of the content rather than being imposed on it — any
   section has its ground (one colour), its cards (a second), and its squiggle
   and buttons (the third).

   Orange used to do blue's job AND red's job. That is why this was not a
   find-and-replace.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ───────────────────────────────────────────────────────────────── TOKENS ── */
:root{
  --white:#FFFFFF; --black:#141414; --ink-2:#3A3A3A;
  --blue:#2D5BE3; --red:#EE4B3B; --yellow:#FFD23F;
  --yellow-soft:#FFF5D1; --blue-soft:#E4EBFF; --red-soft:#FDE4E1;
  --blue-soft-2:#D1DBF9;

  --f-head:"Gabarito",system-ui,sans-serif;
  --f-body:"Plus Jakarta Sans",system-ui,sans-serif;

  --r-sm:8px; --r-md:16px; --r-lg:24px; --r-xl:48px; --r-full:9999px;
  --bw:2px;

  --bounce:cubic-bezier(.34,1.56,.64,1);
  --ease:cubic-bezier(.16,1,.3,1);

  /* GROUND-DEPENDENT. The portfolio hardcodes var(--black) for every border and
     hard shadow, because the portfolio has no dark sections. AC Studios has
     four (Pricing, Work, the CTA strips, the footer), and a black border on
     #141414 is invisible. So structure goes through a variable that the ground
     flips. This is the portfolio's own move — its footer puts WHITE shapes on
     the yellow band — generalised into a token. */
  --line:var(--black);
  --pop-c:var(--black);
  --fg:var(--black);
  --fg-dim:var(--ink-2);

  --pop:4px 4px 0 0 var(--pop-c);
  --pop-hover:6px 6px 0 0 var(--pop-c);
  --pop-active:2px 2px 0 0 var(--pop-c);
  --pop-lg:8px 8px 0 0 var(--pop-c);

  --dots:radial-gradient(rgba(20,20,20,.16) 1.5px,transparent 1.6px) 0 0/22px 22px;

  /* ── COMPATIBILITY ALIASES ────────────────────────────────────────────────
     The page-specific CSS still names the old tokens in a few hundred places.
     Rather than rewrite every one, the old names now point at the new values,
     so anything not explicitly restyled below still lands inside the new
     palette instead of staying orange.
     --accent is DELIBERATELY ABSENT. It had two jobs and the new system
     splits them, so leaving it defined would let the ambiguity survive. Every
     use of it has been sorted into --blue or --red at the call site. If an
     `var(--accent)` ever reappears it will fall back to nothing and show up
     immediately, which is the point. */
  --bg:var(--white);
  --surface:var(--yellow-soft);
  --surface-2:var(--blue-soft);
  --text:var(--black);
  --text-muted:var(--ink-2);
  --border:var(--black);
  --accent-light:var(--yellow);
  --font-head:var(--f-head);
  --font-body:var(--f-body);
  --radius-sm:var(--r-sm); --radius-md:var(--r-md);
  --radius-lg:var(--r-lg); --radius-xl:var(--r-full);
  --ease-out:var(--ease);
}

/* Dark sections. One class on the <section> and everything inside follows. */
.on-dark{
  --line:var(--white); --pop-c:var(--white);
  --fg:var(--white); --fg-dim:rgba(255,255,255,.72);
  --bg:var(--black); --surface:rgba(255,255,255,.08); --border:var(--white);
  --text-muted:rgba(255,255,255,.72);
  background:var(--black); color:var(--white);
}
/* --text IS DELIBERATELY NOT REDEFINED HERE, and that is load-bearing. In the
   old system --text named the ink colour AND the dark-section background: the
   pattern was literally `background: var(--text)`. Flipping it to white inside
   .on-dark turned every dark band white and left white text sitting on it.
   Ink comes from the `color` declaration above and from --fg; --text keeps
   meaning #141414 everywhere, so `background: var(--text)` still means dark. */
.on-dark h1,.on-dark h2,.on-dark h3,.on-dark h4{color:var(--white)}
.on-dark p{color:rgba(255,255,255,.72)}
/* Eyebrows go YELLOW on dark, not red. Measured: --red #EE4B3B on #141414 is
   4.1:1, which fails AA for the 0.72rem uppercase an eyebrow is set at.
   --yellow #FFD23F on the same ground is 11.6:1. */
/* Eyebrow TEXT goes yellow on dark (red is 4.1:1 on #141414 and fails AA at
   this size) but the DOT stays red — a 9px dot is a graphic, which needs 3:1,
   and without it the dark band would be the one stretch of page carrying only
   two of the three colours. */
.on-dark .eyebrow{color:var(--yellow)}
.on-dark .eyebrow::before{background:var(--red)}
/* Emphasis numbers follow the eyebrows to yellow on dark, for the same contrast
   reason and for one more: the Pricing section had the big "$50" in red and the
   price ranges beside it in yellow, which is two emphasis colours doing one job
   in a single band. */
.on-dark .pricing-signal__num,.on-dark .pricing-signal__from,
.on-dark .pricing-signal__denom,.on-dark .pricing-card__range,
.on-dark .work-card__stat,.on-dark .cs-card__label{color:var(--yellow)}

/* BAND RHYTHM — the thing I got most wrong the first time.
   Measured off the portfolio: the page is WHITE almost all the way down. There
   is exactly ONE tinted body band (About, in --blue-soft) and then the footer
   goes FULL --yellow at full strength. Yellow is a punctuation mark, not a
   background. Tinting most sections --yellow-soft, which is what I did, is why
   it read as "so much yellow" — it spent the loudest colour on filler and left
   nothing for the moment that should land.
   So: white by default, .on-cool for the one calm band, .on-yellow for the
   single loud one. --yellow-soft survives only inside components (pills,
   highlights, icon tiles), never as a section ground. */
.on-yellow{background:var(--yellow);color:var(--black)}
.on-cool{background:var(--blue-soft)}   /* pale blue */
.on-soft{background:var(--yellow-soft)} /* pale yellow */
.on-warm{background:var(--red-soft)}    /* pale red */


/* The yellow CTA band gets the portfolio's footer-well treatment: big heading,
   red squiggle under it, buttons in a row. */
.on-yellow h2{font-size:clamp(2.2rem,6vw,4rem);font-weight:800;letter-spacing:-.035em}
.on-yellow p{color:var(--black);opacity:.78}
.on-yellow .eyebrow{color:var(--black);background:var(--white);
  border:var(--bw) solid var(--black);border-radius:var(--r-full);
  padding:.35rem 1rem;transform:rotate(-3deg)}
.on-yellow .eyebrow::before{display:none}

/* ────────────────────────────────────────────────────────────────── RESET ── */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;overflow-x:hidden}
body{font-family:var(--f-body);background:var(--white);color:var(--black);
  font-size:1rem;line-height:1.6;overflow-x:hidden;-webkit-font-smoothing:antialiased}
img{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
ul{list-style:none}
button{cursor:pointer;border:none;background:none;font:inherit;color:inherit}
svg{stroke-width:2.25}

/* ONE focus ring for the whole site, in blue, because focus is an action state.
   Replaces twelve separate `outline: 2px solid var(--accent)` declarations. */
:focus-visible{outline:3px solid var(--blue);outline-offset:3px;border-radius:var(--r-sm)}
.on-dark :focus-visible{outline-color:var(--yellow)}

/* ───────────────────────────────────────────────────────────── TYPOGRAPHY ── */
h1,h2,h3,h4{font-family:var(--f-head);line-height:1.15;letter-spacing:-.025em;
  text-wrap:balance;color:var(--fg)}
h1{font-size:clamp(2.4rem,5.5vw,4.2rem);font-weight:800;letter-spacing:-.035em}
h2{font-size:clamp(1.8rem,3.5vw,2.8rem);font-weight:800}
h3{font-size:1.2rem;font-weight:800}
h4{font-size:1rem;font-weight:800}
p{color:var(--fg-dim)}

/* Emphasis inside a heading. Was orange text; now it is the portfolio's yellow
   marker highlight, which is the same gesture with the system's own colour.
   Kept as an inline background so it wraps with the text across lines. */
h1 em,h2 em,.em{font-style:normal;font-weight:inherit;color:var(--black);
  background:linear-gradient(transparent 58%,var(--yellow) 58%);
  padding-inline:.08em}
.on-dark h1 em,.on-dark h2 em{color:var(--black);
  background:linear-gradient(transparent 0,var(--yellow) 0);padding-inline:.12em}

/* EYEBROW — black text, red dot. Copied from the portfolio exactly, and the
   reason matters: --red is 3.68:1 on white and 2.55:1 on the yellow pill, so
   red TEXT fails AA at any size under 24px. The portfolio never sets small
   text in red. It puts the red on a dot instead, which is a graphic and only
   needs 3:1. Red text survives only where it is genuinely large: the hero
   stat numbers, the pricing figure, the terms numerals. */
.eyebrow{font-family:var(--f-body);font-size:.76rem;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;color:var(--black);
  display:inline-flex;align-items:center;gap:.5rem}
.eyebrow::before{content:"";width:9px;height:9px;border-radius:50%;
  background:var(--red);flex:none}

/* THE SQUIGGLE — the portfolio's drawn red underline, tile and all.
   This is what section headings use for emphasis. It matters beyond looks:
   it keeps the YELLOW highlight reserved for the logo, so the logo's band
   never has to compete with a heading on the same screen.
   The tile starts and ends at a wave PEAK, where the tangent is horizontal,
   so the butt cap is flush with the tile edge and the repeats join invisibly.
   Do not move the ends to a midline crossing, use Q/T, or pad the viewBox. */
/* THE SQUIGGLE. The portfolio sets white-space:nowrap on this, which is safe
   there because it only ever wraps a two-word heading. Here it wraps a whole
   sentence, and at 320px nowrap pushed headings up to 144px past the right
   edge of the page.
   So it is a repeating background on the inline box rather than an absolutely
   positioned ::after, with box-decoration-break:clone so every line fragment
   of a wrapped heading gets its own underline. Identical on one line, correct
   on two.
   The tile starts and ends at a wave PEAK, where the tangent is horizontal, so
   the butt cap is flush with the tile edge and repeats join invisibly. Do not
   move the ends to a midline crossing, use Q/T, or pad the viewBox. */
.squig{
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 12'%3E%3Cpath d='M0 2.8 C4.36 2.8 7.64 9.2 12 9.2 C16.36 9.2 19.64 2.8 24 2.8' fill='none' stroke='%23EE4B3B' stroke-width='3'/%3E%3C/svg%3E") repeat-x left bottom/auto .3em;
  padding-bottom:.2em;
  -webkit-box-decoration-break:clone;box-decoration-break:clone}

/* ───────────────────────────────────────────────────────────────── LAYOUT ── */
.container{max-width:1240px;margin-inline:auto;
  padding-inline:clamp(1.25rem,5vw,3rem);position:relative;z-index:1}
section{padding-block:clamp(4rem,8vw,8rem);position:relative;z-index:1;
  scroll-margin-top:96px}
.section-header{display:flex;flex-direction:column;gap:.85rem;
  margin-bottom:clamp(2.5rem,5vw,4rem)}
.section-header p{color:var(--fg-dim);font-size:1.05rem;max-width:52ch;line-height:1.7}

/* Section headings get the red drawn underline. This is the other half of
   where red lives, and it is what keeps YELLOW free for the logo band and the
   one loud section.
   THE SQUIGGLE GOES ON A SPAN AROUND THE WORDS, not on the <h2>. Two reasons,
   both found the hard way: .section-header is a column flex container, so an
   inline-block h2 gets blockified back to `block` and the underline stretches
   the full column width; and even without that, shrink-to-fit on a heading
   that wraps still resolves to the available width. The portfolio marks up a
   span for exactly this reason. See .squig above. */

/* Marker highlight for body copy — the portfolio's .hl. Yellow earns its place
   here, a few words at a time, instead of as a section wash. */
.hl{background:linear-gradient(transparent 60%,var(--yellow) 60%);
  padding-inline:.1em;font-weight:700;color:var(--black)}

/* ──────────────────────────────────────────────────── AMBIENT BACKGROUND ──
   Replaces #pixel-canvas and the four blurred .fshape blobs. Those were a
   drifting particle canvas and 50px-blur radial gradients: soft, atmospheric,
   and the opposite of a system built on 2px black outlines.
   These are the portfolio's breathing shapes — flat geometry, low opacity,
   out of phase with each other.
   COLOUR RULE, copied from the portfolio's own comment: red over blue makes a
   soft lavender and is fine. YELLOW over BLUE goes khaki. So blue shapes are
   placed clear of the yellow ones, never on top of them.
   ───────────────────────────────────────────────────────────────────────── */
/* SCOPED TO THE HERO, NOT FIXED TO THE VIEWPORT. The blur blobs this replaces
   were position:fixed and drifted behind the whole page, which was survivable
   at 50px of blur. These shapes have hard edges, so the same treatment put a
   solid yellow pill under a paragraph halfway down the page and made the body
   copy hard to read. The portfolio confines its shapes to two wells — the hero
   and the footer — and never lets them run behind running text. Same here. */
.hero,.page-hero,.notfound{position:relative;overflow:hidden;isolation:isolate}
.drift{position:absolute;inset:0;z-index:-1;pointer-events:none;overflow:hidden}

/* EVERY SHAPE SITS WHOLLY INSIDE ITS HERO — no bleeding off the edges.
   That is harder than it sounds, for two reasons:

   1. The heroes are wildly different heights: 388px on Confirm a Project, 1056
      on the homepage, 1670 on North Alabama. Sizing in vw (what I had) means a
      shape that fits the tall hero overflows the short one. So every shape is
      sized by HEIGHT as a percentage of the hero, with a px ceiling, and takes
      its width from aspect-ratio. A percentage height can never overflow the
      box it is measured against.

   2. ROTATION INFLATES THE BOUNDING BOX and the insets have to pay for it.
      A square rotated 14 degrees occupies 1.21x its own width. A 3.4:1 pill
      rotated 8 degrees grows ~45% TALLER than its own height, because most of
      that growth comes from its width swinging into the vertical. The pill's
      rotation is therefore gentler than the portfolio's -16deg, and its bottom
      inset is sized for the inflated box, not the nominal one.
   Verified by measuring all four edges of all six shapes against the hero box
   on all eight pages. If you change a size or an angle, re-measure. */
.sh{position:absolute;opacity:.12}
.sh.circle{height:min(30%,320px);aspect-ratio:1;border-radius:50%;
  background:var(--red);left:3%;top:7%}
.sh.tri{height:min(24%,250px);aspect-ratio:1;background:var(--yellow);
  clip-path:polygon(50% 4%,96% 92%,4% 92%);right:7%;top:10%;rotate:10deg;opacity:.3}
.sh.b-ring{height:min(19%,190px);aspect-ratio:1;border-radius:50%;
  border:clamp(12px,1.6vw,22px) solid var(--blue);left:7%;top:45%}
.sh.b-dot{height:min(12%,130px);aspect-ratio:1;border-radius:50%;
  background:var(--blue);right:26%;top:24%}
.sh.pill{height:min(13%,140px);aspect-ratio:3.2;border-radius:var(--r-full);
  background:var(--yellow);left:14%;bottom:13%;rotate:-8deg;opacity:.3}
.sh.ring{height:min(20%,210px);aspect-ratio:1;border-radius:50%;
  border:clamp(14px,1.8vw,26px) solid var(--red);right:11%;bottom:8%}

@keyframes breathe{0%,100%{opacity:.05}50%{opacity:.14}}
@keyframes breatheY{0%,100%{opacity:.10}50%{opacity:.26}}
@keyframes drift{0%,100%{translate:0 0}50%{translate:0 -14px}}
@keyframes wiggle{0%,100%{rotate:0deg}25%{rotate:3deg}75%{rotate:-3deg}}

@media (prefers-reduced-motion:no-preference){
  .sh{animation:breathe 11s ease-in-out infinite,drift 16s ease-in-out infinite}
  .sh.tri,.sh.pill{animation-name:breatheY,drift}
  /* Offsets chosen so no two shapes peak together. Line them up and the page
     pulses as one object instead of drifting. */
  .sh.tri   {animation-delay:-3s,-6s;  animation-duration:13s,18s}
  .sh.pill  {animation-delay:-6s,-2s;  animation-duration:12s,15s}
  .sh.ring  {animation-delay:-8s,-9s;  animation-duration:14s,20s}
  .sh.b-ring{animation-delay:-2s,-11s; animation-duration:12s,19s}
  .sh.b-dot {animation-delay:-10.5s,-7.5s;animation-duration:13s,21s}
}
@media (max-width:768px){.drift{display:none}}

/* ─────────────────────────────────────────────────────────── SCROLL REVEAL ── */
.rev{opacity:0;transform:translateY(28px);
  transition:opacity .8s var(--ease),transform .8s var(--ease)}
.rev.visible{opacity:1;transform:none}
.rev.rd1{transition-delay:.1s}
.rev.rd2{transition-delay:.2s}
.rev.rd3{transition-delay:.3s}
.rev.rd4{transition-delay:.4s}
@media (prefers-reduced-motion:reduce){
  .rev{opacity:1;transform:none;transition:none}
  .sh{animation:none}
}

/* ──────────────────────────────────────────────────────────────────── NAV ──
   The portfolio's hanging bar: no top border, bottom corners rounded, a hard
   shadow, and it sits inside the page width instead of spanning the viewport.
   Replaces the translucent blurred bar — a backdrop-filter has no place in a
   system whose whole premise is opaque surfaces with hard edges. */
/* NO max-width HERE, deliberately. .nav__inner also carries .container, and
   .container widens to 1600px above a 1600px viewport. Pinning .nav to 1240px
   left the bar 360px narrower than the content under it on a wide screen.
   .nav stays full-width and transparent; the bar IS the container. */
.nav{position:sticky;top:0;z-index:100;
  padding-bottom:12px;background:none;border:none;backdrop-filter:none}
.nav__inner{display:flex;align-items:center;justify-content:space-between;
  gap:1rem;padding:.6rem clamp(1rem,3vw,2rem);min-height:72px;
  background:var(--white);border:var(--bw) solid var(--black);border-top:none;
  border-radius:0 0 var(--r-lg) var(--r-lg);box-shadow:4px 4px 0 0 var(--black)}
.nav__links{display:flex;align-items:center;gap:.25rem}
.nav__links a,.nav__dropdown-trigger{
  display:inline-flex;align-items:center;min-height:44px;padding:0 1rem;
  font-family:var(--f-body);font-size:.9rem;font-weight:700;color:var(--black);
  border:var(--bw) solid transparent;border-radius:var(--r-full);
  transition:background-color .25s var(--ease),color .25s var(--ease)}
@media (hover:hover){
  .nav__links a:not(.btn-nav):hover,
  .nav__dropdown-trigger:hover{background:var(--yellow-soft)}
}
.nav__links a.active,
.nav__dropdown-trigger.active,
.nav__dropdown.open .nav__dropdown-trigger{color:var(--blue)}
/* `.nav__links a` is class+element, so it outranks the plain `.btn-nav` in the
   button block below and was overriding BOTH its colour and its border — the
   Let's Talk pill lost the 2px black stroke and the hard shadow that the
   portfolio's Resume pill has, and was left a flat blue lozenge. Restated here
   at matching specificity. */
.nav__links a.btn-nav{
  color:var(--white);background:var(--blue);
  border:var(--bw) solid var(--black);box-shadow:var(--pop)}
.nav__links a.btn-nav:hover{
  background:var(--blue);color:var(--white);
  transform:translate(-2px,-2px);box-shadow:var(--pop-hover)}
.nav__links a.btn-nav:active{transform:translate(2px,2px);box-shadow:var(--pop-active)}

/* NAV SQUIGGLE — "you are here". The portfolio draws the red wave under the
   active link, not a colour change. Heavier stroke than the heading squiggle
   because this renders at 8px tall and a 3-unit stroke comes out under 2px. */
.nav__links a.nl,.nav__links a.active,.nav__dropdown-trigger{position:relative}
.nav__links a.active::after,.nav__dropdown-trigger.active::after{
  content:"";position:absolute;left:1rem;right:1rem;bottom:6px;height:8px;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 12'%3E%3Cpath d='M0 2.8 C4.36 2.8 7.64 9.2 12 9.2 C16.36 9.2 19.64 2.8 24 2.8' fill='none' stroke='%23EE4B3B' stroke-width='3.6'/%3E%3C/svg%3E") repeat-x 0 50%/auto 100%}
.nav__dropdown-trigger{gap:.3rem;background:none}
.nav__dropdown-trigger svg{transition:transform .2s var(--ease)}
.nav__dropdown.open .nav__dropdown-trigger svg{transform:rotate(180deg)}

.nav__dropdown{position:relative}
/* Right-anchored, not left. The Work dropdown is second from the end of the
   nav, so opening leftward from the trigger is the only way it cannot push
   past the page edge — at 769px, the first width above the mobile
   breakpoint, a left-anchored 200px menu overflowed by 9px. */
.nav__dropdown-menu{position:absolute;top:calc(100% + .6rem);right:0;left:auto;min-width:200px;
  background:var(--white);border:var(--bw) solid var(--black);
  border-radius:var(--r-md);padding:.4rem;box-shadow:var(--pop);
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .2s var(--ease),transform .2s var(--ease),visibility .2s;z-index:10}
.nav__dropdown:hover .nav__dropdown-menu,
.nav__dropdown.open .nav__dropdown-menu{opacity:1;visibility:visible;transform:none}
.nav__dropdown-menu li+li{margin-top:.15rem}
.nav__dropdown-menu a{display:flex;align-items:center;min-height:44px;
  padding:.4rem .75rem;border-radius:var(--r-sm);
  font-size:.9rem;font-weight:700;color:var(--black);border:none;
  transition:background .15s,color .15s}
.nav__dropdown-menu a:hover{background:var(--yellow-soft)}
.nav__dropdown-menu a.active{color:var(--blue);background:var(--blue-soft)}

.nav__toggle{display:none;flex-direction:column;gap:5px;padding:10px;
  border:var(--bw) solid var(--black);border-radius:var(--r-sm);background:var(--white)}
.nav__toggle span{display:block;width:22px;height:2px;background:var(--black);
  border-radius:2px;transition:transform .3s var(--ease),opacity .3s}

@media (max-width:768px){
  .nav__links{display:none}
  .nav__links.open{display:flex;flex-direction:column;position:absolute;
    top:calc(100% + 6px);left:0;right:0;background:var(--white);
    border:var(--bw) solid var(--black);border-radius:var(--r-lg);
    box-shadow:var(--pop);padding:1rem;gap:.2rem;align-items:stretch;
    animation:slideDown .25s var(--ease)}
  .nav__links.open li{width:100%}
  .nav__links.open a,.nav__links.open .nav__dropdown-trigger{
    display:flex;width:100%;padding:.75rem 1rem;font-size:1rem;border-radius:var(--r-sm)}
  .nav__links.open .btn-nav{margin-top:.6rem;justify-content:center}
  .nav__links.open .nav__dropdown-trigger svg{display:none}
  .nav__links.open .nav__dropdown-menu{position:static;opacity:1;visibility:visible;
    transform:none;box-shadow:none;border:none;padding:0 0 0 .75rem}
  .nav__toggle{display:flex}
}
@keyframes slideDown{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}

/* ──────────────────────────────────────────────────────────────── BUTTONS ──
   Every primary action is now the same object: a pill with a 2px black border
   and a hard shadow that moves under the press. Replaces five near-identical
   classes (.btn-primary .btn-nav .btn-cta .btn-pricing) that each
   carried their own soft orange glow. The shadow colour comes from --pop-c, so
   these work unchanged inside a dark section. */
.btn-primary,.btn-nav,.btn-cta,.btn-pricing{
  display:inline-flex;align-items:center;justify-content:center;gap:.6rem;
  font-family:var(--f-head);font-weight:800;letter-spacing:-.01em;
  background:var(--blue);color:var(--white);
  border:var(--bw) solid var(--line);border-radius:var(--r-full);
  box-shadow:var(--pop);
  transition:transform .3s var(--bounce),box-shadow .3s var(--bounce),
             background .25s var(--ease)}
.btn-primary,.btn-cta,.btn-pricing{
  min-height:56px;padding:0 1.9rem;font-size:1.02rem}
.btn-nav{min-height:44px;padding:0 1.2rem;font-size:.9rem}
.btn-primary:hover,.btn-nav:hover,.btn-cta:hover,.btn-pricing:hover:hover{
  background:var(--blue);color:var(--white);transform:translate(-2px,-2px);box-shadow:var(--pop-hover)}
.btn-primary:active,.btn-nav:active,.btn-cta:active,.btn-pricing:active:active{
  transform:translate(2px,2px);box-shadow:var(--pop-active)}

/* Secondary: same object, white fill. The old .btn-secondary was a bare text
   link whose only hover was a widening gap, which gave the page two completely
   different ideas of what a button looks like. */
.btn-secondary,.btn-secondary-outline{
  display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
  min-height:56px;padding:0 1.6rem;
  font-family:var(--f-head);font-weight:800;font-size:1.02rem;
  background:var(--white);color:var(--black);
  border:var(--bw) solid var(--black);border-radius:var(--r-full);
  box-shadow:4px 4px 0 0 var(--black);
  transition:transform .3s var(--bounce),box-shadow .3s var(--bounce),color .25s var(--ease)}
.btn-secondary:hover,.btn-secondary-outline:hover{
  transform:translate(-2px,-2px);box-shadow:6px 6px 0 0 var(--black);color:var(--blue)}
.btn-secondary:active,.btn-secondary-outline:active{
  transform:translate(2px,2px);box-shadow:2px 2px 0 0 var(--black)}

.magnetic-wrap{display:inline-block}

/* ───────────────────────────────────────────────────────────── PAGE HERO ── */
.page-hero{padding-block:clamp(3rem,6vw,5.5rem) clamp(2.5rem,5vw,4rem)}
.page-hero__inner{max-width:780px;display:flex;flex-direction:column;gap:1.25rem}
.page-hero h1{color:var(--fg)}
.page-hero__sub{font-size:clamp(1.05rem,1.5vw,1.2rem);color:var(--fg-dim);
  line-height:1.75;max-width:58ch}

/* ──────────────────────────────────────────────────────── CARD SHAPE LAYER ──
   The one recipe every panel on the site now uses: white, 2px black outline,
   hard shadow, and a press that pushes it into the page. Applied by class list
   rather than by a shared `.card` class so the existing markup does not have to
   change. */
/* ═══ THE TRIAD RULE ═══════════════════════════════════════════════════════
   The portfolio gets away with an all-red resting shadow because its grids are
   full-bleed PHOTOGRAPHS — the imagery carries the colour and the shadow is
   just an edge. AC Studios' grids are text cards on white, so one shadow colour
   repeated six times becomes a wall of that colour. First pass: all black, and
   yellow ended up carrying the page. Second pass: all red, and Services and
   Team became red-and-white with no blue anywhere.
   So the resting shadow CYCLES red → blue → yellow across every grid, and the
   icon tile inside each card is offset by one step. Each card therefore shows
   two different colours, and any three consecutive cards show all three. The
   rule is per-grid, so it holds no matter how many cards a section has.
   Blue still owns action: hover is what moves, and clickable cards still go
   blue on hover. A resting shadow is an ambient layer, not a control.
   ═══════════════════════════════════════════════════════════════════════════ */
.service-card,.pricing-card,.testimonial-card,.note-card,
.confirm-card,.contact-card,.team-card,.highlight-card,.credential-card,
.service-link-card,.callout,.cs-card,.hero__visual,
.terms-section,.jotform-embed{
  background:var(--white);border:var(--bw) solid var(--black);
  border-radius:var(--r-md);box-shadow:6px 6px 0 0 var(--red);color:var(--black);
  transition:transform .35s var(--ease),box-shadow .35s var(--ease)}

/* THE WORK — blue. Everything in this group leads somewhere: a case study, a
   client, a service you can enquire about, a linked sub-page. Blue already
   means "this goes somewhere", so the shadow is saying the same thing the
   button says. */
.service-card,.service-link-card,.cs-card,.client-card,
.highlight-card,.faq__list,.local-faq{
  box-shadow:6px 6px 0 0 var(--blue)}

/* MONEY — yellow, but NOT as a shadow. #FFD23F is 1.7:1 on white: as a hard
   offset it barely separates the card from the page, and on the pale yellow
   Pricing band it vanishes outright. Yellow is a SURFACE colour everywhere
   else in this system — bands, highlights, pills, the logo mark — and a hard
   shadow is not a surface.
   So the money cards say "money" with their yellow icon tile and the yellow
   band they sit on, and take BLUE for the shadow, which is honest anyway:
   every one of them leads to a quote or the contact form. */
.pricing-card,.contact-card,.confirm-card{
  box-shadow:6px 6px 0 0 var(--blue)}

/* PEOPLE AND VOICE — red. These say something in a human voice and none of them
   is a control: the crew, Angie's own note, testimonials, asides. Red is
   already the colour of the squiggle and the eyebrow dot — the marks that point
   at something without being clickable — so this is the same job, scaled up. */
.team-card,.note-card,.testimonial-card,.callout,.credential-card,
.terms-section,.about__photo-wrap{
  box-shadow:6px 6px 0 0 var(--red)}
/* The About photo keeps the portfolio's bigger offset. */
.about__photo-wrap{box-shadow:8px 8px 0 var(--red)}

/* A card on a dark band keeps the dark ground and flips its STRUCTURE to white,
   rather than becoming a white card. Six white panels in a black band would
   invert the band's whole read, and the band exists to break up the page. */
.on-dark .service-card,.on-dark .pricing-card,.on-dark .note-card,
.on-dark .faq-item,.on-dark .cs-card,.on-dark .highlight-card,
.on-dark .credential-card,.on-dark .callout,.on-dark .contact-card{
  background:transparent;color:var(--white);border-color:var(--white)}
.on-dark .service-card h3,.on-dark .highlight-card h3,
.on-dark .credential-card h3,.on-dark .cs-card__title{color:var(--white)}
.on-dark .highlight-card p,.on-dark .credential-card p{color:rgba(255,255,255,.72)}

/* ICON TILES. One rule for all three, and it exists because of a collision:
   the old CSS set the tile to --accent and the glyph inside to --accent-light,
   two values that were far apart in the orange palette. Both alias into the
   new yellow, so the icons went yellow-on-yellow and vanished. Black glyph on
   a bordered yellow tile — legible on every ground, light or dark. */
/* ICON TILES — white with a RED glyph, not solid yellow. Six yellow blocks in
   a service grid plus six more on Pricing was most of the remaining yellow,
   and it put the loudest colour on a repeated decorative element. Red ties the
   glyph to the card's own red shadow and to the heading squiggles, so the three
   colours each hold a consistent job down the page. Red on white is 3.68:1,
   which clears the 3:1 that graphics need (it is only TEXT that red fails).
   Yellow arrives on hover — the tile lights up when you touch the card. */
.service-card__icon,.pricing-card__icon,.highlight-card__icon,
.credential-card__icon,.service-link-card__icon{
  background:var(--blue-soft);color:var(--black);
  border:var(--bw) solid var(--black);border-radius:var(--r-sm);
  box-shadow:3px 3px 0 var(--black);
  display:grid;place-items:center;flex:none;
  transition:background-color .25s var(--ease),transform .25s var(--bounce)}
.service-card__icon svg,.pricing-card__icon svg,.highlight-card__icon svg,
.credential-card__icon svg{stroke:currentColor}

/* The icon tile carries its card's meaning as a pale tint, so each card reads
   as one unit instead of two unrelated colours. */
.service-card__icon,.service-link-card__icon,.highlight-card__icon{background:var(--blue-soft)}
.pricing-card__icon{background:var(--yellow-soft)}
.credential-card__icon{background:var(--red-soft)}

.service-card:hover .service-card__icon,.service-card.is-inview .service-card__icon,
.pricing-card:hover .pricing-card__icon,.pricing-card.is-inview .pricing-card__icon,
.highlight-card:hover .highlight-card__icon{
  background:var(--yellow);color:var(--black);transform:rotate(-6deg) scale(1.08)}
/* On a dark band the tile keeps a white ground so the glyph still reads. */
.on-dark .highlight-card__icon,.on-dark .credential-card__icon{
  background:var(--white);box-shadow:3px 3px 0 var(--white)}

/* Hover lift. `.is-inview` is the site's own touch-device stand-in for hover:
   the reveal script adds it when a card scrolls into view, so a phone sees the
   hover state once instead of never. Kept. */
.service-card:hover,.service-card.is-inview,
.pricing-card:hover,.pricing-card.is-inview,
.team-card:hover,.team-card.is-inview,
.highlight-card:hover,.credential-card:hover,
.service-link-card:hover,.service-link-card.is-inview,
.cs-card:hover,.testimonial-card:hover{
  transform:translate(-2px,-2px);box-shadow:8px 8px 0 0 var(--blue)}
/* The press pushes the card into the page, same as the portfolio's tiles. */
.service-link-card:active,.cs-card:active{
  transform:translate(4px,4px);box-shadow:3px 3px 0 0 var(--blue);transition-duration:.08s}

/* The client-card name bar was a scrim fading to transparent. That works over
   a dark brand gradient and fails over the WHITE panel the real-logo clients
   use: white text on near-white at the top of the bar. A solid band instead,
   which is also what the rest of the system does — opaque surfaces, no fades.
   Pre-existing problem, fixed here because the band had to be restyled anyway. */
.work-card__info{background:var(--black);border-top:var(--bw) solid var(--black)}
.work-card__info-name{color:var(--white)}

/* CHIPS — white, not yellow. The portfolio's skill chips are white pills with a
   black border and a small hard shadow; they only take a tint on HOVER, and the
   tint cycles through all three pale colours so no one chip looks singled out.
   A grid of six service cards with four yellow chips each was a big part of
   what made the page read as one colour. */
.tag,.process-step__pill{
  display:inline-flex;align-items:center;gap:.4rem;
  font-family:var(--f-body);font-size:.78rem;font-weight:700;letter-spacing:0;
  padding:.3rem .85rem;border-radius:var(--r-full);
  border:var(--bw) solid var(--black);background:var(--white);color:var(--black);
  box-shadow:3px 3px 0 var(--black);
  transition:transform .25s var(--bounce),box-shadow .25s var(--bounce),
             background-color .25s var(--ease)}
@media (hover:hover){
  .tag:hover,.process-step__pill:hover{transform:translate(-2px,-2px);box-shadow:5px 5px 0 var(--black)}
  .tag:nth-child(3n+1):hover{background:var(--yellow-soft)}
  .tag:nth-child(3n+2):hover{background:var(--blue-soft-2)}
  .tag:nth-child(3n+3):hover{background:var(--red-soft)}
}

/* STATUS badges keep the yellow tint — the portfolio's "Coming soon" pill does
   the same. These say something about state, so standing out is the job. */
.client-card__badge,.in-progress-badge,.team-card__role{
  display:inline-flex;align-items:center;gap:.4rem;
  font-family:var(--f-body);font-size:.74rem;font-weight:700;letter-spacing:.02em;
  padding:.22rem .7rem;border-radius:var(--r-full);
  border:var(--bw) solid var(--black);background:var(--yellow-soft);color:var(--black)}



/* ─────────────────────────────────────────────────────── PAINT STROKE ──
   Modelled on the portfolio's intro animation: a yellow brush lays down
   first and the content is revealed INSIDE it a beat later. The intro does
   that on a canvas with bristle sub-strokes and a `source-in` composite.
   Here it is the same idea in CSS — the mark is an SVG of one thick
   round-capped wave plus five thinner bristle waves at varying width and
   alpha, which is what gives it a dry-brush edge rather than a flat bar.
   The waves are cubics tuned to a true sine (controls at 0.3634 of each
   half-period, horizontal tangent at the peaks), the same construction the
   portfolio's .squig uses.

   The reveal is two clip-paths: the stroke wipes in, and the text follows
   120ms behind it. That lag is the portfolio's too — its mask runs at
   (p - 0.14) / 0.86, so the paint always leads the content.

   USED TWICE, DELIBERATELY. Once on the availability line and once on the
   emphasised phrase in each page's h1. Any more and it stops being a
   flourish. */
.paint{position:relative;display:inline-block;isolation:isolate}
.paint::before{
  content:"";position:absolute;z-index:-1;
  left:-.5em;right:-.5em;top:-.22em;bottom:-.18em;
  background:url("data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 400 100%22 preserveAspectRatio=%22none%22><path d=%22M14.0 53.5 C47.8 53.5 73.2 46.5 107.0 46.5 C140.8 46.5 166.2 53.5 200.0 53.5 C233.8 53.5 259.2 46.5 293.0 46.5 C326.8 46.5 352.2 53.5 386.0 53.5%22 fill=%22none%22 stroke=%22%23FFD23F%22 stroke-width=%2234%22 stroke-linecap=%22round%22/><path d=%22M26.0 29.8 C46.6 29.8 62.1 24.2 82.7 24.2 C103.3 24.2 118.7 29.8 139.3 29.8 C159.9 29.8 175.4 24.2 196.0 24.2 C216.6 24.2 232.1 29.8 252.7 29.8 C273.3 29.8 288.7 24.2 309.3 24.2 C329.9 24.2 345.4 29.8 366.0 29.8%22 fill=%22none%22 stroke=%22%23FFD23F%22 stroke-width=%223%22 stroke-linecap=%22round%22 opacity=%220.3%22/><path d=%22M18.0 28.2 C51.1 28.2 75.9 33.8 109.0 33.8 C142.1 33.8 166.9 28.2 200.0 28.2 C233.1 28.2 257.9 33.8 291.0 33.8 C324.1 33.8 348.9 28.2 382.0 28.2%22 fill=%22none%22 stroke=%22%23FFD23F%22 stroke-width=%225%22 stroke-linecap=%22round%22 opacity=%220.45%22/><path d=%22M10.0 37.8 C32.0 37.8 48.6 32.2 70.7 32.2 C92.7 32.2 109.3 37.8 131.3 37.8 C153.4 37.8 170.0 32.2 192.0 32.2 C214.0 32.2 230.6 37.8 252.7 37.8 C274.7 37.8 291.3 32.2 313.3 32.2 C335.4 32.2 352.0 37.8 374.0 37.8%22 fill=%22none%22 stroke=%22%23FFD23F%22 stroke-width=%227%22 stroke-linecap=%22round%22 opacity=%220.62%22/><path d=%22M22.0 63.2 C55.1 63.2 79.9 68.8 113.0 68.8 C146.1 68.8 170.9 63.2 204.0 63.2 C237.1 63.2 261.9 68.8 295.0 68.8 C328.1 68.8 352.9 63.2 386.0 63.2%22 fill=%22none%22 stroke=%22%23FFD23F%22 stroke-width=%226%22 stroke-linecap=%22round%22 opacity=%220.58%22/><path d=%22M14.0 72.8 C35.6 72.8 51.8 67.2 73.3 67.2 C94.9 67.2 111.1 72.8 132.7 72.8 C154.2 72.8 170.4 67.2 192.0 67.2 C213.6 67.2 229.8 72.8 251.3 72.8 C272.9 72.8 289.1 67.2 310.7 67.2 C332.2 67.2 348.4 72.8 370.0 72.8%22 fill=%22none%22 stroke=%22%23FFD23F%22 stroke-width=%224%22 stroke-linecap=%22round%22 opacity=%220.42%22/><path d=%22M34.0 71.2 C65.3 71.2 88.7 76.8 120.0 76.8 C151.3 76.8 174.7 71.2 206.0 71.2 C237.3 71.2 260.7 76.8 292.0 76.8 C323.3 76.8 346.7 71.2 378.0 71.2%22 fill=%22none%22 stroke=%22%23FFD23F%22 stroke-width=%222.5%22 stroke-linecap=%22round%22 opacity=%220.26%22/><path d=%22M30.0 46.0 C50.0 46.0 65.0 42.0 85.0 42.0 C105.0 42.0 120.0 46.0 140.0 46.0 C160.0 46.0 175.0 42.0 195.0 42.0 C215.0 42.0 230.0 46.0 250.0 46.0 C270.0 46.0 285.0 42.0 305.0 42.0 C325.0 42.0 340.0 46.0 360.0 46.0%22 fill=%22none%22 stroke=%22%23FFFFFF%22 stroke-width=%222.5%22 stroke-linecap=%22round%22 opacity=%22.18%22/><path d=%22M40.0 53.0 C70.0 53.0 92.5 57.0 122.5 57.0 C152.5 57.0 175.0 53.0 205.0 53.0 C235.0 53.0 257.5 57.0 287.5 57.0 C317.5 57.0 340.0 53.0 370.0 53.0%22 fill=%22none%22 stroke=%22%23FFFFFF%22 stroke-width=%222%22 stroke-linecap=%22round%22 opacity=%22.14%22/></svg>") center/100% 100% no-repeat;
  clip-path:inset(0 100% 0 0)}
.paint__t{display:inline-block;clip-path:inset(0 101% 0 0)}
.paint.painted::before{clip-path:inset(0 0 0 0);
  transition:clip-path .9s cubic-bezier(.16,1,.3,1)}
.paint.painted .paint__t{clip-path:inset(0 -4% 0 0);
  transition:clip-path .9s cubic-bezier(.16,1,.3,1) .12s}

/* The emphasised phrase in a headline is now a painted stroke rather than the
   flat marker band. Same colour, same job — it just arrives by being painted.
   The insets are POSITIVE, pulling the brush in from the line box, because the
   line box is taller than the letters and centring on it floated the bristles
   up into the line above. From Gabarito's metrics at line-height 1.15: content
   area 1.2em, half-leading -0.025em, so the baseline sits 0.915em down and the
   cap top 0.234em down. The brush spans just outside that band. */
h1 .paint::before{left:-.3em;right:-.3em;top:.17em;bottom:.15em}

/* The availability line is 0.72rem uppercase — small enough that the brush
   needs to be proportionally taller than it is on a headline, or it reads as
   an underline rather than a stroke the text sits in. */
.avail-badge.paint::before{left:-1.1em;right:-1.1em;top:-.95em;bottom:-.9em}
/* A hair off-axis, the way the portfolio tilts its "LIKE WHAT YOU SEE?"
   kicker. At this size the bristle texture squashes away to almost
   nothing, so the tilt is what stops it reading as a UI pill again. */
.avail-badge.paint{rotate:-1.5deg;transform-origin:left center}

/* AVAILABILITY LINE. The pill is gone: no border, no fill, no radius. The
   brush is the container now, and the LABEL is what pulses — there is no
   longer a dot.

   THE LABEL ITSELF NEVER WEAKENS. An opacity breath was the first attempt and
   it was wrong: a loop that spends half its time fading the text out makes the
   thing quieter, when the whole point is emphasis. So the text sits at full
   strength in the heaviest weight Gabarito has, and the PULSE MOVED BEHIND IT
   — the brush swells and settles while the words stay put. Emphasis is added
   at the peak instead of subtracted at the trough.

   Gated on .painted so the swell only starts once the brush has finished
   laying down. The two would fight otherwise. */
.avail-badge{background:none;border:none;border-radius:0;box-shadow:none;
  padding:.1rem .2rem;width:fit-content;cursor:default}
.avail-badge:hover{background:none;border:none}
/* Same size, far more weight. 900 is the top of Gabarito's range, and the
   wider tracking buys presence at a size that cannot grow. */
.avail-text{color:var(--black);font-weight:900;letter-spacing:.085em}

/* The brush swells; the words do not move and do not dim. Scaled from the left
   edge so the mark grows into the space after it rather than drifting off the
   stat card's left margin. */
@keyframes availSwell{
  0%,100%{transform:scale(1,1);opacity:.92}
  50%    {transform:scale(1.035,1.14);opacity:1}
}
@media (prefers-reduced-motion:no-preference){
  .avail-badge.painted::before{
    transform-origin:8% center;
    animation:availSwell 2.8s ease-in-out 1s infinite}
}

@media (prefers-reduced-motion:reduce){
  .paint::before,.paint .paint__t{clip-path:none;transition:none}
}

/* ─────────────────────────────────────────────────────────────── ACCORDION ──
   The FAQ is ONE card with rows inside, not six stacked cards.
   Two reasons. The original markup was a plain divider list — no box — so
   `.faq-item__btn` carried `padding: 1.5rem 0`, vertical only. Dropping each
   item into the card recipe gave it a 2px border with no horizontal padding
   behind it, so every question and answer sat directly on the stroke. And six
   bordered, shadowed cards stacked with no gap is a lot of chrome for what is
   really one list.
   So the WRAPPER is the card and the items are rows divided by a hairline.
   Blue shadow, because an accordion is something you operate. */
.faq__list,.local-faq{
  background:var(--white);border:var(--bw) solid var(--black);
  border-radius:var(--r-md);overflow:hidden;
  padding-inline:clamp(1.1rem,3vw,1.75rem)}
/* .local-faq ships with gap:1.5rem, which would leave the row dividers
   floating in mid-air instead of separating anything. */
.local-faq{gap:0}
.local-faq__item{padding-block:1.35rem}
.local-faq__item p{padding-right:2.5rem}
.faq-item,.local-faq__item{
  border:none;border-bottom:1px solid rgba(20,20,20,.14);
  background:none;box-shadow:none;border-radius:0}
.faq-item:first-child,.local-faq__item:first-child{border-top:none}
.faq-item:last-child,.local-faq__item:last-child{border-bottom:none}
.faq-item:hover,.local-faq__item:hover{transform:none;box-shadow:none}

/* The button keeps its vertical rhythm; the horizontal inset now comes from
   the wrapper, so the question and the + stay clear of the border. */
.faq-item__btn{padding-block:1.35rem;padding-inline:0;gap:1rem}
.faq-item__body-inner p{padding-bottom:1.4rem;padding-right:2.5rem}

/* Open state: the + rotates into an ×, on yellow. */
.faq-item__icon{background:var(--yellow-soft);border:2px solid var(--black);
  width:26px;height:26px}
.faq-item__btn[aria-expanded="true"] .faq-item__icon{background:var(--yellow)}

/* ─────────────────────────────────────────────────────────────── CTA STRIP ──
   The portfolio's "Let's Connect!" well: full yellow, oversized heading, red
   squiggle under it, buttons centred below. These used to be a second BLACK
   band sitting directly on top of the black footer — two dark slabs in a row,
   and the one place on the page that should shout was the quietest. */
/* .cta-strip is a <div>, not a <section>, so it never picked up the section
   padding and the band was clipping its own button against the footer. */
.cta-strip{position:relative;isolation:isolate;
  padding-block:clamp(3.5rem,7vw,6rem)}
.cta-strip__inner{display:grid;justify-items:center;text-align:center;gap:1.25rem;
  max-width:900px}
.cta-strip h2{color:var(--black)}
.cta-strip p{color:var(--black);opacity:.78;max-width:52ch}
/* Buttons sit on yellow, so the white secondary needs its border to carry it. */
.cta-strip .btn-cta,.cta-strip .btn-primary{margin-top:.5rem}

/* ───────────────────────────────────────────────────────────────── FOOTER ──
   Stays dark and stays a real four-column site footer. What changes is that
   the structure flips to white: --line is white in here, so the divider and
   any bordered child follow without a rule of their own. */
footer{background:var(--black);color:var(--white);
  --line:var(--white);--pop-c:var(--white);--fg:var(--white);--fg-dim:rgba(255,255,255,.72)}
.footer__grid{display:grid;grid-template-columns:1.4fr 1fr 1fr;gap:2.5rem;
  padding-block:3.5rem 2.5rem}
.footer__brand{display:flex;flex-direction:column;gap:1.1rem;max-width:340px}
.footer__tagline{font-size:.9rem;line-height:1.7;color:rgba(255,255,255,.62)}
.footer__contact{display:flex;align-items:center;gap:1rem}
.footer__email,.footer__col-links a{font-size:.9rem;font-family:var(--f-body);
  font-weight:500;color:rgba(255,255,255,.62);
  text-decoration-thickness:2px;text-underline-offset:3px;transition:color .2s}
.footer__email:hover,.footer__col-links a:hover{color:var(--white);text-decoration:underline}
.footer__social{display:inline-flex;color:rgba(255,255,255,.62);transition:color .2s}
.footer__social:hover{color:var(--yellow)}
.footer__col-title{font-family:var(--f-body);font-size:.74rem;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;color:var(--yellow);margin-bottom:1.1rem}
.footer__col-links{display:flex;flex-direction:column;gap:.75rem}
.footer__bottom{border-top:var(--bw) solid rgba(255,255,255,.18);padding-block:1.5rem}
.footer__copy{font-size:.82rem;font-family:var(--f-body);color:rgba(255,255,255,.5)}

/* ──────────────────────────────────────────────────────────── RESPONSIVE ── */
@media (max-width:900px){
  .footer__grid{grid-template-columns:1fr 1fr;gap:2rem}
  .footer__brand{grid-column:1 / -1;max-width:none}
}
/* TAP TARGETS. At 320px the nav lockup measured 22px tall and the hamburger
   38px, both under the 44px minimum. The lockup keeps its baseline alignment;
   the extra height is padding around it, not a bigger logo.
   The logo rule is NOT inside the mobile query: 769px is a tablet in landscape
   as often as it is a small desktop, and a 28px link is a bad target on either.
   It costs nothing visually — the bar is 72px tall regardless. */
.nav .ac-logo{min-height:46px;padding-block:.4rem}
@media (max-width:768px){
  .nav__toggle{padding:13px 11px}
}

@media (max-width:640px){
  /* The portfolio shrinks its hard shadows on phones so the offsets do not eat
     the margins. Same move here, through the tokens, so every component follows. */
  :root{--pop:2px 2px 0 0 var(--pop-c);--pop-hover:3px 3px 0 0 var(--pop-c);
        --pop-active:1px 1px 0 0 var(--pop-c);--pop-lg:4px 4px 0 0 var(--pop-c)}
  .nav__inner{box-shadow:2px 2px 0 0 var(--black);padding-inline:1rem}
  .btn-primary,.btn-cta,.btn-pricing,.btn-secondary,.btn-secondary-outline{
    min-height:52px;padding:0 1.4rem;font-size:.98rem}
  .btn-secondary,.btn-secondary-outline{box-shadow:2px 2px 0 0 var(--black)}
  .footer__grid{grid-template-columns:1fr}
}


/* ═══════════════════════════════════════════════════════ INTRO (HOME ONLY) ══
   The portfolio's opening, rebuilt for the AC Studios lockup: blue curtain,
   a yellow brush paints across in five alternating passes, the lockup is
   revealed inside the paint a beat behind it, short hold, then the lockup
   flies to its slot in the nav while the curtain fades.

   Differences from the portfolio's version, and why:
   - The portfolio masks a single PNG into the paint with a canvas `source-in`
     composite. The AC Studios lockup is live text plus the Angie mark, not one
     image, so there is nothing to mask. The paint and the lockup are separate
     layers wiped by the same clip-path instead, with the lockup lagging 180ms
     so the brush still leads.
   - The brush DRAWS rather than wipes: each pass is a stroked path animated on
     stroke-dashoffset, staggered by --i, so you watch it lay down pass by pass
     the way the canvas version does.
   - The flight to the nav is FLIP: measure both rects, transform the intro
     lockup onto the nav one, animate to identity.

   Runs on the home page only, once per session. See the script in index.html.
   ═══════════════════════════════════════════════════════════════════════════ */
#acx{position:fixed;inset:0;z-index:500;display:grid;place-items:center;
  background:var(--blue);cursor:pointer;transition:opacity .45s var(--ease)}
#acx[hidden]{display:none}
html.acx-on,html.acx-on body{overflow:hidden}
html.acx-on .nav .ac-logo{visibility:hidden}

/* FULL BLEED. The stage was min(78vw,760px) — a floating panel in the middle
   of the screen, so you could see each stroke start and stop and the paint
   looked like it came from nowhere. It now spans the whole viewport, and every
   stroke path runs 180 units past the viewBox on both sides, so the SVG clips
   the caps at the screen edge. The brush sweeps in from off-screen and leaves
   off-screen; there is no visible origin.
   Height is capped against the viewport so it never dominates a short window. */
.acx__stage{position:relative;display:grid;place-items:center;
  width:100vw;height:min(40vh,330px)}
.acx__brush{position:absolute;inset:0;width:100%;height:100%}
.acx__brush .p path{
  stroke-dasharray:var(--len,1400);stroke-dashoffset:var(--len,1400)}
/* Slower and more overlapped than before: each pass now travels the full
   width of the screen instead of 760px, so the old .62s read as a flick.
   The stagger is shorter than the duration, so passes are always overlapping
   and the paint never appears to stop between strokes. */
#acx.acx-go .acx__brush .p path{
  animation:acxDraw .86s cubic-bezier(.4,0,.15,1) forwards;
  animation-delay:calc(var(--i) * .13s)}
@keyframes acxDraw{to{stroke-dashoffset:0}}

/* The lockup sits over the paint and is revealed by the same left-to-right
   sweep, 180ms behind the first pass — the paint always leads. */
.acx__logo{position:relative;z-index:1;--ac-logo-size:clamp(1.9rem,5.4vw,4rem);
  clip-path:inset(0 100% 0 0)}
#acx.acx-go .acx__logo{clip-path:inset(0 -2% 0 0);
  transition:clip-path 1.02s cubic-bezier(.16,1,.3,1) .22s}
/* The lockup sits on the YELLOW PAINT, not on the blue curtain, so the small
   italic "by" stays dark. Flipping it white for the blue ground put white on
   yellow at 1.6:1 — invisible. Judge the ground the element actually sits on,
   not the one behind it. */
#acx .ac-logo{--ac-by:#141414}

.acx__hint{position:absolute;left:50%;bottom:max(26px,env(safe-area-inset-bottom,0px));
  transform:translateX(-50%);margin:0;color:var(--white);
  font:700 .72rem var(--f-body);letter-spacing:.16em;text-transform:uppercase;
  opacity:0;transition:opacity .4s var(--ease)}
#acx.acx-go .acx__hint{opacity:.62;transition-delay:1.1s}

#acx.acx-fly{background:transparent;transition:background .62s var(--ease)}
#acx.acx-fly .acx__brush{opacity:0;transition:opacity .34s var(--ease)}
#acx.acx-fly .acx__hint{opacity:0;transition-delay:0s}
.acx__logo.acx-flying{transition:transform .68s cubic-bezier(.16,1,.3,1);
  transform-origin:top left}
#acx.acx-out{opacity:0;pointer-events:none}

/* No intro at all under reduced motion — the script checks the same query and
   never inserts it, this is belt and braces. */
@media (prefers-reduced-motion:reduce){ #acx{display:none} }
