/* Dynamic pricing cards.
   Markup is built at runtime by js/pricing-cards.js and injected into
   #dynamic-pricing-container. Included on a page via <duet-include name="pricing">
   (see _includes/pricing.html).

   The visual language is ported from the post-login plans page
   (gocore views/plans-feature.html) so both sides of sign-in read as one product.
   The palette itself lives in css/duet-tokens.css, shared with the download
   block; the container carries the .duet-ui class that defines it. See that file
   for why the tokens are scoped rather than put on :root, and why this is
   light-only. */

#dynamic-pricing-container {
  /* overflow stays visible: the popular card's ribbon sits above its top edge
     and the card itself is scaled up at desktop widths. Both clip otherwise. */
  display: block;
  overflow: visible;
  position: relative;
  margin-top: 40px;
  padding: 52px 20px 40px;
  background-color: var(--duet-bg);
  background-image: var(--duet-bg-glow);
  background-repeat: no-repeat;
  color: var(--duet-text);
  text-align: center;
  font-family: "Nunito Sans", sans-serif;
}

/* Continuation: this block normally opens the surface, but if another module
   precedes it the top glow would restart under that one and band the join, so
   drop it. The leading .duet-ui is what lets this out-rank the plain id rule
   above — see css/duet-tokens.css. */
.duet-ui ~ .duet-ui #dynamic-pricing-container {
  background-image: none;
  margin-top: 0;
}

#dynamic-pricing-container *,
#dynamic-pricing-container *::before,
#dynamic-pricing-container *::after {
  box-sizing: border-box;
}

/* ---------------- term toggle ---------------- */
/* Named pricing-term-switch rather than the old pricing-tabs: duet-styles.css
   carries its own .pricing-tabs rules for the legacy Webflow blocks, and this
   control no longer wants any of them. */
.pricing-term-switch {
  display: inline-flex;
  gap: 3px;
  margin-bottom: 30px;
  padding: 4px;
  background: var(--duet-seg-track);
  border: 1px solid var(--duet-stroke);
  border-radius: 999px;
}

.pricing-term {
  display: inline-flex;
  align-items: center;
  padding: 8px 22px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--duet-muted);
  font-family: inherit;
  font-size: 14px;
  font-weight: 800;
  white-space: nowrap;
  cursor: pointer;
  transition: color .2s ease, background .2s ease, box-shadow .2s ease;
}

.pricing-term:hover {
  color: var(--duet-text);
}

.pricing-term[aria-checked="true"] {
  background: #fff;
  color: var(--duet-text);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .16);
}

/* ---------------- panes ---------------- */
.pricing-pane-container {
  display: block;
  position: relative;
  margin-top: 0;
}

.pricing-cards-pane {
  position: relative;
  opacity: 0;
  height: 0;
  overflow: hidden;
  transition: opacity 600ms ease, height 200ms ease;
}

.pricing-cards-pane.active {
  opacity: 1;
  height: auto;
  overflow: visible;
}

/* align-items: stretch so every card is the same height however many features
   it carries; .pricing-price-block's margin-top:auto then pins each price and
   CTA to a shared baseline. */
.pricing-card-wrapper {
  display: grid;
  gap: 16px;
  align-items: stretch;
  grid-template-columns: repeat(auto-fit, minmax(258px, 1fr));
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  text-align: left;
}

