/* ============================================================
   NOBL — HOME PAGE
   Section-specific styling, in page order.
   ============================================================ */

/* ------------------------------------------------------------
   1. HERO  (Hero D — "Material": light lives inside the mark)
   ------------------------------------------------------------ */

.hero {
  position: relative;
  overflow: hidden;
  background: var(--s2);
  min-height: calc(100dvh - var(--header-h));
  display: flex;
}

/* Layer 1 — fluid gradient field (canvas, low-res upscaled) */
.hero__bg {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
}

/* Layer 2 — dot grid, radially masked */
.hero__dots {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(11,13,15,0.05) 1px, transparent 1px);
  background-size: 22px 22px;
  -webkit-mask-image: radial-gradient(ellipse 70% 60% at 50% 30%, #000, transparent);
          mask-image: radial-gradient(ellipse 70% 60% at 50% 30%, #000, transparent);
  pointer-events: none;
}

/* Layer 3 — bottom fade into the page */
.hero__fade {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 220px;
  background: linear-gradient(180deg, rgba(255,255,255,0), var(--bg));
  pointer-events: none;
}

.hero__content {
  position: relative;
  max-width: var(--page-max);
  margin-inline: auto;
  padding: 56px var(--page-pad) 104px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  width: 100%;
}

/* The mark — arms build outward from the base on load */
.hero__mark {
  position: relative;
  width: clamp(180px, 22vw, 280px);
  margin-bottom: 56px;
  animation: noblBuildArms 1.2s var(--ease-build) .15s both;
}
.hero__mark img { width: 100%; filter: var(--sh-mark); }
/* Light inside the silhouette — clipped via destination-in */
.hero__mark canvas {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
}

/* Staggered load sequence */
.hero__badge { margin-bottom: 30px; animation: noblUp var(--d-reveal) var(--ease-out) 700ms both; }
.hero__title { max-width: 980px; margin: 0 0 28px; animation: noblUp var(--d-reveal) var(--ease-out) 780ms both; }
.hero__sub   { max-width: 620px; margin: 0 0 40px; animation: noblUp var(--d-reveal) var(--ease-out) 860ms both; }
.hero__ctas  { animation: noblUp var(--d-reveal) var(--ease-out) 940ms both; }


@media (max-width: 640px) {
  .hero__content { padding: 32px var(--page-pad) 72px; }
  .hero__mark { margin-bottom: 40px; }
}


/* ------------------------------------------------------------
   2. PARTNER MARQUEE
   ------------------------------------------------------------ */

.marquee-strip {
  border-block: 1px solid var(--stroke);
  background: var(--bg);
  overflow: hidden;
}
.marquee-strip__inner {
  max-width: var(--page-max);
  margin-inline: auto;
  padding: var(--sec-strip) var(--page-pad);
  display: flex;
  align-items: center;
  gap: 40px;
}
.marquee-strip__label { flex: 0 0 auto; margin: 0; }

.marquee {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}
.marquee__track {
  display: flex;
  gap: 64px;
  width: max-content;
  animation: noblMarquee 34s linear infinite;
}
/* Pause on hover/focus so the strip is readable */
.marquee:hover .marquee__track,
.marquee:focus-within .marquee__track { animation-play-state: paused; }

.marquee__group { display: flex; gap: 64px; align-items: center; }
.marquee__item {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-weight: 400;
  font-size: 18px;
  letter-spacing: var(--tr-display);
  color: var(--faint);
  white-space: nowrap;
}

@media (max-width: 640px) {
  .marquee-strip__inner { gap: 20px; }
  .marquee-strip__label { font-size: 9px; }
}


/* ------------------------------------------------------------
   3. WHAT WE DO
   ------------------------------------------------------------ */



/* ------------------------------------------------------------
   4. NOBL OS FEATURE  (client favorite — preserve faithfully)
   ------------------------------------------------------------ */

/* Fiber Fade behind the section. The mark's glass panel and the copy both
   sit on it, so the decorative layers below are re-tuned for a mid-tone
   blue ground rather than near-black. */
.os {
  position: relative;
  background: var(--bg-deep);
}
.os__grid {
  display: grid;
  grid-template-columns: minmax(0,0.85fr) minmax(0,1.15fr);
  gap: var(--gap-col-lg);
  align-items: center;
}
@media (max-width: 1000px) {
  .os__grid { grid-template-columns: 1fr; }
}

.os__brand { display: flex; align-items: center; gap: 10px; margin-bottom: 24px; }
.os__brand img { height: 14px; width: auto; }
.os__brand .eyebrow { margin: 0; }

.os__copy { max-width: 460px; margin: 22px 0 36px; }

/* The record rail is the floor of this section. The cards lift off the
   grey ground, but not all the way to white — pure #FFF was too hot
   against #F7F8F9. This sits halfway, so they still read as panels
   without glaring. */
.os__record { margin-top: clamp(56px, 6vw, 84px); }
.os .rail__item { background: #FCFCFD; }
.os__list { margin: 0 0 40px; padding: 0; list-style: none; }

/* --- The platform mock (glass card) --- */
/* A dark surface owns its own text colour. These panels used to sit
   inside .section--dark and inherit a light colour from it; now that
   the sections around them are light, anything inside without an
   explicit colour falls through to near-black ink on near-black. */
.mock {
  color: var(--on-dark-list);
  border: 1px solid var(--bw-10);
  background: rgba(255,255,255,0.03);
  backdrop-filter: blur(10px);
  border-radius: var(--r-card);
  overflow: hidden;
  box-shadow: var(--sh-mock);
}

.mock__bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 18px;
  border-bottom: 1px solid var(--bw-08);
}
.mock__dots { display: flex; gap: 6px; }
.mock__dots i { width: 9px; height: 9px; border-radius: 50%; background: var(--bw-14); }
.mock__path {
  margin-left: 10px;
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  letter-spacing: var(--tr-label);
  color: var(--on-dark-mono);
}
.mock__live {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  color: var(--accent-fill);
}
.mock__live i {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent-fill);
  animation: noblPulse 1.8s ease-in-out infinite;
}

