@import url('tokens.css');

/* ALevelSoft landing page.
   Desktop is the mockup's 1440px frame; the rules below it are mobile-first
   base styles, with the desktop layout in the media queries each section card
   adds. Every colour, size and radius comes from tokens.css; nothing here
   hard-codes one. */

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

html { -webkit-text-size-adjust: 100%; }

/* No `overflow-x: hidden` here on purpose: it would hide the very thing the
   overflow check looks for, and turn a real layout bug at
   320px into a silent horizontal clip. Offenders get fixed, not masked. */
body { margin: 0; }

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

a { color: inherit; }

/* ==========================================================================
   Layout primitives — the page container and the shared widgets. Written by
   F1 because it is the first section; every later section reuses them.
   ========================================================================== */

body {
  font-family: var(--ff-sans);
  color: var(--c-ink);
  background: var(--c-surface);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

/* The mockup is 1440 wide with 80px gutters, so the content column is 1280.
   Below that the gutter shrinks in two steps and the column just gets narrower;
   nothing reflows because of the container itself. */
.container {
  width: 100%;
  max-width: calc(var(--content-w) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 0 var(--pad);
}

:root { --pad: var(--sp-7); }                       /* 24px on phones */
@media (min-width: 768px)  { :root { --pad: var(--sp-9); } }   /* 40px */
@media (min-width: 1200px) { :root { --pad: var(--gutter); } } /* 80px — the mockup */

/* Desktop-only line break: a space before it, so the two words stay separate
   words when the break is hidden. tools/checks/dom-text.mjs checks that. */
.d { display: none; }
@media (min-width: 1200px) { .d { display: inline; } }

/* ---- eyebrow ------------------------------------------------------------ */
.eyebrow {
  margin: 0;
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-eyebrow);
  /* Figma rounds every auto-layout box to a whole pixel, so a ratio line-height
     leaves each stacked box a fraction tall and the error accumulates down the
     page as visible drift at the section seams. Where a box contributes to a
     section's height, the line-height is pinned in px to the mockup's own box:
     11px text in a 13px box here. */
  line-height: 13px;
}

.eyebrow--pill {
  align-self: flex-start;     /* a pill, not a full-width bar */
  display: inline-block;
  padding: var(--sp-3) 14px;
  border-radius: var(--r-sm);
  background: rgba(0, 181, 173, 0.15);   /* --c-accent-deep at 15% over --c-ink */
  color: var(--c-on-dark);
  font-weight: var(--fw-medium);
}

/* ---- buttons ------------------------------------------------------------ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5) var(--sp-8);
  border: 0;
  border-radius: var(--r-sm);
  font-size: var(--fs-body);
  font-weight: var(--fw-semibold);
  line-height: 19px;          /* 16px text, mockup box 19 -> 51px button */
  text-decoration: none;
  transition: opacity 120ms ease-out;
}

.btn:hover { opacity: 0.9; }

.btn:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 3px;
}

.btn:disabled { cursor: default; opacity: 0.6; }

.btn--primary { background: var(--c-accent); color: var(--c-ink); }

.btn--ghost {
  padding: 15px var(--sp-8);
  box-shadow: inset 0 0 0 1px var(--c-on-dark-30);   /* Figma stroke: INSIDE */
  background: transparent;
  color: var(--c-on-dark-80);
  font-weight: var(--fw-medium);
}

.btn--ghost:hover { box-shadow: inset 0 0 0 1px var(--c-on-dark); color: var(--c-on-dark); opacity: 1; }

.btn--sm { padding: var(--sp-4) var(--sp-7); font-size: var(--fs-sm); line-height: 17px; letter-spacing: var(--ls-button); }

/* ==========================================================================
   F1 · Header
   ========================================================================== */

.header { background: var(--c-ink); }

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 80px;
}

.header__logo { display: flex; flex-shrink: 0; }
.header__logo img { width: 153.454px; height: 24px; }

.header__logo:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 4px; }

