/* ==========================================================================
   components.css  —  reusable pieces
   Every hover/press animation stays on transform + opacity only.
   ========================================================================== */

/* ==========================================================================
   Eyebrow — small label with a rule and a terracotta dot
   ========================================================================== */
.eyebrow {
  position: relative;
  display: inline-block;
  padding-bottom: 18px;
  font-family: var(--font-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-body);
  line-height: 1.3;
  color: var(--c-navy);
}

/* A short rule with a dot at its end, drawn under the label. */
.eyebrow::before {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: var(--eyebrow-rule);
  height: 3px;
  background: var(--c-navy);
  transform-origin: left center;
}

.eyebrow::after {
  content: "";
  position: absolute;
  left: var(--eyebrow-rule);
  bottom: 0;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--c-navy);
  transform: translate(-50%, 33%);
}

.eyebrow--on-dark { color: var(--c-white); }
.eyebrow--on-dark::before,
.eyebrow--on-dark::after { background: var(--c-white); }

/* ==========================================================================
   Button
   Markup:
   <a class="btn btn--primary">
     <span class="btn__label">Get a quote</span>
     <span class="btn__icon"><svg…/><svg…/></span>
   </a>
   ========================================================================== */
.btn {
  --btn-bg:      var(--c-terracotta);
  --btn-bg-hov:  var(--c-terracotta-600);
  --btn-fg:      var(--c-white);
  --btn-dot-bg:  var(--c-white);
  --btn-dot-fg:  var(--c-terracotta);

  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  padding: 7px 7px 7px var(--s-6);
  border-radius: var(--r-pill);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--font-body);
  font-size: var(--fs-btn);
  font-weight: var(--fw-semi);
  line-height: 1;
  white-space: nowrap;
  isolation: isolate;
  overflow: hidden;
  transform: translateZ(0);
  transition:
    transform   var(--t-base) var(--ease-spring),
    background  var(--t-base) var(--ease-out),
    box-shadow  var(--t-base) var(--ease-out);
}

/* Light sweep — a transform, so it composites on the GPU. */
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    100deg,
    transparent 20%,
    rgba(255, 255, 255, 0.22) 50%,
    transparent 80%
  );
  transform: translateX(-110%);
  transition: transform var(--t-slow) var(--ease-smooth);
}

.btn__label { position: relative; }

.btn__icon {
  position: relative;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  border-radius: 50%;
  background: var(--btn-dot-bg);
  color: var(--btn-dot-fg);
  overflow: hidden;
  transition: transform var(--t-base) var(--ease-spring);
}

.btn__icon svg {
  position: absolute;
  width: 15px;
  height: 15px;
  transition:
    transform var(--t-base) var(--ease-out),
    opacity   var(--t-fast) linear;
}

/* Second arrow waits off to the left and takes over on hover. */
.btn__icon svg + svg {
  transform: translateX(-140%);
  opacity: 0;
}

/* ---- Hover / focus ---- */
.btn:hover,
.btn:focus-visible {
  background: var(--btn-bg-hov);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.btn:hover::before,
.btn:focus-visible::before { transform: translateX(110%); }

.btn:hover .btn__icon,
.btn:focus-visible .btn__icon { transform: scale(1.08); }

.btn:hover .btn__icon svg,
.btn:focus-visible .btn__icon svg {
  transform: translateX(140%);
  opacity: 0;
}

.btn:hover .btn__icon svg + svg,
.btn:focus-visible .btn__icon svg + svg {
  transform: translateX(0);
  opacity: 1;
}

.btn:active {
  transform: translateY(0) scale(0.975);
  box-shadow: var(--shadow-sm);
  transition-duration: var(--t-fast);
}

/* ---- Variants ---- */
.btn--primary { /* uses the defaults above */ }

.btn--navy {
  --btn-bg:     var(--c-navy);
  --btn-bg-hov: var(--c-navy-700);
  --btn-fg:     var(--c-white);
  --btn-dot-bg: var(--c-navy-500);
  --btn-dot-fg: var(--c-white);
}

.btn--light {
  --btn-bg:     var(--c-white);
  --btn-bg-hov: var(--c-cream);
  --btn-fg:     var(--c-navy);
  --btn-dot-bg: var(--c-navy);
  --btn-dot-fg: var(--c-white);
}

.btn--glass {
  --btn-bg:     rgba(0, 34, 63, 0.72);
  --btn-bg-hov: rgba(0, 34, 63, 0.88);
  --btn-fg:     var(--c-white);
  --btn-dot-bg: var(--c-navy-500);
  --btn-dot-fg: var(--c-white);
}

/* Product pages: navy with a white dot, and its outlined partner. */
.btn--ink {
  --btn-bg:     var(--c-navy);
  --btn-bg-hov: var(--c-navy-700);
  --btn-fg:     var(--c-white);
  --btn-dot-bg: var(--c-white);
  --btn-dot-fg: var(--c-navy);
}

/* The outline is an inset shadow, not a border, so the two buttons in a pair
   keep exactly the same size. */
.btn--outline {
  --btn-bg:     transparent;
  --btn-bg-hov: var(--c-navy-050);
  --btn-fg:     var(--c-navy);
  --btn-dot-bg: var(--c-navy);
  --btn-dot-fg: var(--c-white);
  box-shadow: inset 0 0 0 1.5px var(--c-navy);
}
.btn--outline:hover,
.btn--outline:focus-visible { box-shadow: inset 0 0 0 1.5px var(--c-navy), var(--shadow-md); }
.btn--outline::before {
  background: linear-gradient(100deg, transparent 20%, rgba(0, 51, 102, 0.08) 50%, transparent 80%);
}

.btn--lg {
  padding: 8px 8px 8px var(--s-6);
  font-size: calc(var(--fs-btn) + 3px);
}
.btn--lg .btn__icon {
  width: 40px;
  height: 40px;
  flex-basis: 40px;
}
.btn--lg .btn__icon svg { width: 17px; height: 17px; }

.btn--sm {
  padding: 5px 5px 5px var(--s-5);
  font-size: var(--fs-sm);
}
.btn--sm .btn__icon {
  width: 28px;
  height: 28px;
  flex-basis: 28px;
}
.btn--sm .btn__icon svg { width: 13px; height: 13px; }

/* ==========================================================================
   Inline arrow link — "View grades →"
   ========================================================================== */
.link-arrow {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding-bottom: 3px;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semi);
  color: var(--c-navy);
}

