/* --------------------------------------------------------------------------
   TIER 1 TOKENS -- ground and scale, shared by every product.
   Declared on .hs-root (not :root) so they cannot leak into the rest of your
   WordPress site, and your theme cannot accidentally win a specificity fight.
   Signature colours (tier 2) live in each product's theme.css.
   -------------------------------------------------------------------------- */
.hs-root {
  /* Shell -- Theme.h Scheme::Blue */
  --rp-bg:        #0a0b11;
  --rp-panel:     #13141d;
  --rp-card:      #191a24;
  --rp-card2:     #20212d;
  --rp-border:    #292b39;
  --rp-border2:   #393c4e;
  --rp-text:      #eceef6;
  --rp-text2:     #969ab0;
  --rp-text3:     #5e617a;

  /* Type scale -- fluid, clamp() so it never needs a media query */
  --rp-f-display: clamp(2.6rem, 6.2vw, 5.1rem);
  --rp-f-h2:      clamp(1.95rem, 3.7vw, 3.05rem);
  --rp-f-h3:      clamp(1.15rem, 1.6vw, 1.4rem);
  --rp-f-lede:    clamp(1.05rem, 1.35vw, 1.24rem);
  --rp-f-body:    clamp(1rem, 1.05vw, 1.09rem);
  --rp-f-small:   0.875rem;
  --rp-f-micro:   0.845rem;   /* eyebrows / labels: was 0.72rem (+2pt) */

  /* Type families -- tier 1 so a product can restyle its whole page from
     its own theme.css by overriding two properties, instead of the ~20
     places base.css used to name a family literally. Whatever a product
     substitutes must also be added to the FONTS <link> in build.py, or the
     browser falls through to the next family in the stack. */
  --rp-font-display: "Space Grotesk", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --rp-font-mono:    "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* Typographic feel -- line-height and tracking, tunable like the sizes */
  --rp-lh-head:   1.06;
  --rp-lh-body:   1.62;
  --rp-ls-head:   -0.028em;

  /* Rhythm */
  --rp-max:       1180px;
  --rp-gutter:    clamp(1.15rem, 4vw, 2.5rem);
  --rp-section:   clamp(4.5rem, 9vw, 8.5rem);
  --rp-r-sm:      10px;
  --rp-r:         16px;
  --rp-r-lg:      22px;

  /* Motion -- fast easings so hovers feel snappy, not floaty */
  --rp-fast:   140ms cubic-bezier(.22,.61,.36,1);
  --rp-med:    240ms cubic-bezier(.22,.61,.36,1);
  --rp-slow:   620ms cubic-bezier(.16,.84,.44,1);
  --rp-spring: 420ms cubic-bezier(.34,1.42,.64,1);
}

/* Clarity Delay - tier-2 signature tokens. VALUES ONLY: one selector block,
   no extra rules. Declared on .hs-root, matching the tier-2 convention every
   product's theme.css follows - not :root, which would leak into the rest of
   the WordPress page and, worse,
   sit farther from the content than tier 1's own .hs-root default, so the
   nearer ancestor (tier 1) would silently win over this override.

   PALETTE SOURCE: the brand guide supplied by the product's designer
   (2026-08-17) - four values, used here as-is rather than reinterpreted:
     #24F1E0  teal    -> --rp-accent
     #FFA98C  peach   -> --rp-brand   (already this product's brand colour)
     #AB8CFF  purple  -> --rp-accent-2
     #566D7D  slate   -> --rp-text2 / --rp-border2, the supporting greys
   The teal and purple are the same two colours the plugin's own GUI uses for
   its meters and knobs, so the page and the product now agree.

   The soft variants are not from the guide - they are lightened forms of the
   guide's own values, needed because several components take a second, paler
   step of the same hue (gradients, hover states). They are derived from the
   supplied colours, not invented alongside them. */
.hs-root {
  /* Purple is the lead signature colour: --rp-brand is what paints the hero
     headline gradient, the ambient wash behind it, the rim light around the
     plugin shot and the logo drop-shadow, so it carries all of those. Peach
     is not dropped - it moves to --rp-accent-2, where it still colours the
     cards and accents that slot uses. Both are the guide's own values; only
     which role each plays has changed. */
  --rp-brand:          #ab8cff;  /* guide: purple */
  --rp-accent:         #24f1e0;  /* guide: teal */
  --rp-accent-soft:    #86f7ec;  /* lightened teal */
  --rp-accent-2:       #ffa98c;  /* guide: peach */
  --rp-accent-2-soft:  #ffc9b5;  /* lightened peach */
  --rp-good:           #24f1e0;  /* the guide carries no green; teal reads as
                                    affirmative here and matches the GUI */
  --rp-warn:           #ffa98c;
  --rp-on-accent:      #0a0b11;  /* all four guide colours are light, so dark
                                    ink is what stays legible on them */

  /* Supporting greys, pulled toward the guide's slate. */
  --rp-text2:          #8ea4b2;
  --rp-border2:        #566d7d;  /* guide: slate */

  /* Tier-1 override. --rp-text3 is the FAINT text step - it colours the
     testimonial credit line, the review channel name, price notes, footer
     links and legal, the sysreq labels and the mode descriptions. Set to the
     guide's teal rather than a grey, so those lines read as a deliberate
     accent instead of receding. */
  --rp-text3:          #24f1e0;

  /* The guide specifies Catamaran. Registered in build.py's FONTS <link>, so
     it is actually fetched rather than silently falling through. Tier 1's
     stack stays behind it as the fallback. The guide's tracking of 100
     (0.1em) is deliberately NOT applied globally: at display sizes it pulls
     the headline apart badly. Tracking is exposed in the studio panel so it
     can be judged per level rather than set blind. */
  --rp-font-display: "Catamaran", "Space Grotesk", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

/* Clarity Delay tier-3: product-local extras (optional), not part of the
   shared contract. Declared on .hs-root, matching tier 1 and tier 2.

   Everything here styles something only THIS product has. Rules that style
   shared components (.hs-review*, .hs-quote__img, .hs-vh, .hs-prices--single,
   the button states) used to live in this file purely because base.css was
   frozen by the golden fixture; they now sit in shared/css/base.css where
   the tiering says they belong, so the next product to adopt reviews.j2 or a
   testimonial portrait gets them for free. */
.hs-root {
  /* --rp-brass is read by base.css itself, so it must be defined here even
     though this product renders no wavebar. The wave/signal tokens that used
     to sit alongside it (--rp-wave-hi, --rp-wave-lo, --rp-sig-red,
     --rp-sig-green) are gone: they existed only for hero.j2's waveform strip,
     which draws a ceiling and the gain reduction taken against it. This
     plugin imposes no ceiling and reduces no gain, so it opts out of the
     strip entirely (hero.wavebar is unset in product.yml) and nothing reads
     those tokens any more. */
  --rp-brass: var(--rp-accent-2);
}

/* ABOVE-THE-FOLD BUDGET
   The hero's job at load is: mark, what it is, the promise, the buttons, and
   the three ticks that answer "what's the catch". On a 1080p laptop the
   shared spacing pushed that last row under the fold once the logo grew, so
   the gaps between those blocks are tightened here - and only the gaps. No
   font size, no line-height and no colour changes, so the hierarchy is
   untouched; the stack just stops running long. Product-local, because it is
   this product's taller logo and four pills that need the room, not a
   judgement about heroes in general. */
.hs-root .hs-hero { padding-top: clamp(2.2rem, 5vw, 4rem); }
.hs-root .hs-hero__logo { margin-bottom: clamp(.5rem, 1.1vw, .85rem); }
.hs-root .hs-badge-row { margin-bottom: 1.15rem; }
.hs-root .hs-hero h1 { margin-bottom: .85rem; }
.hs-root .hs-hero .hs-lede { margin-bottom: 1.45rem; }
.hs-root .hs-trust { margin-top: 1.5rem; }

/* The closing panel's two wash lights sit left and right. Shared base.css
   puts the accent (teal) on the left and the brand colour on the right, but
   this product's closing button row leads with the purple Buy button on the
   LEFT - so the purple wash was behind the wrong button and the two read as
   unrelated. Swapped, so the purple light sits under the purple button.
   Everything else about the panel is untouched. */
.hs-root .hs-final::before {
  background:
    radial-gradient(38% 55% at 18% 50%, color-mix(in srgb, var(--rp-brand) 30%, transparent), transparent 70%),
    radial-gradient(38% 55% at 82% 50%, color-mix(in srgb, var(--rp-accent) 32%, transparent), transparent 70%);
}

/* Review play buttons follow YouTube's own affordance: a rounded rectangle
   rather than a circle, sitting dark and semi-transparent at rest and turning
   YouTube red on hover - which is exactly what the real player does. Using
   the familiar shape and the familiar hover means the card reads as "this is
   a video" without needing a label, and the red appears only on intent, so a
   grid of four cards is not four red blocks competing with the page. */
.hs-root .hs-review__play {
  width: 68px; height: 48px; border-radius: 14px;
  background: rgba(18,18,18,.78); border: 0;
  color: #fff;
  transition: transform var(--rp-med), background var(--rp-med);
}
.hs-root .hs-review__play svg { width: 30px; height: 30px; margin-left: 1px; }
.hs-root .hs-review:hover .hs-review__play {
  background: #f00; color: #fff; transform: scale(1.06);
}

/* The hero shot floats: no panel behind it, no border around it, no inset
   rim. Only a soft drop shadow is kept, so the artwork still sits above the
   page rather than looking pasted flat onto it. */
.hs-root .hs-shot__frame {
  border: 0;
  background: none;
  box-shadow: 0 40px 90px -45px rgba(0,0,0,.95);
}

/* A much larger hero mark. This logo is a horizontal lockup - mark plus
   wordmark, roughly 4.9:1 - where the shared default (430px) was sized for a
   near-square one, so it read as small here at the same number. The vw term
   keeps it from overflowing a narrow window. */
.hs-root .hs-hero__logo { width: min(760px, 88vw); }

/* The last glyph of a gradient headline was being cut off on its right side
   ("Reverb" losing most of its b). .hs-grad paints text with
   background-clip: text on an INLINE box, so the paint area stops at the
   glyph advance width - and .hs-display also applies letter-spacing:-0.04em.
   Catamaran's ink extends past that box where the previous face did not, so
   the overhang had nothing to paint on. The padding gives the paint box room;
   the equal negative margin means layout does not move. Higher specificity
   than base.css's own .hs-grad, which is concatenated after this file. */
.hs-root .hs-grad { padding-right: .09em; margin-right: -.09em; }

/* The card wearing the ribbon glows in the ribbon's own colour, always on -
   every other card only lights up under the cursor. Bound with :has() to the
   badge rather than to a card position, so the highlight follows the ribbon
   automatically if a different feature becomes the new one. */
.hs-root .hs-card:has(.hs-card__badge) {
  border-color: color-mix(in srgb, var(--rp-accent) 45%, transparent);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--rp-accent) 18%, transparent) inset,
    0 26px 60px -34px rgba(0,0,0,.95),
    0 0 62px -26px color-mix(in srgb, var(--rp-accent) 70%, transparent);
}

