/* ===========================================================================
   SERVICE DETAIL — Customer Acquisition & Customer Systems
   Every rule below is scoped to the `.sd` sections these two pages use, so
   nothing here can leak onto any other route. Default state (no JS, reduced
   motion, or `service.js` never loading) is fully visible and static; the
   `sd-js` class on <html> — added only when JS runs and motion is allowed —
   is what switches elements into their hidden-until-scrolled state.
   =========================================================================== */

.sd{ overflow-x: clip; }

/* ============================================================== 1. HERO */
.sd-hero__grid{ display: grid; gap: var(--s-8); }
.sd-hero__art{ order: -1; width: 100%; max-width: 15.5rem; margin-inline: auto; }
@media (min-width: 860px){
  .sd-hero__grid{ grid-template-columns: minmax(0,1fr) minmax(0,.86fr); align-items: center; gap: clamp(2.5rem, 1rem + 5vw, 6rem); }
  .sd-hero__art{ order: 0; max-width: none; margin-inline: 0; }
}

.sd-hero__title{ font-family: var(--font-display); font-weight: 700; font-optical-sizing: auto;
  letter-spacing: -.01em; line-height: .98; overflow-wrap: anywhere;
  font-size: clamp(2.35rem, 1.7rem + 3.6vw, 4.75rem);
  margin-block: var(--s-5) var(--s-6); max-width: 15ch; }
.sd-hero__lede{ max-width: 38ch; }

.sd-hero__art{ position: relative; }
.sd-hero__img{ display: block; width: 100%; height: auto; max-width: none; }
.sd-hero__svg{ position: absolute; inset: 0; width: 100%; height: 100%; }
.sd-field-line{ fill: none; stroke: var(--ink); stroke-opacity: .32; stroke-width: 1.6; stroke-dasharray: 2.5 7; stroke-linecap: round; }
.sd-drift{ transform-box: fill-box; }
.sd-drift--ink{ fill: var(--ink); }
.sd-drift--accent{ fill: var(--accent); }
/* a simpler loop on phones: fewer things drifting */
@media (max-width: 859px){ .sd-hero__svg circle.sd-drift:nth-of-type(4), .sd-hero__svg rect.sd-drift:nth-of-type(6) { display: none; } }
@media (prefers-reduced-motion: reduce){ .sd-drift{ display: none; } }

/* =========================================================== 2. ROUTE */
.sd-route-head{ max-width: 46rem; }
.sd-route-intro{ margin-block: var(--s-4) var(--s-5); max-width: 20ch; }
.sd-route-statement{ color: var(--ink-2); }

.sd-route{ position: relative; margin-top: clamp(2.75rem, 1.75rem + 3.5vw, 4.5rem); }
.sd-route__svg{ display: block; width: 100%; height: auto; margin-bottom: clamp(-1.75rem, -1rem - 2vw, -.75rem); }
.sd-route__path{ fill: none; stroke: var(--ink); stroke-width: 2; stroke-linecap: round; }
html.sd-js .sd-route__path{ stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 1150ms var(--ease-out); }
html.sd-js .sd-route__path.in{ stroke-dashoffset: 0; }

.sd-route__stops{ display: flex; justify-content: space-between; gap: var(--s-6); list-style: none; margin: 0; padding: 0; }
.sd-stop{ display: grid; grid-template-columns: auto 1fr; align-items: center; gap: var(--s-2) var(--s-3); max-width: 15rem; }
.sd-stop__n{ grid-column: 2; color: var(--ink-2); }
.sd-stop__label{ grid-column: 2; font-family: var(--font-display); font-weight: 800; font-stretch: 108%;
  font-size: clamp(1.05rem, .95rem + .5vw, 1.3125rem); letter-spacing: -.02em; line-height: 1.15; }
.sd-stop__dot{ grid-row: 1 / span 2; position: relative; width: 15px; height: 15px; border-radius: 50%;
  border: 1.5px solid var(--ink); flex: none; }
.sd-stop__dot::after{ content: ""; position: absolute; inset: 3px; border-radius: 50%; background: var(--accent); }
html.sd-js .sd-stop__dot::after{ opacity: 0; transform: scale(.3); transition: opacity 480ms var(--ease-out), transform 480ms var(--ease-out); }
html.sd-js .sd-stop.in .sd-stop__dot::after{ opacity: 1; transform: none; }
html.sd-js .sd-stop__label, html.sd-js .sd-stop__n{ opacity: 0; transform: translateY(8px); transition: opacity 480ms var(--ease-out), transform 480ms var(--ease-out); }
html.sd-js .sd-stop.in .sd-stop__label, html.sd-js .sd-stop.in .sd-stop__n{ opacity: 1; transform: none; }
html.sd-js .sd-route__stops .sd-stop:nth-child(2) .sd-stop__dot::after,
html.sd-js .sd-route__stops .sd-stop:nth-child(2) .sd-stop__label,
html.sd-js .sd-route__stops .sd-stop:nth-child(2) .sd-stop__n{ transition-delay: 90ms; }
html.sd-js .sd-route__stops .sd-stop:nth-child(3) .sd-stop__dot::after,
html.sd-js .sd-route__stops .sd-stop:nth-child(3) .sd-stop__label,
html.sd-js .sd-route__stops .sd-stop:nth-child(3) .sd-stop__n{ transition-delay: 180ms; }

