/*
 * Trucker Path Services — page composition.
 *
 * LAYER 3 ONLY. Foundation owns tokens, typography roles, the container rail,
 * Button, Link and Icon; this file owns how those pieces are arranged on the
 * Services surfaces and nothing else. No colour is defined here that is not a
 * var(--tpl-*) reference, and no gradient is hand-rolled — the dark-hero
 * heading uses Foundation's named .tp-site-type-gradient-on-dark.
 *
 * Every selector is prefixed with .tp-services-page. That prefix is a
 * containment boundary against the legacy global CSS on this domain; it is not
 * a licence for a second palette or a parallel set of primitives.
 *
 * GEOMETRY FOLLOWS THE APPROVED PROTOTYPE. Where a value could not be carried
 * over verbatim it is noted inline; the two systematic cases are fractional
 * font sizes (mapped to the nearest named integer role) and page-local colours
 * (mapped to the nearest Foundation token).
 */

.tp-services-page {
  box-sizing: border-box;
}

.tp-services-page *,
.tp-services-page *::before,
.tp-services-page *::after {
  box-sizing: inherit;
}

/* ---------------------------------------------------------------- Hero ---- */

.tp-services-page.tp-services-hero {
  position: relative;
  /* The prototype's own --tp-nav-dark, now a Foundation role of its own.
     It used to borrow --tpl-ink-deep (#001728), which is the FOOTER colour —
     eight steps darker than the navigation surface this hero continues. */
  background: var(--tpl-ink-nav);
  color: var(--tpl-white);
  padding: 0;
}

.tp-services-page .tp-services-hero__inner {
  display: grid;
  min-height: 340px;
  /* The prototype's own two columns: a reading measure beside a 640px figure.
     The figure keeps its absolute width because the screenshot inside it is a
     fixed piece of artwork; the copy takes what the 1200px rail has left. The
     rail itself belongs to .tp-site-container and is not redefined here. */
  grid-template-columns: minmax(0, 1fr) 640px;
  gap: 40px;
  align-items: center;
}

/*
 * The shared header is fixed and sits over the top of a dark hero, so the
 * first block on the page reserves its height. Both measurements come from
 * Site Chrome's own custom properties rather than numbers copied out of it.
 */
.tp-site-chrome--dark-hero #tp-main > .tp-services-page.tp-services-hero:first-child .tp-services-hero__inner {
  padding-top: calc(var(--tp-site-announcement-height) + var(--tp-site-header-height));
}

.tp-services-page .tp-services-hero__copy {
  /* The prototype's own copy measure. Its rail is 1152px wide against this
     one's 1200px, and handing the 48px surplus to the text would re-wrap the
     H1 from three lines to two — which also shortens the hero row enough that
     the figure loses the air above it. The surplus goes to the gutter between
     the two columns instead. */
  max-width: 472px;
  padding: 48px 0;
}

.tp-services-page .tp-services-eyebrow {
  display: inline-flex;
  align-items: center;
  margin-bottom: 22px;
  padding: 7px 16px;
  /* THE BADGE IS BRANDED, NOT NEUTRAL. The prototype tints both the border and
     the fill with the accent itself (35% and 10%); the on-dark family is white
     at low alpha and rendered this as one more grey chip with blue text. */
  border: 1px solid var(--tpl-on-dark-accent-border);
  border-radius: 999px;
  background: var(--tpl-on-dark-accent-surface);
  color: var(--tpl-blue-bright);
  /* Prototype: 11.5px. Fractional sizes are not a density tool; this is the
     named Caption role. */
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  line-height: 1;
  text-transform: uppercase;
}

.tp-services-page .tp-services-hero__title {
  margin: 0 0 16px;
  font-family: var(--tpl-font-head);
  font-size: 52px;
  font-weight: 700;
  letter-spacing: -1.8px;
  line-height: 1.12;
}

.tp-services-page .tp-services-hero__lede {
  /* A reading measure, not the full 1200px rail. The rail itself is owned by
     .tp-site-container and is not redefined here. */
  max-width: 48ch;
  margin: 0;
  color: var(--tpl-on-dark-secondary);
  font-size: 18px;
  line-height: 1.65;
}

/*
 * The hero figure. It is bottom aligned so the screenshot runs off the foot of
 * the hero, and the frame's own corners are rounded only at the top for the
 * same reason.
 *
 * THE FADE IS A MASK, NOT A PAINTED OVERLAY. The prototype lays a gradient of
 * its nav-dark over the bottom 190px of the frame. Reproducing that literally
 * would mean writing an rgba ramp of a Foundation colour into this file, which
 * is the second palette the layering rules exist to prevent. Masking the
 * element instead lets the hero's own background show through, so the result
 * follows the token rather than a copy of it. The stops are the prototype's,
 * inverted: its 0/.18/.5/.82/1 overlay is this 1/.82/.5/.18/0 mask. The
 * rgba() stops below are alpha ramp, not palette: only the fourth channel is
 * read, and no colour of this page comes from them.
 */
.tp-services-page .tp-services-hero__media {
  align-self: end;
  width: 100%;
  padding: 10px 10px 0;
  border-radius: 16px 16px 0 0;
  background: var(--tpl-on-dark-surface);
  -webkit-mask-image: linear-gradient(
    180deg,
    rgba(0, 0, 0, 1) calc(100% - 190px),
    rgba(0, 0, 0, 0.82) calc(100% - 140px),
    rgba(0, 0, 0, 0.5) calc(100% - 95px),
    rgba(0, 0, 0, 0.18) calc(100% - 49px),
    rgba(0, 0, 0, 0) 100%
  );
  mask-image: linear-gradient(
    180deg,
    rgba(0, 0, 0, 1) calc(100% - 190px),
    rgba(0, 0, 0, 0.82) calc(100% - 140px),
    rgba(0, 0, 0, 0.5) calc(100% - 95px),
    rgba(0, 0, 0, 0.18) calc(100% - 49px),
    rgba(0, 0, 0, 0) 100%
  );
}

.tp-services-page .tp-services-hero__media-frame {
  display: block;
  overflow: hidden;
  border-radius: 10px 10px 0 0;
}

/* The 2px bleed is the prototype's: it keeps the resampled edge of the
   screenshot from leaving a hairline inside the rounded corners. */
.tp-services-page .tp-services-hero__media img {
  display: block;
  width: calc(100% + 4px);
  height: 382px;
  margin: -2px -2px 0;
  object-fit: cover;
  object-position: left top;
}

/* -------------------------------------------------------------- Search ---- */

.tp-services-page .tp-services-searchwrap {
  position: relative;
  z-index: 5;
  /* Straddles the hero / white boundary, as the prototype does. The matching
     top padding on the next section reserves the overlap. */
  transform: translateY(80px);
}

.tp-services-page .tp-services-search {
  display: grid;
  grid-template-columns: 0.95fr 1.5fr 0.75fr auto;
  align-items: stretch;
  border-radius: 16px;
  background: var(--tpl-white);
  box-shadow: 0 8px 24px rgba(1, 25, 50, 0.18);
  text-align: left;
}

.tp-services-page .tp-services-search__field {
  /* THE PANEL'S CONTAINING BLOCK, as it is in the source — its own field label
     carries `position:relative` (proto @98062). Without it the suggestion
     panel resolves `left`/`right` against `.tp-services-searchwrap`, the whole
     card, and lands beside the field it belongs to rather than under it. */
  position: relative;
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 5px;
  margin: 14px 0;
  padding: 4px 24px;
  border-right: 1px solid var(--tpl-line-soft);
}

/* THE THIRD CELL IS NARROWER, IN THE DESIGN SOURCE TOO. `Within` holds the
   shortest value on the card ("50 miles") and sits against the submit key, so
   the prototype gives it 20px of side padding where the other two take 24px.
   Four pixels, but they are what keeps the chevron off the button. */
.tp-services-page .tp-services-search__field--last {
  padding: 4px 20px;
}

.tp-services-page .tp-services-search__label {
  color: var(--tpl-ink-soft);
  /* Prototype: 10.5px. Named Caption role instead. */
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.11em;
  line-height: 1;
  text-transform: uppercase;
}

.tp-services-page .tp-services-search__field select,
.tp-services-page .tp-services-search__field input {
  width: 100%;
  min-width: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--tpl-ink);
  font-family: inherit;
  /* The prototype's 18px. Body L is a named role, so this is carried over as
     written rather than mapped down; the box is the page's primary control and
     reads as one at this size. */
  font-size: 18px;
  font-weight: 500;
  line-height: 28px;
}

/* The design source's own -2px. A select carries a little left inset of its
   own that an input does not, and this pulls the two back onto one line. */
.tp-services-page .tp-services-search__field select {
  margin-left: -2px;
}

