/* ==========================================================================
   Simplicity Passerelle — enhancement layer
   --------------------------------------------------------------------------
   Additive only. Every value is derived from the existing Salient theme
   (navy #004372, blue #0076bd, Josefin Sans) so new sections read as the same
   site. Nothing overrides theme selectors — all rules are namespaced .pp-*.

   Motion policy: everything animated here is driven by a single
   IntersectionObserver-backed reveal system with per-element stagger, plus a
   rAF scroll loop for parallax and progress. Every effect has a
   prefers-reduced-motion off-switch at the bottom of this file, and every
   animated element is legible with JavaScript disabled (no opacity:0 without
   a .pp-js guard on <html>).
   ========================================================================== */

:root {
  --pp-navy: #004372;
  --pp-navy-deep: #00273f;
  --pp-navy-mid: #013a63;
  --pp-blue: #0076bd;
  --pp-blue-lift: #2f97d8;
  --pp-ink: #16283a;
  --pp-slate: #5d7183;
  --pp-line: #dde5ec;
  --pp-cloud: #f4f7fa;
  --pp-shell: 1200px;
  --pp-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --pp-ease-io: cubic-bezier(0.65, 0, 0.35, 1);
}

/* The theme's style.css sets `body { overflow: hidden }` — intended to stop
   sideways scroll from its full-bleed rows, but it makes <body> a scroll
   container, and a scroll container that never scrolls silently disables
   `position: sticky` for everything inside it. The pinned process rail never
   pinned; it scrolled away with the page.

   Clipping is kept on the horizontal axis, where the theme actually needs it.
   `clip` rather than `hidden` because `hidden` on one axis forces the other to
   `auto`, which reinstates the scroll container this exists to remove.

   Two element selectors, no !important: this outranks the theme's single
   `body` rule but still loses to `body.mobile-menu-open`-style state rules and
   to the inline overflow our own modal scroll-lock writes. */
html body {
  overflow-x: clip;
  overflow-y: visible;
}

/* Pages whose body we replaced (see build.py) close the theme's .container
   early, leaving it empty but still carrying its vertical padding — a band of
   grey between the header and the first section. */
body.pp-page--replaced .container-wrap {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  min-height: 0 !important;
}

/* ---- Nav fade -------------------------------------------------------------
   A white gradient falling from behind the header. The nav is dark type sitting
   directly on photography, and on a bright frame — surf, sky, the top of the
   coastline shot — it loses contrast badly. This gives it ground to sit on
   without putting a bar across the top of every hero.

   Absolute at the document top rather than fixed, so it travels with the nav
   and is gone once the nav is gone. Below the header (9999) and above the
   hero (1). Injected by pp-next.js. */

.pp-navfade {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 210px;
  z-index: 500;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.97) 0%,
    rgba(255, 255, 255, 0.9) 28%,
    rgba(255, 255, 255, 0.62) 52%,
    rgba(255, 255, 255, 0.26) 76%,
    rgba(255, 255, 255, 0) 100%
  );
}

/* ---- Residual slider type ---------------------------------------------------
   No page carries a hero slider any more — build.py replaces every one of them
   with the authored .pp-hero. This is kept for the theme's remaining decorative
   modules on the legacy WordPress pages (/hola-mundo/, /passerelle-perspective/
   and the policy pages), which still set type over photography with no
   treatment at all. A shadow costs nothing on dark type and rescues light type.

   The scrim, the panel-alpha booster and their JavaScript went with the heroes:
   the hero's contrast is now the .pp-hero__wash, which is part of the component
   rather than a repair applied to someone else's markup after paint. */

rs-layer,
.rs-layer {
  text-shadow: 0 1px 3px rgba(0, 24, 42, 0.4), 0 3px 34px rgba(0, 24, 42, 0.62);
}

.pp {
  font-family: "Josefin Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  color: var(--pp-ink);
  -webkit-font-smoothing: antialiased;
  position: relative;
}

.pp * { box-sizing: border-box; }

.pp-shell {
  max-width: var(--pp-shell);
  margin: 0 auto;
  padding: 0 28px;
  position: relative;
  z-index: 2;
}

.pp-section {
  padding: clamp(64px, 8vw, 116px) 0;
  position: relative;
  /* `overflow: hidden` makes this element a scroll container, which silently
     disables `position: sticky` on any descendant — the pinned process rail
     scrolled away with the page instead of holding. `overflow: clip` gives
     the same clipping (needed for the aurora, which is inset -40%) without
     establishing a scroll container. The `hidden` line stays as the fallback
     for anything that does not understand `clip`. */
  overflow: hidden;
  overflow: clip;
}
.pp-section--tight { padding: clamp(48px, 5vw, 72px) 0; }
.pp-section--cloud { background: var(--pp-cloud); }

.pp-section--navy {
  background: var(--pp-navy-deep);
  color: #fff;
}

/* Slow-drifting aurora behind navy sections. Two offset radial gradients on
   long, prime-ish durations so the loop never visibly repeats. */
.pp-section--navy::before {
  content: "";
  position: absolute;
  inset: -40%;
  background:
    radial-gradient(38% 44% at 18% 26%, rgba(0, 118, 189, 0.42) 0%, transparent 62%),
    radial-gradient(34% 40% at 82% 72%, rgba(47, 151, 216, 0.28) 0%, transparent 60%);
  animation: pp-aurora 31s ease-in-out infinite alternate;
  pointer-events: none;
  z-index: 0;
}

/* Fine grain over the navy so large flat fields don't band on wide displays. */
.pp-section--navy::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.32'/%3E%3C/svg%3E");
  opacity: 0.05;
  pointer-events: none;
  z-index: 1;
}

@keyframes pp-aurora {
  0%   { transform: translate3d(-3%, -2%, 0) scale(1); }
  50%  { transform: translate3d(2%, 3%, 0) scale(1.09); }
  100% { transform: translate3d(4%, -3%, 0) scale(1.03); }
}

.pp-section--navy .pp-eyebrow { color: var(--pp-blue-lift); }
.pp-section--navy .pp-lede,
.pp-section--navy .pp-body { color: rgba(255, 255, 255, 0.8); }
.pp-section--navy .pp-h2 { color: #fff; }
.pp-section--navy .pp-rule { background: var(--pp-blue-lift); }

/* ---- Scroll progress ------------------------------------------------------ */

.pp-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--pp-blue), var(--pp-navy));
  z-index: 9999;
  pointer-events: none;
}

/* ---- Type ----------------------------------------------------------------- */

.pp-eyebrow {
  margin: 0 0 18px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--pp-blue);
}

.pp-h2 {
  margin: 0;
  font-size: clamp(27px, 3.4vw, 44px);
  font-weight: 300;
  line-height: 1.16;
  letter-spacing: 0.015em;
  text-transform: uppercase;
  color: var(--pp-navy);
}

.pp-h3 {
  margin: 0 0 10px;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--pp-navy);
}

.pp-lede {
  margin: 22px 0 0;
  max-width: 66ch;
  font-size: clamp(16px, 1.35vw, 19px);
  font-weight: 300;
  line-height: 1.72;
  color: var(--pp-slate);
}

.pp-body {
  margin: 0;
  font-size: 15px;
  font-weight: 300;
  line-height: 1.75;
  color: var(--pp-slate);
}

.pp-rule {
  width: 0;
  height: 2px;
  margin: 0 0 26px;
  background: var(--pp-blue);
  border: 0;
  transition: width 0.9s var(--pp-ease) 0.1s;
}

.pp-is-visible .pp-rule,
.pp-rule.pp-is-visible { width: 54px; }

/* ---- Word-level headline reveal ------------------------------------------- */
/* Split by pp-next.js. Words rise behind a clipping mask, staggered, so the
   headline assembles rather than fading in as one block. */

.pp-word {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
}

.pp-word > span {
  display: inline-block;
  transform: translateY(105%);
  transition: transform 0.82s var(--pp-ease);
  transition-delay: var(--pp-d, 0ms);
  will-change: transform;
}

.pp-is-visible .pp-word > span { transform: none; }

/* ---- Credibility strip ---------------------------------------------------- */

.pp-marks {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.14);
}

.pp-mark {
  padding: 34px 24px;
  background: rgba(0, 39, 63, 0.72);
  text-align: center;
  position: relative;
  overflow: hidden;
}

.pp-mark::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0, 118, 189, 0.16), transparent 70%);
  opacity: 0;
  transition: opacity 0.45s var(--pp-ease);
}

.pp-mark:hover::after { opacity: 1; }

.pp-mark__value {
  display: block;
  /* Values are words, not figures, so they need room to wrap rather than the
     tight single-line treatment a number would get. */
  font-size: clamp(20px, 2.1vw, 27px);
  font-weight: 200;
  line-height: 1.22;
  letter-spacing: 0.01em;
  color: #fff;
  text-wrap: balance;
}

.pp-mark__label {
  display: block;
  margin-top: 12px;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.62);
}

/* ---- Capability ticker ----------------------------------------------------- */

.pp-ticker {
  overflow: hidden;
  border-top: 1px solid var(--pp-line);
  border-bottom: 1px solid var(--pp-line);
  padding: 20px 0;
  background: #fff;
  position: relative;
  /* An element with a mask cannot be promoted to its own compositor layer the
     way a plain one can, so every frame of the marquee repainted the strip —
     and every frame of a scroll repainted it again. The strip sits on a known
     solid white, so two gradient overlays give exactly the same edge fade for
     none of that cost. */
}

.pp-ticker::before,
.pp-ticker::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 18%;
  z-index: 2;
  pointer-events: none;
}

