/* White Label sales variant; shared primitives remain in base.css. */
#wl-economics .wl-card-label { color: var(--cream-050); }
#wl-economics .wl-calc__row:not(.is-accent) > span { color: var(--cream-300); }
.wl-callout__art { position: relative; min-height: 0; margin-top: 12px; }
.wl-callout__bot { display: block; position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; object-fit: contain; }
/* The nine-item panel sets the height; artwork fills only the remaining room. */
@media (min-width: 993px) {
  #wl-market .wl-market__panel:last-child { contain: size; grid-template-rows: auto auto minmax(0, 1fr); align-content: stretch; min-height: 0; }
  #wl-market .wl-callout { display: grid; grid-template-rows: auto auto minmax(0, 1fr); min-height: 0; }
}
@media (max-width: 992px) {
  .wl-callout__art { height: 240px; }
}
.page--white-label .btn--large { min-height: 60px; padding-inline: 32px; font-size: 18px; font-weight: 500; max-width: 100%; }
.wl-cta-stack { display: flex; flex-direction: column; align-items: center; gap: 18px; width: fit-content; max-width: 100%; }
/* The 420px floor is capped at the space available: on a 390px phone a flat
   420px made the button wider than the screen and stretched the hero column
   (and the video player in it) off the right edge. The cap is measured
   against the viewport, not 100%: the button sits in a fit-content stack, so a
   percentage has nothing definite to resolve against and collapsed the
   desktop button to its label width. Desktop is unchanged at 760px. */