@media screen and (min-width: 1060px) {
  .pricing-card-wrapper {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* ---------------- card ---------------- */
.pricing-card {
  position: relative;
  /* grid items default to min-width:auto, so one long unbroken feature label
     would push the track wider than the viewport on a phone */
  min-width: 0;
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 19px 20px 16px;
  background: var(--duet-surface);
  border: 1px solid var(--duet-stroke);
  border-radius: 22px;
  box-shadow: var(--duet-shadow);
  transition: border-color .25s ease, box-shadow .25s ease;
}

/* No lift on hover — cards shifting under the cursor read as distracting. */
.pricing-card:hover {
  border-color: var(--duet-stroke-strong);
}

.pricing-card.popular {
  /* One less pixel of padding per side than .pricing-card: this border is 1px
     thicker all round and box-sizing is border-box, so at equal padding the
     popular card's content box would be 2px narrower than its neighbours'. */
  padding: 18px 19px 15px;
  border: 2px solid transparent;
  background:
    linear-gradient(var(--duet-surface), var(--duet-surface)) padding-box,
    var(--duet-blue-line) border-box;
  box-shadow: var(--duet-shadow-pop);
}

@media screen and (min-width: 1060px) {
  /* static emphasis only — deliberately unchanged on hover */
  .pricing-card.popular {
    transform: scale(1.035);
    z-index: 2;
  }
}

.pricing-ribbon {
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  padding: 5px 14px;
  border-radius: 999px;
  background: var(--duet-blue-grad);
  color: var(--duet-blue-on);
  font-size: 11px;
  font-weight: 900;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
  box-shadow: 0 6px 18px -6px rgba(92, 152, 222, .75);
}

/* Montserrat, uppercase, tracked out — the pairing duetdisplay.com already uses
   for headings over Nunito Sans body copy. */
.pricing-plan-title {
  margin: 0;
  color: var(--duet-text);
  font-family: var(--duet-heading);
  font-size: 17px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: .085em;
  text-transform: uppercase;
}

/* /api/products opens most feature lists with a roll-up line ("All second-display
   features, plus:"). js/pricing-cards.js splits that off so it can carry the
   divider, exactly as the plans page's .inherits does. */
.pricing-inherits {
  margin: 11px 0 0;
  padding-top: 9px;
  border-top: 1px dashed var(--duet-stroke);
  color: var(--duet-blue-ink);
  font-size: 12px;
  font-weight: 800;
  /* Set explicitly, like every other text rule here: this line is the one that
     wraps, and left to inherit it picks up whatever line-height the host page
     puts on <p> — which spaces it out on the older Webflow templates. */
  line-height: 1.35;
  letter-spacing: .02em;
}

.pricing-features {
  list-style: none;
  display: grid;
  gap: 8px;
  margin: 10px 0 0;
  padding: 0;
}

/* A tier with no roll-up line has nothing else to carry the rule, so its list
   takes the dashed divider directly. */
.pricing-plan-title + .pricing-features {
  margin-top: 11px;
  padding-top: 14px;
  border-top: 1px dashed var(--duet-stroke);
}

.pricing-feature {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--duet-text);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
}

.pricing-feature-icon {
  flex: 0 0 auto;
  width: 17px;
  height: 17px;
  color: var(--duet-blue-ink);
}

.pricing-card:not(.popular) .pricing-feature-icon {
  color: var(--duet-muted);
}

/* ---------------- price + CTA ---------------- */
.pricing-price-block {
  margin-top: auto;
  padding-top: 14px;
}

/* Holds the discount badge and struck-through price. Reserved even when empty so
   a discounted card and an undiscounted one keep the same price baseline. */
.pricing-price-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 22px;
}

.pricing-discount-badge {
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--duet-blue-grad);
  color: var(--duet-blue-on);
  font-size: 11px;
  font-weight: 900;
}

.pricing-original-price {
  color: var(--duet-faint);
  font-size: 14px;
  text-decoration: line-through;
}

.pricing-price-row {
  display: flex;
  align-items: baseline;
  gap: 5px;
  flex-wrap: wrap;
}

.pricing-value {
  display: inline-block;
  /* Montserrat at 700 reads more refined at price size than Nunito Sans at 900,
     whose heavier weight looked blunt. */
  font-family: var(--duet-heading);
  font-size: 34px;
  font-weight: 700;
  line-height: 1.16;
  letter-spacing: -.02em;
  color: var(--duet-text);
  /* the <sup> cents ride above the cap line — without room the glyph clips */
  padding-top: .1em;
  padding-right: .06em;
}

