/* ============================================================================
   TOMORROW LIFE — LOAD-BEARING
   A limestone wall section, lit from above, in which the only thing carrying
   real mass is the part of the policy that is actually in the contract.

   One rule governs every content mark on this page:
     solid + opaque            = stated in the contract  (guaranteed)
     dotted / dashed / hatched = can change               (not guaranteed)
   Colour never encodes certainty. Only material does.

   Interactive controls sit OUTSIDE that system — see "button carve-out".
   ========================================================================= */

/* ---------------------------------------------------------------- fonts -- */

/* Archivo alone is `optional`, not `swap`. It sets the h1, and the h1 carries
   text-wrap: balance — so a face that arrives after first paint can re-break a
   three-line headline and move both CTAs down the fold under a thumb already on
   its way to one. The latin subset is preloaded, so it normally wins the 100ms
   block period; when it does not, this pageview is set in the fallback rather
   than reflowed halfway through. Literata keeps `swap`: it sets no heading, and
   the reading column reflowing is not the fold moving. */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: optional;
  src: url('../fonts/archivo-var-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: optional;
  src: url('../fonts/archivo-var-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Literata';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('../fonts/literata-var-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Literata';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('../fonts/literata-var-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------------- tokens -- */
/*
 * Hue law: the light surfaces are warm cream — parchment, not white — and every
 * grey is biased toward the ink's navy. Never green-grey (drifts sage), never a
 * pure neutral (reads as an unstyled page). Light neutrals are cream limestone;
 * dark neutrals are ink-navy.
 */

:root {
  --ground: #e9e3d3;
  --ground-deep: #ddd5c2;
  --plane: #f6f2e7;
  --ink: #141c2b;
  --ink-2: #39445c;
  --rule: #99a0b0;

  /* Semantic certainty tokens — material, not decoration.
     The non-guaranteed ink is dark enough that a hatched patch and a solid one
     read as the same weight of statement. A hatch lays down a fraction of its
     ink over the ground, so the pale value this used to carry (3.6:1) put every
     caveat on the page below every guarantee — the one thing the material rule
     is not allowed to do. */
  --mark-g: #141c2b;
  --mark-n: #4f586f;

  /* The accent. Four permitted uses: the primary CTA, the tel: link, the
     staffed-hours tab, and the drawn underline under one word of the headline.
     It never touches a certainty mark and never enters .tl-fig. */
  --signal: #22436b;
  --signal-deep: #16304e;
  --signal-on: #f6f2e7;

  /* Interactive controls need a boundary that clears 3:1 against their own
     fill; --rule is a structural hairline and deliberately does not. */
  --rule-control: #6b7286;

  /* Semantic, not the accent. Validation state is not a claim about a policy,
     and it is not one of --signal's three permitted uses. */
  --alert: #9d3324;
  --alert-ink: #141c2b;

  --focus-a: #141c2b;
  --focus-b: #f6f2e7;

  /* Photography is graded toward the page rather than dropped on top of it. */
  --img-filter: saturate(0.76) contrast(1.03);
  --img-veil: 0.1;

  /* Light comes from above: a lifted plane casts along its BOTTOM edge. */
  --cast: 0 1px 0 rgba(20, 28, 43, 0.14);
  --cast-inset: inset 0 1px 0 rgba(20, 28, 43, 0.1);


  /* The closing band's own palette. Deliberately not aliased to --ink: a rule
     cannot both set --ink and read var(--ink) for its background. */
  --terminal-bg: #141c2b;
  --terminal-plane: #1d2637;
  --terminal-ink: #e9e3d3;
  --terminal-ink-2: #9ba3b2;
  --terminal-rule: #4a5468;
  --terminal-mark-n: #8a93a8;
  /* The page's own navy on #141c2b is 1.69:1 — a slab that vanishes into the
     band — so the closing band's accent has to be remapped. But it used to
     borrow the DARK theme's accent wholesale, which flipped the label polarity
     on the last and most decisive CTA on the page: near-white label on navy
     everywhere above, near-black label on powder blue here. Same family, same
     polarity.

     The remap still has to hold 4.5:1 under its near-white label: .tl-btn sets
     17px at weight 600 and that is not WCAG large text. Measured, not
     estimated. */
  --terminal-signal: #3d6291; /* 5.60:1 against --terminal-signal-on */
  /* Hover darkens, as it does everywhere else on the page. It used to lighten,
     which was correct against a near-black label and is 1.66:1 against a
     near-white one — the slab would have got brighter as the words on it
     disappeared. */
  --terminal-signal-deep: #2f507f;
  --terminal-signal-on: #f6f2e7;

  --mark-plate: #f6f2e7;

  /*
   * The closing band's accent as TEXT, which is a different job from
   * --terminal-signal. That token is a button FILL, chosen to clear 4.5:1
   * against the near-white label sitting on it; used as ink on the band's own
   * ground it is 2.73:1. The band had no text accent until a tel: link landed
   * there, and it inherited the fill.
   *
   * One pair for both themes: the band is #141c2b in light and #1e2839 in dark,
   * and these clear 8.78/9.71 and 7.63/8.43 respectively. Hover LIGHTENS here,
   * because on a dark surface that is the direction light goes.
   */
  --terminal-signal-text: #9dbde2;
  --terminal-signal-text-hi: #abc6e6;

  --shell: 1200px;
  --gutter: 24px;
  --margin: 32px;
  --stub: 192px;

  /* ------------------------------------------------------------- spacing --
   * One scale, so a margin is chosen from a set rather than invented at the
   * call site. The file had 31 distinct px values and index.html carried 14
   * inline margin overrides; both are the same bug in two places.
   */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  --s6: 32px;
  --s7: 48px;
  --s8: 64px;
  --s9: 96px;

  /* A lifted plane on the form band. The option cards were the same value as
     the band they sat on, separated by a hairline — which is the whole of the
     "flat and muddy" reading, on the two most important controls on the page. */
  --plane-hi: #fbf8f1;

  /* ------------------------------------------------------------- motion --
   * Motion obeys the same rule the marks do:
   *   1. AN ENTRANCE IS A STATEMENT OF CONTINGENCY. Anything guaranteed is
   *      already there. The drawing already works this way — the floor never
   *      animates, the non-guaranteed marks arrive — and this generalises it.
   *   2. NO MARK ANIMATES ALONE. Containers move; marks do not. Two marks of
   *      different material are never staggered against each other.
   * There is no overshoot curve in this set and there will not be one: on a
   * page where geometry is the argument, a bar that overshoots its outline has
   * for those 90ms credited more than the index moved.
   *
   * Not colour. These must resolve identically in every theme, so they are
   * never redeclared in the dark block, the [data-theme] overrides, or the
   * inverted band.
   */
  --dur-quick: 90ms; /* hover and border swaps — the existing figure       */
  --dur-fast: 140ms; /* the call bar's existing figure                     */
  --dur: 220ms; /* the hero crossfade, and fit-form's own hold        */
  --dur-slow: 380ms; /* anything that TRAVELS                             */
  --dur-draw: 520ms; /* the underline's existing figure                    */
  --dur-draw-long: 900ms; /* the thread's existing figure                  */
  --stagger: 60ms;
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-inout: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-draw: cubic-bezier(0.33, 0.9, 0.35, 1);
  --rise: 14px;
  --rise-sm: 8px;
}

/*
 * Dark is a change of light, not an inversion: the same cream-and-navy family
 * seen in a low-lit room. A lifted plane is LIGHTER than ground and catches a
 * rim along its TOP edge, because the light still comes from above.
 */
@media (prefers-color-scheme: dark) {
  :root {
    --ground: #10151f;
    --ground-deep: #0a0d14;
    --plane: #192231;
    --ink: #e2dccd;
    --ink-2: #9ba3b2;
    --rule: #4a5468;
    --mark-g: #e2dccd;
    /* Pulled back as the hatch pitch tightened, so a hatched patch weighs the
       same in both themes rather than being the stronger mark in dark. */
    --mark-n: #7a839a;
    /* #84a9d6 sat at 6.56:1 against --plane, and the form band IS --plane — so
       the consent escape hatch's tel: link, the one link a hesitating visitor
       is most likely to need, takes the extra headroom rather than scraping the
       page minimum. 7.35:1. */
    --signal: #8fb3dd;
    --signal-deep: #a2c1e6;
    --signal-on: #0a0d14;
    --plane-hi: #212c40;
    --rule-control: #99a1b1;
    --alert: #e08a72;
    --alert-ink: #e2dccd;
    --focus-a: #e2dccd;
    --focus-b: #0a0d14;
    --img-filter: saturate(0.66) contrast(1.02) brightness(0.82);
    --img-veil: 0.16;
    --cast: 0 -1px 0 rgba(226, 220, 205, 0.1);
    --cast-inset: inset 0 1px 0 rgba(0, 0, 0, 0.28);

    /* On a dark page the terminal beat comes from stepping UP into a lit
       surface, not from flipping to white. */
    --terminal-bg: #1e2839;
    --terminal-plane: #283349;
    /* The light theme darkens its terminal accent to clear 4.5:1 against a
       near-white label. On a dark page that band is already a lit surface and
       the page's own accent reads correctly on it, so dark keeps the accent it
       uses everywhere else — 6.08:1, and one blue per theme rather than two. */
    --terminal-signal: #84a9d6;
    --terminal-signal-deep: #a2c1e6;
    --terminal-signal-on: #0a0d14;
    --mark-plate: #eee9dc;
  }
}

/* The viewer's toggle must win over the OS preference in BOTH directions. */
:root[data-theme='dark'] {
  --ground: #10151f;
  --ground-deep: #0a0d14;
  --plane: #192231;
  --ink: #e2dccd;
  --ink-2: #9ba3b2;
  --rule: #4a5468;
  --mark-g: #e2dccd;
  --mark-n: #7a839a;
  --signal: #8fb3dd;
  --signal-deep: #a2c1e6;
  --signal-on: #0a0d14;
  --plane-hi: #212c40;
  --rule-control: #99a1b1;
  --alert: #e08a72;
  --alert-ink: #e2dccd;
  --focus-a: #e2dccd;
  --focus-b: #0a0d14;
  --img-filter: saturate(0.66) contrast(1.02) brightness(0.82);
  --img-veil: 0.16;
  --cast: 0 -1px 0 rgba(226, 220, 205, 0.1);
  --cast-inset: inset 0 1px 0 rgba(0, 0, 0, 0.28);
  --terminal-bg: #1e2839;
  --terminal-plane: #283349;
  --terminal-signal: #84a9d6;
  --terminal-signal-deep: #a2c1e6;
  --terminal-signal-on: #0a0d14;
  --mark-plate: #eee9dc;
}

:root[data-theme='light'] {
  --ground: #e9e3d3;
  --ground-deep: #ddd5c2;
  --plane: #f6f2e7;
  --ink: #141c2b;
  --ink-2: #39445c;
  --rule: #99a0b0;
  --mark-g: #141c2b;
  --mark-n: #4f586f;
  --signal: #22436b;
  --signal-deep: #16304e;
  --signal-on: #f6f2e7;
  --plane-hi: #fbf8f1;
  --rule-control: #6b7286;
  --alert: #9d3324;
  --alert-ink: #141c2b;
  --focus-a: #141c2b;
  --focus-b: #f6f2e7;
  --img-filter: saturate(0.76) contrast(1.03);
  --img-veil: 0.1;
  --cast: 0 1px 0 rgba(20, 28, 43, 0.14);
  --cast-inset: inset 0 1px 0 rgba(20, 28, 43, 0.1);
  --terminal-bg: #141c2b;
  --terminal-plane: #1d2637;
  --terminal-signal: #3d6291;
  --terminal-signal-deep: #2f507f;
  --terminal-signal-on: #f6f2e7;
  --mark-plate: #f6f2e7;
}

/* ---------------------------------------------------------------- reset -- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Several utilities here set an explicit `display`, which would otherwise beat
   the UA stylesheet's [hidden] rule and leave both hours states on screen. */
[hidden] {
  display: none !important;
}

html {
  /* A page that argues it sets numbers honestly sets its five numbers right. */
  font-variant-numeric: tabular-nums lining-nums;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--ground);
  overflow-wrap: break-word;
  color: var(--ink);
  font-family: 'Literata', Georgia, 'Times New Roman', serif;
  font-size: 1.09375rem; /* 17.5px */
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img,
svg {
  display: block;
  max-width: 100%;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

/* Radius is 0 everywhere. The only exception is 2px on the two CTA slabs. */
:where(button, input, select, fieldset, textarea) {
  border-radius: 0;
}

fieldset {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

legend {
  padding: 0;
}

hr {
  border: 0;
  margin: 0;
}

::selection {
  background: var(--ink);
  color: var(--ground);
}

/* ------------------------------------------------------------ typography -- */

/*
 * The headline and the six section heads are sized against each other, not
 * independently. The section head used to be a flat 38px while the h1's 3.4vw
 * did not reach 38px until a 1118px viewport — so across the whole tablet and
 * small-laptop band the headline was the SMALLER display object on its own
 * page. Both are now clamped on the same viewport axis: 3.4 / 2.6 = 1.31, so
 * the ratio is fixed through the fluid band, and the two floors (34/24) and the
 * two ceilings (50/38) are set further apart than that, never closer.
 */
.tl-h1 {
  margin: 0;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 118%;
  font-size: clamp(2.125rem, 3.4vw, 3.125rem);
  line-height: 1.05;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.tl-section-head {
  margin: 0;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 118%;
  font-size: clamp(1.5rem, 2.6vw, 2.375rem);
  line-height: 1.1;
  letter-spacing: -0.012em;
  text-wrap: balance;
}

.tl-kicker {
  margin: 0;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 100%;
  font-size: 1.5rem;
  line-height: 1.3;
  letter-spacing: -0.005em;
  text-wrap: balance;
}

.tl-numeral {
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 112%;
  font-size: 1.875rem;
  line-height: 1.1;
  letter-spacing: -0.01em;
}

.tl-lead {
  margin: 0;
  font-size: 1.25rem;
  line-height: 1.5;
  max-width: 46ch;
}

/* Literata's figures are much wider than its average lowercase, so a `ch` here
   buys about 18% more measure than it reads as: 68ch was setting 80 characters
   to the line. Every measure on the page is counted off the render rather than
   trusted to the unit. */
.tl-prose {
  margin: 0;
  font-size: 1.09375rem;
  line-height: 1.65;
  max-width: 58ch;
}

/* Disclosures are the most carefully set type on this page, not fine print. */
.tl-legal {
  margin: 0;
  font-size: 0.84375rem; /* 13.5px */
  line-height: 1.6;
  color: var(--ink-2);
  max-width: 62ch;
}

.tl-label,
.tl-micro {
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 87%;
  text-transform: uppercase;
  color: var(--ink-2);
  display: block;
}

.tl-label {
  font-size: 0.84375rem;
  letter-spacing: 0.1em;
  line-height: 1.3;
}

.tl-micro {
  font-size: 0.78125rem; /* 12.5px */
  letter-spacing: 0.12em;
  line-height: 1.3;
}

/* Literata never sets a heading, never goes above 20px, is never letterspaced. */

a {
  color: inherit;
}

.tl-link {
  color: var(--ink);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

.tl-link:hover {
  color: var(--ink-2);
}

/* The tel: link is one of the accent's four permitted uses. */
.tl-tel {
  color: var(--signal);
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 100%;
  text-decoration: underline;
  text-decoration-color: var(--signal-deep);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  white-space: nowrap;
}

.tl-tel:hover {
  color: var(--signal-deep);
}

/* --------------------------------------------------------------- layout -- */

.tl-stratum {
  /* Strata are full-bleed and separated by a hard cast edge, never by margin. */
  background: var(--ground);
  border-bottom: 1px solid var(--rule);
}

.tl-stratum--deep {
  background: var(--ground-deep);
}

.tl-stratum--plane {
  background: var(--plane);
  box-shadow: var(--cast);
}

.tl-shell {
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--margin);
}

.tl-band {
  padding-block: 96px;
}

.tl-band--tight {
  padding-block: 56px;
}

/* The stub/field split, borrowed from a policy illustration's row labels.
   Used on exactly two sections: How it works, and the FAQ. */
.tl-split {
  display: grid;
  grid-template-columns: var(--stub) minmax(0, 1fr);
  gap: var(--gutter);
}

.tl-skip {
  position: absolute;
  left: -9999px;
}

.tl-skip:focus {
  position: fixed;
  left: 16px;
  top: 16px;
  z-index: 100;
  background: var(--ink);
  color: var(--ground);
  padding: 12px 20px;
  font-family: 'Archivo', sans-serif;
  font-stretch: 87%;
  font-size: 0.84375rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

/* ---------------------------------------------------- the certainty marks -- */
/*
 * Two invariants:
 *   1. Non-guaranteed content is never made quieter — no opacity reduction,
 *      no smaller type, no lower contrast. It differs in material, not volume.
 *   2. Non-guaranteed is dot / dash / hatch — never a plain outline. That is
 *      what keeps an outlined BUTTON from reading as a certainty claim.
 *
 * A lattice mark has to POINT at the cell it heads, not merely classify it.
 * Four of the six used to be bare key swatches or generic pictograms, which is
 * why the grid needed a legend above it teaching a reading three of the six
 * then contradicted. Each mark below draws the thing its cell is about, in the
 * material that thing actually has.
 *
 * 1.5 of ink every 4px is the pitch everywhere a hatch appears, in CSS and in
 * the SVG pattern. The old 1-in-5 put only 20% coverage on the ground, so a
 * hatched patch averaged out close to the page while a solid one did not — the
 * material rule reading as a volume difference.
 */

.tl-mark {
  display: block;
  width: 56px;
  height: 40px;
  flex: none;
}

/* A guaranteed minimum beside a non-guaranteed part. Left/right rather than the
   footer key's stacked version, deliberately: this cell's heading is literally
   "side by side" and the key's own sentence is literally "above it". */
.tl-mark--split {
  background: linear-gradient(to right, var(--mark-g) 0 50%, transparent 50% 100%),
    repeating-linear-gradient(45deg, transparent 0 2.5px, var(--mark-n) 2.5px 4px);
  border-right: 1.25px dotted var(--mark-n);
  border-top: 1.25px dotted var(--mark-n);
  border-bottom: 1.25px dotted var(--mark-n);
}

/* Charges: your money with pieces taken out of it. Not the three ascending
   solid bars this used to be — ascending bars are the universal glyph for
   growth, so on a life page they argued the opposite of the cell they headed.
   The block is solid because the contract states the maximum charges; the band
   left at the top is hatched because what the carrier deducts inside those
   maximums is a current figure it can raise. */
.tl-mark--charges {
  /*
   * The cuts are thin and the segments are not. An earlier pass spaced three
   * 6px bars over three 4px gaps and detached the hatch band above them by a
   * fourth gap, which at 56x40 is the geometry of a hamburger menu — four
   * evenly weighted horizontal bars — sitting over the words "What the policy
   * actually costs". A block with slices taken out of it has to still read as a
   * block: solid runs of 11, 6, 5 and 4px, cut by 2.5px, and the hatch band
   * flush against the top of the solid rather than floating above it.
   */
  background: linear-gradient(
      to top,
      var(--mark-g) 0 11px,
      transparent 11px 13.5px,
      var(--mark-g) 13.5px 19.5px,
      transparent 19.5px 22px,
      var(--mark-g) 22px 27px,
      transparent 27px 29.5px,
      var(--mark-g) 29.5px 34px,
      transparent 34px 100%
    ),
    repeating-linear-gradient(45deg, transparent 0 2.5px, var(--mark-n) 2.5px 4px);
  background-size: 100% 100%, 100% 6px;
  background-position: bottom, top;
  background-repeat: no-repeat;
  box-shadow: var(--cast);
}

/* Index crediting: the hero drawing's bar-inside-its-outline at 56x40. The
   dotted rectangle is how far the index moved, the hatch is the share of it
   that was credited — the same two objects in the same two materials as the
   figure 800px up the page, which is the whole point of reusing it here.
   Neither quantity is promised, so neither is solid. */
.tl-mark--idx {
  background: repeating-linear-gradient(
    45deg,
    transparent 0 2.5px,
    var(--mark-n) 2.5px 4px
  );
  background-size: 100% 60%;
  background-position: bottom;
  background-repeat: no-repeat;
  border: 1.25px dotted var(--mark-n);
}

/* Sustained funding: the same premium, over and over. Seven bars on 8px
   centres, the first five solid because the premium the design needs is a
   stated requirement, the last two hatched because nobody has committed to
   them — and stopping is exactly what the cell says makes these policies fail. */
.tl-mark--premiums {
  background: repeating-linear-gradient(
      45deg,
      transparent 0 2.5px,
      var(--mark-n) 2.5px 4px
    ),
    repeating-linear-gradient(45deg, transparent 0 2.5px, var(--mark-n) 2.5px 4px),
    repeating-linear-gradient(to right, var(--mark-g) 0 4px, transparent 4px 8px);
  background-size: 4px 100%, 4px 100%, 40px 100%;
  background-position: 50px 0, 42px 0, 2px 0;
  background-repeat: no-repeat;
}

/* Cash value drawn down by a loan: solid mass decaying to a hairline. A loan
   against the policy is a contractual mechanic, so it is solid throughout. */
.tl-mark--wedge {
  background: var(--mark-g);
  clip-path: polygon(0 0, 100% 72%, 100% 100%, 0 100%);
}

/* Two routes, not two halves of one thing. A solid box on the baseline — term
   or guaranteed UL, whose cost is a contract term — and a hatched, dotted one
   raised beside it, whose crediting is not. The different baselines are what
   stop this reading as the split block above with a gap cut into it; the cell
   lists four alternatives, none of which is a guaranteed/non-guaranteed pair. */
.tl-mark--routes {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

.tl-mark--routes::before,
.tl-mark--routes::after {
  content: '';
  flex: 1;
  height: 30px;
}

.tl-mark--routes::before {
  background: var(--mark-g);
  box-shadow: var(--cast);
}

.tl-mark--routes::after {
  margin-bottom: 10px;
  background: repeating-linear-gradient(
    45deg,
    transparent 0 2.5px,
    var(--mark-n) 2.5px 4px
  );
  border: 1.25px dotted var(--mark-n);
}

/* ---------------------------------------------------------------- chips -- */

.tl-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 87%;
  font-size: 0.78125rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
  line-height: 1.2;
}

/*
 * The glyph was 22x12 with the split painted left/right, which gave the hatched
 * half eleven pixels — about two strokes — so BOTH rendered as IN THE CONTRACT
 * with a frayed edge and nine repetitions of the mark could not sort the list
 * it heads. Wider, taller, and a tighter 2-in-3 pitch that this file uses
 * nowhere else, because at 14px a 2.5-in-4 hatch is four strokes and reads as
 * damage rather than as texture.
 */
.tl-chip::before {
  content: '';
  width: 30px;
  height: 14px;
  flex: none;
}

.tl-chip--g::before {
  background: var(--mark-g);
}

.tl-chip--n::before {
  background: repeating-linear-gradient(
    45deg,
    transparent 0 2px,
    var(--mark-n) 2px 3px
  );
  border: 1.25px dotted var(--mark-n);
}

/* Stacked to agree with the footer key's sentence — a guaranteed minimum with a
   non-guaranteed part ABOVE it — and with the drawing, which stacks. The 1px
   hairline is what makes the two halves read as two materials: without it the
   hatch runs its diagonals into the solid half and the boundary between them is
   a ragged edge rather than a stated one. */
.tl-chip--split::before {
  background: linear-gradient(
      to top,
      var(--mark-g) 0 50%,
      var(--ink) 50% calc(50% + 1px),
      transparent calc(50% + 1px) 100%
    ),
    repeating-linear-gradient(45deg, transparent 0 2px, var(--mark-n) 2px 3px);
  border-top: 1.25px dotted var(--mark-n);
}

.tl-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 28px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* --------------------------------------------------------------- header -- */

.tl-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  min-height: 56px;
  padding-block: 12px;
  flex-wrap: wrap;
}

.tl-wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  text-decoration: none;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 112%;
  font-size: 1.125rem;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.tl-wordmark span {
  font-stretch: 87%;
  font-size: 0.78125rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
  font-weight: 600;
}

.tl-header-right {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

/*
 * The header holds the number, the hours and one secondary CTA on screen for the
 * whole scroll — which is what pays for deleting the seven inline "or call us"
 * captions that used to be tacked onto the end of most sections. The number
 * previously scrolled away after ~50px and never came back across 10,000px of
 * document, on desktop, where the call bar is deliberately killed.
 *
 * ≥768 only: below that .tl-callbar owns this job from the bottom edge, and a
 * sticky header there would eat the phone fold the hero card needs.
 */
@media (min-width: 768px) {
  .tl-header-stratum {
    position: sticky;
    top: 0;
    z-index: 30;
  }

  /*
   * The hairline arrives only once the header has actually left its place in the
   * flow. Drawn inset rather than as a border, so gaining it does not change the
   * header's height and shift the fold by a pixel. .is-stuck is set by an
   * IntersectionObserver on a sentinel — position:sticky fires no event, and
   * comparing scrollY against a hard-coded height goes stale the first time the
   * wordmark rewraps.
   */
  .tl-header-stratum {
    box-shadow: inset 0 -1px 0 transparent;
    transition: box-shadow 350ms linear;
  }

  .is-stuck .tl-header-stratum {
    box-shadow: inset 0 -1px 0 var(--rule-control);
  }

  /* Shorter than a body CTA: it rides in a 56px bar, not in a content column.
     Scoped through .tl-header because .tl-btn's own min-height is declared later
     in the file and would otherwise win the tie on source order. */
  .tl-header .tl-header-cta {
    min-height: 40px;
    padding: 0 16px 0 18px;
    font-size: 0.9375rem;
  }
}

/*
 * The CTA appears only where the bar can hold it on ONE row.
 *
 * Below 768 .tl-callbar carries the call path from the bottom edge, and a second
 * button up here would take a third of a 667px fold before the film has been
 * seen. Between 768 and 1023 the wordmark, the hours string and the number
 * already fill the bar: adding the button wrapped .tl-header-right onto a second
 * row and took the sticky header to 119px, which is a seventh of a laptop
 * viewport permanently occupied, and pushed every landing that far down.
 *
 * Nothing is lost in that band — the dialable number is still in the header, as
 * the tel: link the button sits beside.
 */
@media (max-width: 1023px) {
  .tl-header .tl-header-cta {
    display: none;
  }
}

/* ----------------------------------------------------------------- hero -- */
/* The film and the opaque copy panel share one full-bleed stack. The panel
   carries every word that must remain readable while the footage moves. */
.tl-hero-film {
  position: relative;
  display: grid;
  grid-template-areas: 'stack';
  isolation: isolate;
  background: var(--ground-deep);
  min-height: min(82vh, 780px);
}

.tl-scroll-anchor {
  display: block;
  scroll-margin-top: var(--s5);
}

/*
 * Everything an in-page link, a focus jump or the stepper can scroll to has to
 * clear the sticky header.
 *
 * This is the FALLBACK only. page.js measures the header and writes the real
 * value onto <html> as an inline custom property, because the header's height is
 * not a constant: adding the CTA wraps .tl-header-right onto a second row
 * between 768 and about 971px, and the wrap point moves with the font, the
 * locale and the staffed-hours string. A hard-coded 81px was 38px short across
 * that whole band, which put the active form question — and the New York
 * exclusion on the state step — underneath an opaque bar.
 *
 * fit-form.js reads the same property, so the stylesheet and the stepper cannot
 * disagree about where a landing sits.
 *
 * 24px below 768, where the header is not sticky and the call bar owns the
 * bottom edge instead; page.js writes that value too when it measures.
 */
:root {
  --scroll-offset: var(--s5);
}

@media (min-width: 768px) {
  :root {
    /* Static fallback for the no-JS and pre-measure frames: the unwrapped
       header at 57px, plus the standing 24px of air. */
    --scroll-offset: 81px;
  }
}

.tl-scroll-anchor,
.tl-fit-step,
.tl-head-group,
[id] {
  scroll-margin-top: var(--scroll-offset);
}

.tl-hero-film > * {
  grid-area: stack;
  min-width: 0;
}

.tl-hero-media {
  position: relative;
  overflow: hidden;
  min-height: 100%;
}

/*
 * Graded through the theme token like every other image on the page. It used to
 * hardcode saturate(0.88) contrast(1.06), which on a dark page made the hero the
 * brightest and most saturated image by a wide margin — the one photograph that
 * did not respond to the light the rest of the page was lit by.
 *
 * 50% 32%, not 50% 10%: the source is a 16:9 sofa shot and at ≤767 the media box
 * crops it to 1.875:1. Pulled to the top tenth, that crop cut the grandfather's
 * eyeline; a third down holds all three faces at every width.
 */
.tl-hero-media img,
.tl-hero-media video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 32%;
  filter: var(--img-filter) contrast(1.03);
}

/* A class the markup carried with no rule behind it. It is the LCP element and
   the complete no-JS fallback, so it is named here rather than left implicit. */
.tl-hero-poster {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.tl-hero-media::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(10, 13, 20, 0.22) 0%,
    rgba(10, 13, 20, 0.05) 38%,
    rgba(10, 13, 20, 0.06) 62%,
    rgba(10, 13, 20, 0.3) 100%
  );
}

.tl-hero-inner {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: end;
  pointer-events: none;
  padding-block: 88px 24px;
}

.tl-hero-inner > .tl-shell {
  width: 100%;
}

/* The generated video fades over the responsive poster only after playback
   begins, leaving the poster as the first paint and all fallback states. */
.tl-hero-media picture,
.tl-hero-media video {
  position: absolute;
  inset: 0;
}

.tl-hero-media video {
  opacity: 0;
  transition: opacity var(--dur) linear;
}

.tl-hero-media video.is-playing {
  opacity: 1;
}

.tl-hero-card {
  pointer-events: auto;
  width: 100%;
  /* 660, not 620: the trust line above the headline is fixed copy and at 620 it
     set to two lines with one word on the second. The card has the room. */
  max-width: 660px;
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: 16px;
  padding: 26px 30px 28px;
  background: var(--plane);
  /*
   * --rule is the structural hairline and its own comment says it deliberately
   * does not clear 3:1. That is defensible for a divider between two flat bands;
   * it is not defensible for the only boundary this card has, because the card
   * sits on moving footage — 2.34:1 in light, 2.10:1 in dark, which is no edge
   * at all. The second shadow is the contact edge against the film, not a
   * decorative drop.
   */
  border: 1px solid var(--rule-control);
  box-shadow: var(--cast), 0 0 0 1px rgba(0, 0, 0, 0.18);
}

.tl-hero-card > * {
  margin: 0;
}

/*
 * The h1 reused the section head's own 2.6vw slope, so the headline and the six
 * heads below it were identical in size from 1038 to 1384px and the headline was
 * SMALLER above that — the display object on its own page outranked by every
 * subhead in it. 3.2vw holds the ratio between 1.21 and 1.29 across the band.
 */
.tl-hero-card .tl-h1 {
  font-size: clamp(2rem, 3.2vw, 2.875rem);
}

/* The 19-word positioning line, brought onto the card from the strip that used
   to run below the film. It is the only prose on the fold. */
.tl-hero-sub {
  font-size: 1.0625rem;
  line-height: 1.45;
  max-width: 44ch;
  color: var(--ink-2);
}

/* The strip explains the two channels and keeps their helper text attached to
   the relevant action. */
/* This rule must outrank the later generic `.tl-btn-stack > .tl-btn` sizing;
   both hero actions fill their grid tracks instead of shrink-wrapping. */
/* A factual reassurance line, not a stand-in for an unverified review badge. */
.tl-hero-trust {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--ink);
}

.tl-hero-trust::before {
  content: '';
  width: 14px;
  height: 14px;
  margin-top: 0.12em;
  flex: none;
  background: var(--mark-g);
  box-shadow: var(--cast);
}

/* ------------------------------------------------ hero choreography -- */
/*
 * The fold is choreographed in CSS with no script anywhere in the path.
 * [data-reveal] holds content invisible until page.js says otherwise; the first
 * screen may never depend on that, so it uses `animation` with `both`, which
 * starts at parse and always completes.
 *
 * WHAT DOES NOT MOVE, AND WHY:
 *
 *   .tl-hero-media / .tl-hero-poster — the poster is the LCP element on every
 *     viewport and carries fetchpriority="high". An element animating from
 *     opacity 0 is not an LCP candidate until it is visible, so ANY fade here
 *     postpones LCP by exactly delay + duration. It is also the one thing on the
 *     fold that is already there when the HTML arrives.
 *
 *   .tl-h1 / .tl-hero-card — the card is the h1's box, and on a 375px phone the
 *     h1 is the second-largest paint on the screen: the LCP candidate the moment
 *     the poster is slow. It renders complete, always, in every state.
 *
 * Everything below animates opacity and transform ONLY, so the fold's layout is
 * final at first paint and CLS from this block is structurally zero.
 *
 * Budget: the last item starts at 300ms and settles at 680ms, inside the window
 * before a thumb reaches the first control. Tap targets fade but never travel,
 * and are never pointer-events: none, so an early tap always lands on the
 * control it was aimed at.
 */
@keyframes tl-enter {
  from {
    opacity: 0;
    transform: translate3d(0, var(--rise), 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* For anything tappable: it arrives without moving under the thumb. */
@keyframes tl-enter-still {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes tl-stroke {
  to {
    stroke-dashoffset: 0;
  }
}

.tl-js .tl-hero-trust {
  animation: tl-enter var(--dur-slow) var(--ease-out) both;
}

/* The h1 is deliberately absent from this block. */

.tl-js .tl-hero-sub {
  animation: tl-enter var(--dur-slow) var(--ease-out) 180ms both;
}

.tl-js .tl-seed {
  animation: tl-enter-still var(--dur-slow) var(--ease-out) 240ms both;
}

.tl-js .tl-hero-card > .tl-micro:not(.tl-hero-trust) {
  animation: tl-enter var(--dur-slow) var(--ease-out) 300ms both;
}

/*
 * The headline flourish — permitted accent use #4, unchanged. It is above the
 * fold on every viewport, so it is timed rather than observed: an
 * IntersectionObserver for something that is always already there is a blanket
 * timer waiting to happen, which is what the old one turned out to be.
 *
 * 340ms lands it just after the seed row has appeared and while the eye is still
 * on the headline; the second pass follows at the same 130ms interval the file
 * already used, the way a marker doubles back.
 */
.tl-js .tl-draw--underline path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: tl-stroke var(--dur-draw) var(--ease-draw) 340ms both;
}

.tl-js .tl-draw--underline path:nth-child(2) {
  animation-delay: 470ms;
}

/* The film control sits on the footage, clear of the copy panel. */
.tl-hero-toggle {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: var(--plane);
  border: 1px solid var(--rule-control);
  border-radius: 0;
  cursor: pointer;
  transition: border-color var(--dur-quick) linear;
}

.tl-hero-toggle:hover {
  border-color: var(--ink);
}

.tl-hero-toggle .tl-video-glyph {
  display: block;
  width: 12px;
  height: 14px;
}

.tl-hero-toggle[data-playing='true'] .tl-video-glyph {
  background: linear-gradient(
    to right,
    var(--ink) 0 35%,
    transparent 35% 65%,
    var(--ink) 65% 100%
  );
}

.tl-hero-toggle[data-playing='false'] .tl-video-glyph {
  background: var(--ink);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}

html:not(.tl-js) .tl-hero-toggle {
  display: none;
}

/*
 * Stacked at every width now. It used to be a 3-across row spanning the full
 * shell below the film; the two claims that survived the fold's deletion live in
 * the proof band's left column, where a row would set each item to about twenty
 * characters. One rule down the whole list, not one per item — three unconnected
 * ticks in the left margin is not a list.
 */
.tl-trust {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s2);
  justify-content: start;
  list-style: none;
  margin: 0;
  padding: 0;
  border-left: 1px solid var(--rule-control);
  font-size: 0.875rem;
  line-height: 1.45;
  color: var(--ink-2);
}

.tl-trust li {
  padding-inline: var(--s3) 0;
}

/* ----------------------------------------------------- the drawn line --- */
/*
 * A hand-drawn stroke that draws itself in. One flourish under a word in the
 * headline, and one thread running down the four steps of the process.
 *
 * THIS IS AN AMENDMENT TO TWO STANDING RULES. Both are narrowed rather than
 * dropped, and the narrowing is the whole point:
 *
 * 1. "Self-drawing strokes are deliberately absent — a line that draws itself
 *    over time reads as an illustration playing out." That reasoning is about
 *    the crediting figure, where a stroke arriving over time would imply values
 *    accruing over time, which is exactly the claim this page may not make.
 *    So the rule now reads: NOTHING INSIDE .tl-fig, AND NOTHING CARRYING
 *    CERTAINTY MATERIAL, EVER DRAWS ITSELF. The diagram still renders complete;
 *    its non-guaranteed marks still only fade. A flourish under a headline word
 *    and a thread beside four numbered steps make no claim about a policy, so
 *    they are free to be drawn.
 *
 * 2. The accent's permitted uses go from three to four: the primary CTA, the
 *    tel: link, the staffed-hours tab, and this flourish. The invariant that
 *    mattered is untouched — the accent still never touches a certainty mark,
 *    never enters the figure, and may never colour a projection. A stroke under
 *    a word in a sentence is not a value.
 *
 * The thread is --ink, not the accent: it runs beside step four, which carries
 * non-guaranteed material, and the accent may not sit that close to a mark.
 *
 * Geometry is authored on a pathLength="1" path so the dash maths is the same
 * whatever the path actually measures.
 */

.tl-draw {
  display: block;
  overflow: visible;
  pointer-events: none;
}

.tl-draw path {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/*
 * non-scaling-stroke is on the underline ONLY, and this is not a preference.
 *
 * Both drawings use preserveAspectRatio="none" with pathLength="1", and the dash
 * animation depends on "stroke-dasharray: 1" meaning exactly one path length.
 * non-scaling-stroke moves dash geometry into screen space while pathLength
 * normalises against user space, so under a strongly anisotropic scale the two
 * disagree and the dash covers only a fraction of the path. On the thread
 * (viewBox 16x400 drawn at 16xN) that fraction stopped the stroke around step
 * three and step four sat on nothing.
 *
 * The thread does not need it: its box is 16 user units wide drawn at 16px, so
 * the X scale is exactly 1 and a vertical line's stroke width — which is measured
 * across X — already renders at its declared width. The underline does need it:
 * 200x12 stretched to one word's width is anisotropic in both axes, and it is
 * short enough that the dash discrepancy stays under a pixel.
 */
.tl-draw--underline path {
  vector-effect: non-scaling-stroke;
}

/* The headline flourish. Two passes, the way a marker doubles back. */
.tl-draw--underline {
  position: absolute;
  left: 0;
  bottom: -0.18em;
  width: 100%;
  height: 0.34em;
}

.tl-draw--underline path {
  stroke: var(--signal);
  stroke-width: 3;
}

.tl-draw--underline path:nth-child(2) {
  stroke-width: 2;
  opacity: 0.55;
}

/* A word that carries a flourish needs to be its own positioning context, and
   it must not break across a line or the stroke lands under half of it. */
.tl-mark-word {
  position: relative;
  display: inline-block;
  white-space: nowrap;
}

/* The process thread, drawn down the stub gutter beside the four steps. */
.tl-steps-wrap {
  position: relative;
}

.tl-draw--thread {
  position: absolute;
  top: 32px;
  left: 3px;
  width: 16px;
  /* Stops short of the last row's bottom rule so the stroke ends on step four
     rather than running past it into the next section's edge. */
  height: calc(100% - 64px);
}

.tl-draw--thread path {
  stroke: var(--ink);
  stroke-width: 1.5;
}

/* The nodes sit on the thread, so they need to be above it and to carry the
   band's own ground, or the stroke shows through the dotted step-four mark. */
.tl-step-stub {
  position: relative;
  z-index: 1;
}

.tl-step-node {
  box-shadow: 0 0 0 5px var(--ground);
}

.tl-stratum--deep .tl-step-node {
  box-shadow: 0 0 0 5px var(--ground-deep);
}

/* At --stub: 0 the stub column collapses onto the body text and there is no
   gutter left to run a thread down. */
@media (max-width: 767px) {
  .tl-draw--thread {
    display: none;
  }
}

/*
 * Scripting on and motion allowed: the stroke is held back at full length and
 * released when it is scrolled to. Every other state — no scripting, reduced
 * motion, the observer never firing — renders it complete, because a flourish
 * that never arrives is just a missing stroke.
 */
.tl-js .tl-draw path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

/*
 * The thread down the stub gutter. Held at full dash offset and released by the
 * one reveal observer, under the same class every other held state uses.
 * The headline's underline is NOT here — it is above the fold at every width, so
 * it is timed rather than observed (see hero choreography). An observer for
 * something that is always already there is a blanket timer waiting to happen.
 */
.tl-js .tl-draw--thread.is-revealed path {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset var(--dur-draw-long) var(--ease-draw);
}

/* ------------------------------------------------------ scroll reveal -- */
/*
 * One primitive, one observer, one class. It replaces .tl-ng-fade's private
 * observer and .tl-draw's private observer, which were two IntersectionObservers,
 * two safety timers and two class names for one idea.
 *
 *   data-reveal              the element itself arrives
 *   data-reveal="stagger"    its direct children arrive, in DOM order
 *   data-reveal="watch"      observed, gets the class, holds NOTHING back
 *   data-reveal-move="none"  arrives by opacity only — for anything tappable
 *   data-reveal-rise="sm"    the shorter travel, for dense lists
 *
 * FORBIDDEN, and greppable in review:
 *
 *   - Never on a single certainty mark: .tl-mark, .tl-chip, .tl-fig-key--*,
 *     .tl-key-*, .tl-mech-floor, .tl-mech-cap, .tl-mech-part, .tl-step-node.
 *     A mark that arrives on its own timing is a mark making a claim about how
 *     settled it is. Containers only, and every mark inside a moving container
 *     shares one duration and one delay.
 *
 *   - Never a HELD variant on a container that carries a required disclosure.
 *     .tl-fig holds the caption, the five-row key and the stamp; all three are
 *     load-bearing under the illustration rules, so the panel gets "watch" —
 *     observed, never invisible — and only the .tl-ng-fade groups inside the
 *     drawing itself are held. Same for anything inside #fit: the form is never
 *     held back on script.
 *
 *   - Never above the fold. This attribute holds content INVISIBLE until
 *     page.js says otherwise; the first screen may not depend on that. Above
 *     the fold uses `animation` (see hero choreography), which starts at parse
 *     and always completes with no script in the path at all.
 *
 * The held state is gated on .tl-js — set in <head>, so it is live at first
 * paint and nothing flashes — and released by .is-revealed, by initReveal()'s
 * safety timer, or by the reduced-motion block.
 */
.tl-js [data-reveal=''],
.tl-js [data-reveal='stagger'] > * {
  opacity: 0;
  transform: translate3d(0, var(--rise), 0);
  transition: opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
}

.tl-js [data-reveal=''].is-revealed,
.tl-js [data-reveal='stagger'].is-revealed > * {
  opacity: 1;
  transform: none;
}

/*
 * The two modifiers, scoped to the SAME shapes the base primitive uses.
 *
 * They cannot be written bare — `[data-reveal-rise='sm']` on its own also matches
 * a stagger CONTAINER, which the base rule never holds and `.is-revealed > *`
 * never releases. The container would then keep its 8px offset for the life of
 * the page, in every state including reduced motion, and nothing would ever put
 * it back. The carrier mark row is exactly that shape.
 */
.tl-js [data-reveal=''][data-reveal-move='none'],
.tl-js [data-reveal='stagger'][data-reveal-move='none'] > * {
  transform: none;
}

.tl-js [data-reveal=''][data-reveal-rise='sm'],
.tl-js [data-reveal='stagger'][data-reveal-rise='sm'] > * {
  transform: translate3d(0, var(--rise-sm), 0);
}

.tl-js [data-reveal=''][data-reveal-rise='sm'].is-revealed,
.tl-js [data-reveal='stagger'][data-reveal-rise='sm'].is-revealed > * {
  transform: none;
}

/*
 * The ladder. The delay lives on the CHILD and only on the child, so a
 * container never carries a delay that anything it holds would inherit.
 *
 * Capped at seven: past that the last item lands after the first has been read,
 * and a ladder long enough to count is a page waiting for itself.
 */
.tl-js [data-reveal='stagger'] > *:nth-child(2) { transition-delay: var(--stagger); }
.tl-js [data-reveal='stagger'] > *:nth-child(3) { transition-delay: calc(var(--stagger) * 2); }
.tl-js [data-reveal='stagger'] > *:nth-child(4) { transition-delay: calc(var(--stagger) * 3); }
.tl-js [data-reveal='stagger'] > *:nth-child(5) { transition-delay: calc(var(--stagger) * 4); }
.tl-js [data-reveal='stagger'] > *:nth-child(6) { transition-delay: calc(var(--stagger) * 5); }
.tl-js [data-reveal='stagger'] > *:nth-child(n + 7) { transition-delay: calc(var(--stagger) * 6); }

/* Applied by initReveal() to anything already on screen when it runs late.
   The held state is removed in the same frame it would otherwise have been
   animated out of, so nothing flickers on a slow connection. */
/* Descendants, not just direct children: the crediting panel's held state lives
   on figure.tl-fig > svg > g.tl-ng-fade, so a child-only selector left the one
   nested fade on the page still running on a late load. */
.tl-js .is-reveal-instant,
.tl-js .is-reveal-instant * {
  transition: none !important;
}

/* -------------------------------------------------------- the seeded Q1 -- */
/*
 * The fold's conversion device. A real assessment question, not a fake progress
 * trick: answering it writes the answer and opens the form at question two.
 */

.tl-seed {
  width: 100%;
  max-width: 520px;
}

.tl-seed-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  margin-top: 10px;
}

/* ------------------------------------------------ buttons — CARVE-OUT --- */
/*
 * Interactive controls sit outside the certainty system. They never carry
 * hatch, dotted or dashed strokes; their hierarchy comes from size, position,
 * accent and left-edge rule weight — never from fill-vs-outline as meaning.
 */

.tl-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 56px;
  padding: 0 24px;
  border: 0;
  border-radius: 2px;
  background: transparent;
  color: var(--ink);
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 100%;
  font-size: 1.0625rem;
  letter-spacing: 0;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur-quick) linear,
    border-color var(--dur-quick) linear, color var(--dur-quick) linear,
    box-shadow var(--dur-quick) linear,
    transform var(--dur-quick) var(--ease-out);
}

.tl-btn--primary {
  background: var(--signal);
  color: var(--signal-on);
}

.tl-btn--primary:hover {
  background: var(--signal-deep);
}

.tl-btn--outline {
  border: 1.5px solid var(--ink);
  background: transparent;
  color: var(--ink);
}

.tl-btn--outline:hover {
  border-color: var(--ink);
  background: var(--plane);
  box-shadow: var(--cast);
}

/* No left border: the hours tab supplies that edge, so the button carries one
   left edge rather than a 1.5px border, a 3px tab and 5px of gap between them. */
.tl-btn--secondary {
  border: 1.5px solid var(--ink);
  border-left: 0;
  padding-left: 26px;
}

/*
 * Hover used to move the border --ink (13.3:1) to --ink-2 (7.6:1) and change the
 * fill by 1.15:1 — so pointing at the secondary CTA made it QUIETER, which is
 * the opposite of what a hover state is for. It now holds its edge and lifts.
 */
.tl-btn--secondary:hover {
  border-color: var(--ink);
  background: var(--plane);
  box-shadow: var(--cast);
}

/*
 * A slab rises toward the light. This is the page's own light model, not a
 * generic hover lift: a lifted plane here already casts along its bottom edge,
 * so a control that rises 1px is behaving like every other lifted plane on the
 * page. 1px and no more, because this file has no blurred shadows to sell a
 * larger displacement with.
 */
.tl-btn:hover {
  transform: translateY(-1px);
}

/* Instant on the way down: a press has to be under the finger, not after it.
   Nothing on this page had a press state at all, on a page whose conversion
   mechanic is tapping a card that then advances the form 220ms later. */
.tl-btn:active {
  transform: translateY(1px);
  transition-duration: 0ms;
}

.tl-btn:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

.tl-btn:disabled:hover,
.tl-btn:disabled:active {
  transform: none;
  box-shadow: none;
}

/* :hover latches after a tap on iOS, which would leave the slab 1px high for
   the rest of the scroll. A pointerless device gets the press and nothing else. */
/* :not(:active) so the reset cannot outrank the press. Both rules are (0,2,0)
   and this one comes later, so an unqualified :hover won whenever a finger was
   down — which cancelled the press state on exactly the devices it is for. */
@media (hover: none) {
  .tl-btn:hover:not(:active) {
    transform: none;
  }
}

.tl-btn-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 12px;
  width: 100%;
}

.tl-btn-stack {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/*
 * The stack has no width of its own, so it shrink-wraps to its widest child —
 * the 34ch caption — and a `width: 100%` button inside would resolve against
 * that accidental box and come out wider than the primary slab beside it. The
 * button sizes to its own label instead and the caption wraps under it. At
 * 767 and below `.tl-btn-row .tl-btn { width: 100% }` overrides this, later in
 * the file and at equal specificity, which is what the stacked fold wants.
 */
.tl-btn-stack > .tl-btn {
  width: max-content;
  max-width: 100%;
}

/*
 * The hours indicator: a solid tab that IS the secondary CTA's left edge, not a
 * line beside it. It is a live-state control, so only its VALUE changes, never
 * its material.
 */
.tl-hours-tab {
  position: absolute;
  inset: 0 auto 0 0;
  width: 5px;
  background: var(--rule);
}

/* Overhangs by the border width at both ends so it meets the outer corners of
   the top and bottom borders rather than stopping inside them. */
.tl-btn--secondary .tl-hours-tab {
  inset: -1.5px auto -1.5px 0;
}

:root[data-hours='open'] .tl-hours-tab {
  background: var(--signal);
}

/* The document ships data-hours="unknown" and attribution.js resolves it on
   load. Stated explicitly so the staffed-hours use of the accent — "an agent is
   at the desk right now" — can never be asserted by first paint, or permanently
   with scripting blocked, before anything has actually checked the clock. */
:root[data-hours='unknown'] .tl-hours-tab {
  background: var(--rule);
}

.tl-hours-caption {
  font-size: 0.9375rem;
  line-height: 1.4;
  color: var(--ink-2);
  max-width: 34ch;
}

/* --------------------------------------------------------- figure panel -- */

.tl-fig {
  position: relative;
  border: 1px solid var(--rule);
  background: var(--ground);
  padding: 20px;
}

/* The UA gives <figure> `margin: 1em 40px` and this file has no figure reset, so
   removing the inline `style="margin: 0"` inset the whole crediting panel 40px
   from every other element in its band. */
.tl-fig {
  margin: 0;
}

/*
 * Capped, and centred in the panel. Uncapped, the drawing took the whole
 * content column — 1136px at a 1200 shell — which rendered the in-drawing stub
 * labels (17 viewBox units) at 34.5px: larger than the section head above them
 * and about twice the body column, and the 4-unit hatch pattern at an 8.1px
 * period, which is a coarse diagonal rather than a texture. It also meant the
 * figure was 2.1x larger at 1024px than at 1023px, in opposite directions from
 * the width, because the ≤1023 rule capped it and nothing capped it above.
 * 560px is the width the two-column band gives it at 1024, held from there up.
 */
.tl-fig svg {
  width: 100%;
  max-width: 560px;
  height: auto;
  margin-inline: auto;
}

/*
 * The figure's own sentence, and the only one that says what the marks mean
 * rather than modifying them. It brackets the drawing against .tl-fig-keys
 * below — same rule, same 16px — so caption and key read as one pair of
 * margins around the drawing. It renders at every width; the key does not
 * replace it, because the key names the marks and this names the argument.
 */
.tl-fig-caption {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--rule);
}

/* An outlined chip — solid stroke, because it is a statement about the page,
   not a non-guaranteed value. No accent touches the diagram. One line, and it
   closes the panel: four negations at the top of the column classified the
   whole figure as disclosure furniture before anyone read the drawing. */
.tl-fig-stamp {
  display: inline-block;
  margin: 16px 0 0;
  border: 1.25px solid var(--ink);
  padding: 5px 9px;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 87%;
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
  line-height: 1.3;
  max-width: 56ch;
}

/* The panel's two-chip legend is gone. It predates .tl-fig-keys rendering at
   every width, and once the key prints a swatch and a gloss for all five marks
   the chips repeated two of those words about 50px below them. Two statements
   of the same thing in one panel is the reader's problem, not the page's. */

/* ---- the drawing itself ------------------------------------------------
   No accent colour touches this diagram. The one place a reader could
   mistake colour for meaning is the one place colour is banned. */

.tl-svg-floor {
  fill: var(--mark-g);
}

/* The index is an observable, never a promise — so it is never solid. 1.5 is
   the ceiling for this stroke: any thicker against a `2 3` dash and the dots
   start touching, which would read as solid and collapse the distinction the
   whole system rests on. Widen the dasharray before widening the stroke. */
.tl-svg-idx {
  fill: none;
  stroke: var(--mark-n);
  stroke-width: 1.5;
  stroke-dasharray: 2 3;
}

/* A real event of an unpromised size. It takes the index outline's own x and
   width, so no stroke of its own: the dotted rect drawn over it supplies the
   edge, and the mark is hatch inside a dotted outline — the same object the
   key swatch shows. A solid outline here made the two disagree. */
.tl-svg-credit {
  fill: url(#tl-hatch);
  stroke: none;
}

.tl-svg-hatchline {
  stroke: var(--mark-n);
  stroke-width: 1.5;
}

/* Dotted = never promised. Dashed = a number the carrier can reset. */
.tl-svg-cap {
  stroke: var(--mark-n);
  stroke-width: 1.5;
  stroke-dasharray: 5 4;
  fill: none;
}

/*
 * Label furniture, not a mark. It carries no quantity of its own — it points a
 * stub label at a gap — but at 1.5px in --mark-n it was drawn in the
 * non-guaranteed MATERIAL token, at the weight of the cap and the index, and it
 * was the only unbroken stroke in the drawing besides the floor. The floor has
 * to be the one solid object here, because "solid" is the whole of this page's
 * promise vocabulary.
 *
 * Not --rule: that is the structural hairline and it reaches only 2.1:1 on the
 * figure's ground, below the 3:1 a graphic needs to be understood by. Dashing
 * it is worse than either, because dashed is a material and this is not making
 * a claim. --rule-control exists for exactly this — 3.8:1 light, 7.0:1 dark,
 * and it is the token buttons and field wells use, which are the other things
 * on this page that sit outside the certainty system.
 */
.tl-svg-bracket {
  fill: none;
  stroke: var(--rule-control);
  stroke-width: 1;
}

/*
 * Set in viewBox units, so the rendered size is this number times the SVG's
 * width over 540. At 17 that is 15.7px from 1280 up and 12.9px at 1024; at the
 * 13 it used to carry it was 9.8px and 8.1px — the drawing legible and the
 * words attached to it not. The stub is 158 units wide and the longest string
 * needs 152 of them, so these two sizes are the ceiling, not a preference.
 */
.tl-svg-label {
  fill: var(--ink);
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-size: 17px;
  font-weight: 600;
  font-stretch: 87%;
  letter-spacing: 0.08em;
}

.tl-svg-label--end {
  text-anchor: end;
}

/* The qualifier under each stub label. Never dimmer than the secondary ink and
   never far off the claim's size — this tier carries IN THE CONTRACT and CAN
   CHANGE at the same weight, so it must not be readable as a volume ranking of
   the two. */
.tl-svg-label--sub {
  fill: var(--ink-2);
  font-size: 15px;
  font-weight: 500;
}

/*
 * The Spanish figure is drawn on a 580-unit viewBox against the English 540,
 * so the same rendered box scales its units down by a further 8% and the same
 * font-size lands smaller on screen. It is set larger here to render at parity
 * — 15.5px against English's 15.7px at the width the hero settles at.
 *
 * The stub is still 158 units on both, so the two longest Spanish strings were
 * the binding constraint rather than the type size: at this size the old
 * PERIODOS A LA BAJA and NO SE ACREDITA NADA ran past the left edge. They are
 * now A LA BAJA and NADA ACREDITADO, which say the same thing and fit. Anything
 * longer than about 14 characters will clip here — check it against the render,
 * not against the English string.
 */
[lang='es'] .tl-svg-label {
  font-size: 18px;
}

[lang='es'] .tl-svg-label--sub {
  font-size: 16px;
}

.tl-fig-keys {
  display: grid;
  margin: 0;
  padding: 16px 0 0;
  border-top: 1px solid var(--rule);
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
}

.tl-fig-keys > div {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
}

.tl-fig-keys dt {
  height: 14px;
  align-self: center;
}

.tl-fig-keys dd {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.4;
  color: var(--ink);
}

.tl-fig-keys dd span {
  display: block;
  color: var(--ink-2);
  font-size: 0.875rem;
}

.tl-fig-key--floor {
  background: var(--mark-g);
}

.tl-fig-key--cap {
  border-top: 1.5px dashed var(--mark-n);
  height: 0 !important;
}

.tl-fig-key--part,
.tl-fig-key--down {
  background: repeating-linear-gradient(
    45deg,
    transparent 0 2.5px,
    var(--mark-n) 2.5px 4px
  );
  border: 1.25px dotted var(--mark-n);
}

/* Empty, with the floor closing it off above — which is what the drawing shows
   in a down period. Without that solid edge this swatch is pixel-identical to
   the six index outlines drawn above the floor, i.e. to the opposite claim. */
.tl-fig-key--down {
  background: none;
  border-top: 3px solid var(--mark-g);
}

/*
 * Projections arrive; guarantees do not. The floor is drawn on the first frame
 * the panel is visible; only the non-guaranteed marks fade up behind it.
 *
 * The held state lives on the PANEL, not on the two <g> elements. That is the
 * material rule made structural rather than remembered: the two groups have
 * different vertical extents (y12-195 and y195-265), so observing them
 * individually fired them at different scroll positions and staggered two
 * non-guaranteed marks against each other for no reason but geometry. One class
 * on one ancestor cannot stagger anything.
 *
 * 220ms with a 140ms lead-in, not 120ms flat: 120ms is below the threshold at
 * which a fade reads as motion at all, so the page's one intended figure beat
 * was invisible. The delay is what puts the solid floor there first.
 *
 * Gated on .tl-js so that with scripting off the diagram renders complete rather
 * than losing exactly the marks a reader most needs to see.
 */
.tl-js .tl-fig .tl-ng-fade {
  opacity: 0;
  transition: opacity var(--dur) var(--ease-out) var(--dur-fast);
}

.tl-js .tl-fig.is-revealed .tl-ng-fade {
  opacity: 1;
}

/* The single highest-credibility sentence on the page. Never demoted. */
.tl-concession {
  margin: 0;
  font-size: 1.09375rem;
  line-height: 1.65;
  font-weight: 600;
  color: var(--ink);
  max-width: 62ch;
  border-left: 1px solid var(--ink);
  padding-left: 20px;
}

/* ------------------------------------------- crediting mechanics rows --- */

.tl-mech {
  display: grid;
  gap: 0;
  margin: 0;
  border-top: 1px solid var(--rule);
}

.tl-mech-row {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: var(--gutter);
  align-items: start;
  padding-block: 24px;
  border-bottom: 1px solid var(--rule);
}

/*
 * Three rows of ~40 words stacked ran 360px to do 180px of work, directly under a
 * figure that had just made the same three points visually. Side by side they read
 * as the drawing's three parts rather than as three more paragraphs — and the
 * order is floor, cap, participation: the guaranteed one first, which is the same
 * polarity the drawing uses and is not a taste decision.
 */
@media (min-width: 1024px) {
  .tl-mech {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: var(--s7);
    border-bottom: 1px solid var(--rule);
  }

  .tl-mech-row {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s3);
    border-bottom: 0;
  }
}

.tl-mech-fig {
  height: 40px;
  display: flex;
  align-items: center;
}

/* FLOOR: the only solid mass. */
.tl-mech-floor {
  width: 100%;
  height: 14px;
  background: var(--mark-g);
  box-shadow: var(--cast);
}

/* CAP: a number the carrier sets and can reset — dashed, not dotted. */
.tl-mech-cap {
  width: 100%;
  height: 0;
  border-top: 1.5px dashed var(--mark-n);
}

/* PARTICIPATION: a share of the move is credited, not all of it — so this is
   the drawing's own bar-inside-its-outline at 34px, dotted rectangle for the
   index move and hatch for the part of it credited. It used to be a clip-path
   trapezoid rising left to right, which says nothing about a share and is the
   mirror image of the loan wedge. These three rows exist to rescue a reader who
   did not parse the SVG; handing that reader a fourth shape is the one thing
   they cannot afford. */
.tl-mech-part {
  width: 100%;
  height: 34px;
  background: repeating-linear-gradient(
    45deg,
    transparent 0 2.5px,
    var(--mark-n) 2.5px 4px
  );
  background-size: 100% 60%;
  background-position: bottom;
  background-repeat: no-repeat;
  border: 1.25px dotted var(--mark-n);
}

.tl-mech-row dt {
  margin: 0;
}

.tl-mech-row dd {
  margin: 0;
}

/* -------------------------------------------------------------- lattice -- */

.tl-lattice {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: 1px solid var(--rule);
  border-left: 1px solid var(--rule);
}

.tl-lattice-cell {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 32px 20px 36px;
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}

.tl-lattice-cell h3 {
  margin: 0;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 112%;
  font-size: 1.375rem;
  line-height: 1.2;
  letter-spacing: -0.008em;
  text-wrap: balance;
}

.tl-lattice-cell p {
  margin: 0;
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--ink-2);
}

/* ---------------------------------------------------------- proof band --- */

.tl-proof {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 48px var(--gutter);
}

/* An exact grid, not a wrapping row. Six slots of unequal label width wrapped
   4+2 at desktop, 3+3 at 1024 and 5+1 at 768 — the only ragged block on a page
   built entirely from exact grids, sitting in the band a sceptic scans hardest,
   where a half-empty row reads as an unfinished affiliate page. */
.tl-slotrow {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/*
 * A neutral slot awaiting real, verified content. Deliberately plain — it takes
 * no material from the certainty vocabulary, because "not filled in yet" is
 * not a claim about a policy.
 */
.tl-slot {
  border: 1px solid var(--rule);
  padding: 10px 14px;
  color: var(--ink-2);
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 500;
  font-stretch: 87%;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.3;
}

/*
 * A carrier mark. These are third-party trademarks and the only artwork on the
 * page the agency does not own, so they get a plate of their own rather than
 * being dropped onto the ground colour.
 *
 * The plate is LIGHT in both themes. Every mark here is dark-on-transparent, so
 * on the dark theme's #0a0d14 ground an unaltered logo is invisible, and the
 * hover state the greyscale exists to reward would reveal nothing. Lighting the
 * plate rather than filtering the mark is also the safer answer to carrier brand
 * guidelines: hue, proportion and clear space are never touched. It follows the
 * page's own dark rule — a lifted plane is lighter than ground, because the
 * light still comes from above — just carried further than the UI planes are.
 */
/* --mark-plate on --ground-deep is 1.31:1 in light — a lit plate with no edge,
   which is the whole of the "the proof band reads as mush" complaint. The border
   gives the plate a boundary at 3.28:1 without touching the plate's own value. */
.tl-slot--mark {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 14px 18px;
  min-height: 66px;
  background: var(--mark-plate);
  border: 1px solid var(--rule-control);
}

/*
 * Height-normalised, not width-normalised: these are six marks of wildly
 * different proportion — wordmarks up to 5.8:1 beside a square emblem — and
 * fitting them to a common width would print the emblem at a fifth of the
 * wordmarks' size. `--mark-h` lets a square mark take more height so it carries
 * the same optical weight; the wordmarks all sit at the 26px default.
 */
.tl-slot--mark img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: var(--mark-h, 26px);
}

/*
 * Reserved, currently unused. The named-agent cards and the review lines were
 * both removed from the proof band rather than shipped with invented content —
 * a fabricated license number or testimonial is a regulatory problem, not a
 * copy one. These two rules stay so that restoring either block with real,
 * verifiable content is a markup change and nothing else.
 */
.tl-agent-credential {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 16px 0;
  border-top: 1px solid var(--rule);
}

.tl-agent-credential b {
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 100%;
  font-size: 1.0625rem;
}

.tl-review-line {
  margin: 0;
  font-size: 1.09375rem;
  line-height: 1.6;
  max-width: 46ch;
}

.tl-review-line cite {
  display: block;
  margin-top: 6px;
  font-style: normal;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 87%;
  font-size: 0.78125rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
}

/* ----------------------------------------------------------------- form -- */

.tl-form-wrap {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
  gap: 64px;
  align-items: start;
}

.tl-optional {
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-2);
}

.tl-fit {
  max-width: 620px;
}

/* Progress is expressed as RULE WEIGHT, never as squares filling — filling
   would borrow the guaranteed material for something that is not a claim. */
.tl-fit-progress {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 6px;
  margin: 10px 0 28px;
  padding: 0;
  list-style: none;
}

/*
 * The one growing quantity this site is allowed to have: the visitor's own
 * progress through their own form. It is not a policy value, so it carries no
 * certainty material and no accent — the ink is --ink. --rule is the structural
 * hairline and its own comment says it must not carry state; --rule-control is
 * the token that clears 3:1 for exactly this.
 *
 * Drawn left to right rather than switched on, because a rule being laid down is
 * what "you have done that one" looks like in this file's vocabulary. The fill is
 * a pseudo-element under a transform, so nothing about the row's layout changes:
 * the segment keeps its 2px box, the current one keeps its 4px, and the row keeps
 * its baseline. Going back retracts the wipe leftward, which reads as an undo.
 */
.tl-fit-segment {
  position: relative;
  height: 2px;
  background: var(--rule-control);
  align-self: end;
}

.tl-fit-segment::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur) var(--ease-inout);
}