/* "New" flag on a feature card: a ribbon folded over the top-right corner,
   at 45 degrees. No extra markup and no clipping rules are needed - .hs-card
   already sets position: relative and overflow: hidden, so an oversized
   rotated band is trimmed to the card's rounded corner for free.

   The teal is the brand guide's own #24F1E0 (via --rp-accent). It is the
   brightest of the four guide colours against this dark ground, so it still
   announces itself while staying on palette, and dark ink on it clears
   contrast comfortably.

   The band is deliberately wider than the corner it covers: at 45 degrees the
   diagonal is longer than either edge, so a band sized to the visible span
   would show cut ends where it meets the card border. */
.hs-card__badge {
  position: absolute; top: 1.15rem; right: -3rem;
  width: 11rem; transform: rotate(45deg);
  text-align: center; padding: .32em 0;
  font-family: var(--rp-font-mono);
  font-size: .6rem; font-weight: 700; letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--rp-on-accent); background: var(--rp-accent);
  box-shadow: 0 8px 20px -10px rgba(0,0,0,.95);
}

/* Two routes into the product, weighted differently on purpose: the purchase
   is filled in the accent teal and carries the eye, the trial sits beneath it
   as a purple outline - clearly available, clearly the second option. The
   purple ties it to the brand colour without competing with the fill above.
   Higher specificity than base.css's .hs-btn--ghost, which loads after this
   file and would otherwise win at equal weight. */
.hs-root .hs-btn--trial {
  border-color: color-mix(in srgb, var(--rp-brand) 55%, transparent);
  color: var(--rp-brand);
  background: color-mix(in srgb, var(--rp-brand) 8%, transparent);
}
.hs-root .hs-btn--trial:hover {
  border-color: var(--rp-brand);
  background: color-mix(in srgb, var(--rp-brand) 16%, transparent);
}

/* HIDDEN FOR NOW, not deleted. The pill copy is still in product.yml so it
   can come back with one line; hiding it here rather than emptying the data
   keeps the decision reversible and the content intact. display:none also
   removes it from the accessibility tree, so a screen reader is not read
   three labels nobody can see. */
.hs-root .hs-hero .hs-badge-row { display: none; }

/* --------------------------------------------------------------------------
   HERO WORD MOTION - "Delay" echoes, "Reverb" blooms
   Each word gets the behaviour it names, which is the whole joke: the delay
   word repeats itself in fading copies at a fixed interval, the reverb word
   swells and decays as a diffuse halo with no discrete repeats.

   Both are built from ::before/::after copies of the word rather than
   animating the text itself, so the real glyphs never move - the layout is
   untouched and the text stays selectable and readable. Both are switched off
   entirely under prefers-reduced-motion further down base.css, which already
   kills animations globally.
   -------------------------------------------------------------------------- */
.hs-fx { position: relative; display: inline-block; }
.hs-fx::before, .hs-fx::after {
  content: attr(data-word);
  position: absolute; inset: 0;
  pointer-events: none;
}
/* Delay: two discrete repeats, offset in time and space, fading out - the
   visual equivalent of feedback taps. */
.hs-fx--delay::before,
.hs-fx--delay::after { color: var(--rp-accent); opacity: 0; }
.hs-fx--delay::before { animation: hs-echo 3.4s ease-out infinite; }
.hs-fx--delay::after  { animation: hs-echo 3.4s ease-out infinite .28s; }
@keyframes hs-echo {
  0%   { opacity: .5; transform: translateX(0) scale(1); }
  35%  { opacity: 0;  transform: translateX(.22em) scale(1.02); }
  100% { opacity: 0;  transform: translateX(.22em) scale(1.02); }
}
/* Reverb: no discrete repeats - one soft bloom that swells and decays. */
.hs-fx--reverb::before {
  color: var(--rp-brand);
  filter: blur(9px);
  animation: hs-bloom 4.6s ease-in-out infinite;
}
.hs-fx--reverb::after { content: none; }
@keyframes hs-bloom {
  0%, 100% { opacity: .12; transform: scale(1); }
  45%      { opacity: .5;  transform: scale(1.035); }
}

/* The hero pills were carrying the same type size as body labels elsewhere,
   which made three of them read as a second headline under the mark. They are
   a caption, not a claim - so they step down a size and tighten their padding.
   Only the pills in the hero: the same class is used for section eyebrows
   where the larger size is right. */
.hs-root .hs-hero .hs-badge {
  font-size: .72rem;
  padding: .3em .7em;
  letter-spacing: .09em;
}

/* --------------------------------------------------------------------------
   MODES - the delay modes and reverb engines, named.
   Styles sections/05-modes.j2, which is bespoke to this product: nothing
   else under products/ has modes, so neither the template nor these rules
   are shared.
   -------------------------------------------------------------------------- */
.hs-modes { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: 1.25rem; }
.hs-modes__group {
  padding: clamp(1.5rem, 2.6vw, 2rem);
  border: 1px solid var(--rp-border);
  border-radius: var(--rp-r);
  background: linear-gradient(168deg, var(--rp-card), var(--rp-panel));
}
.hs-modes__title {
  font-family: var(--rp-font-mono);
  font-size: .68rem; letter-spacing: .13em; text-transform: uppercase;
  color: var(--rp-text3); margin-bottom: 1.15rem;
}
.hs-modes__list { display: grid; gap: .55rem; }
.hs-modes__list li {
  display: flex; align-items: baseline; gap: .75rem;
  font-size: .95rem; color: var(--rp-text);
  padding-bottom: .55rem; border-bottom: 1px solid var(--rp-border);
}
.hs-modes__list li:last-child { border-bottom: 0; padding-bottom: 0; }
.hs-modes__n {
  font-family: var(--rp-font-mono);
  font-size: .72rem; color: var(--rp-text3); flex: none; min-width: 1.4em;
}
.hs-modes__desc { color: var(--rp-text3); font-size: .85rem; margin-left: auto; text-align: right; }
.hs-modes__new {
  font-family: var(--rp-font-mono);
  font-size: .6rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--rp-on-accent); background: var(--rp-brand);
  border-radius: 999px; padding: .16em .6em; margin-left: .55rem;
}

/* The focus shot, inside the modes block. Full wrap width so its edges line
   up with the two tables below it - a narrower, centred image floating above
   full-width tables reads as a separate thing that wandered in.

   No hover zoom: hs-figure scales on hover for the diagrams it was written
   for, and a plugin GUI just goes soft when it is enlarged. */
/* #hsModes, not .hs-focus-shot alone: base.css loads AFTER this file (tokens
   -> theme -> section -> base) and its reset sets margin:0 on every figure.
   That reset ties on specificity, so it was winning on order alone and the
   image sat flush against the tables. The id settles it. */
#hsModes .hs-focus-shot {
  width: 100%;
  /* CROPPED, not shrunk: the source is 4:3 and ran 825px tall at this width,
     which made the shot the whole section. 16:9 takes a quarter off the height
     while keeping the edges flush with the tables below. cover crops top and
     bottom, which is where this frame has the least going on. */
  aspect-ratio: 16 / 9;
  /* The same gap the intro text leaves above it, so the image is spaced
     evenly inside the block rather than butted against the tables. */
  margin: 0 auto clamp(2rem, 3.5vw, 2.8rem);
}
#hsModes .hs-focus-shot img { height: 100%; object-fit: cover; }
#hsModes .hs-focus-shot:hover img { transform: none; }

/* ==========================================================================
   HARDSTOP SALES PAGE -- structural stylesheet (tier 4 of the cascade)
   Tokens now live in three tiers, assembled ahead of this file by
   stylesheet() in build.py:
     tier 1  shared/css/tokens.css        ground + scale, every product
     tier 2  products/<slug>/theme.css    eight signature values
     tier 3  products/<slug>/section.css  product-local extras (optional)
   This file consumes those custom properties; it declares none of its own.
   ========================================================================== */

/* @property lets the browser interpolate a custom property instead of
   snapping between values. Without this the knob arc jumps; with it, it
   sweeps. Unsupported browsers ignore the block and just snap -- no harm. */
@property --arc { syntax: '<angle>'; inherits: true; initial-value: 0turn; }

/* --------------------------------------------------------------------------
   2. RESET -- scoped. Divi injects a lot of global CSS; this neutralises it
   inside our block only, without touching the rest of the site.
   -------------------------------------------------------------------------- */
.hs-root,
.hs-root *,
.hs-root *::before,
.hs-root *::after { box-sizing: border-box; }

.hs-root {
  margin: 0;
  padding: 0;
  background: var(--rp-bg);
  color: var(--rp-text);
  font-family: var(--rp-font-display);
  font-size: var(--rp-f-body);
  line-height: var(--rp-lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
  position: relative;
  isolation: isolate;           /* keeps our z-indexes out of Divi's stack */
}

/* :where() contributes ZERO specificity, so every one of these rules weighs
   exactly as much as ".hs-root" alone (0,1,0) instead of (0,1,1).
   That matters: written the naive way, ".hs-root p { margin: 0 }" would beat
   ".hs-price__sub { margin-bottom: 1.5rem }" -- same class count, but the
   element selector tips it -- and component spacing would silently vanish.
   With :where() the reset still overpowers Divi's global styles but always
   loses to our own component classes. This is the single most useful
   specificity trick in modern CSS. */
.hs-root :where(h1, h2, h3, h4, p, ul, ol, li, figure, dl, dd, dt) {
  margin: 0; padding: 0; border: 0;
}
.hs-root :where(ul, ol) { list-style: none; }

/* Tables are the one place :where() is the WRONG tool. Divi ships global table
   chrome -- `table { border: 1px solid #eee; margin: 0 0 15px }` plus th/td
   borders and padding -- and some of those rules are class-scoped (0,1,1), so a
   zero-specificity :where() reset (0,1,0) would lose to them. These are written
   with a real element selector (0,1,1) instead: they tie with Divi and win on
   source order, because this <style> block is injected after the theme's.
   Left unreset, Divi's #eee border painted a bright rectangle around .hs-table
   and its 15px bottom margin dropped .hs-tablewrap's rounded border a row's
   worth below the table's actual edge -- the two outlines visibly came apart.
   Everything here is re-set properly by section 14; this only clears the theme.
   Section 14 sits later in the file, so it wins the same source-order tie. */
.hs-root table { border: 0; border-collapse: collapse; border-spacing: 0; margin: 0; background: none; }
.hs-root caption,
.hs-root thead, .hs-root tbody, .hs-root tfoot,
.hs-root tr, .hs-root th, .hs-root td {
  margin: 0; padding: 0; border: 0; background: none;
  font: inherit; color: inherit; text-align: inherit; vertical-align: inherit;
}

.hs-root :where(h1, h2, h3, h4) {
  font-weight: 700;
  line-height: var(--rp-lh-head);
  letter-spacing: var(--rp-ls-head);
  color: var(--rp-text);
}

.hs-root :where(img, svg, canvas, video, iframe) {
  display: block; max-width: 100%; height: auto;
}

/* :where() drops this to zero-for-the-selector specificity, so a component that
   sets its own colour (.hs-btn, below) wins even though it is also 1 class deep.
   Without it, .hs-root a (0,1,1) beat .hs-btn (0,1,0) and every filled button
   inherited body-text white instead of its dark --btn-fg. */
.hs-root :where(a) { color: inherit; text-decoration: none; }
.hs-root button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

.hs-root ::selection { background: var(--rp-accent); color: #04060c; }

.hs-root :focus-visible {
  outline: 2px solid var(--rp-accent);
  outline-offset: 3px;
  border-radius: 6px;
}

/* --------------------------------------------------------------------------
   3. LAYOUT PRIMITIVES
   -------------------------------------------------------------------------- */
.hs-wrap {
  width: 100%;
  max-width: var(--rp-max);
  margin-inline: auto;
  padding-inline: var(--rp-gutter);
}
.hs-wrap--wide { max-width: 1400px; }

.hs-section { padding-block: var(--rp-section); position: relative; }
.hs-section--tight { padding-block: clamp(3rem, 5vw, 4.5rem); }

/* Hairline separators that fade at the edges -- subtler than a full border */
.hs-rule {
  height: 1px; border: 0; margin: 0;
  background: linear-gradient(90deg,
    transparent, var(--rp-border) 18%, var(--rp-border) 82%, transparent);
}

.hs-grid { display: grid; gap: clamp(1rem, 2vw, 1.6rem); }
.hs-grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); }
.hs-grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr)); }

