/* ============================================================
   HOME — styles specific to index.html
   (loaded after base.css)
   ============================================================ */

/* ============================================================
   HERO
   ============================================================ */
.hero{
  position:relative;
  padding:calc(100px + var(--space-7)) 0 var(--space-7);
  /* ---- Hero sky ---------------------------------------------------------
     Photograph by Lhar Capili on Unsplash (photo-1700975647766-29b1a71370ca),
     free under the Unsplash License. Cropped to rect 2200,0,3320,1844 of the
     5520x4140 original and served at 2880x1600 — the crop is baked into the
     file so cover/center needs no per-breakpoint nudging.

     The crop was chosen by measurement, not eye: white text over the frame was
     scored against the zone the hero type actually occupies at 1024/1280/1440/
     1680/1920/2560 and at phone widths. It holds 5.10-5.93:1 everywhere, against
     6.70:1 for the flat blue it replaces and 4.5:1 for WCAG AA. Cropping further
     left drops to 1.09:1 at 1440 where the type crosses the cloud, which is why
     the clouds sit hard against the left edge.

     No overlay — the source is already this saturated. The colour underneath is
     the image's own mean, so the swap is invisible while the file loads.

     To revert to the original flat blue:
       background:
         radial-gradient(ellipse 70% 60% at 0% 0%, rgba(0,0,0,0.06), transparent 70%),
         radial-gradient(ellipse 70% 60% at 100% 0%, rgba(0,0,0,0.06), transparent 70%),
         #1D4ED8;
     --------------------------------------------------------------------- */
  background-color:#214E9B;
  background-image:url('../images/Hero Image/hero-sky.jpg');
  background-size:cover;
  background-position:center;
  background-repeat:no-repeat;
  overflow:hidden;
}
.hero::after{
  content:'';position:absolute;left:0;right:0;bottom:0;height:160px;
  background:linear-gradient(to bottom, transparent, var(--bg-alt));
  pointer-events:none;
}
.availability-pill{
  display:inline-flex;align-items:center;gap:8px;
  padding:8px 16px;border:1px solid var(--border-strong);border-radius:var(--radius-pill);
  font-size:14px;font-weight:500;color:var(--ink-soft);
  margin-bottom:28px;background:#fff;
}
.hero-grid{display:flex;flex-direction:column;align-items:center;text-align:center;max-width:1200px;margin:0 auto;position:relative;z-index:1;}
.hero-eyebrow{margin-bottom:26px;color:rgba(255,255,255,0.78);}
.hero-headline{margin-bottom:28px;max-width:1200px;color:#fff;}
.hero-body{font-size:16px;line-height:1.65;max-width:660px;margin:0 auto 44px;color:rgba(255,255,255,0.89);}
.hero-ctas{display:flex;gap:14px;flex-wrap:wrap;justify-content:center;}
.hero-ctas .btn-primary{background:#fff;color:var(--accent);}
.hero-ctas .btn-primary:hover{background:#fff;color:var(--accent-dark);transform:translateY(-1px);box-shadow:0 10px 24px -8px rgba(11,12,13,0.35);}
.hero-ctas .btn-secondary{background:transparent;border:1.5px solid rgba(255,255,255,0.4);color:#fff;}
.hero-ctas .btn-secondary:hover{background:rgba(255,255,255,0.08);border-color:#fff;color:#fff;transform:translateY(-1px);}
/* mobile — the shared .h1 clamp bottoms out at 48px, which pushes this
   headline to ~5 lines on a phone. Scale it down from the breakpoint (the
   curve meets the desktop size at 860px, so there's no jump) and drop the
   hardcoded <br> so the text reflows instead of breaking twice. Scoped to
   .hero-headline, so every other h1 on the site keeps the shared scale. */
@media (max-width:860px){
  /* the 100px term clears the sticky nav; the rest is the gap below it, which
     on a phone left the pill stranded. 120px -> 60px, bottom padding kept. */
  .hero{padding-top:calc(100px + 60px);}

  .hero-headline{font-size:clamp(30px, 12px + 7vw, 66px);}
  .hero-headline br{display:none;}

  /* hero CTAs stack full-bleed within the container gutter. .hero-grid
     centres its children, so the row has to opt out of that with
     align-self:stretch before the buttons can fill it. */
  .hero-ctas{align-self:stretch;flex-direction:column;}
  .hero-ctas .btn{width:100%;justify-content:center;}
}

/* ============================================================
   TRUSTED BY — client social proof

   Sits on the same --bg-alt surface the hero fades down into. Its
   padding, head and head-to-content gap are the page's standard section
   rhythm: --space-7 top and bottom like every other section, so the
   240px gap to the next one matches the rest of the page, and a shared
   .section-head carrying .eyebrow + .h2 so the heading has the same
   authority as "Recent projects.".
   ============================================================ */
.trust-section{padding:var(--space-7) 0;background:var(--bg-alt);}
/* the shared head, centred over the logo row; everything else about it —
   eyebrow scale, .h2 scale, its --space-5 bottom margin — is inherited */
.trust-section .section-head{max-width:820px;margin-left:auto;margin-right:auto;text-align:center;}
.trust-logos{
  --logo-scale:1;
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:clamp(34px,4.4vw,58px);
  /* collapses against .section-head's 56px, so the head-to-logos gap
     resolves to 80px — the same figure .work-list uses */
  margin-top:var(--space-6);
}
/* One treatment for six marks that arrive in three different colour
   schemes (Andela is black artwork, Dévorer/Purse/Triton white, Taste
   and Odoakpu are two-colour rasters): brightness(0) collapses each to
   solid ink over its own alpha, and the opacity holds them at roughly
   --ink-soft so they sit under the Locus type rather than over it. */
.trust-logo img{
  width:calc(var(--logo-w) * var(--logo-scale) * 1px);
  max-width:100%;height:auto;
  filter:brightness(0);
  opacity:.62;
  transition:opacity var(--dur-sm) var(--ease);
}
.trust-logo:hover img{opacity:.92;}
/* Per-logo widths, not a shared height: the source files differ in
   aspect from 2.19 (Triton, a stacked lockup) to 5.66 (Taste, a wide
   wordmark), so a single height would leave the wide marks huge and
   the stacked one tiny. Each width below is derived from that logo's
   trimmed content box so the six carry the same optical weight, then
   nudged for stroke weight — Dévorer is ultra-bold and reads heavier
   than its box, Andela's serif lighter. Height stays auto throughout,
   so no mark can be stretched. */
.trust-logo-andela{--logo-w:110;}
.trust-logo-triton{--logo-w:76;}
.trust-logo-purse{--logo-w:87;}
.trust-logo-devorer{--logo-w:82;}
.trust-logo-taste{--logo-w:115;}
.trust-logo-odoakpu{--logo-w:110;}
.trust-more{font-size:15px;color:var(--ink-faint);}

/* Below ~1180px the six no longer hold one comfortable row, so they
   move to a grid — 3 up, then 2 up — with "and many more" spanning
   the full width underneath, keeping the composition centred. */
@media (max-width:1180px){
  .trust-logos{
    display:grid;grid-template-columns:repeat(3,1fr);justify-items:center;
    row-gap:clamp(36px,5vw,52px);
  }
  .trust-more{grid-column:1 / -1;}
}
/* the hard break in the heading balances its two lines while the type is
   large; below this it is small enough that a natural wrap over the full
   measure reads better, the same trade .hero-headline makes. */
@media (max-width:860px){
  .trust-section .section-head br{display:none;}
}
/* mobile — these two sections both sit on --bg-alt, so the standard
   120px + 120px section boundary between them reads as one uninterrupted
   void rather than a break; on a phone that is roughly a third of the
   viewport. Elsewhere on the page the backgrounds alternate and the same
   figures land correctly, so this is scoped to the one seam that needs it
   and stays on the spacing scale: 56px below "and many more", 80px of
   breathing room above the Featured Work eyebrow, 136px in total. */
@media (max-width:700px){
  .trust-section{padding-bottom:var(--space-5);}
  .gallery-section{padding-top:var(--space-6);}
}
@media (max-width:700px){
  .trust-logos{
    --logo-scale:.92;
    grid-template-columns:repeat(2,1fr);
    column-gap:clamp(24px,6vw,40px);
    row-gap:clamp(32px,8vw,44px);
  }
}

/* ============================================================
   CAPABILITY GALLERY
   ============================================================ */
.gallery-section{padding:var(--space-7) 0; background:var(--bg-alt); overflow:hidden;}
.section-head{max-width:640px;margin-bottom:var(--space-5);}
/* wider than the shared 640px cap so the headline holds its two-line
   break instead of spilling onto a third line — Showcase only */
.gallery-section .section-head{max-width:880px;}
.gallery-track-wrap{overflow:hidden;position:relative;margin-top:var(--space-4);}
.gallery-track{display:flex;gap:28px;width:max-content;padding:4px 0;}
.gallery-card{
  height:clamp(340px,34vw,540px);flex-shrink:0;border-radius:26px;overflow:hidden;
}
.gallery-card img{display:block;height:100%;width:auto;max-width:none;object-fit:cover;}
@media (max-width:640px){.gallery-card{height:260px;}}

/* mock composition primitives — homepage sizing (gallery cards
   and work-feature thumbs use a more compact scale than the
   case study pages, see assets/css/case-study.css) */
.mock-card{background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.12);border-radius:8px;padding:10px;width:100%;}
.mock-card.light{background:#fff;border-color:rgba(11,12,13,0.08);}
.mock-line{height:6px;border-radius:3px;background:rgba(255,255,255,0.18);margin-bottom:6px;}
.mock-line.light{background:rgba(11,12,13,0.1);}
.mock-line.short{width:40%;}
.mock-bars{display:flex;gap:4px;align-items:flex-end;height:44px;margin-top:8px;}
.mock-bars i{flex:1;background:var(--accent);border-radius:2px;}

/* ============================================================
   SELECTED WORK — editorial, one project per row
   ============================================================ */
.work-section{padding:var(--space-7) 0;}
.work-list{margin-top:var(--space-6);}
.work-feature{margin-bottom:var(--space-7);}
.work-feature:last-of-type{margin-bottom:var(--space-6);}
.work-feature-link{
  display:block;border-radius:var(--radius-lg);
}
/* every work card shares one frame ratio, declared here rather than per
   card, so all four thumbs resolve to the same height at any viewport and
   the column reads as one system. The .media-frame class in the markup
   consumes this (see base.css); the fixed height below is the fallback for
   any card not using the frame. */
.work-feature-thumb{
  --media-ratio:8/5;
  height:min(70vh,640px);min-height:420px;position:relative;overflow:hidden;border-radius:var(--radius-lg);
}
.work-feature-thumb .thumb-inner{transition:transform .7s var(--ease);}
/* real project artwork — contain keeps the full mockup visible at every
   breakpoint; the card's gradient shows through as the surround */
.work-feature-media{display:block;width:100%;height:100%;object-fit:contain;object-position:center;}
.work-feature-link:hover .thumb-inner{transform:scale(1.035);}
.work-feature-info{
  display:flex;justify-content:space-between;align-items:flex-end;flex-wrap:wrap;gap:20px;
  padding:28px 4px 0;
}
.work-feature-info .cat{font-size:13px;color:var(--ink-faint);letter-spacing:.05em;text-transform:uppercase;margin-bottom:10px;}
.work-feature-info .title{font-family:var(--font-display);font-size:clamp(28px,3.4vw,48px);font-weight:900;line-height:0.96;letter-spacing:-0.03em;margin-bottom:10px;}
.work-feature-info .desc{font-size:16px;color:var(--ink-soft);max-width:440px;}
.view-case{
  display:inline-flex;align-items:center;gap:10px;font-size:16px;font-weight:600;color:var(--ink);
  padding-bottom:2px;flex-shrink:0;
  transition:color var(--dur-sm) var(--ease);
}
.view-case svg{transition:transform var(--dur-sm) var(--ease);}
.work-feature-link:hover .view-case{color:var(--accent);}
.work-feature-link:hover .view-case svg{transform:translate(3px,-3px);}
@media (max-width:860px){.work-feature-thumb{height:320px;min-height:320px;}}

.work-cta-row{display:flex;justify-content:center;margin-top:var(--space-6);}

/* ============================================================
   THE STANDARD WE DESIGN TO — editorial reference list.

   Dark, because on this page dark is already the language of the
   statement moments (process, testimonial, contact panel) rather
   than a new visual register. It also punctuates the light
   work -> services run without two adjacent tones merging.

   The row is deliberately the .service-row pattern — CSS grid,
   hairline rule, same 36px rhythm — so it reads as native to the
   page. Type and rules only: no logos, cards or gradients.
   ============================================================ */
.standards-section{padding:var(--space-7) 0;background:var(--dark-bg);color:var(--dark-text);}
.standards-section .eyebrow{color:var(--dark-text-soft);}
.standards-section .h2{color:var(--dark-text);}
.standards-section p{color:var(--dark-text-soft);}
.standards-head{max-width:760px;}
.standards-lead{margin-top:20px;max-width:640px;}

/* 4 x 2. margin-bottom on .section-head (56px) collapses against this 80px,
   so the head-to-grid gap resolves to 80px, not 136px. Row gap matches
   .why-grid's 32px so the vertical rhythm is the page's, not a new one. */
.standards-grid{
  display:grid;grid-template-columns:repeat(4,1fr);gap:32px 28px;
  margin-top:var(--space-6);
}
/* each cell carries its own hairline — the .why-card pattern, same 32px
   top padding. It survives any column count, so the rules stay deliberate
   as the grid rewraps, which vertical dividers would not. */
.standard-item{padding:var(--space-4) 4px 0;border-top:1px solid var(--dark-border);}

/* mark and name are one line — the mark anchors, the name identifies.
   19px display is .why-title's exact cut, so these read as siblings of the
   other section subheads rather than as a new type size. */
.standard-name{
  display:flex;align-items:center;gap:11px;
  font-family:var(--font-display);font-size:19px;font-weight:700;
  line-height:1.2;letter-spacing:-0.015em;color:var(--dark-text);
}
.standard-logo{
  display:flex;align-items:center;flex-shrink:0;height:var(--logo-h,20px);
  color:var(--dark-text-soft);
  transition:color var(--dur-sm) var(--ease);
}
/* height fixed, width auto — these marks have different aspect ratios and
   forcing them to a common box would distort them (same rule the footer
   social marks use). currentColor keeps every mark monochrome, so no
   brand palette breaks the section's two-tone scheme. */
.standard-logo svg{display:block;height:100%;width:auto;fill:currentColor;}
/* optical balance, not uniform measurement: the Vercel triangle reads far
   larger than its box while the Stripe and Figma marks read smaller, so a
   single height would leave the row visually uneven */
.logo-stripe{--logo-h:21px;}
.logo-linear{--logo-h:19px;}
.logo-vercel{--logo-h:16px;}
.logo-figma{--logo-h:21px;}
.logo-framer{--logo-h:19px;}
.logo-airbnb{--logo-h:20px;}
.logo-apple{--logo-h:21px;}
.logo-notion{--logo-h:19px;}

/* 15px matches .service-positioning / .pricing-desc — the page's standing
   size for a supporting line under a name */
.standard-descriptor{font-size:15px;line-height:1.55;margin-top:12px;transition:color var(--dur-sm) var(--ease);}
/* restrained, in the .service-row:hover idiom — the mark and its line
   brighten; nothing lifts, scales or glows */
.standard-item:hover .standard-logo{color:var(--dark-text);}
.standard-item:hover .standard-descriptor{color:var(--dark-text);}

@media (max-width:900px){.standards-grid{grid-template-columns:repeat(2,1fr);}}
/* single column reads as a continuous list, so the rules butt together and
   each item needs its own closing space */
@media (max-width:560px){
  .standards-grid{grid-template-columns:1fr;gap:0;}
  .standard-item{padding:var(--space-3) 4px var(--space-3);}
}

/* ============================================================
   SERVICES
   ============================================================ */
.services-section{padding:var(--space-7) 0;background:var(--bg-alt);}
.service-row{
  display:grid;grid-template-columns:1.3fr 1fr;gap:40px;align-items:start;
  padding:36px 0;border-top:1px solid var(--border);
}
.service-row:last-of-type{border-bottom:1px solid var(--border);}
/* service icons — Phosphor Icons, duotone weight (MIT), inlined as SVG so
   they inherit currentColor; no runtime library or build step is added.
   Each mark is two paths on Phosphor's 256 grid: a backdrop held at low
   opacity plus the solid figure, which is where the depth comes from —
   the tone is monochrome --ink throughout, no second hue.

   The frame is deliberately unfilled: a hairline in the same --border the
   service rows are already ruled with, so the icon reads as framed rather
   than sitting in a button, and the section's own background shows through.
   Fixed 48px square with the icon centred, so every row's mark lands on
   exactly the same footprint whatever its silhouette. */
.service-icon-wrap{
  display:flex;align-items:center;justify-content:center;
  width:48px;height:48px;margin-bottom:18px;
  background:transparent;
  border:1px solid var(--border);
  border-radius:var(--radius-md);
  transition:border-color var(--dur-sm) var(--ease);
}
.service-row:hover .service-icon-wrap{border-color:var(--border-strong);}
.service-icon{
  display:block;width:26px;height:26px;
  color:var(--ink);
  fill:currentColor;
  transition:color var(--dur-sm) var(--ease);
}
.service-icon-dt{opacity:.22;}
.service-row:hover .service-icon{color:var(--accent);}
.service-name{font-family:var(--font-display);font-size:23px;font-weight:700;letter-spacing:-0.015em;}
.service-price{font-size:15px;color:var(--ink-faint);margin-top:6px;}
.service-positioning{font-size:15px;color:var(--ink-soft);margin-top:12px;max-width:400px;line-height:1.6;}
/* The row is a grid with align-items:start, so the left column keeps its
   top-to-bottom flow; align-self overrides that for this column alone,
   centring the list against the row's full content height. Grid measures
   both columns itself, so this stays correct as bullet counts and
   description lengths change, with no offset to maintain.

   Below 860px the grid collapses to one column, where each item gets its
   own content-height track — align-self resolves to no movement there, so
   the existing mobile stacking is untouched.

   (The former padding-top:2px was an optical nudge for top alignment; it
   would now push the list a pixel below true centre.) */
.service-deliverables{display:flex;flex-direction:column;gap:9px;align-self:center;}
.service-deliverables span{font-size:14px;color:var(--ink-soft);position:relative;padding-left:16px;transition:color var(--dur-sm) var(--ease);}
.service-deliverables span::before{content:'';position:absolute;left:0;top:8px;width:5px;height:5px;border-radius:50%;background:var(--accent);}
.service-row:hover .service-deliverables span{color:var(--ink);}
@media (max-width:860px){.service-row{grid-template-columns:1fr;gap:16px;}}

.custom-engagement{
  margin-top:32px;padding:36px;border-radius:var(--radius-lg);border:1px solid var(--border-strong);
  display:flex;justify-content:space-between;align-items:center;gap:24px;flex-wrap:wrap;background:#fff;
}
.custom-engagement p{max-width:420px;}

/* ============================================================
   PROCESS (scroll-linked)
   ============================================================ */
.process-section{padding:var(--space-7) 0;background:var(--dark-bg);color:var(--dark-text);}
.process-section .eyebrow{color:var(--dark-text-soft);}
.process-section .h2{color:var(--dark-text);}
.process-section p{color:var(--dark-text-soft);}
.process-inner{margin-top:var(--space-5);display:grid;grid-template-columns:0.9fr 1.1fr;gap:80px;}
.process-list{position:sticky;top:130px;align-self:start;}
.process-item{
  display:flex;gap:20px;padding:20px 0;border-top:1px solid var(--dark-border);cursor:pointer;
}
.process-item:last-child{border-bottom:1px solid var(--dark-border);}
.process-num{font-size:14px;color:var(--dark-text-soft);font-weight:600;padding-top:2px;}
.process-item.active .process-num{color:var(--accent);}
.process-title{font-size:19px;font-weight:600;color:var(--dark-text-soft);transition:color var(--dur-sm) var(--ease);}
.process-item.active .process-title{color:var(--dark-text);}
.process-desc{
  font-size:15px;color:var(--dark-text-soft);max-height:0;overflow:hidden;opacity:0;
  transition:max-height .4s var(--ease), opacity .4s var(--ease), margin .4s var(--ease);
}
.process-item.active .process-desc{max-height:100px;opacity:1;margin-top:8px;}
.process-track{position:relative;padding-left:0;}
.process-progress-rail{position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--dark-border);}
.process-progress-fill{position:absolute;left:0;top:0;width:2px;background:var(--accent);height:0%;transition:height .1s linear;}
.process-visual-stack{padding-left:28px;}
.process-visual{
  height:420px;border-radius:var(--radius-lg);border:1px solid var(--dark-border);
  background:var(--dark-bg-alt);display:flex;align-items:center;justify-content:center;
  position:sticky;top:130px;overflow:hidden;
}
.process-visual .stage-num{font-size:120px;font-weight:800;color:rgba(255,255,255,0.06);letter-spacing:-.04em;transition:opacity .3s;}
@media (max-width:900px){
  .process-inner{grid-template-columns:1fr;gap:40px;}
  .process-list{position:static;}
  .process-visual{position:static;height:280px;}
}

/* ============================================================
   WHY LOCUS
   ============================================================ */
.why-section{padding:var(--space-7) 0;}
.why-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:32px;margin-top:var(--space-5);}
.why-card{padding:32px 4px;border-top:1px solid var(--border);}
.why-num{font-size:13px;color:var(--ink-faint);margin-bottom:16px;}
.why-title{font-family:var(--font-display);font-size:19px;font-weight:700;margin-bottom:10px;letter-spacing:-0.015em;}
@media (max-width:860px){.why-grid{grid-template-columns:1fr;}}

/* ============================================================
   RETAINERS
   ============================================================ */
.retainer-section{padding:var(--space-7) 0;background:var(--bg-alt);}
.pricing-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;margin-top:var(--space-5);}
.pricing-card{
  background:#fff;border:1px solid var(--border);border-radius:var(--radius-lg);
  padding:34px 28px;display:flex;flex-direction:column;gap:20px;
  transition:border-color var(--dur-sm) var(--ease), transform var(--dur-sm) var(--ease), box-shadow var(--dur-sm) var(--ease);
}
.pricing-card:hover{border-color:var(--border-strong);transform:translateY(-4px);box-shadow:0 24px 50px -30px rgba(11,12,13,0.25);}
.pricing-card.featured{border-color:var(--accent);position:relative;}
.pricing-badge{
  position:absolute;top:0;left:50%;transform:translate(-50%,-50%);
  font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  color:#fff;background:var(--accent);border-radius:var(--radius-pill);
  padding:5px 14px;white-space:nowrap;
}
.pricing-tier{font-size:14px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-faint);}
.pricing-amount{font-size:32px;font-weight:800;letter-spacing:-0.02em;}
.pricing-amount span{font-size:15px;font-weight:400;color:var(--ink-faint);}
.pricing-desc{font-size:15px;color:var(--ink-soft);}
.pricing-includes{display:flex;flex-direction:column;gap:8px;margin:4px 0;}
.pricing-includes span{font-size:14px;color:var(--ink-soft);padding-left:16px;position:relative;}
.pricing-includes span::before{content:'';position:absolute;left:0;top:8px;width:5px;height:5px;border-radius:50%;background:var(--accent);}
.pricing-card .btn{margin-top:auto;justify-content:center;}
@media (max-width:900px){.pricing-grid{grid-template-columns:1fr;}}

/* ============================================================
   TESTIMONIAL
   ============================================================ */
.testimonial-section{
  padding:var(--space-8) 0;background:var(--dark-bg);color:var(--dark-text);text-align:center;
}
.testimonial-quote{
  font-family:var(--font-display);font-weight:700;letter-spacing:-0.025em;
  font-size:clamp(24px,3.4vw,42px);line-height:1.3;max-width:920px;margin:0 auto var(--space-4);
}
.testimonial-attr{font-size:16px;color:var(--dark-text-soft);display:flex;align-items:center;justify-content:center;gap:12px;}
.testimonial-avatar{
  width:44px;height:44px;flex-shrink:0;border-radius:50%;
  object-fit:cover;border:1px solid var(--dark-border);
}
.testimonial-attr strong{color:var(--dark-text);font-weight:600;}
/* mobile — avatar and text stay one horizontal group, centred as a unit.
   The row direction, align-items:center and justify-content:center all
   come from the base rule, so nothing about the arrangement is restated
   here: the avatar keeps sitting beside the text and centred against it,
   and the group as a whole stays centred in the section.

   What does change is the text block. The role drops onto its own line
   under the name, .testimonial-sep removes the comma that joins them on
   one line at desktop, and text-align:left overrides the section's
   centring so the two lines range against each other rather than each
   centring on its own width. Desktop is untouched. */
@media (max-width:640px){
  .testimonial-attr{gap:14px;line-height:1.55;text-align:left;}
  .testimonial-sep{display:none;}
  .testimonial-role{display:block;}
}

/* ============================================================
   LOCUS FIELD (signature)
   ============================================================ */
.field-section{padding:var(--space-7) 0;overflow:hidden;}
.field-grid{display:grid;grid-template-columns:1fr 1fr;gap:60px;align-items:center;}
.field-canvas-wrap{
  position:relative;height:440px;border-radius:var(--radius-lg);border:1px solid var(--dark-border);
  background:radial-gradient(120% 100% at 50% 0%, #10141F 0%, var(--dark-bg) 62%);overflow:hidden;
}
#fieldCanvas{width:100%;height:100%;display:block;}
@media (max-width:900px){.field-grid{grid-template-columns:1fr;} .field-canvas-wrap{height:320px;order:-1;}}

/* ============================================================
   FAQ
   ============================================================ */
.faq-section{padding:var(--space-7) 0;background:var(--bg-alt);}
.faq-list{margin-top:var(--space-5);max-width:820px;}
.faq-item{border-top:1px solid var(--border);}
.faq-item:last-child{border-bottom:1px solid var(--border);}
.faq-q{
  width:100%;display:flex;justify-content:space-between;align-items:center;gap:20px;
  padding:26px 4px;font-size:18px;font-weight:600;text-align:left;letter-spacing:-0.01em;
  transition:color var(--dur-sm) var(--ease);
}
.faq-q:hover{color:var(--accent);}
.faq-icon{width:22px;height:22px;position:relative;flex-shrink:0;}
.faq-icon::before,.faq-icon::after{
  content:'';position:absolute;background:currentColor;top:50%;left:50%;transform:translate(-50%,-50%) rotate(0deg);
  transition:transform .35s var(--ease);
}
.faq-icon::before{width:14px;height:1.6px;}
.faq-icon::after{width:1.6px;height:14px;}
.faq-q[aria-expanded="true"] .faq-icon::before{transform:translate(-50%,-50%) rotate(180deg);}
.faq-q[aria-expanded="true"] .faq-icon::after{transform:translate(-50%,-50%) rotate(90deg);}
.faq-a{max-height:0;overflow:hidden;transition:max-height .45s var(--ease);}
.faq-a p{padding:0 4px 26px;max-width:640px;}

/* ============================================================
   CONTACT
   ============================================================ */
.contact-section{padding:var(--space-7) 0;}
.contact-panel{
  background:var(--dark-bg);color:var(--dark-text);border-radius:var(--radius-lg);
  padding:var(--space-6) var(--gutter);
  background-image:radial-gradient(900px 400px at 90% 0%, rgba(41,126,255,0.22), transparent 60%);
}
.contact-grid{display:grid;grid-template-columns:0.9fr 1.1fr;gap:64px;}
.contact-panel .h2{color:var(--dark-text);}
/* Contact heading line breaks — intentional, not a by-product of how the
   column happens to resolve. Each phrase is its own block box (so the break
   is fixed) and unbreakable (so a narrow column can't wrap one of them into
   a fourth line). The grid is untouched.

   1200px, not the 900px grid breakpoint: the widest phrase, "something
   worth", measures 434.8px at the 64px cap, and the column only clears that
   above ~1092px. Holding the break below that would overflow the column
   instead of wrapping. Under 1200px the spans fall back to inline and the
   heading wraps naturally, as it did before. */
@media (min-width:1200px){
  .contact-heading span{display:block;white-space:nowrap;}
}
.contact-panel p{color:var(--dark-text-soft);}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-bottom:20px;}
.field label{display:block;font-size:14px;font-weight:500;color:var(--dark-text-soft);margin-bottom:10px;}
.field input, .field select, .field textarea{
  width:100%;background:rgba(255,255,255,0.06);border:1.5px solid var(--dark-border);
  border-radius:var(--radius-sm);padding:15px 16px;font-size:16px;font-weight:400;color:var(--dark-text);
  color-scheme:dark;
  font-family:inherit;transition:border-color var(--dur-sm) var(--ease), background var(--dur-sm) var(--ease);
}
.field input::placeholder, .field textarea::placeholder{color:rgba(243,243,241,0.4);font-size:16px;font-weight:400;}
.field input:hover, .field select:hover, .field textarea:hover{border-color:rgba(255,255,255,0.28);}
.field input:focus, .field select:focus, .field textarea:focus{border-color:var(--accent);outline:none;background:rgba(255,255,255,0.09);}
.field{margin-bottom:20px;}
.field select{
  appearance:none;cursor:pointer;
  background-color:rgba(255,255,255,0.06);
  background-image:url('../icons/chevron-down.svg');
  background-repeat:no-repeat;background-position:right 16px center;padding-right:40px;
}
.field select option{background:#fff;color:var(--ink);}
textarea{resize:vertical;min-height:120px;}
@media (max-width:900px){.contact-grid{grid-template-columns:1fr;} .form-row{grid-template-columns:1fr;}}
/* mobile spacing only — home.css doesn't load on the case-study pages, so the
   shared .site-footer rule stays as-is everywhere else.
   pill -> first field: the 64px column gap reads as a stacked gap once the
   grid is one column, and the pill's own 28px trailing margin sits on top of
   it. 92px -> 28px, taking the trailing margin off the dark pill only.
   card -> footer: 120px + 120px of section padding -> 56px + 80px. */
@media (max-width:860px){
  .contact-grid{gap:28px;}
  .contact-panel .availability-pill{margin-bottom:0;}
  .contact-section{padding-bottom:var(--space-5);}
  .site-footer{padding-top:var(--space-6);}
}

/* ============================================================
   CONTACT FORM STATES — submit button while sending, and the
   inline error line under it. Both sit inside the dark contact
   panel, so they read against --dark-bg.
   ============================================================ */
.btn[data-loading="true"]{opacity:.72;cursor:progress;}
.btn[data-loading="true"]:hover{transform:none;box-shadow:none;background:var(--accent);}
.btn-spinner{
  width:14px;height:14px;flex-shrink:0;border-radius:50%;
  border:1.8px solid rgba(255,255,255,0.35);border-top-color:#fff;
  animation:btn-spin .7s linear infinite;
}
@keyframes btn-spin{to{transform:rotate(360deg);}}
@media (prefers-reduced-motion: reduce){.btn-spinner{animation:none;}}

.form-error{
  margin-top:14px;font-size:14px;line-height:1.5;color:#FF8A8A;
}

/* ============================================================
   ENQUIRY SENT MODAL
   ============================================================ */
.enquiry-modal{position:fixed;inset:0;z-index:200;display:flex;align-items:center;justify-content:center;padding:var(--gutter);}
.enquiry-modal[hidden]{display:none;}
.enquiry-modal-backdrop{
  position:absolute;inset:0;background:rgba(11,12,13,0.58);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  opacity:0;transition:opacity var(--dur-sm) var(--ease);
}
.enquiry-modal-card{
  position:relative;width:100%;max-width:460px;
  background:var(--dark-bg);color:var(--dark-text);
  background-image:radial-gradient(700px 320px at 85% 0%, rgba(41,126,255,0.24), transparent 62%);
  border:1px solid var(--dark-border);border-radius:var(--radius-lg);
  padding:var(--space-5) var(--space-4) var(--space-4);
  box-shadow:0 40px 90px -30px rgba(0,0,0,0.6);
  opacity:0;transform:translateY(14px) scale(.98);
  transition:opacity var(--dur-sm) var(--ease), transform var(--dur-sm) var(--ease);
}
.enquiry-modal.is-open .enquiry-modal-backdrop{opacity:1;}
.enquiry-modal.is-open .enquiry-modal-card{opacity:1;transform:none;}
.enquiry-modal-card .h3{color:var(--dark-text);}
.enquiry-modal-card p{margin-top:14px;color:var(--dark-text-soft);}
.enquiry-modal-mark{
  display:flex;align-items:center;justify-content:center;
  width:46px;height:46px;margin-bottom:var(--space-3);
  border-radius:50%;color:var(--green);
  background:rgba(53,196,106,0.12);border:1px solid rgba(53,196,106,0.32);
}
.enquiry-modal-close{
  position:absolute;top:18px;right:18px;
  display:flex;align-items:center;justify-content:center;
  width:34px;height:34px;border-radius:50%;
  color:var(--dark-text-soft);border:1px solid var(--dark-border);
  transition:color var(--dur-sm) var(--ease), border-color var(--dur-sm) var(--ease), background var(--dur-sm) var(--ease);
}
.enquiry-modal-close:hover{color:var(--dark-text);border-color:rgba(255,255,255,0.28);background:rgba(255,255,255,0.06);}
.enquiry-modal-dismiss{margin-top:var(--space-4);width:100%;justify-content:center;}
@media (prefers-reduced-motion: reduce){
  .enquiry-modal-backdrop,.enquiry-modal-card{transition:none;}
}

/* misc */
.section-cta-center{display:flex;justify-content:center;margin-top:var(--space-5);}