/*
 * The disclosure chevron, not the operating system's. Left native it is a
 * different shape on every platform and none of them is the one the design
 * source draws.
 *
 * DRAWN TO THE DESIGN SOURCE, NOT COPIED FROM `.tp-site-select`. The shared
 * field's chevron is 18px in --tpl-ink-soft; this one is the prototype's own
 * 17px in #6B7A87, a step darker. The two are separate marks on purpose — the
 * shared one sits in a bordered 40px control, this one inside an 18px
 * borderless field on a white card — so this is not the Foundation asset with
 * a tweak, and changing one must not silently change the other.
 *
 * The stroke is written into the data URI because that is the only place an
 * SVG `stroke` can live; it cannot read a custom property. #6B7A87 has no
 * token because nothing else on this domain uses it.
 */
.tp-services-page .tp-services-search__field select {
  padding-right: 26px;
  -webkit-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236B7A87' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-position: right 4px center;
  background-repeat: no-repeat;
  background-size: 17px 17px;
}

.tp-services-page .tp-services-search__field input::placeholder {
  color: var(--tpl-ink-faint);
  font-weight: 400;
}

/* KEYBOARD ONLY. The design source draws no ring on these controls, and a
   driver who clicks the box is already looking at it; design-system.md §7
   still requires a visible focus for the keyboard, so the ring stays and the
   pointer stands it down — the inline script under the search form in
   hub.blade.php sets `data-quiet-focus` for the one focus a pointer caused.
   Inline rather than deferred on purpose: this rule paints from the first
   frame, so whatever withholds it has to be armed just as early, or a slow
   network opens a window in which a click draws the ring. A select is not
   marked because the UA already withholds `:focus-visible` from a clicked
   one. */
/* .tp-services-page .tp-services-search__field select:focus-visible,
.tp-services-page .tp-services-search__field input:focus-visible {
  outline: 2px solid var(--tpl-blue);
  outline-offset: 2px;
} */

.tp-services-page .tp-services-search__field input[data-quiet-focus]:focus-visible {
  outline: none;
}

.tp-services-page .tp-services-search__submit {
  display: flex;
  align-items: center;
  padding: 14px;
}

.tp-services-page .tp-services-search__button {
  display: flex;
  height: 100%;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 0 26px;
  border: 0;
  border-radius: 11px;
  background: var(--tpl-blue);
  color: var(--tpl-white);
  cursor: pointer;
  font-family: inherit;
  font-size: 15px;
  font-weight: 500;
  white-space: nowrap;
  transition: background-color 140ms ease;
}

.tp-services-page .tp-services-search__button:hover,
.tp-services-page .tp-services-search__button:focus-visible {
  background: var(--tpl-blue-strong);
}

/*
 * Waiting for a place to be chosen. Set by services-hub.js and never in the
 * HTML, so a page without JavaScript never reaches this state.
 *
 * It has to read as unavailable rather than merely quiet: a full-strength
 * button that does nothing when clicked is the worse of the two failures.
 */
.tp-services-page .tp-services-search__button:disabled {
  background: var(--tpl-line);
  color: var(--tpl-ink-soft);
  cursor: not-allowed;
}

.tp-services-page .tp-services-search__button:disabled:hover {
  background: var(--tpl-line);
}

.tp-services-page .tp-services-search__button .tp-site-icon {
  fill: currentColor;
}

/* ----------------------------------------------------------- Shortcuts ---- */

.tp-services-page .tp-services-shortcuts {
  display: flex;
  align-items: center;
  gap: 22px;
  margin-top: 16px;
  flex-wrap: wrap;
}

.tp-services-page .tp-services-shortcut {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--tpl-blue-bright);
  /* Prototype: 13.5px. Named Body Small role instead. */
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
}

.tp-services-page .tp-services-shortcut:hover,
.tp-services-page .tp-services-shortcut:focus-visible {
  text-decoration: underline;
}

.tp-services-page .tp-services-shortcut .tp-site-icon {
  fill: currentColor;
}

/* --------------------------------------------------------------- Body ----- */

.tp-services-page.tp-services-main {
  /* 200px absorbs the search card's 80px overlap and keeps the prototype's
     air between it and the first heading. The claims band owns the space at
     the foot, so there is none to add here. */
  padding: 200px 0 0;
  background: var(--tpl-white);
  color: var(--tpl-ink);
}

.tp-services-page .tp-services-section + .tp-services-section {
  margin-top: 52px;
}

.tp-services-page .tp-services-section__title {
  margin: 0 0 22px;
  color: var(--tpl-ink);
  font-family: var(--tpl-font-head);
  font-size: 34px;
  font-weight: 700;
  letter-spacing: -1.5px;
  line-height: 1.15;
}

/* -------------------------------------------------------------- Tiles ----- */