.mock__stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-bottom: 1px solid var(--bw-08);
}
.mock__stat { padding: 15px 18px; }
.mock__stat + .mock__stat { border-left: 1px solid var(--bw-08); }
.mock__stat dt {
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  color: var(--on-dark-mono);
  letter-spacing: var(--tr-chip);
}
.mock__stat dd {
  font-family: var(--font-display);
  text-transform: uppercase;
  font-weight: 400;
  font-size: 28px;
  letter-spacing: var(--tr-display);
  color: var(--on-dark-heading);
  margin: 8px 0 0;
  /* tabular figures stop the live counter from jittering the layout */
  font-variant-numeric: tabular-nums;
}
.mock__stat--installed dd { color: var(--accent-fill); }
.mock__stat--payout dd { color: var(--gold); }

.mock__chart { padding: 17px 18px 12px; border-bottom: 1px solid var(--bw-08); }
.mock__chart-head {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  color: var(--on-dark-mono);
  letter-spacing: var(--tr-chip);
  margin-bottom: 14px;
}
.mock__chart-head em { font-style: normal; color: var(--accent-fill); }
.mock__bars { display: flex; align-items: flex-end; gap: 10px; height: 96px; }
.mock__bars i {
  flex: 1;
  border-radius: var(--r-button) var(--r-button) 0 0;
  background: linear-gradient(180deg, rgba(91,157,181,0.5), rgba(91,157,181,0.08));
}
/* Final two weeks break out — gold, the payout colour */
.mock__bars i.is-peak {
  background: linear-gradient(180deg, var(--gold), rgba(212,168,90,0.1));
}

.mock__feed { padding: 4px 0 2px; min-height: 172px; }
.mock__row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 9px 18px;
  animation: noblSlideIn .6s var(--ease-out) both;
}
/* The row marker carries its row's status colour, lit just enough to
   register without competing with the payout figure. */
.mock__avatar {
  width: 12px; height: 12px;
  /* Sits on the NAME's line, not centred on the whole row — centring it
     against name-plus-address reads as misaligned to the eye. */
  margin-top: 2.5px;
  border-radius: 3px;
  background: rgba(255,255,255,0.08);
  flex: 0 0 auto;
}
.mock__avatar--installed {
  background: var(--accent-fill);
  box-shadow: 0 0 7px rgba(91,157,181,0.5);
}
.mock__avatar--scheduled {
  background: var(--gold);
  box-shadow: 0 0 7px rgba(212,168,90,0.5);
}
.mock__avatar--submitted {
  background: var(--on-dark-meta);
  box-shadow: 0 0 7px rgba(154,161,166,0.38);
}
/* Name over address. These were inline spans, so they ran together and
   their ellipsis truncation never applied. */