.link-arrow::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--t-base) var(--ease-out);
}

.link-arrow svg {
  width: 13px;
  height: 13px;
  transition: transform var(--t-base) var(--ease-spring);
}

.link-arrow:hover::after,
.link-arrow:focus-visible::after { transform: scaleX(1); }

.link-arrow:hover svg,
.link-arrow:focus-visible svg { transform: translateX(5px); }

.link-arrow--on-dark { color: var(--c-white); }
.link-arrow--on-accent { color: var(--c-white); }

/* ==========================================================================
   Circular icon button — carousel arrows, card corners
   ========================================================================== */
.icon-btn {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  flex: 0 0 40px;
  border-radius: 50%;
  background: var(--c-navy);
  color: var(--c-white);
  overflow: hidden;
  transition:
    transform  var(--t-base) var(--ease-spring),
    background var(--t-base) var(--ease-out),
    opacity    var(--t-base) var(--ease-out);
}

.icon-btn svg {
  width: 15px;
  height: 15px;
  transition: transform var(--t-base) var(--ease-out);
}

.icon-btn:hover:not(:disabled),
.icon-btn:focus-visible:not(:disabled) {
  background: var(--c-navy-700);
  transform: scale(1.09);
}

.icon-btn:hover:not(:disabled) svg { transform: translateX(2px); }
.icon-btn--back:hover:not(:disabled) svg { transform: translateX(-2px); }

.icon-btn:active:not(:disabled) { transform: scale(0.94); }

.icon-btn--ghost {
  background: var(--c-navy-050);
  color: var(--c-navy);
}
.icon-btn--ghost:hover:not(:disabled) {
  background: var(--c-navy-100);
}

.icon-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

/* ==========================================================================
   Badge — "12 TYPES"
   ========================================================================== */
.badge {
  display: inline-block;
  padding: 5px 10px;
  border-radius: var(--r-pill);
  background: var(--c-terracotta-100);
  color: var(--c-terracotta-700);
  font-size: var(--fs-badge);
  font-weight: var(--fw-semi);
  letter-spacing: var(--ls-badge);
  text-transform: uppercase;
  line-height: 1;
}

.badge--on-accent {
  background: rgba(255, 255, 255, 0.24);
  color: var(--c-white);
}

/* ==========================================================================
   Product card
   ========================================================================== */
.p-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--s-3);
  border-radius: var(--r-lg);
  background: var(--c-white);
  /* So the fill below can sit at z-index -1: above the card's own background,
     beneath everything in it. */
  isolation: isolate;
  /* The lift rides `translate`, not `transform`: the entrance reveal owns
     transform and resets it to none, which would cancel the hover outright. */
  transition:
    translate  var(--t-base) var(--ease-out),
    background var(--t-base) var(--ease-out);
}

/* The accent arrives as a fill rising from the foot of the card rather than
   the whole panel switching colour in one step. clip-path rather than a scale,
   so the corner radius keeps its shape the whole way up. */