/* Gradient figure on the popular card, written so the price is never invisible
   on an engine that cannot draw it.

   The transparency is declared with -webkit-text-fill-color rather than
   `color: transparent`, because that property travels with the clip: an engine
   that understands -webkit-text-fill-color is the same one that understands
   -webkit-background-clip: text, and one that understands neither drops the
   line and keeps the `color` beneath it. `color: transparent` on its own is
   valid everywhere, so on IE, pre-49 Firefox and older Android WebViews it
   would have hidden the whole figure with nothing painted in its place. The
   literal #2f6fbf under the token is for the same browsers from the other
   direction - no custom properties means the var() line is dropped too, and the
   var() gradient above it with it. On every current browser the fill-color line
   wins and the rendering is exactly what it was. (This is the same idiom the
   site already uses for .tagline and .text-logo in css/duet-styles.css.) */
.pricing-card.popular .pricing-value {
  background: var(--duet-blue-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: #2f6fbf;
  color: var(--duet-blue-ink);
  -webkit-text-fill-color: transparent;
}

/* The "$" is drawn taller than the digits in Montserrat - its ink rises .82em
   of the price size against the digits' .7125em - so at full size it breaks the
   flush top edge that the cents are aligned to. .869em (= .7125 / .82) brings
   its cap down to exactly the digit height, so "$", "2" and ".99" share one top
   line. The baseline is untouched, so nothing else in the row shifts. */
.pricing-value .pricing-currency {
  font-size: .869em;
}

/* Cap-align the cents with the top of the main digits: the top of ".99" sits
   level with the top of the "2". The raise is a vertical-align length - it
   resolves against the sup's own font-size, so .659em is .659 x 17.68px at a
   34px price - rather than position: relative + top, because Safari gives a
   positioned (or opacity < 1) descendant of a -webkit-background-clip: text
   element its own paint layer, and that layer never receives the clipped
   gradient: the cents then paint in their inherited transparent colour and
   vanish, which is why the popular card read "$2" instead of "$2.99" there.

   .659em is measured rather than derived from the nominal 0.7 cap height: with
   Montserrat rendered and the glyphs' painted pixels scanned, the digits top
   out at .7125em of the price size and the cents need .6587em of their own to
   meet them. The old .65em sat 0.15px low, so this is a rounding fix, not a
   move. A bare <sup> defaults to vertical-align: super, so this overrides that
   rather than adding to it. */
.pricing-value sup {
  font-size: .52em;
  font-weight: 600;
  letter-spacing: 0;
  /* css/normalize.css (loaded site-wide from _includes/head.html) raises every
     <sup> with `position: relative; top: -.5em`. Both have to be cancelled here
     or that raise stacks on top of the vertical-align below and the cents fly
     clear of the figure - and `position: relative` is itself what breaks the
     popular card in Safari, per the note above. Cancel, do not override with
     another `top`: the point is that nothing positions this element. */
  position: static;
  top: auto;
  vertical-align: .659em;
}

/* Lighter and slightly faded so "$3.99" cannot be misread as "$399". The
   popular card is already set apart by its gradient and must not use opacity
   here - see above. */
.pricing-card:not(.popular) .pricing-value sup {
  opacity: .69;
}

/* Safety net for the cents on the popular card, where they are painted by the
   ancestor's clipped gradient and so are only visible while they stay in that
   ancestor's paint layer. Anything that promotes the <sup> to a layer of its
   own - position, transform, filter, opacity below 1, a blend mode, isolation,
   will-change - takes it out of that layer, and the layer never receives the
   clipped gradient, so the cents paint in their inherited transparent fill and
   the card reads "$2" where it should read "$2.99" (the reported bug; Safari is
   where this is reproducible, and the scale() on .pricing-card.popular above
   1060px makes it likelier because the card is already its own layer).

   The rule above cancels the two that normalize.css sets, but this file is
   loaded from _includes/pricing.html - inside the page body - so any later
   stylesheet, reset or third-party widget that touches <sup> can put them back
   on a single page and hide the cents again there. Pinning every promoting
   property to its initial value keeps that from happening whatever loads after
   us. Each of these is the effective value today, so nothing moves or changes
   size: this is a floor, not a restyle. */
.pricing-card.popular .pricing-value sup {
  position: static;
  top: auto;
  opacity: 1;
  transform: none;
  filter: none;
  mix-blend-mode: normal;
  isolation: auto;
  will-change: auto;
}

.pricing-term-label {
  color: var(--duet-muted);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.4;
  vertical-align: baseline;
}

.pricing-subtext {
  display: block;
  margin-top: 2px;
  min-height: 17px;
  color: var(--duet-faint);
  font-size: 12px;
  line-height: 1.4;
}

.pricing-action-button {
  display: block;
  width: 100%;
  margin-top: 11px;
  padding: 11px 18px;
  border: 1.5px solid transparent;
  border-radius: 999px;
  font-family: inherit;
  font-size: 15.5px;
  font-weight: 700;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  background: transparent;
  color: var(--duet-blue-ink);
  background-image:
    linear-gradient(var(--duet-surface), var(--duet-surface)),
    var(--duet-blue-line);
  background-origin: border-box;
  background-clip: padding-box, border-box;
  transition: filter .18s ease;
  /* The neon pulse owns box-shadow, so hover only brightens — an animation
     always beats a normal declaration, and a hover shadow here would never
     paint. */
  animation: pricingCtaNeon 2.8s ease-in-out infinite;
}

.pricing-action-button:hover {
  color: var(--duet-blue-ink);
  filter: brightness(1.06);
}

@keyframes pricingCtaNeon {
  0%, 100% { box-shadow: 0 0 5px 0 rgba(var(--duet-neon-rgb), .12); }
  50%      { box-shadow: 0 0 14px 1px rgba(var(--duet-neon-rgb), .30); }
}

/* Primary action: solid Duet blue, white type. */
.pricing-card.popular .pricing-action-button {
  /* single-value clip: the base rule's "padding-box, border-box" pair belongs to
     its two-layer outline trick, and leaving it here would clip the fill inside
     the 1.5px border, showing the card through as a pale ring */
  background-image: var(--duet-cta-grad);
  background-clip: border-box;
  border-color: transparent;
  color: var(--duet-blue-on);
  text-shadow: 0 1px 1px rgba(20, 50, 100, .25);
  animation: pricingCtaNeonPrimary 2.8s ease-in-out infinite;
}

.pricing-card.popular .pricing-action-button:hover {
  color: var(--duet-blue-on);
  filter: saturate(1.08) brightness(1.05);
}

@keyframes pricingCtaNeonPrimary {
  0%, 100% {
    box-shadow: 0 10px 26px -12px rgba(92, 152, 222, .6),
                inset 0 1px 0 rgba(255, 255, 255, .34),
                0 0 6px 0 rgba(var(--duet-neon-rgb), .14);
  }
  50% {
    box-shadow: 0 12px 32px -12px rgba(92, 152, 222, .72),
                inset 0 1px 0 rgba(255, 255, 255, .34),
                0 0 18px 2px rgba(var(--duet-neon-rgb), .36);
  }
}

/* Risk reversal directly under the button — the highest-leverage spot on the
   card. Two lines are reserved because the Lifetime wording wraps where the
   trial wording does not; without it the tallest card grows on toggle and, since
   the grid is equal-height, every card visibly resizes. */
.pricing-reassure {
  margin: 8px 0 0;
  min-height: 32px;
  color: var(--duet-faint);
  font-size: 11px;
  line-height: 1.45;
  text-align: center;
}

@media screen and (max-width: 620px) {
  #dynamic-pricing-container {
    padding: 44px 16px 32px;
  }

  .pricing-term {
    padding: 8px 16px;
    font-size: 13.5px;
  }

  .pricing-card.popular {
    margin-top: 8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* A strobing 1ms loop is worse than no pulse at all — hold a steady glow. */
  .pricing-cards-pane,
  .pricing-card,
  .pricing-term,
  .pricing-action-button {
    transition-duration: .001ms;
  }

  .pricing-action-button {
    animation: none;
    box-shadow: 0 0 10px 1px rgba(var(--duet-neon-rgb), .22);
  }

  .pricing-card.popular .pricing-action-button {
    animation: none;
    box-shadow: 0 10px 26px -12px rgba(92, 152, 222, .6),
                inset 0 1px 0 rgba(255, 255, 255, .34),
                0 0 12px 1px rgba(var(--duet-neon-rgb), .25);
  }
}
