/* KuyaYos — site-wide styles
 * Brand: navy-teal #1a6b8a (structure) + warm orange #e87722 (action).
 * Typography: Nunito Sans (self-hosted).
 * No external resources, no inline styles, strict CSP-friendly.
 */

/* Self-hosted Nunito Sans variable font.
 * If /assets/fonts/NunitoSans-Variable.woff2 isn't present yet, the system
 * fallback stack below keeps the site readable. See README for setup.
 */
@font-face {
  font-family: 'Nunito Sans';
  src: url('/assets/fonts/NunitoSans-Variable.woff2') format('woff2-variations'),
       url('/assets/fonts/NunitoSans-Variable.woff2') format('woff2');
  font-weight: 200 1000;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Nunito Sans';
  src: url('/assets/fonts/NunitoSans-Italic-Variable.woff2') format('woff2-variations'),
       url('/assets/fonts/NunitoSans-Italic-Variable.woff2') format('woff2');
  font-weight: 200 1000;
  font-style: italic;
  font-display: swap;
}

:root {
  /* Brand */
  --brand: #1a6b8a;
  --brand-700: #155674;
  --brand-800: #0f445d;
  --brand-900: #0a2f42;
  --brand-50: #e7f1f5;
  --brand-100: #cfe3eb;

  --action: #e87722;
  --action-700: #cb5f0d;
  --action-800: #a04a08;
  --action-50: #fdf0e4;

  /* Neutrals */
  --ink: #0f1c24;
  --ink-soft: #324a58;
  --slate-700: #4b5d68;
  --slate-500: #768691;
  --slate-300: #c2cdd4;
  --slate-200: #dde4e9;
  --slate-100: #eef2f5;
  --slate-50: #f6f8f9;
  --paper: #ffffff;
  --bg: #f8fafb;

  /* Effects.
   *
   * Radii unified to 6px across all frame elements (cards, buttons, chips,
   * stamps, inputs). 6px matches the docket-card brand radius. Sub-tokens
   * (sm / lg / pill) are kept as named aliases so existing rules don't
   * need to be rewritten — they all resolve to the same value.
   *
   * Docket-shadow tokens carry a solid colour plate ONLY (no soft drop).
   * The soft blur previously stacked behind read as an unintentional
   * airbrush on different backgrounds. Solid plates render the same way
   * on cream, teal, white — consistency above visual flourish.
   *
   * Ink variants are for elements that are themselves orange (primary
   * buttons), where an orange plate would have no contrast.
   */
  --radius: 6px;
  --radius-sm: 6px;
  --radius-lg: 6px;
  --radius-pill: 6px;
  /* Legacy generic shadow tokens — redefined as hard ink offsets so anything
   * still calling var(--shadow*) inherits the docket-system look automatically. */
  --shadow-sm: 2px 2px 0 0 var(--ink);
  --shadow:    4px 4px 0 0 var(--ink);
  --shadow-lg: 8px 8px 0 0 var(--ink);
  --docket-shadow-sm: 4px 4px 0 0 var(--action);
  --docket-shadow:    8px 8px 0 0 var(--action);
  --docket-shadow-lg: 12px 12px 0 0 var(--action);
  --docket-shadow-sm-ink: 4px 4px 0 0 var(--ink);
  --docket-shadow-ink:    12px 12px 0 0 var(--ink);
  --focus-ring: 0 0 0 3px rgba(232, 119, 34, 0.45);
  --focus-color: var(--action);

  /* Layout */
  --max: 1200px;
  --max-narrow: 760px;

  /* Type */
  --font-display: 'Nunito Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
  --font-system: var(--font-display);

  /* Docket aesthetic tokens — paper, ink rule, mono font. Available
   * site-wide so the .section-docket / .section-stamp / .section-heading-row
   * classes work on any page that uses them. */
  --docket-paper: #fbf8f0;
  --docket-paper-edge: #ede5cc;
  --docket-rule: #d8cca8;
  --docket-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

body {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink);
  background: var(--bg);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: 'kern', 'liga', 'calt';
}

h1, h2, h3, h4 {
  color: var(--brand-900);
  line-height: 1.15;
  margin: 0 0 0.5rem;
  font-weight: 800;
  letter-spacing: -0.02em;
}

/* h1 takes a slightly tighter tracking for display-scale headlines, plus
 * text-wrap: balance so multi-word headlines wrap evenly. */
h1 {
  font-size: clamp(2.25rem, 4.2vw + 1rem, 3.75rem);
  letter-spacing: -0.028em;
  text-wrap: balance;
}
h2 {
  font-size: clamp(1.75rem, 2.4vw + 1rem, 2.5rem);
  text-wrap: balance;
}
h3 { font-size: 1.25rem; font-weight: 700; }
h4 { font-size: 1.0625rem; font-weight: 700; }

p {
  margin: 0 0 1rem;
}

a {
  color: var(--brand);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color 0.15s ease;
}

a:hover {
  color: var(--brand-800);
}

:focus-visible {
  outline: 3px solid var(--focus-color);
  outline-offset: 3px;
  border-radius: 6px;
}

img, svg {
  max-width: 100%;
  height: auto;
  display: block;
}

ul, ol {
  padding: 0;
  margin: 0;
  list-style: none;
}

/* Skip link ------------------------------------------------- */

.skip-link {
  position: absolute;
  left: 1rem;
  top: -3rem;
  background: var(--brand);
  color: #fff;
  padding: 0.75rem 1rem;
  border-radius: var(--radius-sm);
  font-weight: 700;
  text-decoration: none;
  z-index: 100;
  transition: top 0.15s ease;
}

.skip-link:focus,
.skip-link:focus-visible {
  top: 1rem;
}

/* Layout ---------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 1.25rem;
}

.container--narrow {
  max-width: var(--max-narrow);
}

.section {
  padding: 4rem 0;
}

.section--muted {
  background: var(--paper);
}

.section__lede {
  max-width: 62ch;
  color: var(--ink-soft);
  font-size: 1.0625rem;
  margin-bottom: 2.25rem;
}

.eyebrow {
  display: inline-block;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 0.75rem;
  font-weight: 800;
  color: var(--action-700);
  background: var(--action-50);
  padding: 0.4rem 0.85rem;
  border-radius: var(--radius-pill);
  margin: 0 0 1rem;
}

/* Muted text: keep readable. WCAG AA on body text needs >= 4.5:1; --slate-500
 * on white was ~3.8:1 (fail). --slate-700 brings the ratio above 4.5:1 while
 * still reading visibly secondary. .muted--soft is reserved for footnotes
 * where a slightly lighter tone is acceptable. */
.muted {
  color: var(--slate-700);
}
.muted--soft {
  color: var(--slate-500);
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.85rem 1.4rem;
  border-radius: var(--radius-pill);
  font-family: inherit;
  font-weight: 700;
  font-size: 1rem;
  text-decoration: none;
  border: 2px solid transparent;
  cursor: pointer;
  /* Tightened to cubic-bezier ease-out (no bounce) per impeccable's motion rules.
   * Adds box-shadow + transform to the transition list so hover lifts feel
   * unified instead of staggered. */
  transition:
    background 0.18s cubic-bezier(0.22, 1, 0.36, 1),
    color 0.18s cubic-bezier(0.22, 1, 0.36, 1),
    border-color 0.18s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.22s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
  line-height: 1.2;
  letter-spacing: -0.01em;
  white-space: nowrap;
  position: relative;
}

.btn:hover:not(:disabled):not(.is-loading) {
  transform: translateY(-1px);
}

.btn:active:not(:disabled):not(.is-loading) {
  transform: translateY(1px);
  transition-duration: 0.05s;
}

.btn--small {
  padding: 0.55rem 1rem;
  font-size: 0.9375rem;
}

.btn--large {
  padding: 1rem 1.7rem;
  font-size: 1.0625rem;
}

.btn--primary {
  background: var(--action);
  color: #fff;
  box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
}

.btn--primary:hover:not(:disabled):not(.is-loading) {
  background: var(--action-700);
  color: #fff;
  /* Hard offset shadow grows on hover — matches the docket-card aesthetic.
   * Ink shadow (not action shadow) because the button itself is orange. */
  box-shadow: 3px 3px 0 0 var(--ink);
}

.btn--secondary {
  background: var(--brand);
  color: #fff;
}

.btn--secondary:hover:not(:disabled):not(.is-loading) {
  background: var(--brand-800);
  color: #fff;
  box-shadow: 3px 3px 0 0 var(--action);
}