.wl-offer-hero__copy--cta .btn { width: clamp(min(420px, 100vw - 48px), 60vw, 760px); max-width: 100%; min-width: 0; }
.wl-section-cta .btn,
.cta__actions .btn { width: clamp(min(420px, 100vw - 48px), 60vw, 760px); max-width: 100%; min-width: 0; }
.wl-trust-strip { display: block; width: 190px; max-width: 100%; height: auto; margin-top: 2px; }
.wl-section-cta .wl-cta-stack, .cta__actions .wl-cta-stack { margin-inline: auto; }
.wl-project-shot, .wl-console-overview { margin: 0; }
.wl-project-shot img, .wl-console-overview img { display: block; width: 100%; height: auto; border-radius: 12px; border: 1px solid var(--ink-600); }
.wl-console-overview { margin-block: 24px; }
.wl-pain__symbol { flex: 0 0 auto; font-size: 22px; line-height: 1; border: 0; background: none; padding: 0; }
.wl-pain__symbol--bad { color: #f87171; }
.wl-pain__symbol--good, .wl-cap-grid .ph { color: var(--good); }
.wl-model { display: flex; flex-direction: column; }
.wl-model ul { width: 100%; margin-top: auto; padding: 20px; background: var(--surface-fill-soft); border: 1px solid var(--ink-600); border-radius: 12px; display: grid; gap: 16px; text-align: center; }
.wl-model:first-child ul { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.wl-model ul li { font-family: var(--font-mono); font-size: 16px; font-weight: 400; line-height: 1.5; padding: 0; border: 0; background: none; color: var(--cream-100); }
.wl-model .t-body { margin-bottom: 24px; }
.wl-included-rows { display: grid; gap: 20px; }
.wl-included-row { display: grid; grid-template-columns: 1.15fr 1fr; gap: clamp(20px,3vw,40px); align-items: center; min-height: calc(40svh - 20px); padding: clamp(18px,2vw,28px); border: 1px solid var(--ink-600); border-radius: 16px; background: var(--surface-fill-soft); }
.wl-included-row .wl-image-placeholder { aspect-ratio: auto; min-height: 0; height: clamp(150px, 30svh, 260px); padding: 16px; }
.wl-included-row .t-h3 { font-size: clamp(22px,2vw,30px); }
.wl-included-row .t-body { font-size: 16px; line-height: 1.55; }
.wl-included-image { display: block; width: auto; max-width: 100%; height: auto; max-height: 30svh; margin-inline: auto; object-fit: contain; border: 0; outline: 0; box-shadow: none; border-radius: 12px; overflow: hidden; clip-path: inset(0 round 12px); background: transparent; }
.wl-included-row:nth-child(even) .wl-included-row__copy { order: 2; }
.wl-included-row__copy { display: grid; gap: 16px; }
.wl-image-placeholder { min-width: 0; aspect-ratio: 16/10; border-radius: 12px; border: 1px dashed var(--ink-500); background: var(--surface-fill-soft); display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 12px; padding: 24px; color: var(--cream-300); }
.wl-image-placeholder .ph { font-size: 36px; color: var(--cream-500); }
.wl-image-placeholder small { font-size: 13px; color: var(--cream-500); }
.wl-pricing__grid--offer .plan { padding: clamp(24px,3vw,48px); }
.wl-pricing__grid--offer .plan__name { font-size: 26px; }
.wl-pricing__grid--offer .plan__amount { font-size: clamp(52px,5vw,76px); line-height: 1.05; }
.wl-pricing__grid--offer .plan__per { font-size: 18px; }
.wl-pricing__grid--offer .plan__list { gap: 16px; }
.wl-pricing__grid--offer .plan__list li { font-size: 17px; line-height: 1.6; color: var(--cream-100); }
.wl-pricing__grid--offer .plan__flag { font-size: 14px; }
.wl-pricing-trust { display: flex; justify-content: center; width: 100%; max-width: 52rem; padding: 28px; margin: 24px auto 0; border: 1px solid var(--ink-600); border-radius: 16px; background: var(--surface-fill-soft); }
.wl-pricing-trust .wl-trust-strip { width: 340px; }
.wl-pricing .wl-disclaimer { font-size: 15px; line-height: 1.6; }
.wl-audience li { min-height: 110px; padding: 28px; font-size: 21px; color: var(--cream-050); line-height: 1.4; }
.wl-final-stack li { font: inherit; }
.wl-final-stack, .page--white-label .cta__lead { font-size: clamp(18px,1.5vw,22px); }
.wl-final-bonuses { gap: 16px 24px; }
.wl-final-bonuses li { font-size: 16px; color: var(--cream-050); }
.wl-final-bonuses__check { color: var(--good); }
.wl-sticky__bar { border-color: color-mix(in srgb, var(--cream-050) 10%, transparent); box-shadow: 0 8px 32px #0003; }
.wl-sticky__copy { gap: 4px 12px; }
.wl-sticky__sub { display: block; font-size: 13px; }
.footer--sales .footer__plate { padding-top: 32px; }
.footer--sales .footer__plate { box-shadow: none; border-top: 0; }
.footer--sales .footer__meta { border-top: 0; }
.footer--sales .footer__meta { margin-top: 0; }

/* Category carousel follows the Output section's interaction model. */
.wl-output { min-width: 0; }
.wl-output__tabs { position: relative; display: flex; gap: 8px; overflow-x: auto; padding: 8px 0 20px; }
.wl-output__tab { flex-shrink: 0; border: 1px solid var(--ink-600); border-radius: 999px; background: transparent; color: var(--cream-300); padding: 10px 16px; font-size: 14px; }
.wl-output__tab[aria-current="true"] { color: var(--app-primary-fg); background: var(--accent); border-color: var(--accent); }
.wl-output__track { position: relative; display: flex; gap: 24px; overflow-x: auto; scroll-snap-type: x mandatory; padding-block: 8px 20px; }
.wl-output__tabs, .wl-output__track { scrollbar-width: none; cursor: grab; user-select: none; }
.wl-output__tabs::-webkit-scrollbar, .wl-output__track::-webkit-scrollbar { display: none; }
.wl-output__tabs .wl-output__tab { cursor: grab; }
.wl-output .is-dragging, .wl-output .is-dragging * { cursor: grabbing; scroll-snap-type: none; }
.wl-output__browser img { -webkit-user-drag: none; }
.wl-output__slide { margin: 0; flex: 0 0 74%; width: 74%; min-width: 0; scroll-snap-align: center; opacity: .45; transition: opacity .25s; }
.wl-output__slide:first-child { margin-left: 0; }
.wl-output__slide:last-child { margin-right: 13%; }
.wl-output__slide.is-active { opacity: 1; }
.wl-output__browser { display: flex; flex-direction: column; width: 100%; height: auto; min-height: 0; aspect-ratio: auto; border: 1px solid var(--ink-600); border-radius: 16px; overflow: hidden; background: var(--ink-800); }
.wl-output__chrome { flex: 0 0 44px; height: 44px; display: flex; align-items: center; gap: 8px; padding: 12px 16px; border-bottom: 1px solid var(--ink-600); color: var(--cream-500); font-size: 12px; }
.wl-output__chrome i { width: 8px; height: 8px; border-radius: 50%; background: var(--ink-500); }
.wl-output__chrome span { margin-inline: auto; padding: 5px 14px; border: 1px solid var(--ink-600); border-radius: 999px; background: var(--surface-fill-soft); font: 12px var(--font-mono); max-width: 75%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The first slide (1438x978) sets the box; every slide covers it, so that
   one shows complete and the rest fill the width. */
/* Box ratio comes from the CRM slide (1042x695), the reference every gallery
   image is now exported to. Every slide FILLS it with cover: an image a pixel
   or two off that ratio loses at most a sliver, never shows a gap. */
.wl-output__browser img { flex: 0 0 auto; min-height: 0; width: 100%; height: auto; aspect-ratio: 1042 / 695; display: block; object-fit: cover; object-position: top; }
.wl-output__caption { display: grid; gap: 10px; text-align: center; margin: 24px auto; max-width: 560px; }
.wl-output__caption h3 { font-size: 25px; }
.wl-output__controls { display: flex; justify-content: center; align-items: center; gap: 20px; }
.wl-output__controls button { width: 44px; height: 44px; border-radius: 999px; border: 1px solid var(--ink-600); background: transparent; color: var(--cream-050); }
.wl-output__controls button:disabled { opacity: .35; cursor: not-allowed; }
.wl-output__count { font: 14px var(--font-mono); }
.wl-output__placeholder { aspect-ratio: 16/10; display: grid; place-content: center; gap: 14px; text-align: center; background: linear-gradient(140deg,var(--surface-fill),transparent); color: var(--cream-300); }
.wl-output__placeholder .ph { font-size: 72px; color: var(--cream-500); }
.wl-output__placeholder small { font-size: 14px; }
.wl-output button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
@media(max-width: 760px) {
 .wl-included-row { grid-template-columns: 1fr; }
 .wl-included-row { gap: 14px; padding: 18px; }
 .wl-included-row .wl-image-placeholder { height: 120px; }
 .wl-included-row__copy { gap: 8px; }
 .wl-included-row:nth-child(even) .wl-included-row__copy { order: 0; }
 .wl-output__slide { flex-basis: 90%; width: 90%; }
 .wl-output__browser { height: auto; }
 .wl-output__slide:first-child { margin-left: 5%; }
 .wl-output__slide:last-child { margin-right: 5%; }
 .wl-sticky__copy { display: grid; gap: 4px; }
 .wl-sticky__sub { font-size: 11px; }
 .wl-sticky__title { font-size: 12px; }
 .wl-sticky__bar { border-radius: 24px; padding: 12px; }
 .wl-model:first-child ul { padding: 16px 10px; }
 .wl-model ul li { font-size: 15px; }
 /* Hug the label: no 60px floor, 16px above and below, and a tight line box -
    the inherited 1.55 made an 18px label 28px tall and the button grew. */
 .page--white-label .btn--large { min-height: 0; padding: 16px 24px; line-height: 1.2; }
}
@media(prefers-reduced-motion: reduce) { .wl-output__slide { transition: none; } }

/* Restore the page scrollbar without exposing the showcase's internal rails. */
html:has(.page--white-label) { scrollbar-width: thin; scrollbar-color: var(--ink-500) var(--ink-850); }
html:has(.page--white-label)::-webkit-scrollbar { width: 10px; }
html:has(.page--white-label)::-webkit-scrollbar-track { background: var(--ink-850); }
html:has(.page--white-label)::-webkit-scrollbar-thumb { background: var(--ink-500); border: 2px solid var(--ink-850); border-radius: 999px; }
html:has(.page--white-label)::-webkit-scrollbar-thumb:hover { background: var(--cream-500); }

/* Preview proportions reconstructed from the supplied product markup. */
.wl-preview__toolbar { gap: 8px; }
.wl-preview__tabs { margin: 0 auto 0 0; }
.wl-preview__tabs, .wl-preview__viewport { height: 32px; padding: 2px; background: var(--ink-800); border-color: var(--app-border); gap: 4px; }
.wl-preview__tab, .wl-preview__vp { padding: 0 12px; height: 100%; font: 500 12px var(--font-body); }
.wl-preview__tab.is-active, .wl-preview__vp.is-active { background: var(--app-card); box-shadow: 0 0 0 1px var(--app-border); }
.wl-preview__actions { margin-left: 0; }
.wl-preview__action { width: 32px; height: 32px; background: var(--app-card); border-color: var(--app-border); }
.wl-preview__frame { width: 100%; border-color: var(--app-border); background: var(--app-card); box-shadow: 0 20px 40px #0004; }
.wl-preview__chrome { height: 40px; padding: 0 12px; background: var(--ink-800); border-color: var(--app-border); }
.wl-preview__url { flex: 0 1 auto; max-width: 70%; margin-inline: auto; background: var(--app-card); font: 11px var(--font-body); padding: 4px 12px; }
.wl-preview__badge { font-size: 9px; border-radius: 999px; background: var(--ink-800); }
.wl-preview__body { min-height: 0; overflow: hidden; }
.wl-product-canvas { position: absolute; top: 0; left: 0; transform-origin: left top; width: 1280px; height: 800px; pointer-events: none; user-select: none; }
.wl-product-canvas .wl-preview__panel { width: 100%; height: 800px; min-height: 0; background: radial-gradient(ellipse at 50% 10%, #ff5e0038, transparent 60%), var(--ink-900); }
.wl-product-canvas .wl-preview__panel.is-active { display: flex; align-items: center; justify-content: center; }
.wl-product-canvas .wl-preview__auth { position: static; width: 384px; max-width: calc(100% - 48px); padding: 0; gap: 12px; }
.wl-product-canvas .wl-preview__brand { gap: 10px; font-size: 26px; color: var(--app-foreground); }
.wl-product-canvas .wl-preview__brand .wl-mark { width: 40px; height: 40px; }
.wl-product-canvas .wl-preview__welcome { font-size: 24px; margin: 8px 0 0; font-weight: 600; }
.wl-product-canvas .wl-preview__lead { font-size: 14px; color: var(--app-muted-fg); }
.wl-product-canvas .wl-preview__social { margin-top: 16px; gap: 12px; }
.wl-product-canvas .wl-preview__social button { height: 44px; font-size: 14px; padding: 0; border-radius: 999px; background: var(--app-card); border-color: var(--app-border); }
.wl-product-canvas .wl-preview__or { margin: 8px 0; font: 11px var(--font-body); text-transform: uppercase; }
.wl-product-canvas .wl-preview__field input { height: 44px; font-size: 14px; background: var(--app-card); border-color: var(--app-border); border-radius: 8px; }
.wl-product-canvas .wl-preview__signin { height: 44px; border-radius: 999px; font-size: 14px; background: linear-gradient(#ff8b47,#ff5e00); color: var(--app-primary-fg); }
.wl-product-canvas .wl-preview__footer-link { margin-top: 8px; font-size: 12px; }
.wl-product-canvas .wl-preview__tagline { position: absolute; bottom: 32px; left: 50%; transform: translateX(-50%); white-space: nowrap; border-radius: 999px; padding: 10px 24px; background: color-mix(in srgb,var(--app-card) 55%,transparent); border: 1px solid var(--app-border); font: 500 14px var(--font-display); color: var(--app-foreground); }
.wl-product-canvas .wl-preview__home { max-width: 600px; font-size: 18px; padding: 32px; }
.wl-product-canvas .wl-preview__loading { font-size: 18px; }
.wl-preview.is-expanded { z-index: 2147483000; }
@media(max-width:600px) {
 .wl-preview__toolbar { justify-content: flex-start; }
 .wl-preview__tabs { flex-basis: auto; }
 .wl-preview__vp { padding-inline: 8px; }
}

/* ---------------------------------------------------------------------------
   HERO LIGHT RAYS
   Two neutral beams raking in from the top corners. Geometry read off the
   reference hero at 1440: the left beam spans 433 of a 1425 container and the
   right 400, both 485px tall from the top edge, so they are kept here as
   ratios of the hero rather than pixel boxes and hold at any width. The SVGs
   are greyscale, which is why they sit on the warm ground without a tint.
   The entrance is the reference's own: a 0.5s linear slide from 230px out and
   230px up, with the right beam also fading in.
   ------------------------------------------------------------------------ */
.wl-hero-light {
  position: absolute; top: 0; z-index: 0;
  opacity: 0.9;
  pointer-events: none;
  line-height: 0;
}
/* Height comes from the artwork's own 406x415 ratio rather than a fixed box.
   A fixed 485px box plus object-fit:contain letterboxed the beam and left a
   ~20px dead band above it, which read as padding against the top edge. */
.wl-hero-light img { display: block; width: 100%; height: auto; }
/* 0.45s on an ease-out, the same clock the hero copy now runs on, so the
   beams land with the words instead of ahead of them. Both fade: the left
   one used to slide in at full opacity while only the right one faded. */
.wl-hero-light--left { left: 0; width: 30.4%; }
.wl-hero-light--right { right: 0; width: 28.1%; }
/* Held at zero until page.js boots. 1.8s on a gentle ease-in-out so the
   beams swell in gradually rather than snapping on. */
.wl-hero-light { opacity: 0; }
.is-booted .wl-hero-light--left { animation: wl-light-left 1.8s cubic-bezier(.4, 0, .2, 1) both; }
.is-booted .wl-hero-light--right { animation: wl-light-right 1.8s cubic-bezier(.4, 0, .2, 1) both; }
.no-js .wl-hero-light { opacity: 0.9; }

@keyframes wl-light-left {
  from { opacity: 0; transform: translate(-230px, -230px); }
  to { opacity: 0.9; transform: none; }
}
@keyframes wl-light-right {
  from { opacity: 0; transform: translate(230px, -230px); }
  to { opacity: 0.9; transform: none; }
}

/* The copy has to win the stacking order once the beams are in the box. */
.wl-offer-hero .shell { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  .wl-hero-light { animation: none; opacity: 0.9; }
}
@media (max-width: 768px) {
  .wl-hero-light { opacity: 0.6; }
}

/* ---------------------------------------------------------------------------
   HERO LIGHT RAYS - AIWA AMBIENCE
   The beam artwork is greyscale. Rather than filter-tinting it, which would
   drag the whites off-hue, the SVG is used as a MASK over a fill in AIWA's own
   ambience colour: the beam keeps its exact falloff and the colour is the
   lander's --accent, not an approximation of it.

   The <img> stays in the box but invisible - it is what gives the container
   its height, since the art's 406:415 ratio drives `height: auto`.
   ------------------------------------------------------------------------ */
/* No position here: the beams are already absolute, which is what gives
   ::after its containing block. Re-declaring it as relative dropped them into
   the flow and pushed the hero's content out of the box. */
.wl-hero-light img { visibility: hidden; }

.wl-hero-light::after {
  content: '';
  position: absolute; inset: 0;
  /* The lander lights its hero with --accent at low alpha over a warm ground,
     and its cards run the sunset pair; both are echoed here. */
  background:
    linear-gradient(160deg,
      color-mix(in srgb, var(--accent) 92%, transparent) 0%,
      color-mix(in srgb, var(--accent-hot) 78%, transparent) 55%,
      color-mix(in srgb, var(--accent-deep) 55%, transparent) 100%);
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.wl-hero-light--left::after {
  -webkit-mask-image: url("/wl-assets/images/wl/hero-light-left.svg");
  mask-image: url("/wl-assets/images/wl/hero-light-left.svg");
}
.wl-hero-light--right::after {
  -webkit-mask-image: url("/wl-assets/images/wl/hero-light-right.svg");
  mask-image: url("/wl-assets/images/wl/hero-light-right.svg");
  background:
    linear-gradient(200deg,
      color-mix(in srgb, var(--accent) 92%, transparent) 0%,
      color-mix(in srgb, var(--accent-hot) 78%, transparent) 55%,
      color-mix(in srgb, var(--accent-deep) 55%, transparent) 100%);
}

/* ---------------------------------------------------------------------------
   HERO DOT FIELD + BLOB OFF
   The dot texture is the reference's own asset, placed the way the reference
   places it: a square box, object-fit cover, sitting behind the copy and above
   the ground. Here it spans the hero's top band rather than one corner, since
   this hero is centred rather than split, and a radial mask takes it to zero
   before it reaches an edge so no rectangle shows.

   The page's soft amber blob is off on this hero - it and the dot field were
   competing for the same space to the right of the video.
   ------------------------------------------------------------------------ */
.wl-offer-hero .page-hero__blob { display: none; }

.wl-hero-dots {
  position: absolute;
  top: 0; left: 50%;
  width: min(140%, 1600px);
  height: clamp(420px, 55vw, 820px);
  translate: -50% 0;
  z-index: 0;
  opacity: 1;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(ellipse 62% 72% at 50% 26%, #000 25%, transparent 85%);
  mask-image: radial-gradient(ellipse 62% 72% at 50% 26%, #000 25%, transparent 85%);
}
.wl-hero-dots img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center;
}

@media (max-width: 768px) {
  .wl-hero-dots { opacity: 0.34; }
}

/* ---------------------------------------------------------------------------
   HERO CHECK ROW
   Replaces the dot-separated kicker with a check-and-label row.

   The glyph is the reference's own: a broken circle with a tick through it,
   inlined with stroke="currentColor" so it takes its colour from the row
   instead of being a fixed-colour file. Because that circle IS the frame, the
   separate badge chip the reference sits it on is dropped - stacking a filled
   chip behind a glyph that already draws its own ring just doubled the shape.

   Sized and weighted to sit under the headline rather than compete with it:
   supporting copy, not a second heading.
   ------------------------------------------------------------------------ */
.wl-hero-checks {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 10px 22px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.wl-hero-checks li {
  display: flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
  font-size: clamp(11px, 0.92vw, 13.5px);
  line-height: 1.25;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--cream-400);
}

.wl-hero-checks__icon {
  flex: 0 0 auto;
  width: 13px; height: 13px;
  color: var(--accent-hot);
}

/* Below the tablet tier the three labels cannot share a line at any readable
   size, so they stack rather than shrink into illegibility. */
@media (max-width: 860px) {
  .wl-hero-checks { flex-direction: column; align-items: center; gap: 8px; }
  .wl-hero-checks li { font-size: 13px; }
}

/* Breathing room above the headline. Overrides the clamp in page.css; the
   beams and dot field stay anchored to the hero's own top edge, so the padding
   moves the copy down without pulling the background layers with it. */
.page--white-label .wl-offer-hero { padding-top: 100px; }

/* ---------------------------------------------------------------------------
   MARKET PANELS - HATCH
   The diagonal field from the reference, at its own values: a layer at inset 0
   filled rgb(240,232,218) and masked by a 20x20 tile at mask-size 5px 5px.

   A masked bitmap, not a repeating gradient: a gradient rasterises each
   45-degree line separately against the pixel grid, which leaves some lines
   heavier than others. The tile downscales uniformly, so every line carries
   the same weight.

   The panel only gains a positioning context; its padding, border, radius and
   fill are untouched. The layer inherits the radius so it cannot square off
   the panel's corners.
   ------------------------------------------------------------------------ */
#wl-market .wl-market__panel { position: relative; }

.wl-market__lines {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  background-color: rgb(240, 232, 218);
  /* The reference holds its lines layer at opacity 1 but wraps it in a parent
     carrying opacity 0.25 - the fill is only a quarter strength on the page.
     Applied directly here, since there is no wrapper to inherit it from. */
  opacity: 0.25;
  -webkit-mask-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAZ0lEQVR4Aa3BWwoDQQwDwZbx/a/sHdBHAsm+VaVZMBFQhDUgbDDxQhHWfAgbTDxQhDW/hA0mbijCmn3CBhMXFGHNOWGDiQNFWHOdsMHEH0VYc5+wwcSXIqx5TthgYinCmveEDUsRtgH8hg0/9klauAAAAABJRU5ErkJggg==");
  mask-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAZ0lEQVR4Aa3BWwoDQQwDwZbx/a/sHdBHAsm+VaVZMBFQhDUgbDDxQhHWfAgbTDxQhDW/hA0mbijCmn3CBhMXFGHNOWGDiQNFWHOdsMHEH0VYc5+wwcSXIqx5TthgYinCmveEDUsRtgH8hg0/9klauAAAAABJRU5ErkJggg==");
  -webkit-mask-size: 5px 5px;
  mask-size: 5px 5px;
  -webkit-mask-repeat: repeat;
  mask-repeat: repeat;
  -webkit-mask-position: 0 0;
  mask-position: 0 0;
  pointer-events: none;
}

/* The panel's own content stays above the field. */
#wl-market .wl-market__panel > *:not(.wl-market__lines) {
  position: relative;
  z-index: 1;
}

/* The callout's fill is only 8% amber, so the hatch behind it read straight
   through. A backdrop blur wider than the hatch's own 5px period averages
   those lines into a flat tone, which clears the card without giving up the
   translucency the amber tint depends on. */
#wl-market .wl-callout {
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}

/* ---------------------------------------------------------------------------
   MARKET ROWS - CORNER BRACKETS
   Each corner is an L: two 1px strokes at 30% alpha, 7px long, meeting -
   left+top, right+top, left+bottom, right+bottom - rather than a filled
   square. Eight background layers, so the rows stay plain <li> and the row's
   own fill underneath is untouched.

   Corners are square because background layers clip to the border radius; on
   a rounded row the brackets would bend into arcs instead of meeting at a
   right angle.
   ------------------------------------------------------------------------ */
#wl-market .wl-demand-list li,
#wl-market .wl-strike-list li {
  border-radius: 0;
  background-image:
    linear-gradient(rgba(240, 231, 218, 0.3) 0 0), linear-gradient(rgba(240, 231, 218, 0.3) 0 0),
    linear-gradient(rgba(240, 231, 218, 0.3) 0 0), linear-gradient(rgba(240, 231, 218, 0.3) 0 0),
    linear-gradient(rgba(240, 231, 218, 0.3) 0 0), linear-gradient(rgba(240, 231, 218, 0.3) 0 0),
    linear-gradient(rgba(240, 231, 218, 0.3) 0 0), linear-gradient(rgba(240, 231, 218, 0.3) 0 0);
  background-size:
    7px 1px, 1px 7px,
    7px 1px, 1px 7px,
    7px 1px, 1px 7px,
    7px 1px, 1px 7px;
  background-position:
    0 0,        0 0,
    100% 0,     100% 0,
    0 100%,     0 100%,
    100% 100%,  100% 100%;
  background-repeat: no-repeat;
}

/* ---------------------------------------------------------------------------
   FAQ - REFERENCE ARRANGEMENT
   Closed-state values measured off the reference section, not estimated:
   two columns of 588 at 24px apart with 10px between rows; each row a 72px
   card, radius 14px, padding 16px 30px, contents 24px apart; question at
   20px/30px weight 500; the toggle a 40x40 square at radius 10px.

   Colours are AIWA's: the reference's rgb(12,12,13) card and rgb(28,30,32)
   toggle map onto --ink-800 and --ink-700, the question to --cream-050, and
   the eyebrow's muted gold to --accent.

   The open state is the page's own accordion - it already expands, closes its
   siblings and animates the +/-, so only the closed row needed rebuilding.
   The heading stays on AIWA's t-h2 scale rather than the reference's 58px, so
   it still matches every other section head on this page.
   ------------------------------------------------------------------------ */
#wl-faq .faq__tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-size: 18px;
  font-weight: 500;
  color: var(--cream-400);
}
#wl-faq .faq__tag .ph { font-size: 20px; color: var(--accent); }

/* The shell is 48rem by default, which squeezed each column to 314px and
   wrapped every question onto two lines. 1200px is the reference's container:
   less the 24px gap it splits into two 588px columns, its card width exactly. */
#wl-faq .faq__inner { max-width: 75rem; }

#wl-faq .faq__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 24px;
  align-items: start;
}

#wl-faq .accordion__item {
  border: 0;
  border-radius: 14px;
  background: var(--ink-800);
  overflow: hidden;
}

#wl-faq .accordion__head {
  gap: 24px;
  min-height: 72px;
  padding: 16px 30px;
  font-size: 20px;
  line-height: 30px;
  font-weight: 500;
  letter-spacing: normal;
  color: var(--cream-050);
}

/* Square toggle, not the circular one the rest of the site uses. */
#wl-faq .accordion__icon {
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 10px;
  background: var(--ink-700);
}

/* The accordion collapses with grid-template-rows: 0fr on .accordion__body and
   overflow: hidden on its child. Padding on that child is OUTSIDE the clipped
   content box, so a 0fr row still resolves to the padding's height - this item
   sat 20px taller than its question and leaked the top of the answer. The
   padding therefore goes on the paragraph, which is inside the clipped box and
   collapses with it. Same open-state spacing: 0.85rem above (site.css's value)
   and 1.6rem below (its 0.35rem plus the 20px that used to sit on the div). */
#wl-faq .accordion__body > div { padding: 0; }
#wl-faq .accordion__body p { padding: 0.85rem 30px 1.6rem; }

@media (max-width: 900px) {
  #wl-faq .faq__grid { grid-template-columns: minmax(0, 1fr); }
}

/* ---------------------------------------------------------------------------
   ONE GROUND FOR THE WHOLE PAGE
   Two things used to paint over the page's own --ink-900: the alternating
   --alt sections at rgb(11,9,7) and the trust strip at rgba(18,18,17,.45).
   The --alt banding is cleared so every section sits on the same ground.

   Its 1px top and bottom hairlines go with it. Left in place they would
   survive as rules straight across the page, marking the seams the banding
   used to hide - which is the opposite of one continuous background.

   THE TRUST STRIP KEEPS ITS BAND. It is not part of the alternating rhythm -
   it is a single hairline-bounded strip between the hero and the page proper,
   and page.css gives it rgba(18,18,17,.45) between two --ink-600 rules. Its
   hairlines read as the strip's own edges rather than a seam, so both stay.

   Scoped to this page: page-section--alt is shared with the rest of the site,
   where the alternating bands are still wanted.
   ------------------------------------------------------------------------ */
.page--white-label .page-section--alt {
  background: transparent;
  border-top: 0;
  border-bottom: 0;
}

/* ---------------------------------------------------------------------------
   UPLIFT - treatments taken from the reference, in AIWA's palette
   Every value below was read off the reference's own stylesheet.

   Typography needed no change: the reference runs Inter for body text and so
   does AIWA (--font-body), and the brief keeps AIWA's display face for
   headings, so Bricolage Grotesque stays on every h1/h2.
   ------------------------------------------------------------------------ */

/* The spinning conic border needs an animatable angle, which only a
   registered custom property gives you - a plain var cannot be tweened. */
@property --wl-border-angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}
@keyframes wl-border-spin { to { --wl-border-angle: 360deg; } }

/* Reference: two backgrounds, fill on padding-box and the conic on
   border-box, with a transparent 1.5px border for the conic to show through.
   Their triad was violet/pink/amber; this is AIWA's accent ramp. */
.page--white-label .wl-spin-border {
  --wl-border-angle: 0deg;
  --wl-spin-fill: var(--ink-800);
  background:
    linear-gradient(var(--wl-spin-fill), var(--wl-spin-fill)) padding-box,
    conic-gradient(from var(--wl-border-angle),
      var(--accent), var(--accent-hot), var(--accent-deep), var(--accent)) border-box;
  border: 1.5px solid transparent;
  animation: 3.5s linear infinite wl-border-spin;
}

/* Pin lighting. Reference puts a top-centred glow at 80% 60% at 50% -10%,
   the accent held at 22%. The --alt sections lost their fill when the page
   went to one ground, so the alternation now reads as light instead of
   banding - same rhythm, no seams.
   The 20px dot grid rides on the same layer. */
.page--white-label .page-section--alt { position: relative; }
.page--white-label .page-section--alt::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    radial-gradient(80% 60% at 50% -10%,
      color-mix(in srgb, var(--accent) 22%, transparent), transparent),
    radial-gradient(circle at 1px 1px,
      color-mix(in srgb, var(--cream-050) 7%, transparent) 0.5px, transparent 0.52px);
  background-size: auto, 20px 20px;
  /* Fade the grid out before it reaches an edge so no rectangle shows. */
  -webkit-mask-image: radial-gradient(70% 70% at 50% 30%, #000 30%, transparent 85%);
  mask-image: radial-gradient(70% 70% at 50% 30%, #000 30%, transparent 85%);
}
.page--white-label .page-section--alt > .shell { position: relative; z-index: 1; }

/* Pricing: the featured plan takes the animated border, and the reference's
   nudge pulse drives attention to it. Their pulse was violet/pink; the ring
   and the drop here are the accent at the same 4px / 6px 20px -6px spread. */
@keyframes wl-plan-pulse {
  0%, 100% { box-shadow: 0 0 transparent; }
  50% {
    box-shadow:
      0 0 0 4px color-mix(in srgb, var(--accent) 22%, transparent),
      0 6px 20px -6px color-mix(in srgb, var(--accent-hot) 28%, transparent);
  }
}
.page--white-label #wl-pricing .plan--featured {
  --wl-border-angle: 0deg;
  --wl-spin-fill: var(--ink-800);
  background:
    linear-gradient(var(--wl-spin-fill), var(--wl-spin-fill)) padding-box,
    conic-gradient(from var(--wl-border-angle),
      var(--accent), var(--accent-hot), var(--accent-deep), var(--accent)) border-box;
  border: 1.5px solid transparent;
  animation: 3.5s linear infinite wl-border-spin;
}
.page--white-label #wl-pricing .plan--featured .plan__flag {
  animation: 2.8s ease-in-out infinite wl-plan-pulse;
  border-radius: 999px;
}

/* The call to action before the footer: same spinning border on its button,
   plus the grid and top light behind the section. */
.page--white-label #wl-final { position: relative; }
.page--white-label #wl-final .cta__inner { position: relative; z-index: 1; }
.page--white-label #wl-final .btn--primary {
  --wl-border-angle: 0deg;
  background:
    linear-gradient(var(--accent), var(--accent-hot)) padding-box,
    conic-gradient(from var(--wl-border-angle),
      var(--cream-050), var(--accent), var(--accent-deep), var(--cream-050)) border-box;
  border: 1.5px solid transparent;
  animation: 3.5s linear infinite wl-border-spin;
}