.hs-center { text-align: center; }
/* Third-party storefront scripts (Audioloom's embedded storefront among them)
   show and hide their own elements by toggling the `hidden` attribute, and
   rely on the page having a rule that honours it. The UA default is weak
   enough that any display value overrides it, so this needs the !important
   the vendor asks for. No markup this repo generates carries the attribute -
   it exists for injected elements only. */
[hidden] { display: none !important; }
/* Visually hidden, still announced. For text that qualifies a visible label
   (e.g. spelling out what an "Official video" badge means) without repeating
   it on screen. */
.hs-vh {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.hs-measure { max-width: 62ch; }
.hs-measure-tight { max-width: 48ch; }
.hs-center .hs-measure,
.hs-center .hs-measure-tight { margin-inline: auto; }

/* --------------------------------------------------------------------------
   4. TYPOGRAPHY HELPERS
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   SALE - banner, struck price, countdown

   SHARED, not per-product. These were written in clarity-delay/section.css
   because Clarity Delay was the only product with a sale block; the markup
   that uses them is emitted by the shared pricing.j2, so ANY product running
   a sale rendered this banner and only one product had the CSS to paint it.
   Every colour here comes from --rp-accent, which each theme declares, so the
   banner takes on whichever product it appears in.
   -------------------------------------------------------------------------- */
.hs-sale {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: .75rem 1.1rem;
  margin: 0 auto clamp(1.5rem, 3vw, 2.2rem);
  padding: .7rem 1.15rem;
  width: fit-content; max-width: 100%;
  /* No longer a pill: the countdown sits on its own line below the price, so
     a 999px radius would bow the sides of a two-line box. */
  border-radius: var(--rp-r-lg);
  border: 1px solid color-mix(in srgb, var(--rp-accent) 45%, transparent);
  background: color-mix(in srgb, var(--rp-accent) 9%, transparent);
}
.hs-sale__tag {
  font-family: var(--rp-font-mono);
  font-size: .62rem; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--rp-on-accent); background: var(--rp-accent);
  border-radius: 999px; padding: .34em .8em;
}
.hs-sale__price { font-size: 1.05rem; color: var(--rp-text); }
.hs-sale__price s {
  color: var(--rp-text2); margin-right: .15em; text-decoration-thickness: .08em;
}
.hs-sale__price b { color: var(--rp-accent); font-weight: 700; }
/* OWN LINE. flex-basis:100% breaks the row inside the wrapping flex parent,
   and the hairline above separates the deadline from the price rather than
   letting the two read as one run-on strip. */
.hs-sale__clock {
  flex-basis: 100%; justify-content: center;
  padding-top: .62rem;
  border-top: 1px solid color-mix(in srgb, var(--rp-accent) 24%, transparent);
  display: inline-flex; align-items: baseline; gap: .5em;
  font-family: var(--rp-font-mono);
}
.hs-sale__clock-label {
  font-size: .6rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--rp-text3);
}
/* Tabular figures so the seconds ticking over does not shift the layout. */
.hs-sale__clock-val {
  font-size: .95rem; font-weight: 700; color: var(--rp-text);
  font-variant-numeric: tabular-nums;
}
/* The price it WAS. Sized absolutely, not in em: em here resolves against
   .hs-price__amt, whose font-size is the card's - the 2.6-3.5rem figure lives
   on the sibling <b> - so .55em rendered this at about 9px with a strike too
   thin to read. Set to sit clearly below the new price but well above the
   "one-time" note, and lifted from --rp-text3 to --rp-text2: struck text is
   already visually demoted, and dimming it as well made it unreadable. */
.hs-price__was {
  color: var(--rp-text2); font-size: clamp(1.15rem, 1.7vw, 1.45rem);
  font-weight: 500; margin-right: .18em; text-decoration-thickness: .07em;
}

/* THE SAVING, next to a struck-through price. Shared rather than per-product:
   the hub and every product page all render it, and a second copy in a
   product's section.css is a second place for the two to drift apart.

   Deliberately quieter than the sale price it follows. The new price is the
   number that closes the sale; this only tells a shopper how to feel about it,
   and two loud figures side by side make neither read. */
.hs-save {
  /* --rp-accent is declared by a PRODUCT's theme, so it is undefined on the
     hub's deal banner, which sits outside any card. An undefined var inside
     color-mix() invalidates the whole declaration - border, background and
     colour all silently drop and the chip renders as plain white text. The
     fallback chain keeps it painted everywhere: the product's accent inside a
     themed card, the house accent on the hub, a literal as the last resort. */
  --save-ink: var(--rp-accent, var(--hub-accent, #7c5cff));
  display: inline-block; white-space: nowrap; vertical-align: baseline;
  margin-left: .45em;
  padding: .18em .5em; border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--save-ink) 40%, transparent);
  background: color-mix(in srgb, var(--save-ink) 12%, transparent);
  color: var(--save-ink);
  font-family: var(--rp-font-mono); font-size: .64rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; line-height: 1.3;
}
/* On the price card it is a flex item beside a 3rem figure - `display:block`
   would do nothing there, so it is aligned and spaced instead. margin-left
   separates it from the price note it follows ("one-time"). */
.hs-save--card { align-self: center; margin-left: .55rem; }
/* The featured card is themed in --rp-brand throughout - its rule, glow, flag,
   ticks and button all use it - so a pill in --rp-accent reads as a stray
   element from another palette. HardStop is the case that shows it: accent is
   Drive blue, brand is clip red, and the blue pill sat alone on a red card. */
.hs-price--feature .hs-save { --save-ink: var(--rp-brand); }
/* .hs-price__amt span paints EVERY span in the price row --rp-text3 at .9rem,
   and (0,1,1) outranks .hs-save's own (0,1,0) - so inside a price card the
   pill lost both its colour and its size and came out grey and oversized.
   Re-asserted here at (0,2,0) rather than by reordering the file, which would
   only hide the collision until the next rule lands between them. */
.hs-price__amt .hs-save { color: var(--save-ink); font-size: .64rem; }

/* Struck price inside a button, for a CTA that quotes a price. */
.hs-btn__was {
  opacity: .62; font-weight: 500; margin-right: .12em;
  text-decoration-thickness: .07em;
}

.hs-eyebrow {
  font-family: var(--rp-font-mono);
  font-size: var(--rp-f-micro);
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--rp-accent);
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
}
.hs-eyebrow::before {
  content: "";
  width: 22px; height: 2px;
  background: currentColor;
  border-radius: 2px;
  opacity: 0.85;
}
.hs-center .hs-eyebrow::before { display: none; }
/* One step up from the standard eyebrow, with the tracking eased off so the
   extra size does not turn into extra sprawl. */
.hs-eyebrow--lg {
  font-size: calc(var(--rp-f-micro) * 1.22);
  letter-spacing: 0.16em;
  color: var(--rp-accent-soft);
}

/* text-wrap:balance lets the browser even out the lines of a heading instead of
   filling greedily and leaving one orphaned word on the last line -- the job a
   hand-placed <br> used to do, except it re-solves itself at every window
   width. Browsers that don't support it simply wrap the old way, and it is
   capped at a few lines by spec so it never costs layout time on body copy.
   `pretty` is the cheaper cousin for paragraphs: it only fixes the last line. */
.hs-display { font-size: var(--rp-f-display); letter-spacing: -0.04em; text-wrap: balance; }
.hs-h2      { font-size: var(--rp-f-h2); text-wrap: balance; }
.hs-h3      { font-size: var(--rp-f-h3); letter-spacing: -0.018em; text-wrap: balance; }

.hs-lede { font-size: var(--rp-f-lede); color: var(--rp-text2); line-height: calc(var(--rp-lh-body) + .04); text-wrap: pretty; }
.hs-body { color: var(--rp-text2); }
.hs-mono {
  font-family: var(--rp-font-mono);
  font-size: var(--rp-f-small);
  letter-spacing: 0.01em;
}
.hs-dim  { color: var(--rp-text3); }
.hs-white{ color: var(--rp-text); }

