/* qs-landing.css — design pass for the public landing page.
 *
 * Hand-authored source, not build output. Loads after visual-overhaul.css, so
 * rules here win without needing !important; reach for a higher-specificity
 * selector before reaching for the flag.
 *
 * Scope every rule to this screen. Shared token changes belong in
 * visual-overhaul.css and must be raised rather than duplicated here, so two
 * screens cannot drift apart on the same value.
 *
 * Bump the ?v=qs-landing-N key in scripts/build-static.js whenever this file changes,
 * or browsers keep serving the previous copy.
 *
 * ---------------------------------------------------------------------------
 * What this pass is for
 *
 * The landing page had already been through a structural pass: the nav, the
 * hero grid and the section column all come from visual-overhaul.css and are
 * sound. What it had never had was an interaction layer. Below the nav, 22 of
 * its 31 controls had no transition and no hover rule of any kind, because the
 * markup carried its whole appearance in inline style attributes and an inline
 * background cannot be overridden by a stylesheet without !important. So the
 * page looked considered and felt dead: nothing acknowledged the pointer.
 *
 * The build now names those parts instead of dressing them inline, so this
 * file can own them on ordinary specificity. There is exactly one !important
 * below, on the hero typeface, and it is there to beat an existing !important;
 * it is marked and explained where it appears.
 *
 * Focus rings and touch-action are deliberately NOT set here. frontend-qa.css
 * already gives every button, link, input and [role=tab] a 2px --qt-cyan ring
 * at 3px offset plus a dark 1px separator, and already sets touch-action on
 * the same set. Restating it here would fork a value that is currently right
 * in one place.
 * ---------------------------------------------------------------------------
 */

.qs-public-root {
  /* Local to this screen. Durations and easing come from the shared scale so
     the landing page and the workspace accelerate the same way. */
  --qsl-ease: var(--qt-ease-out);
  --qsl-fast: var(--qt-motion-fast);
  --qsl-slow: var(--qt-motion-standard);

  /* Vertical rhythm. Sections were spaced by a hardcoded 110px inline margin
     regardless of whether the block above ended in a panel edge or a line of
     text, so the measured gaps were even but the optical ones were not. */
  --qsl-section: clamp(72px, 8.5vw, 118px);
  --qsl-section-tight: clamp(52px, 6vw, 82px);
}

/* -------------------------------------------------------------------------- */
/* Typography                                                                 */
/* -------------------------------------------------------------------------- */


/* Section headings kept their tracking from an attribute-substring selector,
   `.qs-public-section [style*="font-size:40px"]`, which stopped matching once
   the runtime re-serialised the inline styles with a space after the colon.
   That is why they sit in Plex while the hero sits in Inter. Set on the
   element so it cannot depend on how a style attribute is spelled. */
.qs-public-root .qs-public-section h2,
.qs-public-root .qs-public-cta h2 {
  letter-spacing: -.028em;
  line-height: 1.1;
  text-wrap: balance;
}

/* Widows in the standfirst under each heading. */
.qs-public-root .qs-public-copy,
.qs-public-root .qs-feature-body,
.qs-public-root .qs-step-body {
  text-wrap: pretty;
}

/* The eyebrows are the page's only small-caps run and they were tracking at
   0.14em in the body face, where they read as stretched sentence text rather
   than as labels. The mono face is what the rest of the page uses for
   machine-ish text, and it holds tracking without smearing. */
.qs-public-root .qs-public-section > div:first-child > div:first-child[style*="letter-spacing"] {
  font-family: "IBM Plex Mono", monospace;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .16em;
}

/* Figures that are not already in the mono face still need to line up in a
   column. Plex Sans defaults to proportional digits. */