.tl-fit-segment.is-done::after,
.tl-fit-segment.is-current::after {
  transform: scaleX(1);
}

/*
 * Position is the rule's WEIGHT — done and current used to resolve to identical
 * CSS, which left the whole burden of "you are here" on a 4px pseudo-element
 * that read as a speck. Bottom-aligned, so the current segment grows upward
 * against a common baseline rather than shifting the row.
 */
.tl-fit-segment.is-current {
  height: 4px;
}

/*
 * Stepping is progressive enhancement. With scripting off every question is
 * present and the form is one honest scroll; with scripting on only the active
 * step renders, and it never flashes because .tl-js is set in <head>.
 */
.tl-fit-step + .tl-fit-step {
  margin-top: 44px;
  padding-top: 36px;
  border-top: 1px solid var(--rule);
}

.tl-js .tl-fit-step {
  display: none;
}

.tl-js .tl-fit-step.is-active {
  display: block;
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

/*
 * Step change. The stepper swaps `display`, so this is an ANIMATION, not a
 * transition: an element that was display:none in the previous frame has no start
 * value for a transition to run from. `both` fill means the step sits at its
 * final state before and after, so nothing is ever left mid-flight.
 *
 * Keyed on [data-step-dir], which fit-form.js sets ONLY inside goTo() — so the
 * first render at load, and any browser that restores the form, paint step one
 * with no animation at all.
 *
 * 8px, not 14: the step's heading has just taken focus and the form's own scroll
 * correction may have the page mid-glide. A large travel on top of a smooth
 * scroll is two things moving at once, which is exactly the impression this page
 * cannot give.
 */
@keyframes tl-step-fwd {
  from {
    opacity: 0;
    transform: translate3d(var(--rise-sm), 0, 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes tl-step-back {
  from {
    opacity: 0;
    transform: translate3d(calc(var(--rise-sm) * -1), 0, 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.tl-js .tl-fit[data-step-dir='fwd'] .tl-fit-step.is-active {
  animation: tl-step-fwd var(--dur) var(--ease-out) both;
}

.tl-js .tl-fit[data-step-dir='back'] .tl-fit-step.is-active {
  animation: tl-step-back var(--dur) var(--ease-out) both;
}

.tl-js-only {
  display: none;
}

.tl-js .tl-js-only {
  display: block;
}

.tl-js .tl-fit-progress.tl-js-only {
  display: grid;
}

.tl-js .tl-fit-nav.tl-js-only {
  display: flex;
}

/* The head's <noscript> already hides the whole form, so nothing carrying this
   is reachable without scripting. It stays as the second layer: the controls it
   covers are the stepper's Continue buttons and the submit, and every one of
   them is a dead end or a data loss if the form is ever shown unscripted again. */
.tl-no-js-hide {
  display: none;
}

.tl-js .tl-no-js-hide {
  display: inline-flex;
}

.tl-fit-question {
  margin: 0 0 6px;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 100%;
  font-size: 1.5rem;
  line-height: 1.25;
  letter-spacing: -0.005em;
  text-wrap: balance;
}

.tl-fit-help {
  margin: 0 0 20px;
  font-size: 1rem;
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 56ch;
}

/*
 * The hero's age question is answered before the form opens, so a seeded
 * visitor arrives at question two having apparently done nothing. This reports
 * what was banked, set at help-text weight rather than question weight: it is a
 * receipt for a tap that already happened, not another thing to answer.
 */
.tl-fit-answered {
  margin: 0 0 20px;
  font-size: 1rem;
  line-height: 1.55;
  color: var(--ink-2);
}

.tl-fit-answered b {
  font-weight: 600;
  color: var(--ink);
}

.tl-fit-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/*
 * Option cards. Selection is a 4px solid LEFT EDGE, never a fill change —
 * controls do not participate in the certainty vocabulary.
 *
 * Each card is a <label> for a radio the browser owns. The input is clipped
 * rather than display:none so it stays focusable and stays IN the group: arrow
 * keys walk the options, the whole question is one tab stop, and "3 of 6" is
 * spoken by the browser instead of being rebuilt out of aria-pressed toggles
 * that announced the wrong pattern anyway. It is also what makes the questions
 * answerable with scripting off, which is the state the README claims and the
 * page did not ship.
 */
.tl-fit-radio {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* The input carries the focus, the label carries the ring. */
/* The input carries the focus and the label carries the ring, so this rule has
   to restate :focus-visible's geometry — it was left on the old 2px/3px while
   every other control moved to 3px/5px, which made the one control a keyboard
   visitor spends the most time on the odd one out. The card's own cast is kept
   in the shadow list, the same way .tl-field-well keeps its recess. */
.tl-fit-radio:focus-visible + .tl-fit-option {
  outline: 2px solid var(--focus-a);
  outline-offset: 3px;
  box-shadow: var(--cast), 0 0 0 5px var(--focus-b);
}

.tl-fit-option {
  position: relative;
  display: block;
  width: 100%;
  min-height: 56px;
  padding: 12px 18px 12px 22px;
  text-align: left;
  /*
   * A step UP from the band. #fit is .tl-stratum--plane and this card was also
   * --plane, so the two most important controls on the page were pixel-identical
   * in value to the surface they sat on, separated by one hairline. A lifted
   * plane is lighter than ground and casts along its bottom edge — the page's
   * own light model, applied to the thing the visitor has to tap.
   */
  background: var(--plane-hi);
  /*
   * 1.5px at rest, not 1px. Selection used to widen the border from 1 to 1.5,
   * which moved the label half a pixel on three sides at the exact instant the
   * visitor is checking that their tap registered — the one frame in the whole
   * form where a shift reads as a mis-tap. Selection now changes colour only;
   * the card's box is pixel-identical in every state.
   */
  border: 1.5px solid var(--rule-control);
  border-left: 4px solid transparent;
  box-shadow: var(--cast);
  cursor: pointer;
  transition: border-color var(--dur-quick) linear,
    background-color var(--dur-quick) linear,
    box-shadow var(--dur-quick) linear,
    transform var(--dur-quick) var(--ease-out);
}

/*
 * The confirmation beat: the 4px selected edge is DRAWN down the card rather
 * than switched on. A rule laid down the side of a row is the same grammar
 * .tl-concession and .tl-status already use, and this is the one motion in the
 * form that says "that one".
 *
 * Insets overhang the 1.5px border at both ends so the edge meets the outer
 * corners rather than stopping inside them. 90ms, so it finishes well inside the
 * 220ms fit-form.js holds the card before it changes step.
 */
.tl-fit-option::before {
  content: '';
  position: absolute;
  inset: -1.5px auto -1.5px -4px;
  width: 4px;
  background: var(--ink);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform var(--dur-quick) var(--ease-out);
}

/* Hover changed nothing but a 1px border colour, which on a card this size is
   below the perceptual floor. It now lifts like every other plane. */
.tl-fit-option:hover {
  border-color: var(--ink-2);
  border-left-color: var(--rule-control);
  transform: translateY(-1px);
}

.tl-fit-option:active {
  transform: translateY(1px);
  transition-duration: 0ms;
}

@media (hover: none) {
  .tl-fit-option:hover:not(:active) {
    transform: none;
  }
}

/* Native checked state and the JS-applied class render identically in both
   locales, including while a restored answer is being adopted. */
.tl-fit-option.is-selected,
.tl-fit-radio:checked + .tl-fit-option {
  border-color: var(--ink);
  border-left-color: transparent; /* the ::before paints this edge */
}

.tl-fit-option.is-selected::before,
.tl-fit-radio:checked + .tl-fit-option::before {
  transform: scaleY(1);
}

.tl-fit-option b {
  display: block;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  /*
   * 600 at rest, in every state. Selection used to step this 500 → 600, which
   * relaid the label and could rewrap the <small> under it on the same frame the
   * card confirmed the tap. Selection is carried by the drawn edge and the border
   * colour, which change nothing about the text.
   */
  font-weight: 600;
  font-stretch: 100%;
  font-size: 1.0625rem;
  line-height: 1.35;
}

.tl-fit-option small {
  display: block;
  margin-top: 2px;
  font-size: 0.9375rem;
  line-height: 1.45;
  color: var(--ink-2);
}

/*
 * The counter and Back on one line. Back used to sit after the seventh
 * fieldset, outside every step, so on a phone it was below the whole active
 * question — off screen for the length of Q3 — while an option advances 220ms
 * after a tap. The undo has to be visible from where the tap happened.
 */
.tl-fit-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  /* Back is absent on step one and present on every step after it, so the row
     has to reserve the taller of the two states or the counter drops 25px at
     the exact moment the visitor answers question one. This is the Back
     control's own height: 12 + 12 of padding around 13.5px at 1.4. */
  min-height: 43px;
}

.tl-fit-head .tl-micro {
  margin: 0;
}

/* Base navigation spacing; the counter-row variant below removes the margin. */
.tl-fit-nav {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-top: 24px;
  flex-wrap: wrap;
}

.tl-fit-head .tl-fit-nav {
  gap: 0;
  margin-top: 0;
}

/* Punctuation. Two runs of uppercase Archivo at 13.5px sitting side by side
   read as one string without it. */
.tl-fit-head .tl-fit-nav::before {
  content: '\00B7';
  color: var(--ink-2);
}

/* .tl-js-only is display:none at equal specificity and earlier in the file, so
   both layout rules above would otherwise beat it. Keep stepped navigation out
   of the no-script state, where the whole form is replaced by the call panel. */
html:not(.tl-js) .tl-fit-nav,
html:not(.tl-js) .tl-fit-head {
  display: none;
}

.tl-back {
  background: none;
  border: 0;
  padding: 8px 0;
  cursor: pointer;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 87%;
  font-size: 0.84375rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
  text-decoration: underline;
  text-underline-offset: 4px;
}

.tl-back:hover {
  color: var(--ink);
}

/* The nav copy is a primary escape hatch on a phone and 40x32 is not a target;
   the padding is the whole of the fix, since the glyph is 13.5px of uppercase.
   Scoped, because the other .tl-back is the "Change" control inside the
   answered line, where it sits mid-sentence and must stay inline-sized. */
.tl-fit-nav .tl-back {
  padding: 12px;
  line-height: 1.4;
}

/* Recessed wells read as "write here" — they beat flat-bordered and
   underline-only fields on mobile tap-affordance. */
.tl-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 18px;
}

.tl-field-well {
  width: 100%;
  min-height: 56px;
  padding: 14px 16px;
  background: var(--ground-deep);
  border: 1px solid var(--rule-control);
  border-left: 4px solid transparent;
  box-shadow: var(--cast-inset);
  color: var(--ink);
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-stretch: 100%;
  font-size: 1.0625rem;
}

/*
 * No placeholder rule existed. The phone field ships placeholder="(555) 555-0100"
 * into a well set in Archivo, inheriting tabular figures from html — at UA default
 * colour it reads as a value already typed, on the one field the lead depends on.
 */
.tl-field-well::placeholder {
  color: var(--ink-2);
  opacity: 0.78;
  font-stretch: 87%;
}

select.tl-field-well {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink) 50%),
    linear-gradient(135deg, var(--ink) 50%, transparent 50%);
  background-position: calc(100% - 22px) calc(50% + 2px),
    calc(100% - 16px) calc(50% + 2px);
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 44px;
}

/*
 * An invalid field is not a non-guaranteed claim, so an error state may never
 * borrow dotted, dashed or hatched material — and it is not the accent either,
 * because --signal has an enumerated list of permitted uses and this is not on
 * it. Validation gets its own semantic token.
 */
.tl-field-well[aria-invalid='true'] {
  border-color: var(--alert);
  border-width: 1.5px;
  border-left: 4px solid var(--alert);
}

/* The same treatment as the label above the field it belongs to. In the body
   serif at weight 600 these were the heaviest text on the page — four bold
   Literata blocks down the final step, out-weighing the question set in Archivo
   above them, in an ink identical to --ink. It read as being told off. */
.tl-field-error {
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-stretch: 87%;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--alert-ink);
  font-weight: 600;
}

.tl-field-error:empty {
  display: none;
}

/*
 * The plain-language line above the disclosure. Archivo rather than the label's
 * Literata, so it reads as the page speaking rather than as a second paragraph
 * of the agreement, and at full ink because it is not fine print. It sits
 * OUTSIDE #tl-consent-text: that element is snapshotted verbatim on to the
 * lead, and it is the disclosure, not this.
 */
.tl-consent-summary {
  margin: 0 0 10px;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 100%;
  font-size: 0.9375rem;
  line-height: 1.5;
  max-width: 62ch;
}

.tl-consent {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
  padding: 16px;
  margin: 8px 0 20px;
  background: var(--ground-deep);
  border: 1px solid var(--rule);
}

.tl-consent-box {
  width: 24px;
  height: 24px;
  margin: 2px 0 0;
  appearance: none;
  background: var(--plane);
  border: 1.5px solid var(--ink);
  cursor: pointer;
  flex: none;
}

.tl-consent-box:checked {
  background: var(--ink);
}

.tl-consent-box:checked::after {
  content: '';
  display: block;
  width: 11px;
  height: 6px;
  margin: 5px auto 0;
  border-left: 2px solid var(--plane);
  border-bottom: 2px solid var(--plane);
  transform: rotate(-45deg);
}

.tl-consent label {
  font-size: 0.9375rem;
  line-height: 1.55;
  color: var(--ink-2);
  cursor: pointer;
}

/* Second row of the consent grid, under the disclosure rather than under the
   24px checkbox column. */
.tl-consent .tl-field-error {
  grid-column: 2;
  margin: 12px 0 0;
}

/*
 * The consent checkbox is the one control that blocks every submission, and it
 * is 24px of control inside a block the height of a phone screen. "Check the
 * highlighted fields" has to highlight something findable, so the block takes
 * the same 1.5px + 4px --alert edge the wells take. Still not the accent, and
 * still not a certainty material: validation is not a claim about a policy.
 */
.tl-consent[data-invalid='true'] {
  border: 1.5px solid var(--alert);
  border-left: 4px solid var(--alert);
}

/* The same, for anything that marks the box invalid without going through
   setError. It sits in its own rule on purpose: a browser that does not know
   :has() throws out the whole selector list it appears in, and it would take
   the attribute rule above with it. */
.tl-consent:has(.tl-consent-box[aria-invalid='true']) {
  border: 1.5px solid var(--alert);
  border-left: 4px solid var(--alert);
}

.tl-consent-box[aria-invalid='true'] {
  border-color: var(--alert);
}

/*
 * Live state of the consent box, rendered beside the button it gates because
 * the box itself is a screen-height away by the time the thumb reaches the
 * submit. It reports the state of a control, so it takes neither the accent nor
 * any certainty material — the difference between the two states is the words.
 */
.tl-consent-state {
  margin: 0 0 10px;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 87%;
  font-size: 0.9375rem;
  line-height: 1.4;
  color: var(--ink-2);
}

.tl-consent-state[data-given='true'] {
  color: var(--ink);
}

/*
 * A called-out message, not a control. Filled and boxed at full field width
 * directly above the submit, and set in the reading face, it read as an empty
 * text field the visitor had failed to complete — a fourth thing to do on a
 * step that was already asking for three. The fill and the box go; what is left
 * is a hard left edge and the interface face, which is the same grammar
 * .tl-concession uses to lift one sentence out of a column.
 */
.tl-status {
  margin: 16px 0 0;
  padding: 2px 0 2px 16px;
  border-left: 3px solid var(--ink);
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-stretch: 87%;
  font-size: 1rem;
  line-height: 1.5;
}

/* The form's own live region carries nothing but failures — a blocked submit or
   a send that did not go — so it takes the validation token the field errors
   take. Every other .tl-status on the site is telling the visitor something,
   not telling them something went wrong. */
#tl-status {
  border-left-color: var(--alert);
}

.tl-status:empty {
  display: none;
}

/* ------------------------------------------------------------ how it works -- */

.tl-steps {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--rule);
}

.tl-step {
  display: grid;
  grid-template-columns: var(--stub) minmax(0, 1fr);
  gap: var(--gutter);
  padding-block: 32px;
  border-bottom: 1px solid var(--rule);
}

/* Start, not stretch. The stub is a grid child of a ~200px row, so it used to
   fill the row and the node, centred inside it, dropped 53px below the numeral
   it belongs to — four squares stranded in the left gutter beside the second
   line of each paragraph. */
.tl-step-stub {
  display: flex;
  align-items: baseline;
  align-self: start;
  gap: 14px;
}

/* An empty span's baseline is its bottom edge, so baseline alignment sits the
   node on the numeral's baseline rather than on its cap line. */
.tl-step-node {
  width: 14px;
  height: 14px;
  flex: none;
  background: var(--mark-g);
  transform: translateY(-4px);
}

/* "We'll tell you if IUL is the wrong fit" is a promise about character, not a
   contract term. It gets the non-guaranteed material — but hatched, not empty.
   An unfilled dotted rectangle is already a defined object on this page:
   .tl-fig-key--down uses exactly that object for "Down periods, nothing
   credited", so anyone who decoded the hero key read step four as "nothing
   happens here". Sixteen rather than fourteen so the pitch resolves. */
/*
 * The hatch needs an opaque base under it. The thread runs down the centre of
 * this node's box, and a hatch is transparent between its lines — so the stroke
 * painted through the gaps and the one node whose material is the argument read
 * as a hatch with a line behind it. The box-shadow beside this rule cannot do
 * the job: it is clipped to outside the border box by spec.
 */
.tl-step-node--n {
  width: 16px;
  height: 16px;
  background:
    repeating-linear-gradient(
      45deg,
      transparent 0 2.5px,
      var(--mark-n) 2.5px 4px
    ),
    var(--ground);
  border: 1.5px dotted var(--mark-n);
}

.tl-stratum--deep .tl-step-node--n {
  background:
    repeating-linear-gradient(
      45deg,
      transparent 0 2.5px,
      var(--mark-n) 2.5px 4px
    ),
    var(--ground-deep);
}

.tl-step-body h3 {
  margin: 0 0 8px;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 112%;
  font-size: 1.375rem;
  line-height: 1.2;
  letter-spacing: -0.008em;
  text-wrap: balance;
}

.tl-step-body p {
  margin: 0;
  max-width: 58ch;
  color: var(--ink-2);
}

/* ------------------------------------------------------------------ faq -- */

.tl-faq {
  border-top: 1px solid var(--rule);
}

/* Every rule here is neutral. The row dividers used to restate the row's
   certainty class in rule weight — but the two BOTH rows both took the solid
   guaranteed rule for want of a split treatment, the rules landed on the same
   pixels as the previous row's border, and the footer key has no entry for a
   horizontal divider in any material. A divider is structure, not content; the
   chip beside the question is what classifies the row. */
.tl-faq-row {
  border-bottom: 1px solid var(--rule);
}

.tl-faq-q {
  display: grid;
  grid-template-columns: var(--stub) minmax(0, 1fr) 28px;
  gap: var(--gutter);
  align-items: start;
  width: 100%;
  padding: 22px 0;
  background: none;
  border: 0;
  text-align: left;
  cursor: pointer;
  color: inherit;
}

.tl-faq-h {
  margin: 0;
  font: inherit;
}

.tl-faq-q .tl-faq-text {
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 100%;
  font-size: 1.1875rem;
  line-height: 1.35;
  letter-spacing: -0.005em;
}

.tl-faq-marker {
  position: relative;
  width: 16px;
  height: 16px;
  margin-top: 5px;
  justify-self: end;
  flex: none;
}

.tl-faq-marker::before,
.tl-faq-marker::after {
  content: '';
  position: absolute;
  background: var(--ink);
  transition: transform var(--dur) var(--ease-inout);
}

.tl-faq-marker::before {
  inset: 7px 0 7px 0;
  height: 2px;
}

.tl-faq-marker::after {
  inset: 0 7px 0 7px;
  width: 2px;
}

.tl-faq-q[aria-expanded='true'] .tl-faq-marker::after {
  transform: rotate(90deg);
}

/*
 * Collapsing is progressive enhancement like everything else here, and the only
 * thing that can reopen a collapsed answer is script. Ungated, these rules clip
 * all seven answers to nothing for anyone whose JavaScript never arrives — or
 * whose page.js threw before it reached initFaq().
 */
.tl-js .tl-faq-a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur) var(--ease-out);
}