.btn--ghost {
  background: transparent;
  color: var(--brand);
  border-color: var(--brand);
}

.btn--ghost:hover:not(:disabled):not(.is-loading) {
  background: var(--brand);
  color: #fff;
  box-shadow: 3px 3px 0 0 var(--action);
}

.btn--ghost-light {
  background: transparent;
  color: #fff;
  border-color: rgba(255, 255, 255, 0.7);
}

.btn--ghost-light:hover:not(:disabled):not(.is-loading) {
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  border-color: #fff;
}

/* Loading state. JS adds .is-loading to the submit button on form-submit
 * while the POST is in flight. The button label is hidden visually but
 * stays in the a11y tree; a CSS-only spinner overlays the centre. The
 * button is non-interactive in this state. */
.btn.is-loading {
  cursor: progress;
  pointer-events: none;
  color: transparent !important;
  text-shadow: none;
}

.btn.is-loading > * {
  visibility: hidden;
}

.btn.is-loading::after {
  content: "";
  position: absolute;
  inset: 50% auto auto 50%;
  width: 1.1em;
  height: 1.1em;
  margin: -0.55em 0 0 -0.55em;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  color: #fff;
  animation: btn-spinner 0.7s linear infinite;
}

/* Ghost buttons need a darker spinner colour since they sit on light bg
 * when not hovered. */
.btn--ghost.is-loading::after,
.btn--ghost-light.is-loading::after {
  color: var(--brand);
}

@keyframes btn-spinner {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .btn.is-loading::after {
    animation: none;
    /* Static partial circle reads as a loading indicator even without spin. */
    border-top-color: currentColor;
    opacity: 0.5;
  }
}

/* Header ---------------------------------------------------- */

.site-header {
  background: var(--paper);
  border-bottom: 1px solid var(--slate-200);
  position: sticky;
  top: 0;
  z-index: 50;
  backdrop-filter: saturate(150%) blur(8px);
  -webkit-backdrop-filter: saturate(150%) blur(8px);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 68px;
  gap: 1rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  text-decoration: none;
  color: var(--brand-900);
  font-weight: 800;
  font-size: 1.25rem;
  letter-spacing: -0.02em;
}

/* Text wordmark — split-colour "Kuya" + "Yos". Sharper than rendering
 * the full logo image at small sizes, and matches the brand spec. The
 * /assets/logo.png file is kept in the repo for og-image / future hero
 * usage but isn't referenced from the brand element any more. */

.brand__word {
  display: inline-flex;
  align-items: baseline;
  font-weight: 900;
  font-size: clamp(1.5rem, 0.9vw + 1.25rem, 1.85rem);
  letter-spacing: -0.025em;
  line-height: 1;
}

.brand__word-kuya {
  color: var(--brand);
}

.brand__word-yos {
  color: var(--action);
}

/* Footer override — "Kuya" reads as white on navy, "Yos" stays orange. */
.site-footer .brand__word-kuya {
  color: #fff;
}

.site-footer .brand__word-yos {
  color: var(--action);
}

/* Legacy / fallback styles kept for any old markup that still ships
 * with .brand__mark or .brand__logo. New brand markup uses
 * .brand__word with split children. */
.brand__mark,
.brand__logo {
  display: none;
}

.brand--footer {
  font-size: 1.125rem;
}

.brand--footer .brand__word {
  font-size: clamp(1.65rem, 1vw + 1.25rem, 2rem);
}

/* Nav toggle (no-JS checkbox hack) */

.nav-toggle {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.nav-toggle-label {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 42px;
  height: 42px;
  padding: 10px 9px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  border: 1px solid var(--slate-200);
  background: var(--paper);
}

.nav-toggle-bar {
  display: block;
  height: 2px;
  background: var(--brand-900);
  border-radius: 2px;
  transition: transform 0.15s ease, opacity 0.15s ease;
}

.nav-toggle:focus-visible + .nav-toggle-label {
  outline: 3px solid var(--focus-color);
  outline-offset: 2px;
}

.site-nav {
  display: none;
  position: absolute;
  /* Drops below the header content. Using 100% of the header height
   * (whatever the logo decides it should be) avoids the brittle pixel
   * value that was here before. */
  top: 100%;
  right: 0;
  left: 0;
  background: var(--paper);
  border-bottom: 2px solid var(--ink);
  padding: 1rem 1.25rem 1.25rem;
  box-shadow: 0 4px 0 0 var(--ink);
}

.nav-toggle:checked ~ .site-nav {
  display: block;
}

.site-nav__list {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.site-nav__list a {
  display: block;
  padding: 0.75rem 0.6rem;
  color: var(--ink-soft);
  text-decoration: none;
  border-radius: var(--radius-sm);
  font-weight: 600;
}

.site-nav__list a:hover {
  background: var(--slate-50);
  color: var(--brand);
}

.site-nav__list a[aria-current="page"] {
  color: var(--brand);
}

.site-nav__list .btn {
  margin-top: 0.5rem;
}

@media (min-width: 880px) {
  .nav-toggle-label {
    display: none;
  }
  .site-nav {
    display: block;
    position: static;
    padding: 0;
    border: 0;
    box-shadow: none;
    background: transparent;
  }
  .site-nav__list {
    flex-direction: row;
    gap: 0.25rem;
    align-items: center;
  }
  .site-nav__list a {
    padding: 0.55rem 0.95rem;
  }
  .site-nav__list .btn {
    margin-top: 0;
    margin-left: 0.4rem;
  }
}

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

.hero {
  position: relative;
  background: var(--brand);
  color: #fff;
  padding: 3.5rem 0 4rem;
  overflow: hidden;
  isolation: isolate;
}

.hero::before {
  /* subtle radial accent — orange glow upper-right */
  content: "";
  position: absolute;
  top: -200px;
  right: -200px;
  width: 600px;
  height: 600px;
  background: radial-gradient(closest-side, rgba(232, 119, 34, 0.28), transparent 75%);
  z-index: -1;
}

.hero::after {
  /* subtle radial accent — deeper teal lower-left */
  content: "";
  position: absolute;
  bottom: -300px;
  left: -200px;
  width: 700px;
  height: 700px;
  background: radial-gradient(closest-side, rgba(10, 47, 66, 0.6), transparent 70%);
  z-index: -1;
}

/* Skyline silhouette along the hero base. A 3-image track scrolls
   horizontally so the silhouette drifts slowly leftward. The animation
   translates the track by exactly one image width (calc(-100% / 3) of a
   3-image track), then loops — since each image is identical, the reset
   is invisible. Track holds 3 copies which covers viewports up to ~2× a
   single tile width (handles 4K). Honours prefers-reduced-motion. */
.hero__skyline {
  position: absolute;
  inset: auto 0 0 0;
  height: 140px;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
  opacity: 0.22;
}

@media (min-width: 980px) {
  .hero__skyline {
    height: 200px;
  }
}

.hero__skyline-track {
  display: flex;
  height: 100%;
  width: max-content;
  align-items: flex-end;
  animation: skyline-scroll 120s linear infinite;
  will-change: transform;
}

.hero__skyline-track img {
  height: 100%;
  width: auto;
  flex-shrink: 0;
  display: block;
}

@keyframes skyline-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(calc(-100% / 3), 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .hero__skyline-track {
    animation: none;
  }
}

.hero__inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem;
  align-items: center;
  position: relative;
  z-index: 1;
}

.hero-kicker {
  font-family: inherit;
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  color: var(--action);
  margin: 0 0 0.5rem 0;
  text-transform: none;
}

/* Hero photo slot — designed empty state. When the tradesperson uniform
 * photoshoot lands, replace the inner <p class="hero-portrait__label"> with
 * an <img src="..." alt="..."> and remove aria-hidden on .hero-portrait. */
.hero-portrait {
  margin: 1rem 0 1.25rem 0;
  max-width: 200px;
}

.hero-portrait__frame {
  aspect-ratio: 3 / 4;
  border: 1px dashed rgba(255, 255, 255, 0.35);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.04);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.75rem;
  color: rgba(255, 255, 255, 0.6);
}

.hero-portrait__label {
  margin: 0;
  font-size: 0.85rem;
  text-align: center;
  letter-spacing: 0.02em;
}

.hero-portrait__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: calc(var(--radius) - 2px);
  display: block;
}

@media (max-width: 767px) {
  .hero-portrait {
    max-width: 140px;
  }
}