.qs-public-root .qs-feature-card,
.qs-public-root .qs-step,
.qs-public-root .qs-demo-legend {
  font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------------------------------- */
/* Motion                                                                     */
/* -------------------------------------------------------------------------- */

/* Every transition on this page is declared inside this block, so the reduced
   motion case is the absence of a rule rather than an override that has to
   chase each property. Properties are always listed; `all` would animate
   layout as well as paint. */
@media (prefers-reduced-motion: no-preference) {
  .qs-public-root .qs-nav-cta,
  .qs-public-root .qs-public-actions > :is(div, button),
  .qs-public-root .qs-closing-cta,
  .qs-public-root .qs-demo-cta {
    transition:
      background-color var(--qsl-fast) var(--qsl-ease),
      border-color var(--qsl-fast) var(--qsl-ease),
      box-shadow var(--qsl-fast) var(--qsl-ease),
      transform var(--qsl-fast) var(--qsl-ease);
  }

  .qs-public-root .qs-range-btn,
  .qs-public-root .qs-demo-tab,
  .qs-public-root .qs-broker-chip {
    transition:
      background-color var(--qsl-fast) var(--qsl-ease),
      border-color var(--qsl-fast) var(--qsl-ease),
      color var(--qsl-fast) var(--qsl-ease);
  }

  .qs-public-root .qs-feature-card,
  .qs-public-root .qs-step {
    transition:
      background-color var(--qsl-slow) var(--qsl-ease),
      border-color var(--qsl-slow) var(--qsl-ease),
      transform var(--qsl-slow) var(--qsl-ease);
  }

  .qs-public-root .qs-public-footer a {
    transition: color var(--qsl-fast) var(--qsl-ease);
  }

  /* The nav links already had a hover colour in visual-overhaul.css and no
     transition to carry it, so they snapped between two greys. */
  .qs-public-root .qs-public-links a,
  .qs-public-root .qs-public-links > :is(div, button) {
    transition: color var(--qsl-fast) var(--qsl-ease);
  }
}

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

/* visual-overhaul.css sets the tap-highlight to transparent for `a` and for
   elements carrying a click-handler attribute. The build promotes the page's
   clickable divs into real <button>s and compiles the handler away, so the
   promoted controls fall outside that selector and keep the platform's grey
   flash on tap. Named here rather than widened there because the promotion is
   what moved them out of range. */
.qs-public-root button,
.qs-public-root [role="button"] {
  -webkit-tap-highlight-color: transparent;
}

/* Primary. The nav and hero pair already sat on --qt-cyan; the demo and
   closing pair were hardcoded oklch(75% 0.14 220), which carries roughly twice
   the chroma of the token, so the page shipped its primary action in two
   visibly different blues depending on how far you had scrolled. Both now take
   the token from the same rule. */
.qs-public-root .qs-nav-cta,
.qs-public-root .qs-closing-cta,
.qs-public-root .qs-demo-cta {
  color: #061015;
  background: var(--qt-cyan);
  border: 1px solid var(--qt-cyan);
  cursor: pointer;
  font-weight: 600;
  text-align: center;
}

.qs-public-root .qs-closing-cta {
  display: inline-block;
  padding: 15px 32px;
  border-radius: var(--qt-radius-sm);
  font-size: 15px;
  /* Was `0 8px 30px oklch(60% 0.14 220 / 0.35)`: the only coloured outer glow
     on the page, on the one button furthest from anything else competing for
     attention. The button is already the sole bright object inside a dark
     panel. A shadow tinted to the surface behind it seats it instead of making
     it hover. */
  box-shadow: 0 6px 20px rgb(7 11 15 / 55%);
}

.qs-public-root .qs-demo-cta {
  padding: 9px 15px;
  border-radius: var(--qt-radius-sm);
  font-size: 11px;
}

/* Hover lifts a hair and lightens; active returns it to the surface so the
   press reads as a press rather than as a second hover. */
.qs-public-root .qs-nav-cta:hover,
.qs-public-root .qs-closing-cta:hover,
.qs-public-root .qs-demo-cta:hover,
.qs-public-root .qs-public-actions > :is(div, button):first-child:hover {
  background: color-mix(in oklch, var(--qt-cyan) 88%, #fff);
  border-color: color-mix(in oklch, var(--qt-cyan) 88%, #fff);
}

.qs-public-root .qs-closing-cta:hover {
  transform: translateY(-1px);
  box-shadow: 0 10px 26px rgb(7 11 15 / 62%);
}

.qs-public-root .qs-nav-cta:active,
.qs-public-root .qs-closing-cta:active,
.qs-public-root .qs-demo-cta:active,
.qs-public-root .qs-public-actions > :is(div, button):active {
  transform: translateY(1px);
  box-shadow: none;
}

/* Secondary. The ghost button had a border and nothing else, so it read as
   disabled next to a filled primary until you happened to point at it. */
.qs-public-root .qs-public-actions > :is(div, button):last-child:hover {
  background: var(--qt-panel-hover);
  border-color: var(--qt-line-strong);
}

/* -------------------------------------------------------------------------- */
/* Hero: range strip                                                          */
/* -------------------------------------------------------------------------- */

/* The strip used to be painted from two colours computed in the view and
   passed down as inline background and colour, with no role and no
   aria-pressed: a screen reader read seven identical buttons and never said
   which window was selected. The build now emits the state and both the paint
   and the announcement come from it, so they cannot disagree. */
.qs-public-root .qs-range-btn {
  padding: 6px 12px;
  border: 1px solid transparent;
  border-radius: 4px;
  background: transparent;
  color: var(--qt-muted);
  font-family: "IBM Plex Mono", monospace;
  font-size: 10.5px;
  letter-spacing: .04em;
  cursor: pointer;
}

.qs-public-root .qs-range-btn:hover {
  background: var(--qt-panel-hover);
  color: var(--qt-text-soft);
}

.qs-public-root .qs-range-btn[aria-pressed="true"] {
  background: var(--qt-cyan-dim);
  border-color: color-mix(in oklch, var(--qt-cyan) 42%, transparent);
  color: var(--qt-cyan);
}

/* -------------------------------------------------------------------------- */
/* Broker strip                                                               */
/* -------------------------------------------------------------------------- */

/* Each broker logo sits on its own plate because the marks are drawn for light
   backgrounds. The plates were pure #fff, so a row of eight punched eight
   hard white rectangles into a near-black page and pulled the eye straight
   past the headline above them. An off-white sits the marks on something that
   still reads as paper without flaring. */
.qs-public-root .qs-broker-chip {
  background: var(--qt-panel);
  border: 1px solid var(--qt-line);
  border-radius: var(--qt-radius-md);
  cursor: default;
}

.qs-public-root .qs-broker-chip img {
  background: #eef2f4;
  border-radius: 5px;
}

.qs-public-root .qs-broker-chip:hover {
  background: var(--qt-panel-hover);
  border-color: var(--qt-line-strong);
}

/* -------------------------------------------------------------------------- */
/* Product demo                                                               */
/* -------------------------------------------------------------------------- */

.qs-public-root .qs-demo-tabs {
  display: flex;
  gap: 6px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--qt-line);
}

.qs-public-root .qs-demo-tab {
  padding: 9px 14px;
  border: 1px solid transparent;
  border-radius: var(--qt-radius-sm);
  background: transparent;
  color: var(--qt-muted);
  cursor: pointer;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .06em;
}

.qs-public-root .qs-demo-tab:hover {
  background: var(--qt-panel-hover);
  color: var(--qt-text-soft);
}

.qs-public-root .qs-demo-tab[aria-pressed="true"] {
  background: var(--qt-cyan-dim);
  border-color: color-mix(in oklch, var(--qt-cyan) 40%, transparent);
  color: var(--qt-cyan);
}

/* The device-showcase tabs and the demo toggles are the same kind of control
   two sections apart, and they were selected-tinted in two different blues:
   oklch(75% 0.14 220 / 0.16) here against the token elsewhere. One treatment,
   driven by the aria-selected these already had to set. */
.qs-public-root .qs-showcase-tab {
  background: var(--qt-panel);
  border: 1px solid var(--qt-line);
  color: var(--qt-muted);
}

.qs-public-root .qs-showcase-tab:hover {
  background: var(--qt-panel-hover);
  border-color: var(--qt-line-strong);
  color: var(--qt-text-soft);
}

.qs-public-root .qs-showcase-tab[aria-selected="true"] {
  background: var(--qt-cyan-dim);
  border-color: color-mix(in oklch, var(--qt-cyan) 42%, transparent);
  color: var(--qt-cyan);
}

/* The chart key spelled its own line styles with punctuation -- an em-dash for
   the solid series, two hyphens for the dashed one -- which at 9px read as
   stray characters next to the words rather than as a key. Drawn swatches, in
   the colours the paths are actually stroked with. */
.qs-public-root .qs-demo-legend {
  display: flex;
  gap: 14px;
  align-items: center;
  color: var(--qt-muted);
  font-size: 9.5px;
  letter-spacing: .08em;
}

.qs-public-root .qs-legend-item {
  display: inline-flex;
  gap: 6px;
  align-items: center;
}

.qs-public-root .qs-swatch {
  display: inline-block;
  width: 14px;
  height: 0;
  border-top-width: 2px;
}

.qs-public-root .qs-swatch-solid {
  border-top-style: solid;
  border-top-color: oklch(75% 0.19 150);
}

.qs-public-root .qs-swatch-dashed {
  border-top-style: dashed;
  border-top-color: oklch(50% 0.01 240);
}

/* Same key on the hero chart, which strokes its benchmark a step lighter.
   It is a sibling of the value block and the range strip, so it is ordered
   onto a full-width row of its own beneath them: dropped into the row it
   would push the range strip out of the corner it has always occupied. */
.qs-public-root .qs-hero-legend {
  display: flex;
  order: 3;
  flex-basis: 100%;
  gap: 14px;
  align-items: center;
  margin-top: 2px;
  color: var(--qt-muted);
  font-family: "IBM Plex Mono", monospace;
  font-size: 9.5px;
  letter-spacing: .1em;
}

.qs-public-root .qs-swatch-bench {
  border-top-style: dashed;
  border-top-color: oklch(55% 0.01 240);
}

.qs-public-root .qs-public-chart-head {
  flex-wrap: wrap;
  gap: 12px;
}

/* -------------------------------------------------------------------------- */
/* Features                                                                   */
/* -------------------------------------------------------------------------- */

.qs-public-root .qs-feature-grid {
  display: grid;
  /* Was repeat(3, 1fr): three identical boxes in a row, the most recognisable
     AI-layout signature, and it carries no hierarchy - telling the reader all
     three matter equally means none of them lands. Flow-adjusted performance is
     the claim this product is built on, so it takes a tall lead cell and the two
     diagnostics stack beside it. Three items, three cells, no empty tile. */
  grid-template-columns: 1.32fr minmax(0, 1fr);
  gap: 18px;
}

.qs-public-root .qs-feature-card {
  display: flex;
  flex-direction: column;
  padding: 28px;
  background: var(--qt-panel);
  border: 1px solid var(--qt-line);
  border-radius: var(--qt-radius-lg);
  /* A hairline of light along the top edge. One light source, above the page,
     consistent with the shadow direction on the panels around it. */
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 4%);
}

.qs-public-root .qs-feature-card:hover {
  background: var(--qt-panel-strong);
  border-color: var(--qt-line-strong);
  transform: translateY(-2px);
}

.qs-public-root .qs-feature-glyph {
  display: flex;
  width: 38px;
  height: 38px;
  align-items: center;
  justify-content: center;
  margin-bottom: 18px;
  border-radius: var(--qt-radius-md);
  font-size: 15px;
  /* The plate colours arrive as custom properties rather than as a direct
     inline background, so the three steps of the cyan family stay defined in
     the view next to the copy they label while the plate itself is styled
     here. Fallbacks keep the tile from vanishing if the data ever drops out. */
  background: var(--qsl-tint, var(--qt-cyan-dim));
  color: var(--qsl-ink, var(--qt-cyan));
}

.qs-public-root .qs-feature-title {
  margin: 0 0 9px;
  color: var(--qt-text);
  font-size: 16.5px;
  font-weight: 600;
  letter-spacing: -.008em;
}

.qs-public-root .qs-feature-body {
  margin: 0;
  color: var(--qt-text-soft);
  font-size: 13.5px;
  line-height: 1.65;
}

/* -------------------------------------------------------------------------- */
/* Steps                                                                      */
/* -------------------------------------------------------------------------- */

/* These were three equal cards with the same padding, background, border and
   radius as the feature row directly above them, so the page made the same
   visual statement twice running and neither row carried more weight than the
   other.

   The difference between the two sections is that these are ordered and the
   features are not, so the numbering here is load-bearing rather than
   decorative. Drawn as a rail: one rule runs the width of the section, the
   step numbers sit on it, and the grouping comes from the line rather than
   from three boxes. Marked up as an <ol> for the same reason. */
.qs-public-root .qs-step-rail {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--qt-line);
  list-style: none;
}