.pp-ticker::before { left: 0; background: linear-gradient(90deg, #fff 12%, rgba(255, 255, 255, 0)); }
.pp-ticker::after { right: 0; background: linear-gradient(270deg, #fff 12%, rgba(255, 255, 255, 0)); }

.pp-ticker__track {
  display: flex;
  width: max-content;
  /* Distance and duration are both measured, not assumed — see initTicker().
     The fallbacks are what this used to be, for the no-JS case. */
  animation: pp-marquee var(--pp-marquee-t, 46s) linear infinite;
  /* Held on its own compositor layer. Without this the layer is created and
     destroyed around the animation, and the strip repaints on the main thread
     during a scroll. */
  will-change: transform;
  backface-visibility: hidden;
}

/* No hover-pause.
   ----------------------------------------------------------------------------
   It used to pause on hover, which sounds harmless and is the actual cause of
   the reported stutter. The cursor does not move during a scroll — the page
   moves under it. So the strip passes beneath a stationary pointer, `:hover`
   goes true, the animation pauses, the strip passes on and it resumes.
   Measured: cursor parked at (700,450), scroll the ticker into view, and
   animation-play-state reads `paused`. Every scroll past it produced a visible
   catch. A strip whose entire job is to hold a constant pace must not have a
   pointer-driven stop on it. */

.pp-ticker__item {
  display: inline-flex;
  align-items: center;
  gap: 26px;
  padding: 0 26px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--pp-slate);
  white-space: nowrap;
}

.pp-ticker__item::after {
  content: "";
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--pp-blue);
  opacity: 0.55;
}

/* Travel is a measured whole-pixel distance, not -50%.
   ----------------------------------------------------------------------------
   The track comes out 4219.22px wide, so -50% is -2109.609375px — a fractional
   end point, which means every intermediate frame lands the text on a sub-pixel
   x-offset and it is re-rasterised on each one. That is the shimmer that reads
   as the strip stuttering, and it does not show in a headless browser because
   there is no sub-pixel text rasterisation to do. Rounding to a whole pixel
   costs 0.39px of alignment once every loop and buys a clean frame every frame.

   Duration is derived from the same measurement so the strip moves at a
   constant speed rather than taking a fixed 46s to cross whatever width the
   viewport and font metrics happen to produce. */
@keyframes pp-marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(var(--pp-marquee-x, 50%) * -1), 0, 0); }
}

/* ---- Doors ----------------------------------------------------------------- */

.pp-doors {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 28px;
  margin-top: 48px;
}

.pp-door {
  display: flex;
  flex-direction: column;
  padding: 40px 36px;
  background: #fff;
  border: 1px solid var(--pp-line);
  position: relative;
  overflow: hidden;
  transition: transform 0.5s var(--pp-ease), box-shadow 0.5s var(--pp-ease), border-color 0.4s ease;
}

/* Top accent draws in on hover rather than sitting there statically. */
.pp-door::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  height: 3px;
  width: 100%;
  background: linear-gradient(90deg, var(--pp-blue), var(--pp-navy));
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 0.62s var(--pp-ease);
}

/* Cursor-tracked spotlight; --pp-mx/--pp-my are written by pp-next.js. */
.pp-door::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(420px circle at var(--pp-mx, 50%) var(--pp-my, 0%), rgba(0, 118, 189, 0.09), transparent 62%);
  opacity: 0;
  transition: opacity 0.4s ease;
  pointer-events: none;
}

/* The lift is a custom property, not a transform: the card's transform is
   composed once in the tilt block so lift and tilt can coexist. */
.pp-door:hover {
  --pp-lift: -6px;
  border-color: rgba(0, 118, 189, 0.35);
  box-shadow: 0 26px 60px rgba(0, 67, 114, 0.14);
}

.pp-door:hover::before { transform: none; }
.pp-door:hover::after { opacity: 1; }

.pp-door__for {
  margin: 0 0 14px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--pp-slate);
}

/* list-style on the <ul> is not enough: the theme sets `list-style: disc` on
   the <li> itself, which wins, and every row rendered with a stray bullet
   sitting to the left of our blue rule. */
.pp-door__list { margin: 22px 0 30px; padding: 0; list-style: none; }
.pp-door__list li,
.pp-vault li,
.pp-process__nav li,
.pp-signin__list li { list-style: none; }

.pp-door__list li {
  position: relative;
  padding: 0 0 0 22px;
  margin-bottom: 11px;
  font-size: 14px;
  font-weight: 300;
  line-height: 1.6;
  color: var(--pp-slate);
}

.pp-door__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 9px;
  width: 0;
  height: 1px;
  background: var(--pp-blue);
  transition: width 0.5s var(--pp-ease);
  transition-delay: var(--pp-d, 0ms);
}

.pp-is-visible .pp-door__list li::before { width: 10px; }

.pp-door__cta { margin-top: auto; }

/* ---- Pillars ---------------------------------------------------------------- */

.pp-pillars {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 30px;
  margin-top: 52px;
}

.pp-pillar {
  border-top: 1px solid var(--pp-line);
  padding-top: 24px;
  position: relative;
}

.pp-pillar::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  height: 2px;
  width: 0;
  background: var(--pp-blue);
  transition: width 0.85s var(--pp-ease);
  transition-delay: var(--pp-d, 0ms);
}

.pp-is-visible .pp-pillar::before { width: 100%; }

.pp-section--navy .pp-pillar { border-top-color: rgba(255, 255, 255, 0.2); }

.pp-pillar__num {
  display: block;
  margin-bottom: 14px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2em;
  color: var(--pp-blue);
}

.pp-section--navy .pp-pillar__num { color: var(--pp-blue-lift); }

/* ---- Pinned process --------------------------------------------------------- */
/* The stage list sticks while the reader scrolls the descriptions past it, so
   the four stages read as one continuous process rather than four cards. */

.pp-process { display: grid; grid-template-columns: 340px 1fr; gap: 64px; margin-top: 56px; }

.pp-process__rail { position: sticky; top: 130px; align-self: start; }

.pp-process__nav { margin: 0; padding: 0; list-style: none; position: relative; }

/* A single line drawing down the rail as the reader moves through the stages,
   sitting over the per-item borders. Height is written by the scroll loop, so
   it tracks the reader's actual position rather than snapping between items. */
.pp-process__nav::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 2px;
  height: var(--pp-rail, 0px);
  background: linear-gradient(180deg, var(--pp-blue-lift), rgba(47, 151, 216, 0.25));
  transition: height 0.35s var(--pp-ease);
}

.pp-process__nav li {
  padding: 15px 0 15px 22px;
  border-left: 2px solid rgba(255, 255, 255, 0.16);
  font-size: 15px;
  font-weight: 300;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.42);
  transition: color 0.4s ease, border-color 0.4s ease, padding-left 0.4s var(--pp-ease);
}

.pp-process__nav li.pp-active {
  color: #fff;
  border-left-color: var(--pp-blue-lift);
  padding-left: 30px;
}

.pp-stage { padding: 8px 0 76px; }
.pp-stage:last-child { padding-bottom: 0; }

.pp-stage__num {
  display: block;
  margin-bottom: 14px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.24em;
  color: var(--pp-blue-lift);
}

.pp-stage .pp-h3 { color: #fff; font-size: 20px; }
.pp-stage .pp-body { max-width: 56ch; }

/* ---- Split + report preview -------------------------------------------------- */

.pp-split { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: center; }

.pp-preview {
  border: 1px solid var(--pp-line);
  background: #fff;
  box-shadow: 0 30px 70px rgba(0, 67, 114, 0.13);
  transform: perspective(1400px) rotateY(-7deg) rotateX(2deg);
  transition: transform 0.8s var(--pp-ease);
}

.pp-preview:hover { transform: perspective(1400px) rotateY(0deg) rotateX(0deg); }

.pp-preview__bar { display: flex; align-items: center; gap: 8px; padding: 12px 16px; background: var(--pp-navy); }
.pp-preview__dot { width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, 0.35); }

.pp-preview__title {
  margin-left: 10px;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.8);
}

.pp-preview__body { padding: 26px 24px 30px; }

.pp-preview__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 13px 0;
  border-bottom: 1px solid var(--pp-line);
  font-size: 13px;
  font-weight: 300;
  color: var(--pp-slate);
  opacity: 0;
  transform: translateX(-10px);
  transition: opacity 0.55s var(--pp-ease), transform 0.55s var(--pp-ease);
  transition-delay: var(--pp-d, 0ms);
}

.pp-is-visible .pp-preview__row { opacity: 1; transform: none; }
.pp-preview__row:last-of-type { border-bottom: 0; }
.pp-preview__row strong { font-weight: 600; color: var(--pp-navy); }

.pp-preview__meter { height: 4px; margin-top: 18px; background: var(--pp-cloud); overflow: hidden; }

.pp-preview__meter span {
  display: block;
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, var(--pp-blue), var(--pp-navy));
  transition: width 1.7s var(--pp-ease) 0.5s;
}

.pp-is-visible .pp-preview__meter span { width: 78%; }

/* ---- Buttons ------------------------------------------------------------------ */

.pp-btn {
  display: inline-block;
  position: relative;
  padding: 15px 32px;
  border: 1px solid var(--pp-navy);
  background: transparent;
  color: #fff !important;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none !important;
  cursor: pointer;
  overflow: hidden;
  isolation: isolate;
  transition: color 0.35s var(--pp-ease), border-color 0.35s ease, transform 0.35s var(--pp-ease);
}

/* Fill wipes in from the bottom on hover instead of a flat colour swap. */
.pp-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--pp-navy);
  transform: translateY(0);
  transition: transform 0.45s var(--pp-ease), background 0.35s ease;
  z-index: -1;
}