.tl-js .tl-faq-row.is-open .tl-faq-a {
  grid-template-rows: 1fr;
}

.tl-js .tl-faq-a > div {
  overflow: hidden;
  /* Clipping alone keeps the answer in the accessibility tree while
     aria-expanded says false. visibility takes it out, and delaying it to the
     end of the transition keeps the open/close animation intact. */
  visibility: hidden;
  /*
   * grid-template-rows is a LAYOUT property: the one animation on this page that
   * cannot run on the compositor. It stays, because it is the only technique that
   * animates to CONTENT height without JS measuring a pixel value and writing it
   * back — and a measured height is wrong the moment the text reflows, which on a
   * page with two locales and a variable font it will.
   *
   * `contain: layout paint` is what bounds the cost: the panel's internal layout
   * can no longer invalidate anything outside it, so the per-frame work is one FAQ
   * answer rather than the document below it. Safe here — nothing inside
   * .tl-faq-inner is absolutely positioned or floated, and `contain` does not
   * affect intrinsic sizing (that is `contain: size`, which would break the 1fr).
   */
  contain: layout paint;
  transition: visibility 0s linear var(--dur);
}

.tl-js .tl-faq-row.is-open .tl-faq-a > div {
  visibility: visible;
  transition: visibility 0s linear 0s;
}