.qs-public-root .qs-step {
  position: relative;
  padding: 34px 34px 6px 0;
}

.qs-public-root .qs-step + .qs-step {
  padding-left: 34px;
  border-left: 1px solid var(--qt-line);
}

/* The number straddles the rule rather than sitting under it, which is what
   makes the row read as one sequence instead of three columns. */
.qs-public-root .qs-step-num {
  position: absolute;
  top: -9px;
  left: 0;
  padding-right: 12px;
  background: var(--qt-bg);
  color: var(--qt-cyan);
  font-family: "IBM Plex Mono", monospace;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .12em;
}

.qs-public-root .qs-step + .qs-step .qs-step-num {
  left: 34px;
  padding-left: 12px;
}

.qs-public-root .qs-step-title {
  margin: 0 0 9px;
  color: var(--qt-text);
  font-size: 16.5px;
  font-weight: 600;
  letter-spacing: -.008em;
}

.qs-public-root .qs-step-body {
  margin: 0;
  max-width: 34ch;
  color: var(--qt-text-soft);
  font-size: 13.5px;
  line-height: 1.65;
}

/* -------------------------------------------------------------------------- */
/* Rhythm                                                                     */
/* -------------------------------------------------------------------------- */

/* Sections carried a flat inline `margin:110px auto 0`. A panel-edged section
   and a text-topped section need different amounts of air above them to look
   equally spaced, and the closing CTA in particular sat in a void because the
   security panel above it already ends in 48px of its own padding. */
