/* ==========================================================================
   TrustUs homepage
   Page-specific only. The tokens, typography, containers, buttons and the
   floating header are in tu-system.css, which loads before this.
   ========================================================================== */

/* 1. Hero -----------------------------------------------------------------
   One continuous background with the copy rotating over it. Nothing slides,
   so there is no scroll container and none of the RTL scroll arithmetic the
   carousel needed. overflow:hidden still matters: the background is scaled
   slightly and would otherwise push the page sideways. */
.hp-hero {
  position: relative;
  background: var(--dark);
  overflow: hidden;
  isolation: isolate;
  display: flex;
  align-items: flex-end;
  min-height: min(86vh, 800px);
  min-height: min(86dvh, 800px);

}

.hp-hero__bg {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  z-index: -2;
}

/* The two full-bleed grounds are now <picture>, so that a phone can be sent a
   WebP a fifth of the size. The wrapper must not become a box of its own: the
   image inside it is positioned against the section, and an inline <picture>
   in the flow would add a line box above the copy. display: contents leaves
   the <img> exactly where it was.
   The video sits over the photograph by document order — both are z-index -2 —
   and draws nothing until it has a frame, which is what lets the photograph
   carry the hero on its own until then, and keep carrying it if the video is
   never loaded. */
.hp-hero > picture,
.hp-exp > picture { display: contents; }

/* Held back until it has a frame to show.
   A <video> with nothing loaded draws nothing in most browsers, but Safari on
   iOS paints a black rectangle over whatever is behind it, which would hide
   the photograph exactly on the devices most likely never to load the file at
   all. Fading it in on canplay makes "no video yet" and "no video ever" the
   same state everywhere: the photograph. */
.hp-hero__bg--video {
  opacity: 0;
  transition: opacity .5s ease;
}
.hp-hero__bg--video.is-ready { opacity: 1; }

/* In the column, though, it is an ordinary block: inline would leave the
   figure a baseline's worth of space taller than its picture. */
.hp-about__figure picture { display: block; }

.hp-hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(255deg,
      rgba(16, 13, 18, 0) 0%,
      rgba(18, 14, 20, .42) 46%,
      rgba(20, 15, 22, .76) 100%),
    linear-gradient(180deg,
      rgba(128, 0, 24, 0) 18%,
      rgba(131, 0, 25, .30) 46%,
      rgba(136, 0, 26, .62) 72%,
      rgba(143, 2, 28, .84) 100%),
    linear-gradient(180deg, rgba(12, 8, 12, .5) 0%, transparent 22%);
}

.hp-hero__inner {
  position: relative;
  /* A flex item with `width: auto` is sized by its content, and the floating
     header's wrap override sets exactly that — so the hero's measure was the
     copy's own width, 644px against the 1152 every other section uses, and the
     empty half of the hero was not part of this box at all. Growing it is what
     lets anything be placed opposite the copy; the copy itself does not move,
     because its lines are capped by their own measures. */
  flex: 1 1 auto;
  /* The copy ends at the bottom of this box and stacks upward, so the bottom
     padding is what sets its height on screen — raising it lifts the whole
     block while leaving the button on the same line for every slide, which is
     the point of anchoring it there. It was sitting too low against the trust
     bar. */
  padding-block: clamp(92px, 10vw, 124px) calc(var(--hero-bar) + clamp(76px, 9vw, 136px));
  display: grid;              /* messages stack in one cell and cross-fade */
  /* Explicit, and full width. The implicit column was sized to the copy, so
     anything else placed in that cell could only be positioned inside the
     copy's own box — the marks landed on top of the button instead of in the
     empty half beside it. The copy is capped by its own children's measures,
     so widening the track does not move it. */
  grid-template-columns: minmax(0, 1fr);
}
.hp-hero { --hero-bar: 70px; }

/* Bottom-anchored, not top-anchored. The four messages are two, three and four
   lines long, so aligning them from the top moved the lead and the button by a
   line and a half every time the copy changed. Anchoring the column to its
   bottom edge instead lets the heading grow upward and leaves the button on
   one fixed line for every slide. */
.hp-msg {
  grid-area: 1 / 1;
  align-self: end;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;

  opacity: 0;
  visibility: hidden;
  transform: translateY(16px);
  transition: opacity .5s ease, transform .5s cubic-bezier(.22,.7,.3,1), visibility .5s;
}
.hp-msg.is-on { opacity: 1; visibility: visible; transform: none; }

/* The first message is the page's h1; the rest are paragraphs styled to match,
   so rotating copy never produces four competing headings in the outline.
   `.hp` is on the selector because the rest are <p>: without it this is (0,1,0)
   and loses to the `.hp p` default at (0,1,1), which shrank the rotating hero
   copy to body size while the h1 stayed large. */
.hp .hp-msg h1,
.hp .hp-msg__title {
  margin: 0 0 var(--sp-4);
  color: #fff;
  font-weight: 800;
  font-size: var(--fs-display);
  /* 1.2 is a Latin display leading. Arabic sets taller than Latin at the same
     size — the alif with its hamza, the lam, and the marks above them — so at
     1.2 the shadda on one line was landing on the line under it. */
  line-height: 1.45;
  max-width: 22ch;
  text-wrap: balance;
}
.hp-msg__lead { color: var(--on-dark-soft); font-size: var(--fs-lead); max-width: 44ch; margin: 0 0 var(--sp-5); }