/* With no script the answers are simply present, so the +/− marker would be
   describing a state that does not exist and the row must not invite a tap
   that cannot do anything. */
html:not(.tl-js) .tl-faq-marker {
  display: none;
}

html:not(.tl-js) .tl-faq-q {
  pointer-events: none;
  cursor: default;
}

/* 58ch, not 68: Literata's figures are much wider than its average lowercase, so
   68ch was setting ~80 characters to the line — the exact defect already fixed on
   .tl-prose and .tl-legal, in a selector that was missed. The freed ~100px goes
   to .tl-marginalia in column 3, which was the narrowest measure on the page. */
.tl-faq-inner {
  display: grid;
  grid-template-columns: var(--stub) minmax(0, 58ch) minmax(0, 1fr);
  gap: var(--gutter);
  padding-bottom: 28px;
}

.tl-faq-inner p {
  grid-column: 2;
  margin: 0;
  color: var(--ink-2);
}

/* A qualifier hanging beside the paragraph it qualifies — a document-native
   device no card layout can borrow. */
.tl-marginalia {
  grid-column: 3;
  margin: 0;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 500;
  font-stretch: 87%;
  font-size: 0.8125rem;
  line-height: 1.45;
  letter-spacing: 0.02em;
  color: var(--ink-2);
  border-top: 1.25px dotted var(--mark-n);
  padding-top: 8px;
}