.qs-public-root .qs-public-section,
.qs-public-root .qs-public-cta {
  margin-top: var(--qsl-section);
}

.qs-public-root .qs-public-cta {
  margin-top: var(--qsl-section-tight);
}

.qs-public-root .qs-public-footer {
  margin-top: var(--qsl-section-tight);
}

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

.qs-public-root .qs-public-footer a {
  color: var(--qt-text-soft);
  text-decoration: none;
}

.qs-public-root .qs-public-footer a:hover {
  color: var(--qt-cyan);
  text-decoration: underline;
  text-underline-offset: 3px;
}

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

@media (max-width: 900px) {
  .qs-public-root .qs-feature-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  /* One column: a lead cell spanning two rows would just be a taller box. */
  .qs-public-root .qs-feature-grid > :first-child {
    grid-row: auto;
  }

  /* The rail is a horizontal device. Stacked, the rule and the straddling
     numbers stop describing a sequence, so it becomes a vertical list with the
     line down the left instead. */
  .qs-public-root .qs-step-rail {
    grid-template-columns: minmax(0, 1fr);
    border-top: 0;
    /* The numbers straddle the rule here too, so the rail is inset by half a
       number's width. Without it "01" sits flush against the section's own
       padding edge and reads as clipped. */
    margin-left: 15px;
  }

  .qs-public-root .qs-step {
    padding: 22px 0 22px 26px;
    border-left: 1px solid var(--qt-line);
  }

  .qs-public-root .qs-step + .qs-step {
    padding-left: 26px;
  }

  .qs-public-root .qs-step-num,
  .qs-public-root .qs-step + .qs-step .qs-step-num {
    top: 22px;
    left: 0;
    padding: 0 8px 0 0;
    transform: translateX(-50%);
    background: var(--qt-bg);
  }

  .qs-public-root .qs-step-body {
    max-width: none;
  }
}