.hero__copy h1 {
  color: #fff;
  margin-bottom: 1rem;
  letter-spacing: -0.025em;
  font-weight: 900;
}

.hero__copy h1 em {
  font-style: normal;
  color: var(--action);
}

.hero .lede {
  font-size: 1.125rem;
  color: rgba(255, 255, 255, 0.88);
  max-width: 56ch;
  margin-bottom: 1.5rem;
  font-weight: 400;
}

.hero__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1.25rem;
}

.hero__chips li {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.18);
  padding: 0.4rem 0.85rem;
  border-radius: var(--radius-pill);
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.92);
  font-weight: 600;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

.hero__chips li::before {
  content: "✓";
  color: var(--action);
  font-weight: 800;
}

@media (min-width: 980px) {
  .hero {
    padding: 5rem 0 6rem;
  }
  .hero__inner {
    grid-template-columns: 1.1fr 1fr;
    gap: 3.5rem;
  }
}

/* Hero starter form ----------------------------------------- */

.hero-starter {
  background: var(--paper);
  border: 2px solid var(--ink);
  border-radius: var(--radius-lg);
  padding: 1.5rem;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.85rem;
  color: var(--ink);
  position: relative;
  z-index: 1;
  /* Solid orange plate offset behind the form — same idiom as the
   * .section-docket cards (border + offset plate). Mobile uses the
   * smaller --docket-shadow token; desktop scales to --docket-shadow-lg. */
  box-shadow: var(--docket-shadow);
}

@media (min-width: 980px) {
  .hero-starter {
    box-shadow: var(--docket-shadow-lg);
  }
}

.hero-starter__lead {
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--brand);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  margin: 0 0 0.25rem;
}

.hero-starter__field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.hero-starter__field label {
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--ink-soft);
}

.hero-starter__field select {
  font-family: inherit;
  font-size: 1rem;
  font-weight: 500;
  color: var(--ink);
  padding: 0.85rem 1rem;
  border: 2px solid var(--slate-200);
  border-radius: var(--radius-sm);
  background-color: var(--paper);
  background-image:
    linear-gradient(45deg, transparent 50%, var(--brand) 50%),
    linear-gradient(-45deg, transparent 50%, var(--brand) 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 12px) 50%;
  background-size: 6px 6px;
  background-repeat: no-repeat;
  appearance: none;
  -webkit-appearance: none;
  padding-right: 2.75rem;
  min-height: 52px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  cursor: pointer;
}

.hero-starter__field select:hover {
  border-color: var(--slate-300);
}

.hero-starter__field select:focus-visible {
  outline: none;
  border-color: var(--brand);
  box-shadow: var(--focus-ring);
}

.hero-starter__submit {
  margin-top: 0.4rem;
  width: 100%;
  box-shadow: var(--docket-shadow-sm-ink);
  transition: background 0.18s ease, transform 0.12s ease, box-shadow 0.12s ease;
}

.hero-starter__submit:hover {
  transform: translate(-2px, -2px);
  box-shadow: 6px 6px 0 0 var(--ink);
}

.hero-starter__submit:active {
  transform: translate(0, 0);
  box-shadow: 2px 2px 0 0 var(--ink);
}

.hero-starter__small {
  font-size: 0.8125rem;
  color: var(--slate-500);
  margin: 0.4rem 0 0;
  text-align: center;
}

@media (min-width: 540px) {
  .hero-starter {
    padding: 2rem;
    grid-template-columns: 1fr 1fr;
    gap: 1rem 1rem;
  }
  .hero-starter__lead,
  .hero-starter__submit,
  .hero-starter__small {
    grid-column: 1 / -1;
  }
}

/* Social-proof ribbons -------------------------------------- */

.ribbon {
  background: var(--paper);
  border-top: 1px solid var(--slate-200);
  border-bottom: 1px solid var(--slate-200);
  padding: 1.75rem 0;
}

.ribbon--tinted {
  background: var(--brand-50);
  border-color: var(--brand-100);
}

.ribbon__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  text-align: center;
}

.ribbon__label {
  font-size: 0.75rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--slate-500);
  margin: 0;
}

.ribbon__logos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 1.5rem 2.5rem;
  width: 100%;
  list-style: none;
  padding: 0;
  margin: 0;
}

.ribbon__logos > li {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Press logos: re-tint each publication's mark with the brand teal so they
   harmonize with the site palette. Logos with white backgrounds get an
   alpha-cleaned PNG + brightness(0)+hue-rotate filter chain that resolves to
   roughly #1a6b8a. Inquirer's logo IS a blue rectangle (the "white" is the
   wordmark sitting on solid blue), so it's left untreated — its blue already
   sits comfortably with the teal palette. Hover restores the original
   publication colours so users can verify the source before clicking. */
.ribbon__logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem 0.75rem;
  text-decoration: none;
  border-radius: var(--radius-sm);
  transition: opacity 0.2s ease;
}

.ribbon__logo img {
  display: block;
  max-height: 38px;
  width: auto;
  height: auto;
  transition: filter 0.2s ease, opacity 0.2s ease;
}

/* Alpha-PNG logos (gritdaily-alpha.png, investing-alpha.png) — recolour the
   visible glyphs to brand teal (#1a6b8a) while keeping the surrounding
   transparency intact. */
.ribbon__logo--alpha img {
  filter: brightness(0) saturate(100%) invert(33%) sepia(76%) saturate(384%)
    hue-rotate(160deg) brightness(95%) contrast(89%);
  opacity: 0.9;
}

/* Inquirer is a self-contained blue plaque; gentle desaturate is enough. */
.ribbon__logo--inquirer img {
  filter: saturate(0.85) brightness(0.95);
  opacity: 0.85;
}

.ribbon__logo:hover img,
.ribbon__logo:focus-visible img {
  filter: none;
  opacity: 1;
}

/* "As seen on" marquee variant -------------------------------
   Same pattern as the hero skyline: a track containing 2 copies of the
   logo set, animated 0% -> -50%. The loop reset is invisible because the
   second set sits exactly where the first set started. Edges fade via
   a mask so logos enter/exit the viewport gracefully instead of popping. */
.ribbon--marquee {
  padding-block: 1.5rem;
}

.ribbon--marquee .ribbon__label {
  display: block;
  text-align: center;
  margin: 0 auto 1rem;
}

.ribbon__marquee-track {
  overflow: hidden;
  width: 100%;
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 6%, #000 94%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 6%, #000 94%, transparent 100%);
}

.ribbon--marquee .ribbon__logos {
  display: flex;
  flex-wrap: nowrap;
  width: max-content;
  gap: 3.5rem;
  align-items: center;
  justify-content: flex-start;
  animation: ribbon-scroll 35s linear infinite;
  will-change: transform;
}

.ribbon--marquee .ribbon__logos > li {
  flex-shrink: 0;
}

.ribbon__marquee-track:hover .ribbon__logos,
.ribbon__marquee-track:focus-within .ribbon__logos {
  animation-play-state: paused;
}

@keyframes ribbon-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .ribbon--marquee .ribbon__logos {
    animation: none;
  }
}

.ribbon__logo-slot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 36px;
  min-width: 110px;
  padding: 0 1rem;
  background: var(--slate-100);
  color: var(--slate-500);
  border-radius: var(--radius-sm);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.05em;
}

.ribbon__rating {
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  flex-wrap: wrap;
  justify-content: center;
}

.ribbon__stars {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  color: var(--action);
  font-size: 1.5rem;
  letter-spacing: 0.06em;
  line-height: 1;
}

.ribbon__rating-text {
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--brand-900);
}

.ribbon__rating-source {
  color: var(--slate-500);
  font-weight: 500;
}

@media (min-width: 720px) {
  .ribbon__inner {
    flex-direction: row;
    justify-content: center;
    gap: 2rem;
  }
  .ribbon__label {
    flex-shrink: 0;
  }
}

/* How it works ---------------------------------------------- */

.steps {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  counter-reset: step;
  margin-top: 1.25rem;
}

.step {
  background: var(--paper);
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  padding: 1.75rem;
  position: relative;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
  box-shadow: var(--docket-shadow);
}

.step:hover {
  transform: translate(-2px, -2px);
  box-shadow: var(--docket-shadow-lg);
}

.step__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  background: var(--brand);
  color: #fff;
  border-radius: var(--radius);
  font-weight: 900;
  font-size: 1.1rem;
  margin-bottom: 1rem;
  box-shadow: var(--shadow-sm);
}

.step:nth-child(2) .step__num {
  background: var(--action);
}