/* -------------------------------------------------------------- closing -- */

.tl-closing {
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: 24px;
}

/*
 * The one inverted stratum. Its background reads from --terminal-bg, which is
 * NOT redefined here — the descendants' tokens are, so every mark, rule and
 * button inside re-renders correctly against the dark ground.
 */
.tl-stratum--invert {
  background: var(--terminal-bg);
  border-bottom-color: var(--terminal-bg);
  --ground: var(--terminal-bg);
  --ground-deep: var(--terminal-bg);
  --plane: var(--terminal-plane);
  --ink: var(--terminal-ink);
  --ink-2: var(--terminal-ink-2);
  --rule: var(--terminal-rule);
  --mark-g: var(--terminal-ink);
  --mark-n: var(--terminal-mark-n);
  /* --signal stays the FILL: .tl-btn--primary reads it as a background and
     pairs it with --signal-on. Text that wants the accent takes the rule
     below instead. */
  --signal: var(--terminal-signal);
  --signal-deep: var(--terminal-signal-deep);
  --signal-on: var(--terminal-signal-on);
  --focus-a: var(--terminal-ink);
  --focus-b: var(--terminal-bg);
  color: var(--ink);
}

/* The accent as ink, on the one band where the fill value is not readable. */
.tl-stratum--invert .tl-tel {
  color: var(--terminal-signal-text);
  text-decoration-color: var(--terminal-signal-text);
}