/* Magnetic: --pp-magx/--pp-magy are written by pp-next.js from the pointer's
   offset within the button, so it leans towards the cursor as it approaches. */
.pp-btn:hover {
  border-color: var(--pp-blue);
  transform: translate3d(var(--pp-magx, 0px), calc(var(--pp-magy, 0px) - 2px), 0);
}
.pp-btn:hover::before { background: var(--pp-blue); }
.pp-btn:active { transform: translate3d(var(--pp-magx, 0px), 0, 0); }

.pp-btn--ghost { color: var(--pp-navy) !important; }
.pp-btn--ghost::before { transform: translateY(101%); }
.pp-btn--ghost:hover { color: #fff !important; }
.pp-btn--ghost:hover::before { transform: translateY(0); background: var(--pp-navy); }

.pp-btn--light { border-color: #fff; color: var(--pp-navy) !important; }
.pp-btn--light::before { background: #fff; }
.pp-btn--light:hover { color: #fff !important; border-color: #fff; }
.pp-btn--light:hover::before { transform: translateY(101%); }

.pp-btn[disabled] { opacity: 0.55; cursor: not-allowed; transform: none; }

/* ---- Form ---------------------------------------------------------------------- */

.pp-form { margin-top: 42px; }
.pp-form__grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 22px 26px; }

.pp-field { display: flex; flex-direction: column; position: relative; }
.pp-field--full { grid-column: 1 / -1; }

/* The hint under a field is dead space until the field is in use, then it is
   the most useful thing on the row. */
.pp-field__hint { transition: color 0.3s ease; }
.pp-field:focus-within .pp-field__hint { color: var(--pp-navy); }

.pp-field > label {
  margin-bottom: 8px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--pp-slate);
}

.pp-field > label .pp-req { color: var(--pp-blue); }

.pp-field input,
.pp-field select,
.pp-field textarea {
  width: 100%;
  padding: 14px;
  border: 1px solid var(--pp-line);
  border-radius: 0;
  background: #fff;
  color: var(--pp-ink);
  font-family: inherit;
  /* 16px minimum on touch — anything smaller makes iOS Safari zoom the page
     on focus, which throws the layout and feels broken on a phone. */
  font-size: 16px;
  font-weight: 300;
  /* A rule that draws across the base of the control on focus. Painted as a
     background layer on the control itself rather than a positioned pseudo-
     element on .pp-field, which is a flex column — an absolutely positioned
     rule there lands under the hint text on rows that have one, and under the
     input on rows that do not. The border-colour change alone is easy to miss
     halfway down a long form. */
  background-image: linear-gradient(var(--pp-blue), var(--pp-blue));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0 2px;
  transition: border-color 0.25s ease, box-shadow 0.25s ease,
    background-size 0.42s var(--pp-ease);
  appearance: none;
}

.pp-field input:focus,
.pp-field textarea:focus,
.pp-field select:focus { background-size: 100% 2px; }

/* Two layers: the chevron keeps its own position and size, the focus rule
   gets the second slot. A single-value background-position would move both. */
.pp-field select {
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%235d7183' d='M1 1l5 5 5-5'/%3E%3C/svg%3E"),
    linear-gradient(var(--pp-blue), var(--pp-blue));
  background-repeat: no-repeat, no-repeat;
  background-position: right 14px center, 0 100%;
  background-size: auto, 0 2px;
  padding-right: 38px;
}

.pp-field select:focus { background-size: auto, 100% 2px; }

.pp-field input:focus,
.pp-field select:focus,
.pp-field textarea:focus {
  outline: none;
  border-color: var(--pp-blue);
  box-shadow: 0 0 0 3px rgba(0, 118, 189, 0.13);
}

.pp-field textarea { min-height: 132px; resize: vertical; line-height: 1.6; }
.pp-field__hint { margin: 7px 0 0; font-size: 12px; font-weight: 300; color: var(--pp-slate); }

.pp-hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.pp-form__foot { display: flex; flex-wrap: wrap; align-items: center; gap: 20px; margin-top: 30px; }
.pp-form__note { margin: 0; max-width: 46ch; font-size: 12px; font-weight: 300; line-height: 1.6; color: var(--pp-slate); }

.pp-alert {
  margin-top: 22px;
  padding: 16px 18px;
  border-left: 3px solid var(--pp-blue);
  background: var(--pp-cloud);
  font-size: 14px;
  font-weight: 300;
  color: var(--pp-ink);
}

.pp-alert--error { border-left-color: #a33; background: #fdf4f4; }
.pp-alert[hidden] { display: none; }

.pp-success {
  padding: 46px 40px;
  border: 1px solid var(--pp-line);
  border-top: 3px solid var(--pp-blue);
  background: #fff;
  animation: pp-pop 0.6s var(--pp-ease);
}

@keyframes pp-pop {
  from { opacity: 0; transform: translateY(14px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

/* ---- Modal ---------------------------------------------------------------------- */

.pp-modal {
  position: fixed;
  inset: 0;
  z-index: 100000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.pp-modal[hidden] { display: none; }

.pp-modal__scrim {
  position: absolute;
  inset: 0;
  background: rgba(8, 24, 38, 0.62);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  opacity: 0;
  transition: opacity 0.35s ease;
}

.pp-modal.pp-modal--open .pp-modal__scrim { opacity: 1; }

.pp-modal__panel {
  position: relative;
  width: 100%;
  max-width: 940px;
  max-height: calc(100dvh - 40px);
  /* Column so the close can sit above the body as a sticky flow item rather
     than as an absolute one that scrolls away with the content. */
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  /* Without this, reaching the end of the panel's own scroll chains the gesture
     to the document behind it — the page moves under a modal that is supposed
     to be holding the visitor's attention. */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  background: #fff;
  box-shadow: 0 40px 100px rgba(0, 30, 52, 0.4);
  opacity: 0;
  transform: translateY(22px) scale(0.985);
  transition: opacity 0.42s var(--pp-ease), transform 0.42s var(--pp-ease);
}

.pp-modal.pp-modal--open .pp-modal__panel { opacity: 1; transform: none; }
.pp-modal__panel--narrow { max-width: 460px; }

/* The panel's own children lift in behind it. Without this the modal arrives
   as one flat rectangle of form, which is the moment a visitor decides
   whether filling it in is worth their time. */
.pp-js .pp-modal__body > * {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.45s var(--pp-ease), transform 0.45s var(--pp-ease);
}

.pp-js .pp-modal--open .pp-modal__body > * { opacity: 1; transform: none; }
.pp-js .pp-modal--open .pp-modal__body > *:nth-child(1) { transition-delay: 0.1s; }
.pp-js .pp-modal--open .pp-modal__body > *:nth-child(2) { transition-delay: 0.16s; }
.pp-js .pp-modal--open .pp-modal__body > *:nth-child(3) { transition-delay: 0.22s; }
.pp-js .pp-modal--open .pp-modal__body > *:nth-child(n + 4) { transition-delay: 0.28s; }

/* Sticky rather than absolute. These panels scroll internally — 635px at
   1024x800, over 1,100px on a phone — and an absolute close goes with the
   content, leaving Escape or a scrim tap as the only way out. The negative
   bottom margin keeps it out of flow so the body still starts at the top of
   the panel instead of 54px down. */
.pp-modal__close {
  position: sticky;
  top: 14px;
  z-index: 4;
  align-self: flex-end;
  flex: 0 0 auto;
  margin: 14px 14px -54px 0;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  /* Opaque and bordered because it now floats over live form fields for the
     whole length of the scroll — a translucent glyph sitting on a select reads
     as a rendering fault rather than as a control. */
  border: 1px solid var(--pp-line);
  background: #fff;
  box-shadow: 0 3px 16px rgba(0, 30, 52, 0.14);
  color: var(--pp-slate);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  border-radius: 50%;
  transition: background 0.25s ease, color 0.25s ease, transform 0.25s ease;
}

.pp-modal__close:hover { background: var(--pp-cloud); color: var(--pp-navy); transform: rotate(90deg); }
.pp-modal__body { flex: 1 1 auto; padding: 44px 44px 40px; }
.pp-signin { flex: 1 1 auto; }
.pp-modal__body .pp-form { margin-top: 26px; }

/* ---- Client sign-in (mirrors the Portal login split) ------------------------------ */

.pp-signin { display: grid; grid-template-columns: 1fr 1fr; min-height: 520px; }

.pp-signin__aside {
  position: relative;
  overflow: hidden;
  padding: 44px 38px;
  background: var(--pp-navy-deep);
  color: #fff;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.pp-signin__aside::before {
  content: "";
  position: absolute;
  inset: -40%;
  background:
    radial-gradient(40% 46% at 22% 24%, rgba(0, 118, 189, 0.5) 0%, transparent 62%),
    radial-gradient(36% 42% at 78% 76%, rgba(47, 151, 216, 0.3) 0%, transparent 60%);
  animation: pp-aurora 29s ease-in-out infinite alternate;
}

.pp-signin__aside > * { position: relative; z-index: 1; }

.pp-signin__brand {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.62);
}

.pp-signin__title {
  margin: 26px 0 12px;
  font-size: clamp(26px, 3vw, 34px);
  font-weight: 300;
  line-height: 1.14;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: #fff;
}

.pp-signin__blurb { margin: 0; font-size: 14px; font-weight: 300; line-height: 1.7; color: rgba(255, 255, 255, 0.76); }

.pp-signin__pill {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-top: 22px;
  padding: 7px 14px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.14);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.82);
}

.pp-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #48d597;
  box-shadow: 0 0 0 0 rgba(72, 213, 151, 0.65);
  animation: pp-pulse 2.4s ease-out infinite;
}

@keyframes pp-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(72, 213, 151, 0.6); }
  70%  { box-shadow: 0 0 0 9px rgba(72, 213, 151, 0); }
  100% { box-shadow: 0 0 0 0 rgba(72, 213, 151, 0); }
}

.pp-signin__list { margin: 26px 0 0; padding: 0; list-style: none; }

.pp-signin__list li {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 13px;
  margin-bottom: 8px;
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  font-size: 13px;
  font-weight: 300;
  color: rgba(255, 255, 255, 0.9);
}

.pp-signin__list svg { flex: 0 0 auto; color: var(--pp-blue-lift); }

.pp-signin__main {
  padding: 52px 44px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  background: var(--pp-cloud);
}

.pp-signin__heading {
  margin: 0 0 10px;
  font-size: 24px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--pp-navy);
}