/* The reference guards every one of these behind reduced motion. */
@media (prefers-reduced-motion: reduce) {
  .page--white-label .wl-spin-border,
  .page--white-label #wl-pricing .plan--featured,
  .page--white-label #wl-pricing .plan--featured .plan__flag,
  .page--white-label #wl-final .btn--primary { animation: none; }
}

/* ---------------------------------------------------------------------------
   IDEA SECTION - REFERENCE ARRANGEMENT
   The reference runs this as one row rather than a centred head over two
   columns: a 1200px container, flex row, items centred, 64px between the
   columns, with the heading living INSIDE the narrow copy column (5/12) and
   the visual taking the wider one (7/12).

   Measured off it: max-width 1200, gap-16 (64px), w-5/12 + w-7/12, heading
   margin-bottom 24px, check rows 16px apart with 12px between badge and
   label, and each check sitting in a 20px circle at 20% fill on a 30%
   border. Colours are AIWA's accent, not the reference's emerald.
   ------------------------------------------------------------------------ */
/* The row fills the section's shell rather than the reference's fixed 1200,
   so both columns gain width: the headline settles onto fewer lines and the
   screenshot is rendered larger. The 5/7 proportion is kept. */
#wl-idea .wl-idea {
  grid-template-columns: 5fr 7fr;
  gap: 64px;
  align-items: center;
  max-width: none;
}

/* Stepped down from the page's t-h2 scale: at the copy column's width that
   scale broke this headline over six lines. */
#wl-idea .wl-idea__title {
  margin: 0 0 8px;
  font-size: clamp(1.7rem, 2.35vw, 2.2rem);
  line-height: 1.12;
  text-align: left;
  text-wrap: balance;
}

#wl-idea .wl-check-list { gap: 16px; }

#wl-idea .wl-check-list li {
  align-items: center;
  gap: 12px;
}

/* The badge is the svg itself - padding inside a bordered circle - so the
   markup stays a bare icon with no extra wrapper. */
#wl-idea .wl-check-list__icon {
  width: 20px;
  height: 20px;
  padding: 4px;
  margin-top: 0;
  box-sizing: border-box;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 20%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  color: var(--accent);
}

/* The soft mass the reference floats behind this row: 800x400, blurred 120px,
   held at 10%. Sits under the content, above the section's grid layer. */
#wl-idea::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 800px;
  height: 400px;
  translate: -50% -50%;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  filter: blur(120px);
  pointer-events: none;
  z-index: 0;
}

@media (max-width: 992px) {
  #wl-idea .wl-idea { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  #wl-idea .wl-idea__title { text-align: center; }
  /* The rest of the copy follows the centred headline. The check list is
     centred as a block but its rows stay left-aligned, so the three ticks keep
     one straight column instead of zig-zagging with each line's length. */
  #wl-idea .wl-idea__copy { justify-items: center; text-align: center; }
  #wl-idea .wl-check-list { text-align: left; }
  /* The CTA stack is start-aligned to sit under left-set copy on desktop,
     which left the trust strip hanging off the button's left edge here. */
  #wl-idea .wl-idea__copy .wl-cta-stack { align-items: center; }
}

/* ---------------------------------------------------------------------------
   IDEA COPY - FIT TO THE IMAGE
   The copy column ran 616px against the screenshot's 487. The body text was
   already at 16px, so the height came from the stack rather than the type:
   the five checks at 16px on 16px gaps were 192px on their own, and the six
   24px column gaps another 120.

   Checks drop to 14px on tighter gaps, the column gap comes in, and the punch
   line steps down a size. Line-heights are left generous so the block reads
   as settled rather than squeezed.
   ------------------------------------------------------------------------ */
/* The copy block reads as one settled column rather than a tight stack: the
   rhythm opens up, the checks breathe, and the body returns to 16px. It grows
   past the screenshot's height, which is fine - the two are centred on each
   other, so neither has to be the taller one. */
#wl-idea .wl-idea__copy { gap: 20px; }

#wl-idea .wl-idea__title { margin-bottom: 4px; line-height: 1.1; }

#wl-idea .wl-check-list { gap: 14px; }
#wl-idea .wl-check-list li {
  font-size: 15px;
  line-height: 1.6;
}
#wl-idea .wl-check-list__icon {
  width: 18px;
  height: 18px;
  padding: 3.5px;
}

#wl-idea .wl-idea__copy > p.t-body { font-size: 16px; line-height: 1.65; }

#wl-idea .wl-idea__punch { font-size: 20px; line-height: 1.2; }

#wl-idea .wl-idea__copy .wl-cta-stack { gap: 16px; margin-top: 4px; }

/* ---------------------------------------------------------------------------
   PAIN SECTION
   Five measured faults, all structural:

   1. The head sat in an 896px box with no auto margins, so centring its text
      placed it at 506 while the cards centred at 715 - the section read as
      left-aligned heading over centred content.
   2. The grid was capped at 46rem, so 736px of cards floated in a 1430px
      shell with 347px dead on each side.
   3. The two panels carried wildly unequal weight: a 4.5% cream wash against
      a fully saturated accent fill. In a comparison the emphasis should come
      from the content, not from one side being a billboard.
   4. Rows did not line up across the columns (64/47/47/47 vs 64/64/47/64),
      which in a side-by-side is the one thing that must.
   5. The two column headers were different species - a plain 24px title
      against a 19px pill.
   ------------------------------------------------------------------------ */

/* 1 - heading centres on the same axis as the cards */
#wl-pain .page-section__head {
  max-width: 896px;
  margin-inline: auto;
  text-align: center;
}

/* 2 - the comparison uses the room it has */
#wl-pain .wl-pain {
  max-width: 64rem;
  gap: 24px;
}

/* 3 - equal structure, emphasis carried by the accent rather than a fill */
#wl-pain .wl-pain__col--good {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 7%, var(--ink-800));
}
#wl-pain .wl-pain__col--good .wl-pain__list li {
  border-color: color-mix(in srgb, var(--accent) 22%, transparent);
  background: color-mix(in srgb, var(--ink-950) 55%, transparent);
  color: var(--cream-100);
}

/* 4 - every row the same height, so the two lists read across */
#wl-pain .wl-pain__list li { min-height: 56px; }

/* 5 - both headers take the lander's .hl-eyebrow row rather than a centred
   pill: a dot, the label in mono, then hatching that eats whatever slack is
   left, all held between two 1px rules. Same structure in both columns, told
   apart by colour alone - neutral on the left, accent on the right.

   Geometry is the hero's (40px row, 7px dot, 0.875rem mono, 15px hatch at
   115deg on a 6px pitch, 50%), but the tokens are this page's own: hero.css
   reads --mono / --cream-2 / --rule, which are local aliases that do not
   resolve here. The hatch is flex: 1 1 auto with no ratio, so the row works at
   whatever width the column happens to be. */
#wl-pain .wl-pain__title,
#wl-pain .wl-pain__badge {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  box-sizing: border-box;
  justify-self: stretch;
  width: 100%;
  height: 2.5rem;
  margin: 2px 0 10px;
  padding: 0;
  border-radius: 0;
  border-inline: 0;
  background: none;
  font-family: var(--font-mono);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.5;
  text-align: left;
}

#wl-pain .wl-pain__dot {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
}
#wl-pain .wl-pain__t { flex: none; }
#wl-pain .wl-pain__hatch {
  flex: 1 1 auto;
  min-width: 2rem;
  height: 15px;
  opacity: 0.5;
}