/* Gradient wordmark treatment matching the plugin logo's white->red split */
.hs-grad {
  background: linear-gradient(96deg, var(--rp-text) 0%, var(--rp-text) 42%, var(--rp-brand) 78%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.hs-accent-txt  { color: var(--rp-accent); }
.hs-clip-txt    { color: var(--rp-brand); }
.hs-safety-txt  { color: var(--rp-good); }
.hs-ceiling-txt { color: var(--rp-accent-2); }

/* --------------------------------------------------------------------------
   5. AMBIENT BACKGROUND -- the studio-glow feel, done in CSS so it costs
   nothing to download. Two blurred radial "lamps" plus a fine grid.
   -------------------------------------------------------------------------- */
.hs-atmos { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
.hs-atmos { opacity: var(--rp-atmos-strength, 1); }
.hs-atmos::before,
.hs-atmos::after {
  content: "";
  position: absolute;
  width: 62vw; aspect-ratio: 1;
  border-radius: 50%;
  filter: blur(110px);
  opacity: 0.4;
}
.hs-atmos::before { top: -22%; left: -14%; background: radial-gradient(circle, var(--rp-accent), transparent 66%); }
.hs-atmos::after  { top: 6%;  right: -18%; background: radial-gradient(circle, var(--rp-brand),   transparent 66%); opacity: .3; }

.hs-mesh {
  position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background-image:
    linear-gradient(var(--rp-border2) 1px, transparent 1px),
    linear-gradient(90deg, var(--rp-border2) 1px, transparent 1px);
  background-size: 62px 62px;
  opacity: var(--rp-mesh-strength, 0.13);
  mask-image: radial-gradient(ellipse 80% 62% at 50% 34%, #000 12%, transparent 76%);
  -webkit-mask-image: radial-gradient(ellipse 80% 62% at 50% 34%, #000 12%, transparent 76%);
}

.hs-noise {
  position: absolute; inset: 0; pointer-events: none; z-index: 1; opacity: var(--rp-noise-strength, .16);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  mix-blend-mode: overlay;
}

/* --------------------------------------------------------------------------
   6. NAV -- hidden at top, slides down once you scroll past the hero
   -------------------------------------------------------------------------- */
.hs-nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 90;
  background: color-mix(in srgb, var(--rp-bg) 80%, transparent);
  backdrop-filter: blur(16px) saturate(140%);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  border-bottom: 1px solid transparent;
  transform: translateY(-104%);
  transition: transform var(--rp-med), border-color var(--rp-med);
  will-change: transform;
}
.hs-nav.is-visible { transform: translateY(0); border-bottom-color: var(--rp-border); }
.hs-nav__inner {
  max-width: var(--rp-max); margin-inline: auto;
  padding: 0.7rem var(--rp-gutter);
  display: flex; align-items: center; gap: 1.5rem;
}
.hs-nav__logo { width: 108px; flex: none; }
.hs-nav__logo svg { width: 100%; height: auto; }
.hs-nav__links { display: flex; gap: 1.65rem; margin-left: auto; }
.hs-nav__links a {
  font-size: var(--rp-f-small); color: var(--rp-text2);
  position: relative; padding-block: 3px;
  transition: color var(--rp-fast);
}
.hs-nav__links a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1.5px;
  background: var(--rp-accent); border-radius: 2px;
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--rp-med);
}
.hs-nav__links a:hover { color: var(--rp-text); }
.hs-nav__links a:hover::after { transform: scaleX(1); }
@media (max-width: 880px) { .hs-nav__links { display: none; } .hs-nav__inner > .hs-btn { margin-left: auto; } }

/* --------------------------------------------------------------------------
   7. BUTTONS -- the single most-touched interactive element, so the states
   get the most care. Sheen sweep on hover, 1px press travel on :active.
   -------------------------------------------------------------------------- */
.hs-btn {
  --btn-bg: var(--rp-accent);
  --btn-fg: #04060c;
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: .6em;
  padding: 0.92em 1.75em;
  border-radius: 999px;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-weight: 700;
  font-size: 0.97rem;
  letter-spacing: -0.004em;
  white-space: nowrap;
  /* .hs-root sets antialiased, which thins strokes. That helps light text on a
     dark page but hurts DARK text on a bright fill -- exactly what a filled
     button is. Back to the platform default here so the label stays solid. */
  -webkit-font-smoothing: auto;
  -moz-osx-font-smoothing: auto;
  overflow: hidden;
  isolation: isolate;
  transition: transform var(--rp-fast), box-shadow var(--rp-med), background var(--rp-fast);
  /* The glow is derived from --btn-bg rather than hardcoded, so retinting
     the brand colour retints the shadow with it. color-mix() is what makes
     this possible without a preprocessor. */
  box-shadow: 0 1px 0 rgba(255,255,255,.22) inset,
              0 6px 22px -8px color-mix(in srgb, var(--btn-bg) 62%, transparent);
}
.hs-btn::after {                       /* the sheen */
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(105deg, transparent 32%, rgba(255,255,255,.42) 50%, transparent 68%);
  transform: translateX(-120%);
  transition: transform 620ms cubic-bezier(.22,.61,.36,1);
}
.hs-btn:hover  { transform: translateY(-2px); box-shadow: 0 1px 0 rgba(255,255,255,.28) inset, 0 14px 34px -10px color-mix(in srgb, var(--btn-bg) 78%, transparent); }
.hs-btn:hover::after { transform: translateX(120%); }
.hs-btn:active { transform: translateY(0); transition-duration: 60ms; }

.hs-btn--pro    { --btn-bg: var(--rp-brand); }

.hs-btn--ghost {
  --btn-fg: var(--rp-text);
  /* light-on-dark again, so the thinning is wanted back */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background: rgba(255,255,255,.035);
  border: 1px solid var(--rp-border2);
  box-shadow: none;
  backdrop-filter: blur(6px);
}
.hs-btn--ghost:hover { background: rgba(255,255,255,.075); border-color: var(--rp-text3); box-shadow: none; }

.hs-btn--sm  { padding: 0.66em 1.25em; font-size: .875rem; }
.hs-btn--lg  { padding: 1.05em 2.1em; font-size: 1.03rem; }
.hs-btn--full{ width: 100%; }

.hs-btn__ico { width: 1.05em; height: 1.05em; flex: none; transition: transform var(--rp-spring); }
.hs-btn:hover .hs-btn__ico--down  { transform: translateY(2px); }
.hs-btn:hover .hs-btn__ico--right { transform: translateX(3px); }

.hs-cta-row { display: flex; flex-wrap: wrap; gap: .85rem; }
.hs-center .hs-cta-row { justify-content: center; }

/* --------------------------------------------------------------------------
   8. CARD -- cursor-tracked glow. JS writes --mx/--my as percentages; the
   ::before layer is a radial gradient anchored to those, faded in on hover.
   This is why the glow follows the pointer instead of just switching on.
   -------------------------------------------------------------------------- */
.hs-card {
  position: relative;
  background: linear-gradient(168deg, var(--rp-card) 0%, var(--rp-panel) 100%);
  border: 1px solid var(--rp-border);
  border-radius: var(--rp-r);
  padding: clamp(1.4rem, 2.4vw, 1.95rem);
  overflow: hidden;
  isolation: isolate;
  transition: transform var(--rp-med), border-color var(--rp-med), box-shadow var(--rp-med);
}
.hs-card::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(340px circle at var(--mx, 50%) var(--my, 0%),
              color-mix(in srgb, var(--rp-glow, var(--rp-accent)) var(--rp-cardglow, 17%), transparent), transparent 62%);
  opacity: 0; transition: opacity var(--rp-med);
}
.hs-card:hover {
  transform: translateY(-4px);
  border-color: var(--rp-border2);
  box-shadow: 0 22px 48px -26px rgba(0,0,0,.9);
}
.hs-card:hover::before { opacity: 1; }

.hs-card__ico {
  width: 46px; height: 46px;
  display: grid; place-items: center;
  border-radius: 13px;
  background: color-mix(in srgb, var(--rp-glow, var(--rp-accent)) 13%, transparent);
  border: 1px solid color-mix(in srgb, var(--rp-glow, var(--rp-accent)) 30%, transparent);
  color: var(--rp-glow, var(--rp-accent));
  margin-bottom: 1.1rem;
  transition: transform var(--rp-spring), background var(--rp-med);
}
.hs-card:hover .hs-card__ico { transform: translateY(-2px) scale(1.06) rotate(-4deg); }
.hs-card__ico svg { width: 23px; height: 23px; }
.hs-card h3 { margin-bottom: .5rem; font-size: 1.11rem; }
.hs-card p  { color: var(--rp-text2); font-size: .955rem; line-height: 1.62; }

/* Per-card accent -- mirrors how the plugin colour-codes its own controls */
.hs-g-accent  { --rp-glow: var(--rp-accent); }
.hs-g-safety  { --rp-glow: var(--rp-good); }
.hs-g-clip    { --rp-glow: var(--rp-brand); }
.hs-g-ceiling { --rp-glow: var(--rp-accent-2); }
.hs-g-danger  { --rp-glow: var(--rp-warn); }
/* .hs-g-brass -- HardStop's own tier-3 waveform accent; declared in
   section.css so it travels with --rp-brass instead of forcing every
   product to declare a colour it has no use for. */

/* --------------------------------------------------------------------------
   9. HERO
   -------------------------------------------------------------------------- */
.hs-hero {
  position: relative;
  padding-top: clamp(3.5rem, 8vw, 6.5rem);
  padding-bottom: clamp(3rem, 6vw, 5rem);
  text-align: center;
  overflow: hidden;
}
.hs-hero__inner { position: relative; z-index: 2; }

.hs-hero__logo { width: min(430px, 74vw); margin: 0 auto clamp(1.4rem, 3vw, 2.1rem); }
.hs-hero__logo svg { width: 100%; height: auto; filter: drop-shadow(0 6px 26px color-mix(in srgb, var(--rp-brand) 32%, transparent)); }

.hs-hero h1 { margin-bottom: 1.1rem; }
.hs-hero .hs-lede { margin: 0 auto 1.9rem; max-width: 54ch; }

.hs-badge-row { display: flex; flex-wrap: wrap; justify-content: center; gap: .5rem; margin-bottom: 1.5rem; }
.hs-badge {
  display: inline-flex; align-items: center; gap: .45em;
  padding: .38em .85em;
  border-radius: 999px;
  border: 1px solid var(--rp-border2);
  background: rgba(255,255,255,.03);
  font-family: var(--rp-font-mono);
  font-size: var(--rp-f-micro);
  letter-spacing: .11em; text-transform: uppercase;
  color: var(--rp-text2);
  transition: border-color var(--rp-fast), color var(--rp-fast), background var(--rp-fast);
}
.hs-badge:hover { border-color: var(--rp-accent); color: var(--rp-text); background: color-mix(in srgb, var(--rp-accent) 11%, transparent); }
.hs-badge__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--rp-good); flex: none; }
.hs-badge--free { border-color: color-mix(in srgb, var(--rp-good) 45%, transparent); color: var(--rp-good); background: color-mix(in srgb, var(--rp-good) 10%, transparent); }

.hs-trust { display: flex; flex-wrap: wrap; justify-content: center; gap: .55rem 1.6rem; margin-top: 2.15rem; }
.hs-trust li {
  display: inline-flex; align-items: center; gap: .45em;
  font-size: var(--rp-f-small); color: var(--rp-text3);
}
.hs-trust svg { width: 15px; height: 15px; color: var(--rp-good); flex: none; }

/* Hero shot: perspective tilt that eases flat as it scrolls into view */
.hs-shot {
  position: relative;
  margin-top: clamp(2.5rem, 5vw, 4rem);
  perspective: 1800px;
}
.hs-shot__frame {
  position: relative;
  border-radius: var(--rp-r-lg);
  overflow: hidden;
  border: 1px solid var(--rp-border2);
  background: var(--rp-panel);
  box-shadow:
    0 0 0 1px rgba(255,255,255,.03) inset,
    0 40px 90px -40px rgba(0,0,0,.95),
    0 0 90px -30px color-mix(in srgb, var(--rp-accent) 40%, transparent);
  transform: rotateX(9deg) scale(.965);
  transform-origin: 50% 100%;
  transition: transform 1.1s cubic-bezier(.16,.84,.44,1), box-shadow var(--rp-slow);
}
.hs-shot.is-in .hs-shot__frame { transform: rotateX(0deg) scale(1); }
.hs-shot__frame img { width: 100%; }

/* The blue/red rim light around the hero shot, matching the plugin's own glow */
.hs-shot__glow {
  /* inset was -14% -6%: the -6% pushed this 3px past the viewport edge on a phone,
     which is exactly the kind of overflow you should fix at the source rather than
     paper over with a page-level clip. */
  position: absolute; inset: -14% 0;
  z-index: -1; pointer-events: none;
  background:
    radial-gradient(50% 60% at 12% 50%, color-mix(in srgb, var(--rp-accent) 46%, transparent), transparent 68%),
    radial-gradient(50% 60% at 88% 50%, color-mix(in srgb, var(--rp-brand) 42%, transparent), transparent 68%);
  filter: blur(52px);
  opacity: 0; transition: opacity 1.2s ease;
}
.hs-shot.is-in .hs-shot__glow { opacity: 1; animation: hs-breathe 7s ease-in-out infinite 1.2s; }
@keyframes hs-breathe { 0%,100% { opacity: .82; } 50% { opacity: 1; } }