/* ---- navigation ---------------------------------------------------------
   <details> is the disclosure: real semantics, keyboard operable, no script.
   From 1200 up the summary is hidden and the panel is laid out as a row. */
.nav { position: relative; }

.nav__toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;                      /* a 44px target, not a 24px glyph */
  height: 44px;
  margin-right: calc(var(--sp-3) * -1);
  cursor: pointer;
  list-style: none;
}

.nav__toggle::-webkit-details-marker { display: none; }
.nav__toggle:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }

.nav__bars,
.nav__bars::before,
.nav__bars::after {
  display: block;
  width: 22px;
  height: 2px;
  border-radius: 1px;
  background: var(--c-on-dark);
  content: '';
}

.nav__bars { position: relative; }
.nav__bars::before { position: absolute; top: -7px; }
.nav__bars::after { position: absolute; top: 7px; }

/* State the disclosure explicitly rather than leaning on UA internals: the
   panel's display then actually changes on open, which is both more robust
   across engines and what makes tools/checks/nav-toggle.mjs able to see it. */
.nav:not([open]) .nav__panel { display: none; }

.nav__panel {
  display: block;
  position: absolute;
  right: 0;
  top: calc(100% + var(--sp-4));
  z-index: 10;
  min-width: 208px;
  padding: var(--sp-3);
  border: 1px solid var(--c-on-dark-10);
  border-radius: var(--r-lg);
  background: var(--c-ink-deep);
}

.nav__list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav__link {
  display: block;
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--r-sm);
  color: var(--c-on-dark);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  line-height: var(--lh-ui);
  text-decoration: none;
}

.nav__link:hover { background: var(--c-on-dark-10); }
.nav__link:focus-visible { outline: 2px solid var(--c-accent); outline-offset: -2px; }

/* ==========================================================================
   F1 · Hero
   ========================================================================== */

.hero {
  background: var(--c-ink);
  color: var(--c-on-dark);
  padding: var(--sp-9) 0 var(--sp-10);
}

.hero__inner { position: relative; }

.hero__copy { display: flex; flex-direction: column; gap: var(--sp-8); }

.hero__title {
  max-width: 880px;
  margin: 0;
  /* "transformation" is one unbreakable word 7.17px wide per 1px of font-size
     (measured), so below ~420px the ramp's 44px step no longer fits the content
     column and the word pushes the document wider than the viewport. The floor
     here keeps it inside; min() picks the ramp step everywhere above that, so
     the mockup's own sizes still apply wherever they fit. Note that an
     element-rect overflow check cannot see this: the <h1> box stays 272px wide
     while its text node overflows. */
  font-size: min(var(--fs-h2), calc(13.5vw - 6.5px));
  font-weight: var(--fw-extrabold);
  letter-spacing: var(--ls-tight);
  line-height: var(--lh-display);
}

.hero__title-accent { color: var(--c-accent); }

.hero__sub {
  max-width: 640px;
  margin: 0;
  color: var(--c-on-dark-65);
  font-size: var(--fs-h4);
  line-height: var(--lh-body);
}

.hero__headline { display: flex; flex-direction: column; gap: var(--sp-5); }

/* Side by side in the mockup; stacked below 480 where 209 + 16 + 193 no longer
   fits. Stretched rather than left ragged — two buttons of different intrinsic
   width stacked look like an accident, not a decision. */
.hero__ctas {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--sp-5);
}

@media (min-width: 480px) {
  .hero__ctas { flex-direction: row; flex-wrap: wrap; align-items: center; }
}

.hero__device { display: none; }

@media (min-width: 768px) {
  .hero { padding: var(--sp-11) 0 var(--sp-12); }
  .hero__title { font-size: var(--fs-h1); }
  .hero__sub { line-height: 29px; }    /* 18px text, two lines in the mockup's 58px box */
}