.pp-signin__sub { margin: 0 0 26px; font-size: 14px; font-weight: 300; line-height: 1.65; color: var(--pp-slate); }
.pp-signin__main .pp-field > label { text-align: left; }

.pp-signin__lock {
  margin-top: 24px;
  padding: 14px 16px;
  border: 1px solid var(--pp-line);
  background: #fff;
  font-size: 12px;
  font-weight: 300;
  line-height: 1.6;
  color: var(--pp-slate);
}

/* ---- Vault list --------------------------------------------------------------------- */

.pp-vault { margin: 22px 0 30px; padding: 0; list-style: none; }

.pp-vault li {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 11px 0;
  border-bottom: 1px solid var(--pp-line);
  font-size: 14px;
  font-weight: 300;
  color: var(--pp-slate);
  opacity: 0;
  transform: translateX(-8px);
  transition: opacity 0.5s var(--pp-ease), transform 0.5s var(--pp-ease);
  transition-delay: var(--pp-d, 0ms);
}

.pp-is-visible .pp-vault li { opacity: 1; transform: none; }

.pp-vault li span {
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--pp-blue);
  white-space: nowrap;
}

.pp-access { display: grid; grid-template-columns: repeat(2, 1fr); gap: 28px; margin-top: 48px; }

.pp-access__card {
  display: flex;
  flex-direction: column;
  padding: 38px 34px;
  background: #fff;
  border: 1px solid var(--pp-line);
  position: relative;
  overflow: hidden;
  transition: transform 0.5s var(--pp-ease), box-shadow 0.5s var(--pp-ease), border-color 0.4s ease;
}

.pp-access__card:hover {
  --pp-lift: -5px;
  border-color: rgba(0, 118, 189, 0.32);
  box-shadow: 0 24px 56px rgba(0, 67, 114, 0.13);
}

.pp-access__card--primary { border-top: 3px solid var(--pp-blue); }

/* ---- Reveal ----------------------------------------------------------------------- */
/* .pp-js is set on <html> by the inline head script, so with JS disabled the
   content is simply visible — never a blank page waiting on an observer. */

.pp-js .pp-reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 0.85s var(--pp-ease), transform 0.85s var(--pp-ease);
  transition-delay: var(--pp-d, 0ms);
}

.pp-js .pp-reveal.pp-is-visible { opacity: 1; transform: none; }

.pp-js .pp-reveal--left { transform: translateX(-30px); }
.pp-js .pp-reveal--right { transform: translateX(30px); }
.pp-js .pp-reveal--scale { transform: scale(0.955); }
.pp-js .pp-reveal--left.pp-is-visible,
.pp-js .pp-reveal--right.pp-is-visible,
.pp-js .pp-reveal--scale.pp-is-visible { transform: none; }

/* Parallax offset written by the rAF scroll loop. */
.pp-parallax { will-change: transform; transform: translate3d(0, var(--pp-py, 0px), 0); }

/* ---- RevSlider spacer correction ----------------------------------------------------
   <rs-fw-forcer> reserves layout space for the absolutely-positioned slider.
   The export ships stale inline heights (1581/1975/1955px against a 577px
   slider) — the tall band of dead whitespace under those heroes. pp-next.js
   measures the real height into --pp-forcer-h; this rule outranks RevSlider's
   inline height so the correction survives its own resize handler.
   ------------------------------------------------------------------------------------ */

rs-fw-forcer.pp-forcer-synced { height: var(--pp-forcer-h) !important; }

/* ---- Hero -----------------------------------------------------------------------------
   The authored hero (sections.py). It replaced a RevSlider module whose slide
   held nine copy layers laid out between y=1174 and y=2889 inside a 900px box
   with overflow:hidden — permanently clipped, never on screen — inside a group
   translated up 2,060px on an eight-second timer. None of that could be fixed
   from the stylesheet, so the module went.

   Everything below is declarative and correct on the first painted frame.
   Nothing here waits for a script, which is what the white side bars were: the
   old hero was laid out inside the theme's centred container and measured to
   full width only once RevSlider had built its wrapper — 135ms of visible
   inset, then a snap.
   ---------------------------------------------------------------------------------------- */

.pp-hero {
  /* Full bleed out of the theme's max-width container. 100vw counts the
     scrollbar and leaves the element a few pixels proud each side; `html body
     { overflow-x: clip }` above absorbs that, and overshooting crops a sliver
     of photography where undershooting would put the white bars back. */
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw);

  position: relative;
  display: flex;
  align-items: flex-end;
  /* Tall enough to be a hero, never taller than the screen. `svh` rather than
     `vh` so a phone's collapsing address bar does not make the hero 60-odd
     pixels taller than the viewport it is supposed to fill — which on iOS is
     the difference between the lede landing above the fold and below it. */
  min-height: 620px;
  /* 80svh. At 88 the section below cleared the fold by 37px on a 900px viewport
     — enough to show a strip of empty navy and not enough to show a single word
     of what is in it. 80 puts the whole stat band on the opening screen on the
     homepage and all but the last ~20px of the taller icon variant that Private
     Client and Advisory use, so the hero and the firm's four marks read as one
     composition on every page. */
  height: 80svh;
  max-height: 860px;
  overflow: hidden;
  background: var(--pp-navy-deep);
  isolation: isolate;
}

.pp-hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}

/* `!important` on the height, and it is load-bearing. The theme ships
   `.main-content img { height: auto }` and `.row .col img { height: auto }`,
   both of which are two-selector rules that outrank a single class — so the
   hero image sized itself to its own aspect ratio inside a box that is a
   different shape, and `object-fit: cover` had nothing to crop against.
   Measured at 390x844: the hero box was 658px tall and the image inside it was
   211px, so the photograph occupied the top quarter and the rest of the hero
   was the flat backdrop colour showing through. On a 16:9 desktop viewport the
   two heights happen to land within a few pixels of each other, which is why
   this looked correct there and only failed on a phone. */
.pp-hero__img {
  width: 100%;
  height: 100% !important;
  object-fit: cover;
  display: block;
  /* Drifts a little slower than the page and scales very slightly, anchored to
     its own top edge so the zoom always covers what the drift exposes. Bounded
     to the hero's own height by --pp-hp, so it is finished by the time the
     hero has gone. */
  transform: translate3d(0, calc(var(--pp-hp, 0) * 46px), 0)
             scale(calc(1.02 + var(--pp-hp, 0) * 0.06));
  transform-origin: 50% 0%;
  will-change: transform;
}

/* The wash.
   Two jobs, and they are different enough to need two gradients rather than
   one. The vertical pass darkens the foot of the frame so the copy has ground
   under it and so the hero's last row of pixels is already the colour the next
   section starts on. The diagonal pass weights the darkening toward the corner
   the copy sits in, so the photograph stays a photograph on the other side
   instead of being uniformly dimmed into a flat panel.

   This is why the type is white on a navy-graded frame rather than navy on a
   whitened one: the wash is a property of the hero, so contrast holds on any
   photograph put behind it — including a bright one — instead of depending on
   the picture happening to have a pale region where the words go. "PRIVATE
   CLIENT" in white over lit surf, with nothing behind it, is the fault this
   removes. */
.pp-hero__wash {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(
      180deg,
      rgba(0, 26, 44, 0.34) 0%,
      rgba(0, 26, 44, 0.12) 26%,
      rgba(0, 26, 44, 0.44) 62%,
      rgba(0, 39, 63, 0.88) 88%,
      var(--pp-navy-deep) 100%
    ),
    linear-gradient(
      104deg,
      rgba(0, 30, 52, 0.72) 0%,
      rgba(0, 30, 52, 0.38) 42%,
      rgba(0, 30, 52, 0) 78%
    );
}

/* Interior pages that run into white content resolve to white at the seam
   instead. Resolving to navy there would put a dark bar between the photograph
   and the section below — the same hard join, in the other direction. The
   copy's own darkening is untouched, so the type does not get less legible to
   buy the seam. */
.pp-hero--light .pp-hero__wash {
  background:
    linear-gradient(
      180deg,
      rgba(0, 26, 44, 0.36) 0%,
      rgba(0, 26, 44, 0.16) 24%,
      rgba(0, 26, 44, 0.5) 58%,
      rgba(0, 26, 44, 0.66) 82%,
      rgba(255, 255, 255, 0.06) 97%,
      #fff 100%
    ),
    linear-gradient(
      104deg,
      rgba(0, 30, 52, 0.74) 0%,
      rgba(0, 30, 52, 0.4) 42%,
      rgba(0, 30, 52, 0) 78%
    );
}

/* A last few pixels of the destination colour, sitting above the wash. The
   gradient alone leaves a one- or two-pixel band of not-quite-the-right-navy
   on the join at some viewport heights, because the stop lands mid-pixel. */
.pp-hero__seam {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 3px;
  z-index: 3;
  background: var(--pp-navy-deep);
  pointer-events: none;
}