/* Live canvas waveform strip under the hero shot */
.hs-wavebar {
  margin-top: 1.15rem;
  border: 1px solid var(--rp-border);
  border-radius: var(--rp-r-sm);
  background: linear-gradient(180deg, color-mix(in srgb, var(--rp-panel) 70%, #000), color-mix(in srgb, var(--rp-bg) 88%, #000));
  padding: .55rem .7rem .4rem;
  position: relative;
  overflow: hidden;
}
.hs-wavebar canvas { width: 100%; height: 110px; display: block; }
.hs-wavebar__legend {
  display: flex; flex-wrap: wrap; gap: .35rem 1.15rem;
  padding-top: .45rem;
  font-family: var(--rp-font-mono);
  font-size: 0.66rem; letter-spacing: .1em; text-transform: uppercase; color: var(--rp-text3);
}
.hs-wavebar__legend span { display: inline-flex; align-items: center; gap: .4em; }
.hs-wavebar__legend i { width: 9px; height: 9px; border-radius: 2px; display: block; }

/* --------------------------------------------------------------------------
   10. SPEC / STAT STRIPS
   -------------------------------------------------------------------------- */
.hs-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  border: 1px solid var(--rp-border);
  border-radius: var(--rp-r);
  overflow: hidden;
  background: var(--rp-panel);
}
.hs-stat {
  padding: clamp(1.3rem, 2.4vw, 1.9rem) 1.35rem;
  border-right: 1px solid var(--rp-border);
  position: relative;
  transition: background var(--rp-med);
}
.hs-stat:last-child { border-right: 0; }
.hs-stat:hover { background: var(--rp-card); }
.hs-stat::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--rp-glow, var(--rp-accent));
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--rp-med);
}
.hs-stat:hover::after { transform: scaleX(1); }
.hs-stat__n {
  font-family: var(--rp-font-mono);
  font-size: clamp(1.75rem, 3.1vw, 2.4rem);
  font-weight: 700; line-height: 1;
  color: var(--rp-glow, var(--rp-accent));
  letter-spacing: -.03em;
  display: block; margin-bottom: .3rem;
  font-variant-numeric: tabular-nums;
}
/* The number is the proof; the title is the claim it proves. Splitting them
   lets the card name a feature without giving up the numeral that makes the
   row scan as a row. */
.hs-stat__t {
  display: block;
  font-size: var(--rp-f-small);
  font-weight: 700;
  color: var(--rp-text);
  letter-spacing: -.012em;
  margin-bottom: .32rem;
}
.hs-stat__l { font-size: .845rem; color: var(--rp-text2); line-height: 1.45; }
@media (max-width: 640px) { .hs-stat { border-right: 0; border-bottom: 1px solid var(--rp-border); } }

/* --------------------------------------------------------------------------
   11. SPLIT (image + copy)
   -------------------------------------------------------------------------- */
.hs-split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), 1fr));
  gap: clamp(2rem, 5vw, 4.2rem);
  align-items: center;
}
.hs-split--flip > :first-child { order: 2; }
@media (max-width: 860px) { .hs-split--flip > :first-child { order: 0; } }

.hs-figure {
  position: relative;
  border-radius: var(--rp-r);
  overflow: hidden;
  border: 1px solid var(--rp-border2);
  box-shadow: 0 30px 60px -34px rgba(0,0,0,.92);
  transition: transform var(--rp-slow), box-shadow var(--rp-slow);
}
.hs-figure img { width: 100%; transition: transform 900ms cubic-bezier(.16,.84,.44,1); }
.hs-figure:hover { box-shadow: 0 36px 76px -34px rgba(0,0,0,1), 0 0 60px -26px color-mix(in srgb, var(--rp-glow, var(--rp-accent)) 55%, transparent); }
.hs-figure:hover img { transform: scale(1.035); }
.hs-figure figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 2.4rem 1.15rem .8rem;
  background: linear-gradient(transparent, rgba(6,8,13,.94));
  font-family: var(--rp-font-mono);
  font-size: .68rem; letter-spacing: .13em; text-transform: uppercase; color: var(--rp-text2);
}

/* Two-voice explainer, straight from the manual's "plain / precise" device */
.hs-voice { border-left: 2px solid var(--rp-border2); padding-left: 1.15rem; margin-bottom: 1.35rem; transition: border-color var(--rp-med); }
.hs-voice:hover { border-left-color: var(--rp-glow, var(--rp-accent)); }
.hs-voice__tag {
  display: block;
  font-family: var(--rp-font-mono);
  font-size: var(--rp-f-micro); font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--rp-glow, var(--rp-accent));
  margin-bottom: .45rem;
}
.hs-voice p { color: var(--rp-text2); }

/* Checklist */
.hs-checks { display: grid; gap: .8rem; margin-top: 1.5rem; }
.hs-checks li { display: flex; gap: .75rem; align-items: flex-start; color: var(--rp-text2); font-size: .97rem; }
.hs-checks svg { width: 19px; height: 19px; flex: none; color: var(--rp-good); margin-top: .18em; }
.hs-checks b { color: var(--rp-text); font-weight: 600; }

/* --------------------------------------------------------------------------
   12. CHARACTER KNOB ROW (Pro) -- the four colour-coded controls
   -------------------------------------------------------------------------- */
.hs-knobs { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 235px), 1fr)); gap: 1rem; }
.hs-knob {
  text-align: center;
  padding: 1.75rem 1.25rem 1.5rem;
  border: 1px solid var(--rp-border);
  border-radius: var(--rp-r);
  background: linear-gradient(168deg, var(--rp-card), var(--rp-panel));
  transition: transform var(--rp-med), border-color var(--rp-med), box-shadow var(--rp-med);
}
.hs-knob:hover {
  transform: translateY(-5px);
  border-color: color-mix(in srgb, var(--rp-glow) 55%, transparent);
  box-shadow: 0 20px 44px -26px rgba(0,0,0,.95), 0 0 44px -22px var(--rp-glow);
}
.hs-knob__dial {
  width: 78px; height: 78px; margin: 0 auto 1.05rem;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 32%, #23252f, #0f1017 72%);
  border: 1px solid var(--rp-border2);
  position: relative;
  box-shadow: 0 5px 16px rgba(0,0,0,.55), 0 1px 0 rgba(255,255,255,.06) inset;
  transition: box-shadow var(--rp-med);
}
.hs-knob:hover .hs-knob__dial { box-shadow: 0 5px 16px rgba(0,0,0,.55), 0 0 0 3px color-mix(in srgb, var(--rp-glow) 18%, transparent); }
.hs-knob__dial::before {            /* the arc */
  content: ""; position: absolute; inset: -5px;
  border-radius: 50%;
  background: conic-gradient(from 215deg, var(--rp-glow) 0turn var(--arc, .38turn), transparent var(--arc, .38turn) 1turn);
  mask: radial-gradient(circle, transparent 61%, #000 63%, #000 72%, transparent 74%);
  -webkit-mask: radial-gradient(circle, transparent 61%, #000 63%, #000 72%, transparent 74%);
  transition: --arc var(--rp-spring);
}
.hs-knob__dial::after {             /* the pointer */
  content: ""; position: absolute;
  left: 50%; top: 15%;
  width: 2.5px; height: 24%;
  border-radius: 2px;
  background: var(--rp-glow);
  transform-origin: 50% 165%;
  transform: translateX(-50%) rotate(var(--rot, -38deg));
  box-shadow: 0 0 9px var(--rp-glow);
  transition: transform var(--rp-spring);
}
.hs-knob:hover .hs-knob__dial::after { transform: translateX(-50%) rotate(calc(var(--rot, -38deg) + 46deg)); }
.hs-knob h3 {
  font-family: var(--rp-font-mono);
  font-size: .78rem; font-weight: 700; letter-spacing: .19em; text-transform: uppercase;
  color: var(--rp-glow); margin-bottom: .3rem;
}
.hs-knob__range {
  font-family: var(--rp-font-mono);
  font-size: .66rem; letter-spacing: .1em; color: var(--rp-text3); margin-bottom: .75rem;
}
.hs-knob p { font-size: .9rem; color: var(--rp-text2); line-height: 1.58; }

/* --------------------------------------------------------------------------
   13. VIDEO
   -------------------------------------------------------------------------- */
.hs-video {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--rp-r-lg);
  overflow: hidden;
  border: 1px solid var(--rp-border2);
  background: #06080d center/cover no-repeat;
  box-shadow: 0 44px 90px -44px rgba(0,0,0,.95), 0 0 90px -34px color-mix(in srgb, var(--rp-accent) 34%, transparent);
  cursor: pointer;
}
.hs-video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.hs-video__poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .5; transition: opacity var(--rp-med), transform 900ms cubic-bezier(.16,.84,.44,1); }
.hs-video:hover .hs-video__poster { opacity: .62; transform: scale(1.02); }
.hs-video__play {
  position: absolute; inset: 0; display: grid; place-items: center; gap: .9rem;
  align-content: center;
}
.hs-video__disc {
  width: 84px; height: 84px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(255,255,255,.1);
  border: 1px solid rgba(255,255,255,.28);
  backdrop-filter: blur(9px);
  transition: transform var(--rp-spring), background var(--rp-med), box-shadow var(--rp-med);
}
.hs-video__disc svg { width: 30px; height: 30px; color: #fff; margin-left: 4px; }
.hs-video:hover .hs-video__disc {
  transform: scale(1.09);
  background: var(--rp-accent);
  box-shadow: 0 0 0 12px color-mix(in srgb, var(--rp-accent) 16%, transparent), 0 14px 40px -12px color-mix(in srgb, var(--rp-accent) 76%, transparent);
}
.hs-video__disc::before {
  content: ""; position: absolute; width: 84px; height: 84px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,.34);
  animation: hs-ping 2.8s cubic-bezier(0,0,.2,1) infinite;
}
@keyframes hs-ping { 0% { transform: scale(1); opacity: .7; } 80%,100% { transform: scale(1.65); opacity: 0; } }
.hs-video__label {
  font-family: var(--rp-font-mono);
  font-size: var(--rp-f-micro); letter-spacing: .2em; text-transform: uppercase; color: rgba(255,255,255,.82);
}

/* COMING SOON -------------------------------------------------------------
   This is the DEFAULT state in the markup. The script swaps to the play button
   only once a real video ID is present, so the page tells the truth both before
   the video exists and with JavaScript turned off. */
.hs-video__soon { position: absolute; inset: 0; display: none; place-content: center; justify-items: center; gap: .85rem; }
.hs-video--soon .hs-video__soon { display: grid; }
.hs-video--soon .hs-video__play { display: none; }
.hs-video--soon { cursor: default; }
.hs-video--soon:hover .hs-video__poster { transform: none; opacity: .5; }

.hs-video__soon-badge {
  font-family: var(--rp-font-mono);
  font-size: clamp(.85rem, 2.1vw, 1.25rem);
  font-weight: 700; letter-spacing: .3em; text-transform: uppercase;
  color: var(--rp-text);
  padding: .75em 1.5em .75em 1.8em;      /* extra left pad balances the tracking */
  border: 1px solid var(--rp-border2);
  border-radius: 999px;
  background: color-mix(in srgb, var(--rp-bg) 72%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--rp-accent) 7%, transparent),
              0 18px 44px -20px rgba(0,0,0,.9);
  position: relative;
}
.hs-video__soon-badge::before {
  content: ""; position: absolute; inset: -1px; border-radius: inherit; padding: 1px;
  background: linear-gradient(120deg, var(--rp-accent), transparent 42%, transparent 58%, var(--rp-brand));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: .85;
}
.hs-video__soon-note {
  font-size: var(--rp-f-small); color: var(--rp-text2); text-align: center;
  padding-inline: 1rem;
}