#wl-pain .wl-pain__title {
  /* The lander's rule is cream at 10%, not --ink-600: against the card fill
     --ink-600 is all but invisible, and 10% cream is the reference value. */
  border-block: 1px solid color-mix(in srgb, var(--cream-050) 10%, transparent);
  color: var(--cream-300);
}
#wl-pain .wl-pain__title .wl-pain__dot { background: var(--cream-300); }
#wl-pain .wl-pain__title .wl-pain__hatch {
  background: repeating-linear-gradient(115deg, var(--cream-300) 0 1px, transparent 1px 6px);
}

#wl-pain .wl-pain__badge {
  border-block: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  color: var(--accent);
}
#wl-pain .wl-pain__badge .wl-pain__dot { background: var(--accent); }
#wl-pain .wl-pain__badge .wl-pain__hatch {
  background: repeating-linear-gradient(115deg, var(--accent) 0 1px, transparent 1px 6px);
}

/* ---------------------------------------------------------------------------
   INCLUDED FEATURES - ANIMATED UI CARDS
   Two per row, copy beside a live UI screen. Each screen animates the thing
   its card describes rather than being decoration: a field types, a meter
   fills, console rows arrive, a charge clears.

   Thin-padding principle from the reference: the card's own padding is small
   and the screen's inner gutter smaller still, so the UI reads as filling its
   frame rather than floating in it. Every card is the same height, so the
   grid stays level whatever the copy length.

   Everything is CSS - no JS, no images beyond the AIWA mark - so the screens
   cost nothing to load and stop entirely under reduced motion.
   ------------------------------------------------------------------------ */
#wl-included .wl-included-rows {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
  align-items: stretch;
}

.wl-feat {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 18px;
  align-items: center;
  /* No min-height: the 232px screen plus 12px top and bottom sets the card,
     so the gutter is an even 12px on all four sides rather than 12 at the
     sides and 22 above and below. Cards stay equal because the screen is a
     fixed height and the copy is shorter than it. */
  min-height: 0;
  padding: 12px;
  border: 1px solid var(--ink-600);
  border-radius: 16px;
  background: var(--surface-fill-soft);
}

.wl-feat__copy { display: grid; gap: 8px; align-content: center; }

.wl-feat__eyebrow {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}
.wl-feat__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(17px, 1.35vw, 20px);
  font-weight: 500;
  line-height: 1.2;
  color: var(--cream-050);
}
.wl-feat__desc {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--cream-400);
}

/* ---- the screen ---------------------------------------------------------- */
.wl-feat__art { min-width: 0; }

.wl-feat__screen {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  gap: 6px;
  height: 232px;
  padding: 7px;                     /* the thin gutter */
  border: 1px solid var(--ink-600);
  border-radius: 12px;
  background: var(--ink-950);
  /* faint enough to read as texture rather than a visible pattern */
  background-image: radial-gradient(circle, color-mix(in srgb, var(--cream-050) 7%, transparent) 1px, transparent 1px);
  background-size: 18px 18px;
  overflow: hidden;
  font-family: var(--font-mono);
}

.wl-feat__bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 7px;
  border: 1px solid color-mix(in srgb, var(--cream-050) 7%, transparent);
  border-radius: 7px;
  background: color-mix(in srgb, var(--cream-050) 3%, transparent);
}
.f-logo { display: block; width: 13px; height: 13px; flex: 0 0 auto; border-radius: 3px; }
.f-path { flex: 1 1 auto; font-size: 9.5px; color: var(--cream-500); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.f-live {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 8.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--accent);
}
.f-live::before {
  content: ''; width: 5px; height: 5px; border-radius: 50%;
  background: var(--accent); animation: f-pulse 2s ease-in-out infinite;
}

.wl-feat__stage {
  position: relative;
  display: grid;
  align-content: start;
  gap: 6px;
  padding: 8px;
  border: 1px solid color-mix(in srgb, var(--cream-050) 6%, transparent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--ink-950) 72%, transparent);
  overflow: hidden;
}

/* ---- primitives ---------------------------------------------------------- */
.f-row, .f-trow {
  display: flex; align-items: center; gap: 6px;
  font-size: 10px; color: var(--cream-300);
  opacity: 0;
  animation: f-in 6s ease-in-out infinite;
  animation-delay: calc(var(--i) * .45s);
}
.f-tick, .f-dot { flex: 0 0 auto; width: 11px; height: 11px; border-radius: 50%; }
.f-tick {
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  position: relative;
}
.f-tick::after {
  content: ''; position: absolute; inset: 0; margin: auto;
  width: 4px; height: 2px; border-left: 1.5px solid var(--accent); border-bottom: 1.5px solid var(--accent);
  transform: rotate(-45deg) translate(0.5px, -0.5px);
}
.f-dot { background: color-mix(in srgb, var(--cream-050) 18%, transparent); }

.f-list { display: grid; gap: 6px; }
.f-line {
  display: block; height: 5px; border-radius: 3px;
  background: color-mix(in srgb, var(--cream-050) 8%, transparent);
}
.f-line--wide { width: 78%; } .f-line--short { width: 42%; }

.f-stamp, .f-saved {
  justify-self: start;
  display: inline-flex; align-items: center; gap: 5px;
  margin-top: 2px; padding: 3px 8px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  font-size: 9px; letter-spacing: .06em; text-transform: uppercase; color: var(--accent);
  opacity: 0; animation: f-stamp 6s ease-in-out infinite;
}

.f-label { font-size: 9px; letter-spacing: .08em; text-transform: uppercase; color: var(--cream-500); }
.f-field, .f-url, .f-prompt {
  display: flex; align-items: center; gap: 5px;
  padding: 6px 8px;
  border: 1px solid color-mix(in srgb, var(--cream-050) 9%, transparent);
  border-radius: 6px;
  background: color-mix(in srgb, var(--cream-050) 3%, transparent);
  font-size: 10px; color: var(--cream-100);
  overflow: hidden;
}
.f-type {
  display: inline-block; overflow: hidden; white-space: nowrap;
  max-width: 100%;
  animation: f-typing 6s steps(26, end) infinite;
}
.f-caret {
  flex: 0 0 auto; width: 1px; height: 11px;
  background: var(--accent);
  animation: f-blink 1s steps(1) infinite;
}
.f-lock { flex: 0 0 auto; width: 7px; height: 8px; border: 1.5px solid var(--accent); border-radius: 2px; }
.f-spark { flex: 0 0 auto; width: 9px; height: 9px; background: var(--accent); clip-path: polygon(50% 0, 61% 39%, 100% 50%, 61% 61%, 50% 100%, 39% 61%, 0 50%, 39% 39%); }

.f-screen-mini { display: grid; gap: 5px; padding: 7px; border-radius: 6px; background: color-mix(in srgb, var(--cream-050) 2.5%, transparent); }

/* brand */
.f-preview {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 8px; border-radius: 6px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  animation: f-tint 6s ease-in-out infinite;
}
.f-preview__mark { display: grid; place-items: center; width: 18px; height: 18px; border-radius: 5px; background: var(--ink-950); }
.f-preview__name { font-size: 10px; color: var(--cream-050); }
.f-swatches { display: flex; gap: 5px; }
.f-swatch {
  width: 20px; height: 20px; border-radius: 5px;
  background: var(--accent);
  animation: f-swatch 6s ease-in-out infinite;
  animation-delay: calc(var(--i) * .3s);
}

/* table */
.f-thead, .f-trow { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 9.5px; }
.f-thead { color: var(--cream-500); letter-spacing: .06em; text-transform: uppercase; padding-bottom: 4px; border-bottom: 1px solid color-mix(in srgb, var(--cream-050) 7%, transparent); }
.f-list--rows { gap: 5px; margin-top: 2px; }
.f-trow { padding: 4px 0; color: var(--cream-300); }
.f-trow b { color: var(--accent); font-weight: 500; }

/* plans */
.f-plans { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.f-plan {
  display: grid; gap: 2px; padding: 8px 7px; border-radius: 7px;
  border: 1px solid color-mix(in srgb, var(--cream-050) 8%, transparent);
  background: color-mix(in srgb, var(--cream-050) 2.5%, transparent);
  font-size: 9px; color: var(--cream-400);
  animation: f-highlight 6s ease-in-out infinite;
  animation-delay: calc(var(--i) * 3s);
}
.f-plan b { font-size: 15px; font-weight: 500; color: var(--cream-050); }
.f-plan__per { font-size: 8.5px; color: var(--cream-500); }

/* pay + meter */
.f-pay { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.f-pay__amt { font-size: 17px; color: var(--cream-050); }
.f-pay__to { font-size: 9px; color: var(--cream-500); }
.f-track { height: 6px; border-radius: 4px; background: color-mix(in srgb, var(--cream-050) 7%, transparent); overflow: hidden; }
.f-track__fill { display: block; height: 100%; width: 0; border-radius: 4px; background: linear-gradient(90deg, var(--accent), var(--accent-hot)); animation: f-fill 6s ease-in-out infinite; }
.f-track__fill--slow { animation-duration: 6s; }
.f-meterhead { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: 9.5px; color: var(--cream-500); }
.f-count { font-size: 16px; font-weight: 500; color: var(--accent); }
.f-legend { display: flex; flex-wrap: wrap; gap: 4px; }
.f-legend span {
  padding: 2px 6px; border-radius: 999px; font-size: 8.5px; color: var(--cream-400);
  background: color-mix(in srgb, var(--cream-050) 5%, transparent);
  opacity: 0; animation: f-in 6s ease-in-out infinite; animation-delay: calc(var(--i) * .45s);
}

/* build */
.f-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 2px; }
.f-tile {
  height: 34px; border-radius: 6px;
  border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  opacity: 0; transform: scale(.94);
  animation: f-pop 6s ease-in-out infinite;
  animation-delay: calc(2.4s + var(--i) * .3s);
}

/* ---- keyframes ----------------------------------------------------------- */
@keyframes f-in {
  0%, 8% { opacity: 0; transform: translateX(-4px); }
  22%, 82% { opacity: 1; transform: none; }
  96%, 100% { opacity: 0; transform: translateX(-4px); }
}
@keyframes f-stamp {
  0%, 62% { opacity: 0; transform: translateY(3px); }
  74%, 92% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translateY(3px); }
}
@keyframes f-typing { 0% { width: 0; } 45%, 88% { width: 100%; } 100% { width: 0; } }
@keyframes f-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes f-fill { 0%, 10% { width: 0; } 58%, 88% { width: 100%; } 100% { width: 0; } }
@keyframes f-pulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
@keyframes f-pop {
  0%, 10% { opacity: 0; transform: scale(.94); }
  30%, 86% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: scale(.94); }
}
@keyframes f-swatch {
  0%, 100% { background: var(--accent); }
  33% { background: var(--accent-hot); }
  66% { background: var(--accent-deep); }
}
@keyframes f-tint {
  0%, 100% { background: color-mix(in srgb, var(--accent) 14%, transparent); }
  33% { background: color-mix(in srgb, var(--accent-hot) 14%, transparent); }
  66% { background: color-mix(in srgb, var(--accent-deep) 16%, transparent); }
}
@keyframes f-highlight {
  0%, 44%, 100% { border-color: color-mix(in srgb, var(--cream-050) 8%, transparent); background: color-mix(in srgb, var(--cream-050) 2.5%, transparent); }
  10%, 34% { border-color: color-mix(in srgb, var(--accent) 45%, transparent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
}

@media (prefers-reduced-motion: reduce) {
  .wl-feat__art *,
  .wl-feat__art *::before { animation: none !important; opacity: 1 !important; transform: none !important; }
  .f-type { width: 100% !important; }
  .f-track__fill { width: 100% !important; }
}

@media (max-width: 1100px) {
  #wl-included .wl-included-rows { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 620px) {
  .wl-feat { grid-template-columns: minmax(0, 1fr); min-height: 0; }
  .wl-feat__screen { height: 210px; }
}

/* ---------------------------------------------------------------------------
   FEATURE CARDS - ALTERNATING SIDES ON TABLET
   Between 621 and 1100 the grid is one card per row but the card itself is
   still side by side, so every illustration would land on the same edge and
   the column would read as a single rail. Even cards flip: art left, copy
   right.

   The track widths are swapped with the order, so the illustration keeps the
   wider 1.08fr column on both sides rather than shrinking every time it moves
   left.
   ------------------------------------------------------------------------ */
@media (min-width: 621px) and (max-width: 1100px) {
  #wl-included .wl-feat:nth-child(even) {
    grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
  }
  #wl-included .wl-feat:nth-child(even) .wl-feat__art { order: -1; }
}

/* ---------------------------------------------------------------------------
   FEATURE CARDS - ALTERNATING ILLUSTRATION SIDE (TABLET ONLY)
   Between 621 and 1100 the grid is one card per row but the card is still
   side by side, so without this every illustration lands on the same edge and
   the column reads as one long rail. Even cards flip: art left, copy right.

   The track widths swap with the order, so the illustration keeps the wider
   1.08fr column on either side rather than shrinking when it moves left.

   Outside this band nothing changes: at two per row the desktop grid already
   breaks the repetition, and below 621 the card stacks, where there is no
   left or right to alternate.
   ------------------------------------------------------------------------ */
@media (min-width: 621px) and (max-width: 1100px) {
  #wl-included .wl-feat:nth-child(even) {
    grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
  }
  #wl-included .wl-feat:nth-child(even) .wl-feat__art { order: -1; }
}

/* ---------------------------------------------------------------------------
   IDEA LIGHT - scroll-driven overhead lamp
   Lifted from the Suprema reference's Product Overview light. The transform is
   scroll-linked and perfectly linear; measured off the source:
       scroll    scale      translateY
            0    0.5264      -26.88
          100    0.7344      -20.48
          420    1.4           0      (clamped from here on)
   i.e. 0.00208 scale/px and 0.064px/px across one 420px run, transform-origin
   centre, with opacity and filter untouched throughout. Because it is a scrub
   it plays backwards on the way up, which is the opening/closing read.

   The source PNG is a white glow on black, so its alpha channel is useless as
   a mask - the glow lives in the luminance. idea-light-mask.png is that
   luminance baked into the alpha channel, which keeps the light's exact shape
   while letting the fill be AIWA amber, matching the ambience #wl-idea::after
   already casts rather than the reference's white.

   Sits at z-index 0: over the section's ::before dot grid (same layer, earlier
   in paint order), under `> .shell`, which is already relative/z-index 1. The
   bar itself is 50.4% down the image, so centring the box on the section's top
   edge lands the bar on that edge, exactly as the reference does.
   ------------------------------------------------------------------------ */