.pp-hero--light .pp-hero__seam { background: #fff; }

.pp-hero__inner {
  position: relative;
  z-index: 4;
  width: 100%;
  padding: 0 0 clamp(72px, 9vh, 128px);
}

.pp-hero__eyebrow {
  margin: 0 0 20px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  /* Full white, and the title's two-shadow treatment rather than one soft one.
     At 82% over a bright frame this was the least legible type on the site —
     small, letterspaced, and thin enough that a single diffuse shadow does
     nothing for it. */
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 20, 36, 0.6), 0 2px 22px rgba(0, 20, 36, 0.85);
}

.pp-hero__title {
  margin: 0;
  max-width: 17ch;
  font-family: "Josefin Sans", -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: clamp(38px, 6.2vw, 82px);
  font-weight: 300;
  line-height: 1.02;
  letter-spacing: 0.005em;
  text-transform: uppercase;
  color: #fff;
  /* A tight shadow for edge definition against texture and a wide soft one
     that darkens the area behind the glyphs. Display type this size sits over
     several hundred pixels of photograph and cannot rely on any single part of
     it staying dark. */
  text-shadow: 0 1px 3px rgba(0, 20, 36, 0.5), 0 4px 44px rgba(0, 20, 36, 0.7);
}

.pp-hero__lede {
  margin: 26px 0 0;
  max-width: 54ch;
  font-size: clamp(16px, 1.5vw, 20px);
  font-weight: 300;
  line-height: 1.68;
  color: rgba(255, 255, 255, 0.9);
  text-shadow: 0 1px 3px rgba(0, 20, 36, 0.55), 0 2px 26px rgba(0, 20, 36, 0.7);
}

.pp-hero__cta {
  margin: 34px 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}

/* A secondary action that has to read on photography: bordered, white type,
   filling to solid white on hover. `--ghost` cannot be used here — it is navy
   on white and disappears completely against a dark frame. */
.pp-btn--onphoto {
  border-color: rgba(255, 255, 255, 0.6);
  color: #fff !important;
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}

.pp-btn--onphoto::before { background: #fff; transform: translateY(101%); }
.pp-btn--onphoto:hover { color: var(--pp-navy) !important; border-color: #fff; }
.pp-btn--onphoto:hover::before { transform: translateY(0); }

/* The copy leaves as the hero does — driven by --pp-h-copy, which pp-next.js
   holds at 1 through the opening third of the hero's height and then runs to
   0. It lifts as it fades; a straight opacity ramp at this size reads as the
   page failing to load rather than as an exit. */
.pp-js .pp-hero__inner {
  opacity: var(--pp-h-copy, 1);
  transform: translate3d(0, calc((1 - var(--pp-h-copy, 1)) * -40px), 0);
  will-change: opacity, transform;
}

/* The theme's row wrapper around the hero carries its own vertical padding and
   a full-height minimum, both sized for the slider that used to be there. Left
   alone they add a band of empty page above and below the hero. */
body.pp-page--hero .first-section > .row_col_wrap_12,
body.pp-page--hero #ajax-content-wrap .wpb_row.first-section {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  min-height: 0 !important;
}

body.pp-page--hero .pp-hero { margin-top: 0; }

/* Full bleed for everything else on a hero page, for the same reason and by
   the same means.
   ----------------------------------------------------------------------------
   These sections used to be appended after the theme's `.container` had closed,
   so they were already at page width. They are emitted at the hero's position
   now — which is what puts the page in the right order — and that position is
   inside the container, which is max-width constrained and padded. Left alone,
   every navy band and cloud band on Private Client, Advisory, Contact and the
   homepage renders inset with a white gutter down each side.

   `.pp-shell` inside each section still holds the copy to its own max-width, so
   widening the section box only moves the background, not the text measure. */
body.pp-page--hero .pp-section,
body.pp-page--hero .pp-ticker {
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw);
}

/* Right-hand edge, not centre. Centred, it lands level with the hero's own
   buttons and reads as a third one. */
.pp-scrollcue {
  position: absolute;
  left: auto;
  right: 40px;
  bottom: 30px;
  z-index: 22;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  border: 0;
  background: none;
  cursor: pointer;
  font-family: "Josefin Sans", -apple-system, BlinkMacSystemFont, sans-serif;
  opacity: 1;
  transition: opacity 0.5s ease;
}

.pp-scrollcue--gone { opacity: 0; pointer-events: none; }

.pp-scrollcue__label {
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
  text-shadow: 0 1px 12px rgba(0, 30, 52, 0.55);
}

.pp-scrollcue__line {
  position: relative;
  width: 1px;
  height: 46px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.28);
}

/* A single mote falling the length of the rule, on a long pause between
   passes so it invites rather than nags. */
.pp-scrollcue__line::after {
  content: "";
  position: absolute;
  left: 0;
  width: 1px;
  height: 16px;
  background: linear-gradient(180deg, transparent, #fff);
  animation: pp-cue 2.6s var(--pp-ease-io) infinite;
}

@keyframes pp-cue {
  0%   { transform: translateY(-18px); opacity: 0; }
  22%  { opacity: 1; }
  72%  { transform: translateY(46px); opacity: 0; }
  100% { transform: translateY(46px); opacity: 0; }
}

/* The section directly under the hero.
   It used to be driven by the pinned hero's exit through --pp-h-riser. With
   the pin gone nothing writes that variable, and a rule that hid this shell
   until a variable arrived would hide it for ever — which is exactly what a
   first pass at this did: the credibility band rendered as 160px of empty
   navy. The contents already carry .pp-reveal with their own stagger, so the
   section needs no separate entrance of its own. */

/* The seam.
   The veil resolves to a flat #00273f, but the navy sections carry a drifting
   aurora on ::before that is brightest well away from centre — so the first
   pixels of the riser were a different navy from the last pixels of the hero
   and the join showed as a hard horizontal edge. Holding the section's own
   top band at the flat colour lets the aurora bloom below the seam instead of
   across it. */
/* The gap between the hero and the band under it. `--tight` gives 72px at the
   top, which is right between two ordinary sections and too much directly
   under a full-bleed hero — it reads as a pause rather than a hand-off. The
   bottom keeps its full value so the band is not cramped against what follows. */
.pp-riser { padding-top: clamp(34px, 3.4vw, 48px); }

.pp-riser::before { mask-image: linear-gradient(180deg, transparent 0, transparent 200px, #000 720px); }


/* ---- Header and footer ----------------------------------------------------------------
   The theme's own chrome, which the rest of this stylesheet deliberately leaves
   alone. These are the two places where leaving it alone stopped being the right
   call: they bracket every page, so their spacing is the first and last thing
   read, and both were carrying defaults that no longer sit with the pages
   between them.
   ---------------------------------------------------------------------------------------- */

/* The nav sat 14px from the top of the window with nothing under it — a row of
   type against the edge of the screen rather than a bar. A little height, and
   the items centred in it, is the whole fix. */
#header-outer #top > .container > .row {
  padding-top: 6px;
  padding-bottom: 6px;
}

#header-outer #top nav > ul > li > a {
  letter-spacing: 0.09em;
}

/* ---- Footer ---------------------------------------------------------------------------- */

/* The vertical space above the footer content was coming from two places at
   once — 84px on #footer-widgets and another 75px on the .row inside it, so
   159px of empty navy before the first word. The row's share is zeroed and the
   rhythm is owned in one place. */
#footer-outer #footer-widgets {
  padding: clamp(52px, 4.6vw, 72px) 0 clamp(34px, 3vw, 48px);
}

#footer-outer #footer-widgets .row {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}

/* Every text block in the footer, on one scale.
   The widgets ship at 12px with a 14px line-height — leading tighter than the
   type is tall, which is why the address block read as one run-on paragraph
   rather than two addresses. */
#footer-outer #footer-widgets p,
#footer-outer #footer-widgets li,
#footer-outer #footer-widgets a {
  font-size: 13px;
  line-height: 1.72;
  letter-spacing: 0.02em;
}

#footer-outer #footer-widgets p { margin: 0 0 12px; }
#footer-outer #footer-widgets p:last-child { margin-bottom: 0; }

/* The legal line arrived from a word processor with `font-family: arial;
   font-size: 10px` written into the element. Inline styles need the same
   weapon back — this is the one place in this stylesheet that earns an
   !important. */
#footer-outer #footer-widgets p[style],
#footer-outer #footer-widgets p[style] span {
  font-family: "Josefin Sans", -apple-system, BlinkMacSystemFont, sans-serif !important;
  font-size: 12px !important;
  line-height: 1.7 !important;
  color: rgba(255, 255, 255, 0.6) !important;
}

#footer-outer #footer-widgets h4 {
  margin-bottom: 18px;
  letter-spacing: 0.24em;
  line-height: 1.4;
}

/* Social marks: 36px solid white glyphs, heavier than any type near them.
   Sized down and held back until hovered, so they read as a footer detail
   rather than as the loudest thing in it. */
#footer-outer #footer-widgets .widget_block svg {
  width: 22px;
  height: 22px;
  opacity: 0.72;
  transition: opacity 0.3s ease, transform 0.3s var(--pp-ease);
}

#footer-outer #footer-widgets .widget_block a { display: inline-flex; }
#footer-outer #footer-widgets .widget_block a:hover svg { opacity: 1; transform: translateY(-2px); }

#footer-outer #copyright {
  padding: 20px 0 !important;
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}

#footer-outer #copyright .container { padding-top: 0; padding-bottom: 0; }

#footer-outer #copyright p {
  font-size: 12px;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.55);
}

