/* The relaunch ladder (RELAUNCH.md section 4): one white panel, three
   columns divided by hairlines, Pro floating proud of the panel as its
   own dark card with a gradient rim, drifting smoke, and the glow.
   Shared by /pricing, the reveal screen, and the homepage. The old
   two-card rules left paywall.css with R4: they loaded after this file
   (Propshaft links the stylesheets alphabetically) and won on order. */

.rl-ladder-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-3) var(--space-5);
  margin-bottom: var(--space-6);
}

/* The discount that is live for this visitor (Offer, NUDGE.md): the
   saving pill's colors, beside the switch on a wide screen and under it
   on a phone. The radius is fixed, not a pill, because the timed line
   wraps to two rows at 375px. */
.rl-offer {
  margin: 0;
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 8px;
  padding: 7px 14px;
  border-radius: 18px;
  background: var(--loud);
  color: var(--accent-deep);
  font-size: var(--text-sm);
  font-weight: 500;
  line-height: 1.35;
}

.rl-offer-ends { color: var(--ink-soft); font-weight: 400; }

/* Under a card's hero (LadderFace, NUDGE.md section 8) sits one row, the
   money kept, in the one semantic green (tokens.css, --saving) that
   nothing else wears. It has to stay ONE line in every state, or the
   button under it moves when the switch flips: so the row is a size
   container and its text gives up a fraction of a pixel on the narrowest
   three-column cards (measured 2026-09-21: "Switch to yearly, save $240 a
   year" is 240px at 15px, the card has 229). */
.rl-bill.ladder-sub { display: grid; container-type: inline-size; }
.rl-save { font-weight: 500; color: var(--saving); }
.rl-save, .rl-bill .rl-nudge { font-size: min(1em, 6.1cqi); }
.rl-plan.is-lead .rl-save { color: var(--saving-on-deep); }

/* On a monthly card, discounted or not, the third row offers the saving
   instead of stating it, so it is a button that flips the switch to yearly: the same
   green text, underlined so it reads as something to press. has-nudge
   shows it in place of the text. */
.rl-nudge {
  appearance: none;
  justify-self: start;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-weight: 500;
  text-align: left;
  color: var(--saving);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
  transition: text-decoration-color 200ms ease;
}
.rl-nudge:hover { text-decoration-color: currentColor; }
.rl-nudge:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 3px; border-radius: 4px; }
.rl-plan.is-lead .rl-nudge { color: var(--saving-on-deep); }
.rl-plan.has-nudge .rl-save,
.rl-plan:not(.has-nudge) .rl-nudge { display: none; }

/* On a yearly card, and on any discounted one, the regular MONTHLY price
   stands crossed out before the hero (LadderFace: one baseline, paying
   monthly at the regular price): a real price, never an invented anchor.
   The element is always in the DOM, because the switch can flip a card
   from a state without one (regular monthly) into a state with one;
   has-was shows it. The strike
   is a line drawn over the figure so it can draw itself in; the resting
   state is the finished strike, the controller only hides it on connect
   (strike_controller), and without the script or with reduced motion the
   line is simply there.

   Where the line sits is a fact about the font, so it is measured, not
   guessed, and written in em so it holds at every size the hero scales
   to. In a box one line-height-1 em tall, the middle of Familjen
   Grotesk's digits is 0.592em from the top (ascent 1.042, descent 0.208,
   digits 0.65 tall; measured in the browser 2026-09-21, after "the
   middle of the box" twice put the line off the digits: digits stand on
   the baseline with nothing under it, and every face puts that baseline
   somewhere else). Re-measure if the display face ever changes. */