.wl-idea-light {
  position: absolute;
  top: 0;
  left: 50%;
  z-index: 0;
  width: min(1228px, 94vw);
  aspect-ratio: 1201 / 611;
  translate: -50% -50%;
  /* translate before scale, so translateY stays unscaled as in the source */
  transform: translateY(-26.88px) scale(0.5264);
  transform-origin: 50% 50%;
  will-change: transform;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--accent) 62%, #fff) 0%,
    color-mix(in srgb, var(--accent) 58%, #fff) 49%,
    var(--accent) 57%,
    var(--accent-hot) 74%,
    var(--accent-deep) 100%
  );
  -webkit-mask-image: url("/wl-assets/images/wl/idea-light-mask.png?v=f6bb9f1382");
  mask-image: url("/wl-assets/images/wl/idea-light-mask.png?v=f6bb9f1382");
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

/* Nothing to scrub through, so it rests at the end of the run. */
@media (prefers-reduced-motion: reduce) {
  .wl-idea-light { transform: scale(1.4); }
}

/* 60px of extra room under the light, so the lamp has space to fall before the
   copy starts. Only the top grows - the section's base block padding
   (clamp(3.5rem, 8vh, 6rem)) still sets the bottom and the responsive floor.
   The light is anchored to the section's top edge, not its content box, so it
   does not move with this. */
.page--white-label #wl-idea { padding-top: calc(clamp(3.5rem, 8vh, 6rem) + 60px); }

/* ---------------------------------------------------------------------------
   TYPE UNIFICATION
   Three families, one role each, everywhere on this page:

     header   var(--font-display)  Bricolage Grotesque - h1-h4, section heads,
                                   card titles, and the two rare punch lines
                                   (.wl-callout__lead, .wl-idea__punch)
     subtext  var(--font-body)     Inter - every paragraph, lead, caption and
                                   list of content, plus button labels
     in-line  var(--font-mono)     JetBrains Mono - every small label, eyebrow
                                   and kicker, plus code, domains and figures

   DEVIATION, DELIBERATE: page.css's type hierarchy puts in-card labels
   (.wl-card-label) in the BODY font and reserves mono for .eyebrow above a
   .t-h2. This page runs mono for every small label instead, which is why all
   of this is scoped to .page--white-label - the contract still holds for every
   other page that uses these same classes.

   The house label treatment is .wl-feat__eyebrow's: mono, uppercase, 0.12em.
   Labels that were on the body font are brought onto it whole rather than
   only swapping family, so they actually match.
   ------------------------------------------------------------------------ */

/* in-line: labels that were on the body font */
.page--white-label .wl-card-label,
.page--white-label #wl-faq .faq__tag {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
/* The tag's icon was set against 18px text; hold it to the smaller label. */
.page--white-label #wl-faq .faq__tag .ph { font-size: 14px; }

/* subtext: lists of content that were on the mono font. These are body-size
   reading copy, not labels - the label-role mono (flow nodes, numerals, rate
   cards, domains, code) is left alone. */
.page--white-label .wl-model ul li,
.page--white-label .wl-final-bonuses li {
  font-family: var(--font-body);
  letter-spacing: normal;
}

/* ---------------------------------------------------------------------------
   FEATURE STAGE - SIGN IN (the branding card)
   The branding card's copy promises the loading screen, the sign-in page and
   the workspace all carry the partner's identity, so the stage shows the
   sign-in itself rather than colour swatches - those belong to Custom Brand
   Colors, which still uses the `brand` archetype.

   One 6s loop, the same clock every other stage runs on, so the seventeen
   cards stay in step. The beats, as percentages of it:
       10-34%  email field focused, address types in
       40-60%  password field focused, dots fill
       60-70%  cursor travels to the button
       71-77%  the click, button presses under it
       74-92%  "Signed in" (the shared .f-saved / f-stamp pair, whose timing
               already lands right after the click - no new keyframe needed)
   ------------------------------------------------------------------------ */
[data-art="signin"] .wl-feat__stage { gap: 5px; }

[data-art="signin"] .f-signin__brand { display: flex; align-items: center; gap: 6px; }
[data-art="signin"] .f-signin__name { font-size: 10px; color: var(--cream-050); }
[data-art="signin"] .f-signin__welcome { margin: 0 0 1px; font-size: 9px; color: var(--cream-500); }
[data-art="signin"] .f-signin__key {
  flex: 0 0 auto;
  font-size: 8px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--cream-500);
}

/* The cursor is anchored to the button's own box rather than the stage, so it
   lands dead centre on it whatever the card's width works out to be. */
[data-art="signin"] .f-signin__act { position: relative; margin-top: 1px; }
[data-art="signin"] .f-signin__btn {
  display: grid; place-items: center;
  padding: 7px 8px;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--accent), var(--accent-hot));
  font-size: 10px; font-weight: 500; color: var(--ink-950);
  animation: f-signin-press 6s ease-in-out infinite;
}
[data-art="signin"] .f-cursor {
  position: absolute; left: 50%; top: 50%;
  width: 11px; height: 14px;
  margin: -2px 0 0 -2px;
  background: var(--cream-050);
  clip-path: polygon(0 0, 0 74%, 26% 57%, 45% 97%, 63% 88%, 45% 50%, 80% 47%);
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .65));
  opacity: 0;
  pointer-events: none;
  animation: f-signin-cursor 6s cubic-bezier(.4, 0, .2, 1) infinite;
}

[data-art="signin"] .f-field--a { animation: f-signin-focus-a 6s ease-in-out infinite; }
[data-art="signin"] .f-field--b { animation: f-signin-focus-b 6s ease-in-out infinite; }
[data-art="signin"] .f-type--a { animation: f-signin-type-a 6s steps(17, end) infinite; }
[data-art="signin"] .f-type--b { animation: f-signin-type-b 6s steps(10, end) infinite; letter-spacing: 1px; }
/* Blink runs on opacity, the gate on visibility, so the two do not fight. */
[data-art="signin"] .f-caret--a { animation: f-blink 1s steps(1) infinite, f-signin-gate-a 6s steps(1) infinite; }
[data-art="signin"] .f-caret--b { animation: f-blink 1s steps(1) infinite, f-signin-gate-b 6s steps(1) infinite; }

@keyframes f-signin-focus-a {
  0%, 6%, 38%, 100% {
    border-color: color-mix(in srgb, var(--cream-050) 9%, transparent);
    background: color-mix(in srgb, var(--cream-050) 3%, transparent);
  }
  10%, 34% {
    border-color: color-mix(in srgb, var(--accent) 45%, transparent);
    background: color-mix(in srgb, var(--accent) 10%, transparent);
  }
}
@keyframes f-signin-focus-b {
  0%, 36%, 64%, 100% {
    border-color: color-mix(in srgb, var(--cream-050) 9%, transparent);
    background: color-mix(in srgb, var(--cream-050) 3%, transparent);
  }
  40%, 60% {
    border-color: color-mix(in srgb, var(--accent) 45%, transparent);
    background: color-mix(in srgb, var(--accent) 10%, transparent);
  }
}
@keyframes f-signin-type-a { 0%, 10% { width: 0; } 32%, 96% { width: 100%; } 100% { width: 0; } }
@keyframes f-signin-type-b { 0%, 40% { width: 0; } 58%, 96% { width: 100%; } 100% { width: 0; } }
@keyframes f-signin-gate-a { 0%, 9% { visibility: hidden; } 10%, 35% { visibility: visible; } 36%, 100% { visibility: hidden; } }
@keyframes f-signin-gate-b { 0%, 39% { visibility: hidden; } 40%, 61% { visibility: visible; } 62%, 100% { visibility: hidden; } }
@keyframes f-signin-press {
  0%, 70% { transform: none; filter: none; }
  73% { transform: scale(.965); filter: brightness(1.18); }
  77%, 100% { transform: none; filter: none; }
}
@keyframes f-signin-cursor {
  0%, 56%   { opacity: 0; transform: translate(44px, 32px) scale(1); }
  60%       { opacity: 1; transform: translate(44px, 32px) scale(1); }
  70%       { opacity: 1; transform: translate(0, 0) scale(1); }
  73%       { opacity: 1; transform: translate(0, 0) scale(.76); }
  77%, 92%  { opacity: 1; transform: translate(0, 0) scale(1); }
  100%      { opacity: 0; transform: translate(44px, 32px) scale(1); }
}

/* ---------------------------------------------------------------------------
   FEATURE STAGE - LOGO UPLOAD (the custom logo card)
   A logo file is dragged into an upload field, uploads, and lands as the mark
   in the preview beneath it - the card's actual promise, where before it
   showed the colour swatches that belong to Custom Brand Colors.

   The same 6s loop as every other stage. The beats:
       10-30%  the file travels from off-stage into the zone
       30-38%  it drops, the zone takes the accent
       38-54%  the upload bar fills
       46-95%  the zone's message swaps to the filename
       56-95%  the mark appears in the preview, caption follows it
   ------------------------------------------------------------------------ */
[data-art="logo"] .wl-feat__stage { gap: 6px; }

[data-art="logo"] .f-up { position: relative; }
[data-art="logo"] .f-up__zone {
  display: grid;
  place-items: center;
  gap: 7px;
  height: 74px;
  padding: 8px;
  border: 1px dashed color-mix(in srgb, var(--cream-050) 16%, transparent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--cream-050) 2.5%, transparent);
  animation: f-up-zone 6s ease-in-out infinite;
}
/* Both messages occupy one cell, so the swap cannot move anything. */
[data-art="logo"] .f-up__msg { display: grid; }
[data-art="logo"] .f-up__msg > * { grid-area: 1 / 1; }
[data-art="logo"] .f-up__hint {
  font-size: 9.5px; color: var(--cream-500);
  animation: f-up-hint 6s ease-in-out infinite;
}
[data-art="logo"] .f-up__done {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 9.5px; color: var(--accent);
  opacity: 0;
  animation: f-up-done 6s ease-in-out infinite;
}
[data-art="logo"] .f-up__track {
  width: 64%; height: 4px;
  border-radius: 3px;
  background: color-mix(in srgb, var(--cream-050) 8%, transparent);
  overflow: hidden;
}
[data-art="logo"] .f-up__fill {
  display: block; height: 100%; width: 0;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--accent), var(--accent-hot));
  animation: f-up-fill 6s ease-in-out infinite;
}

/* The dragged file, parked off the zone's top-right corner between passes. */
[data-art="logo"] .f-up__file {
  position: absolute; left: 50%; top: 50%;
  display: grid; place-items: center;
  width: 26px; height: 26px;
  margin: -13px 0 0 -13px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 7px;
  background: var(--ink-950);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .55);
  opacity: 0;
  pointer-events: none;
  animation: f-up-file 6s cubic-bezier(.4, 0, .2, 1) infinite;
}
[data-art="logo"] .f-up__file .f-logo { width: 15px; height: 15px; }

[data-art="logo"] .f-up__preview {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 6px;
  height: 78px;
  border: 1px solid color-mix(in srgb, var(--cream-050) 6%, transparent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--cream-050) 2%, transparent);
}
[data-art="logo"] .f-up__slot {
  display: grid; place-items: center;
  width: 32px; height: 32px;
  border-radius: 9px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  opacity: 0;
  animation: f-up-slot 6s cubic-bezier(.3, 1.4, .5, 1) infinite;
}
[data-art="logo"] .f-up__slot .f-logo { width: 19px; height: 19px; }
[data-art="logo"] .f-up__cap {
  font-size: 9px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--cream-400);
  opacity: 0;
  animation: f-up-cap 6s ease-in-out infinite;
}

/* Comes in from BELOW right, not above: the zone's label sits across the top,
   and a path from the top-right dragged the tile straight through the words. */
@keyframes f-up-file {
  0%, 6%   { opacity: 0; transform: translate(66px, 38px) scale(.88); }
  10%      { opacity: 1; transform: translate(66px, 38px) scale(.88); }
  30%      { opacity: 1; transform: translate(0, 0) scale(1); }
  34%      { opacity: 1; transform: translate(0, 0) scale(.84); }
  40%, 100% { opacity: 0; transform: translate(0, 0) scale(.78); }
}
@keyframes f-up-zone {
  0%, 12%, 64%, 100% {
    border-color: color-mix(in srgb, var(--cream-050) 16%, transparent);
    background: color-mix(in srgb, var(--cream-050) 2.5%, transparent);
  }
  20%, 58% {
    border-color: color-mix(in srgb, var(--accent) 45%, transparent);
    background: color-mix(in srgb, var(--accent) 9%, transparent);
  }
}
/* Clears before the file gets there, so the tile never lands on the words. */
@keyframes f-up-hint { 0%, 20% { opacity: 1; } 28%, 92% { opacity: 0; } 98%, 100% { opacity: 1; } }
@keyframes f-up-done { 0%, 40% { opacity: 0; } 46%, 92% { opacity: 1; } 97%, 100% { opacity: 0; } }
@keyframes f-up-fill { 0%, 38% { width: 0; } 54%, 92% { width: 100%; } 97%, 100% { width: 0; } }
@keyframes f-up-slot {
  0%, 50%   { opacity: 0; transform: scale(.6); }
  58%, 92%  { opacity: 1; transform: scale(1); }
  98%, 100% { opacity: 0; transform: scale(.6); }
}
@keyframes f-up-cap {
  0%, 58%   { opacity: 0; transform: translateY(3px); }
  66%, 92%  { opacity: 1; transform: none; }
  98%, 100% { opacity: 0; transform: translateY(3px); }
}

