/* ===== packages/tokens/tokens.css ===== */
/* ============================================================================
   makeyoursite.in — design tokens
   ----------------------------------------------------------------------------
   SINGLE SOURCE OF TRUTH FOR COLOUR. Inlined into apps/web at build time and
   imported by apps/admin and apps/portal, so all three surfaces share one
   palette and dark mode works everywhere for free.

   Rules:
     - Nothing outside this file may hard-code a hex value except the four
       brand constants below.
     - Both themes must pass WCAG AA. Enforced by apps/web/scripts/contrast-audit.mjs
       which parses THIS file. Change a value here and CI re-checks every pair.
     - The two dark blocks below are intentionally duplicated (attribute-driven
       and media-driven). The audit script asserts they stay identical.
   ========================================================================== */

:root {
  /* --- brand constants: identical in both themes ------------------------- */
  --marigold-base: #f4b400;
  --marigold-deep: #b88200;
  --coral: #e4572e; /* mockup only */
  --wa: #25d366; /* WhatsApp green */

  /* --- light theme (also the no-JS default) ------------------------------ */
  --paper: #ffffff;
  --mist: #f3f5f8;
  --ink: #16213e;
  --ink-2: #2b3559;
  --on-ink: #ffffff;
  --text: #4a5165;
  --line: #e3e7ee;
  --panel: #16213e;
  --panel-text: #ffffff;
  --panel-muted: #b9c0d6;
  --panel-line: #3a4570;
  --sage: #d8e9df;
  --sage-deep: #2f6b4f;
  --marigold: #f4b400;
  /* WhatsApp green is 1.98:1 on white — unusable as text. This is the darkened
     variant used wherever the green must be readable rather than decorative. */
  --wa-text: #0b7a33;
  /* marigold-deep is only legible at display sizes (3.37:1). This is the
     variant for marigold text below 18.66px bold — dates, link hovers. */
  --marigold-text: #8a6200;
  /* coral is a mockup accent (3.68:1 as text). This is the readable variant
     used for validation errors, where legibility is the whole point. */
  --danger: #b33c1e;

  /* --- motion ------------------------------------------------------------ */
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);

  /* --- type -------------------------------------------------------------- */
  --display: 'Syne', 'Syne Fallback', system-ui, sans-serif;
  --body: 'DM Sans', 'DM Sans Fallback', system-ui, -apple-system, sans-serif;

  /* --- layout ------------------------------------------------------------ */
  --wrap: min(1120px, 92vw);
  --section-y: 88px;
  --nav-h: 64px;
  --tap: 48px; /* minimum touch target */
  --fab-clear: 92px; /* space reserved so the WhatsApp FAB never covers a control */
}

/* --- dark theme: explicit choice ----------------------------------------- */
[data-theme='dark'] {
  --paper: #0d1120;
  --mist: #161c2e;
  --ink: #e9edf9;
  --ink-2: #ffffff;
  --on-ink: #0d1120;
  --text: #9aa3be;
  --line: #262e47;
  --panel: #1e2540;
  --panel-text: #f1f4fc;
  --panel-muted: #98a1be;
  --panel-line: #333c5a;
  --sage: #1c3a2d;
  --sage-deep: #8ed6af;
  --marigold: #f7be1f;
  --wa-text: #4ade80;
  --marigold-text: #f7be1f;
  --danger: #ff8a6b;
}

/* --- dark theme: system preference, no stored choice, JS unavailable ------ */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --paper: #0d1120;
    --mist: #161c2e;
    --ink: #e9edf9;
    --ink-2: #ffffff;
    --on-ink: #0d1120;
    --text: #9aa3be;
    --line: #262e47;
    --panel: #1e2540;
    --panel-text: #f1f4fc;
    --panel-muted: #98a1be;
    --panel-line: #333c5a;
    --sage: #1c3a2d;
    --sage-deep: #8ed6af;
    --marigold: #f7be1f;
    --wa-text: #4ade80;
    --marigold-text: #f7be1f;
    --danger: #ff8a6b;
  }
}

/* --- colour-scheme so form controls, scrollbars and caret follow ---------- */
:root {
  color-scheme: light;
}
[data-theme='dark'] {
  color-scheme: dark;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    color-scheme: dark;
  }
}

/* ===== packages/tokens/fallback-fonts.css ===== */
/* Metric-adjusted local fallbacks. Without these the Syne/DM Sans swap shifts
   layout on 4G and tanks CLS. Values approximate the real font metrics so the
   fallback occupies near-identical space. Target CLS < 0.05. */
@font-face {
  font-family: 'Syne Fallback';
  src: local('Arial Bold'), local('Helvetica Bold'), local('Roboto');
  font-weight: 600 800;
  size-adjust: 105%;
  ascent-override: 95%;
  descent-override: 25%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'DM Sans Fallback';
  src: local('Arial'), local('Helvetica'), local('Roboto');
  font-weight: 400 600;
  size-adjust: 100%;
  ascent-override: 98%;
  descent-override: 30%;
  line-gap-override: 0%;
}

/* ===== styles/01-reset.css ===== */
/* ============================================================================
   01 · Reset and document defaults
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
  padding: 0;
}

html {
  scroll-behavior: smooth;
  /* Keeps anchored content clear of the sticky 64px nav. */
  scroll-padding-top: calc(var(--nav-h) + 16px);
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Never overflow-x:hidden on <body>: it silently breaks position:sticky in
     iOS Safari. Overflow is contained per-section instead (see .hero, .strip). */
  overflow-x: clip;
}

img,
svg,
video {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: inherit;
  text-decoration: none;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
}

ul,
ol {
  list-style: none;
}

table {
  border-collapse: collapse;
  width: 100%;
}

/* --- focus: visible, high contrast, never removed ------------------------ */
/* Two-tone by necessity. Marigold on white is 1.86:1, well under the 3:1 that
   WCAG 2.2 SC 1.4.11 requires of a focus indicator, so the marigold band hugs
   the element and an ink ring sits just outside it to carry the contrast
   against the page. It still reads as a marigold focus ring. */
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
  box-shadow: 0 0 0 3px var(--marigold);
  border-radius: 4px;
}
:focus:not(:focus-visible) {
  outline: none;
}

/* --- screen-reader only, still focusable when it needs to be ------------- */
.sr-only {
  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;
}

/* --- skip link ----------------------------------------------------------- */
.skip {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 200;
  background: var(--ink);
  color: var(--on-ink);
  padding: 12px 18px;
  border-radius: 999px;
  font-size: 14.5px;
  font-weight: 600;
  transition: top 0.2s var(--ease);
}
.skip:focus {
  top: 12px;
}

/* --- honeypot: off-screen, never announced, never focusable -------------- */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* --- the router hides inactive routes; JS-off shows the first one -------- */
.page[hidden] {
  display: none;
}

[hidden] {
  display: none !important;
}

/* ===== styles/02-typography.css ===== */
/* ============================================================================
   02 · Typography
   ----------------------------------------------------------------------------
   Syne for display, DM Sans for everything else. Sizes are fluid via clamp()
   so there is no jump between the 520 / 860 / 1040px breakpoints.
   ========================================================================== */

h1,
h2,
h3,
.logo,
.big,
.stat-n,
.plan-amt,
.step-n,
.admin-n,
.proj-initials,
.track {
  font-family: var(--display);
  letter-spacing: -0.025em;
  line-height: 1;
  font-weight: 800;
}

h1 {
  font-size: clamp(34px, 5.6vw, 76px);
  line-height: 0.98;
}

h2 {
  font-size: clamp(28px, 3.8vw, 50px);
  max-width: 16ch;
}