.step__title {
  margin-bottom: 0.4rem;
}

.step p {
  color: var(--ink-soft);
  margin: 0;
}

@media (min-width: 768px) {
  .steps {
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
  }
}

/* Recent jobs strip — hidden via the `hidden` attribute on the section
 * until live job photos exist. Each card slot accepts an <img> dropped
 * into .recent-job-card__photo. Styling mirrors the .step card pattern. */
.recent-jobs__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1rem;
  list-style: none;
  padding: 0;
  margin: 1.25rem 0 0 0;
}

.recent-job-card {
  background: var(--paper);
  border: 1px solid var(--slate-200);
  border-radius: var(--radius);
  overflow: hidden;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.recent-job-card__photo {
  aspect-ratio: 4 / 3;
  background: linear-gradient(135deg, var(--slate-100, #f1f5f9), var(--slate-200, #e2e8f0));
  width: 100%;
}

.recent-job-card__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.recent-job-card__caption {
  padding: 0.85rem 1rem;
  margin: 0;
  font-size: 0.95rem;
  color: var(--ink);
}

/* Footer 'Yos na. signature near the brand mark. */
.footer-signature {
  font-weight: 700;
  color: var(--action);
  font-size: 0.95rem;
  margin: 0.5rem 0 0 0;
  letter-spacing: 0.02em;
}

/* Trades ---------------------------------------------------- */

.trades {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 1.25rem;
}

/* Trade accordion — click-to-expand row per trade. Each <details> styled
 * like a paper-docket button row; clicking the summary reveals the
 * description body below via the dashed-rule separator. Matches the
 * docket vocabulary used elsewhere on the site. */
.trade-accordion {
  background: var(--docket-paper);
  border: 2px solid var(--ink);
  border-radius: 6px;
  overflow: hidden;
  transition: box-shadow 0.18s ease, transform 0.18s ease;
}

.trade-accordion:hover {
  transform: translateY(-1px);
  box-shadow: 0 3px 0 0 var(--ink);
}

.trade-accordion__summary {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.85rem 1rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
  background: rgba(232, 119, 34, 0.04);
  transition: background 0.18s ease;
}

.trade-accordion__summary::-webkit-details-marker { display: none; }
.trade-accordion__summary::marker { content: ""; }

.trade-accordion__summary:hover {
  background: rgba(232, 119, 34, 0.10);
}

.trade-accordion[open] .trade-accordion__summary {
  background: rgba(232, 119, 34, 0.14);
  border-bottom: 1px dashed var(--docket-rule);
}

.trade-accordion__icon {
  display: inline-flex;
  flex-shrink: 0;
  color: var(--brand);
  line-height: 0;
}

.trade-accordion__icon svg {
  fill: currentColor;
}

.trade-accordion__name {
  margin: 0;
  flex-grow: 1;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.95rem;
  font-weight: 800;
  color: var(--ink);
}

.trade-accordion__chevron {
  width: 0.55rem;
  height: 0.55rem;
  border-right: 2px solid var(--ink);
  border-bottom: 2px solid var(--ink);
  transform: rotate(45deg);
  margin-right: 0.4rem;
  margin-top: -0.2rem;
  transition: transform 0.2s ease;
  flex-shrink: 0;
}

.trade-accordion[open] .trade-accordion__chevron {
  transform: rotate(-135deg);
  margin-top: 0.2rem;
}

.trade-accordion__body {
  padding: 0.85rem 1rem 1rem;
  color: var(--ink-soft);
}

.trade-accordion__body p {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.5;
}

.trade-accordion__summary:focus-visible {
  outline: 3px solid var(--action);
  outline-offset: -3px;
}

.trade-card {
  background: var(--paper);
  border: 1px solid var(--slate-200);
  border-radius: 1rem;
  corner-shape: bevel;
  padding: 1.25rem;
  transition: transform 0.18s ease, box-shadow 0.18s ease, filter 0.18s ease, border-color 0.18s ease;
}

.trade-card:nth-child(odd) {
  box-shadow: 10px 10px 5px  rgba(26, 107, 138, 0.2);
}

.trade-card:nth-child(even) {
  box-shadow: 10px 10px 5px  rgba(232, 119, 34, 0.25);
}

.trade-card:hover {
  transform: translateY(-2px);
  border-color: var(--slate-300);
}

.trade-card:nth-child(odd):hover {
  box-shadow: 0 22px 48px -14px rgba(26, 107, 138, 0.65);
}

.trade-card:nth-child(even):hover {
  box-shadow: 0 22px 48px -14px rgba(232, 119, 34, 0.65);
}

.trade-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 0.625rem;
  corner-shape: bevel;
  background: var(--brand-50);
  color: var(--brand);
  margin-bottom: 0.85rem;
}

/* Octagon fallback for browsers that don't support corner-shape yet.
   shape() outline + drop-shadow because clip-path defeats box-shadow. */
@supports not (corner-shape: bevel) {
  @supports (clip-path: shape(from 0 0, line to 0 0, close)) {
    .trade-card {
      border-radius: 0;
      border: 0;
      box-shadow: none;
      clip-path: shape(
        from 1rem 0,
        line to calc(100% - 1rem) 0,
        line to 100% 1rem,
        line to 100% calc(100% - 1rem),
        line to calc(100% - 1rem) 100%,
        line to 1rem 100%,
        line to 0 calc(100% - 1rem),
        line to 0 1rem,
        close
      );
    }
    .trade-card:nth-child(odd) {
      box-shadow: none;
      filter: drop-shadow(0 12px 22px rgba(26, 107, 138, 0.5));
    }
    .trade-card:nth-child(even) {
      box-shadow: none;
      filter: drop-shadow(0 12px 22px rgba(232, 119, 34, 0.5));
    }
    .trade-card:nth-child(odd):hover {
      box-shadow: none;
      filter: drop-shadow(0 18px 32px rgba(26, 107, 138, 0.65));
    }
    .trade-card:nth-child(even):hover {
      box-shadow: none;
      filter: drop-shadow(0 18px 32px rgba(232, 119, 34, 0.65));
    }
    .trade-card__icon {
      border-radius: 0;
      clip-path: shape(
        from 0.625rem 0,
        line to calc(100% - 0.625rem) 0,
        line to 100% 0.625rem,
        line to 100% calc(100% - 0.625rem),
        line to calc(100% - 0.625rem) 100%,
        line to 0.625rem 100%,
        line to 0 calc(100% - 0.625rem),
        line to 0 0.625rem,
        close
      );
    }
  }
}

.trade-card h3 {
  margin-bottom: 0.35rem;
}

.trade-card p {
  color: var(--ink-soft);
  font-size: 0.9375rem;
  margin: 0;
}
/* Mobile dropdown for the trades grid. Markup is <details open> by default so
 * it works without JS. A small inline script in index.html removes `open` on
 * viewports < 768px so users tap to expand. Desktop hides the <summary>. */

.trades-toggle {
  margin-top: 1.25rem;
}

.trades-toggle .trades {
  margin-top: 0.85rem;
}

.trades-toggle__summary {
  list-style: none;
  cursor: pointer;
  padding: 0.95rem 1.15rem;
  background: var(--paper);
  border: 1px solid var(--slate-200);
  border-radius: var(--radius);
  font-weight: 700;
  color: var(--brand-900);
  font-size: 1rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.trades-toggle__summary::-webkit-details-marker {
  display: none;
}

.trades-toggle__summary::after {
  content: "";
  width: 11px;
  height: 11px;
  border-right: 2px solid var(--brand);
  border-bottom: 2px solid var(--brand);
  transform: rotate(45deg);
  transition: transform 0.18s ease;
  flex-shrink: 0;
}

.trades-toggle[open] .trades-toggle__summary::after {
  transform: rotate(-135deg);
}

.trades-toggle__summary:hover {
  background: var(--brand-50);
  border-color: var(--brand-100);
}

.trades-toggle__summary:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

@media (min-width: 768px) {
  .trades-toggle__summary {
    display: none;
  }
  .trades-toggle .trades {
    margin-top: 1.25rem;
  }
}

/* CTA repeat (dual button) ---------------------------------- */

.cta-repeat {
  /* Section frame stays brand teal so the cream docket card inside pops
   * against the dark surround with strong contrast. The docket card and its
   * contents (H2, paragraph, ghost-light button) are styled below to read as
   * cream paper with dark text, matching the .step cards higher on the page. */
  background: var(--brand);
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.cta-repeat::before {
  content: "";
  position: absolute;
  top: -250px;
  right: -150px;
  width: 600px;
  height: 600px;
  background: radial-gradient(closest-side, rgba(232, 119, 34, 0.22), transparent 75%);
  z-index: -1;
}

.cta-repeat__inner {
  text-align: center;
  position: relative;
}

.cta-repeat h2 {
  margin-bottom: 0.6rem;
}

.cta-repeat p {
  color: var(--ink-soft);
  font-size: 1.0625rem;
  max-width: 52ch;
  margin: 0 auto 1.5rem;
}

.cta-repeat__buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  justify-content: center;
  align-items: center;
}

/* FAQ (used on /faq/ page) ---------------------------------- */

.faq {
  background: var(--paper);
  border: 1px solid var(--slate-200);
  border-radius: var(--radius);
  margin-bottom: 0.75rem;
  overflow: hidden;
  transition: border-color 0.15s ease;
}

.faq[open] {
  border-color: var(--brand-100);
}

.faq summary {
  list-style: none;
  cursor: pointer;
  padding: 1.1rem 1.4rem;
  font-weight: 700;
  color: var(--brand-900);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  font-size: 1.0625rem;
}

.faq summary::-webkit-details-marker {
  display: none;
}

.faq summary::after {
  content: "";
  width: 11px;
  height: 11px;
  border-right: 2px solid var(--brand);
  border-bottom: 2px solid var(--brand);
  transform: rotate(45deg);
  transition: transform 0.18s ease;
  flex-shrink: 0;
}

.faq[open] summary::after {
  transform: rotate(-135deg);
}

.faq summary:hover {
  background: var(--brand-50);
}

.faq__body {
  padding: 0 1.4rem 1.3rem;
  color: var(--ink-soft);
}

.faq__body p {
  margin: 0;
}

/* FAQ closing sign-off — appears once after the last accordion. */
.faq-signoff {
  margin-top: 1.5rem;
  padding: 1rem 1.25rem;
  background: var(--paper);
  border-left: 3px solid var(--action);
  border-radius: var(--radius);
  font-size: 0.98rem;
}

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

.site-footer {
  background: var(--brand-900);
  color: rgba(255, 255, 255, 0.84);
  padding: 3.5rem 0 1.5rem;
  margin-top: 0;
}

.site-footer a {
  color: rgba(255, 255, 255, 0.84);
  text-decoration: none;
  transition: color 0.15s ease;
}

.site-footer a:hover {
  color: var(--action);
}

.site-footer .brand,
.site-footer .brand__word {
  color: #fff;
}

.site-footer .brand__mark {
  background: var(--action);
}

.site-footer .brand__mark::after {
  background: var(--brand-50);
}

.site-footer .muted {
  color: rgba(255, 255, 255, 0.6);
}

.site-footer__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.25rem;
}

@media (min-width: 768px) {
  .site-footer__grid {
    /* Five columns on desktop: brand+tagline | NAP | For customers | Follow us
     * | For tradespeople. The two info columns (brand, NAP) get slightly
     * wider tracks because their content wraps; the three nav columns are
     * uniform. On tablet (768–979px) columns are tighter; mobile stacks. */
    grid-template-columns: 1.2fr 1.4fr 1fr 1fr 1fr;
    gap: 2rem;
  }
}

@media (min-width: 980px) {
  .site-footer__grid {
    gap: 2.5rem;
  }
}

.nap p {
  margin: 0 0 0.25rem;
  font-style: normal;
}

.footer-nav__title {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: rgba(255, 255, 255, 0.55);
  margin: 0 0 0.85rem;
  font-weight: 800;
}

.footer-nav ul,
.footer-social ul {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.site-footer__base {
  margin-top: 2.75rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.site-footer__base p {
  margin: 0;
}

.site-footer__base a {
  font-size: 0.9rem;
}

/* Cookie banner — appended to the bottom of every page on first visit by
 * js/cookie-banner.js, dismissed by clicking OK, persistence via
 * localStorage. Uses the docket vocabulary (cream paper + 2px ink edge +
 * hard ink offset) so it reads as part of the same visual system. */
.cookie-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  background: var(--docket-paper);
  border-top: 2px solid var(--ink);
  box-shadow: 0 -4px 0 0 var(--ink);
  padding: 0.95rem 0 1.05rem;
}

.cookie-banner__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
}

.cookie-banner__text {
  margin: 0;
  font-size: 0.92rem;
  color: var(--ink);
  max-width: 64ch;
  line-height: 1.45;
}

.cookie-banner__text a {
  color: var(--brand);
  font-weight: 700;
}

.cookie-banner__text a:hover {
  color: var(--action);
}

.cookie-banner__ok {
  flex-shrink: 0;
  background: var(--action);
  color: #fff;
  border: 2px solid transparent;
}

.cookie-banner__ok:hover {
  background: var(--action-700);
}

.cookie-banner__ok:focus-visible {
  outline: 3px solid var(--focus-color);
  outline-offset: 2px;
}

/* Inline legal links row in the footer base (Privacy · Terms). Sits next to
 * the copyright line with thin separators between items. Keeps to the muted
 * footer-fineprint vocabulary so it doesn't compete with the main footer-nav. */
.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.9rem;
}

.site-footer__legal li {
  position: relative;
}

.site-footer__legal li + li::before {
  content: "·";
  position: absolute;
  left: -0.6rem;
  top: 50%;
  transform: translateY(-50%);
  color: rgba(255, 255, 255, 0.35);
}

.site-footer__legal a[aria-current="page"] {
  color: var(--action);
}

/* Long-form prose inside a .section-docket.docket-prose — h2/h3 spacing,
 * code pill styling for inline filenames (e.g. /book/, /apply/), and
 * tighter list indentation. SCOPED to the .docket-prose modifier so the
 * homepage steps, FAQ accordions, pricing tables, etc. don't inherit
 * decimal list numbering or other prose-only treatments. Add the
 * `docket-prose` class to any .section-docket dominated by paragraphs and
 * numbered / bulleted lists (about, privacy, terms, future policy pages). */
.section-docket.docket-prose h2 {
  margin-top: 2rem;
  margin-bottom: 0.65rem;
  font-size: 1.35rem;
  letter-spacing: -0.01em;
}

.section-docket.docket-prose h2:first-of-type {
  margin-top: 1rem;
}

.section-docket.docket-prose h3 {
  margin-top: 1.25rem;
  margin-bottom: 0.4rem;
  font-size: 1.05rem;
  font-weight: 800;
  color: var(--brand-900);
}

.section-docket.docket-prose > p,
.section-docket.docket-prose > ul > li,
.section-docket.docket-prose > ol > li {
  color: var(--ink-soft);
  line-height: 1.6;
}

.section-docket.docket-prose > ul,
.section-docket.docket-prose > ol {
  margin: 0 0 1rem;
  padding-left: 1.25rem;
}

.section-docket.docket-prose > ul {
  list-style: disc;
}

.section-docket.docket-prose > ol {
  list-style: decimal;
}

.section-docket.docket-prose > ul > li,
.section-docket.docket-prose > ol > li {
  margin-bottom: 0.4rem;
}

.section-docket.docket-prose code {
  font-family: var(--docket-mono);
  font-size: 0.92em;
  background: rgba(232, 119, 34, 0.10);
  border: 1px solid rgba(232, 119, 34, 0.35);
  padding: 0.05em 0.4em;
  color: var(--ink);
}

.section-docket.docket-prose strong {
  color: var(--ink);
}

/* "Who we serve" — three audience cards (households, SMEs, HoA collectives).
 * Cream paper docket cards in a 3-column grid on desktop, stacked on
 * mobile. Each card has a stamp label, headline, benefits list, and a
 * contextual CTA — either a direct booking button or a multi-channel
 * contact strip (Messenger / Email / Viber) for contract discussions. */
.who-we-serve {
  padding: 4rem 0;
}

.serve-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
  margin-top: 1.5rem;
  list-style: none;
  padding: 0;
}