.p-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--c-terracotta);
  clip-path: inset(100% 0 0 0 round var(--r-lg));
  /* 340ms: long enough to read as a movement, short enough to feel immediate. */
  transition: clip-path 340ms var(--ease-smooth);
}

.p-card:not(.p-card--feature):hover::before,
.p-card:not(.p-card--feature):focus-within::before {
  clip-path: inset(0 0 0 0 round var(--r-lg));
}

/* Each colour turns at the moment the fill passes it, so the two read as one
   movement. They snap rather than fade: navy interpolating to white travels
   through a muddy grey, and over the accent that reads as a smear.

   The delays in this rule are the way OUT, where the fill retracts from the top
   down — so the badge clears first and the link last. The hover rule below
   reverses them for the way in. */
.p-card .badge         { transition: color 0s linear 210ms, background 0s linear 210ms; }
.p-card .p-card__title { transition: color 0s linear 235ms; }
.p-card .p-card__text  { transition: color 0s linear 270ms; }
.p-card .link-arrow    { transition: color 0s linear 320ms; }

.p-card:not(.p-card--feature):hover .link-arrow    { transition-delay:  35ms; }
.p-card:not(.p-card--feature):hover .p-card__text  { transition-delay:  90ms; }
.p-card:not(.p-card--feature):hover .p-card__title { transition-delay: 120ms; }
.p-card:not(.p-card--feature):hover .badge         { transition-delay: 145ms; }

/* These cards sit on the navy band, where a navy shadow would not read — so
   the lift is carried by a deeper one. */
.p-card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 18px 38px rgba(0, 10, 22, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-base) var(--ease-out);
}

.p-card:hover { translate: 0 -6px; }
.p-card:hover::after { opacity: 1; }

/* The whole panel is the target. A card that looks like one tappable object
   should behave like one, and on a phone the small "view" link at the foot is
   a poor thing to aim at. */
.p-card__cover {
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
}

.p-card:not(.p-card--feature):hover .p-card__title { color: var(--c-white); }
.p-card:not(.p-card--feature):hover .p-card__text  { color: rgba(255, 255, 255, 0.86); }
.p-card:not(.p-card--feature):hover .link-arrow    { color: var(--c-white); }

/* Solid rather than a translucent wash: it stays crisp against the fill. */
/* The category line turns with the rest of the text as the fill passes it. */
.p-card .p-card__label { transition: color 0s linear 250ms; }
.p-card:not(.p-card--feature):hover .p-card__label {
  color: var(--c-white);
  transition-delay: 130ms;
}

.p-card:not(.p-card--feature):hover .badge {
  background: var(--c-white);
  color: var(--c-terracotta-700);
}

/* The featured card is already accent, so it deepens instead. */
.p-card--feature:hover { background: var(--c-terracotta-600); }

/* Hovering anywhere on the card drives the link's own motion. */
.p-card:hover .link-arrow::after { transform: scaleX(1); }
.p-card:hover .link-arrow svg    { transform: translateX(5px); }

/* 4:3, not the comp's 16:10. The product photographs are portrait studio
   shots — the pile in Frac Sand runs from 11% to 77% of the frame height — and
   a 16:10 window shows only 54% of a portrait picture, which took the top off
   every pile. 4:3 shows 65%, which the tallest of them fits inside. */
.p-card__media {
  aspect-ratio: 4 / 3;
  border-radius: var(--r-md);
  margin-bottom: var(--s-4);
}

/* The window sits above centre because the subject does: these photographs
   carry their empty paper at the foot, not the head. */
.p-card__media img { object-position: center 34%; }

.p-card__media {
  overflow: hidden;
  isolation: isolate;
}

.p-card__media img,
.p-card__media::before {
  transition: transform var(--t-slow) var(--ease-out);
}

.p-card:hover .p-card__media img { transform: scale(1.08); }

/* A wash of the accent over the photograph, so the image joins the fill
   instead of staying a cold rectangle in the middle of it. */
.p-card__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(255, 123, 15, 0) 35%, rgba(190, 77, 0, 0.5) 100%);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-base) var(--ease-out);
}

.p-card:not(.p-card--feature):hover .p-card__media::after { opacity: 1; }

.p-card__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: var(--s-2);
  padding: 0 var(--s-3) var(--s-3);
}

/* Two class selectors so the card keeps its own colour inside .block--navy. */
.p-card .p-card__title {
  font-size: var(--fs-h4);
  line-height: var(--lh-snug);
  color: var(--c-navy);
}

.p-card__text {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  margin-bottom: var(--s-3);
}

/* The listing's category line: small caps in the accent, underlined to its
   own width. */