h3 {
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

p {
  line-height: 1.6;
}

b,
strong {
  font-weight: 600;
}

code {
  font-family: ui-monospace, 'SF Mono', 'Cascadia Mono', Menlo, monospace;
  font-size: 0.92em;
  background: var(--mist);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 1px 5px;
}

/* --- kicker: 22px rule, then the label ----------------------------------- */
.kicker {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--sage-deep);
  margin-bottom: 14px;
  line-height: 1.3;
}
.kicker::before {
  content: '';
  width: 22px;
  height: 2px;
  background: currentColor;
  flex: none;
}

/* --- supporting paragraph beside a heading ------------------------------- */
.sub {
  color: var(--text);
  font-size: 16.5px;
  line-height: 1.6;
  max-width: 44ch;
}

.fine {
  color: var(--text);
  font-size: 13.5px;
  line-height: 1.6;
  max-width: 68ch;
  margin-top: 22px;
}
.fine a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* --- long-form prose: privacy, terms, blog posts ------------------------- */
.prose {
  max-width: 70ch;
  color: var(--text);
  font-size: 16.5px;
}
.prose-wide {
  max-width: 76ch;
}
.prose h2 {
  font-size: clamp(21px, 2.2vw, 26px);
  max-width: none;
  color: var(--ink);
  margin: 38px 0 12px;
}
.prose h2:first-child {
  margin-top: 0;
}
.prose p {
  margin-bottom: 16px;
}
.prose p:last-child {
  margin-bottom: 0;
}
.prose ul {
  margin: 0 0 20px;
  display: grid;
  gap: 10px;
}
.prose li {
  padding-left: 22px;
  position: relative;
}
.prose li::before {
  content: '';
  position: absolute;
  left: 2px;
  top: 10px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--marigold);
}
.prose b {
  color: var(--ink);
  font-weight: 600;
}
.prose a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: var(--marigold);
  text-decoration-thickness: 2px;
}

.legal-updated {
  font-size: 13.5px;
  color: var(--text);
  margin-bottom: 30px;
  padding-bottom: 22px;
  border-bottom: 1px solid var(--line);
}

/* ===== styles/03-layout.css ===== */
/* ============================================================================
   03 · Layout primitives
   ========================================================================== */

.wrap {
  width: var(--wrap);
  margin-inline: auto;
}

.sec {
  padding: var(--section-y) 0;
}

/* First section on an inner route sits under the sticky nav. */
.sec-top {
  padding-top: 56px;
}

.sec-mist {
  background: var(--mist);
}

.sec-panel {
  background: var(--panel);
  color: var(--panel-text);
}
.sec-panel .kicker {
  color: var(--marigold);
}
.sec-panel .sub,
.sec-panel .fine {
  color: var(--panel-muted);
}
.sec-panel h1,
.sec-panel h2,
.sec-panel h3 {
  color: var(--panel-text);
}

/* --- section header: kicker + H2 left, one paragraph right --------------- */
.head {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  align-items: end;
}

.h2-solo {
  max-width: 16ch;
}
.sub-solo {
  margin-top: 14px;
}

/* --- page header on inner routes ----------------------------------------- */
.page-head {
  max-width: 46ch;
}
.page-head h1 {
  max-width: 15ch;
}
.page-lead {
  color: var(--text);
  font-size: clamp(16px, 1.3vw, 18px);
  line-height: 1.6;
  max-width: 46ch;
  margin-top: 20px;
}
.sec-panel .page-lead {
  color: var(--panel-muted);
}

/* Grids under a section header get consistent breathing room. */
.bento,
.steps,
.plans,
.proj-grid,
.quotes,
.svc-grid,
.notes-grid,
.stat-grid,
.team,
.posts,
.faq,
.admin-stats,
.contact-grid,
.table-scroll {
  margin-top: 52px;
}

.sec-more {
  margin-top: 40px;
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

/* --- closing band: heading + CTA side by side ---------------------------- */
.band {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 32px;
  align-items: center;
  padding: 38px;
  border: 1.5px solid var(--ink);
  border-radius: 22px;
  background: var(--paper);
}
.band h2 {
  font-size: clamp(24px, 2.8vw, 34px);
  max-width: 20ch;
}
.band .sub {
  margin-top: 10px;
  max-width: 52ch;
}
.band-tight {
  margin-top: 64px;
}

/* --- generic outline card ------------------------------------------------ */
.note-card {
  border: 1.5px solid var(--line);
  border-radius: 18px;
  padding: 26px;
  background: var(--paper);
}
.note-card h3 {
  font-size: 19px;
  margin-bottom: 10px;
}
.note-card p {
  color: var(--text);
  font-size: 14.5px;
}

.notes-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 14px;
}

/* --- initials avatar, shared by testimonials and the team row ------------ */
.avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--display);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.02em;
  flex: none;
}
.tone-sage {
  background: var(--sage);
  color: var(--sage-deep);
}
.tone-marigold {
  background: var(--marigold);
  color: #5a4200;
}
.tone-panel {
  background: var(--panel);
  color: var(--panel-text);
}
.tone-mist {
  background: var(--mist);
  color: var(--ink);
}

/* --- chips: outline tags naming real tech -------------------------------- */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-top: 14px;
}
.chips li {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px 11px;
}

/* ===== styles/04-buttons.css ===== */
/* ============================================================================
   04 · Buttons
   ----------------------------------------------------------------------------
   Every hover effect is wrapped in @media (hover: hover) and (pointer: fine).
   On Android Chrome a tap applies :hover and it *stays* applied until the user
   taps elsewhere, so an unguarded hover-lift leaves buttons visibly stuck.
   Touch gets :active feedback instead.
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 12px 20px;
  min-height: 44px;
  border-radius: 999px;
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  border: 1.5px solid transparent;
  transition:
    transform 0.2s var(--ease),
    background-color 0.2s var(--ease),
    color 0.2s var(--ease),
    border-color 0.2s var(--ease),
    box-shadow 0.2s var(--ease);
}

.btn .arr {
  display: inline-block;
  transition: transform 0.25s var(--ease);
}

.btn:active {
  transform: scale(0.97);
}

/* --- variants ------------------------------------------------------------ */
.btn-ink {
  background: var(--ink);
  color: var(--on-ink);
  border-color: var(--ink);
}

.btn-gold {
  background: var(--marigold);
  color: #16213e; /* fixed navy: marigold is a brand constant in both themes */
  border-color: var(--marigold);
}

.btn-ghost {
  border-color: var(--ink);
  color: var(--ink);
}

/* For panel (inverted) sections. */
.btn-out {
  border-color: var(--panel-text);
  color: var(--panel-text);
}

.btn-wa {
  background: var(--wa);
  color: #05341a;
  border-color: var(--wa);
}

.form-submit {
  width: 100%;
}

/* --- hover: pointer devices only ----------------------------------------- */
@media (hover: hover) and (pointer: fine) {
  .btn:hover {
    transform: translateY(-2px);
  }
  .btn:hover .arr {
    transform: translateX(4px);
  }
  .btn-ink:hover {
    background: var(--ink-2);
    border-color: var(--ink-2);
    box-shadow: 0 10px 24px rgb(22 33 62 / 0.22);
  }
  .btn-gold:hover {
    background: #ffc21f;
    border-color: #ffc21f;
    box-shadow: 0 10px 24px rgb(244 180 0 / 0.35);
  }
  .btn-ghost:hover {
    background: var(--ink);
    color: var(--on-ink);
    box-shadow: 0 10px 24px rgb(22 33 62 / 0.18);
  }
  .btn-out:hover {
    background: var(--panel-text);
    color: var(--panel);
  }
  .btn-wa:hover {
    background: #1fbe5b;
    border-color: #1fbe5b;
    box-shadow: 0 10px 24px rgb(37 211 102 / 0.35);
  }
}