@media (min-width: 880px) {
  .serve-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 1.75rem;
  }
}

.serve-card {
  background: var(--docket-paper);
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  padding: 1.5rem 1.5rem 1.75rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  position: relative;
  box-shadow: var(--docket-shadow);
  background-image: repeating-linear-gradient(
    0deg,
    transparent 0 1.5rem,
    rgba(21, 41, 99, 0.04) 1.5rem calc(1.5rem + 1px)
  );
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.serve-card:hover {
  transform: translate(-2px, -2px);
  box-shadow: var(--docket-shadow-lg);
}

.serve-card .section-stamp {
  align-self: flex-start;
}

.serve-card h3 {
  margin: 0;
  font-size: 1.2rem;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.serve-card__benefits {
  margin: 0;
  padding-left: 1.15rem;
  list-style: disc;
  color: var(--ink-soft);
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  flex-grow: 1;
}

.serve-card__benefits li {
  line-height: 1.5;
  font-size: 0.95rem;
}

.serve-card__cta {
  margin-top: auto;
  padding-top: 0.85rem;
  border-top: 1px dashed var(--docket-rule);
}

.serve-card__cta .btn {
  width: 100%;
}

.serve-card__cta-lead {
  font-family: var(--docket-mono);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-soft);
  margin: 0 0 0.55rem;
  font-weight: 700;
}

.serve-card__channels {
  display: flex;
  flex-wrap: wrap;
  gap: 0.95rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.serve-card__channels li {
  position: relative;
}

.serve-card__channels li + li::before {
  content: "·";
  position: absolute;
  left: -0.65rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--docket-rule);
}

.serve-card__channels a {
  color: var(--brand);
  font-weight: 700;
  text-decoration: none;
  font-size: 0.95rem;
}

.serve-card__channels a:hover {
  text-decoration: underline;
  color: var(--action);
}


/* Form page header auto-hide -------------------------------- */
.form-header-autohide .site-header {
  transition: transform 0.22s ease, box-shadow 0.22s ease;
  will-change: transform;
}

.form-header-autohide.form-header-is-hidden .site-header {
  transform: translateY(-100%);
  box-shadow: none;
}

.form-header-autohide:has(.nav-toggle:checked) .site-header {
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .form-header-autohide .site-header {
    transition: none;
  }
}

/* Selection + high-contrast --------------------------------- */

::selection {
  background: var(--action);
  color: #fff;
}

@media (prefers-contrast: more) {
  .trade-card,
  .step,
  .faq {
    border-color: var(--ink-soft);
  }
}
/* Trades dropdown fix:
   desktop = always visible,
   mobile = closed by default unless tapped open */
@media (min-width: 768px) {
  #trades details.trades-toggle {
    display: block;
  }

  #trades details.trades-toggle > summary.trades-toggle__summary {
    display: none !important;
  }

  #trades details.trades-toggle > ul.trades,
  #trades details.trades-toggle:not([open]) > ul.trades,
  #trades details.trades-toggle[open] > ul.trades {
    display: grid !important;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0.85rem;
    margin-top: 1.25rem;
    visibility: visible !important;
    opacity: 1 !important;
    height: auto !important;
    max-height: none !important;
    overflow: visible !important;
  }
}