@media (min-width: 1200px) {
  .header__inner { min-height: 80px; }

  .nav__toggle { display: none; }

  /* The panel stops being a panel: no box, no absolute positioning, just a row.
     A closed <details> hides its content, and does so two different ways
     depending on the engine's age, so both are undone: current engines hide the
     ::details-content slot (Chrome 131, Safari 18.4, Firefox 139 — all inside
     this project's browserslist), older ones set display:none on the child from
     the UA sheet. An engine that understood neither would drop both rules and
     hide the desktop nav, which is why they are written as a pair. */
  .nav::details-content {
    content-visibility: visible;
    display: contents;
  }

  .nav__panel,
  .nav:not([open]) .nav__panel {
    display: block;
    position: static;
    min-width: 0;
    padding: 0;
    border: 0;
    background: none;
  }

  .nav__list { flex-direction: row; gap: var(--sp-9); }

  .nav__link { padding: 0; border-radius: 0; }
  .nav__link:hover { background: none; color: var(--c-accent); }

  .hero { padding: var(--sp-12) 0 var(--sp-14); }

  .hero__title { font-size: var(--fs-display); line-height: 79px; }  /* two lines in 158 */

  /* The mockup's 782px render only clears the copy at 1440. Narrower, it keeps its
     right edge and its top and shrinks, by the larger of two lines measured (F8)
     against the opaque pixels under each line of copy: below ~1344 the limit
     grows 0.56px per px of width, above it the subheading's right edge leaves a
     constant 648px. Both carry 8px of margin; at 1440 the cap gives back the
     mockup exactly. Percentages, not vw: they resolve against .container, so a
     classic scrollbar cannot make the render wider than the measurement. */
  .hero__device {
    display: block;
    position: absolute;
    right: 1px;                           /* offsets resolve against .container's padding box */
    top: -99.25px;                        /* section top 80 -> image top 60.75 */
    width: min(782px, max(100% - 656px, 56% - 64px));
    height: auto;
    aspect-ratio: 782 / 586.5;
    max-width: none;
  }
}

/* ==========================================================================
   F2 · Stats
   ========================================================================== */

.stats { background: var(--c-surface); padding: var(--sp-9) 0; }

.stats__inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-8);
}

/* One divider, between the first and second stat. The mockup has exactly one —
   sampling the reference render at x 400, 720 and 1040 finds a rule only at
   400 — so one is what ships. See F2's Decision. */
.stats__divider { display: none; }

.stat { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2); }

/* The rating is a link as a whole (the client's §6): it keeps the stat's look and
   says it is one only on hover and focus. */
.stat--link { color: inherit; text-decoration: none; }
.stat--link:hover .stat__label { text-decoration: underline; }
.stat--link:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 4px; border-radius: var(--r-xs); }

.stat__bar {
  width: 32px;
  height: 3px;
  /* The mockup puts a 12px spacer element between the bar and the number, so
     the column's 6px gap is paid twice around it: 3 + 6 + 12 + 6 + 48 = 75. */
  margin-bottom: 18px;
  border-radius: var(--r-xs);
  background: var(--c-accent);
}

.stat__num {
  margin: 0;
  color: var(--c-ink);
  font-size: var(--fs-stat);
  font-weight: var(--fw-extrabold);
  letter-spacing: var(--ls-tight);
  line-height: var(--lh-flat);
}

.stat__label {
  margin: 0;
  color: var(--c-ink);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-semibold);
  line-height: 18px;          /* 15px text, two lines in the mockup's 36px box */
}