/* --- touch: 48px minimum target, per Android accessibility guidance ------ */
@media (pointer: coarse) {
  .btn {
    min-height: var(--tap);
    padding: 13px 22px;
  }
}

/* ===== styles/05-forms.css ===== */
/* ============================================================================
   05 · Forms
   ----------------------------------------------------------------------------
   Font size is 16px on every field. Anything smaller makes iOS Safari zoom the
   viewport the moment a field is focused, which yanks the layout sideways
   mid-typing. This is the single most common mobile form bug and it is
   invisible on a desktop browser.
   ========================================================================== */

.field {
  display: grid;
  gap: 7px;
}

.field label {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.field label .opt {
  font-weight: 400;
  color: var(--text);
}

input[type='text'],
input[type='tel'],
input[type='email'],
select,
textarea {
  width: 100%;
  font-size: 16px;
  padding: 13px 16px;
  min-height: var(--tap);
  border: 1.5px solid var(--line);
  border-radius: 12px;
  background: var(--paper);
  color: var(--ink);
  transition:
    border-color 0.2s var(--ease),
    box-shadow 0.2s var(--ease);
}

textarea {
  border-radius: 14px;
  resize: vertical;
  min-height: 108px;
  line-height: 1.55;
}

select {
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - 21px) calc(50% + 2px),
    calc(100% - 15px) calc(50% + 2px);
  background-size:
    6px 6px,
    6px 6px;
  background-repeat: no-repeat;
  padding-right: 42px;
}

input::placeholder,
textarea::placeholder {
  color: var(--text);
  opacity: 0.75;
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 4px rgb(244 180 0 / 0.3);
}

/* Keyboard users get the same two-tone ring as every other control; the ink
   outline carries the 3:1 the marigold band cannot. */
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  box-shadow: 0 0 0 3px var(--marigold);
}

/* --- invalid state, applied by JS after a failed submit ------------------ */
.field.is-invalid input,
.field.is-invalid select,
.field.is-invalid textarea {
  border-color: var(--danger);
}

.field-error,
.form-error {
  color: var(--danger);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.45;
}
.field-error:empty,
.form-error:empty {
  display: none;
}

/* --- consent checkbox ---------------------------------------------------- */
.field-check {
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: 11px;
  margin-top: 4px;
}
.field-check input {
  width: 20px;
  height: 20px;
  min-height: 0;
  margin-top: 2px;
  accent-color: var(--marigold);
}
.field-check label {
  font-size: 13.5px;
  font-weight: 400;
  color: var(--text);
  line-height: 1.5;
}

/* --- inline quick form in the final CTA ---------------------------------- */
.quick-form {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  max-width: 760px;
  margin-top: 32px;
}
.quick-form .field {
  flex: 1 1 220px;
}
.quick-form input {
  border-radius: 999px;
  padding: 15px 20px;
}
.quick-form .btn {
  flex: none;
}
.quick-form .form-error {
  flex-basis: 100%;
}

/* --- full contact form card ---------------------------------------------- */
.contact-form {
  display: grid;
  gap: 18px;
  background: var(--mist);
  border: 1.5px solid var(--line);
  border-radius: 22px;
  padding: 30px;
}
.contact-form input,
.contact-form select,
.contact-form textarea {
  background: var(--paper);
}
.form-title {
  font-size: 22px;
  max-width: none;
}
.contact-form .fine {
  margin-top: 0;
}

/* --- success state replacing a submitted form ---------------------------- */
.form-done {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 24px 26px;
  border: 1.5px solid var(--sage-deep);
  border-radius: 18px;
  background: var(--sage);
  color: var(--sage-deep);
  font-weight: 600;
  font-size: 16.5px;
  max-width: 760px;
  margin-top: 32px;
}
.form-done .tick {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--sage-deep);
  color: var(--sage);
  display: grid;
  place-items: center;
  flex: none;
  font-size: 16px;
}
.form-done small {
  display: block;
  font-weight: 400;
  font-size: 14px;
  opacity: 0.85;
  margin-top: 2px;
}

/* --- offline handoff: the API was unreachable, so we hand the visitor a
   prefilled WhatsApp link rather than claiming a lead we did not capture. --- */
.form-done-offline {
  flex-wrap: wrap;
  border-color: var(--danger);
  background: var(--mist);
  color: var(--ink);
}
.form-done-offline b {
  color: var(--danger);
}
.form-done-offline small {
  color: var(--text);
}
.form-done-offline .btn {
  margin-left: auto;
}

/* ===== styles/06-nav.css ===== */
/* ============================================================================
   06 · Sticky nav, theme toggle, mobile menu
   ========================================================================== */

.nav {
  position: sticky;
  top: 0;
  z-index: 90;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  transition: box-shadow 0.3s var(--ease);
}

/* Translucency only where color-mix is supported; older WebViews keep the
   solid background rather than losing legibility. */
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  .nav {
    background: color-mix(in srgb, var(--paper) 86%, transparent);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
  }
}

.nav.scrolled {
  box-shadow: 0 6px 24px rgb(22 33 62 / 0.07);
}

.nav-in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  height: var(--nav-h);
}

/* --- wordmark ------------------------------------------------------------ */
.logo {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 19px;
  flex: none;
}
.logo i {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--marigold);
  flex: none;
}

/* --- centre links -------------------------------------------------------- */
.links {
  display: flex;
  gap: 26px;
  font-size: 14.5px;
  font-weight: 500;
  color: var(--text);
}
.links a {
  position: relative;
  padding: 6px 0;
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  transition: color 0.2s var(--ease);
}
.links a::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 0;
  background: var(--marigold);
  transition: width 0.25s var(--ease);
}
.links a.active {
  color: var(--ink);
  font-weight: 600;
}
.links a.active::after {
  width: 100%;
}

@media (hover: hover) and (pointer: fine) {
  .links a:hover {
    color: var(--ink);
  }
  .links a:hover::after {
    width: 100%;
  }
}

/* --- right cluster ------------------------------------------------------- */
.nav-right {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: none;
}

.theme-toggle {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1.5px solid var(--line);
  color: var(--ink);
  display: grid;
  place-items: center;
  transition:
    transform 0.25s var(--ease),
    border-color 0.2s var(--ease),
    background-color 0.2s var(--ease);
}
.theme-toggle svg {
  grid-area: 1 / 1;
}
.theme-toggle .ic-sun {
  display: none;
}
[data-theme='dark'] .theme-toggle .ic-moon {
  display: none;
}
[data-theme='dark'] .theme-toggle .ic-sun {
  display: block;
}

@media (hover: hover) and (pointer: fine) {
  .theme-toggle:hover {
    transform: rotate(18deg);
    border-color: var(--ink);
    background: var(--mist);
  }
}

/* --- burger: hidden until the links collapse ---------------------------- */
.burger {
  display: none;
  width: var(--tap);
  height: var(--tap);
  border-radius: 12px;
  border: 1.5px solid var(--line);
  color: var(--ink);
  place-items: center;
}
.burger .ic-close {
  display: none;
}
.burger[aria-expanded='true'] .ic-open {
  display: none;
}
.burger[aria-expanded='true'] .ic-close {
  display: block;
}

/* --- mobile menu panel --------------------------------------------------- */
.mobile-menu {
  border-top: 1px solid var(--line);
  background: var(--paper);
  padding: 10px var(--gutter, 4vw) calc(18px + env(safe-area-inset-bottom));
  max-height: calc(100dvh - var(--nav-h));
  overflow-y: auto;
}
.mobile-links {
  display: grid;
}
.mobile-links a {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding: 6px 2px;
  font-size: 17px;
  font-weight: 500;
  color: var(--text);
  border-bottom: 1px solid var(--line);
}
.mobile-links a.active {
  color: var(--ink);
  font-weight: 600;
}
.mobile-cta {
  width: 100%;
  margin-top: 18px;
}