@media (max-width: 767px) {
  #trades details.trades-toggle > summary.trades-toggle__summary {
    display: flex !important;
  }

  #trades details.trades-toggle:not([open]) > ul.trades {
    display: none !important;
  }

  #trades details.trades-toggle[open] > ul.trades {
    display: grid !important;
  }
}


/* === KuyaYos trades dropdown final fix START === */
/* Desktop = jobs always visible.
   Mobile = closed by default; opens when the Browse all trades details is tapped. */

@media (min-width: 768px) {
  #trades .trades-toggle {
    display: none !important;
  }

  #trades ul.trades {
    display: grid !important;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0.85rem;
    margin-top: 1.25rem;
    visibility: visible !important;
    opacity: 1 !important;
    height: auto !important;
    max-height: none !important;
    overflow: visible !important;
  }
}

@media (max-width: 767px) {
  #trades .trades-toggle {
    display: block !important;
    margin-top: 1.25rem;
  }

  #trades .trades-toggle__summary {
    display: flex !important;
  }

  #trades .trades-toggle:not([open]) + ul.trades {
    display: none !important;
  }

  #trades .trades-toggle[open] + ul.trades {
    display: grid !important;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0.85rem;
    margin-top: 0.85rem;
  }
}
/* === KuyaYos trades dropdown final fix END === */

/* Homepage entrance animation — polaroid-develop on the hero
 * starter form. Pure CSS so nothing needs to clear the strict
 * CSP. Scoped to body.home so /book/, /apply/, /faq/, /pricing/
 * still paint statically. Final box-shadow state is inherited
 * from the element's natural CSS; the keyframe only defines the
 * `from` snapshot so the animation just blends in.
 */

/* Develop-in keyframes animate position/opacity/blur only. Box-shadow is
 * deliberately omitted so the element's natural hard docket-shadow stays
 * in place throughout the animation (no soft→hard tween). */
@keyframes kuyayos-polaroid-develop {
  from {
    opacity: 0.90;
    filter: blur(1.5px);
    transform: translateX(100%);
  }
}

@keyframes kuyayos-polaroid-develop-reverse {
  from {
    opacity: 0.90;
    filter: blur(1.5px);
    transform: translateX(-100%);
  }
}

/* Homepage surface tint — shifted to a subtle cool-off-white that leans
 * toward the brand teal at very low chroma. Replaces the previous warm
 * cream (#fcf8f1) which read as the 2026 AI-landing-page paper-on-paper
 * default. The docket cards retain their warm --docket-paper, so body
 * vs card now reads as a deliberate cool-vs-warm contrast (screen vs
 * carbon-copy paper) instead of two flavours of cream. Token name kept
 * as --paper-warm for back-compat with downstream local assets. */
body.home {
  --paper-warm: #f3f6f8;
  background-color: var(--paper-warm);
}

/* The hero-starter's 2px ink border (defined in the base .hero-starter
 * rule above) is now inherited unchanged on the homepage — no override
 * needed to keep it consistent with the rest of the docket system. */

/* Docket-style section wrapper — pulls the /book/ aesthetic onto homepage,
 * FAQ, and pricing content sections. Cream paper card with dark ink border,
 * faint horizontal graph-paper texture, a soft offset shadow, and a
 * perforated tab at the top-left. Used wherever the `.section-docket`
 * class is applied; styles below cover all pages. */
.section-docket {
  background: var(--docket-paper);
  border: 2px solid var(--ink);
  border-radius: 6px;
  padding: 1.75rem 1.25rem 2rem;
  position: relative;
  /* box-shadow defined below in the docket-shadow propagation block so
   * the entire system stays consistent — orange plate + soft drop. */
  background-image: repeating-linear-gradient(
    0deg,
    transparent 0 1.75rem,
    rgba(21, 41, 99, 0.04) 1.75rem calc(1.75rem + 1px)
  );
}

@media (min-width: 640px) {
  .section-docket {
    padding: 2rem 2rem 2.5rem;
  }
}

/* Perforated tab at the top-left of the docket. */
.section-docket::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 1.5rem;
  width: 3rem;
  height: 0.5rem;
  background: var(--ink);
  border-radius: 0 0 4px 4px;
}

/* Docket header row — heading + stamp aligned across, dashed-rule below. */
.section-docket__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}

.section-docket__head h2 {
  margin: 0;
}

.section-docket__rule {
  border: 0;
  border-top: 1px dashed var(--docket-rule);
  margin: 1.25rem 0 1.5rem;
}

/* Stamp — orange-bordered tracked uppercase label. Sits flush (not rotated)
 * to keep the docket aesthetic readable rather than playful. */
.section-stamp {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  padding: 0.5rem 0.85rem;
  border: 2px solid var(--action);
  border-radius: var(--radius);
  color: var(--brand-900, var(--ink));
  background: rgba(232, 119, 34, 0.08);
  line-height: 1;
  flex-shrink: 0;
}

.section-stamp__num {
  font-weight: 800;
  font-size: 0.95rem;
  letter-spacing: 0.08em;
  font-family: var(--docket-mono);
}

.section-stamp__label {
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 0.7rem;
}

/* CTA docket: light-theme button override so the ghost-light secondary
 * button (designed for dark backgrounds) reads correctly on the cream
 * docket paper. Mirrors the .btn--ghost styling (dark border + dark text). */
.cta-repeat .btn--ghost-light {
  background: transparent;
  color: var(--brand);
  border-color: var(--brand);
}

.cta-repeat .btn--ghost-light:hover {
  background: var(--brand);
  color: #fff;
  border-color: var(--brand);
}

/* Step numbers — within body.home, swap solid teal squares for the
 * dashed-circle mono-font pill style from the booking page's steps-track.
 * Keeps the existing .step card layout intact; only the number badge changes. */