.p-card__label {
  align-self: flex-start;
  font-size: calc(var(--fs-badge) + 2.5px);
  font-weight: var(--fw-semi);
  letter-spacing: 1.4px;
  text-transform: uppercase;
  line-height: 1.3;
  color: var(--c-terracotta);
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 6px;
  margin-bottom: var(--s-1);
}

.p-card__body .badge { align-self: flex-start; }
.p-card__body .link-arrow { margin-top: auto; align-self: flex-start; }

/* Featured variant */
.p-card--feature { background: var(--c-terracotta); }
.p-card--feature .p-card__title { color: var(--c-white); }
.p-card--feature .p-card__text { color: rgba(255, 255, 255, 0.82); }

/* ==========================================================================
   Industry card — tall image tile
   ========================================================================== */
.ind-card {
  position: relative;
  display: block;
  aspect-ratio: 3 / 4;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--ph-plant);
  isolation: isolate;
}

.ind-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--t-slow) var(--ease-out);
}

.ind-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(0, 34, 63, 0) 42%,
    rgba(0, 34, 63, 0.82) 100%
  );
  pointer-events: none;
}

.ind-card:hover img { transform: scale(1.08); }

/* The scrim deepens and warms, so the tile reacts as a whole rather than the
   photograph sliding under a fixed sheet of navy. */
.ind-card::after { transition: opacity var(--t-base) var(--ease-out); }

.ind-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(0, 34, 63, 0) 30%, rgba(153, 74, 8, 0.55) 100%);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-base) var(--ease-out);
}

.ind-card:hover::before { opacity: 1; }

.ind-card__foot { transition: transform var(--t-base) var(--ease-out); }
.ind-card:hover .ind-card__foot { transform: translateY(-4px); }
.ind-card:hover .icon-btn { background: var(--c-terracotta); }

.ind-card__foot {
  position: absolute;
  z-index: 1;
  left: var(--s-5);
  right: var(--s-5);
  bottom: var(--s-5);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-3);
}

/* No detail page behind the card: nothing lifts, nothing zooms, nothing
   offers a tap. The label takes the width the arrow button used to hold. */
.ind-card--plain:hover img,
.ind-card--plain:hover .ind-card__foot { transform: none; }

.ind-card--plain .ind-card__label { max-width: none; }

/* The warm wash goes the same way as the lift: a tile that answers the pointer
   reads as a link, and this one is not. */
.ind-card--plain::before { content: none; }

/* The same photograph carries the shape here, so the tile stops drawing a
   rounded box or a colour behind it, and contains the image rather than
   cropping it — the notch has to survive whole. A tile with no photograph
   keeps both, or its label would sit on bare tint. */
.ind-card:has(img) {
  border-radius: 0;
  background: none;
}

.ind-card:has(img) img { object-fit: contain; }

/* The label is white and half these photographs are not, so the foot still
   needs a scrim under it. A rectangle of navy would fill the two corners the
   export cuts away, so the scrim wears the photograph as its own mask and
   stops exactly where the picture does. --tile-shape is the file the img is
   already showing, set on the tile by the template; with none set the mask
   falls back to a flat black rectangle, which masks nothing and leaves the
   plain scrim a square photograph wants anyway. */