@media (max-width: 690px) {
  /* Stacked, the footer had a left-aligned address block, centred nav links and
     a centred copyright line — three alignments in one column. All left. */
  #footer-outer #footer-widgets .col,
  #footer-outer #footer-widgets .col * ,
  #footer-outer #copyright,
  #footer-outer #copyright * { text-align: left !important; }

  /* One controlled gap between the stacked columns. The theme's own 40px
     bottom margin plus an added top margin compounded to 74px, which on a
     phone read as the footer having fallen into two separate blocks. */
  #footer-outer #footer-widgets .col { margin-bottom: 0 !important; }
  #footer-outer #footer-widgets .col + .col { margin-top: 30px; }
  #footer-outer #footer-widgets .widget { margin-bottom: 20px; }
  #footer-outer #footer-widgets .widget:last-child { margin-bottom: 0; }
  #footer-outer #footer-widgets { padding: 48px 0 36px; }
  #footer-outer #copyright { padding: 16px 0 !important; }
}

/* ---- Closing statement ----------------------------------------------------------------
   Ends Private Client and Advisory. Centred, because it is the one place on
   those pages where the firm is speaking about itself rather than about the
   work — and because a left-aligned line under a left-aligned page reads as
   another section rather than as a close. */

.pp-closing { text-align: center; }

.pp-closing__inner {
  max-width: 44ch;
  margin: 0 auto;
}

.pp-closing__lead {
  margin: 0;
  font-size: clamp(24px, 2.9vw, 38px);
  font-weight: 300;
  line-height: 1.22;
  letter-spacing: 0.015em;
  color: #fff;
}

.pp-closing__follow {
  margin: 20px auto 0;
  max-width: 46ch;
  font-size: clamp(15px, 1.3vw, 18px);
  font-weight: 300;
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.76);
}

.pp-closing__cta { margin-top: 34px; }

/* ---- Card tilt ------------------------------------------------------------------------
   Composed through custom properties because these elements are also reveal
   targets: `.pp-reveal.pp-is-visible { transform: none }` would otherwise
   overwrite the tilt the moment the card became visible.
   ---------------------------------------------------------------------------------------- */

.pp-js .pp-door.pp-is-visible,
.pp-js .pp-access__card.pp-is-visible,
.pp-door:not(.pp-reveal),
.pp-access__card:not(.pp-reveal) {
  transform:
    perspective(1000px)
    rotateX(var(--pp-rx, 0deg))
    rotateY(var(--pp-ry, 0deg))
    translate3d(0, var(--pp-lift, 0px), 0);
}

.pp-door.pp-tilting,
.pp-access__card.pp-tilting {
  /* Follow the pointer at pointer speed; keep the slow easing for the lift
     and shadow so the card still settles rather than snapping. */
  transition: transform 0.14s linear, box-shadow 0.5s var(--pp-ease), border-color 0.4s ease;
}

/* ---- Cursor ring -------------------------------------------------------------------------
   Trails the pointer with a lerp so it reads as an object with weight. The
   native cursor is never hidden — this is decoration on top of it, not a
   replacement for it.
   ------------------------------------------------------------------------------------------ */

.pp-cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 26px;
  height: 26px;
  border: 1px solid rgba(0, 118, 189, 0.5);
  border-radius: 50%;
  z-index: 99998;
  pointer-events: none;
  opacity: 0;
  /* transform is written every frame by JS — transitioning it would fight the
     lerp and produce a visible drag. */
  transition: opacity 0.3s ease, width 0.26s var(--pp-ease), height 0.26s var(--pp-ease),
    background 0.26s ease, border-color 0.26s ease;
}

.pp-cursor--on { opacity: 1; }
.pp-cursor--wide { width: 44px; height: 44px; background: rgba(0, 118, 189, 0.07); border-color: rgba(0, 118, 189, 0.72); }
.pp-cursor--down { width: 18px; height: 18px; background: rgba(0, 118, 189, 0.16); }

/* ---- Intro curtain -------------------------------------------------------------------------
   Homepage, once per session, pointer-events:none from the first frame and
   removed by a watchdog regardless of what else happens on the page.
   -------------------------------------------------------------------------------------------- */

.pp-curtain {
  position: fixed;
  inset: 0;
  z-index: 99999;
  pointer-events: none;
  background: #00273f;
  display: grid;
  place-items: center;
  transform: translateY(0);
}

.pp-curtain__mark {
  width: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--pp-blue-lift), transparent);
  transition: width 0.5s var(--pp-ease);
}

.pp-curtain--in .pp-curtain__mark { width: min(320px, 52vw); }

.pp-curtain--out {
  transform: translateY(-100%);
  transition: transform 0.78s cubic-bezier(0.76, 0, 0.24, 1);
}

.pp-curtain--out .pp-curtain__mark { opacity: 0; transition: opacity 0.2s ease; }

/* ---- Clip-path reveal ----------------------------------------------------------------------- */

.pp-js .pp-reveal--mask {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1.05s var(--pp-ease);
  transition-delay: var(--pp-d, 0ms);
}

.pp-js .pp-reveal--mask.pp-is-visible { clip-path: inset(0 0 0 0); }

/* ---- Responsive ---------------------------------------------------------------------- */

@media (max-width: 1080px) {
  /* The process rail, pinned.
     ------------------------------------------------------------------------
     On a wide screen the four stages sit beside a sticky rail, so the reader
     can always see which one they are in. Stacked on a phone that rail scrolled
     away with the heading, and the four stages became four paragraphs with no
     indication that they were a sequence at all — the one part of the page that
     is explicitly "four stages" read as prose.

     So it pins here too, across the top rather than down the side. It sticks
     under the theme's fixed header, carries its own navy so the stage text
     scrolling beneath cannot show through it, and its rule runs left to right
     as the reader moves through the stages. pp-next.js keeps the active pill
     scrolled into view and drives the rule from continuous progress rather than
     from which stage is active, so it moves rather than stepping. */
  .pp-process { grid-template-columns: 1fr; gap: 0; }

  /* Grid items default to a min-width of auto, so an item wider than the track
     widens the track rather than overflowing it. The rail is deliberately wider
     than the shell (it has to reach the screen edges), and without this that
     made the whole process column 404px inside a 375px viewport and pushed the
     stage copy off the right of the screen. */
  .pp-process > * { min-width: 0; }

  .pp-process__rail {
    position: sticky;
    /* The theme's mobile header is position:absolute — it leaves with the page
       rather than staying fixed — so there is nothing above the viewport top to
       clear here. Measured rather than assumed: on desktop it is fixed, which is
       why the desktop rail sits at 130px and this one at 0. */
    top: 0;
    z-index: 40;
    align-self: start;
    padding: 14px 0 0;
    box-shadow: 0 16px 26px -20px rgba(0, 0, 0, 0.85);
  }

  /* The navy reaches the screen edges without the rail itself being wider than
     its grid track — a negative margin would put the track sizing back where it
     was. */
  .pp-process__rail::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: -28px;
    right: -28px;
    background: var(--pp-navy-deep);
    z-index: -1;
  }

  .pp-process__nav {
    display: flex;
    gap: 22px;
    overflow-x: auto;
    padding-bottom: 12px;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }

  .pp-process__nav::-webkit-scrollbar { display: none; }

  .pp-process__nav li {
    border-left: 0;
    padding: 4px 0;
    white-space: nowrap;
    font-size: 12px;
    letter-spacing: 0.16em;
  }

  .pp-process__nav li.pp-active { padding-left: 0; color: #fff; }

  /* The rule. Full width of the strip, under the pills rather than under the
     scrolling list — the list scrolls horizontally, and a rule inside it would
     slide away with the pills it is measuring. */
  .pp-process__nav::after {
    top: auto;
    bottom: 0;
    left: 0;
    width: var(--pp-railx, 0%);
    height: 2px;
    background: linear-gradient(90deg, var(--pp-blue-lift), rgba(47, 151, 216, 0.35));
    transition: width 0.25s linear;
  }

  .pp-process__rail::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 2px;
    background: rgba(255, 255, 255, 0.14);
    z-index: -1;
  }

  /* Room for the pinned strip, so a stage heading never arrives underneath it. */
  .pp-process__body { padding-top: 30px; }
  .pp-stage { scroll-margin-top: calc(60px + var(--pp-railh, 76px) + 16px); }
  .pp-stage { padding-bottom: 46px; }
}

@media (max-width: 999px) {
  .pp-marks { grid-template-columns: repeat(2, 1fr); }
  .pp-pillars { grid-template-columns: repeat(2, 1fr); }
  .pp-split { grid-template-columns: 1fr; gap: 44px; }
  .pp-preview { transform: none; }
  .pp-signin { grid-template-columns: 1fr; min-height: 0; }
  .pp-signin__aside { padding: 34px 28px; }
  .pp-signin__list { display: none; }
  .pp-modal__body { padding: 36px 28px 32px; }
}