.tl-stratum--invert .tl-tel:hover {
  color: var(--terminal-signal-text-hi);
  text-decoration-color: var(--terminal-signal-text-hi);
}

/* --------------------------------------------------------------- footer -- */

.tl-footer-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 40px var(--gutter);
  padding-bottom: 48px;
  border-bottom: 1px solid var(--rule);
}

.tl-footer-block h2 {
  margin: 0 0 12px;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 87%;
  font-size: 0.78125rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.tl-footer-block address {
  font-style: normal;
  font-size: 0.9375rem;
  line-height: 1.7;
}

.tl-footer-links {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.9375rem;
  line-height: 1.9;
}

/* The key is printed exactly as a carrier illustration prints its legend. */
.tl-key {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 24px var(--gutter);
  margin: 0;
  padding: 40px 0;
  border-bottom: 1px solid var(--rule);
}

.tl-key div {
  display: flex;
  gap: 14px;
  align-items: start;
}

.tl-key dt {
  flex: none;
  width: 44px;
  height: 22px;
  margin-top: 2px;
}

.tl-key dd {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--ink-2);
}

.tl-key-g {
  background: var(--mark-g);
}

/* All three non-guaranteed materials in the one swatch that names them. The
   dashed edge is the cap, which is the most consequential non-guaranteed
   element on the page and had no entry here at all — leaving it visually
   indistinguishable from the file's many decorative rules. */