.ind-card:has(img)::after {
  content: "";
  background: linear-gradient(
    180deg,
    rgba(0, 34, 63, 0) 38%,
    rgba(0, 34, 63, 0.3) 64%,
    rgba(0, 34, 63, 0.84) 100%
  );
  -webkit-mask-image: var(--tile-shape, linear-gradient(#000, #000));
          mask-image: var(--tile-shape, linear-gradient(#000, #000));
  -webkit-mask-size: contain;
          mask-size: contain;
  -webkit-mask-position: center;
          mask-position: center;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}

/* Hover. The photograph cannot zoom — it is the mask, and a tile that clips
   would slice the notches off the moment it grew — so the warmth comes from
   the scrim instead, over the same mask, and the label rises to meet it. */
.ind-card:has(img)::before {
  content: "";
  background: linear-gradient(
    180deg,
    rgba(0, 34, 63, 0) 34%,
    rgba(153, 74, 8, 0.26) 66%,
    rgba(153, 74, 8, 0.62) 100%
  );
  -webkit-mask-image: var(--tile-shape, linear-gradient(#000, #000));
          mask-image: var(--tile-shape, linear-gradient(#000, #000));
  -webkit-mask-size: contain;
          mask-size: contain;
  -webkit-mask-position: center;
          mask-position: center;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}

/* On `translate` rather than `transform`, so it never contends with the
   reveal that put the tile on the page — the same way every other card here
   lifts. */
.ind-card:has(img):hover { translate: 0 -6px; }
.ind-card:has(img):hover::before { opacity: 1; }
.ind-card:has(img):hover .ind-card__foot { transform: translateY(-3px); }

@media (prefers-reduced-motion: reduce) {
  .ind-card:has(img):hover { translate: none; }
  .ind-card:has(img):hover .ind-card__foot { transform: none; }
}

.ind-card__label {
  font-family: var(--font-head);
  font-weight: var(--fw-bold);
  font-size: var(--fs-h4);
  line-height: var(--lh-snug);
  color: var(--c-white);
  max-width: 9ch;
}

.ind-card .icon-btn {
  width: 34px;
  height: 34px;
  flex-basis: 34px;
}

.ind-card:hover .icon-btn {
  background: var(--c-terracotta);
  transform: scale(1.09);
}

/* ==========================================================================
   Feature card — "Why choose Reva"
   ========================================================================== */
.f-card {
  display: flex;
  gap: var(--s-5);
  padding: var(--s-6);
  border-radius: var(--r-lg);
  background: var(--c-white);
  transition: transform var(--t-base) var(--ease-out);
}

.f-card:hover { transform: translateX(6px); }

.f-card__icon {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  flex: 0 0 42px;
  border-radius: var(--r-sm);
  background: var(--c-navy);
  color: var(--c-white);
  transition: transform var(--t-base) var(--ease-spring);
}

.f-card__icon svg { width: 20px; height: 20px; }

.f-card:hover .f-card__icon { transform: rotate(-6deg) scale(1.06); }

.f-card__title { margin-bottom: var(--s-2); }

.f-card__text {
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* ==========================================================================
   Logo
   ========================================================================== */
.logo {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
}

.logo__mark {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  flex: 0 0 42px;
  border-radius: 50%;
  background: var(--c-white);
  transition: transform var(--t-base) var(--ease-spring);
}

.logo:hover .logo__mark { transform: rotate(-8deg) scale(1.05); }

.logo__mark svg { width: 24px; height: 24px; }

.logo__text {
  display: flex;
  flex-direction: column;
  font-family: var(--font-head);
  font-weight: var(--fw-bold);
  font-size: 17px;
  line-height: 1.12;
  letter-spacing: -0.2px;
  color: var(--c-white);
}

.logo--ink .logo__text { color: var(--c-navy); }
.logo--ink .logo__mark { background: var(--c-navy-050); }

/* An uploaded mark takes the place of the drawn one, at the same size inside
   the circle. */
.logo__mark img {
  display: block;
  width: 26px;
  height: 26px;
  object-fit: contain;
}

/* A wordmark already carries the name, so it becomes the whole lockup rather
   than being squeezed into the circle the icon was drawn for: the plate and
   the typed name both step aside for it. */
.logo--wordmark .logo__mark {
  width: auto;
  height: auto;
  flex: 0 1 auto;
  border-radius: 0;
  background: none;
}

.logo--wordmark .logo__mark img {
  width: auto;
  height: clamp(34px, 3.2vw, 44px);
  max-width: min(232px, 48vw);
}

.logo--wordmark .logo__text { display: none; }

/* The tilt reads as playful on a drawn badge and as a printing fault on a
   wordmark, so that one lifts instead. */
.logo--wordmark:hover .logo__mark { transform: translateY(-2px); }

/* ==========================================================================
   Social circles
   ========================================================================== */
.social {
  display: flex;
  gap: var(--s-3);
}

.social a {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--c-white);
  color: var(--c-navy);
  transition: transform var(--t-base) var(--ease-spring),
              background var(--t-base) var(--ease-out);
}

.social a svg { width: 15px; height: 15px; }

.social a:hover {
  transform: translateY(-3px);
  background: var(--c-terracotta);
  color: var(--c-white);
}

/* ==========================================================================
   Map pin
   ========================================================================== */
.pin {
  position: absolute;
  /* Above the map, which takes z-index 1 to clear the missing-state grid. */
  z-index: 2;
  /* The DOT is the anchor, not the pill. Centring the pill on the coordinate
     meant a long label dragged its dot off the country -- "Southeast Asia"
     landed half a label away from the islands. 10px is the left padding plus
     half the dot, so left/top now says exactly where the dot goes and the
     label hangs off it. */
  transform: translate(-10px, -50%);
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px 4px 6px;
  border-radius: var(--r-pill);
  background: var(--c-white);
  box-shadow: var(--shadow-sm);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  color: var(--c-navy);
  white-space: nowrap;
}

.pin::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--c-terracotta);
  flex: 0 0 7px;
}

/* Hangs the label to the left of its dot instead. Regions crowd together --
   Europe, the Gulf and the two Asias sit within a few percent of each other --
   and sending every label the same way piles them on top of one another. The
   dot does not move; only the label changes which side it waits on. */
.pin--left {
  flex-direction: row-reverse;
  padding: 4px 6px 4px 9px;
  transform: translate(calc(-100% + 10px), -50%);
}

/* The names, for the phone layout below, where the pins cannot carry them. */
.presence__legend { display: none; }

/* A phone gives the map a third of the width it was drawn for, and nine
   labels on it collide into mush however small the type goes. The map is
   left to speak for itself there -- the highlighted countries already show
   the reach -- and the names are listed underneath. */
@media (max-width: 640px) {
  .pin { display: none; }

  .presence__legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px 14px;
    margin: var(--s-5) 0 0;
    padding: 0;
    list-style: none;
  }

  .presence__legend li {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    font-weight: var(--fw-medium);
    color: var(--c-navy);
  }

  .presence__legend li::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--c-terracotta);
    flex: 0 0 6px;
  }
}

/* ==========================================================================
   Navigation
   ========================================================================== */
.nav {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  padding: 6px;
  border-radius: var(--r-pill);
  background: var(--c-white);
  box-shadow: var(--shadow-sm);
}

.nav__item {
  position: relative;
  isolation: isolate;   /* lets .nav__link::before paint above the pill */
}

.nav__link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 9px var(--s-4);
  border-radius: var(--r-pill);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--c-ink);
  transition: color var(--t-fast) var(--ease-out);
}

.nav__link::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--r-pill);
  background: var(--c-navy);
  transform: scale(0.82);
  opacity: 0;
  z-index: -1;
  transition:
    transform var(--t-base) var(--ease-spring),
    opacity   var(--t-fast) var(--ease-out);
}