/* Foot bar: the real numbers on one side, the message markers on the other. */
/* The registrations, in the half of the hero the copy leaves empty. In an RTL
   page the copy starts at the right, so `justify-self: end` puts these on the
   left; they share the messages' grid cell rather than taking a column of their
   own, so nothing about the copy's own layout changes. No panel behind them:
   the hero's left side measures 46/255 in luminance, dark enough for the white
   marks to carry themselves, and a card here would be a second surface doing
   the background's job. */
/* In the hero's own grid cell, so they sit on the picture rather than under it.
   `justify-self: end` is the left in an RTL page — the half the copy leaves
   empty — and `align-self: end` puts them on the copy's own last line. They
   share the messages' cell rather than taking a column, so nothing about the
   copy's layout changes. */
.hp-hero__marks {
  grid-area: 1 / 1;
  z-index: 2;
  justify-self: end;
  align-self: end;
  list-style: none; margin: 0; padding: 0;
  display: flex;
  align-items: center;
  gap: clamp(var(--sp-5), 3vw, var(--sp-6));
  /* The button's own row, not merely its baseline. Both are anchored to the
     bottom of the hero's cell, so their bottoms already matched — but the marks
     are sized by clamp() and the row shrank with the window: at 1280 it stood
     6px shorter than the button, at 1024 10px, and the two stopped reading as
     one line. Holding the row to the button's height keeps them level at every
     width, and it is the same number, not a copy of it. */
  min-height: var(--btn-h);
}
/* Sized by height with the width left free, and a different height per shape.
   One box for all three put a 5:1 wordmark and a 1:1 seal on the same line and
   the seal came out a third of the size — `contain` fits a square to the box's
   short edge. These heights are chosen so the three read as equals. */
.hp-hero__marks img {
  display: block;
  width: auto;
  max-width: clamp(120px, 11vw, 160px);
  opacity: .78;
  transition: opacity .2s ease;
}
.hp-hero__marks li[data-shape="block"] img { height: clamp(34px, 2.9vw, 42px); }
.hp-hero__marks li[data-shape="wide"]  img { height: clamp(22px, 1.8vw, 26px); }
.hp-hero__marks li[data-shape="seal"]  img { height: clamp(42px, 3.6vw, 52px); }
.hp-hero__marks li:hover img { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .hp-hero__marks img { transition: none; } }

/* On a phone the copy fills the width, so there is no empty half beside it:
   the marks take a row of their own under the copy, still on the picture.
   `.hp` on the front because tu-system.css strips the padding off every list
   inside the page with `.hp ul`, which is (0,1,1) and beats a single class. */
@media (max-width: 900px) {
  .hp-hero__inner { grid-template-rows: 1fr auto; }
  .hp .hp-hero__marks {
    grid-area: 2 / 1;
    justify-self: center;
    gap: var(--sp-5);
    padding: var(--sp-7) 0 0;
  }
  .hp-hero__marks li[data-shape="block"] img { height: 28px; }
  .hp-hero__marks li[data-shape="wide"]  img { height: 18px; }
  .hp-hero__marks li[data-shape="seal"]  img { height: 34px; }
}