.tl-key-n {
  background: repeating-linear-gradient(
    45deg,
    transparent 0 2.5px,
    var(--mark-n) 2.5px 4px
  );
  border: 1.25px dotted var(--mark-n);
  border-top: 1.5px dashed var(--mark-n);
}

/* Stacked, because the sentence beside it says the non-guaranteed part sits
   ABOVE the guaranteed minimum and the drawing stacks. The lattice's own split
   mark stays horizontal — its heading says "side by side". */
.tl-key-split {
  background: linear-gradient(to top, var(--mark-g) 0 50%, transparent 50%),
    repeating-linear-gradient(45deg, transparent 0 2.5px, var(--mark-n) 2.5px 4px);
  border-top: 1.25px dotted var(--mark-n);
}

.tl-key-btn {
  border: 1.5px solid var(--ink);
}

.tl-disclosures {
  display: grid;
  gap: var(--s4);
  padding: var(--s7) 0 0;
}

/*
 * Seven paragraphs in one 62ch column ran about 1,100px of dense legal as the
 * last thing on the page — the visual weight of an appendix, for text that is
 * required to be here. Two columns halves the height and NOTHING is cut: the
 * landing page is the ad, and the ad carries its own disclosure.
 * disclosures.html is the belt, not the braces.
 *
 * NO content-visibility HERE, ever. It was added as a rendering-cost win and it
 * is not one worth having: `content-visibility: auto` keeps skipped subtrees out
 * of the ACCESSIBILITY TREE until they are near the viewport, so on a fresh load
 * at >=1024 all seven statutory paragraphs plus the copyright line were absent
 * from a screen reader's browse buffer — measured as a 934-node tree with them
 * missing against 990 with the property removed. A disclosure a screen reader
 * cannot reach is not a disclosure. The block is ~610px at the very bottom of
 * the document; there was nothing to save.
 */
@media (min-width: 1024px) {
  .tl-disclosures {
    display: block;
    columns: 2;
    column-gap: var(--s7);
  }

  .tl-disclosures > .tl-legal {
    /* A required paragraph must not be split across the column break. */
    break-inside: avoid;
    margin-bottom: var(--s4);
    max-width: none;
  }

  /* The heading and the copyright line span, so the block reads as one
     disclosure with two columns in it rather than as two lists. */
  .tl-disclosures > .tl-label,
  .tl-disclosures > .tl-legal.tl-flow-t2 {
    column-span: all;
  }
}

/* ------------------------------------------------------- sticky call bar -- */

/*
 * One slab and one line, not two slabs. Side by side at 375px the two buttons
 * were 169px each and BOTH labels wrapped to two lines, which is where a bar
 * that is meant to be one obvious action stops being one. The slab now carries
 * the dialable number, because the header is not sticky and nothing else on
 * screen has a number on it below the fold.
 */
.tl-callbar {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 40;
  display: none;
  flex-wrap: wrap;
  gap: 8px;
  padding: 8px 16px calc(8px + env(safe-area-inset-bottom));
  background: var(--plane);
  border-top: 1px solid var(--rule-control);
  /* Was a hardcoded light-theme ink on the top edge with no dark override, so in
     dark it was a near-black hairline on #192231 — invisible. The token is
     already correct for a bottom-docked bar in both themes. */
  box-shadow: var(--cast);
  opacity: 0;
  /*
   * It slides up from the edge it is docked to rather than materialising over the
   * content. A transform on a position:fixed element is safe — only a transform
   * on an ANCESTOR breaks fixed positioning — and 100% carries the safe-area
   * padding off screen with it.
   */
  transform: translate3d(0, 100%, 0);
  /* An opacity-0 element still hit-tests and still takes focus, which would put
     a live tel: link under the bottom 68px of every phone fold. */
  pointer-events: none;
  visibility: hidden;
  transition: opacity var(--dur-fast) linear,
    transform var(--dur) var(--ease-out), visibility 0s linear var(--dur);
}

.tl-callbar.is-shown {
  opacity: 1;
  transform: none;
  pointer-events: auto;
  visibility: visible;
  transition: opacity var(--dur-fast) linear,
    transform var(--dur) var(--ease-out), visibility 0s linear 0s;
}

/* During staffed hours the phone slab is accent-filled, so its live tab has to
   read against the accent rather than disappear into it. */
.tl-callbar .tl-btn--primary .tl-hours-tab {
  background: var(--signal-on);
}

.tl-callbar .tl-btn {
  flex: 1;
  min-height: 52px;
  padding-inline: 12px;
  font-size: 1rem;
}

/*
 * The action the bar is not leading with, one tap away. A link rather than a
 * second slab: two slabs read as a choice, and this is a fallback.
 *
 * Its full-row basis is what turns the bar into a slab-over-line: only one of
 * the two slabs is ever on show, so `flex: 1` gives that one the whole first
 * row and this wraps beneath it. The Spanish bar has no alt line yet and keeps
 * its two-across row untouched.
 */
.tl-callbar-alt {
  flex: 1 0 100%;
  margin: 0;
  text-align: center;
  font-size: 0.9375rem;
  line-height: 1.35;
}

/* --------------------------------------------------------------- focus -- */

/*
 * Offset 3 and spread 5, not 2 and 3: the 2px outline occupied 2-4px from the
 * edge while the halo spread only to 3px, so the ring overlapped its own backing
 * for a third of its width and read as doubled rather than as one ring on one
 * ground. `border-radius: 0` was also here — a LAYOUT property on the element,
 * not on the ring, which squared .tl-btn's 2px corners at the moment of focus.
 */
:focus-visible {
  outline: 2px solid var(--focus-a);
  outline-offset: 3px;
  box-shadow: 0 0 0 5px var(--focus-b);
}

/* The universal box-shadow above replaces the field's recess, so the field's own
   inset is restated with it. A well that flattens while you are typing in it has
   stopped saying "write here" at the moment it most needs to. */
.tl-field-well:focus-visible {
  box-shadow: var(--cast-inset), 0 0 0 5px var(--focus-b);
}

/* ----------------------------------------------------------- responsive -- */

@media (max-width: 1023px) {
  :root {
    --stub: 148px;
  }

  /* The full-bleed film still leads; the panel expands across the shell. */
  .tl-hero-card {
    max-width: none;
    padding: 22px 24px 24px;
  }

  .tl-hero-inner {
    padding-block: 64px 32px;
  }

  /* No font-stretch narrowing here. It pulled the headline to wdth 112 while
     every section head below it stayed at 118, so on the one band where the h1
     was already the smaller object it was the narrower one too. */
  .tl-h1 {
    line-height: 1.06;
  }

  .tl-form-wrap {
    grid-template-columns: minmax(0, 1fr);
    gap: 48px;
  }

  .tl-lattice {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .tl-proof {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }

  .tl-footer-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .tl-faq-inner {
    grid-template-columns: var(--stub) minmax(0, 1fr);
  }

  .tl-marginalia {
    grid-column: 2;
  }
}

@media (max-width: 767px) {
  :root {
    --margin: 20px;
    --stub: 0px;
  }

  /* Both narrow together on a 335px column, and neither carries a size here:
     the two clamps bottom out at 34px and 24px, which is the widest rank the
     pair ever has. Equal width, so the hierarchy is carried by size alone —
     the width axis cannot rank two things when the smaller one is the wider. */
  .tl-h1 {
    font-stretch: 100%;
  }

  .tl-section-head {
    font-stretch: 100%;
  }

  .tl-band {
    padding-block: 56px;
  }

  /*
   * Fold budget on a 375x667 phone: the primary CTA has to be fully visible
   * without scrolling. Everything above it is measured against that.
   */
  .tl-header {
    min-height: 0;
    padding-block: 10px;
    gap: 12px;
  }

  /* The staffed-hours string repeats in the hero caption below. Keep the
     compact language switch visible while removing only the hours variants. */
  .tl-header [data-tl-when] {
    display: none !important;
  }

  .tl-header-right {
    gap: 10px;
  }

  .tl-wordmark {
    font-size: 1.0625rem;
  }

  .tl-wordmark span {
    display: none;
  }

  /*
   * On the narrowest phones the wordmark and the number stop fitting on one
   * row, and the wrap costs ~40px of fold. Shrinking both keeps the header a
   * single line down to 320px, which keeps the primary CTA above the fold.
   */
  @media (max-width: 360px) {
    .tl-wordmark {
      font-size: 0.9375rem;
    }

    .tl-header .tl-tel {
      font-size: 0.9375rem;
    }

    .tl-header {
      gap: 8px;
    }
  }

  /* On phones the film leads, followed by a panel that overlaps its lower edge. */
  .tl-hero-film {
    grid-template-areas: 'media' 'panel';
    grid-template-rows: auto auto;
    min-height: 0;
  }

  .tl-hero-media {
    grid-area: media;
    height: 24vh;
    min-height: 150px;
    max-height: 200px;
  }

  .tl-hero-inner {
    grid-area: panel;
    padding-block: 0;
    align-items: stretch;
  }

  .tl-hero-card {
    max-width: none;
    padding: 18px 0 22px;
    gap: 13px;
    margin-top: -24px;
    border-inline: 0;
    width: calc(100% + var(--margin) * 2);
    margin-inline: calc(var(--margin) * -1);
    padding-inline: var(--margin);
  }

  /* Full clamp is fine here: stacked, the card is not standing on the film and
     nothing below it is at risk of being covered. The ceiling is held at 2.125rem
     rather than following the desktop clamp up, because at 375x667 the card has to
     clear the fold with the subhead, the seed row and the duration line on it. */
  .tl-hero-card .tl-h1 {
    font-size: clamp(1.75rem, 7.4vw, 2.125rem);
  }

  /* Tighter on a phone: the subhead is the one line of prose on the fold and it
     is competing with the seed row for the same 667px. */
  .tl-hero-sub {
    font-size: 1rem;
    line-height: 1.4;
  }

  .tl-hero-toggle {
    top: 10px;
    right: 10px;
  }

  .tl-lead {
    font-size: 1.0625rem;
    line-height: 1.5;
  }

  .tl-lattice {
    grid-template-columns: minmax(0, 1fr);
  }

  .tl-lattice-cell {
    padding: 26px 0 30px;
    border-right: 0;
  }

  .tl-lattice {
    border-left: 0;
  }

  .tl-seed-row .tl-fit-option {
    padding: 12px 6px;
    text-align: center;
    border-left-width: 1.5px;
    border-left-color: var(--rule-control);
  }

  .tl-seed-row .tl-fit-option b {
    font-size: 0.9375rem;
  }

  /* Three across, the selected edge is the BOTTOM one — a left edge on a 33%-wide
     cell reads as a divider between cells rather than as a mark on one. Same beat
     as the form's cards, drawn left to right instead of top to bottom. */
  .tl-seed-row .tl-fit-option::before {
    inset: auto -1.5px -4px -1.5px;
    width: auto;
    height: 4px;
    transform: scaleX(0);
    transform-origin: left;
  }

  .tl-seed-row .tl-fit-option.is-selected,
  .tl-seed-row .tl-fit-radio:checked + .tl-fit-option {
    border-color: var(--ink);
    border-left-color: var(--ink);
  }

  .tl-seed-row .tl-fit-option.is-selected::before,
  .tl-seed-row .tl-fit-radio:checked + .tl-fit-option::before {
    transform: scaleX(1);
  }

  /* Two across, still exact. Six slots wrapping is the failure being fixed. */
  .tl-slotrow {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* The caption swaps between three staffed-hours variants of different lengths,
     and the swap lands while the trust list below it is being read. Reserving
     the tallest keeps that list still under the visitor's thumb. Only the gated
     ones swap — the class is also used for the fixed "call us" lines that close
     three content sections, and those would just carry dead space. */
  .tl-hours-caption[data-tl-when] {
    min-height: 4.2em;
  }

  /* Stretch, not the row's default flex-start: without it the primary sizes to
     its own label and the stack to its 34ch caption, so the two CTAs end at
     different x at the very top of the fold. */
  .tl-btn-row {
    flex-direction: column;
    align-items: stretch;
  }

  .tl-btn-row .tl-btn {
    width: 100%;
  }

  .tl-split,
  .tl-step,
  .tl-faq-q {
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
  }

  /*
   * One track — but the answer paragraphs kept `grid-column: 2` from the desktop
   * three-track layout, which creates an implicit second column and indents
   * every answer to the right of the question that owns it: the only body text
   * on the page off the left margin. row-gap only, so the implicit column can
   * never buy itself a 24px gutter again.
   */
  .tl-faq-inner {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 12px;
  }

  .tl-faq-inner p,
  .tl-faq-inner .tl-marginalia {
    grid-column: 1;
  }

  .tl-faq-q {
    grid-template-columns: minmax(0, 1fr) 28px;
  }

  .tl-faq-q .tl-chip {
    grid-column: 1 / -1;
  }

  .tl-footer-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }

  .tl-mech-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
  }

  .tl-mech-fig {
    max-width: 120px;
  }

  /* The bar is mobile-only and appears only after the hero has been read. */
  .tl-callbar {
    display: flex;
  }

  /* Border, padding, slab, gap and the alternate line: 1 + 8 + 52 + 8 + 19 + 8.
     The inset is carried too, because the bar adds it to its own padding and
     the page underneath has to clear the whole thing. */
  body.has-callbar {
    padding-bottom: calc(100px + env(safe-area-inset-bottom));
  }

  /* Keep anything scrolled-to — including a keyboard-focused field — clear of
     the fixed bar (WCAG 2.2, focus not obscured). */
  html {
    scroll-padding-bottom: calc(112px + env(safe-area-inset-bottom));
  }

  .tl-fig {
    padding: 16px;
  }

  .tl-concession {
    padding-left: 16px;
  }
}