.nav__item:hover .nav__link,
.nav__link:focus-visible,
.nav__link[aria-current="page"] { color: var(--c-white); }

.nav__item:hover .nav__link::before,
.nav__link:focus-visible::before,
.nav__link[aria-current="page"]::before {
  transform: scale(1);
  opacity: 1;
}

.nav__link svg {
  width: 9px;
  height: 9px;
  transition: transform var(--t-base) var(--ease-out);
}

.nav__item:hover .nav__link svg { transform: rotate(180deg); }

/* Dropdown */
.nav__menu {
  position: absolute;
  top: calc(100% + 10px);
  left: 50%;
  min-width: 208px;
  padding: var(--s-2);
  border-radius: var(--r-md);
  background: var(--c-white);
  box-shadow: var(--shadow-md);
  transform: translate(-50%, 8px);
  opacity: 0;
  visibility: hidden;
  transition:
    transform  var(--t-base) var(--ease-out),
    opacity    var(--t-base) var(--ease-out),
    visibility 0s linear var(--t-base);
}

.nav__item:hover .nav__menu,
.nav__item:focus-within .nav__menu {
  transform: translate(-50%, 0);
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}

.nav__menu a {
  display: block;
  padding: 9px var(--s-4);
  border-radius: var(--r-xs);
  font-size: var(--fs-sm);
  color: var(--c-ink);
  transition: background var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out);
}

.nav__menu a:hover {
  background: var(--c-navy-050);
  color: var(--c-navy);
}

/* Burger */
.burger {
  position: relative;
  display: none;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--c-white);
  color: var(--c-navy);
  box-shadow: var(--shadow-sm);
}

/* The three bars are placed from the centre of the button rather than stacked
   in the flow. The open state has to fold them onto one point, and whatever
   spacing the layout works out for itself puts that point somewhere the fixed
   offsets below cannot reach — which is how an X ends up as two strokes that
   never meet. Measured from the middle, the fold is exact.

   Whole-pixel margins rather than a -50% translate: these bars are 2px, and a
   half-pixel offset is the difference between a crisp rule and a grey smudge. */
.burger span {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 20px;
  height: 2px;
  margin: -1px 0 0 -10px;
  border-radius: 1px;
  background: currentColor;
  transition: transform var(--t-base) var(--ease-out),
              opacity var(--t-fast) linear;
}

.burger span:nth-child(1) { transform: translateY(-6px); }
.burger span:nth-child(3) { transform: translateY(6px); }

.burger[aria-expanded="true"] span:nth-child(1) { transform: rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(3) { transform: rotate(-45deg); }

/* The middle rule draws back into the crossing rather than simply vanishing. */
.burger[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
  transform: scaleX(0.3);
}

/* ==========================================================================
   Form
   Markup:
   <form class="form">
     <div class="field"><label class="field__label">…</label>
       <input class="field__input"><p class="field__error"></p></div>
     …
   </form>
   ========================================================================== */
.form { margin-top: var(--s-7); }

.form__row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-4);
}