/* Scroll lock while the menu is open. Applied to <html> by js/04-nav.js. */
html.menu-open,
html.menu-open body {
  overflow: hidden;
}

/* --- language switch ----------------------------------------------------- */
/* A segmented pill the same height as the theme toggle beside it. The language
   being read is filled and carries aria-current; the other is a link. Both
   colour pairs are registered in scripts/contrast-audit.mjs. */
.lang-switch {
  display: flex;
  align-items: center;
  height: 38px;
  padding: 3px;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  flex: none;
}
.lang-opt {
  display: inline-flex;
  align-items: center;
  height: 100%;
  padding: 0 11px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  color: var(--text);
  white-space: nowrap;
  transition:
    color 0.2s var(--ease),
    background-color 0.2s var(--ease);
}
.lang-opt.on {
  background: var(--mist);
  color: var(--ink);
  font-weight: 600;
}
/* The short code is the narrow-screen spelling; the full word is always in
   the accessibility tree via .sr-only, so neither span is ever announced. */
.l-abbr {
  display: none;
}

@media (hover: hover) and (pointer: fine) {
  a.lang-opt:hover {
    color: var(--ink);
    background: var(--mist);
  }
}

/* ===== styles/07-footer.css ===== */
/* ============================================================================
   07 · Footer
   ========================================================================== */

.footer {
  border-top: 1.5px solid var(--ink);
  padding: 46px 0 30px;
}

.fgrid {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr 1fr;
  gap: 40px;
}

.fbrand p {
  color: var(--text);
  font-size: 14.5px;
  max-width: 32ch;
  margin: 16px 0 14px;
}

.fphone {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  color: var(--wa-text);
  font-weight: 600;
  font-size: 16px;
}

.fcol h3 {
  font-family: var(--body);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text);
  margin-bottom: 6px;
}

.fcol ul {
  display: grid;
}

.fcol li a {
  display: flex;
  align-items: center;
  min-height: 40px;
  font-size: 14.5px;
  color: var(--ink);
  transition: color 0.2s var(--ease);
}

@media (hover: hover) and (pointer: fine) {
  .fcol li a:hover,
  .fphone:hover {
    color: var(--marigold-text);
  }
}

.fbottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 40px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
  color: var(--text);
  font-size: 13.5px;
}
.fbottom a {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ===== styles/08-wa-float.css ===== */
/* ============================================================================
   08 · Floating WhatsApp button
   ----------------------------------------------------------------------------
   Fixed bottom-right, which on a phone lands squarely on top of the final CTA's
   submit button and the footer's last column. Two mitigations, both driven by
   js/08-wa.js:
     .fab-tuck   slides it away while a [data-fab-avoid] block is on screen
     .fab-hide   removes it while a field has focus (soft keyboard is open)
   ========================================================================== */

.float-wa {
  position: fixed;
  right: 22px;
  bottom: calc(22px + env(safe-area-inset-bottom));
  z-index: 80;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--wa);
  color: #fff;
  display: grid;
  place-items: center;
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.2);
  transition:
    transform 0.3s var(--ease),
    opacity 0.25s var(--ease);
}

.float-wa .ring {
  position: absolute;
  inset: -5px;
  border-radius: 50%;
  border: 2px solid var(--wa);
  animation: fab-ping 2.2s ease-out infinite;
  pointer-events: none;
}

@keyframes fab-ping {
  0% {
    transform: scale(1);
    opacity: 0.9;
  }
  80%,
  100% {
    transform: scale(1.55);
    opacity: 0;
  }
}

@media (hover: hover) and (pointer: fine) {
  .float-wa:hover {
    transform: scale(1.08);
  }
}

.float-wa.fab-tuck {
  transform: translateY(120%);
  opacity: 0;
  pointer-events: none;
}

.float-wa.fab-hide {
  opacity: 0;
  transform: scale(0.6);
  pointer-events: none;
}

/* Blocks that must never sit under the button reserve room for it. */
[data-fab-avoid] {
  scroll-margin-bottom: var(--fab-clear);
}

/* ===== styles/09-hero.css ===== */
/* ============================================================================
   09 · Hero — blob, word rotator, stats, browser mockup
   ----------------------------------------------------------------------------
   overflow:clip is scoped to this section rather than <body>, because the blob
   and the mockup's floating pills both extend past the viewport edge and would
   otherwise cause horizontal scroll. Clipping the body instead would break
   position:sticky on the nav in iOS Safari.
   ========================================================================== */

.hero {
  position: relative;
  padding: 64px 0 0;
  overflow: clip;
}

/* --- organic sage blob --------------------------------------------------- */
.blob {
  position: absolute;
  right: -10vw;
  top: -8vw;
  width: 44vw;
  height: 44vw;
  background: var(--sage);
  border-radius: 58% 42% 61% 39% / 45% 55% 45% 55%;
  z-index: 0;
  animation: blob-drift 16s ease-in-out infinite alternate;
  will-change: transform, border-radius;
}
[data-theme='dark'] .blob {
  opacity: 0.42;
}

@keyframes blob-drift {
  to {
    border-radius: 42% 58% 39% 61% / 55% 45% 55% 45%;
    transform: translate(-3vw, 3vw) rotate(10deg);
  }
}

.hero-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 48px;
  align-items: center;
}

/* --- rotating word ------------------------------------------------------- */
.swap {
  display: inline-grid;
  color: var(--marigold-deep);
  vertical-align: bottom;
}
.swap span {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateY(60%);
  filter: blur(4px);
  transition:
    opacity 0.5s var(--ease),
    transform 0.55s var(--ease),
    filter 0.5s var(--ease);
}
.swap span.on {
  opacity: 1;
  transform: none;
  filter: none;
}
.swap span.out {
  opacity: 0;
  transform: translateY(-60%);
  filter: blur(4px);
}

.hero .lead {
  font-size: clamp(16px, 1.25vw, 18px);
  color: var(--text);
  max-width: 40ch;
  margin-top: 22px;
}

.cta {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 28px;
}
.cta-note {
  font-size: 13px;
  color: var(--text);
  margin-left: 4px;
}

/* --- stats row ----------------------------------------------------------- */
.stats {
  display: flex;
  gap: 32px;
  margin-top: 40px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}
.stats b {
  display: block;
  font-family: var(--display);
  font-weight: 800;
  font-size: 28px;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.stats span {
  font-size: 13px;
  color: var(--text);
}

/* --- browser mockup ------------------------------------------------------ */
.mock {
  position: relative;
  animation: rise 0.9s var(--ease) 0.35s both;
}

.browser {
  border: 1.5px solid var(--ink);
  border-radius: 16px;
  background: var(--paper);
  overflow: hidden;
  /* Solid offset shadow, no blur — the design language throughout. */
  box-shadow: 14px 14px 0 var(--marigold);
  transition:
    transform 0.5s var(--ease),
    box-shadow 0.5s var(--ease);
}

@media (hover: hover) and (pointer: fine) {
  .mock:hover .browser {
    transform: translate(-4px, -4px);
    box-shadow: 20px 20px 0 var(--marigold);
  }
}

.browser .bar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 11px 14px;
  border-bottom: 1.5px solid var(--ink);
  background: var(--mist);
}
.browser .bar i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--ink);
  opacity: 0.25;
  flex: none;
}
.browser .url {
  flex: 1;
  margin-left: 8px;
  font-size: 12px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 5px 10px;
  color: var(--text);
}