/*
 * Where the stub labels stop being readable, NOT where the hero stacks — the
 * two used to be the same number by coincidence and the figure lost its words
 * 300px early. Below 768 the shell margin is 20 and the panel padding 16, so
 * the SVG is (viewport - 74) wide and a sub-label renders at 15 x that / 540.
 * At 480 that is a 406px drawing and an 11.3px sub-label; under it the caveats
 * drop below 11px, which is the size this figure was rebuilt to get away from.
 * Every phone in the set is comfortably inside this block; a small laptop
 * window is not, and now keeps the labelled drawing.
 */
@media (max-width: 479px) {
  .tl-svg-label,
  .tl-svg-bracket {
    display: none;
  }

  /*
   * With the stub labels gone their gutter is dead space, so the drawing is
   * scaled up and pulled left to crop it out. The gutter ends at x=144 of 540,
   * so the drawing is 540/396 = 136% wider and shifted left by that share of the
   * viewBox TIMES the scale: 144/540 x 136% = 36.4%.
   */
  .tl-fig {
    overflow: hidden;
  }

  .tl-fig svg {
    width: 136%;
    max-width: none; /* beats the global svg { max-width: 100% } */
    margin-left: -36.4%;
  }

  /* The Spanish figure is drawn on a wider viewBox, so the same gutter is a
     smaller share of it and it needs its own crop: 580/436 = 133% wider,
     shifted 144/580 x 133% = 33%. */
  [lang='es'] .tl-fig svg {
    width: 133%;
    max-width: none;
    margin-left: -33%;
  }
}

@media (min-width: 768px) {
  .tl-callbar {
    display: none !important;
  }

  /* Two columns, because the key is the only gloss PARTICIPATION has and it was
     hidden at exactly the widths where the bracket appears with no explanation.
     Paired up, it also fills the 270-300px of empty panel that a one-column key
     left below the drawing at every desktop width. */
  .tl-fig-keys {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 24px;
  }
}

@media (min-width: 1024px) {
  /*
   * Three to a row, so the headings reserve the same height or the row loses its
   * baseline. TWO lines, not three: the reserve was sized for the longest of six
   * headings, and with the grid down to three — and cell one's heading shortened
   * to fit two — the third line was 26px of dead space under five of six
   * headings, twice down the grid.
   */
  .tl-lattice-cell h3 {
    min-height: 2.4em;
  }

  /*
   * The form's last step runs to about y2000 while the aside stops near y860,
   * so the consent block, the submit and the reassurance caption are read
   * beside an empty column. Pinned, the agent credential and the "call
   * instead" number stay on screen for the whole of that scroll — which is
   * where someone who balks at the checkbox needs somewhere else to go.
   */
  .tl-form-wrap > .tl-stack {
    position: sticky;
    top: 24px;
    align-self: start;
  }
}

/* ------------------------------------------------------- reduced motion -- */
/*
 * Durations were already killed here. DELAYS were not — and this page now
 * choreographs, so a ladder with a 300ms delay and a 0ms duration is still
 * 300ms of a blank card. Both axes, both properties, or the choreography
 * survives the preference that exists to remove it.
 *
 * 0.01ms rather than 0ms: transitionend/animationend still fire at 0.01ms in
 * every engine, and at 0ms some skip them. Nothing in this tree waits on one
 * today; the next thing that does must not hang on a preference.
 */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }

  /*
   * Every held pre-state on the page, released unconditionally. This is belt to
   * the braces above: a 0.01ms animation still has to land on the right value,
   * and nothing here may depend on page.js having run.
   *
   * The diagram renders complete, including every non-guaranteed element.
   */
  .tl-ng-fade,
  .tl-fig .tl-ng-fade {
    opacity: 1 !important;
  }

  /* Every shape the primitive can hold, including the two modifiers — a modifier
     sets its own transform and would otherwise survive this block. */
  [data-reveal=''],
  [data-reveal='stagger'] > *,
  [data-reveal-rise='sm'],
  [data-reveal-rise='sm'] > *,
  [data-reveal-move='none'],
  [data-reveal-move='none'] > * {
    opacity: 1 !important;
    transform: none !important;
  }

  .tl-js .tl-draw path {
    stroke-dashoffset: 0 !important;
  }

  .tl-callbar.is-shown {
    transform: none !important;
  }

  /*
   * NOT `transform: none`. None is the identity transform — scaleY(1) — which
   * paints the 4px selected edge on every unchecked card on the page, so under
   * this preference all 27 options read as chosen. The unselected state is the
   * zero scale; only the checked rules below may put it back.
   */
  .tl-fit-option::before {
    transform: scaleY(0);
  }

  .tl-fit-option.is-selected::before,
  .tl-fit-radio:checked + .tl-fit-option::before {
    transform: scaleY(1) !important;
  }

  .tl-seed-row .tl-fit-option::before {
    transform: scaleX(0);
  }

  .tl-seed-row .tl-fit-option.is-selected::before,
  .tl-seed-row .tl-fit-radio:checked + .tl-fit-option::before {
    transform: scaleX(1) !important;
  }

  .tl-fit-segment::after {
    transform: scaleX(0);
  }

  .tl-fit-segment.is-done::after,
  .tl-fit-segment.is-current::after {
    transform: scaleX(1) !important;
  }
}

/* -------------------------------------------------------------- utility -- */

.tl-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* For a clause that changes meaning if it is read across a line break. Used on
   the fold's obligation line, where "nothing / is purchased here" spends one eye
   movement asserting the opposite. */
.tl-nowrap {
  white-space: nowrap;
}

.tl-stack {
  display: flex;
  flex-direction: column;
  gap: 20px;
  align-items: start;
}

.tl-stack--wide {
  gap: 32px;
}

.tl-head-group {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: var(--s7);
  align-items: start;
}

/* The form band's head sits closer to the form than a section head does to a
   grid: the lead is the last thing read before question one. */
.tl-head-group--tight {
  margin-bottom: var(--s5);
}

/*
 * The second head inside a merged band. It has to read as subordinate to the
 * band's own h2 — the two are 900px apart, so if it matched, the band would read
 * as two sections that had lost their strata rather than one with two parts.
 */
.tl-head-group--sub {
  margin-top: var(--s9);
  margin-bottom: var(--s7);
  padding-top: var(--s7);
  border-top: 1px solid var(--rule);
  width: 100%;
}

.tl-subsection-head {
  margin: 0;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 112%;
  /* Deliberately below .tl-section-head's clamp at every width, and above
     .tl-lattice-cell h3's 1.125rem, so the band reads h2 > h3-of-band > h3. */
  font-size: clamp(1.375rem, 2vw, 1.75rem);
  line-height: 1.15;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

/* -------------------------------------------------------- flow spacing -- */
/*
 * Named steps off the --s scale, replacing fourteen inline `style="margin-…"`
 * attributes in index.html. The digit IS the scale step, so the value is legible
 * from the class name and cannot drift from the scale. Snapped on the way in:
 * 28 -> 24 (t5), 40 -> 48 (t7), 14 -> 16 (b4/fig).
 */
.tl-flow-t2 { margin-top: var(--s2); }
.tl-flow-t3 { margin-top: var(--s3); }
.tl-flow-t5 { margin-top: var(--s5); }
.tl-flow-t7 { margin-top: var(--s7); }
.tl-flow-b3 { margin: 0 0 var(--s3); }
.tl-flow-b4 { margin: 0 0 var(--s4); }
.tl-flow-b5 { margin: 0 0 var(--s5); }

.tl-label--tight { margin-bottom: var(--s1); }
.tl-fit-help--after { margin: var(--s1) 0 0; }
.tl-fig-drawing { margin-top: var(--s4); }

.tl-btn--block { width: 100%; }

.tl-rule {
  width: 100%;
  border-top: 1px solid var(--rule);
}

/* ------------------------------------------------------ document pages -- */
/*
 * Privacy, terms, disclosures and the thank-you page. Same materials, plainer
 * composition: a single measured column on the page ground. These pages carry
 * the content a regulator or a careful reader goes looking for, so they are set
 * to be read rather than to be skimmed past.
 */

.tl-doc {
  max-width: 74ch;
  padding-block: 72px 96px;
}

.tl-doc h1 {
  margin: 0 0 8px;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 118%;
  font-size: clamp(1.9rem, 3.4vw, 2.75rem);
  line-height: 1.08;
  letter-spacing: -0.014em;
  text-wrap: balance;
}

.tl-doc h2 {
  margin: 48px 0 12px;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 112%;
  font-size: 1.375rem;
  line-height: 1.25;
  letter-spacing: -0.008em;
  padding-top: 20px;
  border-top: 1px solid var(--rule);
}

.tl-doc h3 {
  margin: 28px 0 8px;
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 100%;
  font-size: 1.0625rem;
}

.tl-doc p,
.tl-doc li {
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ink-2);
}

.tl-doc p {
  margin: 0 0 16px;
}

.tl-doc ul,
.tl-doc ol {
  margin: 0 0 16px;
  padding-left: 22px;
}

.tl-doc li {
  margin-bottom: 8px;
}

.tl-doc strong {
  color: var(--ink);
}

.tl-doc a {
  color: var(--ink);
  text-underline-offset: 3px;
}

/* A button inside a document column is still a button. The rule above is one
   specificity step above .tl-btn--primary, so it was repainting the accent
   slab's label to --ink: near-black on navy, 1.69:1, on the only CTA the
   thank-you pages carry. */
.tl-doc a.tl-btn {
  color: var(--ink);
  text-decoration: none;
}

.tl-doc a.tl-btn--primary {
  color: var(--signal-on);
}

.tl-updated {
  margin: 0 0 40px;
}

/* The thank-you page's one job is telling someone exactly what happens next. */
.tl-next {
  margin: 32px 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--rule);
}

.tl-next li {
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr);
  gap: 16px;
  align-items: start;
  padding: 20px 0;
  margin: 0;
  border-bottom: 1px solid var(--rule);
  color: var(--ink);
}

.tl-next li::before {
  content: '';
  width: 14px;
  height: 14px;
  margin-top: 6px;
  background: var(--mark-g);
}

/* The one step nobody can promise: it depends on when you sent this. */
.tl-next li.is-conditional::before {
  background: none;
  border: 1.5px dotted var(--mark-n);
}

/* ------------------------------------------------------------- imagery -- */
/*
 * Photography lives in the same material world as everything else: hard 1px
 * edge, zero radius, no blurred shadow, no vignette, no rounded corner. The
 * grade pulls a saturated stock frame toward the cream-and-navy palette so it
 * reads as part of the page rather than pasted onto it — restrained on purpose,
 * because a heavy duotone on a family photograph looks like it is trying to
 * hide that it is a stock photograph.
 *
 * Photographs carry NO certainty material. They are not marks, they make no
 * claim about a policy, and the filled/dotted vocabulary never touches them.
 */

.tl-figure {
  position: relative;
  margin: 0;
  border: 1px solid var(--rule);
  background: var(--ground-deep);
  overflow: hidden;
}

.tl-figure img {
  display: block;
  width: 100%;
  height: auto;
  filter: var(--img-filter);
}

/*
 * The form rail's photograph. At 4:5 it is a ~470px block injected between
 * question one and the credential paragraph on a phone — the loudest thing in
 * the column, and a licensed stock frame. Cropped it is ~235px: still present,
 * no longer the argument. 25% down the frame keeps the desk and the hands and
 * loses most of the ceiling.
 */
.tl-agent-figure {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  margin: 0;
}

.tl-figure--agent img {
  aspect-ratio: 16 / 10;
  object-fit: cover;
  object-position: 50% 25%;
}

/* A whisper of the page's own ground, laid over the frame. */
.tl-figure::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--ground);
  opacity: var(--img-veil);
  pointer-events: none;
}

/* Two frames a generation apart: the same subject at both ends of the horizon
   a permanent policy is funded across. */
.tl-generations {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--gutter);
  margin: 0;
}

.tl-generations figure {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin: 0;
}

.tl-generations figcaption {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-top: 12px;
  border-top: 1px solid var(--rule);
}

.tl-figcaption-lead {
  font-family: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-stretch: 100%;
  font-size: 1.0625rem;
  line-height: 1.3;
  letter-spacing: -0.005em;
  color: var(--ink);
}

.tl-figcaption-note {
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--ink-2);
}

@media (max-width: 767px) {
  .tl-generations {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }
}

/* --------------------------------------------------------------- film -- */
/*
 * One ambient clip, muted, no audio track at all. It sits in the second half of
 * the generations diptych and does the same job the photograph does on the
 * left — it is not a hero, not a background, and never covers text.
 *
 * Three rules it has to obey:
 *   1. It never auto-starts under prefers-reduced-motion.
 *   2. It carries a real pause control, because auto-starting motion lasting
 *      more than five seconds needs one (WCAG 2.2.2).
 *   3. It costs nothing until it is scrolled to: preload="none", and playback
 *      starts and stops with an IntersectionObserver so it is not decoding
 *      frames off-screen.
 */

.tl-video {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: var(--ground-deep);
}

.tl-video video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: var(--img-filter);
}

/* The control sits over the frame, so it gets a solid chip of the page's own
   lifted plane rather than relying on whatever pixel is behind it. */
.tl-video-toggle {
  position: absolute;
  right: 12px;
  bottom: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: var(--plane);
  border: 1px solid var(--rule-control);
  border-radius: 0;
  cursor: pointer;
  transition: border-color 90ms linear;
}

.tl-video-toggle:hover {
  border-color: var(--ink);
}

.tl-video-glyph {
  display: block;
  width: 12px;
  height: 14px;
}

/* Playing -> offer pause. Paused -> offer play. */
.tl-video-toggle[data-playing='true'] .tl-video-glyph {
  background: linear-gradient(
    to right,
    var(--ink) 0 35%,
    transparent 35% 65%,
    var(--ink) 65% 100%
  );
}

.tl-video-toggle[data-playing='false'] .tl-video-glyph {
  background: var(--ink);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}

/* With no scripting the <video> and the fallback <img> both render, stacked
   inside a box sized for one — and the UA hands the visitor native controls
   that would start exactly the download preload="none" exists to prevent. The
   poster is the whole story, so the element that would fetch the clip goes. */
html:not(.tl-js) .tl-video video {
  display: none;
}

/* With no scripting the clip never loads; the poster is the whole story. */
.tl-video-fallback {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: var(--img-filter);
}

.tl-js .tl-video-fallback {
  display: none;
}