@media (min-width: 560px) {
  .stats__inner { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 1200px) {
  .stats { padding: var(--sp-11) 0; }

  .stats__inner {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0;
  }

  .stat { flex: 1 1 0; min-width: 0; }

  .stats__divider {
    display: block;
    flex: 0 0 auto;
    align-self: center;
    width: 1px;
    height: 80px;
    background: var(--c-surface-muted);
  }
}

/* ==========================================================================
   F2 · Section header — shared by every section from here down
   ========================================================================== */

/* Most section headers are eyebrow + 40px heading with a 10px gap; the
   services one is eyebrow + 44px heading + a lead paragraph at 12px. */
.section-head { display: flex; flex-direction: column; gap: 10px; }

.services .section-head { gap: var(--sp-4); }

.section-head__title {
  margin: 0;
  color: var(--c-ink);
  font-size: var(--fs-h2-sm);
  font-weight: var(--fw-extrabold);
  letter-spacing: var(--ls-snug);
  line-height: 45px;          /* 40px text, mockup box 45 */
}

.section-head__lead {
  margin: 0;
  color: var(--c-text-muted);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

/* ==========================================================================
   F2 · Services
   ========================================================================== */

.services { background: var(--c-surface-alt); padding: var(--sp-10) 0; }

.services .section-head { margin-bottom: var(--sp-9); }

.cards {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-7);
}

.card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-5);
  padding: var(--sp-8);
  border-radius: var(--r-lg);
  /* Figma's strokes are INSIDE: they overlay the box instead of insetting its
     children, which a CSS border does. An inset shadow draws the same 1px
     without moving anything. */
  box-shadow: inset 0 0 0 1px var(--c-border);
  background: var(--c-surface);
}

.card__icon { flex-shrink: 0; }

.card__title {
  margin: 0;
  color: var(--c-ink);
  font-size: var(--fs-h4);
  font-weight: var(--fw-bold);
  line-height: var(--lh-title);
}

.card__desc {
  flex: 1 1 auto;
  margin: 0;
  color: var(--c-text-muted);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
}

.card__desc--ink { color: var(--c-ink); }

.card__link {
  color: var(--c-ink);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-ui);
  text-decoration: none;
}

.card__link:hover { text-decoration: underline; }
.card__link:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 3px; }

/* The promo card: the image is decoration behind text, so it is a background
   rather than an <img> — a stray line of copy cannot drag it out of the card,
   and it needs no alt. The mockup places a 584x332 image at (-92,-40) inside
   the 400x262 card; the percentages below reproduce that at any card width. */
.card--promo {
  justify-content: center;
  box-shadow: none;           /* the mockup's promo card has no stroke */
  background-image: url('../assets/img/bg-services-promo.jpg');
  background-position: center;
  background-size: cover;
}

/* The description grows on the ordinary cards so the link sits at the bottom;
   on the promo card the whole stack is centred, so growth would break it. */
.card--promo .card__desc { flex: 0 0 auto; }

.card__cta { align-self: stretch; }

@media (min-width: 640px) {
  .cards { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1200px) {
  .services { padding: var(--sp-13) 0; }
  .services .section-head { margin-bottom: 56px; }

  .services .section-head__title { font-size: var(--fs-h2); line-height: 49px; }

  /* Three columns capped at the mockup's 400px, left-aligned. At 1440 that is
     400x3 + 24x2 = 1248 inside a 1280 container, so the right column stops 32px
     short of the gutter — the mockup's own slack, not a rounding error. The cap
     is a maximum rather than a fixed width because between 1200 and 1440 the
     container is narrower than 1248 and fixed columns would overflow it. */
  .cards {
    grid-template-columns: repeat(3, minmax(0, 400px));
    justify-content: start;
  }

  /* min-height, not height: at 1440 the content fills exactly 198px inside the
     mockup's 262px card, but on a narrower column the copy needs room to grow. */
  .card { min-height: 262px; }
}

/* ==========================================================================
   F3 · Technologies
   ========================================================================== */

.tech { background: var(--c-surface); padding: var(--sp-10) 0; }

.tech .section-head { margin-bottom: var(--sp-8); }

/* Seven per row where seven fit, fewer where they do not. A horizontally
   scrolling strip would hide half the stack behind a gesture the mockup gives
   no affordance for. */
.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--sp-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.tile {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 10px;
  height: 96px;
  padding: 19.5px var(--sp-5) var(--sp-5);
  border-radius: var(--r-lg);
  box-shadow: inset 0 0 0 1px var(--c-border-tile);
  background: var(--c-surface);
}

.tile__mark { width: 36px; height: 36px; }

.tile__name {
  color: var(--c-text-label);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-medium);
  line-height: 15px;          /* 12px text, mockup box 15 */
}