.site {
  padding: 20px 22px 22px;
  font-size: 12px;
}
.s-nav {
  display: flex;
  justify-content: space-between;
  font-weight: 600;
}
.s-hero {
  font-family: var(--display);
  font-weight: 800;
  font-size: 27px;
  line-height: 1.05;
  letter-spacing: -0.025em;
  color: var(--ink);
  margin-top: 22px;
}
.s-sub {
  color: var(--text);
  margin-top: 8px;
  max-width: 30ch;
  line-height: 1.5;
}
.s-btn {
  display: inline-block;
  margin-top: 12px;
  background: var(--coral);
  color: #fff;
  border-radius: 999px;
  padding: 7px 13px;
  font-weight: 600;
}
.s-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-top: 20px;
}
.s-grid div {
  height: 50px;
  border-radius: 9px;
  background: var(--mist);
}
.s-grid div:nth-child(2) {
  background: var(--sage);
}

/* --- floating pills ------------------------------------------------------ */
.pill {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--paper);
  border: 1.5px solid var(--ink);
  border-radius: 999px;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  box-shadow: 0 8px 20px rgb(22 33 62 / 0.12);
  animation: pill-float 5s ease-in-out infinite;
}
.pill i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--wa);
  flex: none;
}
.pill.p1 {
  top: -18px;
  left: -22px;
}
.pill.p2 {
  bottom: 36px;
  right: -26px;
  animation-delay: -2.5s;
}

@keyframes pill-float {
  50% {
    transform: translateY(-8px);
  }
}

/* --- load sequence ------------------------------------------------------- */
.in {
  opacity: 0;
  transform: translateY(22px);
  animation: rise 0.8s var(--ease) forwards;
}
.in.d1 {
  animation-delay: 0.05s;
}
.in.d2 {
  animation-delay: 0.18s;
}
.in.d3 {
  animation-delay: 0.3s;
}
.in.d4 {
  animation-delay: 0.42s;
}

@keyframes rise {
  to {
    opacity: 1;
    transform: none;
  }
}

/* ===== styles/10-bento.css ===== */
/* ============================================================================
   10 · Marquee strip and the services bento grid
   ========================================================================== */

/* --- marquee ------------------------------------------------------------- */
.strip {
  margin-top: 64px;
  border-top: 1.5px solid var(--ink);
  border-bottom: 1.5px solid var(--ink);
  overflow: hidden;
  white-space: nowrap;
}
.track {
  display: inline-flex;
  gap: 48px;
  padding: 14px 0;
  font-size: 14px;
  font-weight: 700;
  animation: marquee 28s linear infinite;
  will-change: transform;
}
.track span::before {
  content: '\2726';
  color: var(--marigold-deep);
  margin-right: 12px;
}
.strip:hover .track,
/* Paused off-screen by js/03-reveal.js — five infinite animations running at
   once is measurable battery drain on a budget Android. */
.track.paused {
  animation-play-state: paused;
}

@keyframes marquee {
  to {
    transform: translateX(-50%);
  }
}

/* --- bento --------------------------------------------------------------- */
/* Four columns, three rows, no empty slots. Auto-placement does the tiling:
     row 1 · a spans cols 1-2 · b col 3 · c col 4 spanning rows 1-2
     row 2 · d spans cols 1-2 · e col 3
     row 3 · f spans the full width                                          */
.bento {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 200px;
  gap: 14px;
}

.cell {
  position: relative;
  overflow: hidden;
  border-radius: 20px;
  padding: 24px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 16px;
  background: var(--mist);
  transition: transform 0.35s var(--ease);
}

@media (hover: hover) and (pointer: fine) {
  .cell:hover {
    transform: translateY(-4px);
  }
}

.cell .tag {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
}
.cell h3 {
  font-size: 21px;
}
.cell p {
  color: var(--text);
  font-size: 14px;
  max-width: 32ch;
  margin-top: 8px;
}

.c-wide {
  grid-column: span 2;
}
.c-tall {
  grid-row: span 2;
}
.c-full {
  grid-column: 1 / -1;
}

/* --- cell tones ---------------------------------------------------------- */
.c-panel {
  background: var(--panel);
  color: var(--panel-text);
}
.c-panel .tag,
.c-panel p {
  color: var(--panel-muted);
}

.c-gold {
  background: var(--marigold);
  color: #16213e;
}
.c-gold .tag,
.c-gold p {
  color: #5a4200;
}

.c-sage {
  background: var(--sage);
  color: var(--ink);
}
.c-sage .tag,
.c-sage p {
  color: var(--sage-deep);
}
[data-theme='dark'] .c-sage {
  color: var(--sage-deep);
}

.c-mist {
  background: var(--mist);
}

/* --- the giant "#1" in the Local SEO cell -------------------------------- */
.big {
  font-size: 60px;
  line-height: 0.9;
  margin-bottom: 10px;
  color: var(--sage-deep);
}

/* --- progress bar, filled once the section is revealed ------------------- */
.bar-anim {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 24px;
  height: 6px;
  border-radius: 3px;
  background: rgb(255 255 255 / 0.15);
  overflow: hidden;
}
.bar-anim::after {
  content: '';
  position: absolute;
  inset: 0;
  width: 0;
  border-radius: 3px;
  background: var(--marigold);
}
.stagger.show .bar-anim::after {
  animation: bar-load 1.6s var(--ease) 0.4s forwards;
}

@keyframes bar-load {
  to {
    width: 82%;
  }
}

/* --- WhatsApp circle bleeding off the corner ---------------------------- */
/* The actual WhatsApp mark, the same glyph as the floating button and the
   contact page. It was a green disc with a ring cut out of it in
   `var(--paper)` — white in the light theme and #0d1120 in the dark one, so
   a dark-mode visitor saw a green circle with a black bite taken out of it
   and no logo at all. `--wa` is a brand constant, identical in both themes;
   nothing about this mark is theme-dependent now, which is the point. */
.wa-mark {
  position: absolute;
  right: 22px;
  bottom: 18px;
  color: var(--wa);
  line-height: 0;
  transition: transform 0.5s var(--ease);
}

@media (hover: hover) and (pointer: fine) {
  .cell:hover .wa-mark {
    transform: scale(1.08) rotate(-6deg);
  }
}

/* ===== styles/11-cards.css ===== */
/* ============================================================================
   11 · Steps, projects, plans, testimonials, services, stats, team
   ========================================================================== */

/* --- steps --------------------------------------------------------------- */
.steps {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1.5px solid var(--ink);
}
.step {
  padding: 24px 22px 0 0;
  border-right: 1px solid var(--line);
}
.step:last-child {
  border-right: 0;
}
.step-n {
  font-size: 38px;
  color: var(--marigold-deep);
}
.step-days {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--sage-deep);
  margin-top: 10px;
}
.step h3 {
  font-size: 18px;
  margin-top: 12px;
}
.step p {
  color: var(--text);
  font-size: 14px;
  margin-top: 8px;
}
.step-detail {
  padding-top: 12px;
  margin-top: 12px;
  border-top: 1px solid var(--line);
  font-size: 13.5px;
}
.steps-wide .step {
  padding-bottom: 26px;
}

/* --- project cards ------------------------------------------------------- */
.proj-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

.proj {
  border-radius: 18px;
  overflow: hidden;
  border: 1.5px solid var(--line);
  background: var(--paper);
  transition:
    transform 0.35s var(--ease),
    border-color 0.3s var(--ease),
    box-shadow 0.35s var(--ease);
}

@media (hover: hover) and (pointer: fine) {
  .proj:hover {
    transform: translateY(-5px);
    border-color: var(--ink);
    box-shadow: 8px 8px 0 var(--marigold);
  }
}