@media (max-width: 760px) {
  .qs-public-root .qs-demo-tabs {
    padding: 10px 12px;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .qs-public-root .qs-demo-tab {
    flex: 0 0 auto;
  }
}

/* The three feature cards sat in `repeat(3, 1fr)`: three identical boxes in a
   row, which is the single most recognisable AI-layout signature and carries no
   hierarchy - the reader is told all three matter equally, so none of them
   lands. Flow-adjusted performance is the claim the product is actually built
   on, so it takes a tall lead cell and the two diagnostics stack beside it.
   Three items, three cells, no empty tile. Collapses to one column on phones,
   where a 1.32fr lead cell would just be a narrower box. */
.qs-public-root .qs-feature-grid > :first-child {
  grid-row: span 2;
  justify-content: center;
}

/* ==========================================================================
   The handoff's palette, applied to the marketing page.

   Values are the handoff's own, not sampled from the frames: ground #201e1d,
   text #faf9f8, the neutral ramp inverted so low numbers are surfaces, and the
   accent as oklch rather than the hex beside it - the ramps were built on one
   perceptual lightness scale, so equal steps carry equal visual weight and the
   hex is only the browser's conversion.

   Overriding on .qs-public-root rather than at :root is what keeps this off the
   dashboard: the product keeps its own palette, and every existing marketing
   rule that already reads var(--qt-panel) or var(--qt-line) re-themes untouched.

   Two rules from the handoff that no screenshot would have given me: radius is
   0 everywhere, no exceptions, and there are no shadows anywhere.
   ========================================================================== */
.qs-public-root {
  /* the handoff's own token names, so the spec can be read against this file */
  --color-bg: #201e1d;
  --color-text: #faf9f8;
  --color-surface: #1b1817;
  --color-divider: #87817a;
  --color-neutral-100: #1b1817;
  --color-neutral-200: #2b2724;
  --color-neutral-300: #433d37;
  --color-neutral-400: #5f5952;
  --color-neutral-500: #87817a;
  --color-neutral-600: #b2aca5;
  --color-neutral-700: #d7d2cd;
  --color-neutral-800: #edebe8;
  --color-neutral-900: #faf9f8;
  --color-accent: oklch(62% 0.16 152);
  --color-accent-100: oklch(25% 0.06 152);
  --color-accent-200: oklch(25% 0.06 152);
  --color-accent-600: oklch(78% 0.10 152);
  --color-accent-700: oklch(78% 0.10 152);

  /* the reference authors against these two names */
  --font-body: 'Archivo', 'IBM Plex Sans', Arial, sans-serif;
  --font-heading: 'Archivo', 'IBM Plex Sans', Arial, sans-serif;

  /* the page's existing --qt-* vocabulary, mapped onto the above so no rule
     that already references it has to change */
  --qt-bg: var(--color-bg);
  --qt-bg-raised: var(--color-surface);
  --qt-panel: var(--color-bg);
  --qt-panel-strong: var(--color-surface);
  --qt-panel-hover: var(--color-neutral-200);
  --qt-panel-sunken: var(--color-surface);

  --qt-line: var(--color-neutral-200);
  --qt-line-strong: var(--color-neutral-300);

  --qt-text: var(--color-text);
  --qt-text-soft: var(--color-neutral-700);
  --qt-muted: var(--color-neutral-600);
  --qt-faint: var(--color-neutral-500);

  --qt-cyan: var(--color-accent);
  --qt-cyan-dim: var(--color-accent-100);
  --qt-line-cyan: var(--color-accent-100);
  --qt-on-cyan: var(--color-bg);
  --qt-focus: var(--color-accent);

  /* green and red are reserved for signed numbers, verdicts and the brand mark.
     Nothing decorative is green. */
  --qt-green: var(--color-accent);
  --qt-red: oklch(63% 0.19 25);

  --qt-bar: var(--color-bg);
  --qt-scrim: rgb(32 30 29 / 82%);

  /* radius 0 everywhere, no shadows anywhere */
  --qt-radius-sm: 0;
  --qt-radius-md: 0;
  --qt-radius-lg: 0;
  --qt-shadow: none;

  background: var(--color-bg);
  color: var(--color-text);
  /* The root carries font-family in an inline style attribute, so the family
     has to be forced here or nothing on the page ever requests Archivo and the
     face sits registered-but-unloaded. */
  font-family: 'Archivo', 'IBM Plex Sans', Arial, sans-serif !important;
}

/* Radius 0 is a rule of the system, not a property of particular components,
   so it is asserted once across the subtree rather than component by component. */
/* The class is repeated to raise specificity to (0,2,1). Several component
   rules already set a radius with !important at (0,2,0), so a plain
   `.qs-public-root *` loses to them and six controls keep their corners. */
.qs-public-root.qs-public-root *,
.qs-public-root.qs-public-root *::before,
.qs-public-root.qs-public-root *::after,
.qs-public-root.qs-public-root {
  border-radius: 0 !important;
  box-shadow: none !important;
}

/* The closing block, full bleed.
   It was a rounded card inside the same 1120px column as everything above it,
   carrying a radial glow: the page ended on the same note it had played nine
   times already, so the last thing a reader saw asked for nothing. The
   reference ends on a full-width green field instead, which is the only moment
   on the page where the accent is the ground rather than a detail.
   Full bleed is done with a margin-left of -50vw from the 50% line rather than
   width:100vw, because 100vw includes the scrollbar and would overflow the
   body. Text is near-black on the green: white on this fill measures 3.30:1 and
   fails AA, which is the trap in copying the look without checking it. */
.qs-public-root .qs-closing-band {
  position: relative;
  left: 50%;
  width: 100vw;
  max-width: 100vw;
  margin: 110px 0 0 -50vw;
  padding: 0;
  background: var(--qt-cyan);
  overflow-x: clip;
}

.qs-public-root .qs-closing-inner {
  max-width: 1120px;
  margin: 0 auto;
  padding: 92px 40px 96px;
  text-align: left;
  background: none;
  border: 0;
  border-radius: 0;
}

.qs-public-root .qs-closing-band h2,
.qs-public-root .qs-closing-inner > div:not(.qs-closing-cta) {
  color: var(--qt-on-cyan);
}

.qs-public-root .qs-closing-band h2 {
  max-width: 20ch;
  letter-spacing: -.035em;
  line-height: 1.02;
}

/* On the green field the button inverts: the accent is already the ground, so
   a green button would vanish into it. */
.qs-public-root .qs-closing-band .qs-closing-cta {
  color: var(--qt-cyan);
  background: var(--qt-on-cyan);
  border-color: var(--qt-on-cyan);
}

.qs-public-root .qs-closing-band .qs-closing-cta:hover {
  color: var(--qt-cyan);
  background: #000;
  border-color: #000;
}

.qs-public-root .qs-closing-band .qs-closing-cta:focus-visible {
  outline: 2px solid var(--qt-on-cyan);
  outline-offset: 3px;
}

@media (max-width: 860px) {
  .qs-public-root .qs-closing-inner { padding: 64px 20px 68px; }
}

/* visual-overhaul.css paints `.qs-public-cta > :is(div,button)` as a paneled
   card and caps `.qs-public-cta` at 1480px, both with !important. The band has
   to beat those to bleed, so these carry !important too. They are the only ones
   in this file, and they exist to cancel an existing !important rather than to
   win on cascade order - this sheet already loads last. When the closing card
   treatment is removed from visual-overhaul.css, this block goes with it. */
.qs-public-root .qs-closing-band {
  max-width: 100vw !important;
  padding-left: 0 !important;
  padding-right: 0 !important;
}

.qs-public-root .qs-closing-band > .qs-closing-inner {
  color: var(--qt-on-cyan) !important;
  background: none !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
}

/* The supporting line and the headline are inline-coloured for the dark ground
   they used to sit on. On the green field they have to invert. */
.qs-public-root .qs-closing-band h2,
.qs-public-root .qs-closing-band .qs-closing-inner > div {
  color: var(--qt-on-cyan) !important;
}

.qs-public-root .qs-closing-band .qs-closing-cta {
  color: var(--qt-cyan) !important;
  background: var(--qt-on-cyan) !important;
  border: 1px solid var(--qt-on-cyan) !important;
  box-shadow: none !important;
}

/* The stat rule row under the hero.
   Four readings on one line between two hairlines, which is the reference's
   way of ending the hero: no cards, no icons, the rules and the type scale do
   the separating. The return is bound to the hero chart's own percentage
   rather than typed in, so the number under the chart cannot drift away from
   the line above it - this product's most expensive recurring defect is two
   figures that disagree, and a marketing page is the worst place to start one.
   The remaining three are sample counts, matching the sample series the hero
   already plots. */
.qs-public-root .qs-hero-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 28px;
  max-width: 1120px;
  margin: 64px auto 0;
  padding: 26px 40px 30px;
  border-top: 1px solid var(--qt-line);
  border-bottom: 1px solid var(--qt-line);
}