/* ==========================================================================
   F3 · Case studies
   ========================================================================== */

.cases { background: var(--c-surface-alt); padding: var(--sp-10) 0; }

.cases__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-7);
  margin-bottom: var(--sp-9);
}

.btn--outline {
  box-shadow: inset 0 0 0 1px var(--c-ink);         /* Figma stroke: INSIDE */
  background: transparent;
  color: var(--c-ink);
}

.btn--outline:hover { background: var(--c-ink); color: var(--c-on-dark); opacity: 1; }

.cases__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-7);
}

/* The card's own fill is the section's colour — only its stroke separates it
   from the page, which is what the mockup does. */
.case {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--r-lg);
  box-shadow: inset 0 0 0 1px var(--c-border);
  background: var(--c-surface-alt);
}

.case__media {
  position: relative;
  background: var(--c-ink);   /* shows through the photo's rounded corners */
  line-height: 0;
}

.case__media img { width: 100%; height: auto; }

/* Fill 15%, stroke 50%, text 100% — one colour at three strengths. */
.tag {
  position: absolute;
  left: var(--sp-7);
  bottom: 27px;
  padding: 5px var(--sp-4);
  border-radius: 100px;
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-tag);
  line-height: 13px;
}

.tag--flag {
  box-shadow: inset 0 0 0 1px rgba(255, 107, 53, 0.5);
  background: rgba(255, 107, 53, 0.15);
  color: var(--c-flag);
}

.tag--teal {
  box-shadow: inset 0 0 0 1px rgba(0, 181, 173, 0.5);
  background: rgba(0, 181, 173, 0.15);
  color: var(--c-accent);
}

.case__body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-5);
  padding: var(--sp-7) 28px;
}

.case__title {
  margin: 0;
  color: var(--c-ink);
  font-size: var(--fs-h3);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-hair);
  line-height: 26px;          /* 20px text, two lines in the mockup's 52px box */
}

.case__desc {
  margin: 0;
  color: var(--c-text-muted);
  font-size: var(--fs-sm);
  line-height: 22px;          /* 14px text, two lines in the mockup's 44px box */
}

/* The facts are text now, not figures (the client's §5, F10): a bold line over
   its gloss, stacked — side by side they would get ~120px each between 1200 and
   1440. margin-top: auto sends them to the card's foot, where the link used to
   be, so the three cards' facts line up whatever their descriptions' length. */
.case__stats { display: grid; gap: var(--sp-4); margin: auto 0 0; }

.case__stats dt {
  color: var(--c-ink);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-bold);
  line-height: 20px;
}

.case__stats dd {
  margin: 2px 0 0;
  color: var(--c-text-muted);
  font-size: var(--fs-xs);
  line-height: 18px;
}