/* --------------------------------------------------------------------------
   14. COMPARISON TABLE
   -------------------------------------------------------------------------- */
.hs-tablewrap {
  border: 1px solid var(--rp-border);
  border-radius: var(--rp-r);
  overflow: hidden;
  background: var(--rp-panel);
}
.hs-table { width: 100%; border-collapse: collapse; font-size: .945rem; }
.hs-table thead th {
  background: #05070c;
  padding: 1.05rem 1.15rem;
  text-align: left;
  font-family: var(--rp-font-mono);
  font-size: var(--rp-f-micro); font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  color: var(--rp-text2);
  border-bottom: 1px solid var(--rp-border);
}
.hs-table thead th:nth-child(2),
.hs-table thead th:nth-child(3) { text-align: center; width: 20%; }
.hs-table thead th:nth-child(3) { color: var(--rp-brand); }
.hs-table td { padding: .92rem 1.15rem; border-bottom: 1px solid var(--rp-border); color: var(--rp-text2); vertical-align: middle; }
.hs-table td:first-child { color: var(--rp-text); font-weight: 500; }
.hs-table td:nth-child(2),
.hs-table td:nth-child(3) { text-align: center; font-family: var(--rp-font-mono); font-size: .78rem; color: var(--rp-text3); }
.hs-table tbody tr { transition: background var(--rp-fast); }
.hs-table tbody tr:hover { background: color-mix(in srgb, var(--rp-accent) 6%, transparent); }
.hs-table tbody tr:last-child td { border-bottom: 0; }
.hs-table tbody tr td:nth-child(3) { background: color-mix(in srgb, var(--rp-brand) 5%, transparent); }
.hs-yes { color: var(--rp-good); font-size: 1.15rem; line-height: 1; }
.hs-no  { color: var(--rp-text3); opacity: .55; }
@media (max-width: 720px) {
  .hs-tablewrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    /* Without this, dragging the wide comparison table sideways on a phone can
       chain into the document and fight the vertical scroll. */
    overscroll-behavior-x: contain;
  }
  .hs-table { min-width: 560px; }
}

/* --------------------------------------------------------------------------
   15. PRICING
   -------------------------------------------------------------------------- */
/* Two-value gap: <row> <column>. The row gap only ever materialises once
   auto-fit wraps the cards into a stack, so this costs nothing in the
   side-by-side layout -- there is only one row there. It has to be bigger than
   the column gap, not equal to it: stacked, the cards are full-bleed and the
   only thing separating two tiers is that gap, and at 1.25rem it was *smaller*
   than the card's own 1.7rem padding, so the boundary between two cards read as
   tighter than the whitespace inside one and the tiers looked fused. It also
   gives the Pro card's red glow somewhere to fall off before it hits Basic. */
.hs-prices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 330px), 1fr));
  gap: clamp(2.25rem, 5vw, 3rem) 1.25rem;
  align-items: stretch;
}
.hs-price {
  position: relative;
  display: flex; flex-direction: column;
  padding: clamp(1.7rem, 3vw, 2.4rem);
  border: 1px solid var(--rp-border);
  border-radius: var(--rp-r-lg);
  background: linear-gradient(168deg, var(--rp-card), var(--rp-panel));
  transition: transform var(--rp-med), border-color var(--rp-med), box-shadow var(--rp-med);
  overflow: hidden;
}
.hs-price:hover { transform: translateY(-5px); border-color: var(--rp-border2); box-shadow: 0 30px 60px -32px rgba(0,0,0,.95); }
.hs-price--feature {
  border-color: color-mix(in srgb, var(--rp-brand) 50%, transparent);
  box-shadow: 0 0 62px -28px color-mix(in srgb, var(--rp-brand) 70%, transparent);
}
.hs-price--feature:hover { border-color: var(--rp-brand); box-shadow: 0 30px 66px -30px rgba(0,0,0,.95), 0 0 70px -24px color-mix(in srgb, var(--rp-brand) 80%, transparent); }
.hs-price--feature::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--rp-brand), transparent);
}
.hs-price__flag {
  position: absolute; top: 1.15rem; right: 1.15rem;
  padding: .3em .75em; border-radius: 999px;
  background: var(--rp-brand); color: #fff;
  font-family: var(--rp-font-mono);
  font-size: .62rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
}
.hs-price__tier {
  font-family: var(--rp-font-mono);
  font-size: .74rem; font-weight: 700; letter-spacing: .2em; text-transform: uppercase;
  color: var(--rp-text3); margin-bottom: .85rem;
}
.hs-price__amt { display: flex; align-items: baseline; gap: .4rem; margin-bottom: .35rem; }
.hs-price__amt b {
  font-size: clamp(2.6rem, 5vw, 3.5rem); font-weight: 700; line-height: 1; letter-spacing: -.04em;
  font-family: var(--rp-font-display);
}
.hs-price__amt span { font-size: .9rem; color: var(--rp-text3); }
.hs-price__sub { color: var(--rp-text2); font-size: .93rem; margin-bottom: 1.5rem; min-height: 2.6em; }
.hs-price__list { display: grid; gap: .68rem; margin-bottom: 1.85rem; flex: 1; }
.hs-price__list li { display: flex; gap: .68rem; align-items: flex-start; font-size: .92rem; color: var(--rp-text2); }
.hs-price__list svg { width: 17px; height: 17px; flex: none; margin-top: .2em; }
.hs-price__list li b { color: var(--rp-text); font-weight: 600; }
.hs-price__note { margin-top: .95rem; text-align: center; font-size: .78rem; color: var(--rp-text3); }
/* One tier must not stretch the full grid - constrain and centre it so a
   single card reads as deliberate rather than as a layout that lost its
   sibling. Must stay AFTER .hs-prices above: same specificity, later wins. */
.hs-prices--single { grid-template-columns: minmax(0, 420px); justify-content: center; }
/* A tier with no ls_product_id yet - not-yet-purchasable, not a dead link. */
.hs-btn--disabled { opacity: .55; cursor: default; pointer-events: none; }
.hs-btn--disabled::after { display: none; }
/* A trial that shares its tier's checkout sits under the buy button as the
   quieter of the two routes into the same product. */
.hs-btn--trial { margin-top: .6rem; }
.hs-price__note--trial { margin-top: .5rem; }

/* --------------------------------------------------------------------------
   16. TESTIMONIALS
   -------------------------------------------------------------------------- */
.hs-quotes { columns: 3 300px; column-gap: 1.15rem; }
.hs-quote {
  break-inside: avoid; margin-bottom: 1.15rem;
  padding: 1.55rem;
  border: 1px solid var(--rp-border);
  border-radius: var(--rp-r);
  background: linear-gradient(168deg, var(--rp-card), var(--rp-panel));
  transition: transform var(--rp-med), border-color var(--rp-med), box-shadow var(--rp-med);
}
.hs-quote:hover { transform: translateY(-3px); border-color: var(--rp-border2); box-shadow: 0 20px 44px -26px rgba(0,0,0,.9); }
.hs-quote__stars { display: flex; gap: 2px; margin-bottom: .9rem; color: var(--rp-warn); }
.hs-quote__stars svg { width: 15px; height: 15px; }
.hs-quote p { color: var(--rp-text); font-size: .975rem; line-height: 1.65; margin-bottom: 1.1rem; }
.hs-quote footer { display: flex; align-items: center; gap: .7rem; }
.hs-quote__av {
  width: 38px; height: 38px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: linear-gradient(150deg, var(--rp-accent), var(--rp-brand));
  color: #04060c; font-weight: 700; font-size: .84rem;
}
.hs-quote__who b { display: block; font-size: .89rem; font-weight: 600; }
.hs-quote__who span { display: block; font-size: .77rem; color: var(--rp-text3); }
/* Optional per-entry portrait. A testimonial without an image renders exactly
   as it always did; only an entry carrying image: gets these. */
.hs-quote--portrait { padding: 0; overflow: hidden; }
.hs-quote--portrait > :not(.hs-quote__img) { padding-inline: 1.55rem; }
.hs-quote--portrait > :first-child + * { padding-top: 1.4rem; }
.hs-quote--portrait footer { padding-bottom: 1.55rem; }
.hs-quote__img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 16 / 9; object-fit: cover;
  border-bottom: 1px solid var(--rp-border);
}

/* --------------------------------------------------------------------------
   16b. REVIEWS -- a wall of video cards. Each is a plain link over a locally
   served thumbnail, so a page carrying this section still makes no request to
   any video host until a visitor clicks through.
   -------------------------------------------------------------------------- */
.hs-reviews { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem; }
@media (max-width: 720px) { .hs-reviews { grid-template-columns: minmax(0, 1fr); } }
.hs-review {
  display: block; text-decoration: none; color: inherit;
  border: 1px solid var(--rp-border);
  border-radius: var(--rp-r);
  background: linear-gradient(168deg, var(--rp-card), var(--rp-panel));
  overflow: hidden;
  transition: transform var(--rp-med), border-color var(--rp-med), box-shadow var(--rp-med);
}
.hs-review:hover { transform: translateY(-3px); border-color: var(--rp-border2); box-shadow: 0 20px 44px -26px rgba(0,0,0,.9); }
.hs-review__thumb { display: block; position: relative; aspect-ratio: 16 / 9; background: #000; }
.hs-review__thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.hs-review__play {
  position: absolute; inset: 0; margin: auto;
  width: 62px; height: 62px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(8,10,16,.72); border: 1px solid rgba(255,255,255,.22);
  color: #fff; backdrop-filter: blur(2px);
  transition: transform var(--rp-med), background var(--rp-med);
}
.hs-review__play svg { width: 26px; height: 26px; margin-left: 3px; }
.hs-review:hover .hs-review__play { transform: scale(1.08); background: var(--rp-brand); color: var(--rp-on-accent); }
.hs-review__flag {
  position: absolute; top: .7rem; left: .7rem;
  font-family: var(--rp-font-mono);
  font-size: .6rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--rp-text2); background: rgba(8,10,16,.82);
  border: 1px solid var(--rp-border2); border-radius: 999px;
  padding: .3em .7em;
}
.hs-review__meta { display: block; padding: 1.05rem 1.2rem 1.2rem; }
.hs-review__title { display: block; font-size: .95rem; font-weight: 600; line-height: 1.4; color: var(--rp-text); }
.hs-review__channel { display: block; margin-top: .35rem; font-size: .8rem; color: var(--rp-text3); }

/* --------------------------------------------------------------------------
   17. COMPATIBILITY
   -------------------------------------------------------------------------- */
.hs-os {
  padding: clamp(1.5rem, 2.6vw, 2rem);
  border: 1px solid var(--rp-border);
  border-radius: var(--rp-r);
  background: var(--rp-panel);
  transition: border-color var(--rp-med);
}
.hs-os:hover { border-color: var(--rp-border2); }
.hs-os__head { display: flex; align-items: center; gap: .75rem; margin-bottom: 1.25rem; padding-bottom: 1.1rem; border-bottom: 1px solid var(--rp-border); }
.hs-os__head svg { width: 26px; height: 26px; color: var(--rp-text2); }
.hs-os__head h3 { font-size: 1.06rem; }
.hs-os dl { display: grid; grid-template-columns: auto 1fr; gap: .7rem 1.15rem; font-size: .9rem; }
.hs-os dt { font-family: var(--rp-font-mono); font-size: .68rem; letter-spacing: .13em; text-transform: uppercase; color: var(--rp-text3); padding-top: .2em; }
.hs-os dd { color: var(--rp-text2); margin: 0; }