/* Only a robot fills this in, so it is taken off the page rather than hidden:
   display:none is the first thing they learn to skip. */
.form__trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.field { margin-bottom: var(--s-5); }
.form__row .field { margin-bottom: 0; }
.form__row + .field { margin-top: var(--s-5); }

.field__label {
  display: block;
  margin-bottom: 10px;
  font-family: var(--font-head);
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  line-height: 1.2;
  letter-spacing: var(--ls-heading);
  color: var(--c-ink);
}

.field__input {
  display: block;
  width: 100%;
  min-height: 52px;
  padding: 13px 20px;
  border: 0;
  border-radius: var(--r-xs);
  background: var(--c-mist);
  color: var(--c-ink);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  line-height: 1.5;
  transition:
    box-shadow var(--t-base) var(--ease-out),
    background var(--t-base) var(--ease-out);
}

.field__input::placeholder {
  color: rgba(16, 33, 58, 0.55);
  opacity: 1;
}

.field__input:hover { background: #E8E8E8; }

.field__input:focus,
.field__input:focus-visible {
  outline: 0;
  background: var(--c-white);
  box-shadow: inset 0 0 0 2px var(--c-navy-500);
}

.field__input--area {
  min-height: 150px;
  padding-top: 16px;
  resize: vertical;
}

/* A select wears the same skin as the boxes beside it, with the browser's own
   arrow swapped for the one the rest of the page uses. */
.field__pick {
  position: relative;
  display: block;
}

.field__pick select.field__input {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 46px;
  cursor: pointer;
}

.field__pick > svg {
  position: absolute;
  top: 50%;
  right: 18px;
  width: 12px;
  height: 12px;
  translate: 0 -50%;
  color: var(--c-navy);
  pointer-events: none;
}

/* A field left on its own in a row takes the width rather than half of it. */
.form__row:has(> .field:only-child) { grid-template-columns: minmax(0, 1fr); }

/* Where the two labels can run to different depths, the boxes line up by their
   feet rather than their tops. Neither field in such a row carries an error
   message under it, so nothing shifts when one is shown. */
.form__row--foot { align-items: end; }

/* Phone: the country code sits inside the field, as drawn. */
.field__pair {
  display: flex;
  align-items: stretch;
  gap: var(--s-2);
  border-radius: var(--r-xs);
  background: var(--c-mist);
}

.field__pair .field__input {
  flex: 1 1 auto;
  min-width: 0;
  background: transparent;
  padding-left: 4px;
}
.field__pair .field__input:hover { background: transparent; }
.field__pair:focus-within { box-shadow: inset 0 0 0 2px var(--c-navy-500); }
.field__pair .field__input:focus,
.field__pair .field__input:focus-visible {
  background: transparent;
  box-shadow: none;
}

.field__code {
  position: relative;
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  border-radius: var(--r-xs);
  background: var(--c-terracotta);
  color: var(--c-white);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
}

.field__code select {
  appearance: none;
  -webkit-appearance: none;
  height: 100%;
  padding: 0 14px;
  border: 0;
  border-radius: var(--r-xs);
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.field__code select option { color: var(--c-ink); }

/* Without the script the select shows itself, so cap it: the number still
   needs room beside it. */
.field__code select { max-width: 132px; }
.js .field__code select { max-width: none; }

/* The list carries the country names; the face shows the code alone, the way
   the comp draws it. Without the script the select shows itself instead, so
   the chosen code is always the one on screen. */
.field__code-face { display: none; }

.js .field__code select {
  position: absolute;
  inset: 0;
  width: 100%;
  padding: 0;
  opacity: 0;
}

.js .field__code-face {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 12px 0 14px;
  pointer-events: none;
}

.field__code-face svg {
  width: 13px;
  height: 13px;
  color: var(--c-white);
}

.field__code:focus-within {
  outline: 2px solid var(--c-navy-500);
  outline-offset: 2px;
}

.field__error {
  margin-top: 7px;
  font-size: calc(var(--fs-xs) - 2px);
  line-height: 1.4;
  color: var(--c-error);
}

.field.has-error .field__input,
.field.has-error .field__pair { box-shadow: inset 0 0 0 2px var(--c-error); }

.form__alert {
  margin-bottom: var(--s-5);
  padding: 14px 18px;
  border-radius: var(--r-xs);
  background: rgba(179, 38, 30, 0.08);
  font-size: var(--fs-xs);
  line-height: 1.45;
  color: var(--c-error);
}

.form__foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-4) var(--s-6);
  margin-top: var(--s-6);
}

.form__status {
  font-size: var(--fs-xs);
  line-height: 1.4;
  color: var(--c-ink-muted);
}
.form__status:empty { display: none; }
.form__status.is-error { color: var(--c-error); }