@media (min-width: 640px) {
  .cases__grid { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1000px) {
  .cases__head { flex-direction: row; justify-content: space-between; align-items: flex-start; }
  .cases__grid { grid-template-columns: repeat(3, 1fr); }
}

@media (min-width: 1200px) {
  .tech { padding: var(--sp-13) 0; }
  .tech .section-head { margin-bottom: 48px; }
  .tiles { grid-template-columns: repeat(7, 1fr); }

  .cases { padding: var(--sp-13) 0; }
  .cases__head { margin-bottom: 56px; }
}

/* ==========================================================================
   F4 · How we work
   ========================================================================== */

/* bg-process.jpg is the image node already composited at its 20% opacity over
   #0b1d35, so the section's own colour is the same colour the art was baked
   over: wherever the image does not reach — and below 1200 the stacked steps
   make the section much taller than the art — the seam is invisible. Anchored
   top-left at the mockup's offset rather than `cover`, which would rescale the
   framing the designer chose. */
.process {
  padding: var(--sp-10) 0;
  background-color: var(--c-ink);
  background-image: url('../assets/img/bg-process.jpg');
  background-repeat: no-repeat;
  background-position: -154px -214px;
  color: var(--c-on-dark);
}

.section-head--dark .eyebrow { color: var(--c-accent); }
.section-head--dark .section-head__title { color: var(--c-on-dark); }

.process .section-head { margin-bottom: var(--sp-9); }

.steps {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.step {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  padding: var(--sp-9);
  background: var(--c-step-b);
}

/* The panels alternate by position, not by index, so the checker survives the
   two-column layout as well as the four-column one. */
.step:nth-child(odd) { background: var(--c-step-a); }

.step__num {
  margin: 0;
  color: var(--c-accent);
  font-size: var(--fs-stat);
  font-weight: var(--fw-extrabold);
  letter-spacing: var(--ls-tight);
  line-height: 58px;          /* 48px text, mockup box 58 */
}

.step__title {
  margin: 0;
  color: var(--c-on-dark);
  font-size: var(--fs-h3);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-hair);
  line-height: 26px;          /* two lines in the mockup's 52px box */
}

.step__desc {
  margin: 0;
  color: var(--c-on-dark-55);
  font-size: var(--fs-sm);
  line-height: 22px;          /* four lines in the mockup's 88px box */
}

/* ==========================================================================
   F4 · Testimonials
   ========================================================================== */

.testimonials { background: var(--c-surface-alt2); padding: var(--sp-10) 0; }

.testimonials .section-head { margin-bottom: var(--sp-9); }

.quotes {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-7);
}

.quote {
  display: flex;
  flex-direction: column;
  gap: var(--sp-7);
  margin: 0;
  padding: var(--sp-8);
  border-radius: var(--r-lg);
  box-shadow: inset 0 0 0 1px var(--c-border);
  background: var(--c-surface);
}

/* The glyph is #0b1d35 inside a 20% group in the source SVG; the opacity here
   is the group's, kept in CSS so the file stays a plain mark. */
.quote__mark { width: 32px; height: 32px; }

.quote__text {
  margin: 0;
  color: var(--c-ink-75);
  font-size: var(--fs-body-sm);
  line-height: 26px;          /* four lines in the mockup's 104px box */
}

.quote__by { display: flex; align-items: center; gap: var(--sp-4); min-height: 48px; }

.quote__avatar { width: 40px; height: 40px; border-radius: 50%; }

.quote__who { display: flex; flex-direction: column; }

.quote__name {
  color: var(--c-ink);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  line-height: 17px;
}

.quote__role {
  margin-top: 2px;
  color: var(--c-text-muted);
  font-size: var(--fs-2xs);
  line-height: 15px;
}

@media (min-width: 640px) {
  .steps { grid-template-columns: repeat(2, 1fr); }
  .quotes { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1000px) {
  .quotes { grid-template-columns: repeat(3, 1fr); }
}

@media (min-width: 1200px) {
  .process { padding: var(--sp-13) 0; }
  .process .section-head { margin-bottom: 64px; }
  .steps { grid-template-columns: repeat(4, 1fr); }
  .step { min-height: 310px; }

  .testimonials { padding: var(--sp-13) 0; }
  .testimonials .section-head { margin-bottom: 56px; }
}

/* ==========================================================================
   F5 · Closing CTA
   ========================================================================== */

.cta {
  display: flex;
  align-items: center;
  padding: var(--sp-10) 0;
  background-color: var(--c-ink);
  background-image: url('../assets/img/bg-cta.jpg');
  background-repeat: no-repeat;
  background-position: -103px -115px;
  color: var(--c-on-dark);
  text-align: center;
}

.cta__inner { display: flex; flex-direction: column; align-items: center; }

.cta__eyebrow { color: var(--c-accent); }

.cta__title {
  width: 100%;
  max-width: 720px;
  margin: 20px 0 0;           /* the mockup's 20px spacer under the eyebrow */
  font-size: var(--fs-h2-sm);
  font-weight: var(--fw-extrabold);
  letter-spacing: var(--ls-tight);
  line-height: var(--lh-heading);
}

.cta__accent { color: var(--c-accent); }

.cta__sub {
  width: 100%;
  max-width: 560px;
  margin: var(--sp-5) 0 0;
  color: var(--c-on-dark-55);
  font-size: var(--fs-lead);
  line-height: 27px;          /* 17px text, mockup box 27 */
}

.cta__btn {
  margin-top: var(--sp-9);
  padding: 18px var(--sp-9);
  letter-spacing: var(--ls-button);
}

.cta__note {
  margin: var(--sp-5) 0 0;
  color: var(--c-on-dark-35);
  font-size: var(--fs-xs);
  line-height: 16px;
}

/* ==========================================================================
   F5 · Footer
   ========================================================================== */

.footer { background: var(--c-ink-deep); color: var(--c-on-dark); }

.footer__body {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-9);
  padding-top: var(--sp-10);
  padding-bottom: var(--sp-10);
}