.hs-formats { display: flex; flex-wrap: wrap; gap: .45rem; }
.hs-format {
  padding: .34em .8em; border-radius: 7px;
  border: 1px solid var(--rp-border2);
  background: rgba(255,255,255,.028);
  font-family: var(--rp-font-mono);
  font-size: .7rem; font-weight: 700; letter-spacing: .1em; color: var(--rp-text2);
  transition: all var(--rp-fast);
}
.hs-format:hover { border-color: var(--rp-accent); color: var(--rp-accent); background: color-mix(in srgb, var(--rp-accent) 10%, transparent); transform: translateY(-1px); }

/* --------------------------------------------------------------------------
   18. FAQ -- the accordion animates grid-template-rows 0fr->1fr, which is the
   only pure-CSS way to transition to "auto" height. No JS height math.
   -------------------------------------------------------------------------- */
.hs-faq { display: grid; gap: .7rem; }
.hs-faq__item {
  border: 1px solid var(--rp-border);
  border-radius: var(--rp-r-sm);
  background: var(--rp-panel);
  overflow: hidden;
  transition: border-color var(--rp-med), background var(--rp-med);
}
.hs-faq__item:hover { border-color: var(--rp-border2); }
.hs-faq__item.is-open { border-color: color-mix(in srgb, var(--rp-accent) 42%, transparent); background: var(--rp-card); }
.hs-faq__q {
  width: 100%; display: flex; align-items: center; gap: 1rem;
  padding: 1.15rem 1.35rem;
  text-align: left; font-size: 1.005rem; font-weight: 600; line-height: 1.4;
  transition: color var(--rp-fast);
}
.hs-faq__item.is-open .hs-faq__q { color: var(--rp-accent); }
.hs-faq__sign { margin-left: auto; flex: none; width: 17px; height: 17px; position: relative; }
.hs-faq__sign::before,
.hs-faq__sign::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  background: currentColor; border-radius: 2px;
  transform: translate(-50%, -50%);
  transition: transform var(--rp-spring), opacity var(--rp-fast);
}
.hs-faq__sign::before { width: 15px; height: 2px; }
.hs-faq__sign::after  { width: 2px; height: 15px; }
.hs-faq__item.is-open .hs-faq__sign::after { transform: translate(-50%,-50%) rotate(90deg); opacity: 0; }
.hs-faq__panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--rp-med); }
.hs-faq__item.is-open .hs-faq__panel { grid-template-rows: 1fr; }
.hs-faq__panel > div { overflow: hidden; }
.hs-faq__panel p { padding: 0 1.35rem 1.3rem; color: var(--rp-text2); font-size: .955rem; }
.hs-faq__panel p + p { padding-top: 0; }

/* --------------------------------------------------------------------------
   19. CONTACT
   -------------------------------------------------------------------------- */
.hs-contact { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); gap: 1.15rem; }
.hs-contact__card {
  display: flex; flex-direction: column; align-items: flex-start; gap: .55rem;
  padding: 1.65rem;
  border: 1px solid var(--rp-border);
  border-radius: var(--rp-r);
  background: linear-gradient(168deg, var(--rp-card), var(--rp-panel));
  transition: transform var(--rp-med), border-color var(--rp-med), box-shadow var(--rp-med);
}
.hs-contact__card:hover {
  transform: translateY(-4px);
  border-color: color-mix(in srgb, var(--rp-glow, var(--rp-accent)) 50%, transparent);
  box-shadow: 0 22px 46px -28px rgba(0,0,0,.92), 0 0 44px -26px var(--rp-glow, var(--rp-accent));
}
.hs-contact__ico {
  width: 42px; height: 42px; border-radius: 12px; display: grid; place-items: center;
  background: color-mix(in srgb, var(--rp-glow, var(--rp-accent)) 13%, transparent);
  border: 1px solid color-mix(in srgb, var(--rp-glow, var(--rp-accent)) 30%, transparent);
  color: var(--rp-glow, var(--rp-accent));
  margin-bottom: .5rem;
  transition: transform var(--rp-spring);
}
.hs-contact__card:hover .hs-contact__ico { transform: scale(1.07) rotate(-5deg); }
.hs-contact__ico svg { width: 21px; height: 21px; }
.hs-contact__card h3 { font-size: 1.03rem; }
.hs-contact__card p { font-size: .91rem; color: var(--rp-text2); }
.hs-contact__link {
  margin-top: auto; padding-top: .55rem;
  font-family: var(--rp-font-mono);
  font-size: .8rem; color: var(--rp-glow, var(--rp-accent));
  display: inline-flex; align-items: center; gap: .4em;
  transition: gap var(--rp-fast);
}
.hs-contact__card:hover .hs-contact__link { gap: .7em; }

/* --------------------------------------------------------------------------
   20. FINAL CTA + FOOTER
   -------------------------------------------------------------------------- */
.hs-final {
  position: relative; overflow: hidden;
  border-radius: var(--rp-r-lg);
  border: 1px solid var(--rp-border2);
  background: linear-gradient(150deg, #12131c, #0a0b11 55%, #150d12);
  padding: clamp(2.8rem, 6vw, 5rem) clamp(1.5rem, 4vw, 3.5rem);
  /* NB: centring comes from the .hs-center class on the element, not from a
     text-align here. Setting it locally is what caused the button row to stay
     left-aligned: text-align centres inline content, but .hs-cta-row is a flex
     container and needs justify-content -- which only .hs-center supplies. One
     mechanism, one place. */
}
.hs-final::before {
  content: ""; position: absolute; inset: -50% -10%;
  background:
    radial-gradient(38% 55% at 18% 50%, color-mix(in srgb, var(--rp-accent) 32%, transparent), transparent 70%),
    radial-gradient(38% 55% at 82% 50%, color-mix(in srgb, var(--rp-brand) 30%, transparent), transparent 70%);
  filter: blur(48px); pointer-events: none;
  animation: hs-drift 18s ease-in-out infinite alternate;
}
@keyframes hs-drift { from { transform: translateX(-3%); } to { transform: translateX(3%); } }
.hs-final > * { position: relative; z-index: 1; }

.hs-foot { border-top: 1px solid var(--rp-border); padding-block: 2.6rem 3rem; }
.hs-foot__inner { display: flex; flex-wrap: wrap; gap: 1.5rem 2.5rem; align-items: center; }
.hs-foot__logo { width: 132px; }
.hs-foot__logo svg { width: 100%; height: auto; opacity: .85; }
.hs-foot__links { display: flex; flex-wrap: wrap; gap: 1.35rem; margin-left: auto; }
.hs-foot__links a { font-size: .855rem; color: var(--rp-text3); transition: color var(--rp-fast); }
.hs-foot__links a:hover { color: var(--rp-accent); }
.hs-foot__legal { width: 100%; font-size: .78rem; color: var(--rp-text3); padding-top: 1.4rem; border-top: 1px solid var(--rp-border); }

/* --------------------------------------------------------------------------
   21. SCROLL REVEAL -- the class is added by IntersectionObserver.
   Everything starts hidden ONLY if JS is running (html.hs-js), so the page
   is still fully readable with JS blocked. That's the progressive-enhancement
   rule: never hide content you can't guarantee you'll show again.
   -------------------------------------------------------------------------- */
.hs-js .hs-reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity var(--rp-slow), transform var(--rp-slow);
  transition-delay: var(--d, 0ms);
  will-change: opacity, transform;
}
.hs-js .hs-reveal.is-in { opacity: 1; transform: none; }

/* ------------------------------------------------- customer reviews --- */
/* Score beside the breakdown rather than above it: same information, about
   half the height, and the bars get the width to actually be read. */
.hs-rsummary__eyebrow { display: block; text-align: center; margin-bottom: 1.1rem; }
.hs-rsummary {
  display: grid; grid-template-columns: minmax(0, 210px) minmax(0, 1fr);
  gap: clamp(1.4rem, 3.5vw, 3rem); align-items: center;
  margin-bottom: clamp(1.8rem, 3.5vw, 2.6rem);
}
.hs-rsummary__score { text-align: center; }
.hs-rsummary__num {
  font-size: clamp(2.4rem, 5vw, 3.4rem); font-weight: 700;
  line-height: 1; letter-spacing: -.03em; margin: .7rem 0 .5rem;
}
.hs-rsummary__count {
  margin: .55rem 0 0; font-family: var(--rp-font-mono); font-size: .66rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--rp-text3);
}
@media (max-width: 760px) {
  .hs-rsummary { grid-template-columns: minmax(0, 1fr); }
  .hs-rbars { max-width: 320px; margin-inline: auto; }
}

/* The breakdown. Every row is counted from the ratings, never written by hand. */
.hs-rbars { display: grid; gap: .3rem; }
.hs-rbar {
  display: grid; grid-template-columns: 2.4ch minmax(0, 1fr) 2.5ch;
  gap: .6rem; align-items: center;
  font-family: var(--rp-font-mono); font-size: .64rem; color: var(--rp-text3);
}
.hs-rbar__track {
  height: 7px; border-radius: 999px; overflow: hidden;
  background: rgba(255, 255, 255, .09);
}
.hs-rbar__fill {
  display: block; height: 100%; border-radius: 999px;
  background: var(--rp-accent);
}
.hs-rbar__c { text-align: right; }

/* Cards. Taller than a clamped teaser so a short review is whole on the card,
   and long ones fade rather than cut mid-word. */