body.home .step__num {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--docket-paper);
  border: 2px dashed var(--docket-rule);
  color: var(--ink);
  font-family: var(--docket-mono);
  font-size: 0.9rem;
  font-weight: 700;
  box-shadow: none;
  margin-bottom: 1rem;
}

body.home .step:nth-child(2) .step__num {
  background: var(--docket-paper);
}

/* Docket-shadow application — site-wide.
 *
 *   1. Header "Book a tradesman" button — uses the ink variant because
 *      the button is itself orange; an orange plate would disappear into
 *      the button colour.
 *   2. .section-docket cream-paper cards (How it works, Ready when you
 *      are, FAQ, Pricing, Privacy, Terms, About) — get the orange-plate
 *      + soft-drop treatment.
 */

.section-docket {
  box-shadow: var(--docket-shadow-lg);
}

@media (max-width: 640px) {
  .section-docket {
    box-shadow: var(--docket-shadow);
  }
}

.site-header .btn--primary {
  box-shadow: var(--docket-shadow-sm-ink);
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease, transform 0.12s ease, box-shadow 0.12s ease;
}

.site-header .btn--primary:hover {
  transform: translate(-2px, -2px);
  box-shadow: 6px 6px 0 0 var(--ink);
}

.site-header .btn--primary:active {
  transform: translate(0, 0);
  box-shadow: 2px 2px 0 0 var(--ink);
}

/* Header nav button — restore white text. The .site-nav__list a rule
 * (color: var(--ink-soft)) wins by specificity over .btn--primary's
 * color: #fff, so primary buttons inside the nav need an explicit
 * white-text override to stay consistent with other orange CTAs. */
.site-nav__list a.btn--primary,
.site-nav__list a.btn--primary:hover,
.site-nav__list a.btn--primary:focus,
.site-nav__list a.btn--primary:active {
  color: #fff;
}

/* Section heading row — flex container that pairs an H2 with a section
 * stamp on the right. Used on sections that don't need a full docket
 * wrapper but still want the stamp accent. */
.section-heading-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}

.section-heading-row h2 {
  margin: 0;
}

/* Trade cards as mini-dockets — paper card with dark ink border, soft
 * offset shadow, faint graph-paper texture, slight rotate on hover.
 * Scoped to body.home only because the pricing page's trade tabs have
 * their own visual treatment that shouldn't be overridden. */
body.home .trade-card {
  background: var(--docket-paper);
  border: 2px solid var(--ink);
  border-radius: 6px;
  box-shadow: 0 2px 0 0 var(--ink);
  background-image: repeating-linear-gradient(
    0deg,
    transparent 0 1.5rem,
    rgba(21, 41, 99, 0.04) 1.5rem calc(1.5rem + 1px)
  );
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}

body.home .trade-card:hover {
  transform: translateY(-2px) rotate(-0.3deg);
  box-shadow: 0 4px 0 0 var(--ink);
}

body.home .trade-card h3 {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 1rem;
  font-weight: 800;
}

/* CTA docket inner layout — left-align the heading row and the buttons.
 * `.cta-repeat__inner` is normally centred for the default CTA layout, but
 * inside a docket the heading should align with the stamp on the right and
 * the buttons should sit left-anchored. */
.cta-repeat .section-docket {
  text-align: left;
}

.cta-repeat .section-docket .cta-repeat__buttons {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-top: 0.5rem;
  justify-content: flex-start;
}

/* Move 4 — Hero trust chips as orange-bordered slightly-rotated stamps.
 * Stays on the brand teal hero background; the chips read as tactile docket
 * stamps rather than soft pills. */
body.home .hero__chips {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  list-style: none;
  padding: 0;
  margin: 1rem 0 0;
}

body.home .hero__chips li {
  display: inline-flex;
  align-items: center;
  padding: 0.45rem 0.75rem;
  border: 2px solid var(--action);
  border-radius: var(--radius);
  color: #fff;
  background: rgba(232, 119, 34, 0.12);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.72rem;
  line-height: 1;
  font-family: var(--docket-mono);
}

body.home .hero__chips li::before {
  content: none;
}

/* Hero chips rendered straight (no rotation) per design decision —
 * the docket vocabulary stays via orange border + uppercase mono font,
 * but the slant is dropped because they read cleaner straight. */

@media {
  body.home .hero-starter {
    animation: kuyayos-polaroid-develop 1.4s cubic-bezier(0.34, 1.56, 0.64, 1) 0s backwards;
    /* No box-shadow override — the carbon-copy ::before/::after layers
     * defined in the base .hero-starter rule are the form's shadow effect. */
  }

  /* Hero copy slides in from the opposite side, staggered top-to-bottom
   * so the eye is led down the column while the form arrives from the
   * right. `backwards` fill-mode keeps each element hidden during its
   * pre-roll delay (otherwise they'd flash visible before sliding). */
  body.home .hero__copy .eyebrow {
    animation: kuyayos-polaroid-develop-reverse 1.0s cubic-bezier(0.34, 1.56, 0.64, 1) 0.05s backwards;
  }
  body.home .hero__copy h1 {
    animation: kuyayos-polaroid-develop-reverse 1.0s cubic-bezier(0.34, 1.56, 0.64, 1) 0.2s backwards;
  }
  body.home .hero__copy .lede {
    animation: kuyayos-polaroid-develop-reverse 1.0s cubic-bezier(0.34, 1.56, 0.64, 1) 0.4s backwards;
  }
  body.home .hero__copy .hero__chips {
    animation: kuyayos-polaroid-develop-reverse 1.0s cubic-bezier(0.34, 1.56, 0.64, 1) 0.55s backwards;
  }
}

/* Service-page "How a KuyaYos X helps" — non-sequential examples.
 *
 * Previously rendered as numbered .steps cards (1/2/3), which read as a
 * sequence. The three items are actually independent examples, not steps,
 * so the numbers were AI scaffolding (per impeccable's "numbered eyebrows
 * on every section is AI grammar"). New .examples grid keeps the rhythm
 * but drops the numerals. Each card leans on a strong h3 plus a clear
 * problem statement; the visual differentiation comes from typography and
 * a small leading accent rule, not a chip.
 */
.examples {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.example {
  position: relative;
  padding: 1.25rem 1.25rem 1.4rem;
  background: var(--docket-paper);
  border: 2px solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--docket-shadow-sm);
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1),
              box-shadow 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}

.example:hover {
  transform: translate(-2px, -2px);
  box-shadow: var(--docket-shadow);
}

/* A small leading orange rule above the headline — replaces the numbered
 * chip. Same accent colour, no implication of order. */
.example::before {
  content: "";
  display: block;
  width: 32px;
  height: 3px;
  background: var(--action);
  margin-bottom: 0.85rem;
  border-radius: 1.5px;
}

.example__title {
  margin: 0 0 0.5rem;
  font-size: 1.05rem;
  line-height: 1.3;
  color: var(--brand-900);
  letter-spacing: -0.012em;
}

.example p {
  margin: 0;
  color: var(--ink-soft);
  line-height: 1.55;
  font-size: 0.97rem;
}

/* Page-level loading spinner — reserved for cases where a whole region
 * is waiting on a network response. Form-submit spinners are scoped
 * inside .btn.is-loading (see Buttons section). This spinner is a
 * standalone component that callers can drop in. */
.spinner {
  display: inline-block;
  width: 2.25rem;
  height: 2.25rem;
  border: 3px solid var(--slate-200);
  border-top-color: var(--brand);
  border-radius: 50%;
  animation: spinner-rotate 0.8s linear infinite;
}

.spinner--sm { width: 1rem; height: 1rem; border-width: 2px; }
.spinner--lg { width: 3rem; height: 3rem; border-width: 4px; }

.spinner--action { border-top-color: var(--action); }
.spinner--inverse {
  border-color: rgba(255, 255, 255, 0.25);
  border-top-color: #fff;
}

@keyframes spinner-rotate {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
    /* Static circle reads as "loading" even without motion. */
    border-color: var(--slate-300);
    border-top-color: var(--brand);
    opacity: 0.7;
  }
}

/* Loading overlay — covers a form or panel during a long-running action.
 * Lives inside a position: relative parent. Keeps the underlying content
 * scannable but disabled so users can read the form while it's submitting. */
.is-loading-overlay {
  position: relative;
}

.is-loading-overlay::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.55);
  backdrop-filter: blur(1px);
  -webkit-backdrop-filter: blur(1px);
  z-index: 1;
  pointer-events: all;
  cursor: progress;
}