/* ---------------------------------------------------------------------------
   MODEL CARDS - TAG PILLS
   The list was one bordered, filled panel with its items laid out on a grid.
   The panel's fill, border and 20px padding come off, and each item becomes
   its own pill instead: a wrapping flex row, 8px apart, 16px of padding top
   and bottom. Applied to all three cards so the row stays consistent, not
   just to the first.
   ------------------------------------------------------------------------ */
#wl-models .wl-model ul {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 8px;
  padding: 0;
  border: 0;
  background: none;
}
/* All three cards hold their pills to exactly two rows. Left to natural
   wrapping that only survived at ~1600px wide - by 1500 the columns had
   narrowed enough that card 01's second row and card 02's pairs both broke to
   three rows, and 1440/1366 are ordinary laptop widths, not edge cases.

   So the side padding and the type scale with the column: 18px/16px at 1604
   down to 5px/10.5px at 992, where .wl-models goes single-column and the
   question stops applying. The padding is the same on all four sides, so the
   top and bottom follow the same ramp as the sides.
   Both ramps are linear between those two points; the floor is set by card
   02, whose paired pills are the widest thing that has to fit two-up. */
#wl-models .wl-model ul li {
  padding: clamp(5px, 2.124vw - 16.1px, 18px);
  border: 1px solid var(--ink-600);
  border-radius: 999px;
  background: var(--surface-fill-soft);
  font-size: clamp(10.5px, 0.899vw + 1.6px, 16px);
  line-height: 1.2;
}
/* Single column: no two-row limit to protect, so the ramp's 5px floor would
   only cramp the pills. A flat 12px all round instead. */
@media (max-width: 992px) {
  #wl-models .wl-model ul li { padding: 12px; }
}

/* ---------------------------------------------------------------------------
   PRICING - REFERENCE REBUILD
   Every value below was read off the reference's own computed styles rather
   than the screenshot. The palette is AIWA's; the geometry and structure are
   the reference's.

   Carried over verbatim:
     section        padding-block 90px
     grid overlay   two 1px gradients at 32px 32px, under a
                    radial-gradient(ellipse at center, #000 10%, transparent 70%)
     head           max-width 720px, centred, 16px rhythm
     eyebrow        13.125px uppercase, letter-spacing .328px, in a pill
     h2             56.25px / 56.25px, letter-spacing -1.40625px
     lead           18.75px / 26.25px
     frame          1px border, three stacked rows, 1px dividers between cells
     column         min-height 280px, padding 30px, featured one a darker fill
     price          45px / 45px, weight 800, letter-spacing -2.25px
     per / billed   13.125px
     credits label  11px, weight 600, uppercase, letter-spacing .88px
     helper         11px / 15.125px
     corner marks   23px squares centred on the frame's four corners

   The beam uses the reference's technique exactly: an overlay with a
   TRANSPARENT 1px border and two stacked masks - one clipped to padding-box,
   one to border-box - composited with `intersect`, which leaves only the 1px
   ring visible. A square carrying the gradient orbits inside, so the ring
   lights wherever the square currently is. Their ramp ran violet to pink to
   amber; this is AIWA's accent, accent-hot, accent-deep.
   ------------------------------------------------------------------------ */
.wl-price {
  position: relative;
  padding-block: 90px;
  overflow: hidden;
}

/* 32px rule grid, faded toward the edges by the reference's own mask. */
.wl-price__grid-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(90deg, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    linear-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 32px 32px;
  -webkit-mask-image: radial-gradient(ellipse at center, #000 10%, transparent 70%);
  mask-image: radial-gradient(ellipse at center, #000 10%, transparent 70%);
}

.wl-price__inner { position: relative; z-index: 1; }

.wl-price__head {
  display: grid;
  justify-items: center;
  gap: 16px;
  max-width: 720px;
  margin: 0 auto 40px;
  text-align: center;
}
.wl-price__eyebrow {
  margin: 0;
  padding: 6px 16px;
  border: 1px solid var(--ink-600);
  border-radius: 999px;
  background: var(--surface-fill-soft);
  font-family: var(--font-mono);
  font-size: 13.125px;
  letter-spacing: 0.328px;
  text-transform: uppercase;
  color: var(--cream-400);
}
.wl-price__h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2rem, 3.6vw, 56.25px);
  line-height: 1;
  letter-spacing: -1.40625px;
  font-weight: 500;
  color: var(--cream-050);
  text-wrap: balance;
}
.wl-price__lead {
  margin: 0;
  font-size: 18.75px;
  line-height: 26.25px;
  color: var(--cream-300);
}

/* The corner marks straddle the frame's edge, so the frame cannot clip them -
   the border and the dividers live on .wl-price__table inside it. */
.wl-price__frame {
  position: relative;
  /* Same 52rem as .wl-pricing-trust below it, so the table and the trust bar
     are exactly the same width. Narrower than the reference's 1155px, which
     filled far too much of this page's wider shell. */
  max-width: 52rem;
  margin-inline: auto;
}
/* Opaque, deliberately: --surface-fill-soft is a color-mix against
   transparent, which let the 32px grid read straight through the table. The
   reference's cells are solid (#18181b / #0f0f11) so the grid stays behind. */
.wl-price__table {
  overflow: hidden;
  border: 1px solid var(--ink-600);
  background: var(--ink-800);
}

.wl-price__corner {
  position: absolute;
  z-index: 2;
  width: 23px;
  height: 23px;
  translate: -50% -50%;
  color: var(--ink-500);
  background-image: linear-gradient(currentColor 0 0), linear-gradient(currentColor 0 0);
  background-size: 11px 1px, 1px 11px;
  background-position: center, center;
  background-repeat: no-repeat;
  pointer-events: none;
}
.wl-price__corner--tl { top: 0; left: 0; }
.wl-price__corner--tr { top: 0; left: 100%; }
.wl-price__corner--bl { top: 100%; left: 0; }
.wl-price__corner--br { top: 100%; left: 100%; }

/* Three stacked rows, each a column grid with 1px dividers between cells and a
   rule under all but the last - the reference's `divide-x` plus `border-b`. */
.wl-price__row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.wl-price__row--plans,
.wl-price__row--cta { border-bottom: 1px solid var(--ink-600); }
.wl-price__row > .wl-price__col + .wl-price__col { border-left: 1px solid var(--ink-600); }

.wl-price__col {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 30px;
  background: var(--ink-800);
}
.wl-price__row--plans > .wl-price__col { min-height: 280px; }
.wl-price__col--featured { background: var(--ink-950); }

.wl-price__topline { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.wl-price__name {
  margin: 0;
  font-family: var(--font-display);
  font-size: 18.75px;
  line-height: 26.25px;
  font-weight: 700;
  color: var(--cream-050);
}
.wl-price__flag {
  padding: 2px 10px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), var(--accent-hot));
  font-size: 11.25px;
  line-height: 15px;
  font-weight: 600;
  color: var(--ink-950);
}
.wl-price__desc {
  min-height: 3rem;
  margin: 8px 0 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--cream-300);
}
.wl-price__amount {
  margin: 12px 0 0;
  font-family: var(--font-display);
  font-size: 45px;
  line-height: 45px;
  font-weight: 800;
  letter-spacing: -2.25px;
  color: var(--cream-050);
}
.wl-price__per { margin: 6px 0 0; font-size: 13.125px; line-height: 18.75px; color: var(--cream-400); }
.wl-price__billed { margin: 2px 0 0; font-size: 13.125px; line-height: 21.33px; color: var(--cream-500); }


.wl-price__row--cta > .wl-price__col { padding: 14px; }
.wl-price__btn { width: 100%; justify-content: center; }

.wl-price__plus { margin: 0 0 12px; font-size: 13px; color: var(--cream-300); }
.wl-price__plus b { color: var(--accent); font-weight: 600; }
.wl-price__list { display: grid; gap: 10px; margin: 0; padding: 0; list-style: none; }
.wl-price__list li {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 13px; line-height: 1.5; color: var(--cream-200);
}
.wl-price__check { flex: 0 0 auto; width: 16px; height: 16px; margin-top: 1px; color: var(--accent); }

/* --- the moving beam ------------------------------------------------------
   The overlay's border is transparent and 1px. Mask one is clipped to
   padding-box and is fully transparent; mask two is clipped to border-box and
   fully opaque. `intersect` keeps only what both cover, which is the 1px ring
   and nothing else. */
.wl-price__beam {
  position: absolute;
  inset: 0;
  z-index: 3;
  overflow: hidden;
  box-sizing: border-box;
  border-radius: inherit;
  pointer-events: none;
  padding: 1px;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}
/* Nothing travels: a conic gradient SWEEPS, and the ring mask shows whatever
   part of it currently lands on the border.

   Two earlier attempts both snapped, for the same underlying reason - they
   moved a rigid object around a box with square corners:
     1. A square sized 55% of the card orbited by animating left/top between
        the corners. It overlapped two edges at once, so a long stretch lit up,
        and its centre moved in a straight line between corners, so the lit
        part jumped to the next edge while the previous edge sat frozen.
     2. offset-path fixed the speed and the length, but a 90 degree vertex has
        no curve to follow, so offset-rotate flipped the bar a quarter turn in
        an instant - the snap into the next side.
   A conic gradient has no object and no rotation to perform. The colour stops
   sweep past the corner continuously, so the light rounds it with ease.

   Angle comes from --wl-border-angle, already registered with @property above
   (a plain custom property cannot be tweened), driven by the file's existing
   wl-border-spin keyframes. */
.wl-price__beam {
  background: conic-gradient(from var(--wl-border-angle) at 50% 50%,
    transparent 0deg,
    color-mix(in srgb, var(--accent-deep) 45%, transparent) 26deg,
    var(--accent-hot) 58deg,
    var(--accent) 78deg,
    color-mix(in srgb, var(--accent) 65%, #fff) 90deg,
    var(--accent) 102deg,
    color-mix(in srgb, var(--accent-deep) 45%, transparent) 124deg,
    transparent 150deg,
    transparent 360deg);
  animation: wl-border-spin 6s linear infinite;
}

/* The hero and #wl-reveal carry their reassurance as a bare 190px strip under
   the CTA, not in a bordered panel. The panel treatment (52rem box, 28px
   padding, 340px strip) stays on .wl-pricing elsewhere; here it is stripped
   back to match. The frame keeps its own 52rem max-width, so losing the bar's
   box does not change the table's width. */
.wl-price .wl-pricing-trust {
  display: flex;
  justify-content: center;
  width: auto;
  max-width: none;
  margin: 20px auto 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
}
.wl-price .wl-pricing-trust .wl-trust-strip { width: 190px; }
.wl-price .wl-disclaimer { margin-top: 12px; text-align: center; }

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

@media (max-width: 860px) {
  .wl-price__row { grid-template-columns: minmax(0, 1fr); }
  .wl-price__row > .wl-price__col + .wl-price__col {
    border-left: 0;
    border-top: 1px solid var(--ink-600);
  }
}

/* ---------------------------------------------------------------------------
   REVEAL CALLOUT - MATCH THE HERO'S CTA, GROUP THE COPY
   The button ran at its natural 261px here because the hero's width rule
   (.wl-offer-hero__copy--cta .btn, and the same declaration on .wl-section-cta
   / .cta__actions) never covered this callout. Same clamp, so it is the hero's
   button rather than a lookalike. The trust strip already matched at 190px -
   .wl-trust-strip sets that globally - so only the button needed the change.

   The lead and the sub were two siblings of the button in one 16px grid, which
   spaced all three the same and read as three loose lines. They now sit in
   their own group at 6px so they read as a title with its subtitle, and the
   24px gap below separates that pair from the button.
   ------------------------------------------------------------------------ */
#wl-reveal .wl-callout .btn {
  width: clamp(min(420px, 100vw - 48px), 60vw, 760px);
  max-width: 100%;
  min-width: 0;
}

#wl-reveal .wl-callout--block { gap: 24px; }

#wl-reveal .wl-callout__group {
  display: grid;
  justify-items: center;
  gap: 6px;
  text-align: center;
}
#wl-reveal .wl-callout__group .wl-callout__sub { margin-top: 0; }

/* ---------------------------------------------------------------------------
   NO STROKE ON A FILLED CONTAINER
   The page was carrying a 1px hairline on almost every box that already had a
   fill, so each card, panel, figure and list row was outlined twice over - the
   fill separating it from the ground, and the stroke separating it again. The
   fill does that job on its own here, so the stroke comes off and the box is
   read by its surface.

   Scoped to .page--white-label: these classes are shared with the rest of the
   site, where the hairlines are still wanted.

   Unfilled boxes keep their stroke - it is the only thing defining them.

   TWO DELIBERATE EXCLUSIONS:
   1. The mock product UI (.wl-feat__screen, .wl-preview, .wl-output__browser
      and the .f-* stage parts). Those are pictures OF software, where a
      hairline is part of what is being depicted, not page chrome.
   2. The pricing table's frame and its column dividers, which were built to
      match a reference you asked to copy exactly and whose structure IS those
      1px rules. Its filled pill and trust bar are swept like everything else.
   ------------------------------------------------------------------------ */
.page--white-label :is(
  .wl-demand-list li,
  .wl-strike-list li,
  .wl-pain__list li,
  .wl-cap-grid li,
  .wl-audience li,
  #wl-models .wl-model ul li,
  .wl-feat,
  .wl-bonus,
  .wl-own-card,
  .wl-market__panel,
  .wl-shot,
  .wl-model,
  .wl-pain__col,
  .wl-rate-card,
  .wl-calc,
  .wl-econ-visual,
  .wl-callout,
  .wl-pricing-trust,
  .wl-price__eyebrow,
  .wl-trust,
  .wl-vsl__hit
) {
  border: 0;
}

/* ---------------------------------------------------------------------------
   ONE CHECK MARK
   Every tick on the page is now the hero's glyph - the circle-check SVG from
   .wl-hero-checks - instead of three different Phosphor icons (ph-check-circle
   in the pain columns, ph-check in the console grid and again in the final
   bonuses).

   It carries the hero's COLOUR too - --accent-hot, the same rgb(242,129,62)
   the benefit-strip check uses. The green these marks used to be is gone on
   purpose: the point was one mark, not one outline in three colours.

   Sized in em, not px. Each of those contexts already set a font-size to scale
   the icon FONT it used to carry, so 1em reproduces the box the Phosphor glyph
   occupied and nothing shifts.
   ------------------------------------------------------------------------ */