/* Flat colour art panel with a semicircle and initials — no photographs. */
.proj-art {
  position: relative;
  height: 170px;
  overflow: hidden;
  display: grid;
  place-items: center;
}
.proj-shape {
  position: absolute;
  left: -30px;
  bottom: -60px;
  width: 150px;
  height: 150px;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.22);
}
.proj-initials {
  position: relative;
  font-size: 44px;
  letter-spacing: -0.03em;
}
.art-sage {
  background: var(--sage);
  color: var(--sage-deep);
}
.art-marigold {
  background: var(--marigold);
  color: #5a4200;
}
.art-panel {
  background: var(--panel);
  color: var(--panel-text);
}
.art-coral {
  background: var(--coral);
  color: #fff;
}
.art-mist {
  background: var(--mist);
  color: var(--ink);
}

.proj-meta {
  border-top: 1.5px solid var(--line);
  padding: 20px;
}
.proj-meta h3 {
  font-size: 19px;
}
.proj-where {
  font-size: 13px;
  color: var(--text);
  margin-top: 5px;
}
.proj-metric {
  font-size: 14.5px;
  font-weight: 600;
  color: var(--sage-deep);
  margin-top: 10px;
}

/* --- plans --------------------------------------------------------------- */
.plans {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  align-items: end;
}

.plan {
  border: 1.5px solid var(--panel-line);
  border-radius: 22px;
  padding: 28px;
  transition:
    transform 0.35s var(--ease),
    border-color 0.3s var(--ease);
}

@media (hover: hover) and (pointer: fine) {
  .plan:hover {
    transform: translateY(-6px);
    border-color: #5c6a9a;
  }
  .plan-hot:hover {
    border-color: var(--marigold);
  }
}

.plan-hot {
  background: var(--marigold);
  color: #16213e;
  border-color: var(--marigold);
  padding-bottom: 40px;
}

.plan-name {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: 14px;
  font-weight: 600;
}
.plan-name em {
  font-style: normal;
  font-size: 11.5px;
  background: #16213e;
  color: #fff;
  padding: 4px 10px;
  border-radius: 999px;
  white-space: nowrap;
}

.plan-amt {
  font-size: 46px;
  letter-spacing: -0.03em;
  margin: 12px 0 2px;
}
.plan-for {
  font-size: 13.5px;
  opacity: 0.75;
}

.plan-feats {
  display: grid;
  gap: 9px;
  margin: 22px 0 26px;
  font-size: 14px;
}
.plan-feats li {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  line-height: 1.45;
}
.plan-feats li::before {
  content: '\2713';
  font-weight: 700;
  color: var(--marigold);
  flex: none;
}
.plan-hot .plan-feats li::before {
  color: #16213e;
}

.plan .btn {
  width: 100%;
}

/* --- testimonials -------------------------------------------------------- */
.quotes {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

.quote {
  border: 1.5px solid var(--line);
  border-radius: 20px;
  padding: 26px;
  background: var(--paper);
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.stars {
  color: var(--marigold);
  font-size: 15px;
  letter-spacing: 2px;
  line-height: 1;
}
.quote blockquote p {
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--ink);
}
.quote figcaption {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}
.who {
  display: grid;
}
.who b {
  font-size: 14.5px;
  font-weight: 600;
}
.who small {
  font-size: 13px;
  color: var(--text);
}

/* --- service cards (/services) ------------------------------------------- */
.svc-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}
.svc {
  border: 1.5px solid var(--line);
  border-radius: 20px;
  padding: 28px;
  background: var(--paper);
  transition: border-color 0.3s var(--ease);
}
.svc-tag {
  font-size: 13px;
  font-weight: 600;
  color: var(--sage-deep);
  margin-bottom: 10px;
}
.svc h3 {
  font-size: 22px;
  max-width: 24ch;
}
.svc-body {
  color: var(--text);
  font-size: 14.5px;
  margin-top: 12px;
  max-width: 46ch;
}

@media (hover: hover) and (pointer: fine) {
  .svc:hover {
    border-color: var(--ink);
  }
}

/* --- stat cards (/about) ------------------------------------------------- */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-top: 0;
}
.stat-card {
  border: 1.5px solid var(--line);
  border-radius: 20px;
  padding: 28px;
  background: var(--paper);
}
.stat-n {
  font-size: 52px;
  color: var(--marigold-deep);
  letter-spacing: -0.03em;
}
.stat-card h3 {
  font-size: 17px;
  margin-top: 10px;
}
.stat-card p {
  color: var(--text);
  font-size: 14px;
  margin-top: 6px;
}

/* --- team ---------------------------------------------------------------- */
.team {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
.team-card {
  border: 1.5px solid var(--line);
  border-radius: 20px;
  padding: 26px;
  display: grid;
  gap: 6px;
  justify-items: start;
}
.team-card .avatar {
  width: 52px;
  height: 52px;
  font-size: 17px;
  margin-bottom: 10px;
}
.team-card h3 {
  font-size: 19px;
}
.team-card p {
  color: var(--text);
  font-size: 14px;
}

/* ===== styles/12-tables.css ===== */
/* ============================================================================
   12 · Tables
   ----------------------------------------------------------------------------
   Wide tables scroll inside their own container so the page body never scrolls
   horizontally. The first column is sticky, otherwise a scrolled comparison
   table loses the label for the row you are reading.
   ========================================================================== */

.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1.5px solid var(--line);
  border-radius: 18px;
  background: var(--paper);
}

.table {
  min-width: 520px;
  font-size: 14.5px;
}

.table caption {
  text-align: left;
  padding: 18px 20px 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}

.table th,
.table td {
  text-align: left;
  padding: 15px 20px;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.table thead th {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text);
  white-space: nowrap;
}

.table tbody th {
  font-weight: 600;
  color: var(--ink);
}

.table tbody tr:last-child th,
.table tbody tr:last-child td {
  border-bottom: 0;
}

.table td {
  color: var(--text);
}

.td-price {
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
}

/* Sticky row label while the table scrolls sideways. */
.table-compare tbody th,
.table-compare thead th:first-child {
  position: sticky;
  left: 0;
  background: var(--paper);
  z-index: 1;
}

.table-compare td {
  text-align: center;
}
.table-compare thead th:not(:first-child) {
  text-align: center;
}

.yes {
  color: var(--sage-deep);
  font-weight: 700;
}
.no {
  color: var(--text);
  opacity: 0.45;
}

/* --- comparison: table on wide screens, stacked cards on phones ---------- */
.compare-narrow {
  display: none;
}

.cmp-card {
  border: 1.5px solid var(--line);
  border-radius: 18px;
  padding: 22px;
  background: var(--paper);
}
.cmp-card + .cmp-card {
  margin-top: 12px;
}
.cmp-card h3 {
  font-size: 20px;
  margin-bottom: 14px;
}
.cmp-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
  font-size: 14.5px;
}
.cmp-row:last-child {
  border-bottom: 0;
}
.cmp-row dt {
  color: var(--text);
}
.cmp-row dd {
  font-weight: 600;
  text-align: right;
}

/* ===== styles/13-faq.css ===== */
/* ============================================================================
   13 · FAQ accordion
   ----------------------------------------------------------------------------
   Panels are collapsed with max-height rather than [hidden], so the answers
   stay in the document for crawlers. With JS unavailable every panel renders
   open, which is the correct fallback for a page whose whole purpose is
   answering questions.
   ========================================================================== */

.faq {
  border-top: 1.5px solid var(--ink);
}

.faq-item {
  border-bottom: 1px solid var(--line);
}

.faq-q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  text-align: left;
  padding: 22px 2px;
  min-height: var(--tap);
  font-family: var(--display);
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -0.02em;
  line-height: 1.3;
  color: var(--ink);
  transition: color 0.2s var(--ease);
}

@media (hover: hover) and (pointer: fine) {
  /* marigold-TEXT, not marigold-deep. The question is 19px/700 here, which
     clears WCAG's 18.66px bold bar for "large" text and so only needs 3:1 —
     but 20-responsive.css drops it to 17px at 380px, and 17px bold is normal
     text, which needs 4.5:1. marigold-deep gives 3.37:1. A narrow window with
     a mouse is the case that fails, and it is reachable. The token file says
     as much in its own comment: marigold-deep is for display sizes, and this
     variant is "for marigold text below 18.66px bold — dates, link hovers". */
  .faq-q:hover {
    color: var(--marigold-text);
  }
}