@media (max-width: 699px){
  .sd-route__svg{ display: none; }
  .sd-route__stops{ flex-direction: column; gap: var(--s-7); position: relative; padding-left: 1.9rem; }
  .sd-route__stops::before{ content: ""; position: absolute; left: 6px; top: 7px; bottom: 7px; width: 2px; background: var(--rule-strong); }
  .sd-stop{ position: relative; max-width: none; grid-template-columns: 1fr; }
  .sd-stop__dot{ position: absolute; left: -1.9rem; top: 0; }
  .sd-stop__n, .sd-stop__label{ grid-column: 1; }
}

@media (prefers-reduced-motion: reduce){
  .sd-route__path{ stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
}

/* ======================================================= 3. CAPABILITIES */
.sd-caps-head{ max-width: 40rem; }
.sd-caps-head .h2{ margin-top: var(--s-4); }

.sd-caps{ margin-top: clamp(2.5rem, 1.5rem + 3vw, 4rem); }
.sd-cap{ border-bottom: 1px solid var(--rule-strong); }
.sd-cap:first-child{ border-top: 1px solid var(--ink); }
.sd-cap__summary{ display: grid; grid-template-columns: 3rem 1fr auto; align-items: center; gap: var(--s-3) var(--s-4);
  padding-block: var(--s-5); cursor: pointer; list-style: none; -webkit-tap-highlight-color: transparent; }
.sd-cap__summary::-webkit-details-marker{ display: none; }
.sd-cap__summary::marker{ content: ""; }
.sd-cap__n{ color: var(--ink-2); }
.sd-cap__t{ font-family: var(--font-display); font-weight: 800; font-stretch: 108%; font-size: var(--t-h3); letter-spacing: -.015em; }
.sd-cap__chev{ width: 11px; height: 7px; color: var(--ink); flex: none; transition: transform var(--dur-2) var(--ease); }
.sd-cap[open] .sd-cap__chev{ transform: rotate(180deg); }
.sd-cap__list{ display: grid; gap: var(--s-3); grid-column: 2 / -1; padding: 0 0 var(--s-6); margin: 0; list-style: none; }
.sd-cap__list li{ font-family: var(--font-mono); font-size: var(--t-mono); color: var(--ink-2); padding-left: var(--s-5); position: relative; }
.sd-cap__list li::before{ content: ""; position: absolute; left: 0; top: .6em; width: 8px; height: 1.5px; background: var(--ink); }

@media (min-width: 700px){
  .sd-caps{ display: grid; grid-template-columns: repeat(2, 1fr); border-top: 1px solid var(--ink); border-left: 1px solid var(--ink); }
  .sd-cap{ border: 0; border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
  .sd-cap__summary{ padding: var(--s-6) var(--s-6) var(--s-4); cursor: default; grid-template-columns: 2.75rem 1fr; }
  .sd-cap__chev{ display: none; }
  .sd-cap__list{ padding: 0 var(--s-6) var(--s-7); grid-column: 2 / -1; }
  /* forced open: the matrix reads as an index, not an accordion. Chrome
     wraps a closed <details>'s non-summary content in an internal
     ::details-content box set to `content-visibility: hidden; height: 0`;
     overriding the light-DOM child is not enough, the pseudo-element itself
     has to be reopened or the row collapses to the summary's height and the
     list paints outside its own cell. */
  .sd-cap:not([open])::details-content{ content-visibility: visible; block-size: auto; height: auto; }
  .sd-cap:not([open]) > .sd-cap__list{ display: grid; content-visibility: visible; }
}
@media (min-width: 1060px){ .sd-caps{ grid-template-columns: repeat(3, 1fr); } }

html.sd-js .sd-cap{ opacity: 0; transform: translateY(16px); transition: opacity 620ms var(--ease-out), transform 620ms var(--ease-out); }
html.sd-js .sd-cap.in{ opacity: 1; transform: none; }
html.sd-js .sd-cap:nth-child(1){ transition-delay: 0ms; } html.sd-js .sd-cap:nth-child(2){ transition-delay: 60ms; }
html.sd-js .sd-cap:nth-child(3){ transition-delay: 120ms; } html.sd-js .sd-cap:nth-child(4){ transition-delay: 180ms; }
html.sd-js .sd-cap:nth-child(5){ transition-delay: 240ms; } html.sd-js .sd-cap:nth-child(6){ transition-delay: 300ms; }
html.sd-js .sd-cap:nth-child(7){ transition-delay: 360ms; }
@media (max-width: 699px){ html.sd-js .sd-cap{ opacity: 1; transform: none; transition: none; } }

.sd-cap__summary:hover{ background: var(--hover); }
.sd-cap:focus-within .sd-cap__summary{ background: var(--hover); }

/* ============================================================ 4. CLOSING */
.sd-close__text{ position: relative; display: inline-block; }
.sd-close__trace{ display: block; width: min(100%, 26rem); height: .8rem; margin-top: var(--s-4); overflow: visible; }
.sd-close__trace path{ fill: none; stroke: var(--accent); stroke-width: 3; stroke-linecap: round; }
html.sd-js .sd-close__trace path{ stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 900ms var(--ease-out); }
html.sd-js .sd-close__trace.in path{ stroke-dashoffset: 0; }

@media (prefers-reduced-motion: reduce){
  .sd-close__trace path{ stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
}

/* Belt and suspenders: if `sd-js` is somehow present without a matching
   IntersectionObserver ever resolving (e.g. the callback never fires because
   the element was already in view at load and some browser quirk skips the
   first tick), nothing above is allowed to stay invisible forever — the
   scroll-reveal targets keep a visible base state and only ever *add*
   motion, they never start from `display:none` or `visibility:hidden`. */

/* ============================================ v4.2 · after the site audit */
/* the kicker's "Services" is the way back up: a breadcrumb, not decoration */
.sd-crumb{ color: inherit; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }
.sd-crumb:hover{ text-decoration-thickness: 2px; }

/* no lonely last card: a card alone on its row spans the row and lays its
   list out across it (Customer Systems has seven groups) */
@media (min-width: 700px) and (max-width: 1059px){
  .sd-cap:last-child:nth-child(odd){ grid-column: 1 / -1; }
}
@media (min-width: 1060px){
  /* v5.5 mark 7: "make the pointed arrow a smaller box but in the middle center
     it". Customer Systems has seven groups, so card 07 was alone on row three.
     It used to span the full row and fan its five short items across three
     columns, which left two thin gutters of white between them — the emptiness
     the owner bracketed. It now sits in the middle column at the same width as
     every other card, with its list in one column like theirs.
     The selector stays conditional on :last-child:nth-child(3n+1) so an eighth
     group would simply start a normal row again; hard-coding card 7 would break
     that. */
  .sd-caps:not(.sd-caps--2) > .sd-cap:last-child:nth-child(3n+1){ grid-column: 2; }
  .sd-caps--2{ grid-template-columns: repeat(2, 1fr); }
  .sd-caps--2 > .sd-cap:last-child:nth-child(odd){ grid-column: 1 / -1; }
}
html.sd-js .sd-cap:nth-child(8){ transition-delay: 420ms; }
/* Growth Partner's scope items are one sentence each: body copy, not a list */
.sd-caps--2 .sd-cap__list li{ font-family: var(--font-body); font-size: var(--t-small); padding-left: 0; }
.sd-caps--2 .sd-cap__list li::before{ display: none; }

/* ============================================ v4.4 · capability cards
   Smaller, and each group is a card: a white title strip with the number on
   an ink chip, the list on a pale wash of the band below it. */
.sd-caps{ display: grid; gap: var(--s-4); border: 0; }
.sd-cap, .sd-cap:first-child{ border: 1.5px solid var(--ink); background: rgba(255, 255, 255, .38); box-shadow: 4px 4px 0 0 rgba(30, 25, 25, .14); }
.sd-cap__summary{ grid-template-columns: auto 1fr auto; gap: var(--s-3); padding: var(--s-3) var(--s-4); background: var(--white); border-bottom: 1.5px solid var(--ink); }
.sd-cap:not([open]) .sd-cap__summary{ border-bottom-color: transparent; }
.sd-cap__summary:hover, .sd-cap:focus-within .sd-cap__summary{ background: var(--white); }
.sd-cap__n{ display: inline-grid; place-items: center; min-width: 2rem; height: 1.6rem; padding: 0 .35rem; background: var(--ink); color: var(--yellow); font-size: .6875rem; letter-spacing: .08em; }
.sd-cap__t{ font-size: 1.0625rem; line-height: 1.2; letter-spacing: -.01em; }
.sd-cap__list{ gap: var(--s-2); grid-column: 1 / -1; padding: var(--s-4) var(--s-4) var(--s-5); }
.sd-cap__list li{ font-size: .75rem; line-height: 1.5; color: var(--ink); padding-left: var(--s-4); }
.sd-cap__list li::before{ top: .75em; width: 6px; background: var(--orange); }
@media (min-width: 700px){
  .sd-caps{ grid-template-columns: repeat(2, 1fr); border: 0; align-items: stretch; }
  .sd-cap{ border: 1.5px solid var(--ink); }
  .sd-cap__summary{ padding: var(--s-3) var(--s-4); grid-template-columns: auto 1fr; border-bottom-color: var(--ink) !important; }
  .sd-cap__list{ padding: var(--s-4) var(--s-4) var(--s-5); grid-column: 1 / -1; }
}
@media (min-width: 1060px){ .sd-caps{ grid-template-columns: repeat(3, 1fr); gap: var(--s-5); } }
.sd-caps-head .h2{ font-size: clamp(1.6rem, 1.1rem + 1.6vw, 2.4rem); }
/* v4.4: the service scenes are larger drawings; the tall one is held to the
   hero's height instead of running past it */
.sd-hero__img{ max-height: min(34rem, 66vh); object-fit: contain; }
@media (max-width: 859px){ .sd-hero__art{ max-width: 17rem; } .sd-hero__img{ max-height: 15rem; } }

/* v4.5 (10a): "keeps moving" is held together by a non-breaking space in the
   string itself (service-detail.js), not by a blanket nowrap here — a CSS rule
   would also catch Customer Acquisition's 24-character phrase and clip it
   behind .sd{ overflow-x: clip } on phones. */

/* v4.5 (9b): the route draws slower, and a car rides the head of the line so
   01-02-03 reads as travel rather than a line appearing. The car shares the
   path data with .sd-route__path, so it is always exactly at the drawn head.
   Guarded by @supports: where motion path is unavailable the car is simply
   not drawn, and the road behaves as it did before. */
html.sd-js .sd-route__path{ transition: stroke-dashoffset 2600ms var(--ease-out); }

.sd-route__car{ display: none; }
@supports (offset-path: path("M0,0 L1,1")){
  .sd-route__car{
    display: block; color: var(--ink);
    offset-path: path("M20,50 C220,5 320,60 450,32 C580,4 680,60 880,20");
    offset-rotate: auto;
    offset-distance: 100%;
  }
  html.sd-js .sd-route__car{
    offset-distance: 0%; opacity: 0;
    transition: offset-distance 2600ms var(--ease-out), opacity 260ms linear;
  }
  html.sd-js .sd-route__path.in ~ .sd-route__car{ offset-distance: 100%; opacity: 1; }
}
@media (prefers-reduced-motion: reduce){
  /* service.js returns before adding sd-js when reduced motion is set, so the
     animated rules never attach on load. This covers the case where the
     preference changes afterwards: it has to match the specificity of
     html.sd-js .sd-route__car to win the cascade, which .sd-route__car alone
     does not. */
  html.sd-js .sd-route__car,
  html.sd-js .sd-route__path.in ~ .sd-route__car{
    offset-distance: 100%; opacity: 1; transition: none;
  }
  html.sd-js .sd-route__path{ transition: none; }
}

/* v4.5 (9a): the route headline kept the right half of the band empty, because
   .sd-route-head is capped at 46rem. It now shares a row with a scene. */
.sd-route-top{ display: grid; gap: var(--s-7); align-items: center; }
@media (min-width: 900px){
  .sd-route-top{ grid-template-columns: minmax(0, 46rem) minmax(0, 1fr); gap: var(--s-8); }
}
/* v5.5 mark 6: "make this asset bigger much bigger the page looks empty". The
   art column was the leftover of a 46rem text column and rendered 459x157 in a
   band whose headline block is 736x347 — the picture read as a thumbnail beside
   the type. Two changes, both measured:
     - the text column drops to 36rem so the art gets the larger half. The lede
       is short enough that 36rem does not add a line at 1460 (checked).
     - rt-robots.webp was re-encoded from its surviving source clip at
       `4 300 52 7` -> 878x342 intrinsic, so the bigger box is still a DOWNSCALE
       rather than the upscale that made v5.4 mark 8 a defect. Cost 358KB -> 632KB
       on a service route, not the homepage. Raising quality instead was measured
       and rejected: q42 saved only 39KB. */
@media (min-width: 1100px){
  .sd-route-top{ grid-template-columns: minmax(0, 36rem) minmax(0, 1fr); }
}
.sd-route-art{ margin: 0; }
.sd-route-art img{ display: block; width: 100%; height: auto; max-width: none; }
/* rt-systems was generated without a side gutter, so it gets one here */
/* v5.4: rt-systems became rt-robots (marks 7/9/10 replaced all three route
   illustrations). The 6% inset stays with the slot, not with the old art: it is
   there because this band's asset is the widest and shortest of the three. */
.sd-route-art--rt-robots img{ padding-inline: 0; }