.qs-public-root .qs-hero-stat-v {
  font-size: clamp(26px, 2.6vw, 34px);
  font-weight: 600;
  letter-spacing: -.03em;
  line-height: 1;
  color: var(--qt-text);
  font-variant-numeric: tabular-nums;
}

.qs-public-root .qs-hero-stat-up { color: var(--qt-green); }

.qs-public-root .qs-hero-stat-l {
  margin-top: 10px;
  font-family: "IBM Plex Mono", monospace;
  font-size: 10.5px;
  letter-spacing: .12em;
  line-height: 1.35;
  color: var(--qt-muted);
}

@media (max-width: 860px) {
  .qs-public-root .qs-hero-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 26px 20px;
    margin-top: 44px;
    padding: 22px 20px 26px;
  }
}

/* ==========================================================================
   Archivo, self-hosted.

   The handoff sets its display type in Archivo and loads it from Google Fonts.
   Neither reference works here: the CSP blocks external font hosts, and the
   build rewrites every fonts.googleapis.com URL it finds, so a linked
   stylesheet would silently resolve to nothing and the page would fall back per
   machine - the exact defect that had the hero rendering in Segoe UI.

   Archivo is a variable font, so Google serves ONE file per subset across the
   whole 400-800 axis. Declaring it once with a weight range gives every weight
   the handoff asks for (400 body, 600 labels, 700-800 display) from 66KB, where
   naming the weights separately would ship the same bytes three times.
   Licence: SIL Open Font License 1.1.
   ========================================================================== */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400 800;
  font-stretch: 100%;
  font-display: swap;
  src: url('/assets/archivo-latin.woff2?v=qs-archivo-1') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400 800;
  font-stretch: 100%;
  font-display: swap;
  src: url('/assets/archivo-latin-ext.woff2?v=qs-archivo-1') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* ==========================================================================
   The reference file's own utility and responsive rules, scoped.

   Its :root block, and its `body`, `a` and `*` resets, are deliberately NOT
   carried over: the tokens are already declared on .qs-public-root above, and
   a bare `body` or `*` rule from a marketing page would reach the dashboard,
   the auth screens and the checkout with it. Everything here is prefixed so it
   cannot leave the landing subtree.

   One breakpoint at 1040px, which is the reference's: the three 0.92fr/1.08fr
   splits collapse to one column, the right columns drop their rule and inset,
   the four-up grids go two-up and the steps go one-up.
   ========================================================================== */