.fcol { display: flex; flex-direction: column; gap: var(--sp-4); }

.fcol--brand { gap: var(--sp-5); }

.footer__logo { width: 153.454px; height: 24px; }

.footer__tagline {
  max-width: 260px;
  margin: 0;
  color: var(--c-on-dark-45);
  font-size: var(--fs-xs);
  line-height: 22px;          /* four lines in the mockup's 88px box */
}

.footer__rating { display: flex; align-items: center; min-height: 24px; margin: 0; }

/* The stars, the score and the Clutch mark are one link to the profile; it takes
   over the row's layout so the mockup's spacing is unchanged. */
.footer__rating-link { display: inline-flex; align-items: center; gap: var(--sp-3); color: inherit; text-decoration: none; }
.footer__rating-link:hover .footer__score { text-decoration: underline; }
.footer__rating-link:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 3px; }

.footer__stars {
  color: var(--c-accent);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  line-height: 16px;
}

.footer__score { color: var(--c-on-dark-45); font-size: var(--fs-2xs); line-height: 15px; }

.footer__review { width: 42.34px; height: 12px; margin-left: var(--sp-1); }

.fcol__label {
  /* the mockup puts an 8px spacer under the label, inside a 12px gap */
  margin: 0 0 var(--sp-3);
  color: var(--c-accent);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  line-height: 13px;
}

/* line-height on the list, not just the anchor: the <li>'s own line box comes
   from the inherited body value (25.6px) and would set the row height whatever
   the inline <a> says. */
.fcol__list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  margin: 0;
  padding: 0;
  line-height: 17px;
  list-style: none;
}

.fcol__link {
  color: var(--c-on-dark);
  font-size: var(--fs-sm);
  line-height: 17px;
  text-decoration: none;
}

.fcol__link:hover { color: var(--c-accent); }
.fcol__link:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 3px; }

.fcol__address { color: var(--c-on-dark); font-size: var(--fs-sm); font-style: normal; line-height: 17px; }

.footer__social { display: flex; gap: var(--sp-4); margin: var(--sp-4) 0 0; padding-top: var(--sp-7); }

.social {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--r-md);
  background: var(--c-on-dark-10);
}

.social img { width: 16px; height: 16px; }
.social .social__wide { width: 21.33px; height: 21.33px; }

.social:hover { background: var(--c-on-dark-30); }
.social:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }

.footer__bar {
  box-shadow: inset 0 0 0 1px var(--c-on-dark-08);
  background: var(--c-on-dark-04);
}

.footer__bar-inner {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  align-items: center;
  min-height: 60px;
  justify-content: center;
  padding-top: var(--sp-6);
  padding-bottom: var(--sp-6);
}

.footer__bar-inner p {
  margin: 0;
  color: var(--c-on-dark-60);
  font-size: var(--fs-sm);
  line-height: 17px;
}