.hp-hero__bar {
  position: absolute; inset-inline: 0; bottom: 0; z-index: 3;
  --hero-bar-bg: var(--dark);
  /* `--hero-bar` is what the copy's bottom padding is built from, but the bar
     itself was 65px, so the variable was five pixels short of the truth and
     anything measured from the bar landed off the copy's last line. Fixed only
     where the bar is one row; the phone stacks it and sets its own height. */
  min-height: var(--hero-bar);
  border-top: 1px solid rgba(255, 255, 255, .16);
  background: linear-gradient(180deg, transparent, rgba(27, 7, 16, .55));
}
.hp-hero__bar-in {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-5); padding-block: var(--sp-4); flex-wrap: wrap;
}
.hp-hero__trust { display: flex; gap: clamp(16px, 2.4vw, 34px); flex-wrap: wrap; }
.hp-hero__trust div { display: flex; align-items: baseline; gap: var(--sp-2); }
.hp-hero__trust b { color: #fff; font-size: var(--fs-h4); font-weight: 800; font-variant-numeric: tabular-nums; }
.hp-hero__trust span { color: rgba(255, 255, 255, .6); font-size: var(--fs-caption); }
.hp-hero__stars { color: #e8b04b; letter-spacing: 1px; font-size: var(--fs-caption); }
.hp-trust__l--short { display: none; }
/* One line for the three figures. The full wording wrapped them onto two and
   left the last one alone, so the phone takes the shorter labels, drops the
   stars — the 5.0 beside them says the same thing — and stops the row wrapping
   at all. */
@media (max-width: 700px) {
  .hp-hero__trust { flex-wrap: nowrap; gap: var(--sp-4); }
  .hp-hero__stars { display: none; }
  .hp-hero__trust b { font-size: var(--fs-body); }
  .hp-hero__trust span { font-size: var(--fs-caption); white-space: nowrap; }
  .hp-trust__l { display: none; }
  .hp-trust__l--short { display: inline; }
}

.hp-dots { display: flex; gap: var(--sp-2); align-items: center; }
.hp-dot { background: none; border: 0; padding: var(--sp-2) 0; cursor: pointer; width: 26px; display: block; }
.hp-dot i { display: block; height: 2px; background: rgba(255, 255, 255, .35); transition: background-color .25s ease; }
.hp-dot.is-on { width: 46px; }
.hp-dot.is-on i { background: #fff; }
.hp-dot:hover i { background: rgba(255, 255, 255, .7); }

/* 3. About ---------------------------------------------------------------- */
.hp-about__grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(36px, 6vw, 84px); align-items: center; }
.hp-about p { margin: 0 0 var(--sp-5); }
.hp-about p:last-of-type { margin-bottom: 0; }

/* Three words, so they are set as three words: the brand red, spaced, with a
   rule above to separate them from the paragraph they follow. `.hp` on the
   front because tu-system's `.hp p` is (0,1,1) and would keep the body size. */
.hp .hp-about__values {
  margin-top: clamp(var(--sp-5), 3vw, var(--sp-6));
  padding-top: clamp(var(--sp-5), 3vw, var(--sp-6));
  border-top: 1px solid var(--line);
  color: var(--red);
  font-size: clamp(17px, 1.5vw, 21px);
  font-weight: 800;
  letter-spacing: 0;
}
.hp .hp-about__values strong { font-weight: 800; }
.hp-about__figure { position: relative; }
/* A picture set into the layout, so it takes the surface corner. It was the
   only one on the site left square, next to About's pictures and the blog
   cards, which are not. The hero and the experience band stay square because
   they are full-bleed grounds, not pictures in a column, and so do the client
   logos. */
.hp-about__figure img {
  width: 100%; aspect-ratio: 5/4; height: auto; object-fit: cover;
  border-radius: var(--r-surface);
}
/* An offset frame instead of a shadow: quieter, and it echoes the hairlines. */
.hp-about__figure::before {
  content: ""; position: absolute; inset: -16px -16px 16px 16px;
  border: 1px solid var(--line); z-index: -1;
}

/* 4. Services index ------------------------------------------------------- */
/* Numbered rows rather than six shadowed tiles: a firm's service list reads as
   a considered index, and the numbering is true information — there are six. */
.hp-svc__list { border-top: 1px solid var(--line); }
.hp-svc__row {
  display: grid; grid-template-columns: 46px 1fr 1.35fr auto;
  gap: clamp(16px, 3vw, 40px); align-items: center;
  padding-block: clamp(22px, 2.6vw, 34px);
  border-bottom: 1px solid var(--line);
  position: relative; transition: background-color .25s ease;
}
.hp-svc__row:hover { background: var(--wash); }
.hp-svc__row h3 { font-size: var(--fs-h3); }
.hp-svc__row p { margin: 0; font-size: var(--fs-body); line-height: 1.75; }
.hp-svc__go {
  width: 44px; height: 44px; border: 1px solid var(--line); border-radius: 50%;
  display: grid; place-items: center; color: var(--red); flex: none;
  transition: background-color .25s ease, border-color .25s ease, color .25s ease;
}
.hp-svc__go::after { content: ""; position: absolute; inset: 0; }
.hp-svc__row:hover .hp-svc__go { background: var(--red); border-color: var(--red); color: #fff; }
.hp-svc__go svg { width: 17px; height: 17px; }
/* The original service icons, back in the row. Tinted to the brand red so six
   different illustrations read as one set rather than six separate pictures. */
.hp-svc__icon {
  width: 38px; height: 38px; object-fit: contain;
  opacity: .92;
  transition: transform .25s ease;
}
.hp-svc__row:hover .hp-svc__icon { transform: scale(1.08); }
.hp-svc__actions { margin-top: clamp(30px, 4vw, 46px); }

/* 5. Experience band ------------------------------------------------------ */
.hp-exp { position: relative; background: var(--dark); color: #fff; overflow: hidden; isolation: isolate; }
.hp-exp__bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; }
/* Two scrims, not one.
   The old single diagonal left the bottom of the photograph bright, so the CTA
   and the numbers sat on the busiest part of the bridge with nothing behind
   them. A vertical darkening carries legibility everywhere, and the diagonal
   on top only deepens the reading side. */
/* The photograph is a night shot, so it carries white text almost on its own.
   The scrim only deepens the reading side enough for contrast; anything more
   and the city lights - the reason to use this picture - go flat. */
.hp-exp::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  /* Reaches further across than before: the numbers moved out to the far side
     of the band and needed ground under them too. Still a gradient, so the
     lit half of the city is not flattened. */
  background: linear-gradient(
    to left,
    rgba(10, 8, 14, .74) 0%,
    rgba(10, 8, 14, .66) 34%,
    rgba(10, 8, 14, .46) 62%,
    rgba(10, 8, 14, .18) 88%,
    rgba(10, 8, 14, .08) 100%
  );
}
[dir="ltr"] .hp-exp::after { transform: scaleX(-1); }

/* The source is 1000px wide and this band is full-bleed, so it is being
   upscaled on wide screens. Held slightly soft rather than sharpened, which
   would only make the enlargement obvious. */
.hp-exp__bg { filter: saturate(1.04); }

/* A single column, not a two-column split. The copy and the numbers were on
   opposite sides with nothing aligning them; stacking puts every element on the
   one line the rest of the page uses. */
.hp-exp__inner {
  /* Copy and numbers on one line. Stacked, the copy sat in the right-hand half
     and the whole left of the frame was empty; side by side the content spans
     the band and the section stops reading as half-used. */
  padding-block: clamp(var(--sp-7), 5.5vw, 76px);
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: clamp(var(--sp-6), 5vw, 72px);
}

.hp-exp__copy { max-width: 54ch; }

.hp-exp h2 {
  color: #fff;
  /* Carries the last of the legibility so the scrim doesn't have to be heavier
     than the photograph can take. */
  text-shadow: 0 1px 18px rgba(0, 0, 0, .55);
  font-size: var(--fs-h2);
  line-height: 1.42;
  /* Was 20ch, which broke this heading into four ragged lines that ran into
     the flag in the photograph. 34ch holds it to two. */
  max-width: 34ch;
}
.hp-exp p { margin: var(--sp-4) 0 0; color: rgba(255,255,255,.88); max-width: 52ch; text-shadow: 0 1px 14px rgba(0,0,0,.5); }
.hp-exp__act { margin-top: var(--sp-6) !important; }

/* The numbers now sit in one bar under the copy, separated by a hairline, so
   they read as a footer to the statement instead of floating over the water. */
/* A column beside the copy, not a bar beneath it. The rule runs down the inline
   edge because it now separates two columns rather than two stacked blocks. */
.hp-exp__bar {
  /* The three sit in a row, not a stack: stacked they turned the band into a
     tall column and pushed the section height back up. */
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(var(--sp-4), 2vw, var(--sp-5));
  padding-inline-start: clamp(var(--sp-5), 2.6vw, var(--sp-6));
  border-inline-start: 1px solid var(--on-dark-faint);
}
.hp-exp__stat { border: 0; padding: 0; }
.hp-exp__stat b {
  display: block; color: #fff; font-size: var(--fs-stat);
  font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 14px rgba(0, 0, 0, .6);
}
.hp-exp__stat span {
  display: block; margin-top: var(--sp-2);
  color: var(--on-dark-soft); font-size: var(--fs-small); line-height: 1.5;
  text-shadow: 0 1px 10px rgba(0, 0, 0, .65);
}

/* The red keeps its role from the rest of the page: a short accent mark, not a
   full border down the side of every number. */
.hp-exp__stat b::after {
  content: ""; display: block; width: 26px; height: 2px;
  background: var(--red); margin-top: var(--sp-3);
}

@media (max-width: 860px) {
  /* Back to stacked: two columns at this width leave neither enough room. */
  .hp-exp__inner { grid-template-columns: 1fr; }
  .hp-exp__bar {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    padding-inline-start: 0;
    border-inline-start: 0;
    padding-top: var(--sp-5);
    border-top: 1px solid var(--on-dark-faint);
  }
}
@media (max-width: 560px) {
  .hp-exp__bar { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: var(--sp-5); }
}

/* 6. Clients -------------------------------------------------------------- */
/* Inside the reviews section now, not a section of its own: a rule above it
   and the section's own spacing below, so it closes that section rather than
   being a 180px strip of its own between two bands. */
.hp-clients {
  margin-top: clamp(var(--sp-6), 5vw, var(--sp-7));
  padding-top: clamp(var(--sp-6), 5vw, var(--sp-7));
  border-top: 1px solid var(--line);
}
.hp-clients__band { display: flex; align-items: center; gap: clamp(24px,5vw,64px); flex-wrap: wrap; }
.hp-clients__label { flex: 0 0 auto; max-width: 220px; }
.hp-clients__label h3 { font-size: var(--fs-h4); margin: 0; }
.hp-clients__label p { margin: var(--sp-1) 0 0; font-size: var(--fs-small); }
/* The strip drifts because there are twenty-odd logos now — far more than fit
   on one line — and a wrapped grid of that many would take over the section. */
.hp-clients__marquee {
  flex: 1 1 420px;
  min-width: 0;
  overflow: hidden;
  display: flex;
  width: 100%;
  /* Both ends fade so logos arrive and leave instead of being clipped. */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}
.hp-clients__logos {
  flex: none;
  display: flex; align-items: center;
  gap: clamp(var(--sp-6), 4vw, var(--sp-7));
  padding-inline-end: clamp(var(--sp-6), 4vw, var(--sp-7));
  /* Travels exactly one copy's width, so the reset is invisible. */
  animation: hp-logos-run 60s linear infinite;
}
.hp-clients__marquee:hover .hp-clients__logos { animation-play-state: paused; }

@keyframes hp-logos-run {
  from { transform: translateX(0); }
  to   { transform: translateX(-100%); }
}
[dir="rtl"] .hp-clients__logos { animation-name: hp-logos-run-rtl; }
@keyframes hp-logos-run-rtl {
  from { transform: translateX(0); }
  to   { transform: translateX(100%); }
}

@media (prefers-reduced-motion: reduce) {
  .hp-clients__logos { animation: none; }
  .hp-clients__marquee { overflow-x: auto; }
  .hp-clients__logos:last-child { display: none; }
}
.hp-clients__logos img { flex: none; max-height: 44px; width: auto; width: auto; object-fit: contain; filter: grayscale(1); opacity: .55; transition: filter .25s ease, opacity .25s ease; }
.hp-clients__logos img:hover { filter: none; opacity: 1; }

/* 7. Reviews -------------------------------------------------------------- */
.hp-rev__grid { display: grid; grid-template-columns: 290px 1fr; gap: clamp(28px,4vw,56px); align-items: start; }
.hp-score { border: 1px solid var(--line); border-radius: var(--r-surface); padding: var(--card-pad); background: var(--paper); }
.hp-score b { display: block; font-size: var(--fs-stat); font-weight: 800; color: var(--ink); line-height: 1; font-variant-numeric: tabular-nums; }
.hp-score__stars { color: #e8b04b; font-size: var(--fs-h4); letter-spacing: 3px; margin-top: var(--sp-3); }
.hp-score p { margin: var(--sp-3) 0 0; font-size: var(--fs-body); }
.hp-score p strong { color: var(--ink); }
.hp-score a { display: inline-block; margin-top: var(--sp-4); color: var(--red); font-weight: 800; font-size: var(--fs-small); border-bottom: 1.5px solid currentColor; }



/* 8. Blog ----------------------------------------------------------------- */
.hp-blog__list { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(22px,3vw,30px); margin-bottom: var(--sp-7); }

/* Real cards, like the live site. Previously the images sat bare on the section
   background with the text floating under them, so three posts read as loose
   fragments rather than three things of the same kind. Border and radius carry
   that here — no shadow anywhere on this page, per the brief. */
.hp-post {
  display: flex; flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-surface);
  overflow: hidden;
  transition: border-color .25s ease, transform .25s ease;
}
.hp-post:hover { border-color: var(--red-edge); transform: translateY(-3px); }
@media (prefers-reduced-motion: reduce) {
  .hp-post, .hp-post:hover { transition: none; transform: none; }
}

.hp-post__media { display: block; line-height: 0; background: var(--wash); }
.hp-post__thumb {
  width: 100%; aspect-ratio: 3/2; height: auto; object-fit: cover;
  /* height: auto is what makes the ratio above work. WordPress prints width and
     height attributes on the images it generates, and those act as the
     specified size — aspect-ratio only applies when one axis is auto, so the
     ratio was being written and ignored on exactly the images WordPress
     produces. The blog thumbnails were rendering at their attribute height,
     432px in a 341px column, instead of the 3:2 asked for here. */
  /* No bottom margin now: the image is flush inside the card, and the padding
     below belongs to the body rather than to the picture. */
  margin: 0;
  transition: transform .4s ease;
}
.hp-post:hover .hp-post__thumb { transform: scale(1.04); }
@media (prefers-reduced-motion: reduce) {
  .hp-post:hover .hp-post__thumb { transform: none; }
}

/* Padding lives on the body so cards of different text lengths still line their
   images and their first line of copy up across the row. */
.hp-post__body { padding: var(--card-pad); display: flex; flex-direction: column; flex: 1; }
.hp-post h3 { font-size: var(--fs-h3); line-height: 1.55; margin: 0 0 var(--sp-3); }
.hp-post h3 a { color: var(--ink); }
.hp-post h3 a:hover { color: var(--red); }
.hp-post__cat { display: block; font-size: var(--fs-caption); font-weight: 800; color: var(--red); margin-bottom: var(--sp-3); }
.hp-post p { margin: 0; font-size: var(--fs-body); line-height: 1.75; }

/* Centred under the row rather than hanging off the last card, where it read as
   part of that post instead of as the section's action. */
.hp-blog__actions { display: flex; justify-content: center; }

/* Two section heads that do not take the page's default.

   Reviews: the heading and the line under it read as one statement and were
   taking two, above a summary bar that is already a single row. Side by side
   they are one line, and the section starts at the figures sooner. It falls
   back to stacked when the two no longer fit.

   The blog: centred, because what follows is three equal cards rather than a
   column of rows — a head aligned to one edge left the row looking hung off
   it. The eyebrow is already a flex row, so centring it carries its rule and
   its label together rather than leaving the rule hanging off the text. */
.hp-rv .hp-head {
  max-width: none;
  display: flex;
  align-items: baseline;
  gap: var(--sp-5);
  flex-wrap: wrap;
}
/* Next to the heading, not opposite it. Pushed to the far edge they were two
   things at either end of an empty row rather than one sentence continuing;
   the line reads from the heading straight into it. A rule between them, so
   the eye has the join. */
.hp-rv .hp-head h2 { margin: 0; }
.hp-rv .hp-head p {
  margin: 0;
  max-width: 54ch;
  padding-inline-start: var(--sp-5);
  border-inline-start: 1px solid var(--line);
}

.hp-blog .hp-eyebrow { justify-content: center; }
.hp-blog .hp-head { max-width: 62ch; margin-inline: auto; text-align: center; }

/* 9. FAQ ------------------------------------------------------------------ */
/* Moved to assets/tu-faq.css: About uses the same accordion, and two copies of
   it would have drifted. */

/* 10. Closing CTA --------------------------------------------------------- */
.hp-cta { background: var(--dark); color: #fff; padding-block: clamp(56px, 7vw, 96px); }
.hp-cta__grid { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-6); flex-wrap: wrap; }
.hp-cta h2 { color: #fff; font-size: var(--fs-h2); max-width: 20ch; }
.hp-cta p { margin: var(--sp-4) 0 0; color: rgba(255,255,255,.75); max-width: 46ch; }
.hp-cta__actions { display: flex; gap: var(--sp-4); align-items: center; flex-wrap: wrap; }

/* Responsive -------------------------------------------------------------- */
@media (max-width: 1024px) {
  .hp-blog__list { grid-template-columns: repeat(2, 1fr); }
  .hp-svc__row { grid-template-columns: 40px 1fr auto; }
  .hp-svc__row p { grid-column: 2 / -1; }
  .hp-svc__icon { width: 32px; height: 32px; }
}
@media (max-width: 700px) {
  .hp { font-size: var(--fs-body); }
  .hp-blog__list { grid-template-columns: 1fr; }

  /* On a narrow screen the bar wraps to two or three rows, and any reserved
     height is a guess that eventually cuts through the button again. Taking it
     out of the overlay and letting it sit under the image removes the whole
     class of collision.

     The hero is a flex row, so a bar that is no longer absolute becomes a flex
     item and stands BESIDE the copy — which is exactly what it was doing: the
     copy squeezed into 149px on one side and the numbers into 209px on the
     other. The hero has to become a column for the two to stack. */
  /* The bar stacks under the picture here rather than sitting on it, so this
     height is the picture alone and the section is that much taller again.
     Raised so the picture still reads as a picture now that it carries the
     marks as well as the copy. */
  .hp-hero { flex-direction: column; align-items: stretch; min-height: min(94dvh, 780px); }
  .hp-hero__inner {
    flex: 1 1 auto;
    /* The header floats over the picture at --hd-float-h, and the copy is
       bottom-anchored, so this padding is all that stands between the heading
       and the bar. The desktop clamp bottoms out at 92px here, which left 4px
       of air: the first line of the headline was touching the menu. */
    padding-block-start: calc(var(--hd-float-h) + clamp(32px, 8vw, 52px));
  }
  .hp-hero__bar {
    position: static;
    flex: 0 0 auto;
    width: 100%;
    /* Below the picture here, so it paints its own ground rather than fading
       into one. */
    background: var(--hero-bar-bg);
    border-top: 0;
  }

  /* The reserved strip was there to keep the copy clear of an overlaid bar.
     The bar is in the flow now, so reserving it only pushes the copy up into
     the middle of nowhere. */
  .hp-hero { --hero-bar: 0px; }
  .hp-hero__bar-in {
    justify-content: flex-start;
    align-items: flex-start;
    flex-direction: column;
    gap: var(--sp-4);
    padding-block: var(--sp-5);
  }
  /* Three numbers is one too many on a phone: the row wrapped and the middle
     one landed alone on its own line. The rating and the years carry the point;
     the review count is repeated in full in the reviews section below. */
  .hp-hero__trust { justify-content: center; width: 100%; }
  .hp-hero__bar-in { align-items: center; }
  .hp-dots { align-self: center; }
  .hp-svc__go { width: 38px; height: 38px; }
}
@media (prefers-reduced-motion: reduce) { .hp * { transition: none !important; } }



/* ==========================================================================
   Framed treatment (this template only)
   A white capsule menu floating over a light ground, and the hero inset as a
   rounded panel rather than running edge to edge. No shadows anywhere — depth
   comes from the inset itself, not from a drop shadow.
   ========================================================================== */

/* The palette lives on .hp, which wraps the page content — the header is a
   sibling of it, so every var(--red) in the header rules below resolved to
   nothing. Re-declaring the tokens at body level puts them in scope for both. */
/* :root, not a page-template class.
   These tokens have now been chased across three scopes. On .hp they could not
   reach the header, which is a sibling rather than a child. On the homepage's
   body class they could not reach the About template, which does not carry that
   class — every section there lost its padding because --section resolved to
   nothing. This stylesheet is enqueued per template, so anything that loads it
   wants the whole system: header, footer, and any page built on it. */

/* --- Hero as an inset frame --- */
.tu-dark-hero .hp-hero {
  /* Full bleed: the inset left a white border around the photograph that read
     as padding rather than as a deliberate frame. */
  margin: 0;
  border-radius: 0;
}

/* The top scrim existed to hold a transparent menu over the photo; the capsule
   sits on white above the frame now, so it is no longer needed. */
.tu-dark-hero .hp-hero::before { display: none; }

/* No shadows, per the brief — on the capsule, the frame, or anything inside. */
.tu-dark-hero .hp-hero,
.tu-dark-hero .hp-score { box-shadow: none; }

/* Dropdowns hang off a white bar now, so they need a light panel. */

@media (max-width: 1100px) {
  .tu-dark-hero .hp-hero { margin: 0; }
}




/* ==========================================================================
   Content width matched to the menu and the hero frame
   The sections were capped at 1200px and centred while the frame ran to
   1372px, so every section sat inside the frame's edges. All three now share
   one inset, and one inner gutter keeps text off the edge.
   ========================================================================== */





/* --- Services: folded rows + the two buttons under the list --- */

/* Folded rows are removed from layout, not just faded — a hidden row must not
   leave a gap or be reachable by Tab. .is-folded is dropped by the button. */
.tu-dark-hero .hp-svc__row.is-folded { display: none; }

/* Rows revealed by the button ease in, so two appearing at once reads as an
   expansion rather than a jump. Rows present on load are not animated. */
@keyframes hp-svc-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
.tu-dark-hero .hp-svc__row.is-revealed { animation: hp-svc-in .28s ease both; }
@media (prefers-reduced-motion: reduce) {
  .tu-dark-hero .hp-svc__row.is-revealed { animation: none; }
}

/* Both actions grouped at the start. They were pinned to opposite ends of the
   row, which read as two unrelated controls with a gap of nothing between
   them; side by side they read as one pair. */
.tu-dark-hero .hp-svc__actions {
  display: flex; align-items: center; justify-content: flex-start;
  gap: var(--sp-4); flex-wrap: wrap;
  margin-top: var(--sp-6);
}

/* The reveal button is secondary to the solid services link, so it is outlined.
   Same height and padding as .hp-btn, so the pair sits on one baseline. */
.tu-dark-hero .hp-btn--ghost {
  background: transparent;
  color: var(--red);
  border: 1px solid var(--red-edge);
}
.tu-dark-hero .hp-btn--ghost:hover {
  background: var(--red-tint);
  border-color: var(--red);
}

/* With JS off nothing can unfold, so the button would be a dead control —
   hide it and let all twelve rows show instead. */
.no-js .tu-dark-hero [data-svc-more] { display: none; }
.no-js .tu-dark-hero .hp-svc__row.is-folded { display: grid; }

@media (max-width: 640px) {
  .tu-dark-hero .hp-svc__actions { flex-direction: column; align-items: stretch; }
  .tu-dark-hero .hp-svc__actions .hp-btn { text-align: center; }
}

/* --- Ticker: newest posts, flush under the hero ------------------------- */

.hp-ticker {
  background: var(--wash);
  border-bottom: 1px solid var(--line);
  /* No top border and no margin: it has to sit against the hero, not below it. */
  overflow: hidden;
}

/* The mask holds the two copies side by side and fades both ends, so items
   arrive and leave instead of being cut off at the edge. */
.hp-ticker__mask {
  display: flex;
  width: max-content;
  animation: hp-ticker-run 46s linear infinite;
  /* In RTL the natural reading direction is right-to-left, so the strip travels
     the same way rather than against it. */
}
.hp-ticker:hover .hp-ticker__mask,
.hp-ticker:focus-within .hp-ticker__mask { animation-play-state: paused; }

@keyframes hp-ticker-run {
  /* Exactly one copy's width: the second copy is already where the first
     started, so the reset is invisible. */
  from { transform: translateX(0); }
  to   { transform: translateX(50%); }
}

.hp-ticker__track {
  display: flex; align-items: center;
  margin: 0; padding: 0; list-style: none;
  flex: none;
}

.hp-ticker__item { flex: none; }
.hp-ticker__item::after {
  /* A dot between items rather than a rule — lighter, and it never collides
     with a pill. */
  content: "";
  display: inline-block; vertical-align: middle;
  width: 4px; height: 4px; border-radius: 50%;
  background: var(--line-strong);
  margin-inline: var(--sp-5);
}

.hp-ticker__item a {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  padding-block: var(--sp-4);
  color: var(--muted); font-size: var(--fs-small); line-height: 1.6;
  white-space: nowrap;
  transition: color .2s ease;
}
.hp-ticker__item a:hover .hp-ticker__text { color: var(--ink); }

/* The category is the only coloured thing in the strip, which is what makes it
   readable at a glance while the rest streams past. */
.hp-ticker__pill {
  flex: none;
  padding: 5px var(--sp-3);
  border-radius: var(--r-pill);
  background: var(--red-tint);
  color: var(--red);
  font-size: var(--fs-caption); font-weight: 800;
}

.hp-ticker__text { transition: color .2s ease; }

@media (prefers-reduced-motion: reduce) {
  /* Nothing moves; the strip becomes a plain scrollable row instead. */
  .hp-ticker__mask { animation: none; width: auto; overflow-x: auto; }
  .hp-ticker__track:last-child { display: none; }
}


/* --- Reviews -------------------------------------------------------------
   A summary strip over a grid of equal-height cards. Nothing moves: the
   drifting version clipped every card at the top and bottom of its window, so
   no single review could be read through. */

.hp-rv__summary {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--sp-4) clamp(var(--sp-5), 3vw, var(--sp-7));
  padding: var(--sp-5) var(--sp-5);
  margin-bottom: clamp(var(--sp-5), 3vw, var(--sp-6));
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-surface);
}

.hp-rv__brand {
  display: flex; align-items: center; gap: var(--sp-3);
  color: var(--ink); font-weight: 700; font-size: var(--fs-small);
}
.hp-rv__brand svg { flex: none; }

/* Score, "of 5" and the stars share one baseline — stacked, the qualifier
   dropped to a size that read as a subscript. */
.hp-rv__figure { margin: 0; display: flex; align-items: baseline; gap: var(--sp-3); }
.hp-rv__score { color: var(--ink); font-size: clamp(28px, 2.6vw, 34px); font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; }
.hp-rv__of { color: var(--muted); font-size: var(--fs-small); font-weight: 700; }
.hp-rv__sstars { display: inline-flex; gap: 2px; color: #e8b04b; }

.hp-rv__count { margin: 0; color: var(--muted); font-size: var(--fs-small); font-weight: 700; }

/* Pushed to the far end so the strip reads left-to-right as identity, score,
   volume, action rather than as four things in a queue. */
.hp-rv__write {
  margin-inline-start: auto;
  color: var(--red); font-weight: 800; font-size: var(--fs-small);
  border-bottom: 1.5px solid currentColor;
}
.hp-rv__write:hover { color: var(--red-deep); }

.hp-rv__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--grid-gap);
  /* Rows stretch to the tallest card in the row, so a short review and a long
     one still line their edges up. */
  align-items: stretch;
}