.qs-public-root .qsl-num { font-variant-numeric: tabular-nums; }

.qs-public-root ::selection {
  background: oklch(38% 0.10 152);
  color: var(--color-neutral-900);
}

@media (max-width: 1040px) {
  /* minmax(0, 1fr), not 1fr. A grid track sized 1fr still floors at the widest
     child's min-content, and the demo holdings table is a fixed-column grid
     about 434px wide, so at 375px the collapsed column measured 481px and took
     the hero headline and body copy out past the viewport with it. Nothing
     showed a scrollbar because the public root sets overflow-x: hidden, so the
     copy was simply cut off and the page looked fine. The same trap the chart
     sizing note in the earlier handoff describes. */
  .qs-public-root .qsl-split { grid-template-columns: minmax(0, 1fr) !important; gap: 40px !important; }
  .qs-public-root .qsl-split > * { min-width: 0; }
  .qs-public-root .qsl-right { border-left: 0 !important; padding-left: 0 !important; padding-top: 0 !important; }
  .qs-public-root .qsl-quad  { grid-template-columns: repeat(2, 1fr) !important; }
  .qs-public-root .qsl-tri   { grid-template-columns: 1fr !important; gap: 28px; }
}

/* Wide fixed-column tables scroll inside their own panel rather than pushing
   the page. Only the demo panel is affected; the rest of the page is fluid. */