.mock__who { min-width: 0; flex: 1; display: grid; gap: 3px; }
.mock__name {
  display: block;
  color: var(--on-dark-list);
  font-size: 12.5px;
  line-height: 1.35;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mock__addr {
  display: block;
  font-size: 11.5px;
  color: var(--on-dark-mono);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}



/* ------------------------------------------------------------
   6. STEPPER — one step open at a time

   Four columns of running text at 241px was a wall. Only the open
   step carries its body now, and it widens to take the room the
   other three give up, so its copy lands at a readable measure.

   The number and title were inline spans and collided on one line —
   that, more than the density, was what made this look crammed.
   ------------------------------------------------------------ */

.stepper { position: relative; }

/* The line runs node-centre to node-centre — the journey starts at step
   01 and ends at the payout, so it should not overhang either end. JS
   measures both, because the columns resize as steps open. */
.stepper__rail {
  position: absolute;
  top: 11px; left: 0;
  width: 100%;
  height: 1px;
  background: var(--stroke);
}
.stepper__fill {
  position: absolute;
  top: 11px; left: 0;
  width: 0;
  height: 1px;
  background: var(--accent);
  transition: width var(--d-reveal) var(--ease-out);
}
/* The sequence ends in money, so the rail arrives in gold. */
.stepper--payout .stepper__fill {
  background: linear-gradient(90deg,
              var(--accent) 0%, var(--accent) 64%, var(--gold) 100%);
}

/* Stretch, not flex-start: the four cards are one row of boxes and have
   to share a bottom edge whichever one is open. */
.stepper__list {
  display: flex;
  align-items: stretch;
  gap: var(--gap-card);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The rail is positioned, so without this the items stay static and the
   line paints OVER the nodes. The ring's white fill then hides the line
   where it passes behind, which is what makes the fill read as threading
   through the nodes rather than across them. */
.stepper__item {
  min-width: 0;
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
}

/* The node keeps its own track above the card, so the rail geometry is
   untouched by the boxes — and a hairline stem drops from each ring into
   the card it belongs to, so the dot doesn't read as floating. */
.stepper__node {
  position: relative;
  display: block;
  height: 23px;
}
.stepper__node::after {
  content: "";
  position: absolute;
  left: 11px; top: 23px;
  width: 1px; height: 21px;
  background: var(--stroke);
  transition: background var(--d-state);
}

.stepper__ring {
  width: 23px; height: 23px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--stroke-strong);
  display: grid; place-items: center;
  transition: border-color var(--d-state);
}
.stepper__ring i {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--stroke-strong);
  transition: background var(--d-state);
}

/* The box. Same language as the three pillar cards above — off-white
   panel, hairline, 6px — so the open step lifts to plain white the way
   the active pillar does. */
.stepper__card {
  position: relative;
  flex: 1;
  margin-top: 20px;
  padding: 20px 22px 24px;
  background: var(--s2);
  border: 1px solid var(--stroke);
  border-radius: var(--r-card);
  transition: background var(--d-state), border-color var(--d-state);
}