/* Marigold plus that rotates to an x when the panel opens. */
.faq-ic {
  position: relative;
  width: 20px;
  height: 20px;
  flex: none;
  transition: transform 0.3s var(--ease);
}
.faq-ic::before,
.faq-ic::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  background: var(--marigold);
  border-radius: 2px;
  transform: translate(-50%, -50%);
}
.faq-ic::before {
  width: 18px;
  height: 2.5px;
}
.faq-ic::after {
  width: 2.5px;
  height: 18px;
}
.faq-q[aria-expanded='true'] .faq-ic {
  transform: rotate(45deg);
}

.faq-a {
  overflow: hidden;
  transition: max-height 0.35s var(--ease);
}
.faq-a p {
  color: var(--text);
  font-size: 15.5px;
  max-width: 68ch;
  padding: 0 2px 24px;
}

/* Collapsed only once JS has taken over. */
.js .faq-a {
  max-height: 0;
}

/* ===== styles/14-blog.css ===== */
/* ============================================================================
   14 · Blog index and post
   ========================================================================== */

.posts {
  border-top: 1.5px solid var(--ink);
}

.post-row {
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: 28px;
  padding: 28px 0;
  border-bottom: 1px solid var(--line);
}

.post-date {
  font-family: var(--display);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: -0.02em;
  color: var(--marigold-text);
  padding-top: 4px;
}

.post-main h2 {
  font-size: clamp(21px, 2.3vw, 27px);
  max-width: 28ch;
}
.post-main h2 a {
  transition: color 0.2s var(--ease);
}

.post-ex {
  color: var(--text);
  font-size: 15px;
  max-width: 60ch;
  margin-top: 10px;
}

.post-more {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.post-more .arr {
  transition: transform 0.25s var(--ease);
}

@media (hover: hover) and (pointer: fine) {
  .post-main h2 a:hover {
    color: var(--marigold-deep);
  }
  .post-row:hover .post-more .arr {
    transform: translateX(4px);
  }
}

/* --- single post --------------------------------------------------------- */
.post-head {
  max-width: 70ch;
  padding-bottom: 30px;
  margin-bottom: 34px;
  border-bottom: 1px solid var(--line);
}
.post-head h1 {
  font-size: clamp(30px, 4.4vw, 52px);
  max-width: 20ch;
}
.post-head .kicker {
  margin-bottom: 16px;
}

.back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 8px;
}

@media (hover: hover) and (pointer: fine) {
  .back:hover {
    color: var(--ink);
  }
}

/* ===== styles/15-contact.css ===== */
/* ============================================================================
   15 · Contact page
   ========================================================================== */

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

.crows {
  border-top: 1px solid var(--line);
}

.crow {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  padding: 18px 4px;
  min-height: var(--tap);
  border-bottom: 1px solid var(--line);
  transition: background-color 0.2s var(--ease);
}

.crow-ic {
  width: 40px;
  height: 40px;
  border-radius: 12px;
  background: var(--mist);
  color: var(--ink);
  display: grid;
  place-items: center;
  flex: none;
}

.crow-body {
  display: grid;
  gap: 2px;
}
.crow-label {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text);
}
.crow-value {
  font-size: 16.5px;
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.crow-note {
  font-size: 13.5px;
  color: var(--text);
}

@media (hover: hover) and (pointer: fine) {
  a.crow:hover {
    background: var(--mist);
  }
  a.crow:hover .crow-ic {
    background: var(--marigold);
  }
}

.contact-cta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 28px;
}

/* ===== styles/16-admin.css ===== */
/* ============================================================================
   16 · Admin dashboard preview
   ========================================================================== */

.admin-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