.tp-services-page .tp-services-tiles {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tp-services-page .tp-services-tile {
  display: flex;
  height: 100%;
  align-items: center;
  gap: 18px;
  padding: 24px 22px;
  border: 1px solid var(--tpl-line-soft);
  border-radius: 12px;
  background: var(--tpl-white);
  color: inherit;
  text-decoration: none;
  transition: box-shadow 240ms ease, border-color 140ms ease;
}

.tp-services-page .tp-services-tile:hover,
.tp-services-page .tp-services-tile:focus-visible {
  border-color: var(--tpl-line);
  box-shadow: 0 4px 24px rgba(1, 25, 50, 0.1);
}

.tp-services-page .tp-services-tile__icon {
  display: block;
  width: 40px;
  height: 40px;
  flex: none;
  object-fit: contain;
}

.tp-services-page .tp-services-tile__copy {
  display: block;
  min-width: 0;
  flex: 1;
}

.tp-services-page .tp-services-tile__label {
  display: block;
  color: var(--tpl-ink);
  font-size: 17px;
  font-weight: 600;
  line-height: 1.3;
}

.tp-services-page .tp-services-tile__count {
  display: block;
  margin-top: 3px;
  color: var(--tpl-ink-soft);
  /* Prototype: 12.5px. Named Caption role instead. */
  font-size: 12px;
}

/* ------------------------------------------------------------- Claims ----- */

.tp-services-page .tp-services-claims-band {
  padding: 64px 0 8px;
  margin-bottom: 44px;
}

.tp-services-page .tp-services-claims {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tp-services-page .tp-services-claim {
  padding: 26px 24px;
  border: 1px solid var(--tpl-line-soft);
  border-radius: 14px;
  background: var(--tpl-surface-alt);
  transition: background-color 180ms ease, box-shadow 180ms ease;
}

.tp-services-page .tp-services-claim:hover {
  background: var(--tpl-white);
  box-shadow: 0 8px 32px rgba(1, 25, 50, 0.1);
}

/* A type selector here outranks the three .tp-services-claim__* rules below
   it, so a blanket `margin: 0` silently cancelled the 8px and 12px the
   prototype puts between the value, the title and the body. Only the last
   paragraph needs its trailing margin removed. */
.tp-services-page .tp-services-claim p {
  margin-top: 0;
}

.tp-services-page .tp-services-claim p:last-child {
  margin-bottom: 0;
}

.tp-services-page .tp-services-claim__value {
  margin-bottom: 8px;
  color: var(--tpl-ink);
  font-family: var(--tpl-font-head);
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.8px;
  line-height: 1.1;
}

.tp-services-page .tp-services-claim__title {
  margin-bottom: 12px;
  color: var(--tpl-ink);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
}

.tp-services-page .tp-services-claim__body {
  color: var(--tpl-ink-secondary);
  font-size: 14px;
  line-height: 1.7;
}

/* ------------------------------------------------------------- Browse ----- */

.tp-services-page.tp-services-browse {
  border-top: 1px solid var(--tpl-line);
  background: var(--tpl-surface-alt);
}

.tp-services-page .tp-services-browse__inner {
  display: flex;
  flex-direction: column;
  gap: 30px;
  padding-top: 38px;
  padding-bottom: 50px;
}

.tp-services-page .tp-services-browse__title {
  margin: 0 0 10px;
  color: var(--tpl-ink-soft);
  /* Prototype: 11.5px. Named Caption role instead. */
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.09em;
  line-height: 1.4;
  text-transform: uppercase;
}

.tp-services-page .tp-services-browse__links {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tp-services-page .tp-services-browse__links li {
  display: flex;
  align-items: baseline;
}

.tp-services-page .tp-services-browse__links a {
  color: var(--tpl-link);
  /* Prototype: 13.5px. Named Body Small role instead. */
  font-size: 14px;
  text-decoration: none;
}

.tp-services-page .tp-services-browse__links a:hover,
.tp-services-page .tp-services-browse__links a:focus-visible {
  text-decoration: underline;
}

.tp-services-page .tp-services-browse__sep {
  padding: 0 9px;
  color: var(--tpl-ink-faint);
}

/* The last item in a group has nothing after it to separate from. */
.tp-services-page .tp-services-browse__links li:last-child .tp-services-browse__sep {
  display: none;
}

/* -------------------------------------------------------------- Empty ----- */

.tp-services-page .tp-services-empty {
  padding: 32px;
  border: 1px solid var(--tpl-line);
  border-radius: 12px;
  background: var(--tpl-surface-alt);
}

.tp-services-page .tp-services-empty p {
  margin: 0;
}

.tp-services-page .tp-services-empty p + p {
  margin-top: 8px;
  color: var(--tpl-ink-secondary);
}

/* ------------------------------------------------- Below the full rail ---- */

/*
 * The prototype's hero is a 472px measure beside a 640px figure on an 1152px
 * rail, and those two only both hold their size while the rail is full. Under
 * that width the split stays in the prototype's proportion rather than the
 * copy paying for all of the loss: a fixed figure against a shrinking column
 * reaches a 300px measure at 1024px, which is not a column a 52px heading can
 * be set in.
 */
@media screen and (max-width: 1199px) {
  .tp-services-page .tp-services-hero__inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
  }

  .tp-services-page .tp-services-hero__copy {
    max-width: none;
  }
}

/* ------------------------------------------------------ Narrow desktop ---- */

/*
 * A component edge, not a third page tier. design-system.md §3.5 allows a
 * smaller breakpoint for a definite local structural change and forbids it
 * becoming a second typographic system: nothing here touches type or the
 * container. What changes is arity — four tiles to two, three claims to two,
 * four search cells to two, and the hero figure out — because at this width
 * those rows are compressed rather than merely narrow.
 */
@media screen and (max-width: 1023px) {
  .tp-services-page .tp-services-tiles {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .tp-services-page .tp-services-claims {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .tp-services-page .tp-services-hero__inner {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }

  .tp-services-page .tp-services-hero__media {
    display: none;
  }

  .tp-services-page .tp-services-search {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .tp-services-page .tp-services-search__field--last {
    border-right: 0;
  }

  .tp-services-page .tp-services-search__submit {
    grid-column: 1 / -1;
    border-top: 1px solid var(--tpl-line-soft);
  }

  .tp-services-page .tp-services-search__button {
    width: 100%;
    height: 48px;
  }
}

/* -------------------------------------------------------------- Phone ----- */

/*
 * 809px, NOT 743px. design-system.md §3.5 sets the tiers for new page bodies at
 * Desktop >=1200 / Tablet 810-1199 / Phone <810, and names 743px explicitly as a
 * Site Chrome compatibility edge that must not be copied into a new page body.
 *
 * It also has to be 809 to be correct: site-design.css switches
 * --tp-site-gutter to its mobile value at 809, so every .tp-site-container on
 * this page was already narrowing there. At 743 the type and the grid changed
 * 66px later than the gutter did, and 744-809px rendered desktop headings
 * inside phone margins.
 */
@media screen and (max-width: 809px) {
  .tp-services-page .tp-services-hero__copy {
    padding: 32px 0;
  }

  .tp-services-page .tp-services-hero__title {
    font-size: 36px;
    letter-spacing: -1px;
  }

  .tp-services-page .tp-services-hero__lede {
    font-size: 16px;
  }

  /* On a phone the card does not straddle the hero/white seam. The prototype
     keeps the whole search card AND the shortcut stack on the dark hero, with
     white starting only at "What We Cover". Drop the overlap so the hero box
     grows to contain them; the matching reserve on .tp-services-main comes off
     below. */
  .tp-services-page .tp-services-searchwrap {
    transform: none;
    padding-bottom: 36px;
  }

  /* A vertical stack on the dark hero, not a wrapping row: measured, the row's
     last item spilled past the dark boundary onto the white section below
     (y=840 against a hero ending at y=821). */
  .tp-services-page .tp-services-shortcuts {
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
    margin-top: 20px;
  }

  .tp-services-page .tp-services-search {
    grid-template-columns: minmax(0, 1fr);
  }

  .tp-services-page .tp-services-search__field {
    margin: 0;
    padding: 14px 20px;
    border-right: 0;
    border-bottom: 1px solid var(--tpl-line-soft);
  }

  /* The field has no margin here, so its own bottom IS where the next row
     starts — the 14px that clears the card at full width would be a gap inside
     it. Only the air is left. */
  .tp-services-page .tp-services-search__field .tp-services-suggest {
    top: calc(100% + 6px);
  }

  .tp-services-page .tp-services-search__submit {
    border-top: 0;
  }

  /* No straddle on phone (see .tp-services-searchwrap above), so there is no
     card overlap to reserve — just normal section air. */
  .tp-services-page.tp-services-main {
    padding: 40px 0 0;
  }

  /* Prototype hub (mobile): "What We Cover" is a 2-column tile grid, not one
     column. Compact the tile (smaller padding/gap/icon) so two fit on a phone. */
  .tp-services-page .tp-services-tiles {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
  }

  .tp-services-page .tp-services-tile {
    gap: 11px;
    padding: 14px;
  }

  .tp-services-page .tp-services-tile__icon {
    width: 32px;
    height: 32px;
  }

  /* Prototype hub (mobile): "Why This Directory Is Different" is stacked text
     blocks under a divider, not gray cards. Strip the card treatment on phone;
     spacing + type carry the separation. Desktop/tablet keep their cards. */
  .tp-services-page .tp-services-claims-band {
    padding: 32px 0 8px;
    margin-bottom: 32px;
    border-top: 1px solid var(--tpl-line-soft);
  }

  .tp-services-page .tp-services-claims {
    grid-template-columns: minmax(0, 1fr);
    gap: 26px;
  }

  .tp-services-page .tp-services-claim {
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
  }

  /* Prototype claims are plain text blocks, not interactive cards — no bg/shadow
     change on tap/hover (on touch, :hover sticks after a tap and would flash the
     block white). Neutralize the card hover on phone. */
  .tp-services-page .tp-services-claim:hover {
    background: transparent;
    box-shadow: none;
  }

  /* Prototype hub (mobile) has no heading for this area — the claims follow the
     divider directly. Hide the visible title on phone only; it stays in the DOM
     so the section keeps its accessible name (aria-labelledby) and SEO text. */
  .tp-services-page .tp-services-claims-band .tp-services-section__title {
    display: none;
  }

  .tp-services-page .tp-services-section__title {
    font-size: 26px;
    letter-spacing: -0.5px;
  }

  .tp-services-page .tp-services-section + .tp-services-section {
    margin-top: 40px;
  }
}

/* ------------------------------------------------- Blocked permission ----- */

/*
 * The only thing left of the location gate's own surface. The primer dialog
 * that used to stand here — our reason over a replica of the browser's
 * permission sheet — was removed 2026-09-22; the request now goes straight to
 * the browser. This line is what a refusal looks like, and it has to exist
 * because a refused browser will not prompt again.
 */

.tp-services-page .tp-services-geo-blocked {
  margin: 14px 0 0;
  color: var(--tpl-ink-secondary);
  font-size: 14px;
  line-height: 1.6;
}

/* Nothing has happened yet, so nothing is reserved. */
.tp-services-page .tp-services-geo-blocked:empty {
  display: none;
}

/* ==================================================== Search view ========= */

/*
 * Option A's application screen. A full-viewport three-column layout: filters,
 * results, map. Correct here and only here — this page is noindex, so controls
 * and a dominant map may own the first screen without costing search traffic.
 */

.tp-services-page.tp-services-search-page {
  background: var(--tpl-white);
  color: var(--tpl-ink);
}

.tp-services-page .tp-services-toolbar {
  flex: none;
}

/* ------------------------------------------------------------ Toolbar ----- */

/* A BAND, NOT A CONTINUATION OF THE LIST. The design source puts the query on
   --tp-bg-gray under the nav; white made it read as the top of the results
   column rather than as the control strip above all three. */
.tp-services-page .tp-services-toolbar {
  border-bottom: 1px solid var(--tpl-line);
  background: var(--tpl-surface-alt);
}

/*
 * Clear the fixed header, whose height Site Chrome publishes. Applied to the
 * sentinel rather than to the toolbar so the reserved space and the element
 * that sets the header's treatment stay the same object.
 */
/*
 * `.tpl-hero` brings a dark gradient and, on a dark-hero body, a large
 * padding-top. Both are neutralised here: this element only reserves the fixed
 * header's height and gives Site Chrome something to measure.
 *
 * The compound selector matches the specificity of the layout rule it has to
 * beat rather than relying on source order.
 */
/* ------------------------------------------------------------- Top bar ---- */

/*
 * The Services tree's own header. See services.partials._product-header for
 * why these pages do not wear the marketing one.
 *
 * STICKY, AND THAT IS THE WHOLE REASON THE SENTINELS ARE GONE. The marketing
 * header is `position: fixed` and reserves no space, so each Services page had
 * to reserve 114px for it and then tell Site Chrome where its dark hero ended.
 * Three mechanisms for one problem the flow solves by itself.
 */
.tp-services-topbar {
  position: sticky;
  z-index: 60;
  top: 0;
  /* Same role as the hero it sits on — see .tp-services-hero. */
  background: var(--tpl-ink-nav);
}

.tp-services-topbar__inner {
  display: flex;
  align-items: center;
  /* The design source's own 48px. */
  gap: 48px;
  /* Not .tp-site-container: the design source's bar runs the full width with
     its own 18px gutter, because the screen below it is a three-column
     application rather than a reading measure. */
  min-height: 72px;
  padding: 0 18px;
}

.tp-services-topbar__logo {
  display: block;
  flex: none;
  line-height: 0;
}

.tp-services-topbar__logo img {
  display: block;
  width: auto;
  /* 36px, the design source's own height. The shared asset is 197x36 and the
     prototype's is 1373x251 — the same 5.47 ratio — so at this height the mark
     is 197px wide in both, to the pixel. It was set to 22px, which is the
     marketing header's size, not this bar's. */
  height: 36px;
}

.tp-services-topbar__spacer {
  flex: 1;
}

.tp-services-topbar__link {
  flex: none;
  color: var(--tpl-white);
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}

.tp-services-topbar__link:hover,
.tp-services-topbar__link:focus-visible {
  color: var(--tpl-white);
  text-decoration: underline;
}

/* Same edge as the page below it. This bar used to switch at 767px while the
   hero and the search card switched at 743px, so 744-767px showed a phone bar
   over a tablet page. */
@media screen and (max-width: 809px) {
  .tp-services-topbar__inner {
    min-height: 60px;
    gap: 14px;
    padding: 0 16px;
  }

  .tp-services-topbar__logo img {
    height: 28px;
  }

  .tp-services-topbar__link {
    font-size: 12px;
  }
}

.tp-services-page .tp-services-toolbar__inner {
  display: flex;
  align-items: center;
  /* The design source's own 20px 18px / 14px. */
  gap: 14px;
  padding: 20px 18px;
}

.tp-services-page .tp-services-toolbar__form {
  display: flex;
  flex: none;
  align-items: center;
  gap: 8px;
}

.tp-services-page .tp-services-toolbar__where {
  display: flex;
  /* The design source's 230px. The field sits in a row with the radius select,
     the category rail and two buttons; taking 280 pushed the rail's scroll
     start 50px to the right on every width. */
  width: 230px;
  height: 38px;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  border: 1px solid var(--tpl-line);
  border-radius: 999px;
  background: var(--tpl-white);
  transition: border-color 140ms ease;
}

.tp-services-page .tp-services-toolbar__where:focus-within {
  border-color: var(--tpl-blue);
}

.tp-services-page .tp-services-toolbar__where .tp-site-icon {
  flex: none;
  fill: var(--tpl-ink-soft);
}

.tp-services-page .tp-services-toolbar__where input {
  width: 100%;
  min-width: 0;
  border: 0;
  background: transparent;
  color: var(--tpl-ink);
  font-family: inherit;
  /* Prototype: 12.5px. Named Body Small role instead. */
  font-size: 13px;
  font-weight: 500;
}

.tp-services-page .tp-services-toolbar__where input:focus-visible {
  outline: none;
}

/* The same chevron the hub's search card carries, at this bar's own size: the
   design source draws it 15px and 12px in from the edge, against the hub's 17px
   at 4px. The 34px of right padding is what keeps "50 miles" off it. */
.tp-services-page .tp-services-toolbar__radius {
  height: 38px;
  padding: 0 34px 0 14px;
  border: 1px solid var(--tpl-line);
  border-radius: 999px;
  -webkit-appearance: none;
  appearance: none;
  background-color: var(--tpl-white);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236B7A87' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-position: right 12px center;
  background-repeat: no-repeat;
  background-size: 15px 15px;
  color: var(--tpl-ink);
  font-family: inherit;
  /* Prototype: 12.5px, same as the Where field beside it. */
  font-size: 13px;
  font-weight: 500;
}

.tp-services-page .tp-services-toolbar__rail {
  display: flex;
  min-width: 0;
  flex: 1;
  gap: 8px;
  overflow-x: auto;
}

/* A rule between the query and the category rail, as the prototype has. */
.tp-services-page .tp-services-toolbar__divide {
  width: 1px;
  height: 24px;
  flex: none;
  background: var(--tpl-line);
}

.tp-services-page .tp-services-railitem {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 15px;
  border: 1px solid var(--tpl-line);
  border-radius: 999px;
  background: var(--tpl-white);
  color: var(--tpl-ink);
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color 140ms ease, background-color 140ms ease, color 140ms ease;
}

.tp-services-page .tp-services-railitem:hover,
.tp-services-page .tp-services-railitem:focus-visible {
  border-color: var(--tpl-blue);
  color: var(--tpl-blue);
}

/* The selected category is brand blue, not ink: the rail is a filter, and the
   selection is the page's own accent rather than a heavier surface. */
.tp-services-page .tp-services-railitem.is-active {
  border-color: var(--tpl-blue);
  background: var(--tpl-blue);
  color: var(--tpl-white);
}

.tp-services-page .tp-services-railitem__icon {
  display: block;
  width: 18px;
  height: 18px;
  flex: none;
  object-fit: contain;
}

/* The icons are dark-stroked SVGs served as <img>, so their colour cannot be
   inherited. On the selected chip's blue they are inverted to white rather
   than left as near-black on blue. */
.tp-services-page .tp-services-railitem.is-active .tp-services-railitem__icon {
  filter: brightness(0) invert(1);
}

.tp-services-page .tp-services-railitem__n {
  color: var(--tpl-ink-soft);
  /* The design source's own 11px: the count is a footnote to the label beside
     it, not a second label. */
  font-size: 11px;
  font-weight: 500;
}

.tp-services-page .tp-services-railitem.is-active .tp-services-railitem__n {
  color: var(--tpl-on-dark-secondary);
}

/* ------------------------------------------------------------ Columns ----- */

/*
 * The prototype subtracts a fixed 151px for the chrome above this grid. That
 * number is only right for the chrome it was drawn against — here the
 * announcement bar, header and toolbar are each their own height, and the sum
 * is 26px different, which shows up as a page that scrolls by exactly that.
 *
 * A flex column measures it instead: the sentinel and toolbar take what they
 * need, the grid takes the rest, and the page is exactly one viewport tall
 * whatever the chrome does.
 */
.tp-services-page.tp-services-search-page {
  display: flex;
  flex-direction: column;
  /* The sentinel above this element already occupies the fixed chrome's
     height, so one viewport minus that is what is left to fill. */
  height: calc(100vh - var(--tp-site-announcement-height) - var(--tp-site-header-height));
}

.tp-services-page .tp-services-results {
  display: grid;
  min-height: 0;
  flex: 1;
  grid-template-columns: 225px 500px minmax(0, 1fr);
}

/* ------------------------------------------------------------ Filters ----- */

.tp-services-page .tp-services-filters {
  padding: 18px;
  border-right: 1px solid var(--tpl-line);
  overflow-y: auto;
}

.tp-services-page .tp-services-filters__title {
  margin: 0 0 14px;
  color: var(--tpl-ink);
  font-size: 15px;
  font-weight: 600;
}

.tp-services-page .tp-services-filters__group + .tp-services-filters__group {
  margin-top: 18px;
}

/* A HEADING, NOT AN OVERLINE. The design source sets these in the primary ink
   at .05em and does not upper-case them — they name the group you are choosing
   inside. Rendering them as soft grey small-caps pushed them behind the very
   options they label. */
.tp-services-page .tp-services-filters__legend {
  margin: 0 0 9px;
  color: var(--tpl-ink);
  /* Prototype: 11.5px. Named Caption role instead. */
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.05em;
}

.tp-services-page .tp-services-filters__items {
  display: flex;
  flex-direction: column;
  gap: 9px;
}

/* Density only. The box, its checked state and its focus ring belong to
   `.tp-site-checkbox`; this rule sets the size and colour the rail reads at and
   centres the mark against a single-line label. */
.tp-services-page .tp-services-filters__item {
  align-items: center;
  gap: 9px;
  color: var(--tpl-ink-secondary);
  /* Prototype: 13.5px. Named Body Small role instead. */
  font-size: 13px;
  line-height: 1.4;
}

.tp-services-page .tp-services-filters__item .tp-site-checkbox__mark {
  margin-top: 0;
}

/* ------------------------------------------------------------- Results ---- */

/* The head is fixed and the answer takes what is left. Stated here because the
   loading placeholder sizes itself against that remainder — without it the
   skeleton has no height to fill and ends in a band of white. */
.tp-services-page .tp-services-list {
  display: flex;
  flex-direction: column;
  padding: 16px;
  border-right: 1px solid var(--tpl-line);
  overflow-y: auto;
}

.tp-services-page .tp-services-results-region {
  flex: 1;
  min-height: 0;
}

.tp-services-page .tp-services-list__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  /* The design source's own 4px. The gap that separates the head from the rows
     belongs to whatever sits between them, not to the head. */
  margin-bottom: 4px;
}

/* THE COUNT IS A COLUMN HEADING, NOT A PAGE TITLE. The design source sets it
   at 15px/600 — the same weight as a result's name — because the three columns
   are one application screen and no part of it should read as a document
   title. It had grown to 20px/700, which made the list look like the page and
   the map like an illustration beside it. */
.tp-services-page .tp-services-list__count {
  margin: 0;
  color: var(--tpl-ink);
  font-family: var(--tpl-font-head);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
}

.tp-services-page .tp-services-list__fixture-note {
  margin: 0 0 12px;
  padding: 10px 14px;
  border-left: 3px solid var(--tpl-line);
  background: var(--tpl-surface-alt);
  color: var(--tpl-ink-soft);
  font-size: 12px;
  line-height: 1.6;
}

/* The design source's note under the count. It carried only a top margin, so
   it ended flush against the first card — the paragraph and the list read as
   one block. The 12px below is what separates a note about the search from the
   answer to it. */
.tp-services-page .tp-services-list__anchor {
  margin: 0 0 12px;
  color: var(--tpl-ink-soft);
  font-size: 12px;
  line-height: 1.6;
}

.tp-services-page .tp-services-list__sort {
  flex: none;
  color: var(--tpl-ink-soft);
  font-size: 12px;
}

.tp-services-page .tp-services-list__sub {
  margin: 6px 0 14px;
  color: var(--tpl-ink-secondary);
  font-size: 13px;
  line-height: 1.6;
}

.tp-services-page .tp-services-rows {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A RESULT ROW, TO THE DESIGN SOURCE'S OWN GEOMETRY.
 *
 * Every number below is the prototype's, not an approximation: card radius 10
 * and padding 14/15, an 18px pin, a 15px/1.3 name, a 12px grey meta line, a
 * 6px-radius button pair with a 7px gap.
 *
 * TWO FONT SIZES ARE ROUNDED, AND THAT IS DELIBERATE. The source specifies
 * 9.5px for the pin, 11.5px for the buttons and 12.5px for the reach line.
 * AGENTS.md: "Fractional font-size values such as 12.5px are not valid density
 * tools: map the content to Caption, Body Small, Body". They map to 12, 12
 * and 13.
 */
.tp-services-page .tp-services-row {
  padding: 14px 15px;
  border: 1px solid var(--tpl-line);
  border-radius: 12px;
  background: var(--tpl-white);
  transition: border-color 140ms ease, box-shadow 180ms ease;
}

.tp-services-page .tp-services-row:hover {
  border-color: var(--tpl-line);
  box-shadow: 0 4px 16px rgba(1, 25, 50, 0.08);
}

.tp-services-page .tp-services-row__head {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

/* The same number the map marker carries. That is the only reason it is here. */
.tp-services-page .tp-services-row__idx {
  display: flex;
  width: 18px;
  height: 18px;
  flex: none;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--tpl-blue);
  color: var(--tpl-white);
  font-size: 12px;
  font-weight: 600;
}

.tp-services-page .tp-services-row__name {
  flex: 1;
  min-width: 0;
  color: var(--tpl-ink);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  text-decoration: none;
}

/* A row with no page behind it keeps the name as text rather than linking
 * somewhere that 404s. It has to read the same either way. */
.tp-services-page .tp-services-row__name_flat {
  cursor: default;
}

.tp-services-page .tp-services-row__name:hover,
.tp-services-page .tp-services-row__name:focus-visible {
  text-decoration: underline;
}

/* One grey line carrying the junction, the score and the kind of place — the
 * position the design source fills with exit, rating, hours, rate and kind. */
/* THE RATING SITS IN THE META LINE, NOT ABOVE IT. The shared compact variant
   renders 16px/700, which on this 12px row came out larger than the shop's own
   name one line up and pulled the eye to the score before the business. The
   design source keeps it level with the text around it: the row's size, one
   weight heavier, with a 13px mark. Overridden here rather than in the shared
   variant because other surfaces use it at its own scale. */
.tp-services-page .tp-services-row__meta .tp-data-rating_compact {
  gap: 5px;
  font-size: 12px;
  font-weight: 600;
  /* The variant carries `line-height: 24px` for the surfaces it was built for.
     Left standing it makes the score a 24px-tall box inside a 12px line and
     stretches the whole meta row around it; the design source's score is just
     text on that row. */
  line-height: inherit;
}

/* THE MARK AND THE GLYPH INSIDE IT ARE TWO BOXES. `__mark` is a wrapper; the
   `components.site.icon` it holds is `size: sm`, which is 16px. Resizing only
   the wrapper left a 16px star in a 13px box — it overflowed 3px past the
   bottom and read as sitting below the number it belongs to. Both are set. */
.tp-services-page .tp-services-row__meta .tp-data-rating__mark,
.tp-services-page .tp-services-row__meta .tp-data-rating__mark > .tp-site-icon {
  width: 13px;
  height: 13px;
}

.tp-services-page .tp-services-row__meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 5px;
  color: var(--tpl-ink-soft);
  font-size: 12px;
}

.tp-services-page .tp-services-row__dot {
  color: var(--tpl-ink-faint);
}

/* Distance, in the design's green. `--tpl-go` is the Foundation's own token at
 * the value the design system calls `--tp-success`. */
.tp-services-page .tp-services-row__reach {
  margin-top: 6px;
  color: var(--tpl-go);
  font-size: 13px;
  font-weight: 500;
}

.tp-services-page .tp-services-row__counts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}

.tp-services-page .tp-services-row__counts li {
  color: var(--tpl-ink-secondary);
  font-size: 12px;
}

.tp-services-page .tp-services-row__counts li::after {
  margin-left: 6px;
  color: var(--tpl-line);
  content: "\00b7";
}

.tp-services-page .tp-services-row__counts li:last-child::after {
  content: none;
}

.tp-services-page .tp-services-row__counts strong {
  color: var(--tpl-ink);
  font-weight: 600;
}

/* How many of the total are paid — a qualifier on the number beside it, not a
   count of its own, so it stays at the line's own weight. */
.tp-services-page .tp-services-row__count-note {
  color: var(--tpl-ink-faint);
}

/* --------------------------------------------------- Unconfirmed band ---- */

/*
 * The line between the rows a filter confirmed and the rows it could not
 * judge.
 *
 * Quiet on purpose. It is not a warning and the rows under it are not worse
 * results — they are results we know less about, and a driver reading past it
 * should feel informed rather than warned off.
 */
.tp-services-page .tp-services-unconfirmed {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 18px 0 14px;
}

.tp-services-page .tp-services-unconfirmed__rule {
  flex: none;
  width: 24px;
  height: 1px;
  background: var(--tpl-line);
}

.tp-services-page .tp-services-unconfirmed__note {
  margin: 0;
  color: var(--tpl-ink-soft);
  font-size: 13px;
  line-height: 1.5;
}

/* TWO BUTTONS, EQUAL WIDTH. The design's pair: primary then Open, `gap: 7px`,
 * `margin-top: 11px`, both `flex: 1`.
 *
 * Neither is filled. The design fills the primary only for book and eta, and
 * its own unclaimed branch — the one every row here lands on — returns
 * `kind: 'call'`, whose style is the neutral outline. */
.tp-services-page .tp-services-row__actions {
  display: flex;
  gap: 7px;
  margin-top: 11px;
}

/* THE TWO ARE NOT THE SAME SIZE IN THE DESIGN SOURCE. The primary action is
   13px on 10px of padding, the secondary 11.5px on 8px — the pair reads as an
   action and its alternative rather than as two equal choices. They had been
   flattened to one 12px/9px rule for both. */
.tp-services-page .tp-services-row__call,
.tp-services-page .tp-services-row__listing {
  flex: 1;
  border-radius: 6px;
  background: var(--tpl-white);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
  white-space: nowrap;
  transition: background-color 140ms ease;
}

.tp-services-page .tp-services-row__call {
  padding: 10px 0;
  border: 1.5px solid var(--tpl-line);
  color: var(--tpl-ink);
  font-size: 13px;
}

.tp-services-page .tp-services-row__listing {
  padding: 8px 0;
  border: 1.5px solid var(--tpl-blue);
  color: var(--tpl-blue);
  /* Prototype: 11.5px. Named Caption role instead. */
  font-size: 12px;
}

.tp-services-page .tp-services-row__call:hover,
.tp-services-page .tp-services-row__call:focus-visible {
  background: var(--tpl-surface);
}

.tp-services-page .tp-services-row__listing:hover,
.tp-services-page .tp-services-row__listing:focus-visible {
  background: var(--tpl-blue-wash);
}

.tp-services-page .tp-services-list__note {
  margin: 18px 0 10px;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--tpl-surface-alt);
  color: var(--tpl-ink-soft);
  font-size: 12px;
  line-height: 1.6;
}

.tp-services-page .tp-services-list__out {
  margin-bottom: 8px;
}

/* ------------------------------------------------------- Sponsored -------- */

.tp-services-page .tp-services-ad {
  display: block;
  margin-bottom: 14px;
  padding: 12px 14px;
  border: 1px solid var(--tpl-line);
  border-radius: 10px;
  background: var(--tpl-surface-alt);
}

.tp-services-page .tp-services-ad__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

/* Disclosure is a heading before the entry, never an inline badge inside it. */
.tp-services-page .tp-services-ad__label {
  color: var(--tpl-ink-soft);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.tp-services-page .tp-services-ad__why {
  color: var(--tpl-link);
  font-size: 12px;
  text-decoration: none;
}

.tp-services-page .tp-services-ad__creative {
  position: relative;
  display: flex;
  height: 132px;
  align-items: center;
  justify-content: center;
  margin-bottom: 12px;
  padding: 16px;
  border-radius: 8px;
  background: var(--tpl-surface);
  text-align: center;
}

.tp-services-page .tp-services-ad__creative-note {
  max-width: 34ch;
  color: var(--tpl-ink-soft);
  font-size: 12px;
  line-height: 1.5;
}

.tp-services-page .tp-services-ad__tag {
  position: absolute;
  top: 8px;
  left: 8px;
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--tpl-ink);
  color: var(--tpl-white);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.tp-services-page .tp-services-ad__head-row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
}

.tp-services-page .tp-services-ad__name {
  color: var(--tpl-ink);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
}

.tp-services-page .tp-services-ad__rating {
  color: var(--tpl-ink-secondary);
  font-size: 13px;
}

.tp-services-page .tp-services-ad__pro {
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--tpl-go-wash);
  color: var(--tpl-go-text);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.tp-services-page .tp-services-ad__meta,
.tp-services-page .tp-services-ad__reach {
  margin-top: 5px;
  color: var(--tpl-ink-secondary);
  font-size: 13px;
  line-height: 1.5;
}

.tp-services-page .tp-services-ad__reach {
  color: var(--tpl-ink-soft);
}

.tp-services-page .tp-services-ad__actions {
  margin-top: 10px;
}

.tp-services-page .tp-services-ad__tel {
  color: var(--tpl-ink);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
}

/* ---------------------------------------------------------------- Map ----- */

.tp-services-page .tp-services-map {
  position: relative;
  overflow: hidden;

  /* A FLOOR, BECAUSE THE GRID ROW IS NOT ONE.
     On desktop this column takes its height from the row, and the row takes
     its height from the list beside it. An empty list is therefore a map with
     no height — and an empty list is the search being unavailable, or matching
     nothing, which are the two moments a driver most needs to see where they
     are. The narrow breakpoints already state a height; this is the same
     promise at full width, and it costs nothing once there are rows, because
     the row is taller than the floor by then. */
  min-height: 420px;
  background: var(--tpl-surface);
}

.tp-services-page .tp-services-map__image {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.tp-services-page .tp-services-map__caption {
  position: absolute;
  top: 14px;
  left: 14px;
  padding: 7px 11px;
  border: 1px solid var(--tpl-line);
  border-radius: 6px;
  background: var(--tpl-white);
  color: var(--tpl-ink);
  font-size: 12px;
  font-weight: 500;
  box-shadow: 0 2px 8px rgba(1, 25, 50, 0.12);
}

/* §3.2A estimate note: the map is centred on a guess (time zone / national),
   not the driver's position. Sits at the foot of the map, plainly subordinate to
   the map itself, and reuses the same card treatment as the caption so the two
   read as one family. Tokens only. */
.tp-services-page .tp-services-map__estimate {
  position: absolute;
  right: 14px;
  bottom: 14px;
  left: 14px;
  margin: 0;
  padding: 8px 11px;
  border: 1px solid var(--tpl-line);
  border-radius: 6px;
  background: var(--tpl-white);
  color: var(--tpl-ink-muted, var(--tpl-ink));
  font-size: 12px;
  line-height: 1.4;
  box-shadow: 0 2px 8px rgba(1, 25, 50, 0.12);
}

.tp-services-page .tp-services-map__estimate[hidden] {
  display: none;
}

/*
 * THE MAP COLUMN WITH NO MAP IN IT — Confluence CT/4474830867 item 49.
 *
 * Centred in the column the map would have filled, on the same grey the column
 * already carries, because this is the column's own resting state and not a
 * card floating over something. No caution colour: a reader who declined
 * cookies got what they asked for, and nothing has gone wrong.
 */
.tp-services-page .tp-services-map__blocked {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 24px;
  background: var(--tpl-surface);
  text-align: center;
}

.tp-services-page .tp-services-map__blocked-copy {
  max-width: 34ch;
  margin: 0;
  color: var(--tpl-ink-secondary);
  font-size: 13px;
  line-height: 1.7;
}

.tp-services-page .tp-services-map__blocked-act {
  padding: 8px 14px;
  border: 1px solid var(--tpl-line);
  border-radius: 6px;
  background: var(--tpl-white);
  color: var(--tpl-blue);
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
}

.tp-services-page .tp-services-map__blocked-act:hover {
  text-decoration: underline;
}

/*
 * THE STATIC MAP'S PIN.
 *
 * Geometry is the design source's: a 34x44 pin, the 16px glyph centred on its
 * head, and the rank in an 18px badge on its shoulder. Keep it in step with
 * pin() in services-map.js — the two draw the same marker, one out of the
 * asset files and one as an inline SVG.
 *
 * ONE MAPPED COLOUR. The badge in the design source is the pin file's own ink,
 * #0277AD — the app's POI blue, which is not a Foundation token because
 * nothing else on the website is drawn in it. This file does not declare
 * colours, so the badge takes the nearest token instead: --tpl-blue-strong is
 * #146FA3 against the source's #0277AD, a difference of about eight levels per
 * channel on an 18px disc. The live map, which draws the asset's paths itself
 * rather than through this stylesheet, keeps the exact ink. Recorded in
 * docs/services-fidelity.md.
 */
.tp-services-page .tp-services-pin {
  position: absolute;
  left: var(--tp-pin-x);
  top: var(--tp-pin-y);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  transform: translate(-50%, -100%);
}

/* The hover is the comp's, and it is the mark that grows — not the label
   under it, which would drag the whole pin's footprint around with it. */
.tp-services-page .tp-services-pin__mark {
  position: relative;
  display: block;
  width: 34px;
  height: 44px;
  transform-origin: 50% 100%;
  transition: transform 0.15s ease;
}

.tp-services-page .tp-services-pin:hover .tp-services-pin__mark,
.tp-services-page .tp-services-pin:focus-visible .tp-services-pin__mark {
  transform: scale(1.35);
}

.tp-services-page .tp-services-pin__body {
  display: block;
  width: 100%;
  height: 100%;
}

/*
 * 38.6% of 44 is the head's centre. Written as the source writes it, so the
 * glyph stays on the head if the pin is ever scaled.
 */
.tp-services-page .tp-services-pin__glyph {
  position: absolute;
  left: 50%;
  top: 38.6%;
  display: block;
  width: 16px;
  height: 16px;
  transform: translate(-50%, -50%);
}

/* On the shoulder, lifted off the pin by a shadow rather than cut out of it
   with a stroke. */
.tp-services-page .tp-services-pin__idx {
  position: absolute;
  top: -3px;
  right: -3px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 999px;
  background: var(--tpl-blue-strong);
  color: var(--tpl-white);
  font-size: 11px;
  font-weight: 700;
  box-shadow: 0 2px 6px rgba(1, 25, 50, 0.25);
}

.tp-services-page .tp-services-pin__label {
  padding: 5px 9px;
  border: 1px solid var(--tpl-line);
  border-radius: 6px;
  background: var(--tpl-white);
  color: var(--tpl-ink);
  font-size: 12px;
  font-weight: 600;
  box-shadow: 0 3px 12px rgba(1, 25, 50, 0.2);
  white-space: nowrap;
}

/* ------------------------------------------------- Search, narrow --------- */

@media screen and (max-width: 1100px) {
  /* Below this the map moves under the list, so the page is taller than the
     viewport by design and the one-screen cap has to come off. */
  .tp-services-page.tp-services-search-page {
    height: auto;
  }

  .tp-services-page .tp-services-results {
    grid-template-columns: 200px minmax(0, 1fr);
    flex: none;
  }

  /* The map follows the list rather than competing with it for width. */
  .tp-services-page .tp-services-map {
    grid-column: 1 / -1;
    height: 420px;
  }

  .tp-services-page .tp-services-list {
    border-right: 0;
  }
}

@media screen and (max-width: 743px) {
  .tp-services-page .tp-services-toolbar__inner {
    flex-wrap: wrap;
    padding: 12px 20px;
  }

  .tp-services-page .tp-services-toolbar__form {
    width: 100%;
  }

  .tp-services-page .tp-services-toolbar__where {
    width: auto;
    flex: 1;
  }


  .tp-services-page .tp-services-results {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Filters stop being a rail on a phone: they sit above the list, as a
     disclosure the driver opens rather than a column that costs width. */
  .tp-services-page .tp-services-filters {
    border-right: 0;
    border-bottom: 1px solid var(--tpl-line);
  }

  .tp-services-page .tp-services-filters__items {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 8px 16px;
  }

  .tp-services-page .tp-services-map {
    height: 320px;
  }
}


/* ------------------------------------------- Search, application state ---- */

/* The banner shown when a position was asked for and refused. */
.tp-services-page .tp-services-gps {
  margin-bottom: 14px;
  padding: 12px 14px;
  border: 1px solid var(--tpl-caution-border);
  border-radius: 10px;
  background: var(--tpl-caution-wash);
}

.tp-services-page .tp-services-gps p {
  margin: 0;
  color: var(--tpl-caution-text);
  font-size: 13px;
  line-height: 1.6;
}

.tp-services-page .tp-services-gps button {
  margin-top: 10px;
  padding: 9px 16px;
  border: 0;
  border-radius: 7px;
  background: var(--tpl-ink);
  color: var(--tpl-white);
  cursor: pointer;
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.tp-services-page button.tp-services-row__name {
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  font-family: inherit;
  text-align: left;
}

.tp-services-page .tp-services-row.is-open {
  border-color: var(--tpl-blue);
}

/* Suggestions under the query field. */
/* Both boxes anchor the same panel; see services-suggest.js. */
.tp-services-page .tp-services-toolbar__where,
.tp-services-page .tp-services-search__field {
  position: relative;
}

/*
 * THE SUGGESTION PANEL, AND IT IS TWO PANELS IN THE SOURCE.
 *
 * One script builds it for both hosts, which is right — but the design source
 * draws it differently in each, and this file had collapsed the two into one
 * shape plus an override that only moved it:
 *
 *   results toolbar (proto @218654)  left:0; width:320px; radius 12;
 *                                    shadow 0 16px 44px rgba(1,25,50,.24)
 *   hub search card (proto @98757)   left:0; right:0 — the field's own width;
 *                                    radius 10; shadow …,.28
 *
 * The base below is the toolbar's, because that host (`__where`) is 230px wide
 * and a panel tied to it would be too narrow to read. The hub's is stated
 * beside its field, where the wider shape belongs.
 *
 * `padding: 7px 0` rather than `8px`: the source insets its rows by 15px each
 * and leaves the container's sides at zero, so a highlighted row runs the full
 * width of the panel instead of floating inside a margin.
 */
.tp-services-page .tp-services-suggest {
  position: absolute;
  z-index: 20;
  top: calc(100% + 6px);
  left: 0;
  display: flex;
  /* Never wider than the viewport — the card is narrow at 390px and a fixed
     320px panel would hang off the side of the screen. */
  width: 320px;
  max-width: calc(100vw - 32px);
  flex-direction: column;
  padding: 7px 0;
  border: 1px solid var(--tpl-line);
  border-radius: 12px;
  background: var(--tpl-white);
  box-shadow: 0 16px 44px rgba(1, 25, 50, 0.24);
}

.tp-services-page .tp-services-suggest__geo,
.tp-services-page .tp-services-suggest__item {
  display: flex;
  /* `baseline`, as the source has it: the place and its kind sit on one line
     of type rather than being centred against each other, so a two-line label
     keeps its first line level with the word beside it. */
  align-items: baseline;
  justify-content: space-between;
  gap: 9px;
  /* 15px each side, and no radius: the rows are full-bleed against a container
     whose own sides are zero, so a highlight reaches the panel edge. */
  padding: 8px 15px;
  border: 0;
  border-radius: 0;
  background: none;
  color: var(--tpl-ink);
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  text-align: left;
}

/* The one row that is an action rather than an answer: centred, because it
   pairs a 15px icon with its label rather than two runs of text. */
.tp-services-page .tp-services-suggest__geo {
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  padding: 10px 15px;
  color: var(--tpl-blue);
  /* 13.5px in the source; the named Body S role is 13. */
  font-weight: 500;
}

/* The crosshair takes the row's own colour rather than carrying one. */
.tp-services-page .tp-services-suggest__geo .tp-site-icon {
  flex: none;
  color: currentColor;
}

.tp-services-page .tp-services-suggest__geo .tp-site-icon {
  fill: currentColor;
}

.tp-services-page .tp-services-suggest__geo:hover,
.tp-services-page .tp-services-suggest__item:hover {
  background: var(--tpl-surface-alt);
}

/* THE SEPARATOR IS ITS OWN ELEMENT, as it is in the source — a 1px rule with
   5px of air on each side, not a border hung off the row above it. It carries
   `--tp-border-2`, the lighter of the two lines: it divides the action from the
   answers inside one panel, which is a smaller job than the panel's own edge.

   This rule existed and matched the source already, and nothing rendered it —
   services-suggest.js drew the border instead. The script builds it now. */
.tp-services-page .tp-services-suggest__rule {
  height: 1px;
  margin: 5px 0;
  background: var(--tpl-line-soft);
}

.tp-services-page .tp-services-suggest__label {
  padding: 5px 15px 4px;
  color: var(--tpl-ink-soft);
  /* ⚠️ 9.5px in the source, and it stays 12 here. The named roles are
     integers and Caption is the smallest of them; shrinking a tracked
     all-caps label below it is not a density tool this design system offers.
     Recorded as an intentional deviation — see docs/services-fidelity.md. */
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* The kind sits in the Caption role beside the place, not the faint one: the
   source spends `--tp-text-4` on separators and nothing else. */
.tp-services-page .tp-services-suggest__kind {
  color: var(--tpl-ink-soft);
  font-size: 12px;
}

/* The listbox itself. Built by script, so these only ever apply with JS. */
.tp-services-page .tp-services-suggest__list {
  max-height: 280px;
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-y: auto;
}

/*
 * Keyboard and pointer share one highlight. Two different-looking "current"
 * rows in one list is two things to explain and one of them will be wrong.
 */
.tp-services-page .tp-services-suggest__item[aria-selected='true'] {
  background: var(--tpl-surface-alt);
}

.tp-services-page .tp-services-suggest__status {
  margin: 0;
  padding: 8px 10px;
  color: var(--tpl-ink-soft);
  font-size: 13px;
}

/* The hub's card sits on the dark hero; its panel needs the same lift the
   toolbar's has, and the field's own divider must not show through it. */
/*
 * THE HUB'S PANEL IS THE FIELD'S OWN WIDTH — proto @98757 `left:0; right:0`.
 *
 * It used to inherit the toolbar's fixed 320px and get nudged 14px to the
 * right, so on a card whose Where field is several hundred pixels wide the
 * panel sat narrow and inset, with the field's right half empty above it. That
 * is the difference visible in the page owner's screenshot.
 *
 * `right: 0` with `width: auto` rather than `width: 100%`: the host is the
 * field `<label>`, and `100%` would measure its content box while `left/right`
 * span the padding box the source's own field also spans.
 *
 * A softer radius and a heavier shadow than the toolbar's, both the source's:
 * this panel hangs over a white card rather than a dense toolbar, and needs
 * more separation to read as being above it.
 */
.tp-services-page .tp-services-search__field .tp-services-suggest {
  /* CLEAR OF THE CARD, NOT OF THE FIELD.
   *
   * The field is one cell of a grid card with no padding of its own, so the
   * field's `margin-bottom` IS the distance from its box to the card's edge:
   * `100% + 14px` lands exactly on that edge whatever the type inside measures,
   * and the 6px after it is the same air the tree's other panel hangs on.
   *
   * It used to be `100% - 4px` — four pixels ABOVE the field's own bottom, so
   * the panel started inside the field, covered the rest of it and cut across
   * the card's lower edge and rounded corner. The source hangs it clear
   * (`top: 74px` against a field roughly fifty tall, proto @98757). */
  top: calc(100% + 14px + 6px);
  right: 0;
  left: 0;
  width: auto;
  border-radius: 10px;
  box-shadow: 0 16px 44px rgba(1, 25, 50, 0.28);
}

/* The detail panel, over the map. */
.tp-services-page .tp-services-panel {
  position: absolute;
  z-index: 10;
  right: 14px;
  bottom: 14px;
  left: 14px;
  padding: 16px 18px;
  border: 1px solid var(--tpl-line);
  border-radius: 12px;
  background: var(--tpl-white);
  box-shadow: 0 12px 40px rgba(1, 25, 50, 0.18);
}

.tp-services-page .tp-services-panel__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.tp-services-page .tp-services-panel__name {
  margin: 0;
  color: var(--tpl-ink);
  font-size: 16px;
  font-weight: 600;
}

.tp-services-page .tp-services-panel__close {
  flex: none;
  padding: 4px;
  border: 0;
  background: none;
  color: var(--tpl-ink-soft);
  cursor: pointer;
}

.tp-services-page .tp-services-panel__close .tp-site-icon {
  fill: currentColor;
}

.tp-services-page .tp-services-panel__meta,
.tp-services-page .tp-services-panel__reach,
.tp-services-page .tp-services-panel__note {
  margin: 6px 0 0;
  color: var(--tpl-ink-secondary);
  font-size: 13px;
  line-height: 1.5;
}

.tp-services-page .tp-services-panel__note {
  margin-top: 12px;
  color: var(--tpl-ink-soft);
  font-size: 12px;
}

.tp-services-page .tp-services-panel__actions {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 12px;
}

/* A pin is a control now. */
.tp-services-page button.tp-services-pin {
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

/*
 * `display` on these beats the reset's [hidden] rule on specificity, so they
 * would stay laid out while marked hidden — visible, and in the case of the
 * panels, swallowing clicks on what is behind them. Restore the attribute's
 * meaning for every element on this page that uses it.
 */
.tp-services-page [hidden] {
  display: none !important;
}

/* The live map fills the column the static image otherwise would. */
.tp-services-page .tp-services-map__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/*
 * THE LIVE MAP'S PIN, AND THE HOVER BOTH MAPS SHARE.
 *
 * services-map.js draws this node through an OverlayView rather than a Marker
 * precisely so these three declarations can exist: the comp gives the pin
 * `transform-origin: 50% 100%`, `scale(1.35)` and `transition: transform .15s
 * ease`, and a Marker is an image with nothing to hang them on.
 *
 * The box is the comp's 34x44 pin, so `50% 100%` is the same point here as it
 * is there — bottom centre, just under the tip, which is what makes the pin
 * grow out of the map rather than off it. The image is larger than the box on
 * purpose: the exported document is 48x56 so the rank badge and the two
 * shadows are not clipped, and it is offset by the -4,-8 its viewBox opens
 * out to.
 */
.tp-services-page .tp-services-map__pin {
  position: absolute;
  width: 34px;
  height: 44px;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  transform-origin: 50% 100%;
  transition: transform 0.15s ease;
}

.tp-services-page .tp-services-map__pin img {
  position: absolute;
  top: -8px;
  left: -4px;
  display: block;
  width: 48px;
  height: 56px;
}

.tp-services-page .tp-services-map__pin:hover,
.tp-services-page .tp-services-map__pin:focus-visible {
  transform: scale(1.35);
}

/* The caption sits over the map, so it has to outrank the map's own controls. */
.tp-services-page [data-services-map="live"] .tp-services-map__caption {
  z-index: 2;
}

/*
 * A pin that grows on hover is explaining which pin the cursor is on, so the
 * size stays and only the travel between the two sizes goes.
 */
@media (prefers-reduced-motion: reduce) {
  .tp-services-page .tp-services-map__pin,
  .tp-services-page .tp-services-pin__mark {
    transition: none;
  }
}

/* ------------------------------------------------------------------ CSR -- */

/*
 * The results arrive from a fetch, so the column has three states rather than
 * one: waiting, answered, and unreachable.
 */

/* Waiting. It holds the column open and says it is working — and claims
 * nothing else. A skeleton shaped like "5 results within 50 mi" before
 * anything has been asked is a lie with an animation over it. */
/*
 * FULL COLUMN, NOT A HEADER AND THEN NOTHING. The template renders more cards
 * than fit and this clips them, so the placeholder reaches the bottom of the
 * list at any viewport height. Without the clip the extra cards would lengthen
 * the column and give the loading state a scrollbar the answer does not have.
 */
.tp-services-page .tp-services-skeleton {
  display: flex;
  height: 100%;
  flex-direction: column;
}

/*
 * FULL COLUMN, NOT A HEADER AND THEN NOTHING. The template renders more cards
 * than fit and this clips them, so the placeholder reaches the bottom of the
 * list at any viewport height. Without the clip the extra cards would lengthen
 * the column and give the loading state a scrollbar the answer does not have.
 */
.tp-services-page .tp-services-skeleton__cards {
  display: block;
  min-height: 0;
  flex: 1;
  overflow: hidden;
}

/* The result card's own geometry — see .tp-services-row. */
.tp-services-page .tp-services-skeleton__card {
  display: block;
  padding: 14px 15px;
  border: 1px solid var(--tpl-line);
  border-radius: 12px;
  background: var(--tpl-white);
  animation: tp-services-skeleton 1.1s ease-in-out infinite;
}

.tp-services-page .tp-services-skeleton__card + .tp-services-skeleton__card {
  margin-top: 10px;
}

.tp-services-page .tp-services-skeleton__head {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* The rank dot, which is the one shape on the card that is never text. */
.tp-services-page .tp-services-skeleton__idx {
  display: block;
  width: 18px;
  height: 18px;
  flex: none;
  border-radius: 999px;
  background: var(--tpl-line);
}

.tp-services-page .tp-services-skeleton__line {
  display: block;
  height: 10px;
  border-radius: 4px;
  background: var(--tpl-surface-alt);
}

/* Name and dot are a shade stronger: they are what the eye lands on first in
   the real card, and the placeholder keeps that order. */
.tp-services-page .tp-services-skeleton__line_name {
  height: 13px;
  width: 52%;
  background: var(--tpl-line);
}

.tp-services-page .tp-services-skeleton__line_meta {
  width: 78%;
  margin-top: 10px;
}

.tp-services-page .tp-services-skeleton__line_reach {
  width: 46%;
  margin-top: 7px;
}

.tp-services-page .tp-services-skeleton__actions {
  display: flex;
  gap: 7px;
  margin-top: 12px;
}

.tp-services-page .tp-services-skeleton__act {
  display: block;
  height: 32px;
  flex: 1;
  border-radius: 6px;
  background: var(--tpl-surface-alt);
}

/*
 * The design source's own 1.1s breath. It explains one thing — that the page is
 * still working — and stops at opacity; nothing moves, nothing resizes.
 */
@keyframes tp-services-skeleton {
  0% { opacity: 0.55; }
  50% { opacity: 1; }
  100% { opacity: 0.55; }
}

@media (prefers-reduced-motion: reduce) {
  .tp-services-page .tp-services-skeleton__card {
    animation: none;
  }
}

/* Below the cards and always in view: the clip above never reaches it. */
.tp-services-page .tp-services-skeleton__say {
  margin: 16px 0 0;
  flex: none;
  color: var(--tpl-ink-secondary);
  font-size: 14px;
}

/*
 * Answered, and a new question asked before the reply.
 *
 * THE COLUMN GOES BACK TO THE SKELETON. It used to keep the previous answer on
 * screen at 55% opacity, on the reasoning that clearing it on every keystroke
 * makes the page flash. The flash is real but the cure was worse: a dimmed list
 * is still a list, and after changing the radius from 50 to 80 the rows on
 * screen belonged to a search nobody was running any more. AGENTS.md: never
 * keep old target data visible while a new target loads.
 *
 * The flash is handled where it belongs instead — services-search.js debounces
 * the ask, so a driver typing never reaches the request at all, and Show more
 * appends rather than replacing.
 */

/* Unreachable. Only the retry needs a control; the copy is the empty box. */
.tp-services-page .tp-services-retry {
  margin-top: 16px;
  padding: 8px 16px;
  border: 1px solid var(--tpl-line);
  border-radius: 8px;
  background: var(--tpl-surface);
  color: var(--tpl-ink);
  font: inherit;
  cursor: pointer;
}

/* The static map's pins arrive with the results that placed them. The wrapper
 * covers exactly the box they were already positioned against, so the
 * percentages on each pin mean what they always meant. */
.tp-services-page .tp-services-map__pins {
  position: absolute;
  inset: 0;
}

/* One more page of the same answer. */
.tp-services-page .tp-services-more {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 16px 0 4px;
}

.tp-services-page .tp-services-more__btn {
  padding: 9px 18px;
  border: 1px solid var(--tpl-line);
  border-radius: 999px;
  background: var(--tpl-white);
  color: var(--tpl-blue);
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
}

.tp-services-page .tp-services-more__btn:hover {
  border-color: var(--tpl-blue);
}

.tp-services-page .tp-services-more__note {
  color: var(--tpl-ink-soft);
  font-size: 12px;
}

/* The empty state's own action — ask for a position, or ask again. */
.tp-services-page .tp-services-empty__act {
  margin-top: 12px;
  padding: 9px 18px;
  border: 0;
  border-radius: 999px;
  background: var(--tpl-blue);
  color: var(--tpl-white);
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
}