.stepper__btn {
  display: block;
  width: 100%;
  text-align: left;
  cursor: pointer;
}
/* The whole card is the target, not just the two lines of the button. */
.stepper__btn::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--r-card);
}
.stepper__btn:focus-visible { outline: none; }
.stepper__btn:focus-visible::after {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* These two were inline. Blocking them is the actual bug fix. */
.stepper__num {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 11px;
  transition: color var(--d-state);
}
.stepper__title {
  display: block;
  font-size: var(--t-step-title);
  font-weight: 700;
  line-height: 1.28;
  letter-spacing: var(--tr-display);
  color: var(--muted);
  transition: color var(--d-state);
}

.stepper__body {
  font-size: var(--t-card);
  line-height: var(--lh-body);
  color: var(--body);
  margin: 12px 0 0;
}

/* Reached (this step or an earlier one) */
.stepper__item[data-reached="true"] .stepper__ring { border-color: var(--accent); }
.stepper__item[data-reached="true"] .stepper__ring i { background: var(--accent); }
.stepper__item[data-reached="true"] .stepper__node::after { background: var(--accent-line); }
.stepper__item[data-reached="true"] .stepper__title { color: var(--text); }
.stepper__item[data-active="true"] .stepper__num { color: var(--accent); }
.stepper__item[data-active="true"] .stepper__card {
  background: var(--bg);
  border-color: var(--accent-line);
}

/* Payout is the destination — it lands in gold, not blue. */
.stepper__item:last-child[data-reached="true"] .stepper__ring { border-color: var(--gold); }
.stepper__item:last-child[data-reached="true"] .stepper__ring i { background: var(--gold); }
.stepper__item:last-child[data-reached="true"] .stepper__node::after { background: var(--gold-line); }
.stepper__item:last-child[data-active="true"] .stepper__num { color: var(--gold); }
.stepper__item:last-child[data-active="true"] .stepper__card { border-color: var(--gold-line); }

@keyframes stepBody {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* ---- the accordion, desktop only ---- */
@media (min-width: 901px) {
  .stepper__item {
    flex: 0.72 1 0;
    transition: flex-grow .6s var(--ease-out);
  }
  .stepper__item[data-active="true"] { flex-grow: 1.84; }

  /* Reserve two lines so the body always starts on the same baseline,
     whichever step is open. */
  .stepper__title { min-height: calc(2 * 1.28 * var(--t-step-title)); }

  .stepper__body { display: none; min-height: 48px; }
  .stepper__item[data-active="true"] .stepper__body {
    display: block;
    animation: stepBody .5s var(--ease-out) both;
  }

  /* No JS, or reduced motion: every step carries its body. */
  .stepper--open-all .stepper__item { flex: 1 1 0; }
  .stepper--open-all .stepper__body { display: block; animation: none; }
}

@media (max-width: 900px) {
  .stepper__rail, .stepper__fill { display: none; }
  .stepper__list { flex-direction: column; gap: 0; }

  /* Node in its own column so the spine can run the full height of each
     card, and the boxes stack down the right of it. */
  .stepper__item {
    flex: none;
    width: 100%;
    display: grid;
    grid-template-columns: 23px minmax(0, 1fr);
    column-gap: 17px;
    padding-bottom: var(--gap-card);
  }
  .stepper__item:last-child { padding-bottom: 0; }

  .stepper__node { align-self: stretch; height: auto; }
  .stepper__node::after { top: 23px; bottom: calc(-1 * var(--gap-card)); height: auto; }
  .stepper__item:last-child .stepper__node::after { display: none; }

  .stepper__card { margin-top: 0; }
}

/* ------------------------------------------------------------
   7. TESTIMONIAL
   ------------------------------------------------------------ */

.quote-block {
  max-width: 900px;
  margin-inline: auto;
  text-align: center;
}
.quote-block__mark {
  height: 20px; width: auto;
  margin: 0 auto 36px;
  opacity: 0.9;
}
.quote-block blockquote {
  /* Body face: a testimonial shouts in all caps. */
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--t-quote);
  line-height: var(--lh-quote);
  letter-spacing: -0.02em;
  margin: 0 0 32px;
  text-wrap: balance;
}
.quote-block figcaption {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
}
.quote-block__avatar {
  width: 40px; height: 40px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent-fill), var(--accent));
  flex: 0 0 auto;
}
.quote-block__who { text-align: left; }
.quote-block__name { font-size: 14px; font-weight: 700; }
.quote-block__role { font-size: 12.5px; color: var(--muted); }




/* ------------------------------------------------------------
   3b. WHAT WE DO — the mark as the diagram

   The mark's three upper limbs map left-to-right onto the three
   items. Position carries the correspondence, so the nodes need
   no labels. Decorative: the copy reads fine with the SVG absent.
   ------------------------------------------------------------ */

.wwd__diagram {
  width: clamp(230px, 31vw, 400px);
  margin: 0 auto 60px;
}

.wwd__svg { display: block; width: 100%; height: auto; overflow: visible; }

/* Hairline at any size — the mark scales, the stroke must not. */
.wwd__outline {
  fill: none;
  stroke: rgba(11,13,15,0.26);
  stroke-width: 1.4;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* Fill is a dot pattern set on the element, so the reveal rides opacity —
   `fill` can't be transitioned between a pattern and a colour. */
.wwd__limb {
  opacity: 0;
  transition: opacity .55s var(--ease-out);
}
.wwd__limb.is-on { opacity: 1; }

.wwd__dot {
  fill: rgba(11,13,15,0.22);
  transition: fill .4s var(--ease-out);
}
.wwd__node.is-on .wwd__dot { fill: var(--accent); }

.wwd__halo {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.4;
  vector-effect: non-scaling-stroke;
  opacity: 0;
  transition: opacity .4s var(--ease-out);
}
.wwd__node.is-on .wwd__halo { opacity: .45; }

/* No JS, or reduced motion: every limb simply reads as itself. */
.wwd--static .wwd__limb { opacity: 1; }

.wwd__list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--gap-card);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Glass cards — the kit's base container: white panel, hairline
   border, 6px. */