@media (min-width: 640px) {
  .footer__body { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1200px) {
  .cta { height: 420px; padding: 0; }
  .cta__title { font-size: var(--fs-h1); line-height: 58px; }  /* two lines in 116 */

  .footer__body {
    grid-template-columns: repeat(4, 1fr);
    gap: 0;
    padding-top: var(--sp-10);
    padding-bottom: var(--sp-10);
  }

  .fcol { min-height: 210px; }

  .footer__bar-inner {
    flex-direction: row;
    justify-content: space-between;
    padding-top: var(--sp-6);
    padding-bottom: var(--sp-6);
  }
}

/* ==========================================================================
   F13 · Contact — the client's form (§3), "in the site's style, without a
   design task of its own": the section-head type, the card surface and the
   primary button the rest of the page already uses.
   ========================================================================== */

.contact { background: var(--c-surface-alt); padding: var(--sp-10) 0; }

.contact__title { margin-bottom: var(--sp-8); }

.contact-form {
  display: grid;
  gap: var(--sp-6);
  max-width: 640px;
  padding: var(--sp-7);
  border-radius: var(--r-lg);
  box-shadow: inset 0 0 0 1px var(--c-border);      /* Figma stroke: INSIDE */
  background: var(--c-surface);
}

.field { display: grid; gap: var(--sp-3); }

.field__label {
  color: var(--c-ink);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-ui);
}

/* 16px text, so a phone does not zoom into the field it focuses. */
.field__input {
  width: 100%;
  margin: 0;
  padding: var(--sp-4) var(--sp-5);
  border: 0;
  border-radius: var(--r-sm);
  box-shadow: inset 0 0 0 1px var(--c-border);
  background: var(--c-surface);
  color: var(--c-ink);
  font: inherit;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.field__input--area { min-height: 160px; resize: vertical; }

.field__input:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }

.field__input[aria-invalid="true"] { box-shadow: inset 0 0 0 1px var(--c-error); }

.field__error {
  margin: 0;
  color: var(--c-error);
  font-size: var(--fs-xs);
  line-height: var(--lh-ui);
}

.contact-form__actions { display: grid; justify-items: start; gap: var(--sp-5); }

.contact-form__status {
  margin: 0;
  color: var(--c-ink);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
}

.contact-form__status:empty { display: none; }

.contact-form__status[data-state="failed"] { color: var(--c-error); }

@media (min-width: 768px) {
  .contact-form { padding: var(--sp-9); }
}

@media (min-width: 1200px) {
  .contact { padding: var(--sp-13) 0; }
}

/* ==========================================================================
   F16 · Privacy Policy and Terms of Use — the current site's own texts, on
   the contact page's surface with the section-head title. Long-form reading:
   a measure of about 70 characters, body copy as the rest of the site sets it,
   headings in ink at the card-title sizes.
   ========================================================================== */

.legal { background: var(--c-surface-alt); padding: var(--sp-10) 0; }

.legal__title { margin-bottom: var(--sp-8); }

.legal__body { max-width: 760px; color: var(--c-text-muted); }

.legal__body h2,
.legal__body h3 {
  margin: var(--sp-9) 0 var(--sp-5);
  color: var(--c-ink);
  line-height: var(--lh-title);
}

.legal__body h2 { font-size: var(--fs-h3); font-weight: var(--fw-bold); letter-spacing: var(--ls-hair); }

.legal__body h3 { margin-top: var(--sp-8); font-size: var(--fs-h4); font-weight: var(--fw-semibold); }

.legal__body p,
.legal__body ul { margin: 0 0 var(--sp-5); }

.legal__body ul { padding-left: var(--sp-6); }

.legal__body li { margin-bottom: var(--sp-3); }

/* The text quotes a URL with no break opportunity of its own. */
.legal__body p { overflow-wrap: anywhere; }

@media (min-width: 1200px) {
  .legal { padding: var(--sp-13) 0; }
}