.admin-stat {
  border: 1.5px solid var(--line);
  border-radius: 18px;
  padding: 24px;
  background: var(--paper);
}
.admin-n {
  font-size: 40px;
  letter-spacing: -0.03em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.admin-stat h2 {
  font-family: var(--body);
  font-size: 14.5px;
  font-weight: 600;
  max-width: none;
  letter-spacing: 0;
  margin-top: 8px;
}
.admin-hint {
  font-size: 13px;
  color: var(--text);
  margin-top: 3px;
}

.admin-panel {
  margin-top: 16px;
}

.admin-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.admin-head h2 {
  font-size: 24px;
  max-width: none;
}
.admin-live {
  font-size: 13px;
  font-weight: 600;
  color: var(--sage-deep);
  background: var(--sage);
  border-radius: 999px;
  padding: 6px 14px;
}

.table-leads {
  min-width: 640px;
}
.table-leads .status {
  display: inline-block;
  font-size: 12.5px;
  font-weight: 600;
  border-radius: 999px;
  padding: 4px 11px;
  background: var(--sage);
  color: var(--sage-deep);
  white-space: nowrap;
}

.admin-empty {
  border: 1.5px dashed var(--line);
  border-top: 0;
  border-radius: 0 0 18px 18px;
  padding: 30px;
  text-align: center;
  color: var(--text);
  font-size: 14.5px;
  display: grid;
  gap: 10px;
  justify-items: center;
}
.admin-empty b {
  color: var(--ink);
  font-size: 16px;
}
.admin-empty p {
  max-width: 52ch;
}
.admin-empty .btn {
  margin-top: 8px;
}

/* ===== styles/20-responsive.css ===== */
/* ============================================================================
   20 · Responsive
   ----------------------------------------------------------------------------
   Breakpoints: 1040 (nav crowding) · 860 (the main collapse) · 640 (three-up
   grids drop to two) · 520 (single column) · 380 (small-Android guard).
   The 380px stop is not in the original spec but Galaxy A-series and Redmi
   handsets at 360px are a large share of this audience.
   ========================================================================== */

@media (max-width: 1040px) {
  .links {
    gap: 18px;
    font-size: 14px;
  }
  .nav-cta {
    padding: 11px 16px;
  }
}

/* --------------------------------------------------------------- < 860px */
@media (max-width: 860px) {
  :root {
    --section-y: 64px;
  }

  /* nav collapses to a burger menu */
  .links,
  .nav-cta {
    display: none;
  }

  /* The language switch does NOT collapse into the menu. It is the one
     control a visitor who cannot read the page needs to find immediately,
     and a control behind a burger is one they have to read to open. */
  .lang-opt {
    padding: 0 10px;
  }
  .burger {
    display: grid;
  }

  /* two-column layouts stack */
  .hero-grid,
  .head,
  .contact-grid,
  .svc-grid,
  .band {
    grid-template-columns: 1fr;
  }
  .head {
    gap: 18px;
  }
  .band {
    padding: 28px;
    gap: 22px;
  }
  .band .btn {
    justify-self: start;
  }

  h2,
  .page-head h1 {
    max-width: 20ch;
  }

  /* hero: mockup below the copy, blob larger and pushed further off */
  .hero {
    padding-top: 40px;
  }
  .mock {
    margin-top: 36px;
  }
  .blob {
    width: 80vw;
    height: 80vw;
    right: -35vw;
    top: -14vw;
  }
  .pill.p1 {
    left: 0;
  }
  .pill.p2 {
    right: 0;
  }
  .stats {
    gap: 22px;
  }

  /* bento: two columns, every span reset */
  .bento {
    grid-template-columns: repeat(2, 1fr);
    grid-auto-rows: 180px;
  }
  .c-wide,
  .c-tall,
  .c-full {
    grid-column: span 2;
    grid-row: auto;
  }

  /* steps and plans stack; the popular plan no longer needs extra padding */
  .steps,
  .plans {
    grid-template-columns: 1fr;
  }
  .step {
    border-right: 0;
    border-bottom: 1px solid var(--line);
    padding: 22px 0;
  }
  .step:last-child {
    border-bottom: 0;
  }
  .plan-hot {
    padding-bottom: 28px;
  }

  /* comparison: stacked per-plan cards replace the 4-column table */
  .compare-wide {
    display: none;
  }
  .compare-narrow {
    display: block;
  }

  /* blog rows: date above the title */
  .post-row {
    grid-template-columns: 1fr;
    gap: 10px;
  }

  /* footer to two columns, brand spanning */
  .fgrid {
    grid-template-columns: 1fr 1fr;
    gap: 30px;
  }
  .fbrand {
    grid-column: 1 / -1;
  }

  /* reserve room so the floating WhatsApp button never covers a control */
  .final,
  .footer {
    padding-bottom: var(--fab-clear);
  }

  .contact-form {
    padding: 24px;
  }
  .quick-form .btn {
    width: 100%;
  }
}

/* --------------------------------------------------------------- < 640px */
@media (max-width: 640px) {
  .proj-grid,
  .quotes,
  .stat-grid,
  .team,
  .admin-stats {
    grid-template-columns: 1fr;
  }
  .notes-grid {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------- < 520px */
@media (max-width: 520px) {
  /* single-column bento; cells size to content rather than a fixed row height,
     otherwise six 200px rows become a 1,200px scroll of mostly empty space */
  .bento {
    grid-template-columns: 1fr;
    grid-auto-rows: auto;
  }
  .cell {
    min-height: 168px;
  }
  .c-wide,
  .c-tall,
  .c-full {
    grid-column: span 1;
  }

  /* One column means the WhatsApp card is barely wider than its own headline,
     and a 116px mark in the bottom-right corner lands on top of it. Smaller,
     and moved up beside the tag — the one short line on the card. */
  .wa-mark {
    top: 18px;
    right: 16px;
    bottom: auto;
  }
  .wa-mark svg {
    width: 66px;
    height: 66px;
  }

  .cta {
    gap: 10px;
  }
  .cta .btn {
    width: 100%;
  }
  .cta-note {
    margin-left: 0;
  }

  .stats {
    flex-wrap: wrap;
    gap: 18px 26px;
  }

  .fgrid {
    grid-template-columns: 1fr;
  }

  .quote,
  .svc,
  .note-card,
  .stat-card,
  .admin-stat {
    padding: 22px;
  }

  .float-wa {
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom));
  }
}

/* --------------------------------------------------------------- < 380px */
@media (max-width: 380px) {
  :root {
    --wrap: 94vw;
  }
  .logo {
    font-size: 17px;
  }
  .plan-amt {
    font-size: 40px;
  }
  .stat-n {
    font-size: 44px;
  }
  .proj-initials {
    font-size: 38px;
  }
  .faq-q {
    font-size: 17px;
  }
  .crow-value {
    font-size: 15.5px;
  }
}

/* --------------------------------------------------------------- print */
@media print {
  .nav,
  .float-wa,
  .skip,
  .mobile-menu,
  .band,
  .sec-more {
    display: none !important;
  }
  .page[hidden] {
    display: none;
  }
  body {
    background: #fff;
    color: #000;
  }
}

/* --------------------------------------------------------------- < 600px */
/* Four things share a 390px phone: the wordmark, the language switch, the
   theme toggle and the burger. The wordmark alone is 232px of Syne at 19px —
   more than half the screen — so it comes down here, and the switch offers
   only the language you are NOT reading, because the one you are reading is
   the page in front of you. Measured, not guessed: e2e/web.mjs fails the walk
   when the row runs past the viewport, which is how this was found.

   600px, not 480: the full two-option control is 123px and the whole row then
   needs about 550px of viewport. A 480px breakpoint put the wide form into a
   520px screen, where it ran 5px past the edge — which is the kind of band
   nobody opens and every phone in landscape lands in. */
@media (max-width: 600px) {
  .nav-in {
    gap: 8px;
  }
  .nav-right {
    gap: 8px;
  }
  .logo {
    font-size: 16px;
    gap: 6px;
  }
  .logo i {
    width: 9px;
    height: 9px;
  }
  .theme-toggle {
    width: 36px;
    height: 36px;
  }
  .lang-switch {
    height: 36px;
    padding: 2px;
  }
  .lang-opt {
    padding: 0 8px;
    font-size: 12px;
  }
  /* The language you are already reading is not an option worth 36px here. */
  .lang-opt.on {
    display: none;
  }
  .l-full {
    display: none;
  }
  .l-abbr {
    display: inline;
  }
}

/* --------------------------------------------------------------- < 380px */
/* A 360px Android is the narrowest screen this audience actually carries, and
   the row fits it with nothing to spare. The wordmark gives up one more pixel
   of size rather than the language switch giving up its place.

   Below about 340px the row has never fitted — the wordmark alone is wider
   than a third of the screen — and it did not fit before the switch existed
   either. That is a wordmark problem, not this one. */
@media (max-width: 380px) {
  .nav-in {
    gap: 6px;
  }
  .nav-right {
    gap: 6px;
  }
  .logo {
    font-size: 15px;
  }
}

/* ===== styles/21-motion.css ===== */
/* ============================================================================
   21 · Reveal animations and the reduced-motion contract
   ----------------------------------------------------------------------------
   Reveals are opt-in via .js: with JavaScript unavailable nothing is ever
   hidden, because an IntersectionObserver that never runs would otherwise
   leave the entire page invisible.
   ========================================================================== */

.js .rv {
  opacity: 0;
  transform: translateY(28px);
  transition:
    opacity 0.7s var(--ease),
    transform 0.7s var(--ease);
}
.js .rv.show {
  opacity: 1;
  transform: none;
}

.js .stagger > * {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity 0.6s var(--ease),
    transform 0.6s var(--ease);
}
.js .stagger.show > * {
  opacity: 1;
  transform: none;
}
.js .stagger.show > *:nth-child(2) {
  transition-delay: 0.08s;
}
.js .stagger.show > *:nth-child(3) {
  transition-delay: 0.16s;
}
.js .stagger.show > *:nth-child(4) {
  transition-delay: 0.24s;
}
.js .stagger.show > *:nth-child(5) {
  transition-delay: 0.32s;
}
.js .stagger.show > *:nth-child(6) {
  transition-delay: 0.4s;
}
/* Cap at six: beyond that the last card would wait almost a second. */
.js .stagger.show > *:nth-child(n + 7) {
  transition-delay: 0.4s;
}

/* ============================================================================
   prefers-reduced-motion
   ----------------------------------------------------------------------------
   Not just "animation: none". Several effects encode information in their end
   state — the progress bar's fill, the rotator's visible word, the reveal
   opacity — so each is explicitly resolved to its final value rather than
   frozen at zero.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  html {
    scroll-behavior: auto;
  }

  /* everything that reveals is simply present */
  .js .rv,
  .js .stagger > *,
  .in {
    opacity: 1 !important;
    transform: none !important;
  }

  /* the progress bar carries a value, so it is filled rather than empty */
  .bar-anim::after {
    width: 82% !important;
  }

  /* the rotator freezes on the first word instead of cycling */
  .swap span {
    opacity: 0;
    filter: none;
    transform: none;
  }
  .swap span.on,
  .swap span:first-child {
    opacity: 1;
  }

  /* infinite decorative loops stop entirely */
  .track,
  .blob,
  .pill,
  .float-wa .ring {
    animation: none !important;
  }
  .float-wa .ring {
    opacity: 0;
  }

  /* the FAQ opens and closes instantly rather than not at all */
  .faq-a {
    transition: none !important;
  }
}