@media (max-width: 690px) {
  .pp-shell { padding: 0 20px; }
  .pp-pillars,
  .pp-doors,
  .pp-access,
  .pp-form__grid { grid-template-columns: 1fr; }

  /* The stat row stays two-up on a phone rather than collapsing to one.
     Every value in it is two or three words, so a full-width row is mostly
     empty space, and four of them turned a compact band into 500px of
     scrolling with one short line in the middle of each screen-width card.
     Two-up keeps it reading as a single band. */
  .pp-marks { grid-template-columns: repeat(2, 1fr); }
  .pp-mark { padding: 26px 14px; }
  .pp-mark__value { font-size: 17px; }
  .pp-mark__label { font-size: 9.5px; letter-spacing: 0.16em; }
  .pp-marks--wide .pp-mark { padding: 18px 12px 16px; }
  .pp-doors, .pp-access { gap: 20px; }
  .pp-door, .pp-access__card { padding: 30px 24px; }
  /* Modals are full-screen on a phone, not a bottom sheet. The sheet left 8dvh
     (67px at 390x844) of blurred scrim above the panel, which reads as the page
     having been shoved down out from under its own header — there is no logo and
     no nav up there, just a gap. It also spent height on the one viewport with
     the least of it, on panels that already scroll ~1,200px internally. */
  .pp-modal { padding: 0; align-items: stretch; }
  .pp-modal__panel,
  .pp-modal__panel--narrow {
    max-width: none;
    min-height: 100dvh;
    max-height: 100dvh;
    /* A scale on a full-bleed panel exposes a sliver of scrim down both edges as
       it settles. Slide only. */
    transform: translateY(26px);
  }

  .pp-modal.pp-modal--open .pp-modal__panel { transform: none; }
  .pp-modal__body { padding: 26px 20px calc(30px + env(safe-area-inset-bottom)); }

  .pp-modal__close {
    top: calc(8px + env(safe-area-inset-top));
    margin: calc(8px + env(safe-area-inset-top)) 8px -48px 0;
  }

  /* The sign-in split puts its navy aside above the form, so the close sits on
     navy there and needs the opposite treatment. */
  .pp-modal__panel:has(.pp-signin) .pp-modal__close {
    background: rgba(255, 255, 255, 0.14);
    border-color: rgba(255, 255, 255, 0.24);
    color: #fff;
    box-shadow: none;
  }

  .pp-form__grid { gap: 18px 20px; }
  .pp-signin__main { padding: 34px 24px calc(34px + env(safe-area-inset-bottom)); }
  .pp-form__foot { gap: 14px; }
  .pp-form__foot .pp-btn { width: 100%; text-align: center; }
  .pp-btn { padding: 16px 26px; }
  /* Parallax fights momentum scrolling on touch — the browser's compositor and
     our rAF loop disagree during the fling, which reads as jitter. Off. */
  .pp-parallax { transform: none !important; }
  .pp-ticker__track { animation-duration: 30s; }

  /* Hero on a phone: the wash and the copy exit stay (opacity and a few
     pixels, both composite cleanly) but the photograph does not drift or
     scale. Scaling a full-bleed image mid-fling is where touch jitter shows,
     and a translate that is barely readable on a laptop eats real estate on a
     small screen. */
  .pp-hero__img { transform: none; }
  /* No cue on a phone. The CTAs go full-width and stack, so there is no
     column left for it to sit in — it landed on top of the second button.
     A scroll hint on a touch device is advice nobody needed anyway. */
  .pp-scrollcue { display: none; }

  /* The nav fade is WHITE because the nav is dark type. The hero eyebrow is
     also white, and on a phone it lands at 166px — inside a 210px fade, which
     was actively bleaching it. The header here is ~90px, so the fade is sized
     to clear that and stop before the hero's own copy begins. */
  .pp-navfade {
    height: 132px;
    background: linear-gradient(
      180deg,
      rgba(255, 255, 255, 0.97) 0%,
      rgba(255, 255, 255, 0.86) 34%,
      rgba(255, 255, 255, 0.44) 66%,
      rgba(255, 255, 255, 0) 100%
    );
  }

  /* The wash has to be rebuilt for a portrait box, not just inherited.
     The desktop version leans on a 104deg diagonal to weight the darkening
     toward the corner the copy sits in — over a 16:9 frame that leaves most of
     the photograph untouched. Run the same diagonal across a 390x743 box and
     it crosses the whole thing: measured, the picture was visible for the top
     200px and the remaining three quarters of the hero was flat navy. So on a
     phone the darkening is vertical only, and it starts lower. */
  .pp-hero__wash {
    background: linear-gradient(
      180deg,
      rgba(0, 26, 44, 0.42) 0%,
      rgba(0, 26, 44, 0.16) 20%,
      rgba(0, 26, 44, 0.3) 44%,
      rgba(0, 30, 52, 0.76) 72%,
      rgba(0, 39, 63, 0.95) 92%,
      var(--pp-navy-deep) 100%
    );
  }

  .pp-hero--light .pp-hero__wash {
    background: linear-gradient(
      180deg,
      rgba(0, 26, 44, 0.44) 0%,
      rgba(0, 26, 44, 0.18) 20%,
      rgba(0, 26, 44, 0.34) 44%,
      rgba(0, 26, 44, 0.72) 74%,
      rgba(0, 26, 44, 0.6) 90%,
      rgba(255, 255, 255, 0.1) 98%,
      #fff 100%
    );
  }

  /* Portrait crop: more of the hero's height is photograph the reader can see,
     so the copy block needs to sit lower and tighter rather than filling it. */
  .pp-hero {
    height: 74svh;
    min-height: 520px;
    max-height: none;
  }

  /* Two rows of stat cards cannot both clear a phone fold under any hero worth
     having, so the second row is meant to be below it — but the first row
     should sit properly on the opening screen rather than half of it. */
  .pp-riser { padding-top: 28px; }

  /* A local ground for the copy block. The full-width wash cannot be made much
     stronger without flattening the photograph, but a portrait crop puts the
     lede over whatever happens to be at mid-frame — on the contact bridge that
     is a lit tower. This darkens only the band the words occupy. */
  .pp-hero__inner {
    padding-bottom: clamp(48px, 7vh, 72px);
    padding-top: 26px;
    background: linear-gradient(
      180deg,
      rgba(0, 26, 44, 0) 0%,
      rgba(0, 26, 44, 0.42) 22%,
      rgba(0, 26, 44, 0.58) 60%,
      rgba(0, 26, 44, 0.62) 100%
    );
  }
  .pp-hero__title { max-width: 13ch; line-height: 1.05; }
  .pp-hero__lede { margin-top: 18px; font-size: 15.5px; line-height: 1.62; }
  .pp-hero__cta { margin-top: 26px; gap: 10px; }
  .pp-hero__cta .pp-btn { flex: 1 1 auto; justify-content: center; text-align: center; }
}

/* No pointer-driven effects where there is no pointer. */
@media (hover: none) {
  /* The aurora behind the navy sections is a 31-second animation over two
     radial gradients on a box inset -40% — comfortably the most expensive
     continuously-painting thing on the page, and it sits directly above the
     ticker. The gradient stays; only the motion goes. Nobody is watching a
     31-second loop on a phone, and the compositor has less to spare there. */
  .pp-section--navy::before { animation: none; }

  .pp-cursor { display: none; }
  .pp-js .pp-door.pp-is-visible,
  .pp-js .pp-access__card.pp-is-visible { transform: translate3d(0, var(--pp-lift, 0px), 0); }
}

/* ---- Reduced motion ------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .pp-js .pp-reveal,
  .pp-js .pp-reveal--left,
  .pp-js .pp-reveal--right,
  .pp-js .pp-reveal--scale { opacity: 1; transform: none; transition: none; }
  .pp-word > span { transform: none; transition: none; }
  .pp-rule { width: 54px; transition: none; }
  .pp-is-visible .pp-preview__row,
  .pp-preview__row,
  .pp-vault li { opacity: 1; transform: none; transition: none; }
  .pp-preview__meter span { width: 78%; transition: none; }
  .pp-is-visible .pp-pillar::before { width: 100%; transition: none; }
  .pp-is-visible .pp-door__list li::before { width: 10px; transition: none; }
  .pp-section--navy::before,
  .pp-signin__aside::before,
  .pp-ticker__track,
  .pp-dot { animation: none; }
  .pp-parallax { transform: none !important; }
  .pp-door:hover, .pp-access__card:hover, .pp-btn:hover { transform: none; }
  .pp-preview, .pp-preview:hover { transform: none; }
  .pp-modal__panel, .pp-modal__scrim { transition: none; }
  .pp-success { animation: none; }

  /* Hero: the wash stays — it is a static gradient doing a compositional and
     contrast job, not motion — but nothing moves, nothing fades on scroll, and
     the cue, which exists only to advertise motion, is not rendered. */
  .pp-hero__img { transform: none; }
  .pp-js .pp-hero__inner { opacity: 1; transform: none; }
  .pp-scrollcue { display: none; }
  .pp-js .pp-riser .pp-shell { transform: none; opacity: 1; transition: none; }
  .pp-js .pp-door.pp-is-visible,
  .pp-js .pp-access__card.pp-is-visible { transform: none; }
  .pp-cursor { display: none; }
  .pp-curtain { display: none; }
  .pp-js .pp-reveal--mask { clip-path: none; transition: none; }
  .pp-js .pp-modal__body > * { opacity: 1; transform: none; transition: none; }
  .pp-ticker__inner { transform: none; }
  .pp-process__nav::after { transition: none; }
  .pp-field input, .pp-field select, .pp-field textarea { transition: border-color 0.25s ease; }
  .pp-scrollcue__line::after { animation: none; }
}

/* ---- Glyphs -----------------------------------------------------------------------------
   Inline SVG, sized in ems so a glyph tracks whatever it sits beside, and
   coloured by `currentColor` so one markup form works on the navy sections and
   the white ones. Deliberately understated: these are wayfinding, marking where
   a block begins, not illustration competing with the headline next to it.
   ------------------------------------------------------------------------------------------ */

.pp-ico {
  width: 1em;
  height: 1em;
  display: block;
  flex: none;
  /* Hairline strokes on a light ground go muddy at small sizes without this. */
  shape-rendering: geometricPrecision;
}

/* ---- Credibility strip, wide variant ------------------------------------------------------
   The homepage strip carries four short value/label pairs. On the interior
   pages the same component carries a glyph as well, so the cell needs more
   vertical room and the type has to step down — "Service & management" over two
   lines in the homepage's size overflows its cell.
   ------------------------------------------------------------------------------------------ */