@media (max-width: 1040px) {
  .qs-public-root .qsl-quad,
  .qs-public-root .qsl-tri { min-width: 0; }
  .qs-public-root #demo [style*="grid-template-columns: 84px"],
  .qs-public-root #measure [style*="grid-template-columns: 1.4fr"] {
    min-width: 0;
  }
  .qs-public-root #demo,
  .qs-public-root #measure { overflow-x: auto; overscroll-behavior-x: contain; }
}

/* The nav is a single 68px row of brand, three section anchors and the primary
   button. The handoff's responsive notes cover the three column splits and stop
   there, so at 375px the row simply ran past the viewport - and because the
   public root sets overflow-x: hidden, it was clipped rather than scrolled: the
   Request access button, the one action the page exists for, was off-screen and
   unreachable with no scrollbar to suggest it.

   Section anchors go first; they point at content the reader can reach by
   scrolling anyway. The brand's PRIVATE BETA tag goes at the narrowest width,
   where it wraps to two lines and doubles the nav's height. The button always
   stays. */
@media (max-width: 760px) {
  .qs-public-root .qsl-nav-link { display: none; }
  .qs-public-root .qsl-nav-right { gap: 0; }
}

@media (max-width: 420px) {
  .qs-public-root .qsl-nav-tag { display: none; }
}