.wwd__item {
  position: relative;
  padding: 26px 24px 28px;
  background: var(--s2);
  border: 1px solid var(--stroke);
  border-radius: var(--r-card);
  transition: background var(--d-state), border-color var(--d-state);
}
/* The active card is the one the diagram is drawing: it lifts to white
   and takes a soft accent edge. Depth from tint, no drop shadow. */
.wwd__item.is-on {
  background: var(--bg);
  border-color: var(--accent-line);
}

.wwd__num {
  font-family: var(--font-mono);
  font-size: var(--t-eyebrow);
  letter-spacing: var(--tr-eyebrow);
  color: var(--muted);
  margin: 0 0 16px;
  transition: color .5s var(--ease-out);
}
.wwd__item.is-on .wwd__num { color: var(--accent); }

.wwd__title {
  font-size: var(--t-card-title);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0 0 10px;
}

.wwd__body {
  font-size: var(--t-card);
  color: var(--body);
  line-height: var(--lh-body);
  margin: 0;
}

/* The outline glows where a limb meets it, so the dots read as streaming
   off a lit edge rather than floating in the shape. */
.wwd__edge {
  opacity: 0;
  transition: opacity .55s var(--ease-out);
}
.wwd__edge.is-on { opacity: 1; }

.wwd__edgeGlow,
.wwd__edgeMid,
.wwd__edgeCore {
  fill: none;
  stroke: var(--accent);
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.wwd__edgeGlow { stroke-width: 11; opacity: .16; }
.wwd__edgeMid  { stroke-width: 5;  opacity: .38; }
.wwd__edgeCore { stroke-width: 1.9; }

.wwd--static .wwd__edge { opacity: 1; }

@media (max-width: 860px) {
/* Stacked, but still cards — the old rule zeroed the gap and
     re-set the padding for a borderless column list. */
  .wwd__list { grid-template-columns: 1fr; gap: var(--gap-card); }
  .wwd__item { padding: 22px 20px 24px; }
  .wwd__num { margin-bottom: 12px; }
  .wwd__diagram { width: clamp(200px, 54vw, 300px); margin-bottom: 44px; }
}


/* ------------------------------------------------------------
   4b. NOBL OS on Fiber Fade

   The section's ground is a mid-tone blue, which the original
   dark-section treatment was never built for: the mock was glass
   (3% white) meant to sit on near-black, and the copy used the
   dark-section greys. Both had to be re-grounded.
   ------------------------------------------------------------ */

/* A soft scrim under the copy column. White body text measures 3.03:1
   against the gradient's light end — under the 4.5:1 it needs — and this
   carries it over while reading as depth rather than a patch. */

/* The blue bloom is invisible on blue; make it a light one instead. */
.os .glow--bl {
  background: radial-gradient(circle, rgba(173,214,233,0.22), rgba(173,214,233,0) 65%);
}

.os .check-list span { color: var(--body); }

/* The mock is a real screen. The section around it is light now, so
   the dark panel reads as the product rather than as the page —
   the way Stripe keeps a code block dark in a white section. */
.os .mock {
  background: var(--smoke);
  border-color: var(--smoke);
  box-shadow: var(--sh-mock);
}


/* ------------------------------------------------------------
   4c. The claims point at their own proof

   Hovering a checklist item settles the mock onto the part of the
   product that backs it up. Nothing is hidden behind the hover —
   every claim and every figure is readable without it.
   ------------------------------------------------------------ */

.os .check-list li {
  cursor: default;
  transition: opacity .4s var(--ease-out);
}
.os .check-list[data-focus] li:not(.is-on) { opacity: .45; }
.os .check-list__mark { background: var(--accent-soft); }
.os .check-list__mark--gold { background: var(--gold-soft); }

.mock [data-os-part] { transition: opacity .45s var(--ease-out); }
.mock[data-focus] .mock__bar,
.mock[data-focus] .mock__stat,
.mock[data-focus] .mock__chart,
.mock[data-focus] .mock__feed { opacity: .28; }
.mock[data-focus] [data-os-part].is-lit { opacity: 1; }

/* Payout is the money moment, so it gets a little more than undimming. */
.mock[data-focus="payout"] [data-os-part="payout"] {
  box-shadow: inset 0 0 0 1px rgba(212,168,90,0.45),
              0 0 26px -4px rgba(212,168,90,0.4);
  border-radius: 3px;
}