/* === Scroll-triggered reveal system ============================================
 *
 * Elements marked `data-reveal` start hidden (opacity 0, slightly offset). When
 * IntersectionObserver detects them entering the viewport it adds `.is-visible`,
 * which triggers a one-shot keyframe animation. Keyframes are used instead of
 * transitions so the element's existing `transition` declarations (hover lifts,
 * etc.) are not overridden. `forwards` fill-mode locks the revealed state.
 *
 * Direction variants:
 *   [data-reveal]            — default: rises up (translateY 24px → 0)
 *   [data-reveal="left"]     — slides from the left
 *   [data-reveal="right"]    — slides from the right
 *
 * Mobile trades note: trade cards live inside a closed <details> on mobile, so
 * they have no layout box until the user opens the dropdown. IntersectionObserver
 * does not fire for display:none elements; when the user toggles the dropdown
 * open the cards gain a box, IO recomputes intersection, the callback fires,
 * and the cards cascade in (stagger via nth-child below). The prefers-reduced-
 * motion media query at the top of this file neutralises the animation entirely.
 */

/* Reveal-gating fix (P0 from the 2026-06 impeccable audit).
 *
 * Previously [data-reveal] defaulted to opacity:0, which meant any
 * JS-load failure (slow network, CSP block, blocker plugin) left
 * dozens of elements permanently invisible — a real risk for headless
 * renderers (Lighthouse, social-card scrapers) and JS-disabled users.
 *
 * New behaviour: default is VISIBLE. js/reveal.js adds .is-armed to
 * elements that are below the fold when the script runs; only those
 * elements get hidden and then animated in. Above-the-fold elements
 * stay visible from first paint, so there is no flash. If the script
 * never runs, every [data-reveal] just stays visible. No invisible
 * content failure modes. */
[data-reveal] {
  /* Default state: visible. Do not hide here. */
}

[data-reveal].is-armed {
  opacity: 0;
  transform: translateY(24px);
  /* will-change is scoped to ARMED elements only, not the universal
   * [data-reveal] hint that was triggering 50+ GPU layers per page. */
  will-change: opacity, transform;
}
[data-reveal="left"].is-armed  { transform: translateX(-32px); }
[data-reveal="right"].is-armed { transform: translateX(32px); }
[data-reveal="scale"].is-armed { opacity: 0; transform: scale(0.96); }
[data-reveal="rise"].is-armed  { opacity: 0; transform: translateY(40px) scale(0.98); }

@keyframes kuyayos-reveal-up {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: none; }
}
@keyframes kuyayos-reveal-left {
  from { opacity: 0; transform: translateX(-32px); }
  to   { opacity: 1; transform: none; }
}
@keyframes kuyayos-reveal-right {
  from { opacity: 0; transform: translateX(32px); }
  to   { opacity: 1; transform: none; }
}
/* Scale variant: cards rise into focus instead of sliding up. Used for
 * .trade-accordion, .serve-card, and .example.problem cards so each
 * group has its own entrance signature. */
@keyframes kuyayos-reveal-scale {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: none; }
}
@keyframes kuyayos-reveal-rise {
  from { opacity: 0; transform: translateY(40px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}

/* Animation runs on .is-visible. Curve is ease-out-expo (smooth, no
 * overshoot) per impeccable's motion rules ("No bounce, no elastic"). */
[data-reveal].is-visible            { animation: kuyayos-reveal-up    0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
[data-reveal="left"].is-visible     { animation: kuyayos-reveal-left  0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
[data-reveal="right"].is-visible    { animation: kuyayos-reveal-right 0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
[data-reveal="scale"].is-visible    { animation: kuyayos-reveal-scale 0.55s cubic-bezier(0.16, 1, 0.3, 1) forwards; }
[data-reveal="rise"].is-visible     { animation: kuyayos-reveal-rise  0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards; }

/* Per-section motion treatments. The audit flagged "uniform reflex" —
 * every section was using the same fade-up. Now reveals are shaped by
 * the content they reveal: trade cards scale-in (interactive containers
 * inviting a click), serve cards rise (heavier, magazine-cover-style),
 * FAQ details fade in faster (lighter, conversational). */
.trades > .trade-accordion[data-reveal].is-armed {
  opacity: 0;
  transform: scale(0.96);
}
.trades > .trade-accordion[data-reveal].is-visible {
  animation: kuyayos-reveal-scale 0.5s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

.serve-grid > .serve-card[data-reveal].is-armed {
  opacity: 0;
  transform: translateY(28px) scale(0.985);
}
.serve-grid > .serve-card[data-reveal].is-visible {
  animation: kuyayos-reveal-rise 0.65s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

details.faq[data-reveal].is-armed,
details.trade-accordion[data-reveal].is-armed {
  opacity: 0;
  transform: translateY(12px);
}
details.faq[data-reveal].is-visible,
details.trade-accordion[data-reveal].is-visible {
  animation: kuyayos-reveal-up 0.45s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

/* Per-group cascades — staggered animation-delay so neighbouring items don't
 * land at the same instant. The delay applies on top of the IO trigger moment;
 * for clusters that enter the viewport together (e.g. a grid of trade cards
 * on desktop, or all the cards appearing at once when the mobile dropdown
 * opens) this produces a cascade rather than a synchronised pop. */
.steps .step[data-reveal]:nth-child(1).is-visible { animation-delay: 0s;    }
.steps .step[data-reveal]:nth-child(2).is-visible { animation-delay: 0.12s; }
.steps .step[data-reveal]:nth-child(3).is-visible { animation-delay: 0.24s; }

.trades > [data-reveal]:nth-child(1).is-visible  { animation-delay: 0s;    }
.trades > [data-reveal]:nth-child(2).is-visible  { animation-delay: 0.06s; }
.trades > [data-reveal]:nth-child(3).is-visible  { animation-delay: 0.12s; }
.trades > [data-reveal]:nth-child(4).is-visible  { animation-delay: 0.18s; }
.trades > [data-reveal]:nth-child(5).is-visible  { animation-delay: 0.24s; }
.trades > [data-reveal]:nth-child(6).is-visible  { animation-delay: 0.30s; }
.trades > [data-reveal]:nth-child(7).is-visible  { animation-delay: 0.36s; }
.trades > [data-reveal]:nth-child(8).is-visible  { animation-delay: 0.42s; }
.trades > [data-reveal]:nth-child(9).is-visible  { animation-delay: 0.48s; }
.trades > [data-reveal]:nth-child(10).is-visible { animation-delay: 0.54s; }

/* CTA cluster — heading, paragraph, button row cascade. */
.cta-repeat__inner > [data-reveal]:nth-child(1).is-visible { animation-delay: 0s;    }
.cta-repeat__inner > [data-reveal]:nth-child(2).is-visible { animation-delay: 0.12s; }
.cta-repeat__inner > [data-reveal]:nth-child(3).is-visible { animation-delay: 0.24s; }

/* FAQ accordion stagger — modest delays so adjacent items in viewport
 * cascade instead of popping simultaneously. Items further down the page
 * trigger one-at-a-time as the user scrolls, so these delays only matter
 * for the cluster that initially enters the viewport. */
details.faq[data-reveal]:nth-child(1).is-visible  { animation-delay: 0s;    }
details.faq[data-reveal]:nth-child(2).is-visible  { animation-delay: 0.07s; }
details.faq[data-reveal]:nth-child(3).is-visible  { animation-delay: 0.14s; }
details.faq[data-reveal]:nth-child(4).is-visible  { animation-delay: 0.21s; }
details.faq[data-reveal]:nth-child(5).is-visible  { animation-delay: 0.28s; }
details.faq[data-reveal]:nth-child(6).is-visible  { animation-delay: 0.35s; }
details.faq[data-reveal]:nth-child(7).is-visible  { animation-delay: 0.42s; }
details.faq[data-reveal]:nth-child(8).is-visible  { animation-delay: 0.49s; }
details.faq[data-reveal]:nth-child(9).is-visible  { animation-delay: 0.56s; }

/* Pricing — per-trade-section internals (icon header, 3 tier cards, tasks
 * list) and section ledes/cards. Stagger keeps tab-switch reveals smooth. */
.pricing-tiers > .pricing-tier[data-reveal]:nth-child(1).is-visible { animation-delay: 0s;    }
.pricing-tiers > .pricing-tier[data-reveal]:nth-child(2).is-visible { animation-delay: 0.10s; }
.pricing-tiers > .pricing-tier[data-reveal]:nth-child(3).is-visible { animation-delay: 0.20s; }