.pp-marks--wide .pp-mark { padding: 26px 20px 24px; }
.pp-marks--wide .pp-mark__value { font-size: clamp(17px, 1.35vw, 21px); }

/* The mark's icon. Sized against the card it sits in, not on its own terms:
   at 26px with a 16px margin it made the --wide band 52px taller than the plain
   one on a desktop and 106px taller on a phone, which is the whole reason the
   Private Client band's second row landed below the fold when the homepage's
   did not. The bands have to be the same shape to sit the same way under an
   identically-sized hero. */
.pp-mark__ico {
  display: flex;
  justify-content: center;
  margin-bottom: 10px;
  font-size: 21px;
  color: var(--pp-blue-lift);
  opacity: 0.92;
}

/* ---- Pillar glyph ------------------------------------------------------------------------
   Sits above the number rather than beside it: the number is already a strong
   left-aligned marker, and putting both on one line makes the pillar's top edge
   read as a toolbar.
   ------------------------------------------------------------------------------------------ */

/* A mark at the head of each door card. Sized and coloured like the pillar
   marks so the two grids read as one system rather than two treatments. */
.pp-door__ico {
  display: block;
  margin-bottom: 18px;
  color: var(--pp-blue);
}

.pp-door__ico .pp-ico { width: 30px; height: 30px; }

.pp-access__card--primary .pp-door__ico { color: var(--pp-blue-lift); }

.pp-pillar__ico {
  display: block;
  margin-bottom: 16px;
  font-size: 28px;
  color: var(--pp-blue);
}

.pp-section--navy /* A mark at the head of each door card. Sized and coloured like the pillar
   marks so the two grids read as one system rather than two treatments. */
.pp-door__ico {
  display: block;
  margin-bottom: 18px;
  color: var(--pp-blue);
}

.pp-door__ico .pp-ico { width: 30px; height: 30px; }

.pp-access__card--primary .pp-door__ico { color: var(--pp-blue-lift); }

.pp-pillar__ico { color: var(--pp-blue-lift); }

/* ---- Step list ----------------------------------------------------------------------------
   A glyph, then a labelled line. Distinct from .pp-vault, which is a
   label/value pair with the value set as small uppercase blue and pinned right
   — reusing it here would have set the entire description in 10.5px uppercase
   on one unwrapping line.
   ------------------------------------------------------------------------------------------ */

.pp-steps {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--pp-line);
}

.pp-steps li {
  display: flex;
  align-items: flex-start;
  gap: 18px;
  padding: 20px 2px;
  border-bottom: 1px solid var(--pp-line);
  font-size: 15px;
  font-weight: 300;
  line-height: 1.55;
  color: var(--pp-slate);
}

/* Hidden only when the script that reveals them is actually running — the
   .pp-js guard on <html> is what keeps every animated block legible with
   JavaScript off. */
.pp-js .pp-steps li {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.55s var(--pp-ease), transform 0.55s var(--pp-ease);
  transition-delay: var(--pp-d, 0ms);
}

.pp-js .pp-is-visible .pp-steps li,
.pp-js .pp-steps li.pp-is-visible { opacity: 1; transform: none; }

.pp-steps .pp-ico {
  font-size: 22px;
  margin-top: 2px;
  color: var(--pp-blue);
}

.pp-steps strong {
  font-weight: 600;
  color: var(--pp-navy);
}

@media (max-width: 900px) {
  .pp-marks--wide .pp-mark { padding: 20px 14px 18px; }
  .pp-mark__ico { font-size: 19px; margin-bottom: 8px; }
  .pp-steps li { gap: 14px; padding: 16px 2px; font-size: 14.5px; }
}

@media (prefers-reduced-motion: reduce) {
  .pp-js .pp-steps li { opacity: 1; transform: none; transition: none; }
}

/* Inline reassurance notes — a row under a form's lede answering the three
   things people actually hesitate over before filling one in: who reads it,
   what happens to it, and how long it takes. Set quietly; this is a footnote
   with glyphs, not a feature list. */
.pp-inline-notes {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 34px;
  margin: 26px 0 0;
  padding: 0;
  list-style: none;
}

.pp-inline-notes li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  font-weight: 300;
  color: var(--pp-slate);
}

.pp-inline-notes .pp-ico {
  font-size: 17px;
  color: var(--pp-blue);
  opacity: 0.85;
}

.pp-steps a { color: var(--pp-blue); text-decoration: none; border-bottom: 1px solid transparent; }
.pp-steps a:hover { border-bottom-color: currentColor; }
.pp-steps span { min-width: 0; }

@media (max-width: 900px) {
  .pp-inline-notes { gap: 10px 20px; }
  .pp-inline-notes li { font-size: 12.5px; }
}

/* ==========================================================================
   Document request — the type picker, quick-request tags, sign-in alternate
   --------------------------------------------------------------------------
   Added with the /client-demo/ work. Site-wide, because the document request
   modal is injected on every page and any control anywhere can open it
   pre-selected via `data-pp-docs`.

   The thirteen document types are behind ONE collapsed control rather than
   laid out as thirteen chips. Visible, they read as a form to work through
   before the form starts, and they pushed the name and email fields below the
   fold on a phone. Collapsed, they read as a single question.

   The inputs inside are real checkboxes with real labels — not styled buttons
   and not a custom listbox — so the panel survives a keyboard, a screen reader
   and autofill, and `presetDocTypes()` can tick them without knowing anything
   about the widget.
   ========================================================================== */

.pp-multi { display: grid; gap: 7px; }

/* The panel is positioned against THIS, not against .pp-multi — anchoring it
   to the whole block put it 22px too low, over the hint line underneath. */
.pp-multi__field { position: relative; }

.pp-multi__label {
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--pp-navy);
  font-weight: 600;
}

.pp-multi__trigger {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 13px 16px;
  background: #fff;
  border: 1px solid var(--pp-line);
  border-radius: 4px;
  font-size: 15px;
  line-height: 1.35;
  color: var(--pp-ink);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}

.pp-multi__trigger:hover { border-color: var(--pp-blue); }
.pp-multi__trigger:focus-visible { outline: 2px solid var(--pp-blue); outline-offset: 2px; }

.pp-multi__trigger[aria-expanded="true"] {
  border-color: var(--pp-blue);
  box-shadow: 0 0 0 3px rgba(0, 118, 189, 0.12);
}

.pp-multi__trigger svg {
  flex: none;
  margin-left: auto;
  color: var(--pp-slate);
  transition: transform 0.2s var(--pp-ease);
}

.pp-multi__trigger[aria-expanded="true"] svg { transform: rotate(180deg); }

.pp-multi__summary { min-width: 0; }
.pp-multi__summary[data-empty="1"] { color: var(--pp-slate); }

/* Absolute, so opening the picker does not push the rest of the form down —
   the reason a details/summary version of this felt like the page jumping. */
.pp-multi__panel {
  position: absolute;
  z-index: 5;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  max-height: 264px;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: #fff;
  border: 1px solid var(--pp-blue);
  border-radius: 4px;
  box-shadow: 0 22px 44px -26px rgba(0, 39, 63, 0.55);
  padding: 6px;
}

.pp-multi__panel[hidden] { display: none; }

.pp-multi__opt {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 10px;
  border-radius: 3px;
  cursor: pointer;
  margin: 0;
  transition: background 0.14s ease;
}

.pp-multi__opt:hover { background: var(--pp-cloud); }

.pp-multi__opt input {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 17px;
  height: 17px;
  margin: 0;
  border: 1.5px solid var(--pp-line);
  border-radius: 4px;
  background: #fff;
  cursor: pointer;
}

.pp-multi__opt input:checked {
  background: var(--pp-blue) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / 11px 11px no-repeat;
  border-color: var(--pp-blue);
}

.pp-multi__opt input:focus-visible { outline: 2px solid var(--pp-blue); outline-offset: 2px; }

.pp-multi__opt span { font-size: 14.5px; line-height: 1.35; color: var(--pp-ink); }
.pp-multi__opt input:checked + span { font-weight: 600; color: var(--pp-navy); }

/* Quick-request tags on /client-login/ */

.pp-quickreq {
  background: #fff;
  border: 1px solid var(--pp-line);
  border-left: 3px solid var(--pp-blue);
  padding: 30px 32px;
  display: grid;
  gap: 22px;
}

.pp-quickreq__row { display: flex; flex-wrap: wrap; gap: 8px; }

.pp-tagbtn {
  border: 1px solid var(--pp-line);
  border-radius: 999px;
  background: #fff;
  padding: 9px 16px;
  font-size: 13.5px;
  color: var(--pp-ink);
  cursor: pointer;
  transition: border-color 0.18s ease, color 0.18s ease, transform 0.18s ease;
}

.pp-tagbtn:hover {
  border-color: var(--pp-blue);
  color: var(--pp-blue);
  transform: translateY(-1px);
}

/* Sign-in modal — the way out for someone who has no account yet */

.pp-signin__alt {
  margin: 18px 0 0;
  font-size: 12.5px;
  line-height: 1.65;
  color: var(--pp-slate);
}

.pp-signin__alt a { color: var(--pp-blue); border-bottom: 1px solid rgba(0, 118, 189, 0.35); }
.pp-signin__alt a:hover { border-bottom-color: var(--pp-blue); }

@media (max-width: 690px) {
  .pp-quickreq { padding: 22px 20px; }
  /* 16px on the trigger: anything smaller makes iOS Safari zoom the page when
     a control in this form takes focus, and the modal never zooms back out. */
  .pp-multi__trigger { font-size: 16px; padding: 12px 14px; }
  .pp-multi__panel { max-height: 232px; }
}