.form__done {
  margin-top: var(--s-7);
  padding: var(--s-6) var(--s-7);
  border-radius: var(--r-md);
  background: var(--c-mist);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--c-ink);
}
.form__done p + p { margin-top: var(--s-4); }

/* Sending: the button keeps its size and stops taking clicks. */
.form.is-sending .btn { pointer-events: none; opacity: 0.72; }

/* ==========================================================================
   Request panel
   The dialog the product page's three buttons open. Native <dialog>, so the
   focus trap, the Escape key and the return of focus to the button that
   opened it are the browser's job rather than ours.
   ========================================================================== */
.modal {
  width: min(560px, calc(100vw - 32px));
  max-height: min(86dvh, 780px);
  padding: 0;
  border: 0;
  border-radius: var(--r-lg);
  background: var(--c-white);
  box-shadow: var(--shadow-lg);
  color: var(--c-ink);
  overflow: hidden;
}

/* Only while it is open: the closed state is the browser's display:none. */
.modal[open] { display: flex; }

.modal::backdrop { background: rgba(0, 20, 38, 0.62); }

.modal__panel {
  position: relative;
  flex: 1;
  min-width: 0;
  padding: var(--s-8) var(--s-7) var(--s-7);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.modal__close {
  position: absolute;
  top: var(--s-4);
  right: var(--s-4);
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--c-navy-050);
  color: var(--c-navy);
  transition: background var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out);
}

.modal__close:hover,
.modal__close:focus-visible {
  background: var(--c-navy);
  color: var(--c-white);
}

.modal__close svg { width: 15px; height: 15px; }

/* Which product this is about, said once at the top rather than repeated
   through the headings. */
.modal__product {
  display: inline-block;
  margin-bottom: var(--s-3);
  padding: 5px var(--s-3);
  border-radius: var(--r-pill);
  background: var(--c-navy-050);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: var(--c-navy);
}

/* All three headings are in the page; the intent decides which one is read. */
.modal__head { display: none; }

.modal[data-intent="enquire"] .modal__head[data-for="enquire"],
.modal[data-intent="sample"]  .modal__head[data-for="sample"],
.modal[data-intent="quote"]   .modal__head[data-for="quote"] { display: block; }

.modal__title {
  /* The heading tracks the section scale but keeps a floor: a dialog title
     that shrinks with the page ends up smaller than the labels under it. */
  font-size: clamp(23px, calc(var(--fs-h2) - 10px), 30px);
  line-height: var(--lh-heading);
  margin-bottom: var(--s-2);
}

.modal__lead {
  margin-bottom: var(--s-6);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--text-muted);
}

/* The sample questions. Hidden and disabled together, so what is not asked
   is also not sent. */
.modal__extra {
  display: none;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.modal[data-intent="sample"] .modal__extra { display: block; }

.modal .form__foot { margin-top: var(--s-6); }

@media (prefers-reduced-motion: no-preference) {
  .modal[open] { animation: modal-rise 240ms var(--ease-out); }
  .modal[open]::backdrop { animation: modal-wash 240ms var(--ease-out); }
}

@keyframes modal-rise { from { opacity: 0; transform: translateY(14px) scale(0.985); } }
@keyframes modal-wash { from { opacity: 0; } }

@media (max-width: 520px) {
  .modal__panel { padding: var(--s-7) var(--s-5) var(--s-6); }
  .modal__close { top: var(--s-3); right: var(--s-3); }
}

/* --------------------------------------------------------------------------
   WhatsApp button
   Fixed to the bottom-right corner of every page. It sits below the header
   bar and below any open request panel, which the dialog top layer puts
   above everything on the page.
   -------------------------------------------------------------------------- */
.wa {
  position: fixed;
  right: var(--s-5);
  bottom: var(--s-5);
  z-index: 55;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: #25D366;
  color: var(--c-white);
  box-shadow: var(--shadow-lg);
  transition:
    transform  var(--t-base) var(--ease-spring),
    box-shadow var(--t-base) var(--ease-out);
}

.wa svg {
  width: 28px;
  height: 28px;
}

.wa:hover,
.wa:focus-visible {
  transform: translateY(-3px);
  color: var(--c-white);
}

@media (max-width: 767px) {
  .wa {
    right: var(--s-4);
    bottom: calc(var(--s-4) + env(safe-area-inset-bottom, 0px));
    width: 52px;
    height: 52px;
  }

  .wa svg {
    width: 26px;
    height: 26px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .wa { transition: none; }
  .wa:hover,
  .wa:focus-visible { transform: none; }
}

@media print {
  .wa { display: none; }
}