.hp-rv__card {
  /* Belt and braces with the minmax above: a card must never be the thing
     that decides how wide the page is. */
  min-width: 0;
  margin: 0;
  padding: var(--card-pad);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-surface);
  display: flex; flex-direction: column;
}
.hp-rv__card.is-folded { display: none; }

/* Revealed cards ease in, so three appearing at once reads as an expansion
   rather than a jump. */
@keyframes hp-rv-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
.hp-rv__card.is-revealed { animation: hp-rv-in .28s ease both; }
@media (prefers-reduced-motion: reduce) {
  .hp-rv__card.is-revealed { animation: none; }
}

/* Header row: who said it, and where it was said. */
.hp-rv__top { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-3); }

/* Stands in for the Google profile picture, which is on Google's CDN and not
   ours to hotlink. The hue comes from the name, so a reviewer keeps the same
   colour instead of it shifting between renders. */
.hp-rv__avatar {
  flex: none;
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  background: hsl(var(--rv-hue, 350) 42% 32%);
  color: #fff; font-weight: 800; font-size: var(--fs-body);
  line-height: 1;
}

.hp-rv__name {
  flex: 1; min-width: 0;
  color: var(--ink); font-size: var(--fs-small); font-weight: 800;
  /* Names run long ("Abdulghani al khadar albaghdadi") and would push the
     Google mark out of the card. */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.hp-rv__g { flex: none; display: block; line-height: 0; }

.hp-rv__stars { display: flex; gap: 2px; color: #e8b04b; margin-bottom: var(--sp-3); }

.hp-rv__card blockquote {
  /* Divi puts a thick side border and padding on every blockquote; inside a
     card that showed up as a dark bar down the edge of the quote. */
  margin: 0 0 var(--sp-4);
  padding: 0;
  border: 0;
  color: var(--muted); font-size: var(--fs-small); line-height: 1.8;
  /* Grows to fill, so every caption in a row sits on the same line. */
  flex: 1;
}
/* The quote no longer has to grow to align captions — there are none — but it
   still fills so cards in a row stay the same height. */

.hp-rv__actions { display: flex; justify-content: center; margin-top: clamp(var(--sp-5), 3vw, var(--sp-6)); }

/* Nothing here for the JS-off case: the control is a plain link to the Google
   listing until the script takes it over, so it degrades on its own. */

@media (max-width: 900px) { .hp-rv__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) {
  .hp-rv__grid { grid-template-columns: minmax(0, 1fr); }
  .hp-rv__write { margin-inline-start: 0; }
}

/* ==========================================================================
   MOBILE
   The page was built at desktop width and several sections had no rule for a
   phone, so their columns simply divided the small width between them. This
   block is the one place that says what a section does when there is no room.
   ========================================================================== */

@media (max-width: 860px) {

  /* Two columns of nothing: the picture and the copy each got about half of a
     phone, so the text wrapped to two or three words a line. */
  .hp-about__grid { grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); }
  .hp-about__media { order: 2; }

  .hp-head { max-width: none; }
}

@media (max-width: 700px) {
  /* Sections keep a rhythm but a shorter one; the desktop 96px top and bottom
     is a third of a phone screen. */
  .tu-dark-hero .hp-section { padding-block: var(--sp-7); }

  .hp-rv__summary { flex-direction: column; align-items: flex-start; gap: var(--sp-3); }
  .hp-rv__write { margin-inline-start: 0; }

  .hp-clients__band { flex-direction: column; align-items: stretch; gap: var(--sp-5); }
  .hp-clients__label { max-width: none; }

  /* flex:1 1 420px was written for a row, where 420px is a width. The band is a
     column here, so that basis became a 420px HEIGHT and the logos floated in
     the middle of an empty box. */
  .hp-clients__marquee { flex: 0 0 auto; width: 100%; }

  .hp-ticker__item a { font-size: var(--fs-caption); }
}

@media (max-width: 560px) {
  /* Service rows: icon, then title and copy stacked under it, with the arrow
     on its own line rather than squeezed into a third column. */
  .hp-svc__row {
    grid-template-columns: 34px minmax(0, 1fr);
    gap: var(--sp-3) var(--sp-4);
    padding-block: var(--sp-5);
  }
  .hp-svc__row h3 { grid-column: 2; }
  .hp-svc__row p { grid-column: 2; }
  .hp-svc__go { grid-column: 2; justify-self: start; }
  .hp-svc__icon { width: 30px; height: 30px; }

  .hp-post__body { padding: var(--sp-4); }
}

/* The way from the strip of logos to the page that holds all of them. */
.hp-clients__more {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: var(--sp-3);
  color: var(--red);
  font-size: var(--fs-caption);
  font-weight: 800;
  line-height: 1.5;
}
.hp-clients__more svg { width: 16px; height: 16px; flex: none; transition: transform .18s ease; }
.hp-clients__more:hover svg { transform: translateX(-3px); }
[dir="ltr"] .hp-clients__more:hover svg { transform: translateX(3px); }

@media (prefers-reduced-motion: reduce) {
  .hp-clients__more svg { transition: none; }
  .hp-clients__more:hover svg { transform: none; }
}