.rl-was {
  position: relative;
  align-self: baseline;
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-size: clamp(1.1875rem, 8.4cqi, 1.5rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: lining-nums tabular-nums;
  text-decoration: none;
  color: var(--ink-mute);
}
.rl-was::after {
  content: "";
  position: absolute;
  left: -3px;
  right: -3px;
  top: calc(0.592em - 1px);
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
  transform: scaleX(1);
  transform-origin: left center;
}
.rl-plan:not(.has-was) .rl-was { display: none; }
.rl-plan.is-lead .rl-was { color: rgba(255, 255, 255, 0.6); }
.rl-plan.is-lead .rl-was::after { background: var(--loud); }

/* The draw: one stroke per card, left to right, a beat apart, and the
   hero figure settles from grey as its strike lands (only on a card that
   has a strike to land). */
.will-strike .rl-was::after { transform: scaleX(0); }
.will-strike .rl-plan.has-was .ladder-face-figure { color: var(--ink-mute); }
.will-strike .rl-plan.is-lead.has-was .ladder-face-figure { color: rgba(255, 255, 255, 0.6); }
.will-strike .rl-plan.is-struck .rl-was::after { transform: scaleX(1); transition: transform 520ms var(--ease-out) var(--strike-delay, 0ms); }
.will-strike .rl-plan.is-struck .ladder-face-figure { color: var(--ink); transition: color 320ms ease calc(var(--strike-delay, 0ms) + 380ms); }
.will-strike .rl-plan.is-lead.is-struck .ladder-face-figure { color: #fff; }
.rl-plan:nth-child(2) { --strike-delay: 140ms; }
.rl-plan:nth-child(3) { --strike-delay: 280ms; }

@media (prefers-reduced-motion: reduce) {
  .will-strike .rl-was::after,
  .will-strike .rl-plan.is-struck .rl-was::after { transform: scaleX(1); transition: none; }
  .will-strike .rl-plan.has-was .ladder-face-figure,
  .will-strike .rl-plan.is-struck .ladder-face-figure { color: var(--ink); transition: none; }
  .will-strike .rl-plan.is-lead.has-was .ladder-face-figure,
  .will-strike .rl-plan.is-lead.is-struck .ladder-face-figure { color: #fff; }
}

/* The billing switch (switch_controller): Monthly, the knob, Yearly.
 The track is orange with the knob to the right while yearly is on,
 the saving pill beside Yearly; the labels are links so the no-JS
 path still works. */
.rl-switch {
display: inline-flex;
align-items: center;
gap: 14px;
font-size: var(--text-sm);
font-weight: 500;
}

.rl-switch-label {
display: inline-flex;
align-items: center;
gap: 8px;
color: var(--ink-mute);
text-decoration: none;
transition: color 200ms;
}

.rl-switch-label:hover { color: var(--ink-soft); }
.rl-switch-label.is-on { color: var(--ink); }

.rl-switch-track {
position: relative;
display: block;
width: 56px;
height: 30px;
border-radius: var(--radius-pill);
background: var(--tint);
box-shadow: inset 0 1px 2px rgba(15, 20, 23, 0.14);
transition: background-color 320ms ease, box-shadow 320ms ease;
}

.rl-switch-track:hover { box-shadow: inset 0 1px 2px rgba(15, 20, 23, 0.14), 0 0 0 4px rgba(194, 65, 12, 0.12); }
.rl-switch-track:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: 2px; }
.rl-switch.is-year .rl-switch-track { background: var(--accent); box-shadow: inset 0 1px 2px rgba(15, 20, 23, 0.25); }

.rl-switch-knob {
position: absolute;
top: 3px;
left: 3px;
width: 24px;
height: 24px;
border-radius: 50%;
background: #fff;
box-shadow: 0 1px 3px rgba(15, 20, 23, 0.3);
transition: transform 320ms var(--ease-out);
}

.rl-switch.is-year .rl-switch-knob { transform: translateX(26px); }

.rl-switch-save {
font-size: 0.75rem;
line-height: 1.2;
padding: 3px 9px;
border-radius: var(--radius-pill);
background: var(--tint);
color: var(--ink-mute);
transition: background-color 320ms ease, color 320ms ease;
}

.rl-switch.is-year .rl-switch-save { background: var(--loud); color: var(--accent-deep); }

/* While a discount is live the offer line is the one pill above the
   cards: the yearly note steps back to plain text, in either position of
   the switch, so two savings never shout at once. */
.has-offer .rl-switch .rl-switch-save,
.has-offer .rl-switch.is-year .rl-switch-save { background: none; padding: 0; color: var(--ink-mute); }

.rl-ladder.ladder {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: repeat(6, auto);
  gap: 0;
  width: 100%;
  max-width: none;
  background: var(--paper-card);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-deep);
  text-align: left;
}

/* Each card is a column of the panel's subgrid: name, tagline, price,
   billed line, button, features, so the button and the list start on
   the same line in every card. Where subgrid is missing the card is a
   flex column and the rows drift with the copy. */
.rl-plan.ladder-card {
  position: relative;
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 6;
  align-content: start;
  row-gap: var(--space-4);
  padding: 2.75rem 2.5rem 3rem;
  margin: 0;
  background: transparent;
  color: var(--ink);
  border: 0;
  border-left: 1px solid var(--line);
  border-radius: 0;
  box-shadow: none;
  transition: background-color 200ms, box-shadow 400ms ease;
}

@supports not (grid-template-rows: subgrid) {
  .rl-plan.ladder-card { display: flex; flex-direction: column; align-items: stretch; gap: var(--space-4); }
}

.rl-plan.ladder-card:first-child { border-left: 0; border-radius: var(--radius-lg) 0 0 var(--radius-lg); }
.rl-plan.ladder-card:last-child { border-radius: 0 var(--radius-lg) var(--radius-lg) 0; }
.rl-plan.ladder-card:not(.is-lead):hover { background: var(--paper); box-shadow: 0 0 0 1px rgba(194, 65, 12, 0.12), 0 26px 50px -30px rgba(194, 65, 12, 0.55); }

/* A side card under the pointer (the lead card has its own light): a
   hairline of the accent with a peach light orbiting it. The angle is a
   registered property so it animates; where @property is missing the
   light stands still. */
@property --rl-orbit {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.rl-plan.ladder-card:not(.is-lead)::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  padding: 1.5px;
  pointer-events: none;
  --rl-orbit: 0deg;
  background: conic-gradient(from var(--rl-orbit), rgba(194, 65, 12, 0.34) 0deg, rgba(194, 65, 12, 0.34) 250deg, rgba(226, 90, 31, 0.95) 322deg, var(--loud) 346deg, rgba(194, 65, 12, 0.34) 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: 0;
  transition: opacity 400ms ease;
}

.rl-plan.ladder-card:not(.is-lead):hover::after { opacity: 1; animation: rl-orbit 4.5s linear infinite; }

@keyframes rl-orbit { to { --rl-orbit: 360deg; } }

@media (prefers-reduced-motion: reduce) {
  .rl-plan.ladder-card:not(.is-lead):hover::after { animation: none; }
}


.rl-plan.is-lead {
  background: var(--deep);
  color: #fff;
  border-left: 0;
  overflow: hidden;
  border-radius: var(--radius-lg);
  margin: -22px 0;
  padding-top: calc(2.75rem + 22px);
  padding-bottom: calc(3rem + 22px);
  box-shadow: 0 30px 60px -24px rgba(15, 20, 23, 0.55), 0 0 0 1px rgba(15, 20, 23, 0.06);
  transition: box-shadow 600ms ease;
}

.rl-plan.is-lead:hover { background: var(--deep); box-shadow: 0 34px 70px -24px rgba(15, 20, 23, 0.65), 0 0 0 1px rgba(226, 90, 31, 0.2); }
/* The smoke, grain and rim are placed by the rl-glow rules in home.css;
   no child rule here, or it would out-rank them and turn the decorative
   layers into flex items (QC find 2026-09-15: the Pro card grew 800px). */

.rl-plan-top {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.rl-plan-name.ladder-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.25rem;
  letter-spacing: -0.015em;
  margin: 0;
}

.rl-pop.ladder-badge {
  position: static;
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--accent);
  background: transparent;
  border: 1px solid rgba(194, 65, 12, 0.4);
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  line-height: 1.2;
  transform: none;
  animation: none;
}

.rl-pop.ladder-badge::after { display: none; }
.rl-plan.is-lead .rl-pop.ladder-badge { color: var(--loud); border-color: rgba(255, 215, 194, 0.55); }
.rl-plan.is-mine .rl-pop.ladder-badge { color: var(--ink); border-color: var(--ink); }
.rl-plan.is-lead.is-mine .rl-pop.ladder-badge { color: #fff; border-color: rgba(255, 255, 255, 0.7); }

.rl-plan-tl {
  font-size: 0.9375rem;
  color: var(--ink-soft);
  margin-top: calc(-1 * var(--space-2));
}

.rl-plan.is-lead .rl-plan-tl { color: rgba(255, 255, 255, 0.72); }

/* The price zone is one typographic unit with its own rhythm (2026-09-21,
   after the owner's eye on a 918px window): 28px of air above the hero,
   12 to the saving, 28 to the button.

   The hero row is its own size container, so the figure scales with the
   CARD's width, not the window's: three columns at 920px and one column
   on a phone each get a hero that fits. (The card itself cannot be the
   container: containment would switch off its subgrid and the rows would
   stop lining up across the three cards.) The rem sizes are the fallback
   where container units are missing. If the row still cannot fit, the
   unit drops under the figure whole, never broken in two. */
.rl-price.ladder-face {
  container-type: inline-size;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  margin-top: var(--space-3);
  text-align: left;
}

.rl-price .ladder-face-figure {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 2.75rem;
  font-size: clamp(2.125rem, 15.5cqi, 2.75rem);
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: lining-nums tabular-nums;
  white-space: nowrap;
}

/* The cents: small, raised until their tops meet the dollars' tops.
   Measured, like the strike: Familjen Grotesk's digits stand 0.65em
   tall, so the lift is 0.65 x (1 - 0.42) of the hero's size, which is
   0.9em of the cents' own. */
.rl-price .ladder-face-cents {
  position: relative;
  top: -0.9em;
  margin-left: 0.06em;
  font-size: 0.42em;
  line-height: 0;
  letter-spacing: -0.01em;
  vertical-align: baseline;
}
.rl-price .ladder-face-cents:empty { display: none; }

/* The terms beside the hero (the owner's pick 2026-09-21, after Mobbin's
   cards): "a month" over "billed yearly", two small lines that together
   stand as tall as the figure's digits, so the price and how it is billed
   read as one block and the row under it is free for the saving.

   Two facts carry it. The stack is an inline-block inside the flex item,
   because a flex row lines items up by their FIRST baseline and an
   inline-block's baseline is its LAST line: that puts "billed yearly" on
   the figure's baseline and "a month" above it. And the size follows the
   figure (both in cqi): the digits stand 0.65em tall, two lines at 1.25
   plus a cap height come to 1.96 of the text size, so the text is a third
   of the figure (5.1cqi against 15.5). */
.rl-price .rl-terms {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-size: clamp(0.75rem, 5.1cqi, var(--text-sm));
  line-height: 1.25;
  letter-spacing: 0;
  color: var(--ink-soft);
}
.rl-price .rl-terms-stack { display: inline-block; vertical-align: baseline; }
.rl-price .ladder-face-unit,
.rl-price .rl-billed {
  display: block;
  font-size: inherit;
  color: inherit;
  text-transform: none;
  white-space: nowrap;
}

.rl-plan.is-lead .rl-terms { color: rgba(255, 255, 255, 0.72); }

.rl-bill.ladder-sub {
  font-size: var(--text-sm);
  line-height: 1.45;
  color: var(--ink-mute);
  margin-top: calc(-1 * var(--space-1));
}

.rl-plan.is-lead .rl-bill.ladder-sub { color: rgba(255, 255, 255, 0.72); }

.rl-plan-list.ladder-features {
  list-style: none;
  margin: var(--space-3) 0 0;
  padding: 0;
  border: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  font-size: 0.9375rem;
  line-height: 1.45;
}

.rl-plan-list li {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

.rl-plan-list .check-icon {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin-top: 3px;
  color: var(--accent);
}

.rl-plan.is-lead .rl-plan-list .check-icon { color: var(--loud); }
.rl-plan-list li.is-off { color: var(--ink-mute); padding-left: 26px; opacity: 1; }

.rl-trust.ladder-trust {
  margin-top: calc(var(--space-6) + 22px);
  text-align: center;
  font-size: var(--text-xs);
  color: var(--ink-mute);
}

.rl-ladder-fine.ladder-fine {
  margin-top: var(--space-3);
  text-align: center;
  font-size: var(--text-xs);
  color: var(--ink-mute);
  max-width: 48rem;
  margin-inline: auto;
  text-wrap: pretty;
}

.rl-ladder-fine a { color: var(--ink-soft); text-decoration: underline; text-underline-offset: 3px; }

@media (max-width: 1100px) {
  .rl-plan.ladder-card { padding: 2.125rem 1.625rem 2.375rem; }
}

/* Stacked from 900px down (was 720, owner's eye 2026-09-21: between the
   two, three columns squeezed to about 245px and every row wrapped). On a
   tablet the single column keeps a card's width instead of stretching. */
@media (max-width: 900px) {
  .rl-ladder.ladder { grid-template-columns: minmax(0, 1fr); border-radius: var(--radius-md); max-width: 34rem; margin-inline: auto; }
  .rl-plan.ladder-card { border-left: 0; border-top: 1px solid var(--line); padding: 1.75rem 1.375rem 2rem; border-radius: 0; }
  .rl-plan.ladder-card:first-child { border-top: 0; border-radius: var(--radius-md) var(--radius-md) 0 0; }
  .rl-plan.ladder-card:last-child { border-radius: 0 0 var(--radius-md) var(--radius-md); }
  .rl-plan.is-lead { margin: 0; border-radius: var(--radius-md); padding-top: 2.25rem; padding-bottom: 2.5rem; }
  .rl-trust.ladder-trust { margin-top: var(--space-5); }
}

/* The funnel pages (/pricing and the reveal screen) keep their narrow
   column for the head and the design; the ladder itself needs the room
   of three columns plus the floating Pro card, so it stands on its own
   stage with the same 1.25rem gutters the narrow column has (the phone
   dock's full-bleed math in paywall.css counts on them). */
.rl-ladder-stage {
  width: min(72rem, 100% - 2.5rem);
  margin-inline: auto;
}

.paywall-page .rl-ladder-head { justify-content: center; }

.reveal-left {
  text-align: center;
  color: var(--ink-soft);
  font-size: var(--text-sm);
  margin: var(--space-4) 0 var(--space-3);
}

/* The smoke (smoke_controller): a canvas under everything in the lead
   card; the rim rides above it, the content above that. The hidden
   radio is left out of the child rule on purpose: it must stay out of
   the flow (see above). A light travels the border ring under the
   pointer while the card is hovered: a masked gradient ring at --mx
   and --my, which the controller keeps up to date. */
.rl-plan.is-lead .rl-smoke { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }
.rl-plan.is-lead > :where(:not(.rl-smoke, .rl-rim)) { position: relative; z-index: 1; }
.rl-plan.is-lead .rl-rim { z-index: 2; }

.rl-plan.is-lead::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
  padding: 1.5px;
  pointer-events: none;
  background: radial-gradient(300px circle at var(--mx, 50%) var(--my, 0%), rgba(255, 215, 194, 1), rgba(226, 90, 31, 1) 25%, rgba(226, 90, 31, 0.35) 50%, transparent 70%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: 0;
  transition: opacity 400ms ease;
}

.rl-plan.is-lead:hover::after,
.rl-plan.is-lead.is-lit::after { opacity: 1; }

/* The card's button: full width, the halo wrapping it; inside the dark
   card the halo is the full peach bloom. */
.rl-plan-cta { display: block; margin-top: var(--space-3); }
.rl-plan-cta .rl-halo { display: block; width: 100%; }
.rl-plan-cta .ladder-cta { width: 100%; max-width: none; }
.rl-plan.is-lead .rl-halo::before { inset: -50px -40px; background: radial-gradient(closest-side, rgba(255, 215, 194, 0.55), rgba(237, 107, 36, 0.2) 50%, transparent 100%); filter: blur(22px); }
.rl-plan.is-lead .rl-halo:hover::before { transform: scale(1.3); }

@media (prefers-reduced-motion: reduce) {
  .rl-plan.is-lead::after { transition: none; }
}

/* The trust line in the body face: the August paywall's mono rule in
   paywall.css still names the class (review find 2026-09-15). */
.rl-trust.ladder-trust { font-family: var(--font-body); letter-spacing: 0; }

/* On the reveal screen the ladder follows the design card: a breath
   between the two (review capture 2026-09-15 had the switch touching
   the card). */
.reveal-page .rl-ladder-stage { margin-top: var(--space-6); }

/* The starter pass under the plans (STARTER.md S6): a smaller step,
   quieter than any card, where someone holds blurred designs. */
.starter-offer {
  display: grid;
  justify-items: center;
  gap: var(--space-3);
  max-width: 40rem;
  margin: var(--space-6) auto 0;
  padding: var(--space-5);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--paper-card);
  text-align: center;
}

/* Leading, on the arrival from nudge email 2: right under the design,
   the offer the reader clicked for. */
.starter-offer.is-lead {
  margin-top: var(--space-5);
  border-color: var(--accent);
}

.starter-offer-lead {
  margin: 0;
  font-size: var(--text-base);
  color: var(--ink);
  text-wrap: balance;
}

.starter-offer-form {
  margin: 0;
}

.starter-offer-fine {
  margin: 0;
  max-width: 34rem;
  font-size: var(--text-xs);
  color: var(--ink-soft);
}