.hs-creviews {
  display: grid; gap: clamp(.7rem, 1.6vw, 1rem);
  /* Four, explicitly. auto-fit picked three at this measure and stranded the
     fourth card alone on a second row. */
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 940px) { .hs-creviews { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Still two across on a phone - the pager drops to 2 per page to match, so a
   card keeps a readable width instead of being squeezed to a column of four.
   Everything shrinks a step rather than the layout collapsing. */
@media (max-width: 520px) {
  .hs-creviews { gap: .55rem; }
  .hs-creview { min-height: 210px; padding: .8rem .85rem; gap: .4rem; }
  .hs-creview__title { font-size: .82rem; }
  .hs-creview__body { font-size: .78rem; -webkit-line-clamp: 5; }
  .hs-creview__by { font-size: .54rem; gap: .3rem; flex-wrap: wrap; }
  .hs-creview__more { display: none; }
}
.hs-creview {
  position: relative; overflow: hidden;
  min-height: 250px; padding: 1rem 1.1rem;
  display: flex; flex-direction: column; gap: .5rem; text-align: left;
  border: 1px solid var(--rp-border); border-radius: var(--rp-r-lg);
  background: linear-gradient(168deg, var(--rp-card, #12131c), var(--rp-panel, #0d0e15));
  color: inherit; font: inherit; cursor: pointer;
  transition: border-color var(--rp-med), transform var(--rp-med), box-shadow var(--rp-med);
}
.hs-root .hs-creview:hover, .hs-root .hs-creview:focus-visible {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--rp-accent) 55%, transparent);
  box-shadow: 0 24px 46px -30px rgba(0,0,0,.95);
}
.hs-creview.is-hidden { display: none; }
.hs-creview__title { font-size: .92rem; color: var(--rp-text); }
.hs-creview__body {
  font-size: .85rem; line-height: 1.55; color: var(--rp-text2);
  display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical;
  overflow: hidden;
}
.hs-creview__by {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: .6rem; margin-top: auto; padding-top: .5rem;
  font-family: var(--rp-font-mono); font-size: .6rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--rp-text3);
}
.hs-creview__name { color: var(--rp-text2); font-weight: 700; }
/* Quiet on purpose. The badge is a fact, not a sales device - it sits beside
   the name at the same weight as the date, and never competes with the review
   itself. Green rather than the product accent, so it reads as a status and
   not as decoration. */
/* Rating and badge on one line: both answer "how much does this count", so
   they are read together, above the words rather than buried under them. Wraps
   rather than squeezing - on the narrowest cards the badge drops to its own
   line instead of crushing the stars. */
.hs-creview__top {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: .4rem .5rem;
}
.hs-vbadge {
  display: inline-flex; align-items: center; gap: .25em;
  padding: .15em .5em;
  font-family: var(--rp-font-mono); font-size: .54rem; text-transform: uppercase;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, #35d07f 45%, transparent);
  background: color-mix(in srgb, #35d07f 12%, transparent);
  color: #7ce0ab;
  font-weight: 700; letter-spacing: .08em;
  white-space: nowrap;
}
.hs-rmodal__verified {
  display: inline-flex; align-items: center; gap: .3em;
  margin: .8rem 0 0; padding: .25em .7em;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, #35d07f 45%, transparent);
  background: color-mix(in srgb, #35d07f 12%, transparent);
  color: #7ce0ab;
  font-family: var(--rp-font-mono); font-size: .62rem;
  letter-spacing: .12em; text-transform: uppercase;
}
.hs-rmodal__verified[hidden] { display: none; }
/* Present for a mouse only on hover, but always in the accessibility tree via
   the button role - a keyboard user gets it from focus styling instead. */
.hs-creview__more {
  font-family: var(--rp-font-mono); font-size: .56rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--rp-accent);
  opacity: 0; transition: opacity var(--rp-med);
}
.hs-creview:hover .hs-creview__more,
.hs-creview:focus-visible .hs-creview__more { opacity: 1; }

/* Paging controls. Same shape as the hero slider's arrows so the two read as
   the same control, with a count between them - without it there is no way to
   tell how much is left, and an arrow that silently wraps feels broken. */
.hs-pager {
  display: flex; align-items: center; justify-content: center; gap: .9rem;
  margin-top: clamp(1.1rem, 2.4vw, 1.6rem);
}
.hs-pager__arrow {
  display: grid; place-items: center;
  width: 38px; height: 38px; padding: 0; border-radius: 50%; cursor: pointer;
  border: 1px solid rgba(255, 255, 255, .22);
  background: rgba(255, 255, 255, .06);
  color: var(--rp-text);
  transition: background var(--rp-med), border-color var(--rp-med), transform var(--rp-med);
}
.hs-root .hs-pager__arrow:hover {
  background: rgba(255, 255, 255, .14);
  border-color: color-mix(in srgb, var(--rp-accent) 70%, transparent);
  transform: scale(1.06);
}
.hs-pager__arrow:focus-visible { outline: 2px solid var(--rp-accent); outline-offset: 3px; }
.hs-pager__arrow svg { width: 16px; height: 16px; }
.hs-pager__count {
  min-width: 5ch; text-align: center;
  font-family: var(--rp-font-mono); font-size: .72rem; font-weight: 700;
  letter-spacing: .12em; color: var(--rp-text3);
}
@media (prefers-reduced-motion: reduce) {
  .hs-pager__arrow { transition: none; }
  .hs-root .hs-pager__arrow:hover { transform: none; }
}

/* The full review. <dialog> supplies the backdrop and Escape; this only has to
   look like the rest of the site. */
.hs-rmodal {
  width: min(92vw, 640px); padding: clamp(1.5rem, 3vw, 2.2rem);
  border: 1px solid var(--rp-border2); border-radius: var(--rp-r-lg);
  background: var(--rp-panel, #0d0e15); color: var(--rp-text);
  box-shadow: 0 40px 90px -40px rgba(0,0,0,1);
}
.hs-rmodal::backdrop { background: rgba(0, 0, 0, .72); backdrop-filter: blur(3px); }
.hs-rmodal__close {
  position: absolute; top: .7rem; right: .8rem;
  width: 32px; height: 32px; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--rp-border); background: none;
  color: var(--rp-text3); font-size: 1.2rem; line-height: 1;
}
.hs-root .hs-rmodal__close:hover { color: var(--rp-text); }
.hs-rmodal__title { display: block; margin: .8rem 0 .6rem; font-size: 1.15rem; }
.hs-rmodal__body { margin: 0; color: var(--rp-text2); line-height: 1.7; }
.hs-rmodal__by {
  margin: 1.1rem 0 0; font-family: var(--rp-font-mono); font-size: .66rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--rp-text3);
}

/* Stars. An outline for the unearned ones rather than a missing shape, so a
   5-star review can never be mistaken for a 1-star one. */
.hs-stars { display: inline-flex; gap: .12rem; color: var(--rp-brand); }
.hs-stars svg { width: 15px; height: 15px; }
.hs-stars--lg { justify-content: center; }
.hs-stars--lg svg { width: 22px; height: 22px; }

@media (prefers-reduced-motion: reduce) {
  .hs-creview, .hs-creviews__all, .hs-creview__more { transition: none; }
  .hs-root .hs-creview:hover { transform: none; }
}

/* --------------------------------------------------------------------------
   22. REDUCED MOTION -- respect the OS setting. Non-negotiable for a11y.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .hs-root *,
  .hs-root *::before,
  .hs-root *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .hs-js .hs-reveal { opacity: 1 !important; transform: none !important; }
  .hs-shot__frame { transform: none !important; }
}

/* ----------------------------------------------------------- hero slider --- */
/* Only present when a product declares hero.images. Every slide is stacked in
   the same box and cross-faded, so the frame never changes size between shots
   - the images are all the same aspect, and this keeps the page from jumping
   even if one day they are not.

   The first slide keeps its place in flow and sets the height; the rest are
   absolutely positioned over it. Without JavaScript they simply stack and the
   first one is on top, so the hero still shows the plugin. */
/* pan-y: vertical scrolling stays with the browser, horizontal gestures
   come to the slider. Without it a sideways drag scrolls the page and the
   swipe never lands. */
.hs-shot--slider .hs-shot__frame { position: relative; touch-action: pan-y; }
.hs-shot__slide { display: block; width: 100%; }
.hs-shot--slider .hs-shot__slide + .hs-shot__slide {
  position: absolute; inset: 0; height: 100%;
}
/* .hs-js is set by the page script, so these opacity rules only take effect
   once something can change them back. */
.hs-js .hs-shot--slider .hs-shot__slide {
  opacity: 0; transition: opacity 620ms ease;
}
.hs-js .hs-shot--slider .hs-shot__slide.is-current { opacity: 1; }

.hs-shot__dots {
  display: flex; justify-content: center; align-items: center; gap: .5rem;
  margin-top: 1rem;
}
/* NOT --rp-text3 for the inactive state. A product theme may repaint that
   token - Clarity Delay sets it to the guide's teal - which made the inactive
   dot the SAME colour as the active one, so nothing indicated which slide you
   were on. A fixed white at low alpha reads on any product's ground. */
.hs-root .hs-shot__dot {
  width: 30px; height: 6px; padding: 0; border: 0; border-radius: 999px;
  background: rgba(255, 255, 255, .26);
  cursor: pointer;
  transition: background var(--rp-med), width var(--rp-med), box-shadow var(--rp-med);
}
.hs-root .hs-root .hs-shot__dot:hover { background: rgba(255, 255, 255, .55); }
/* The current slide is wider AND brighter: two signals, so it still reads for
   anyone who cannot separate the accent from white. */
.hs-root .hs-shot__dot[aria-current="true"] {
  width: 46px;
  background: var(--rp-accent);
  box-shadow: 0 0 14px -2px color-mix(in srgb, var(--rp-accent) 70%, transparent);
}
.hs-root .hs-root .hs-shot__dot:focus-visible { outline: 2px solid var(--rp-accent); outline-offset: 3px; }

/* Prev/next. Swipe already works on touch; these are the same control for a
   mouse, which has nothing to swipe with. */
.hs-root .hs-shot__arrow {
  display: grid; place-items: center;
  width: 34px; height: 34px; padding: 0;
  border-radius: 50%; cursor: pointer;
  border: 1px solid rgba(255, 255, 255, .22);
  background: rgba(255, 255, 255, .06);
  color: var(--rp-text);
  transition: background var(--rp-med), border-color var(--rp-med), transform var(--rp-med);
}
.hs-root .hs-shot__arrow:hover {
  background: rgba(255, 255, 255, .14);
  border-color: color-mix(in srgb, var(--rp-accent) 70%, transparent);
  transform: scale(1.06);
}
.hs-root .hs-shot__arrow:focus-visible { outline: 2px solid var(--rp-accent); outline-offset: 3px; }
.hs-shot__arrow svg { width: 15px; height: 15px; }
@media (prefers-reduced-motion: reduce) {
  .hs-shot__dot, .hs-shot__arrow { transition: none; }
  .hs-shot__arrow:hover { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .hs-js .hs-shot--slider .hs-shot__slide { transition: none; }
}

/* --------------------------------------------------- review submission --- */
.hs-reviewform {
  display: grid; gap: .7rem; max-width: 620px; margin: 0 auto;
  grid-template-columns: 1fr 1fr;
}
.hs-reviewform__body, .hs-reviewform__go,
.hs-reviewform__note { grid-column: 1 / -1; }
.hs-reviewform__field {
  padding: .85rem 1.1rem; border-radius: var(--rp-r);
  border: 1px solid var(--rp-border2); background: rgba(255,255,255,.03);
  color: var(--rp-text); font: inherit;
}
/* Dark the whole control, popup list included. Without color-scheme the
   option list is drawn by the UA in its light palette, which put near-white
   text on a white background - legible only by luck. */
.hs-reviewform__field { color-scheme: dark; }
.hs-reviewform__field option {
  background: var(--rp-panel, #0d0e15);
  color: var(--rp-text, #eceef6);
}
.hs-reviewform__field:focus {
  outline: 2px solid var(--rp-accent); outline-offset: 2px; border-color: transparent;
}
.hs-reviewform__note {
  margin: .2rem 0 0; min-height: 1.4em; font-size: .9rem; color: var(--rp-text2);
}
/* The success line, and the code inside it. Monospace and boxed because it is
   a thing to be copied by hand - the shape says "select me" without a button
   that would need clipboard permissions to mean anything. */
.hs-reviewform__note.is-thanks { color: var(--rp-text); }
.hs-reviewform__code {
  display: inline-block; margin-left: .1em; padding: .12em .5em;
  border-radius: 6px; border: 1px dashed var(--rp-accent);
  background: color-mix(in srgb, var(--rp-accent) 12%, transparent);
  font-family: var(--rp-font-mono); font-size: .95em; letter-spacing: .08em;
  user-select: all;
}
/* Offsets the anchor from under the sticky header, so #reviews lands on the
   heading rather than scrolling it out of sight. */
.hs-anchor { display: block; height: 0; scroll-margin-top: 90px; }

@media (max-width: 560px) { .hs-reviewform { grid-template-columns: 1fr; } }


/* visually-hidden but still read by screen readers */
.hs-root .hs-sr {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