.page--white-label .wl-check {
  flex: 0 0 auto;
  width: 1em;
  height: 1em;
  color: var(--accent-hot);
}

/* ---------------------------------------------------------------------------
   BONUS CARDS - SMALLER SUBTEXT
   Both paragraphs ran at 17.644px, the page's body scale. 16px here, and the
   limit line a step under that so it still reads as a note rather than a third
   paragraph - it also now leads with the same check mark, set inline against
   the text baseline.
   ------------------------------------------------------------------------ */
.page--white-label .wl-bonus .t-body,
.page--white-label .wl-bonus .t-small {
  font-size: 16px;
  line-height: 1.6;
}

.page--white-label .wl-bonus__limit {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 15px;
  line-height: 1.5;
}

/* ---------------------------------------------------------------------------
   LAUNCH SECTION - VERTICAL RHYTHM
   The three blocks of the section sat too close together: 40px from the
   headline down to the steps, then only 32px from the steps down to the
   button and its trust icons, inside 80px of section padding. The outer
   padding was therefore twice the space separating the parts, so the whole
   region read as one tight clump.

   Both gaps go to 64px, even above and below the steps, which puts the
   internal rhythm in proportion to the 80px the section already reserves at
   its edges. The steps' own columns are untouched.
   ------------------------------------------------------------------------ */
.page--white-label #wl-launch .page-section__head { margin-bottom: 64px; }
.page--white-label #wl-launch .wl-section-cta { margin-top: 64px; }

/* ---------------------------------------------------------------------------
   FINAL CTA STACK - ONE LINE
   Five items stacked vertically at 22px in a 170px column. They now run as a
   single row at 18px, separated by the same middot that came off the two
   headlines earlier.

   The separator is a ::before on every item after the first, so it never
   trails the last one and there is no empty element to keep in sync with the
   copy. Its margins carry the spacing rather than the flex gap, which would
   otherwise add to them and double the gutter around each dot.

   Below 720px the row is allowed to wrap: at that width one line would run
   past the viewport, and the page is overflow-x: clip, so it would be cut off
   rather than scrolled to.
   ------------------------------------------------------------------------ */
.page--white-label .wl-final-stack {
  display: flex;
  flex-wrap: nowrap;
  justify-content: center;
  align-items: center;
  gap: 0;
  width: auto;
  max-width: 100%;
  /* As a grid item this defaults to min-width:auto, i.e. floored at its
     min-content size - and that floor beats max-width, so at 390px the row
     stayed 420px wide inside a 339px column and ran off the viewport. */
  min-width: 0;
  font-size: 18px;
  line-height: 1.4;
}
.page--white-label .wl-final-stack li {
  font: inherit;
  white-space: nowrap;
}
.page--white-label .wl-final-stack li + li::before {
  content: '\00B7';
  margin: 0 14px;
  color: var(--cream-500);
}

@media (max-width: 720px) {
  /* Measured against the viewport, not the grid area. .cta__inner is a grid
     whose track is stretched to 420px by .cta__actions .btn's own
     clamp(420px, ...) floor, so `100%` here resolves to 420 and constrains
     nothing at a 390px viewport. (That button overflowing at this width is a
     separate, pre-existing issue in the CTA block.) */
  .page--white-label .wl-final-stack {
    flex-wrap: wrap;
    max-width: calc(100vw - 48px);
    font-size: 16px;
  }
}

/* ---------------------------------------------------------------------------
   FEATURE CARD 01 - VIDEO ILLUSTRATION
   Takes the exact box the CSS stages use (.wl-feat__screen: 232px tall, 12px
   radius, --ink-600 hairline) so the card sits flush in the grid and all
   seventeen keep the same height.

   muted + playsinline are what make autoplay legal in every current browser;
   loop with no controls is the gif behaviour. preload="metadata" so a 13MB
   file does not compete with the page's own load.
   ------------------------------------------------------------------------ */
/* Locked to 3:2. Recordings are now exported at a 3:2 canvas, so any of
   them drops in with nothing cropped. It took four clips at four ratios
   (16:9, 1618:1080, 1044:700, 1046:698) to settle this - if a future clip
   is NOT 3:2, change aspect-ratio and the width cap below to match it, or
   object-fit will crop the difference off one edge. */
.page--white-label .wl-feat__video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  max-width: calc(232px * 3 / 2);
  max-height: 232px;
  margin-inline: auto;
  object-fit: cover;
  border: 1px solid var(--ink-600);
  border-radius: 12px;
  background: var(--ink-950);
}

@media (prefers-reduced-motion: reduce) {
  .page--white-label .wl-feat__video { animation: none; }
}

/* ---------------------------------------------------------------------------
   FEATURE CARDS - VIDEO IN EVERY CARD, STACKED
   Every card now carries a screen recording, and on the desktop two-up grid
   (>1100px) each card stacks: copy on top, video below at the card's full
   width. A recording shown in half a card was drawn ~3x smaller than it was
   captured, so its UI text read as texture; at full card width it plays close
   to its own 696px size. Below 1100px every card is already a full row and
   keeps the side-by-side layout.

   THE 6px FRAME. The video keeps box-sizing: content-box, overriding the
   site-wide border-box, so aspect-ratio sizes the PICTURE and the 6px border
   is added outside it. Under border-box the ratio would describe the outer
   frame, the picture inside would lose 20px each way off-ratio, and cover
   would start cropping again. The width is 100% minus both borders so the
   frame still fits its column.

   Colour is --ink-800, the same black the bonus cards are filled with. Those
   use it at 45% alpha; here it is opaque, because a translucent border would
   pick up whatever sits behind it and read as a different shade.
   ------------------------------------------------------------------------ */
@media (min-width: 1101px) {
  .page--white-label #wl-included .wl-feat {
    grid-template-columns: minmax(0, 1fr);
    align-content: start;
    gap: 16px;
  }
  .page--white-label #wl-included .wl-feat__copy { padding: 8px 8px 0; }
  .page--white-label #wl-included .wl-feat__art { display: grid; justify-items: center; }
}
/* Stacked cards get the same 8px above the eyebrow that the wide layout has,
   so the label is not pressed against the video above it. */
@media (max-width: 1100px) {
  .page--white-label #wl-included .wl-feat__copy { padding-top: 8px; }
}

.page--white-label #wl-included .wl-feat__video {
  box-sizing: border-box;
  width: 100%;
  /* The 348x232 caps from the base video rule were there to keep a half-width
     card level with its neighbour. In this grid no card shares its row with a
     taller one below 1100px (one card per row) and above it the pair stack
     identically, so the caps only left gaps - 176px of empty column at 620.
     Fill the column instead, up to the file's own 696px so it never upscales. */
  max-width: 696px;
  max-height: none;
  /* INSIDE STROKE. A border always sits outside the picture, and an inset
     box-shadow is painted UNDER a video's picture, so it never shows. An
     outline pulled in by its own width lands exactly on the inner 6px of the
     box: outlines paint above the content and follow border-radius, so it
     reads as a stroke drawn over the edge of the video. */
  border: 0;
  outline: 6px solid var(--ink-800);
  outline-offset: -6px;
  border-radius: max(0px, var(--feat-r) - var(--feat-pad));
}

/* CONCENTRIC CORNERS. The video frame sits --feat-pad in from the card's
   edges, so its corners use the card's radius minus that gap - the two curves
   then share a centre. It was 20px inside a 16px card: the inner curve was
   rounder than the outer one, which is what read as off. Both values live on
   the card as custom properties so the frame follows if either changes; max()
   keeps it from going negative if the padding ever outgrows the radius.
   The picture inside the 6px border is rounded by the browser to the frame's
   radius minus the border width, so the same rule carries one level further. */
.page--white-label #wl-included .wl-feat {
  --feat-r: 32px;
  --feat-pad: 12px;
  border-radius: var(--feat-r);
  padding: var(--feat-pad);
}

/* ---------------------------------------------------------------------------
   OWN-CARD SHOTS WITH A URL PILL
   The docs card used to be one flat PNG with its URL pill painted into the
   picture. The screenshot underneath is now real, so the pill is rebuilt as
   an element on top of it: it stays sharp at every size, and the picture
   behind it can be swapped without redrawing the pill.

   A 45% --ink-950 wash sits between the two. The new screenshot is a busy,
   bright docs page, and without the wash the pill's dark body sank into it.
   The figure already clips to its 14px corners, so the wash follows them.

   The pill is sized in cqw off the figure's own width (18px at the ~420px
   desktop frame, as the painted original was), clamped at both ends, so it
   keeps the same proportion inside the frame from phone to desktop.
   ------------------------------------------------------------------------ */
.page--white-label .wl-shot--pill {
  position: relative;
  container-type: inline-size;
}
.page--white-label .wl-shot--pill::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: color-mix(in srgb, var(--ink-950) 45%, transparent);
  pointer-events: none;
}
.page--white-label .wl-shot__pill {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 2;
  translate: -50% -50%;
  padding: 0.8em 1.25em;
  border: 1.5px solid transparent;
  border-radius: 0.8em;
  background:
    linear-gradient(color-mix(in srgb, var(--ink-900) 94%, transparent), color-mix(in srgb, var(--ink-900) 94%, transparent)) padding-box,
    linear-gradient(100deg,
      color-mix(in srgb, var(--cream-050) 55%, transparent) 0%,
      color-mix(in srgb, var(--cream-050) 10%, transparent) 48%,
      var(--accent) 100%) border-box;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
  font-family: var(--font-body);
  font-size: clamp(12px, 4.3cqw, 20px);
  line-height: 1;
  letter-spacing: 0.01em;
  white-space: nowrap;
  color: var(--cream-100);
  pointer-events: none;
}

/* ---------------------------------------------------------------------------
   FEATURE CARDS - EVERY DESCRIPTION HOLDS THREE LINES (desktop)
   So every video in the grid starts at the same height, each description
   gets exactly three lines of room.

   A narrower width alone cannot do it. The copy runs 159 to 248 characters:
   the longest needs >= ~83 characters a line to stay within three lines, the
   shortest needs < ~80 a line to reach a third one. Those cannot both hold,
   so any single measure leaves short ones on two lines or pushes the long one
   to four. Hence two parts:
     max-width 41em   (~533px at 13px) - the measure at which the longest
                      copy still fits in three lines, so most wrap to three
     min-height 3lh   three of the element's own line-heights, so the ones
                      that wrap to two still take three lines of space
   lh follows the computed line-height, so this holds if the type is resized.
   ------------------------------------------------------------------------ */
@media (min-width: 1101px) {
  .page--white-label #wl-included .wl-feat__desc {
    max-width: 41em;
    min-height: 3lh;
  }
}

/* ---------------------------------------------------------------------------
   STICKY BAR - TRUST LOGOS IN PLACE OF THE PRICE LINE
   The bar's sub line ("$997 one-time or $497/year") is replaced by the same
   Stripe / money-back / secure-order strip the CTAs carry. The global strip is
   190px, sized to sit under a 760px button; the bar is far smaller, so it
   runs at 150px here and 132px once the bar stacks its copy on phones.
   align-self: the copy row aligns on the text baseline, and an image's
   baseline is its bottom edge, which would drop it below the title.
   ------------------------------------------------------------------------ */
.page--white-label .wl-sticky__trust {
  display: block;
  width: 150px;
  height: auto;
  margin: 0;
  align-self: center;
}
@media (max-width: 760px) {
  /* On a phone the copy column gets ~111px beside the button. The title was
     white-space: nowrap, so it ran to ~160px and slid under the button - that
     overlap predates the logos. Letting it wrap, and capping the logos at the
     column's own width, keeps both clear of the button. */
  .page--white-label .wl-sticky__title { white-space: normal; line-height: 1.25; }
  .page--white-label .wl-sticky__trust { width: 132px; max-width: 100%; }
}

/* ---------------------------------------------------------------------------
   PLATFORM PREVIEW - EMBEDDED DEMO
   The hand-built preview is replaced by the packaged demo (wl-framer-demo),
   served from /wl-assets/embeds/ and framed here. It is fully self-contained - fonts,
   logos and runtime inline, no network requests - and its background is
   transparent, so the section shows through it.

   Its height is set by page.js from the demo's own content (see
   wlEmbedAutosize); the 820px here is only the pre-script fallback the
   demo's README gives for a ~960px desktop width. Width follows the README's
   960-1100px desktop range, capped rather than stretched so the demo's
   1280px logical canvas is never upscaled.
   ------------------------------------------------------------------------ */
.page--white-label .wl-demo--embed {
  display: grid;
  gap: 16px;
  justify-items: center;
  width: 100%;
  max-width: 1100px;
  margin-inline: auto;
}
.page--white-label .wl-demo__frame {
  display: block;
  width: 100%;
  height: 820px;
  border: 0;
  background: transparent;
  /* Must match the demo's own <meta name="color-scheme" content="dark">.
     When an iframe element and the document inside it resolve to different
     colour schemes, the browser paints the frame with an opaque backdrop to
     keep the embedded page legible - that is the black box, even though
     every layer inside the demo is transparent. Matching them removes it. */
  color-scheme: dark;
}

/* Desktop: the demo shows desktop and phone side by side, so it gets the
   section's full width instead of the single-device 1100px cap - at 1100px
   the pair would draw the laptop screen at barely 60% of its logical size. */
@media (min-width: 1101px) {
  .page--white-label .wl-demo--embed { max-width: none; }
}

/* ---------------------------------------------------------------------------
   PRODUCT SHOTS - SAME FRAME AS THE FEATURE-CARD VIDEOS
   The idea-section shot and the two console shots take the feature cards'
   video treatment: a 6px --ink-800 stroke drawn INSIDE the picture (an outline
   pulled in by its own width, since a border sits outside the image and an
   inset shadow paints underneath it) and 20px corners. Their old 1px hairline
   comes off so the edge is not drawn twice.

   The console shot's figure clips its image at 14.4px, which would cut the
   20px curve short - so the figure's corners move to 20px as well.
   ------------------------------------------------------------------------ */
.page--white-label :is(
  #wl-idea .wl-project-shot img,
  #wl-console .wl-shot img,
  #wl-console .wl-console-overview img
) {
  border: 0;
  border-radius: 20px;
  outline: 6px solid var(--ink-800);
  outline-offset: -6px;
}
.page--white-label #wl-console .wl-shot { border-radius: 20px; }

/* ===========================================================================
   ONE CORNER SYSTEM FOR THE WHOLE PAGE
   The feature card is the model: a 32px card, and media set 12px inside it at
   32 - 12 = 20px, so every curve shares a centre with the one around it.
   Before this the page used ten different radii (8.8, 10, 12, 14, 14.4, 16,
   17.6, 18.4, 20, 40) and several inner shapes were rounder than the cards
   holding them - a 14.4px image inside a 14.4px card with 20px padding.

     --r-card   32px   every card and panel
     --r-media  20px   standalone media - the feature card's video container
     nested            calc(--r-card - gap), concentric with its own card

   Pills (buttons, chips, badges at radius 999) are a shape of their own and
   are left alone. Short rows below 64px tall come out as capsules under a
   32px corner, which matches the pill list rows already on the page.
   =========================================================================== */
.page--white-label {
  --r-card: 32px;
  --r-media: 20px;
}

/* cards and panels */
.page--white-label #wl-bonuses .wl-bonus,
.page--white-label #wl-models .wl-model,
.page--white-label #wl-experience .wl-own-card,
.page--white-label #wl-economics .wl-calc,
.page--white-label #wl-economics .wl-rate-card,
.page--white-label #wl-market .wl-market__panel,
.page--white-label #wl-pain .wl-pain__col,
.page--white-label #wl-audience .wl-audience li,
.page--white-label #wl-console .wl-cap-grid li,
.page--white-label #wl-reveal .wl-infra li,
.page--white-label #wl-faq .accordion__item,
.page--white-label .footer__plate {
  border-radius: var(--r-card);
}

/* standalone media - the same corner as the feature video */
.page--white-label #wl-build .wl-output__browser,
.page--white-label #wl-monetize .wl-shot,
.page--white-label #wl-hero .wl-vsl__hit,
.page--white-label #wl-console .wl-shot,
.page--white-label #wl-console .wl-shot img,
.page--white-label #wl-console .wl-console-overview img,
.page--white-label #wl-idea .wl-project-shot img {
  border-radius: var(--r-media);
}

/* nested - card radius minus the gap to the card's edge */
.page--white-label #wl-experience .wl-own-card .wl-shot {
  border-radius: calc(var(--r-card) - var(--wl-own-pad));
}
.page--white-label #wl-economics .wl-econ-visual,
.page--white-label #wl-economics .wl-econ-visual img {
  border-radius: calc(var(--r-card) - 1.4rem);    /* rate-card padding: 1.4rem */
}
.page--white-label #wl-faq .accordion__icon {
  border-radius: calc(var(--r-card) - 16px);      /* 16px in from the item's corner */
}
.page--white-label #wl-market .wl-callout {
  border-radius: calc(var(--r-card) - 1.4rem);    /* panel padding: 1.4rem */
}
/* The FAQ toggle sat 16px from the row's top and bottom but 30px from its
   right edge. With uneven gaps no single radius can be concentric, so the
   right gap drops to 16px as well: the icon now sits evenly in the corner and
   takes 32 - 16 = 16px. The question keeps its 30px on the left. */
.page--white-label #wl-faq .accordion__head { padding-right: 16px; }

/* ===========================================================================
   GALLERY FRAMES - GLASS BEZEL ON THE LIT SLIDE
   The active slide (the one in light; the others sit at 45% opacity) becomes a
   sheet of glass with its screenshot set 12px inside, under the surface. Every slide keeps
   the same geometry - padding, corners, bar height - so the carousel does not
   shift when the active slide changes; only the glass look switches on.

   Base recipe is the old lander hero's figure panel (.hl-figure): amber pooled
   under the top edge, a faint cream wash toward the foot, an inner light lift
   with no hard stroke. Apple-style layers on top, per research:
     - blur 20px + saturate 165% + brightness 1.08: the saturation keeps the
       amber ambience vivid rather than grey, the difference between Apple glass
       and generic frosted glass
     - a specular rim, brightest top-left and fading round the sides
     - a crisp top hairline (the bevel catching light), a darker base shadow
       inside, and a deep outer shadow - light shadows vanish on --ink-900
     - a faint grain to break up blur banding
   Refraction (SVG displacement) was ruled out: Chromium-only inside
   backdrop-filter, and Safari/Firefox drop it silently. Only one slide is lit
   at a time, so only one blurring layer ever exists.

   Corners follow the page rule: bezel --r-card (32px), screenshot 12px in at
   32 - 12 = 20px.
   =========================================================================== */

/* geometry - every slide */
.page--white-label #wl-build .wl-output__browser {
  --glass-pad: 12px;
  position: relative;
  isolation: isolate;
  gap: var(--glass-pad);
  padding: var(--glass-pad);
  border: 0;
  border-radius: var(--r-card);
  overflow: hidden;
  background: transparent;
  transition: box-shadow .35s ease, -webkit-backdrop-filter .35s ease, backdrop-filter .35s ease;
}
.page--white-label #wl-build .wl-output__chrome {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  height: auto;
  padding: 0 4px;
  border-bottom: 0;
  background: none;
}
/* The screenshot sits UNDER the glass, in a window cut into it, rather than
   floating on top. It used to carry its own drop shadow, which lifted it off
   the bezel like a card laid on glass. The pane replaces that with a recess:
   a dark inner lip along the top edge where the glass overhangs, a faint lit
   bevel along the bottom, and a sheen of the glass surface passing over the
   picture. <img> cannot paint an inset shadow over its own pixels, which is
   why the pane wraps it. */
.page--white-label #wl-build .wl-output__pane {
  position: relative;
  z-index: 1;
  display: block;
  flex: 0 0 auto;
  border-radius: calc(var(--r-card) - var(--glass-pad));
  overflow: hidden;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35);
}
.page--white-label #wl-build .wl-output__pane img { border-radius: 0; }
.page--white-label #wl-build .wl-output__pane::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity .35s ease;
  background: linear-gradient(160deg,
    rgba(251, 249, 246, 0.10) 0%, rgba(251, 249, 246, 0.03) 24%, transparent 42%);
  box-shadow:
    inset 0 2px 4px rgba(0, 0, 0, 0.55),
    inset 0 0 0 1px rgba(0, 0, 0, 0.30),
    inset 0 -1px 0 rgba(251, 249, 246, 0.10);
}
.page--white-label #wl-build .wl-output__slide.is-active .wl-output__pane::after { opacity: 1; }

/* Background light: a dim amber disc behind the focused slide. It hangs on a
   wrapper outside the scroller, so it stays put while slides pass over it -
   the track itself would clip it at its edges and scroll it away. The lit
   slide's backdrop blur and saturation pick it up through the bezel. */
.page--white-label #wl-build .wl-output__stage {
  position: relative;
  isolation: isolate;
}
.page--white-label #wl-build .wl-output__stage::before {
  content: '';
  position: absolute;
  z-index: -1;
  left: 50%;
  top: 50%;
  width: min(1200px, 110vw);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle closest-side,
    color-mix(in srgb, var(--accent) 22%, transparent) 0%,
    color-mix(in srgb, var(--accent-deep) 9%, transparent) 55%,
    transparent 100%);
}
.page--white-label #wl-hero .wl-vsl::before,
.page--white-label #wl-hero .wl-vsl::after,
.page--white-label #wl-build .wl-output__browser::before,
.page--white-label #wl-build .wl-output__browser::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity .35s ease;
}

/* the glass - lit slide only */
.page--white-label #wl-hero .wl-vsl,
.page--white-label #wl-build .wl-output__slide.is-active .wl-output__browser {
  background:
    radial-gradient(75% 28% at 50% 0%, rgba(254, 160, 2, 0.20), transparent 72%),
    linear-gradient(180deg, transparent 45%, rgba(251, 249, 246, 0.025)),
    linear-gradient(180deg, rgba(251, 249, 246, 0.10), rgba(251, 249, 246, 0.04));
  box-shadow:
    inset 0 1px 1px rgba(251, 249, 246, 0.35),
    inset 0 0 36px 1px rgba(251, 249, 246, 0.06),
    inset 0 0 140px 0 rgba(251, 249, 246, 0.025),
    inset 0 -20px 40px -20px rgba(0, 0, 0, 0.35),
    0 20px 40px -12px rgba(0, 0, 0, 0.55),
    0 2px 6px rgba(0, 0, 0, 0.30);
  -webkit-backdrop-filter: blur(20px) saturate(165%) brightness(1.08);
  backdrop-filter: blur(20px) saturate(165%) brightness(1.08);
}
/* specular rim: a 1px ring cut from a conic gradient, brightest top-left */
.page--white-label #wl-hero .wl-vsl::before,
.page--white-label #wl-build .wl-output__browser::before {
  z-index: 2;
  padding: 1px;
  background: conic-gradient(from 215deg at 25% 0%,
    rgba(251, 249, 246, 0.55), rgba(251, 249, 246, 0.06) 35%,
    rgba(251, 249, 246, 0.02) 60%, rgba(254, 160, 2, 0.14) 88%, rgba(251, 249, 246, 0.40));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}
/* grain, under the content so it never lands on the screenshot */
.page--white-label #wl-hero .wl-vsl::after,
.page--white-label #wl-build .wl-output__browser::after {
  z-index: 0;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.page--white-label #wl-hero .wl-vsl::before,
.page--white-label #wl-build .wl-output__slide.is-active .wl-output__browser::before { opacity: 1; }
.page--white-label #wl-hero .wl-vsl::after,
.page--white-label #wl-build .wl-output__slide.is-active .wl-output__browser::after { opacity: 0.05; }
.page--white-label #wl-build .wl-output__slide.is-active .wl-output__chrome i { background: rgba(251, 249, 246, 0.22); }
.page--white-label #wl-build .wl-output__slide.is-active .wl-output__chrome span {
  border-color: rgba(251, 249, 246, 0.10);
  background: rgba(251, 249, 246, 0.06);
  color: var(--cream-300);
}

/* no glass where it is unwanted or unsupported: an opaque panel instead */
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .page--white-label #wl-hero .wl-vsl,
  .page--white-label #wl-build .wl-output__slide.is-active .wl-output__browser {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background: var(--ink-800);
  }
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .page--white-label #wl-hero .wl-vsl,
  .page--white-label #wl-build .wl-output__slide.is-active .wl-output__browser { background: var(--ink-800); }
}

/* ---------------------------------------------------------------------------
   HERO VIDEO - SAME GLASS, ALWAYS ON
   The player sits in the gallery's glass bezel (the recipe above is shared,
   not copied, so the two cannot drift). The wrapper is the glass; the player
   floats 12px inside it with the page's concentric corners: 32px bezel,
   32 - 12 = 20px player. The embedded video, once it replaces the poster,
   takes the same 20px.
   ------------------------------------------------------------------------ */
.page--white-label #wl-hero .wl-vsl {
  --glass-pad: 12px;
  position: relative;
  isolation: isolate;
  padding: var(--glass-pad);
  border-radius: var(--r-card);
  overflow: hidden;
  min-width: 0;
}
.page--white-label #wl-hero .wl-vsl__hit,
.page--white-label #wl-hero .wl-vsl__frame {
  position: relative;
  z-index: 1;
  border: 0;
  border-radius: calc(var(--r-card) - var(--glass-pad));
}

/* ---------------------------------------------------------------------------
   OWNERSHIP AND RATE CARDS - TIGHTER ON PHONES
   At one column the cards' 1.25rem inset left the screenshots a lot narrower
   than the card holding them. 12px matches the gap the gallery and hero glass
   use, and because the screenshot's corner is derived from the same variable
   it stays concentric at 32 - 12 = 20px.
   ------------------------------------------------------------------------ */
@media (max-width: 760px) {
  .page--white-label #wl-experience .wl-own-card { --wl-own-pad: 12px; }

  /* Gallery frames: the three window dots take room the URL needs at this
     width, and they carry no information, so the URL bar gets the row. */
  .page--white-label #wl-build .wl-output__chrome i { display: none; }
  .page--white-label #wl-build .wl-output__chrome span {
    flex: 1 1 auto;
    max-width: 100%;
    text-align: center;
  }

  /* Same for the partner-rate card. Its image corner is written against the
     desktop 1.4rem inset, so it is restated here for the 12px one. */
  .page--white-label #wl-economics .wl-rate-card { padding: 12px; }
  .page--white-label #wl-economics .wl-rate-card .wl-econ-visual,
  .page--white-label #wl-economics .wl-rate-card .wl-econ-visual img {
    border-radius: calc(var(--r-card) - 12px);
  }
}

/* ---------------------------------------------------------------------------
   MOBILE BUTTONS - FILL WHEN ALONE, ROUND IN THE STICKY BAR
   A CTA stack holds one button over its trust strip and nothing beside it, so
   on a phone the button takes the column's full width - two of them (idea,
   monetize) sat at their 245px label width in a 339px column. The stack
   itself is fit-content, so it has to widen first or 100% has nothing to fill.

   The sticky bar's button shares its row with the copy and the dismiss, so it
   does not fill; it becomes a 48px circle carrying just the arrow, which frees
   the copy column. The label stays in the markup, visually hidden, so the
   link keeps its accessible name. The arrow is shown at rest, not on hover -
   there is no hover on a phone.
   ------------------------------------------------------------------------ */
.page--white-label .wl-sticky__icon { display: none; }

@media (max-width: 760px) {
  .page--white-label .wl-cta-stack { width: 100%; }
  .page--white-label .wl-cta-stack > .btn--large { width: 100%; }

  .page--white-label .wl-sticky__cta {
    flex: 0 0 48px;
    width: 48px;
    height: 48px;
    min-height: 0;
    padding: 0;
    border-radius: 50%;
  }
  .page--white-label .wl-sticky__cta .btn__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .page--white-label .wl-sticky__icon {
    display: block;
    font-size: 20px;
    line-height: 1;
  }
}
