/* ── Bridge tokens ──────────────────────────────────────────────────────────
   This file arrived from DESIGN carrying a design system of its own: four
   :root blocks (plus more inside @media), two [data-theme="dark"] blocks, and
   145 tokens in all, of which the CSS only used 53.

   Of those 53 the repo already defines 39 — and TWENTY at a different value:
   --type-h1 56 vs 40, --leading-base 28 vs 20, --radius-sm 4 vs 6, --font-mono
   JetBrains vs Geist, among others. Since both sides used :root, whichever
   loaded last would have won, and those twenty would have changed on every
   page carrying both files, careers included.

   Luis's call on 2026-08-26: the repo's tokens govern. Every :root and
   [data-theme="dark"] block was removed, along with the @media blocks that
   held nothing else, and the 92 tokens nobody used.

   What remains are the 14 the CSS does use and the repo does not define,
   scoped to .prod rather than :root, so new names do not enter the system
   through the back door. If they are ever adopted officially, their place is
   assets/css/tokens/.

   The global reset (*, html, body, a) went too: those rules belong to the
   site, not to one page. And .btn ended up scoped to .prod because it
   collided with the .btn in careers.css.
   ------------------------------------------------------------------------- */
.prod{
  /* DESIGN calls it --font-ui; it is the same stack with Inter at the front. */
  --font-ui: var(--font-sans);

  /* A numbered shadow from DESIGN; the repo uses semantic names.
     Same value as the --shadow-2 in careers-roles.css. */

  /* Type scale steps the repo does not carry.
     h6 matches the one in careers-roles.css; h1pp is this page's own. */
}

/* Eight more tokens DESIGN brought were removed — --c-300, --c-400, --ash,
   --ash-2, --carbon-2 through -4 and --shadow-3 — because the only things
   referencing them were the [data-theme="dark"] blocks, which are gone. If
   dark mode ever comes back, they have to come back with it. */

/* ==========================================================================
   Cardiff — business line of credit
   Extracted from the packed artifact by tools/unpack-artifact.js.

   Two blocks, in source order:the design-system token layer, then the
   page's own rules. Kept together because that is how the sibling pages in
   this folder ship — see business-loans.css, which copies the tokens too.
   The duplication is known; a shared token file is the fix when someone
   decides to make one.
   ========================================================================== */

/* Cardiff — webfonts

   THERE IS NO @font-face HERE, on purpose.

   There were two, declaring Inter and Geist Mono against 'assets/fonts/*.woff2'
   with a RELATIVE path. This file is served from /assets/css/, so they resolved
   to /assets/css/assets/fonts/ — two 404s on every line-of-credit load. That
   folder exists nowhere in the repo. They were removed on 2026-09-02.

   Where the type comes from today:

     Inter        served by the new chrome, via _includes/home-styles.html,
                  as 7 subsetted and hashed woff2 files. They return 200.

     Geist Mono   nobody serves it, and there is no mono token left: --font-mono
                  itself was retired on 2026-09-10. The brand book (ch. 06,
                  p. 32) does name it as a minor face with rules of its own —
                  never above the Sm tier, never a surface default — but
                  adopting it means deciding to and shipping the woff2. Open.

   If it is adopted, the @font-face belongs in assets/css/tokens/fonts.css,
   which is where that layer lives, and the file in assets/fonts/ with an
   absolute path. */

/* Cardiff — color tokens
   Source: Cardiff_DS_Foundations_v1.0, reconciled against the Design Token
   Audit (30 Jul 2026 — SUPERSEDED. That audit's typography findings were
   wrong; see Section 01 of uploads/cardiff-token-reconciliation.pdf, which
   corrects them. Its colour findings, including everything below, stand.
   The citation is kept because it records what was actually reconciled on
   that date, not because the audit is current).
   Brand blue is #2563EB — bespoke, canonical; the ramp locks hue (220.9°)
   and saturation to it. Inverse text is always #FFFFFF,
   never paper:white on 600 is 4.61:1 (AA), paper would be 4.41:1 (fail).
   c-500 is large-text-only (3.60:1 on paper).
   One brand blue. Warm stone neutrals. No cool greys, no second hue.

   Rev 31 Jul 2026 — merged the status scale, elevation layer, and dark theme
   from the Portal Hubs prototype. Three notes on what changed in transit:

   1. The portal's light-mode status text failed AA in three of four cases
      (info 3.38:1, positive 2.53:1, danger 4.24:1 on their own soft fills).
      Each -text value has been darkened along its own hue to clear 4.5:1.
      Its dark-mode status colours all passed unchanged (5.3–8.2:1) and are
      carried as-is.
   2. Solid status fills take --ink, not white — white clears AA only on
      danger (4.83:1) and fails badly on info (2.06:1), positive (1.89:1),
      and warn (2.15:1). See --text-on-status.
   3. Dark mode flips the SEMANTIC ALIASES only; raw tokens keep their literal
      values. --paper is the colour of paper in both themes. Anything that
      needs to invert reads a semantic alias, never a raw token.
   4. --text-link moved from c-600 to c-700. Contrast is symmetric, so the
      4.41:1 already documented above for paper-on-c-600 is the same ratio as
      c-600-on-paper:blue body-size link text on the page canvas fails AA by
      the same margin, in the same pair. c-700 clears it at 5.07:1 and is
      already in the ramp. --accent-word stays on c-600 — it only ever sets
      display-tier words, where 4.41:1 clears the 3.0 large-text threshold. */

/* ---- Dark theme ----
   Aliases only. Brand steps up to --c-400: #2563EB is 3.93:1 on the dark card
   surface and fails, so the primary cannot carry over unchanged. The dark
   brand fill takes --ink, not white (white on --c-400 is 2.92:1).
   Status -soft fills become low-alpha tints so they sit on any dark surface;
   -text values brighten to match. All four clear AA on the composite. */

/* Cardiff — typography tokens
   Source of truth:Cardiff_DS_Foundations_v1.0 · "Typography — The rhythm"
   Family roles per design direction, 31 Jul 2026.

   FAMILY HIERARCHY (rev 7 Aug 2026). Inter is the default for everything.
   Geist Mono is LAST — a minor-detail face, not a co-equal family with its
   own territory. Every mono use needs a reason.

   THE TEST — is the string read as a VALUE or as a SEQUENCE OF CHARACTERS?
   Read as a value -> Inter. Loan amounts, APRs, dates, balances, payment
   schedules, percentages, counts. When figures must align in a column, use
   `font-variant-numeric: tabular-nums`. Inter HAS tabular figures, so column
   alignment is not a reason to change family — this removes most of the
   pressure toward mono in a lending UI.
   Read character by character -> Geist Mono. Application references
   (CF-2024-8871), hashes, API keys, code. The question is how a person reads
   the string, not whether it contains digits.

   TWO HARD LIMITS
     · Mono never appears above the Sm tier. No mono headings, no mono
       display, no mono primary content.
     · Mono is never a surface default. A screen whose numbers ARE its
       content — a dashboard, a payment schedule, an offer summary — is set
       in Inter throughout.

   IF YOU ARE READING THE KITS FOR EXAMPLES, DON'T — not for family choice.
   ui_kits/ and guidelines/ currently set roughly a third of their type in
   mono, and the Portal Hubs prototype uses mono more than Inter. That ratio
   predates this rule and is wrong. Follow the test above, not the kits.
   Prior wording ("identifiers, timestamps, tabular numerals … technical
   surfaces only") read as a restriction but in a lending product enumerated
   nearly the whole screen, which is how the drift happened.

   RETIRED, do not reintroduce:
     · Fraunces        — no separate display face; Inter carries display
     · JetBrains Mono  — out of --font-mono on 2026-09-09, and the token itself
                        retired on 2026-09-10. There is no mono in the system
                        today. Geist Mono was floated as the successor and is
                        still undecided.
     · Instrument Serif italic accent — never applied to a single element in
       any shipped artifact. Declared as `.font-edit` on the homepage (unused,
       while loading four woff2 subsets) and named in the portal overlay
       comment before being explicitly overridden to Inter normal.

   With no serif in the system there is no face to carry brand-voice italics,
   so the accent word is now weight + brand colour only, on Inter. That is
   exactly what the portal already implements.

   THE RULE: every tier's line-height is exactly its size + 4px, at every
   breakpoint. If a value doesn't satisfy size+4, it isn't a Cardiff tier.

   Half-pixels are legal in exactly two places:tablet Sm (13.5/17.5) and
   tablet Xs (11.5/15.5). Both are Foundations tiers and both obey +4. Any
   other half-pixel size — 9.5, 10.5, 12.5, 14.5 — is drift; clear it.

   CEILING: 72px, at every surface. No marketing exemption.

   Tiers are mobile-first: :root holds mobile, tablet and desktop override.
   Consumers read var(--type-h1) and get the right value for the viewport
   without writing media queries of their own.

   ON THE @kind ANNOTATION (rev 5 Aug 2026)
   --accent-style carries an "@kind other" annotation. The DS token classifier
   matches on NAME first and only falls through to the VALUE when the name has no
   kind keyword. Every other token here passes on its name: --weight-*,
   --font-*, and --accent-font all contain `weight` or `font`, so their values
   are never examined at all. --accent-style is the one token in the system
   where both paths fail — its name carries no kind keyword and `normal` is
   not a length, colour, or font metric.
   Worth understanding rather than just copying: the token layer now classifies
   175 of 175, but that reflects naming convention, not validation. Values like
   `50%` on --radius-circle and the multi-layer --shadow-* declarations were
   never parsed; they were waved through on their prefixes. Any future token
   that breaks the --space- / --radius- / --shadow- / --font- prefix habit AND
   carries a keyword or function value will need the same explicit annotation.
   Credit for the diagnosis goes to the Design agent's conflict report. */

/* ───────── Scale · TABLET (641–1024px) ───────── */

/* ───────── Scale · DESKTOP (≥1025px) ───────── */

/* Cardiff — spacing, radii, shadow tokens
   Source:Cardiff_DS_Foundations_v1.0. The 4px grid is Foundations' own
   rhythm principle, carried here from the typography scale.

   Rev 31 Jul 2026 — reconciled against measured usage across all three
   artifacts (DS kits + components, Portal Hubs prototype, built homepage).
   Unlike the colour merge, this one is mostly a correction of THIS file:
   the previous radius ladder and shadow ceiling described almost nothing
   that anyone had actually built.

   WHAT THE MEASUREMENTS SHOWED
     · The 4-step radius ladder (4/8/10/999) covered 5% of DS-kit radius
       declarations, 18% of the portal's, and 13% of the homepage's. It was
       aspirational, not descriptive. Widened below to the clusters that are
       genuinely in use — 16px alone accounts for 30 declarations and had no
       token at all.
     · The spacing scale was missing five on-grid steps that are in constant
       use: 28px (52 uses), 56px (21), 36px (17), 44px (14), 52px (3). Those
       107 uses were forced off-token by an incomplete scale, not by drift.
       Added. --space-22 (88px) has exactly one use and is a candidate for
       removal.
     · The declared shadow ceiling (0.18) was exceeded by every artifact,
       and by the DS's OWN kits worst of all (black at 0.88 alpha vs a
       declared 0.18). The ladder below is built from the portal's geometry,
       which sat closest to the stated intent.

   THE RULE — ratified 31 Jul 2026, multiples of 4, no half-steps.
   Every spacing value is a multiple of 4px. There is no 2px half-step and
   none should be added. Two half-steps sum to a multiple of four, but a half
   step beside a full one propagates (6 + 8 = 14), so a half-step is only
   safe if it never sits adjacent to a full step — a constraint nobody can
   hold in their head while building. Purity here is what keeps the
   arithmetic composable, not house style.

   SCOPE. This rule governs the spacing rhythm. The type scale is governed by
   its own rule — line-height = size + 4px — and its non-multiple-of-4 values
   (11, 13, 14, 15, 17, 18, 22, and the 11.5/13.5/15.5/17.5 tablet tiers) are
   OUTSIDE this rule's scope, not exceptions to it. Two scales, two rules, no
   conflict. A spacing value does not become legal by coinciding with a type
   metric.

   THE ONLY CARVE-OUTS
     · 1px hairlines and borders — --space-hair below. Borders are not
       rhythm, and without this the rule is violated on contact (106 uses).
     · Optical asset dimensions — logo and icon heights, and the corner radius
       of depicted physical objects such as device frames. Ratified 5 Aug 2026;
       see the exemption note in the radius block below.
     · Non-px units — percentages, vw/vh, fr, unitless line-heights. Already
       out of scope; recorded so it is not re-argued.
   Note 2px is NOT a carve-out. It reads as an optical nudge but it is a
   half-step, and it is the value most likely to reintroduce the pattern.

   WHERE THE HALF-STEPS CAME FROM — read this before snapping anything, or
   they will regenerate. Several type tiers have line-heights that are not
   multiples of four:Sm desktop 14/18, Sm mobile 13/17, Xs mobile 11/15.
   Put 4px symmetric padding around an 18px line and the component is 26px
   tall; to land it on 28 the padding has to be 5px. That pressure is exactly
   why 6px and 10px cluster on the dense Sm/Xs surfaces.
   The fix is to stop deriving dense component heights from padding. Set an
   explicit height from the scale and centre the text — a badge is
   `height: var(--space-6)` with centred content, not `padding: 5px 8px`.
   Spacing rule intact, heights land on the grid, and the pressure is removed
   rather than suppressed.

   OUTSTANDING CLEANUP — 642 declarations, of which only 24 are in shipped
   production code (homepage). The remainder is 394 in the DS's own kits and
   components and 224 in the unshipped Portal Hubs prototype. Ties round DOWN
   (6->4, 10->8, 14->12, 18->16, 22->20): rounding down cannot overflow a
   fixed-width container, and a 2px reduction reads as less of a change than
   a 2px increase on dense surfaces. See the accompanying snap list. */

/* ---- Dark theme ----
   A cool-tinted shadow over a near-black surface is close to invisible, so
   dark mode does two things: shadows switch to pure black at higher alpha,
   and elevation is carried primarily by the surface ladder
   (--surface-card / -raised / -sunk) plus --border-default. If a dark
   surface needs to read as lifted, step the surface first and add shadow
   second — never shadow alone. */

/* Cardiff — motion tokens
   Restrained, quiet motion. Rewards scroll, clarifies hierarchy,
   never entertains. Everything respects prefers-reduced-motion. */

/* 1400 to match the chrome's container. The prose does not widen with it:
   almost all of it caps itself in ch, and the two that did not (.body and the
   <li> text) now carry the same 68ch as the rest of the file. Without that cap
   they would go from ~120 characters per line to ~155. */
.prod .wrap{ max-width:1400px; margin:0 auto; padding:0 3rem;}
/* .hero is a flex column so it can centre vertically; without this its .wrap
   shrinks to the content width instead of taking the full 1080. */
.prod .hero > .wrap{ width:100%; position:relative; z-index:3; }

/* ── Hero photo and scrim ──────────────────────────────────────────
   Four layers, bottom to top: photo, glow, scrim, content. The glow sits under
   the scrim so the scrim's arithmetic holds — the glow adds light, and anything
   that lightens the ground after the scrim would eat into the contrast measured
   below.

   The scrim runs .50 at the top to .72 at the bottom because the hero is
   bottom-aligned: the copy lands in the lower half, and that is where the veil
   has to be heaviest. Measured with sRGB compositing, which is how a browser
   blends — in linear light the numbers come out far too optimistic.

   The binding case is .sub, not the h1: it is white at 72% and drops to 20px on
   mobile, so it needs 4.5:1 rather than the 3:1 large text gets. Against a
   photo at .45 luminance it measures 6.0:1; even against blown-out white it
   holds 4.1:1. The h1 in solid white is never in doubt.

   object-position 50% 40% keeps the subject above centre, because the copy
   occupies the bottom of the frame. */
.prod .hero__img{
  position:absolute; inset:0; z-index:0;
  width:100%; height:100%;
  object-fit:cover; object-position:50% 40%;
  /* Placeholder until the photo lands, same as the other slots on this page. */
  background:linear-gradient(160deg,#4b5563,var(--ink));
}
/* For a photograph whose subject sits high in the frame (business loans:
   two people framed from the chest up), anchored to the top so no crop takes
   their heads, whatever the hero's height. */
.prod .hero__img--top{object-position:50% 0}
/* The amount widget is born hidden and products.js reveals it. Hidden with
   display:none it took no room, so when it appeared the hero grew and the
   copy jumped (Lighthouse: CLS 0.143 on line of credit at desktop). With JS
   on (html.js is set in <head> before the first paint) its box is laid out
   from the start, only invisible, so revealing it moves nothing. Without JS
   it stays display:none: nobody sees a control that cannot work. flex,
   because that is the widget's own display; anything else would size the
   reserved box differently and the jump would come back. */
html.js .prod .hero__widget[hidden]{display:flex; visibility:hidden}
.prod .hero .glow{ z-index:1; }
/* Lightened from .50/.62/.72 on 2026-09-28, which is 80% of what it was
   and as far as it goes. The scrim is what makes white type legible over
   a photograph, so this was measured rather than chosen: at 70% the glass
   panel drops to 4.21 on both heroes and line-of-credit’s sub-line to
   4.45, both under the 4.5 they need.

   Where it stands now, worst pixel in each region:

                    h1 (needs 3.0)   sub (4.5)   panel (4.5)
     line-of-credit      7.40           4.95         4.97
     merchant cash       8.03           5.28         4.99

   That is under half a point of headroom on the sub-line and the panel.
   A hero photograph lighter than these two will not pass, so measure
   before replacing one - do not assume.

   The shape stays: lighter at the top, darker at the foot, where the
   photograph meets the page’s own background and an even scrim would
   leave a seam. */
.prod .hero__scrim{
  position:absolute; inset:0; z-index:2; pointer-events:none;
  background:linear-gradient(to bottom,
    rgba(0,0,0,.40) 0%, rgba(0,0,0,.50) 45%, rgba(0,0,0,.58) 100%);
}
.prod .eyebrow{ font-size: var(--type-xs); line-height: var(--leading-xs); letter-spacing: var(--tracking-eyebrow); text-transform:uppercase; font-weight: var(--weight-semibold); color: var(--c-700); margin-bottom:var(--space-3); }
.prod .h2{ margin:0; font-weight: var(--weight-heavy); letter-spacing: var(--tracking-h1); line-height: var(--leading-h2); font-size: var(--type-h2); color: var(--ink); }
.prod .accent{ color: var(--accent-word); }
.prod .body{ margin:0; font-size: var(--type-base); line-height: var(--leading-base); color: var(--coffee); text-wrap:pretty; max-width:68ch; }
/* The base defines shape, not colour. The blue stays as the default because
   the buttons that already exist declare no variant; declaring one is the
   recommended practice from here on. */
.prod .btn{ display:inline-flex; align-items:center; justify-content:center; gap:var(--space-2); border-radius:var(--radius-pill); font-family: var(--font-ui); font-weight:500; line-height:1.2; white-space:nowrap; cursor:pointer; text-decoration:none; border:1px solid transparent; background: var(--brand); color: var(--text-on-brand); padding:var(--space-2) var(--space-4); font-size:var(--type-xs); transition:background var(--motion-fast) var(--ease-standard), color var(--motion-fast) var(--ease-standard), border-color var(--motion-fast) var(--ease-standard); }
.prod .btn:hover{ background: var(--brand-hover); color: var(--text-on-brand); text-decoration:none; }
.prod .btn.lg{ padding:14px 28px; font-size:16px; }

/* The design system's three variants, approved on 2026-09-09.
   They are written with the semantic aliases rather than the raw tokens the
   guide's demo uses: --surface-card, --text-heading and --border-default
   resolve to --white, --ink and --rule today, but they are the layer that
   moves on its own if dark mode ever lands. It is also what careers.css
   already ships. */
.prod .btn--primary{ background: var(--brand); color: var(--text-on-brand); border-color:transparent; }
.prod .btn--primary:hover{ background: var(--brand-hover); color: var(--text-on-brand); }

.prod .btn--secondary{ background: var(--surface-card); color: var(--text-heading); border-color: var(--border-default); }
.prod .btn--secondary:hover{ background: var(--surface-raised); color: var(--text-heading); }

/* For a dark ground — the hero, the final CTA. On paper it has too little
   contrast; --secondary goes there.

   The border ships at .38 and not the proposal's .30: measured against the
   hero (#1C1917), .30 gives 2.71:1 where WCAG 1.4.11 asks 3.0 for a control's
   boundary. .38 gives 3.55:1. The fill reaches 3:1 at no sensible alpha — at
   .24 it is still 2.18 — so the border is the only thing drawing the button,
   which is why it is the border that has to pass. White text on top was never
   in doubt: at .12 fill it measures 12.21:1. */
.prod .btn--dark{ background: var(--surface-on-dark); color: var(--white); border-color: rgba(255,255,255,0.38); }
.prod .btn--dark:hover{ background: rgba(255,255,255,0.20); color: var(--white); border-color: rgba(255,255,255,0.55); }
@media (prefers-reduced-motion:no-preference) {
  .prod .btn.pulse{ animation:cta-pulse 2.4s ease-out infinite; }
  @keyframes cta-pulse {
    0% { box-shadow:0 0 0 0 rgba(var(--brand-rgb),0.35); }
    70% { box-shadow:0 0 0 12px rgba(var(--brand-rgb),0); }
    100% { box-shadow:0 0 0 0 rgba(var(--brand-rgb),0); }
  }
}
/* The 112px at the top was a magic number: it cleared the new chrome's navbar,
   which is position:fixed and 80px tall. It is written out so it can be read,
   and so nobody lowers it by accident. The fallback is there because
   --site-nav-h is defined by careers.css, which this section does not load. */
.prod .hero{ position:relative; overflow:hidden; color:var(--white); background:radial-gradient(120% 100% at 80% 0%, var(--ink-3) 0%, var(--ink-2) 55%, var(--ink) 100%); padding:calc(var(--site-nav-h, 80px) + var(--space-8)) var(--space-12) var(--space-24); }
/* min-height and not height: .hero clips (overflow:hidden, because of the
   glow), so a fixed height would eat the content in silence the moment it
   stopped fitting. At 80vh that does not happen on desktop — the content floor
   is around 440px and 80vh is already 614 in the shortest window (768) — but
   min-height keeps it safe anyway if the copy grows.
   The dvh is for mobile: 100vh counts the address bar even while it is
   showing, so vh overestimates the usable screen. */
.prod .hero{ min-height:80vh; min-height:80dvh; display:flex; flex-direction:column; justify-content:flex-end; }
.prod .hero .glow{ position:absolute; inset:0; opacity:0.5; pointer-events:none; background:radial-gradient(60% 80% at 70% 30%, rgba(120,86,52,0.35) 0%, rgba(28,25,23,0) 70%); }
.prod .pill{ display:inline-flex; align-items:center; gap:var(--space-2); padding:6px 14px; border-radius:var(--radius-pill); font-size:var(--type-xs); font-weight:500; line-height:1.3; background:var(--surface-on-dark); border:1px solid var(--border-on-dark); color:var(--white); }
.prod .pill .dot{ width:7px; height:7px; background:var(--white); border-radius:var(--radius-full); flex-shrink:0; }
.prod .hero h1{ margin:var(--space-7) 0 0; font-weight: var(--weight-heavy); letter-spacing: var(--tracking-display); line-height: var(--leading-h1); font-size: var(--type-h1); color:var(--white); max-width:16ch; }
.prod .hero .sub{ font-size: var(--type-h6); line-height: var(--leading-h6); color:var(--on-dark-2); max-width:44ch; margin:var(--space-6) 0 var(--space-10); }
.prod section.pad{ padding:var(--space-24) var(--space-12); }
.prod section.chalk{ background: var(--chalk); border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
.prod .grid4{ display:grid; grid-template-columns:repeat(auto-fit, minmax(220px, 1fr)); gap:var(--space-5); }
.prod .fcard{ background: var(--surface-card); border: 1px solid var(--border-default); border-radius:var(--radius-xl); padding:var(--space-7); display:flex; flex-direction:column; gap:var(--space-3); }
/* The two in the Secured/Unsecured panel are tinted. The card against the
   section — which is white — measures 1.09:1, so the border is still what
   gives it an outline; it turns bluish so it does not clash with the fill. */
.prod .fcard.prod-pad-32{ background: var(--brand-soft); border-color: var(--brand-soft-line); }
.prod .fcard .dot, .prod .li .dot{ width:8px; height:8px; border-radius:var(--radius-full); background: var(--brand); flex-shrink:0; }
.prod .fcard h3{ margin:0; font-size: var(--type-h6); line-height: var(--leading-h6); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); color: var(--ink); }
.prod .cols{ display:grid; grid-template-columns:repeat(auto-fit, minmax(300px, 1fr)); gap:var(--space-8); margin-top:var(--space-10); }
.prod .split{ display:grid; grid-template-columns:minmax(300px, 2.5fr) minmax(260px, 1fr); gap:var(--space-16);}
/* Tablet and below: the two-column grid stacks. 1023 and not 800 — it is the
   Foundations step, the same one where the Tailwind chrome
   cambia de modo. */
@media (max-width:1023px) { .prod .split{ grid-template-columns:1fr; } }
.prod .tinted{ background: var(--brand-soft); border: 1px solid var(--brand-soft-line); border-radius:var(--radius-lg); padding:var(--space-8); }
.prod .whitecard{ background: var(--surface-card); border: 1px solid var(--border-default); border-radius:var(--radius-lg); padding:var(--space-8); box-shadow: var(--shadow-card-sm); }
.prod .list{ display:flex; flex-direction:column; gap:var(--space-4); }
.prod .li{ display:flex; gap:var(--space-3); align-items:baseline; }
.prod .li .dot{ width:7px; height:7px; position:relative; top:-2px; }
.prod .li span:last-child{ font-size: var(--type-base); line-height: var(--leading-base); color: var(--ink); font-weight:500; max-width:68ch; }
.prod .label{ font-size: var(--type-xs); line-height: var(--leading-xs); letter-spacing: var(--tracking-eyebrow); text-transform:uppercase; font-weight: var(--weight-semibold); color: var(--c-700); margin-bottom:var(--space-5); }
/* Inner arrangement only. The box — border, radius, fill, padding — comes
   from .prod-marquee, which is the only place a .ucase lives. This rule used
   to carry padding and a border-bottom from the old rule treatment, and since
   the two rules tie on specificity the row's won purely by coming later in the
   file. */
.prod .ucase{ display:flex; flex-direction:column; gap:var(--space-2); }
/* No padding here any more: the two columns carry their own, because the head
   is a photograph now and its picture has to reach the edges of its half. */
.prod .final{ background:var(--c-900); color:var(--white); }
/* ── The final CTA, as a banner ─────────────────────────────────────────────
   Same approach as the .cta in careers: a rounded box that stops short of the
   window edges and stands clear of what sits above and below it. What this
   class does not touch is the background, which stays whatever .final sets.

   The inset comes from .wrap on the <section>, not from this class, so the
   banner starts and ends exactly where the text of every other section starts
   and ends instead of floating on a margin of its own that matches nothing.

   A vertical margin escapes a section that has no padding or border. Here the
   section's flow-root (see .prod-band) keeps it contained, so the white
   background covers the gap rather than stopping at the edge of the box. */
.prod .prod-cta{
  margin:var(--space-24) var(--space-28) 0;
  border-radius:var(--radius-2xl);
  overflow:hidden;
}
/* Two columns: the title and the button on the left, the three paragraphs on
   the right. 1.2 against 2.8 of four, so the left is 30% of the track space.

   Halves, and stretched rather than start-aligned: the head carries a
   photograph now, so its box has to reach the full height of the row or the
   picture stops short of the prose beside it. The content still sits at the top
   because the head is a flex column with nothing pushing it down.

   No gap. The two halves meet, photograph against the dark ground, and a gap
   would put a stripe of banner between them. */
.prod .prod-cta__grid{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:0;
  align-items:stretch;
}

/* The veil is light on purpose, so the photograph reads, and what that costs is
   measured rather than assumed. Re-measured 2026-09-17 against the new crop,
   composited in sRGB because that is what a browser does — in linear light the
   same frame reads far kinder than it looks.

   The veil runs left to right rather than top to bottom, dark where the text
   starts and clearing toward the right, because the content is a flex column
   aligned to flex-start: the title and the button hug the left edge, and the
   right third of the photograph carries nothing. Shading by column instead of
   by row spends the darkness where the text is and hands the rest back to the
   picture.

   The numbers, measured over the title's own box — 9% to 78.5% across, 48% to
   87% down: the average is 12.7:1 against the 3.0 large white text needs, and
   1.6% of that area falls under 3.0. The vertical veil it replaces averaged
   11.1:1 but left 10.8% under, because it lit the left edge exactly where the
   words begin. The crop before this one measured 1.90:1 and failed outright.

   The 1.6% that remains is speckle rather than a bright band — 1st percentile
   2.55, so a short word can still land on a highlight. Worth another look only
   if the final copy runs longer than the four lines it runs now. TODO-CARDIFF.

   image-set rather than a plain url: a CSS background takes no srcset, so
   without it every phone would pull the widest file. Resolution-based, and the
   pair changes at 1024 because the box does: half the banner is 684px at a 1592
   window and grows with the viewport past it, while stacked on a phone it is
   about 330. Each of the two rules declares background-image twice, the first
   with a bare url() for engines with no image-set() — see below. */
.prod .prod-cta__head{
  display:flex; flex-direction:column; align-items:flex-start;
  /* justify-content and not align-items: this is a column, so the main axis
     runs down the page and flex-end is what puts the title and the button at
     the foot of the photograph. align-items:flex-end would have moved them
     right instead. */
  justify-content:flex-end;
  gap:var(--space-10);
  padding:var(--space-24) var(--space-16);
  /* Two declarations and not one. Safari shipped unprefixed image-set() in 17,
     and a declaration a browser cannot parse is dropped whole — the veil with
     it — so iOS 15 and 16 would land on the flat --c-900 that .final paints,
     with no photograph and no gradient. The plain url() is what those read; any
     engine that understands image-set() takes the second and the first never
     applies. */
  background-image:
    linear-gradient(to right, rgba(10, 10, 10, .62), rgba(10, 10, 10, .2)),
    url('/assets/img/business-loans/loc-funds-on-demand-1200.jpg');
  background-image:
    linear-gradient(to right, rgba(10, 10, 10, .62), rgba(10, 10, 10, .2)),
    image-set(url('/assets/img/business-loans/loc-funds-on-demand-1200.jpg') 1x,
              url('/assets/img/business-loans/loc-funds-on-demand-2000.jpg') 2x);
  background-size:cover;
  background-position:50% 50%;
  background-repeat:no-repeat;
}
/* 85% of the head's content box, which is the half minus its padding. At a 1592
   window that is 460px, so the cap lands at about 391 — roughly twelve
   characters a line at 64px, and the title comes to four. */
.prod .prod-cta__head > *{max-width:85%}

/* justify-content centres the copy vertically: the photo half beside it, with
   the title and the button, sets the row's height, and the body would
   otherwise sit at the top of it with the leftover space all underneath. */
.prod .prod-cta__body{
  display:flex; flex-direction:column;
  justify-content:center;
  gap:var(--space-5);
  padding:var(--space-24) var(--space-16);
}

/* The title comes down a step from --type-h1pp, and the column is why. At a
   1440 window the banner is 1216 wide, its padding takes 128, and 1.2 of four
   leaves 307px. At 72px that is about 8 characters a line — the word "Growing"
   alone nearly fills one — and the title runs to six lines. At 64 it is nine
   characters and five lines, and on a 1920 screen the column grows to 451px and
   it settles into four.

   Five lines is a deliberate look rather than an accident: a tall narrow block
   of display type against the prose beside it. If it reads as too many, the
   lever is the column, not the size — 2fr/2fr would give the title room without
   shrinking it.

   The leading is --leading-h1p and not --leading-h1. They are four pixels apart
   and both would compile, but 60px of leading under 64px type packs five lines
   until the descenders of one nearly meet the ascenders of the next. Every tier
   here pairs with its own leading at size + 4; reaching into a neighbouring
   family is the kind of mistake nothing reports.

   .prod-cta.final h2 and not .prod-cta h2: with two classes this ties with the
   .prod .final h2 below, which comes later and would win on order alone. */
.prod .prod-cta.final h2{
  font-size:var(--type-h1p);
  line-height:var(--leading-h1p);
  text-wrap:balance;
}

/* The prose loses the centring margin it had as a single stacked column; the
   grid gap is what spaces it now. */
.prod .prod-cta__body p{margin:0; max-width:none}

/* One column below 1024. The prose keeps its reading measure there, where it
   has the full width and would otherwise run past it. */
@media (max-width:1023px){
  .prod .prod-cta__grid{grid-template-columns:1fr; gap:var(--space-10)}
  .prod .prod-cta__body p{max-width:68ch}
}

@media (max-width:1023px){
  .prod .prod-cta__head,
  .prod .prod-cta__body{padding:var(--space-16) var(--space-10)}
  /* Stacked, the head is the width of the banner rather than half of it, but
     that is at most 960 and on a phone about 330. The desktop pair would have a
     375px screen pulling 2000px of photograph. */
  .prod .prod-cta__head{
    background-image:
      linear-gradient(to right, rgba(10, 10, 10, .62), rgba(10, 10, 10, .2)),
      url('/assets/img/business-loans/loc-funds-on-demand-700.jpg');
    background-image:
      linear-gradient(to right, rgba(10, 10, 10, .62), rgba(10, 10, 10, .2)),
      image-set(url('/assets/img/business-loans/loc-funds-on-demand-700.jpg') 1x,
                url('/assets/img/business-loans/loc-funds-on-demand-1200.jpg') 2x);
  }
}
@media (max-width:767px){
  .prod .prod-cta__head,
  .prod .prod-cta__body{padding:var(--space-12) var(--space-8)}
}

.prod .final h2{ margin:0; font-weight: var(--weight-heavy); letter-spacing: var(--tracking-display); line-height: var(--leading-h1); font-size: var(--type-h1pp); color:var(--white); }
/* :where(.final) so this rule stops outranking the margin utilities. Without it
   it sits at (0,2,1) and .prod .prod-mt-28 at (0,2,0), so the shorthand's margin
   was overriding the 28 on the first paragraph and the 40 on the last. Whatever
   goes inside :where() adds no specificity, so this drops to (0,1,1) -- under a
   utility, still over a bare p -- without changing a single declaration. The
   utility takes only its own side; the other three still come from the shorthand
   here. */
.prod :where(.final) p{ font-size: var(--type-base); line-height: var(--leading-base); color:var(--on-dark-2); max-width:100ch; text-wrap:pretty; margin:var(--space-5) auto; }
.prod details{ border-bottom: 1px solid var(--rule); }
/* justify-content:flex-start with the + pushed over by margin-left:auto, not
   space-between: a title with its accent word in a <span> is four flex items —
   text, span, text, + — and space-between spreads them across the full width.
   This way the title stays together whatever it is made of. */
.prod summary{ list-style:none; cursor:pointer; display:flex; justify-content:flex-start; align-items:baseline; gap:var(--space-1); padding:var(--space-6) 0; font-size: var(--type-base); line-height: var(--leading-h6); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); color: var(--ink); }
/* The ones in the "How it works" accordion are section titles, not questions,
   so they go up to H6. Told apart by their container and not by #How_02: an id
   wins for being an id, not because anyone decided it, and one other rule raised
   to .prod details summary would have sent these back to the FAQ size in
   silence. The class states the intent and survives the next edit. */
.prod .prod-accordion > details > summary{ font-size: var(--type-h6); font-weight: var(--weight-semibold); }
.prod summary::-webkit-details-marker{ display:none; }
.prod summary .plus{ color: var(--c-600); font-weight:400; flex-shrink:0; margin-left:auto; transition:transform var(--motion-base) var(--ease-standard); }
.prod details[open] .plus{ transform:rotate(45deg); }
.prod details p{ margin:0; padding:0 0 var(--space-6); font-size: var(--type-base); line-height: var(--leading-base); color: var(--coffee); max-width:68ch; text-wrap:pretty; }
.prod .prod-accordion > details > .faq-body{ padding: var(--space-12) var(--space-12) var(--space-6); }
#two-structures p.body {max-width: none;}

/* ==========================================================================
   Page utilities, lifted from 41 inline style attributes.

   These beat the type selectors by source order, not by specificity. Inline
   styles beat every selector, and hoisting them to bare classes lost that in
   silence: the page has section.pad, .final h2, .final p and details p — all
   (0,1,1) — which outrank a lone class and took back margins the inline styles
   had been winning.

   Scoping the file under .prod (2026-09-09) changed the balance, and not in
   their favour: .prod .prod-mb-40 lands at (0,2,0) and .prod section.pad at
   (0,2,1), so the type rule now wins. It did not before: .loc .loc-mb-40 was
   (0,2,0) against section.pad's (0,1,1).

   Nothing broke, because it was checked element by element: no utility shares
   a property with a type rule that reaches the same node. But the margin of
   safety is gone. If a utility ever has to beat section.pad, .final h2,
   .final p or .hero h1, moving it will not be enough — the class has to be
   doubled (.prod-mb-40.prod-mb-40) or those type rules brought down to
   classes.

   It happened on 2026-09-11 with .final p, which was overriding the prod-mt-28
   on the CTA's first paragraph and the prod-mb-40 on its last. The second way
   out was taken, wrapping .final in :where(): it fixes all three paragraphs at
   once and any utility put on them tomorrow, whereas doubling the class has to
   be repeated utility by utility. The other three type rules -- section.pad,
   .final h2 and .hero h1 -- are untouched; when one of them needs it, the recipe
   is the same. Inline styles beat every
   selector, and hoisting them to bare classes silently lost that:this page
   has section.pad, .final h2, .final p and details p — all (0,1,1) — which
   outrank a lone class and took back padding and margins the inline styles
   had been winning. Measured at 20% of the page changed. The scope restores
   the precedence the attributes had, with no !important.

   These are named for what they do rather than for a component, because that
   is what they were: the export used inline styles as an ad-hoc utility layer.
   Grouping collapsed 41 attributes into 25 classes, and most of those are used
   once — a far smaller win than the role page saw, where the same exercise
   found real repeated components. The near-duplicate spacing steps below
   (mb-20 / mb-24 / mb-40 / mb-48) are the honest shape of the source; folding
   them onto one scale is a design decision, not a refactor.
   ========================================================================== */
.prod .prod-mb-20{margin-bottom:var(--space-5)}
/* flow-root so the band contains the margins of whatever sits inside it.
   Without it the #apply banner's margin escapes the section and the white only
   reaches the edge of the box: the 05 section's chalk would show above it and
   the FAQ's white below. Nothing changes for the 02 section or the FAQ, whose
   padding already stopped the margin from escaping. */
.prod .prod-band{background:var(--white); display:flow-root; }
.prod .prod-band--pad{background:var(--paper);padding:var(--space-24)}
/* section.pad sets padding only. For a paper band on section.pad's padding,
   which is what a section holding a marquee needs: the marquee sits inside
   .wrap there, as on line of credit, and .prod-band--pad's extra 96px a side
   would narrow it. */
.prod .prod-bg-paper{background:var(--paper)}
.prod .prod-mb-24{margin-bottom:var(--space-6)}
.prod .prod-mb-40{margin-bottom:var(--space-10)}
.prod .prod-mb-48{margin-bottom:var(--space-12)}
.prod .prod-mb-80{margin-bottom:var(--space-18)}
.prod .prod-accent{color:var(--c-500)}
.prod .prod-lede{max-width:68ch;margin-top:var(--space-10)}
.prod .prod-pad-32{padding:var(--space-8)}
.prod .prod-sticky{position:sticky;top:96px}
.prod .prod-band--pad-top{background:var(--paper);padding:var(--space-24) var(--space-12) 72px}
.prod .prod-rule-top{border-top:1px solid var(--rule)}
/* wrap: below about 340px the two hero buttons no longer fit side by side,
   and the second one ran off the screen. */
.prod .prod-row{display:flex;flex-wrap:wrap;gap:var(--space-4);align-items:center}
.prod .prod-grid-300{display:grid;grid-template-columns:repeat(auto-fit, minmax(300px, 1fr));gap:var(--space-5)}
.prod .prod-h2--sm{font-size:var(--type-h3);line-height:var(--leading-h3);letter-spacing:var(--tracking-h2);margin-bottom:var(--space-6)}
.prod .prod-mt-0{margin-top:0}
.prod .prod-mt-28{margin-top:var(--space-7)}
.prod .prod-mt-48{margin-top:var(--space-12)}
.prod .prod-mt-80{margin-top:var(--space-18)}
.prod .prod-h2-narrow{max-width:22ch}
.prod .prod-h2-narrow--mb{max-width:22ch;margin-bottom:var(--space-6)}
/* The measure cap on its own. The --mb-* variants add a margin to it, and only
   work in block flow: inside a flex column that margin adds to the container's
   gap and separates more than anyone asked for. */
.prod .prod-measure{max-width:68ch}
.prod .prod-measure--mb-40{max-width:68ch;margin-bottom:var(--space-10)}
.prod .prod-measure--mb-48{max-width:68ch;margin-bottom:var(--space-12)}
/* Centred heading for the one block on the page that is not left-aligned: the
   lede and the four cards it introduces. A short measure is what makes centred
   text readable -- at 22ch it breaks into two or three even lines instead of one
   very long one that leaves the eye hunting for where the next begins. */
.prod .prod-head-center{text-align:center;margin-bottom:var(--space-8)}
/* The measure goes on the h2 and not on the wrapper: ch resolves against the
   font of the element carrying the declaration, and on the div -- which inherits
   the body size -- 22ch would be ~264px instead of the ~580 it gives at 48px. */
.prod .prod-head-center .h2{max-width:22ch;margin-inline:auto}
/* For a centred heading too long for 22ch to hold in two lines. MCA's "Unlock
   Fast Capital with Merchant and Business Cash Advance Loans" is 66
   characters: at 22ch it broke in three; measured, 28ch is the narrowest that
   keeps two lines at every desktop width, and 30 leaves a margin for a
   fallback font. balance evens the two lines instead of leaving a short one. */
.prod .prod-head-center .h2.prod-h2-wide{max-width:30ch; text-wrap:balance}
.prod .prod-lede-center{max-width:68ch;margin:0 auto;font-size:var(--type-h6);line-height:var(--leading-h6);text-align:center}
.prod .prod-narrow{max-width:880px;margin:0 auto}

/* ── The opening lede, in two columns ─────────────────────────
   Five paragraphs down one column run most of a screen before the page has
   shown anything else. Two columns put the whole definition in view on a
   laptop.

   column-count and not a grid: this is one continuous piece of prose, so
   letting it flow and balance itself keeps the two sides even without the
   markup having to decide where the break falls. */
.prod .prod-lede-cols{
  columns:2;
  column-gap:var(--space-16);
  text-align:left;
  /* Never one line of a paragraph alone at the foot or head of a column. */
  orphans:2;
  widows:2;
}
/* .prod .body caps every paragraph at 68ch, which is the right measure when a
   paragraph runs the full width of the page. Inside a 620px column the cap
   would bite before the column filled, leaving a ragged strip of white down the
   middle, so it is released — here only. At (0,3,0) against that rule's
   (0,2,0), so every other .body on this page and across line-of-credit keeps
   its measure untouched. */
.prod .prod-lede-cols .body{max-width:none; margin-bottom:var(--space-5)}
.prod .prod-lede-cols .body:last-child{margin-bottom:0}

/* One column below 1024. Two columns of the tablet width would be about 39
   characters each, under the 45 a line of prose needs to read as prose. */
@media (max-width:1023px){
  .prod .prod-lede-cols{columns:1}
}
.prod .prod-rel{position:relative}

/* The rules for the old nav.top and footer went with the markup they styled.
   They could not just be left behind:the bare `footer` selector kept matching
   once the shared .site-footer was injected, and the display:flex, padding and
   gap it carried are properties .site-footer does not declare, so they applied
   unopposed and laid the whole footer out as a single row. */

/* ── Hero · embedded widget variant ───────────────────────────────────
   The one the design system assigns to a product page: copy on the left, a
   conversion card on the right. A modifier and not a change to .hero, so the
   rest of the section keeps the single-column hero.

   The proportions (1.1 / 0.9) come from the guide. The card does not stretch
   vertically: align-items:center leaves it centred against the text block,
   which is
   mas alto. */
.prod .hero--widget .hero__grid{
  display:grid;
  grid-template-columns:1.2fr 0.8fr;
  gap:var(--space-16);
  /* end, not center: the copy and the panel are different heights, so centred
     they float against each other. Ended, they share a bottom edge. */
  align-items:end;
}
.prod .hero--widget .hero__copy{min-width:0}
/* The headline takes the h1pp step here rather than the h1 the rest of the
   hero uses: in two columns it has half the width and needs the weight to hold
   the fold. Size and leading are the same 68px, so the lines sit directly on
   one another - deliberate for a headline stacked this short, and the reason
   the cap below matters as much as the size does.

   10ch and 30ch are caps, not widths. The grid already decides how much room
   there is; these decide how much of it the text is allowed to use, so the
   headline stacks into short lines and the sub-line stays a readable measure
   beside it instead of running the full column. */
.prod .hero--widget .hero__copy h1{
  /* Size taken from the leading token, not the type token: both resolve to
     68px today, but this now follows the line-spacing scale rather than the
     size scale, so a change to one moves the other. */
  font-size:var(--leading-h1pp);
  line-height:var(--leading-h1pp);
  max-width:10ch;
}
.prod .hero--widget .hero__copy .sub{max-width:30ch}

/* Clear glass, not white. 10% white over a blurred backdrop, with the shape
   carried by the border rather than the fill. It depends entirely on what is
   behind it, and it is shared by two heroes. Since the scrim was lightened the
   worst pixel under the panel gives 4.97:1 on line-of-credit and 4.99:1 on
   merchant cash advance - still above the 4.5 white type needs, but only just.
   The scrim rule above carries the full figures and the reason there is so
   little room left. The brand blue is 2.03:1 on the same panel,
   which is why the label, the arrow and the focus ring turn white below. */
.prod .hero__widget{
  background:rgba(255,255,255,0.10);
  -webkit-backdrop-filter:blur(30px) saturate(135%) brightness(0.86);
  backdrop-filter:blur(30px) saturate(135%) brightness(0.86);
  border:1px solid rgba(255,255,255,0.45);
  border-radius:var(--radius-lg);
  padding:var(--space-8);
  box-shadow:var(--shadow-card);
  display:flex;
  flex-direction:column;
  gap:var(--space-3);
}
.prod .widget-label{
  margin:0;
  font-size:var(--type-xs);
  line-height:var(--leading-xs);
  letter-spacing:var(--tracking-eyebrow);
  text-transform:uppercase;
  font-weight:var(--weight-semibold);
  color:#FFFFFF;
}
/* The native select stays: it brings the operating system's picker, which on a
   phone is a comfortable wheel, and there is no keyboard or focus behaviour to
   reimplement. */
.prod .widget-select{
  width:100%;
  appearance:none;
  -webkit-appearance:none;
  background:transparent;
  border:0;
  border-bottom:2px solid var(--rule);
  padding:0 var(--space-6) var(--space-2) 0;
  font-family:inherit;
  font-size:var(--type-h4);
  font-weight:var(--weight-heavy);
  letter-spacing:var(--tracking-display);
  color:var(--ink);
  cursor:pointer;
}
.prod .widget-select:focus-visible{outline:2px solid #FFFFFF; outline-offset:3px}
/* The arrow is drawn by the wrapper: appearance:none takes the system's away,
   and a background-image on the select itself shifts when the text changes. */
.prod .widget-field{position:relative}
.prod .widget-field::after{
  content:'';
  position:absolute;
  right:2px; top:50%;
  width:9px; height:9px;
  margin-top:-9px;
  border-right:2px solid #FFFFFF;
  border-bottom:2px solid #FFFFFF;
  transform:rotate(45deg);
  pointer-events:none;
}
.prod .hero--widget .widget-go{width:100%; justify-content:center; margin-top:var(--space-2)}
.prod .widget-note{
  margin:0;
  font-size:var(--type-xs);
  line-height:var(--leading-xs);
  color:rgba(255,255,255,0.75);
}

/* Tablet and below: one column. The card goes under the copy — ahead of it,
   it would push the h1 off the first screen, which is what the hero exists to
   show. */
@media (max-width:1023px){
  /* minmax(0,1fr), not 1fr: a bare 1fr track never goes narrower than its
     widest content, and the amount input brings a native width of its own,
     so on a phone the column ran past the screen and cut the text. */
  .prod .hero--widget .hero__grid{grid-template-columns:minmax(0,1fr); gap:var(--space-10)}
  /* One column again, so the headline goes back to the hero's usual step and
     both measures widen: 10ch and 30ch are caps for a half-width column and
     would break the text into slivers across a phone. */
  .prod .hero--widget .hero__copy h1{
    font-size:var(--type-h1);
    line-height:var(--leading-h1);
    max-width:16ch;
  }
  .prod .hero--widget .hero__copy .sub{max-width:44ch}
}

/* Mobile: the height rule goes. Stacked, the content runs to around 830px and
   80vh reaches that on no phone, so the rule does nothing — but leaving it in
   reads to the next person as a promise the layout does not keep.
   Y en horizontal, 80vh son 312px: pedir eso no tiene sentido. */
@media (max-width:767px){
  .prod .hero{min-height:unset}
}

/* ── FAQ a dos columnas ────────────────────────────────────────────────────
   A grid and not `columns:2`: multicolumn splits an element across columns,
   and half a <details> cannot be salvaged; it also rebalances when one opens,
   so the questions jump around under the cursor. With grid each question is one
   cell and stays where it is.

   The flow is by rows: 1-2 on top, 3-4 below. That reads worse than by columns
   in a long list, but opening a question only grows its own row; with column
   flow both would grow at once. */
.prod .faq-grid{
  display:grid;
  grid-template-columns:1fr 1fr;
  column-gap:var(--space-16);
}
/* The <details> stretch to their row's height, which is what keeps the two
   columns' dividers aligned. Without this, an open question next to a closed
   one leaves the two rules at different heights. */
.prod .faq-grid > details{align-self:stretch; display:flex; flex-direction:column}

@media (max-width:1023px){
  .prod .faq-grid{grid-template-columns:1fr}
}

/* The answer's wrapper. overflow:hidden is what lets its height be animated
   without the text spilling out while it folds. The animation is driven by
   products.js and not a CSS transition: <details> does not render its content
   while closed, so there is no initial state to transition from on open, and no
   content to animate on close. The JS keeps the element open until the fold
   finishes. */
.prod .faq-body{overflow:hidden}

/* The curve is the system's — the same one the reveal uses in Motion. The
   duration is not: 0.9s is for a scroll entrance, which is watched; a
   disclosure is used, and at that speed it feels heavy. 280ms to open and 220
   to close, which is the usual pattern — closing is quicker because the reader
   has already seen the content. */
.prod [data-prod-accordion] > details .plus{transition:transform var(--motion-base) var(--ease-standard)}

@media (prefers-reduced-motion:reduce){
  .prod [data-prod-accordion] > details .plus{transition:none}
}

/* ── Feature card with photo ────────────────────────────────────
   The design system's t-card pattern: a full-bleed 3:4 photo, text laid over
   it, and a second state that replaces the note on hover.

   A modifier and not a change to .fcard: that class is shared with the
   Secured / Unsecured cards, which are text on a light ground and stay as
   they are.

   --radius-xl does not exist in the repo (the ladder is 4/8/10/999), so
   --radius-lg is used. Noted in the Cleanup list with the rest of the
   escala. */
.prod .fcard--photo{
  position:relative;
  aspect-ratio:3 / 4;
  border-radius:var(--radius-lg);
  overflow:hidden;
  background:var(--ink);
  border:0;
  padding:0;
  box-shadow:var(--shadow-card-sm);
}
.prod .fcard__img{
  position:absolute; inset:0;
  z-index:0;
  width:100%; height:100%;
  object-fit:cover;
  /* Placeholder until the photo lands: without it the slot is flat black and
     indistinguishable from an image that failed to load. */
  background:linear-gradient(160deg,#4b5563,#1c1917);
}
/* The veil is required, not decorative: the text is white over a photo we do
   not control, and without it the AA contrast fails the moment the image has a
   light patch where the text falls. The component's own entry in the guide
   says so.

   z-index matters here and its absence was a real bug. A pseudo-element is the
   first child of its box, and both this and .fcard__img are absolutely
   positioned; among positioned boxes at z-index auto the later one in tree
   order paints on top, so the photo was covering the veil entirely. Nobody saw
   it while the <img> was a 404, because what showed then was the dark
   placeholder gradient on .fcard__img. The day the real photos landed the text
   was sitting straight on them. Stated explicitly now: photo 0, veils 1, text 2.

   Two layers, because one cannot do both jobs. Whatever guarantees the CTA at
   the very bottom is exactly what must not move, so a single layer's hover is
   capped by its own darkest point — which is why lifting it read as nothing.

     ::before  the colour layer, over the whole card. Lifts to 22% on hover,
               which takes the veil at the top from 62% to 14% and is what lets
               the photograph come forward.
     ::after   a pad over the bottom fifth. Never moves. It is what holds the
               CTA once ::before is out of the way.

   Tinted with --ink-2 rather than pure black: the warm dark the hero and the
   final CTA already use, so the cards belong to the same surface family. At
   0.011 luminance it costs nothing in contrast.

   Measured across the four photos as delivered: title 5.21:1 against the 3.0
   large text needs, resting note 5.21:1 and hover CTA 5.61:1 against 4.5. */
.prod .fcard--photo::before{
  content:'';
  position:absolute; inset:0;
  z-index:1;
  pointer-events:none;
  background:linear-gradient(to bottom,
    rgba(28,25,23,.62) 0%,
    rgba(28,25,23,.62) 22%,
    rgba(28,25,23,0)   34%,
    rgba(28,25,23,0)   50%,
    rgba(28,25,23,.60) 72%,
    rgba(28,25,23,.70) 100%);
  transition:opacity var(--motion-base) var(--ease-standard);
}
.prod .fcard--photo::after{
  content:'';
  position:absolute; inset:0;
  z-index:1;
  pointer-events:none;
  background:linear-gradient(to top,
    rgba(28,25,23,.86) 0%,
    rgba(28,25,23,0)   22%);
}
.prod .fcard--photo:hover::before,
.prod .fcard--photo:focus-within::before{opacity:.22}
.prod .fcard__top{
  position:absolute; top:0; left:0; right:0;
  z-index:2;
  padding:var(--space-5) var(--space-5) 0;
  display:flex; align-items:center; gap:var(--space-2);
}
.prod .fcard--photo .fcard__top h3{margin:0; color:var(--white)}
.prod .fcard--photo .dot{background:var(--white)}

.prod .fcard__foot{
  position:absolute; left:0; right:0; bottom:0;
  z-index:2;
  padding:var(--space-5);
  min-height:96px;
}
.prod .fcard__rest, .prod .fcard__swap{transition:opacity var(--motion-base) var(--ease-standard), transform var(--motion-base) var(--ease-standard)}
.prod .fcard__note{
  margin:0;
  font-size:var(--type-xs);
  line-height:1.5;
  font-weight:var(--weight-semibold);
  color:var(--white);
  max-width:none;
}
.prod .fcard__swap{
  position:absolute;
  left:var(--space-5); right:var(--space-5); bottom:var(--space-5);
  opacity:0;
  transform:translateY(6px);
  pointer-events:none;
}
.prod .fcard__cta{
  display:inline-flex; align-items:center; gap:var(--space-1);
  font-size:var(--type-xs);
  font-weight:var(--weight-bold);
  color:var(--white);
  text-decoration:none;
}
.prod .fcard__cta svg{width:13px; height:13px; transition:transform var(--motion-fast) var(--ease-standard)}

/* :focus-within as well as :hover — otherwise the second state's CTA cannot be
   reached from the keyboard. The card carries tabindex so it can take focus. */
.prod .fcard--photo:hover .fcard__rest, .prod .fcard--photo:focus-within .fcard__rest{opacity:0}
.prod .fcard--photo:hover .fcard__swap, .prod .fcard--photo:focus-within .fcard__swap{opacity:1; transform:none; pointer-events:auto}
.prod .fcard--photo:hover .fcard__cta svg, .prod .fcard--photo:focus-within .fcard__cta svg{transform:translate(2px,-2px)}
.prod .fcard--photo:focus-visible{outline:2px solid var(--white); outline-offset:3px}

/* Touch: there is no real hover, so a finger would never see the CTA and the
   resting state would stay forever. Here both are shown at once — the note
   above and the CTA below — rather than hiding either.
   It is the accessibility rule the guide sets for this component. */
@media (hover:none){
  .prod .fcard__foot{
    display:flex; flex-direction:column; gap:var(--space-3);
    min-height:0;
  }
  .prod .fcard__swap{
    position:static;
    opacity:1;
    transform:none;
    pointer-events:auto;
  }
  /* With both stacked the foot grows and the text starts around 66% of the
     frame, above where the resting pad reaches. It extends up to meet it: two
     of the four photos measured 3.79 and 3.87:1 against the 4.5 needed, and
     land at 5.29 and above with this. ::before is untouched — it never lifts
     here, since there is no hover to lift it. */
  .prod .fcard--photo::after{
    background:linear-gradient(to top,
      rgba(28,25,23,.88) 0%,
      rgba(28,25,23,.58) 20%,
      rgba(28,25,23,0)   40%);
  }
  .prod .fcard--photo:hover .fcard__rest{opacity:1}
}

@media (prefers-reduced-motion:reduce){
  .prod .fcard--photo::before,
  .prod .fcard__rest, .prod .fcard__swap, .prod .fcard__cta svg{transition:none}
}

/* ── Text with a side image ──────────────────────────────────────────────
   7/5 of the twelve columns, the split the guide already documented.

   The prose stays in a single column. At 723px two columns would be 330 each,
   narrower than the reading measure, and .body already caps at 68ch, so it uses
   612 of those 723 and leaves the rest as air. */
.prod-aside-grid{
  display:grid;
  grid-template-columns:7fr 5fr;
  gap:var(--space-16);
  /* stretch and not start: that is what makes the figure take the row's
     height, which the text sets. */
  align-items:stretch;
  margin-top:var(--space-10);
}
/* 65/35 for section 04. The 7/5 above is section 01's, and everything else
   about the pattern is the same, so the ratio travels on a modifier rather than
   in a second grid. fr and not %: percentages would ignore the gap and the row
   would overflow by exactly its width. */
.prod-aside-grid--65-35{grid-template-columns:65fr 35fr}
/* The mirror: image first, text second, for a text-and-image section that
   follows another one. The figure comes first in the markup too, so on a
   phone, where the grid is one column, the image still leads. Declared
   before the one-column rule below so that rule still wins there. */
.prod-aside-grid--flip{grid-template-columns:5fr 7fr}
.prod-aside-grid__text{
  display:flex;
  flex-direction:column;
  gap:var(--space-6);
}
/* No aspect-ratio on purpose: the height comes from the row. With the current
   copy the slot is about 516 x 468 — nearly square, not portrait — and it
   changes on each product page with how long its text runs. The photo is
   cropped from the centre, so it is commissioned with margin to spare. */
.prod-aside-grid__media{
  position:relative;
  margin:0;
  height:100%;
  border-radius:var(--radius-xl);
  overflow:hidden;
  background:var(--ink-2);
  min-height:320px;
}
/* Absolute, so the photograph takes no part in the row's height: the text
   column sets it and the photo crops to fit. In flow, height:100% could not
   resolve against a figure with no height of its own, the img fell back to
   its intrinsic 2:3, and a tall master pushed the row past the text (775px of
   photo beside 452px of copy at 1920). Below 1024 the figure has its own
   16:9 aspect-ratio, so inset:0 still has a box to fill. */
.prod-aside-grid__media img{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
  display:block;
  /* Placeholder until the photo lands: without it the slot is a flat block,
     indistinguishable from an image that failed to load. */
  background:linear-gradient(160deg,#4b5563,var(--ink-2));
}

/* Tablet and below: the image drops underneath. It stays wider than it is tall
   there, because at full width a 4:5 would take nearly a whole screen before
   the text. */
@media (max-width:1023px){
  .prod-aside-grid{grid-template-columns:1fr; gap:var(--space-10)}
  /* Stacked there is no side text whose height to match, so here an
     aspect-ratio is needed or the figure collapses to its content's height. */
  .prod-aside-grid__media{aspect-ratio:16 / 9; min-height:0}
}

/* ── Single-column accordion ───────────────────────────────────────────────
   The FAQ's runs in two columns because its questions are short. This one
   carries paragraphs, lists and panels, so one column at full width. */
.prod-accordion{margin-left:auto; margin-right:auto}
.prod-accordion > details{border-bottom:1px solid var(--rule)}
.prod-accordion > details > summary{padding:var(--space-6) 0}
/* Each panel's content gets room underneath before the next rule. */
.prod-accordion .faq-body > *{padding-bottom:var(--space-10)}

/* The panel's own inset steps down with everything else. The 48 on each side
   is an indent: on desktop it sets the answer in from the question that opens
   it. On a phone that indent costs more than it says — at a 327px content
   width it left 231px for the text, which is under the reading measure — so
   below 768 it goes to zero and the answer uses the full column. The divider
   under each panel spans the same width either way, so nothing loses its
   alignment.

   Same steps as the page gutter: 48 → 32 → 0 across, 48 → 32 → 24 above. */
@media (max-width:1023px){
  .prod .prod-accordion > details > .faq-body{
    padding:var(--space-8) var(--space-8) var(--space-6);
  }
  .prod-accordion .faq-body > *{padding-bottom:var(--space-8)}
}
@media (max-width:767px){
  .prod .prod-accordion > details > .faq-body{
    padding:var(--space-6) 0 var(--space-4);
  }
  .prod-accordion .faq-body > *{padding-bottom:var(--space-6)}
}

/* ── Use cases, as a marquee ───────────────────────────────────
   The same mechanism as the careers benefits band, so the two read as one
   system rather than two takes on the same idea.

   max-content, not 200%: the track is exactly as wide as its two sets, whatever
   they measure, so the -50% in the keyframes always lands on the seam. */
.prod-marquee{position:relative; margin-top:var(--space-12); overflow:hidden}
.prod-marquee__track{
  display:flex;
  width:max-content;
  animation:prodMarquee 45s linear infinite;
}
.prod-marquee__set{display:flex; gap:var(--space-6); padding-right:var(--space-6)}
@keyframes prodMarquee{from{transform:translateX(0)} to{transform:translateX(-50%)}}

/* Three ways to stop it, one per modality: :hover for a mouse, :active for a
   finger, and .marquee-pause for a keyboard — which covers the other two as
   well, and is what WCAG 2.1.1 asks for once 2.2.2 requires the mechanism at
   all.

   :focus-within is deliberately NOT in this list. It was inert while .ucase
   held nothing focusable, and the pause button is what made it live. A button
   keeps focus after it is pressed, so :focus-within went on pinning paused
   after is-paused came off: Resume flipped the label and moved nothing until
   focus left the band. Same story in careers. */
.prod-marquee:hover .prod-marquee__track,
.prod-marquee:active .prod-marquee__track{animation-play-state:paused}

/* Fixed width, not a grid fraction: a marquee has no column count to divide,
   and a fixed card keeps one set comfortably wider than the container so the
   band is never showing empty track. 380 leaves about 31 characters a line
   once the padding is off, which is short but readable for one sentence. */
.prod-marquee .ucase{
  width:380px;
  flex-shrink:0;
  border:1px solid var(--border-default);
  border-radius:var(--radius-lg);
  background:var(--surface-card);
  padding:var(--space-8);
}
@media (max-width:767px){
  .prod-marquee .ucase{width:300px; padding:var(--space-6)}
}

@media (prefers-reduced-motion:reduce){
  /* Motion that starts on its own and never stops is exactly what this query
     exists for. Stopping the animation alone is not enough — the track would
     freeze mid-slide with most of the cards off the edge — so it reverts to the
     grid it replaced. The duplicate set goes with it, or the five use cases
     would read twice. */
  .prod-marquee{overflow:visible}
  .prod-marquee__track{animation:none; display:block; width:auto}
  .prod-marquee__set{
    display:grid;
    grid-template-columns:repeat(3, minmax(0, 1fr));
    gap:var(--space-6);
    padding-right:0;
  }
  .prod-marquee__set[aria-hidden="true"]{display:none}
  .prod-marquee .ucase{width:auto}
}
@media (prefers-reduced-motion:reduce) and (max-width:1023px){
  .prod-marquee__set{grid-template-columns:repeat(2, minmax(0, 1fr))}
}
@media (prefers-reduced-motion:reduce) and (max-width:640px){
  .prod-marquee__set{grid-template-columns:1fr}
}

/* The text block in the row above. The paragraphs cap themselves by measure,
   so all that is needed here is the vertical rhythm. */
.prod-stack{
  display:flex;
  flex-direction:column;
  gap:var(--space-6);
}

/* A use case's label. It was an <h3> at 28px, and the jump against a 20px body
   felt steep in a 242px column. Here the difference is carried by weight and
   colour, not size: the same tier as the paragraph, at 700 and in --ink.

   The <strong> inside contributes no styling — this rule does that — but the
   emphasis, so a screen reader also registers it as the label. */
.prod .ucase__label{
  margin:0;
  font-size:var(--type-base);
  line-height:var(--leading-base);
  letter-spacing:var(--tracking-tight);
  color:var(--ink);
}
.prod .ucase__label strong{font-weight:var(--weight-bold)}

/* ── Secured / Unsecured card icon ─────────────────────────────
   One closed padlock and one open: the pair reads without a caption, because
   the difference between the two options is precisely whether something is
   locked.

   The animation moves only the shackle, which is the part that means
   something. Scaling or spinning the whole icon would be decoration, and the
   guide asks for the opposite. */
.prod .fcard__icon{
  width:44px; height:44px;
  flex-shrink:0;
  border-radius:var(--radius-lg);
  background:var(--white);
  color:var(--c-700);
  display:flex; align-items:center; justify-content:center;
  margin-bottom:var(--space-2);
  transition:background var(--motion-base) var(--ease-standard),
             color var(--motion-base) var(--ease-standard);
}
.prod .fcard__icon svg{width:22px; height:22px; display:block}
/* transform-box:fill-box so the shackle's transform is measured against its
   own box and not against the whole SVG canvas. */
.prod .fcard__shackle{
  transform-box:fill-box;
  transform-origin:center bottom;
  transition:transform var(--motion-base) var(--ease-standard);
}
/* Hover tints the box. c-100 against the card gives 1.12:1: the change is
   noticeable without shouting. */
.prod .fcard:hover .fcard__icon,
.prod .fcard:focus-within .fcard__icon{
  background:var(--brand-soft-line);
  color:var(--c-600);
}
.prod .fcard:hover .fcard__shackle,
.prod .fcard:focus-within .fcard__shackle{transform:translateY(-2px)}

@media (prefers-reduced-motion:reduce){
  .prod .fcard__icon,
  .prod .fcard__shackle{transition:none}
}


/* ── Small screens: one gutter, not five ───────────────────────────────
   Every horizontal inset on this page was a fixed pixel value that never
   stepped down, and most sections apply two of them: the section's own padding
   and the .wrap inside it. On a 375px phone that added up to:

     .prod-band--pad + .wrap    96 + 48 a side  →   87px of content
     #apply’s banner            112 margin + 32 →   87px
     section.pad + .wrap        48 + 48         →  183px
     .hero + .wrap              48 + 48         →  183px
     .prod-band--pad-top        96 (no .wrap)   →  183px

   87px is not just cramped, it overflows: .grid4 declares minmax(220px, 1fr),
   so its track stays 220px wide inside an 87px box and the page scrolls
   sideways.

   From 1023 down the gutter belongs to .wrap alone and the sections keep only
   their vertical rhythm. The two that hold no .wrap — the lede band and the
   CTA banner — carry the same value themselves, so the whole page lines up on
   one edge at every width. The steps follow careers.css, which solved this for
   its own .container: 96/64 → 72/40 → 56/24.

   On a 375px screen the content is 327px wide everywhere now. */
@media (max-width:1023px){
  .prod .wrap{padding:0 var(--space-8)}
  .prod .hero{padding:calc(var(--site-nav-h, 80px) + var(--space-8)) 0 var(--space-18)}
  .prod section.pad{padding:var(--space-18) 0}
  .prod .prod-band--pad{padding:var(--space-18) 0}
  .prod .prod-band--pad-top{padding:var(--space-18) var(--space-8) var(--space-12)}
  .prod .prod-cta{margin:var(--space-18) var(--space-8) 0}

  /* Two columns declared, not left to auto-fit. At this gutter the track maths
     happens to give three, which would leave the fourth card orphaned on a row
     of its own; four cards want 2x2. */
  .prod .grid4{grid-template-columns:repeat(2, minmax(0, 1fr))}
}
@media (max-width:767px){
  .prod .wrap{padding:0 var(--space-6)}
  .prod .hero{padding:calc(var(--site-nav-h, 80px) + var(--space-6)) 0 var(--space-14)}
  .prod section.pad{padding:var(--space-14) 0}
  .prod .prod-band--pad{padding:var(--space-14) 0}
  .prod .prod-band--pad-top{padding:var(--space-14) var(--space-6) var(--space-10)}
  .prod .prod-cta{margin:var(--space-14) var(--space-6) 0}
}

/* The cards hold two columns as far down as 640, and only go single below it.
   In one column the card is as wide as the gutter allows: at a 767px viewport
   that is 719px across and 959 tall on a 3:4 photo — nearly a whole screen per
   card, and it forces a master image wider than anything else on the page
   needs. Two columns cap it at 350 through that band. 640 is the step careers
   .css already uses, so this adds no new breakpoint. */
@media (max-width:640px){
  .prod .grid4{grid-template-columns:1fr}
}

/* ── Marquee pause control ──────────────────────────────────────
   Hidden until it takes focus, the way a skip link is. A mouse already pauses
   the band by hovering and a finger by holding, so the keyboard is the only
   modality that was without a mechanism — and the only one that needs a
   control. This way nobody else carries a button they will never press.

   Not display:none, which cannot be focused and so would hide the control from
   the very people it exists for. The clip technique keeps it in the tree and in
   the tab order while taking it out of the picture.

   It reveals over the band rather than pushing it down: the container clips its
   overflow, so a control that appeared in normal flow would shift every card
   the moment someone tabbed to it. */
.marquee-pause{
  position:absolute;
  width:1px; height:1px;
  margin:-1px; padding:0; border:0;
  overflow:hidden;
  clip-path:inset(50%);
  white-space:nowrap;
}
.marquee-pause:focus{
  width:auto; height:auto;
  margin:0;
  clip-path:none;
  top:var(--space-2); left:var(--space-2);
  z-index:3;
  padding:var(--space-2) var(--space-4);
  border-radius:var(--radius-pill);
  background:var(--ink);
  color:var(--white);
  font-family:var(--font-sans);
  font-size:var(--type-xs);
  font-weight:var(--weight-semibold);
  line-height:1;
  cursor:pointer;
  outline:2px solid var(--c-600);
  outline-offset:2px;
}

@media (prefers-reduced-motion:reduce){
  /* The band is a static grid here, so there is no motion to stop and the
     control would be a tab stop that does nothing. */
  .marquee-pause{display:none}
}
.prod-marquee.is-paused .prod-marquee__track{animation-play-state:paused}

/* ── Feature split — two mixed columns ──────────────────────
   Each column holds a photograph and two cards, and the photographs sit at
   opposite ends so the two sides read as one arrangement rather than a mirror.

   Nothing stretches. A 3:2 shot at a 642px column is 428 tall, and two cards
   with the gap between them come to 336, so each side lands at 784 on its own.
   align-items is start and not stretch for that reason: if the two ever do
   drift apart — a longer note, a wider card — the shorter column should end
   where its content ends instead of a card growing to cover the difference.

   The chip on each card still comes from the homepage's #security band: 52px on
   --c-50 carrying a 22px glyph in --c-600, which careers' .benefit-icon already
   copies. That part of the pattern did not change with the layout. */
.prod .prod-feature-split{
  display:grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:var(--space-5);
  align-items:start;
}
/* One gap value in both directions — between the columns, and between the
   pieces inside each column — so the four cards and the two photographs sit on
   a single rhythm instead of three competing ones. */
.prod .prod-feature-split__col{
  display:flex;
  flex-direction:column;
  gap:var(--space-5);
}
/* 3:2 rather than 16:9: both masters were shot 3:4 portrait, so any landscape
   crop takes a band out of the middle and loses the top and the bottom. 3:2
   keeps more of the frame than 16:9 would. Worth checking each photograph still
   reads once cropped — a subject sitting high or low in the original is gone. */
.prod .prod-feature-split__shot{
  margin:0;
  border-radius:var(--radius-xl);
  overflow:hidden;
  background:var(--ink-2);
  aspect-ratio:3 / 2;
}
.prod .prod-feature-split__shot img{
  width:100%; height:100%;
  object-fit:cover;
  display:block;
}

/* The list. gap rather than margins on the items, so adding or removing one
   needs no :first-child or :last-child exception.

   A plain column again: the four equal rows it used to carry were there to make
   one list fill the height of one tall photograph, and neither of those exists
   now. Two cards to a list, and the column's own gap places them. */
.prod .prod-featlist{
  display:flex;
  flex-direction:column;
  gap:var(--space-5);
  margin:0;
  padding:0;
  list-style:none;
}
/* One column since the icon chip was removed. Left as a grid rather than
   reverted to block: gap and align-content are what space the card, and
   swapping the layout model to save a declaration would move everything. */
.prod .prod-feat{
  display:grid;
  grid-template-columns:1fr;
  gap:var(--space-5);
  align-items:start;
  align-content:start;
  padding:var(--space-6);
  border:1px solid var(--border-default);
  border-radius:var(--radius-2xl);
  background:var(--surface-card);
}
/* A fixed width is what keeps the chip square: the grid column is 52px and
   align-items:start stops it stretching to the row's height. */

.prod .prod-feat__title{
  margin:0;
  font-size:var(--type-base);
  line-height:var(--leading-base);
  font-weight:var(--weight-bold);
  letter-spacing:var(--tracking-tight);
  color:var(--ink);
}
/* Base S, the 16px prose tier. The note is supporting copy beside a title at
   20, which is what that tier exists for.

   padding is zeroed on purpose: inside an accordion panel `.prod details p`
   gives every paragraph 24px underneath, and a card's note would carry it,
   leaving more room below the copy than above it. */
.prod .prod-feat__note{
  margin:var(--space-2) 0 0;
  padding:0;
  font-size:var(--type-base-sm);
  line-height:var(--leading-base-sm);
  color:var(--coffee);
  max-width:none;
}
.prod .prod-feat__cta{
  display:inline-flex; align-items:center; gap:var(--space-2);
  margin-top:var(--space-3);
  font-size:var(--type-sm);
  line-height:var(--leading-sm);
  font-weight:var(--weight-bold);
  color:var(--c-600);
  text-decoration:none;
}
.prod .prod-feat__cta svg{
  width:14px; height:14px;
  transition:transform var(--motion-fast) var(--ease-standard);
}
.prod .prod-feat__cta:hover{color:var(--c-700); text-decoration:underline}
.prod .prod-feat__cta:hover svg{transform:translate(2px,-2px)}
.prod .prod-feat__cta:focus-visible{
  outline:2px solid var(--c-600);
  outline-offset:3px;
  border-radius:var(--radius-sm);
}
@media (prefers-reduced-motion:reduce){
  .prod .prod-feat__cta svg{transition:none}
}

/* One column below 1024. The six pieces then read in markup order — photograph,
   Revolving, Scaling, Funds, No hidden fees, photograph — which still alternates
   picture and cards rather than stacking all four cards in a row. The gap is the
   same var(--space-5) it is everywhere else, so nothing needs saying here. */
@media (max-width:1023px){
  .prod .prod-feature-split{grid-template-columns:1fr}
}

/* The split with ruled rows instead of cards (business loans, "The Cardiff
   way"): the points lose the card's frame, fill and padding, and a --rule
   line separates each from the next; none above the first or below the last.
   Without card edges to separate the two columns, the gap between them opens
   to 48px.

   The columns stretch to one height, and the photograph marked --grow (put
   it in the shorter column) takes up whatever its column is short of: it keeps its 3:2 as a minimum and
   grows from there, so both columns end on the same line. One column below
   1024, where there is no neighbour to match and it stays 3:2. */
.prod .prod-feature-split--ruled{
  align-items:stretch;
  column-gap:var(--space-12);
}
.prod .prod-feature-split--ruled .prod-feature-split__shot--grow{flex:1 1 auto}
.prod .prod-feature-split--ruled .prod-featlist{gap:0}
.prod .prod-feature-split--ruled .prod-feat{
  padding:var(--space-6) 0;
  border:0;
  border-radius:0;
  background:none;
}
.prod .prod-feature-split--ruled .prod-feat + .prod-feat{border-top:1px solid var(--rule)}
.prod .prod-feature-split--ruled .prod-featlist > .prod-feat:first-child{padding-top:0}
.prod .prod-feature-split--ruled .prod-featlist > .prod-feat:last-child{padding-bottom:0}
@media (max-width:640px){
  .prod .prod-feat{gap:var(--space-4); padding:var(--space-5)}
    }

/* The same cards laid across instead of down, for a short set that is read
   side by side (MCA's three kinds of working capital). Grid rows stretch, so
   the three cards share one height whatever their copy runs to. One column
   from 1080 down: below it the accordion's inset leaves each of three columns
   about 200px, under the width a 16px note can be read at. */
.prod .prod-featlist--row{
  display:grid;
  grid-template-columns:repeat(3, minmax(0, 1fr));
}
@media (max-width:1080px){
  .prod .prod-featlist--row{grid-template-columns:1fr}
}

/* ── Requirements table ────────────────────────────────────────────────────
   Starts from the guide's data table (Components → Data) and strips it back to
   its rules: no outer frame, no row tint, only the lines between rows. The
   table sits inside an accordion panel that is already framed by its own
   dividers, so a second box would nest one frame in another.

   Cells run at Base S (16/22), the size of the card notes beside it, rather
   than the guide's 14, because this table is prose, not figures. Row titles
   are <th scope="row"> in ink, so each reads as the label of its line to a
   screen reader as well as to the eye.

   The column heads are badges: the guide's pill on a --c-100 fill, at a
   height taken from the scale, not built from padding. The head row carries
   no rule of its own; the first line is the one between the first two rows. */
.prod .prod-table{
  width:100%;
  /* An accordion panel gives each child 40px underneath; on a separate-border
     table that padding would land under the last row. The 24 on top is extra
     air between the introducing line and the badges. */
  padding:var(--space-6) 0 0;
  border-collapse:separate;
  border-spacing:0;
  font-size:var(--type-base-sm);
  line-height:var(--leading-base-sm);
}
.prod .prod-table th,
.prod .prod-table td{
  padding:var(--space-8) var(--space-6);
  text-align:left;
  vertical-align:top;
  border-bottom:1px solid var(--rule);
}
.prod .prod-table tbody tr:last-child > *{border-bottom:none}
.prod .prod-table thead th{padding-top:0; padding-bottom:var(--space-4); border-bottom:none}
.prod .prod-table__badge{
  display:inline-flex;
  align-items:center;
  height:var(--space-7);
  padding:0 var(--space-3);
  border:1px solid var(--rule);
  border-radius:var(--radius-pill);
  background:var(--c-100);
  font-size:var(--type-xs);
  line-height:var(--leading-xs);
  font-weight:var(--weight-semibold);
  color:var(--coffee);
  white-space:nowrap;
}
.prod .prod-table tbody th{
  width:30%;
  font-weight:var(--weight-bold);
  color:var(--ink);
}
.prod .prod-table td{color:var(--coffee)}
/* The line that introduces the table sits close to it: the panel's own 40px
   between children is the gap, without the paragraph's 24 added on top. */
.prod .prod-table-intro > p:last-child{padding-bottom:0}

/* On a phone two columns leave the answer about 190px, so each row stacks:
   its title, then its answer. The header row would then label nothing, so it
   goes, visually only; a screen reader still gets the table's structure. */
@media (max-width:640px){
  .prod .prod-table thead{
    position:absolute; width:1px; height:1px; overflow:hidden;
    clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap;
  }
  .prod .prod-table tbody th,
  .prod .prod-table td{display:block; width:auto}
  .prod .prod-table tbody th{padding-bottom:0; border-bottom:none}
  .prod .prod-table td{padding-top:var(--space-1)}
}

/* ── Ruled list ────────────────────────────────────────────────────────────
   The bulleted list with a line between items, for a sequence of steps set
   beside the checklist: the two columns then share one rhythm of rules. The
   list's gap becomes each item's padding, so the line sits midway between
   two items; none above the first or below the last. --rule here, not the
   checklist's blue, because this list sits on paper, not on the tinted card. */
/* The rules stop where the text does: each item's text caps at 68ch, so the
   list is capped at the same 68ch plus the 7px dot and its gap. font-size is
   set on the list only so that its ch is the items' ch (the spans run at
   --type-base); nothing in the list inherits it visibly. In a column narrower
   than that, as on MCA, the cap never bites. */
.prod .list--ruled{
  gap:0;
  font-size:var(--type-base);
  max-width:calc(68ch + 7px + var(--space-3));
}
.prod .list--ruled > .li{padding:var(--space-4) 0}
.prod .list--ruled > .li + .li{border-top:1px solid var(--rule)}
.prod .list--ruled > .li:first-child{padding-top:0}
.prod .list--ruled > .li:last-child{padding-bottom:0}

/* ── Checklist ─────────────────────────────────────────────────────────────
   A list of things to have ready, each marked done rather than bulleted: a
   check in a round chip, with a line between items and none above the first
   or below the last. On the tinted card the chip and the lines take the
   card's own border colour (--brand-soft-line), so nothing new enters the
   palette. The chip centres on the first line of its item, not on the whole
   item, so a label that wraps keeps its check beside its opening words. */
.prod .prod-checklist{
  margin:var(--space-4) 0 0;
  padding:0;
  list-style:none;
}
.prod .prod-checklist > li{
  display:flex;
  align-items:flex-start;
  gap:var(--space-4);
  padding:var(--space-4) 0;
  font-size:var(--type-base-sm);
  line-height:var(--leading-base-sm);
  font-weight:500;
  color:var(--ink);
}
.prod .prod-checklist > li + li{border-top:1px solid var(--brand-soft-line)}
.prod .prod-checklist > li:last-child{padding-bottom:0}
.prod .prod-checklist__icon{
  flex:none;
  display:grid;
  place-items:center;
  width:var(--space-6);
  height:var(--space-6);
  margin-top:calc((var(--leading-base-sm) - var(--space-6)) / 2);
  border-radius:var(--radius-full);
  background:var(--brand-soft-line);
  color:var(--c-600);
}
.prod .prod-checklist__icon svg{width:14px; height:14px}

/* ── Card plans ────────────────────────────────────────────────────────────
   Business credit cards: the two cards the page offers, side by side as two
   tinted panels, each a title over a checklist of its terms. Two equal
   columns because the two lists are compared line by line (five of their six
   lines are the same), one column below 768. The title keeps the source's h2;
   it is styled as a panel title, not as a section heading. */
.prod .prod-plans{
  display:grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:var(--space-6);
}
@media (max-width:767px){
  .prod .prod-plans{grid-template-columns:1fr}
}
.prod .prod-plan__title{
  margin:0 0 var(--space-2);
  font-size:var(--type-h5);
  line-height:var(--leading-h5);
  font-weight:var(--weight-bold);
  letter-spacing:var(--tracking-tight);
  color:var(--ink);
}

/* A block as wide as the CTA banner: the banner has no max-width and sits
   112px in from each edge (32 below 1024, 24 below 768), so a section that
   has to line up with it takes the same margins instead of .wrap, whose
   1400px cap and 48px gutter would not match. Its section drops the side
   padding with .prod-flush-x. */
.prod .prod-cta-width{margin-inline:var(--space-28)}
.prod section.prod-flush-x{padding-left:0; padding-right:0}
@media (max-width:1023px){
  .prod .prod-cta-width{margin-inline:var(--space-8)}
}
@media (max-width:767px){
  .prod .prod-cta-width{margin-inline:var(--space-6)}
}

/* ── Product hub ───────────────────────────────────────────────────────────
   Business loans: one card per product, all five in one row, three from 1279
   down, two below 1024, one on a phone. Each card is the prod-feat card, and the whole card is the
   link: the title's <a> stretches an ::after over the card, so there is one
   target and one link per product for a screen reader, named by its title,
   with no second "learn more" link to announce. The arrow is the same one the
   feature cards' links carry. Focus shows on the card, since the link's own
   box is only the title. */
.prod .prod-hub{
  display:grid;
  grid-template-columns:repeat(5, minmax(0, 1fr));
  gap:var(--space-5);
  margin:0;
  padding:0;
  list-style:none;
}
@media (max-width:1279px){
  .prod .prod-hub{grid-template-columns:repeat(3, minmax(0, 1fr))}
}
@media (max-width:1023px){
  .prod .prod-hub{grid-template-columns:repeat(2, minmax(0, 1fr))}
}
@media (max-width:640px){
  .prod .prod-hub{grid-template-columns:1fr}
}
.prod .prod-hub__card{
  position:relative;
  transition:border-color var(--motion-fast) var(--ease-standard),
             box-shadow var(--motion-fast) var(--ease-standard);
}
/* flex-start and a top margin rather than center: when a title wraps, the
   arrow stays beside its first line instead of floating to the middle. The
   margin is the title's line box less the 16px icon, halved. */
.prod .prod-hub__link{
  display:inline-flex;
  align-items:flex-start;
  gap:var(--space-2);
  color:inherit;
  text-decoration:none;
}
.prod .prod-hub__link::after{
  content:"";
  position:absolute;
  inset:0;
  border-radius:inherit;
}
.prod .prod-hub__link svg{
  width:16px; height:16px;
  flex:none;
  margin-top:calc((var(--leading-base) - 16px) / 2);
  color:var(--c-600);
  transition:transform var(--motion-fast) var(--ease-standard);
}
.prod .prod-hub__card:hover{border-color:var(--c-100); box-shadow:var(--shadow-card-sm)}
.prod .prod-hub__card:hover .prod-hub__link svg{transform:translate(2px,-2px)}
.prod .prod-hub__link:focus-visible{outline:none}
.prod .prod-hub__card:focus-within{outline:2px solid var(--c-600); outline-offset:3px}
@media (prefers-reduced-motion:reduce){
  .prod .prod-hub__card,
  .prod .prod-hub__link svg{transition:none}
}

/* A plan panel on white instead of the brand tint, to set one card apart
   from its neighbour. The border drops to the neutral card border, since the
   tint's blue edge would outline a panel that is no longer blue. The
   checklist inside keeps its blue chips and rules. */
.prod .prod-plan--white{
  background:var(--surface-card);
  border-color:var(--border-default);
}

/* On a tinted plan panel the check chips go white: the same --c-100 chip on
   a --c-50 panel barely separates, and white lifts each check off the tint.
   The white panel keeps its blue chips, so the two cards invert each other.
   Scoped to plan panels: MCA's documents checklist sits in a tinted panel
   too and keeps its blue chips. */
.prod .prod-plan:not(.prod-plan--white) .prod-checklist__icon{background:var(--white)}

/* ── Steps with a phone ────────────────────────────────────────────────────
   The homepage's "how" cards (site.css .phone-stage / .phone-tilt /
   .phone-float), rebuilt on this sheet's tokens so a product page can carry
   them without the homepage's Tailwind. Every value is the homepage's: a
   24px-radius white card, a 360px stage with a 300px phone (280 below 640)
   cut off at the bottom by a white fade, a 48px blue disc for the number,
   the phone floating +-5px over 5.2s, and on hover a 4px lift with a 7deg /
   -3deg tilt in 1400px perspective.

   Three across from 1024; below that one column, each card capped at 408px
   and centred, the width the homepage gives its single card. */
.prod .prod-steps{
  display:grid;
  grid-template-columns:repeat(3, minmax(0, 1fr));
  gap:var(--space-10);
  margin:0;
  padding:0;
  list-style:none;
}
@media (max-width:1023px){
  .prod .prod-steps{grid-template-columns:minmax(0, 408px); justify-content:center; gap:var(--space-8)}
}
.prod .prod-step{
  display:flex;
  flex-direction:column;
  height:100%;
  padding:var(--space-10) var(--space-6) var(--space-7);
  border:1px solid var(--rule);
  border-radius:var(--radius-2xl);
  background:var(--surface-card);
}
.prod .prod-step__stage{
  position:relative;
  height:360px;
  margin-bottom:var(--space-6);
  perspective:1400px;
}
.prod .prod-step__phone{
  position:absolute;
  inset:auto 0 0 0;
  display:flex;
  justify-content:center;
  transform-style:preserve-3d;
  transition:transform .55s var(--ease-standard);
}
.prod .prod-step:hover .prod-step__phone{transform:translateY(-4px) rotateY(7deg) rotateX(-3deg)}
.prod .prod-step__device{
  position:relative;
  width:300px;
  aspect-ratio:9 / 11;
  padding:5px 5px 0;
  border-radius:58px 58px 0 0;
  background:var(--ink);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,0.06), inset 0 1px 0 0 rgba(255,255,255,0.12);
}
.prod .prod-step__screen{
  position:relative;
  height:100%;
  padding-top:44px;
  border-radius:54px 54px 0 0;
  overflow:hidden;
  background:var(--white);
}
.prod .prod-step__screen img{display:block; width:100%; height:auto}
.prod .prod-step__notch{
  position:absolute;
  top:10px; left:50%;
  width:88px; height:26px;
  transform:translateX(-50%);
  border-radius:var(--radius-pill);
  background:#000;
}
.prod .prod-step__notch::after{
  content:"";
  position:absolute;
  top:50%; right:8px;
  width:6px; height:6px;
  transform:translateY(-50%);
  border-radius:var(--radius-full);
  background:#262626;
}
.prod .prod-step__fade{
  position:absolute;
  inset:auto 0 0 0;
  height:60px;
  background:linear-gradient(rgba(255,255,255,0) 0%, rgba(255,255,255,0.55) 45%, #FFFFFF 100%);
  pointer-events:none;
}
.prod .prod-step__num{
  position:absolute;
  top:var(--space-2); right:var(--space-2);
  display:flex;
  align-items:center;
  justify-content:center;
  width:48px; height:48px;
  border-radius:var(--radius-full);
  background:var(--c-600);
  color:var(--white);
  font-size:17px;
  font-weight:var(--weight-heavy);
  letter-spacing:var(--tracking-display);
  box-shadow:0 18px 36px -14px rgba(37,99,235,0.6);
}
.prod .prod-step__label{
  margin:var(--space-2) 0 0;
  font-size:var(--type-xs);
  line-height:var(--leading-xs);
  letter-spacing:var(--tracking-eyebrow);
  text-transform:uppercase;
  font-weight:var(--weight-semibold);
  color:var(--mute);
}
.prod .prod-step__title{
  margin:var(--space-4) 0 0;
  font-size:var(--type-h5);
  line-height:1.2;
  font-weight:var(--weight-heavy);
  letter-spacing:var(--tracking-display);
  color:var(--ink);
}
.prod .prod-step__note{
  flex:1;
  margin:var(--space-4) 0 0;
  font-size:var(--type-base-sm);
  line-height:var(--leading-base-sm);
  color:var(--coffee);
  text-wrap:pretty;
}
@media (max-width:640px){
  .prod .prod-step__device{width:280px}
  .prod .prod-step__stage{height:320px}
}
@media (prefers-reduced-motion:no-preference){
  /* In step, as on the homepage: the three phones rise and fall together. */
  .prod .prod-step__float{animation:ucaseFloat 5.2s var(--ease-smooth) infinite}
}
@media (prefers-reduced-motion:reduce){
  .prod .prod-step__phone{transition:none}
  .prod .prod-step:hover .prod-step__phone{transform:none}
}

/* A panel's prose, when it carries a paragraph rather than a checklist
   (equipment leasing's two structures). Base S, the card-note tier, in
   coffee under an ink title. */
.prod .prod-plan__note{
  margin:0;
  font-size:var(--type-base-sm);
  line-height:var(--leading-base-sm);
  color:var(--coffee);
  max-width:none;
}

/* The requirements table without its head row, for a list of features whose
   titles label themselves. Every rule is the prod-table's; only the first row
   loses the space the missing head row would have left above it. */
.prod .prod-table--rows{padding-top:0}

/* A table with an image beside it, 30/70: the figure in the narrow column
   takes the table's height (stretch), which the rows set. fr, not %, so the
   gap does not push the row past the wrap. One column below 1024, where the
   side-image slot's own rule gives the figure 16:9. */
.prod .prod-table-media{
  display:grid;
  grid-template-columns:3fr 7fr;
  gap:var(--space-10);
  align-items:stretch;
  margin-top:var(--space-12);
}
@media (max-width:1023px){
  .prod .prod-table-media{grid-template-columns:1fr}
}

/* Three images in the side column of a text-and-image section, instead of
   one: stacked, sharing the row's height equally, which the text sets. Below
   1024, where the grid stacks and there is no text beside them to take a
   height from, they sit in a row of three at 4:3. */
.prod .prod-media-stack{
  display:grid;
  grid-template-rows:repeat(3, minmax(0, 1fr));
  gap:var(--space-5);
  height:100%;
  min-height:480px;
}
.prod .prod-media-stack__item{
  position:relative;
  margin:0;
  min-height:0;
  border-radius:var(--radius-xl);
  overflow:hidden;
  background:var(--ink-2);
}
/* Absolute for the same reason as the side image above: in flow, a square
   master's intrinsic height fed back into the stack and the row. */
.prod .prod-media-stack__item img{position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block}
@media (max-width:1023px){
  .prod .prod-media-stack{
    grid-template-rows:none;
    grid-template-columns:repeat(3, minmax(0, 1fr));
    height:auto;
    min-height:0;
  }
  .prod .prod-media-stack__item{aspect-ratio:4 / 3}
}
/* Two images centred on the text beside them rather than stretched to its
   height (equipment leasing, "Who it suits"): each keeps 4:3, the pair sits
   at the vertical middle of the row. Below 1024 they sit side by side. */
.prod .prod-media-stack--centered{
  grid-template-rows:none;
  height:auto;
  min-height:0;
  align-self:center;
}
.prod .prod-media-stack--centered .prod-media-stack__item{aspect-ratio:4 / 3}
@media (max-width:1023px){
  .prod .prod-media-stack--centered{grid-template-columns:repeat(2, minmax(0, 1fr))}
}

/* Two instead of three: halves of the column, and a row of two below 1024. */
.prod .prod-media-stack--2{grid-template-rows:repeat(2, minmax(0, 1fr)); min-height:320px}
@media (max-width:1023px){
  .prod .prod-media-stack--2{grid-template-rows:none; grid-template-columns:repeat(2, minmax(0, 1fr))}
}

/* A figure still waiting for its photograph. The same dashed, striped slot the
   use-case cards use, so a missing image reads as pending and not as broken;
   no <img> goes in until the file exists. Two background declarations for the
   same reason as there: a browser that cannot parse color-mix() drops the
   whole declaration, base colour included. */
.prod .prod-aside-grid__media[data-placeholder],
.prod .prod-feature-split__shot[data-placeholder],
.prod .prod-media-stack__item[data-placeholder]{
  border:1px dashed var(--border-default);
  background:var(--paper);
  background:
    repeating-linear-gradient(45deg,
      transparent 0 10px,
      color-mix(in srgb, var(--rule) 45%, transparent) 10px 20px),
    var(--paper);
}

/* The select's own text, and the list the operating system draws for it. Some
   platforms paint that popup with the select's colours, and white on a
   transparent panel would be an empty menu, so the options keep their own. */
.prod .hero__widget .widget-select{color:#FFFFFF; background:transparent}
.prod .hero__widget .widget-select option{color:var(--ink); background:var(--white)}

/* Without backdrop-filter the whole declaration is dropped, veil included, and
   the white type would sit on a pale wash. The fallback darkens instead. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .prod .hero__widget{background:rgba(15,23,42,0.55)}
}

/* ---- Docked amount widget ---------------------------------------------
   The hero panel again, kept within reach once the hero has scrolled away.
   [data-qs-docked] already carries display:none with a flex column above
   1024px, so this is desktop-only without restating it.

   A dark tint rather than the clear fill: fixed to the viewport, it crosses
   light and dark sections alike and cannot rely on what is behind it. Wider
   than the homepage's card because it holds a select, not a number. */
.prod .prod-dock{
  position:fixed; right:24px; bottom:24px; z-index:50; width:268px;
  gap:var(--space-3);
  padding:var(--space-6);
  border-radius:var(--radius-lg);
  background:rgba(15,23,42,0.55);
  -webkit-backdrop-filter:blur(30px) saturate(135%) brightness(0.86);
  backdrop-filter:blur(30px) saturate(135%) brightness(0.86);
  border:1px solid rgba(255,255,255,0.45);
  box-shadow:0 40px 70px -22px rgba(15,23,42,0.45),
             0 18px 36px -14px rgba(15,23,42,0.25);
  opacity:0; transform:translateY(12px); pointer-events:none;
  transition:opacity .25s, transform .25s;
}
.prod .prod-dock.is-in{opacity:1; transform:translateY(0); pointer-events:auto}
.prod .prod-dock .widget-select{color:#FFFFFF; background:transparent}
.prod .prod-dock .widget-select option{color:var(--ink); background:var(--white)}
.prod .prod-dock .widget-go{width:100%; justify-content:center; margin-top:var(--space-2)}
@media (prefers-reduced-motion: reduce){
  .prod .prod-dock{transition:none}
}

/* ---- The amount as a field ---------------------------------------------
   The rule beneath the figure is the control: no box, no fill, just the line,
   which is what the glass panel can carry without turning into a form. The
   arrow belongs to the select variant and is taken off here.

   font-size is set in px rather than from a --type token because this is a
   figure to be read at a glance, not body copy, and it matches the 26px the
   same widget uses on the homepage. */
.prod .widget-field--amount{
  display:flex; align-items:baseline; gap:6px;
  padding-bottom:3px;
  border-bottom:2px solid rgba(255,255,255,0.45);
  transition:border-color .2s;
}
.prod .widget-field--amount::after{content:none}
.prod .widget-field--amount:focus-within{border-bottom-color:#FFFFFF}
.prod .widget-currency{
  font-size:26px; line-height:1;
  font-weight:var(--weight-heavy);
  color:#FFFFFF;
}
/* width:0 drops the input's native width (about 20 characters), so flex
   sizes it from the room the field has rather than from that default. */
.prod .widget-input{
  flex:1 1 auto; min-width:0; width:0;
  padding:0; border:0; outline:none; background:transparent;
  font-family:inherit; font-size:26px; line-height:1.15;
  font-weight:var(--weight-heavy);
  letter-spacing:var(--tracking-display);
  color:#FFFFFF;
}
.prod .widget-input::placeholder{color:rgba(255,255,255,0.55)}
/* The panel already shows a focus ring on the rule above; a second outline on
   the input inside it reads as two controls. */
.prod .widget-input:focus-visible{outline:none}

/* ---- Scroll reveal ------------------------------------------------------
   Documented in the design system under Motion, and driven by reveal.js. The
   group is what gets observed; its children carry the sequence, and the delay
   is a custom property the script sets from each one's position, so no
   duration is named here or in the markup.

   The zero default matters: a child the script never reached still transitions
   instead of waiting forever. */
.reveal{
  opacity:0;
  transform:translateY(20px);
  transition:opacity .9s var(--ease-standard),
             transform .9s var(--ease-standard);
  transition-delay:var(--reveal-delay, 0ms);
}
.reveal.in{opacity:1; transform:none}

/* Without the script the class is never added, so the page would be blank
   below the hero. .js is set by an inline script at the top of the document,
   which means a bundle that fails to load cannot hide the content. */
html:not(.js) .reveal{opacity:1; transform:none}

@media (prefers-reduced-motion:reduce){
  .reveal{transition:none; opacity:1; transform:none}
}

/* ---- Use-case card media ------------------------------------------------
   The slot the photograph goes in, held at the 3:2 the variants are cut to so
   nothing reflows when they arrive. While it is empty it carries
   data-placeholder, which is also how to find these once the files exist.

   The float is the site's floatY by value: five pixels each way over 5.2s on
   ease-in-out, the duration the guide lists for it under Motion. This sheet
   does not get the homepage's keyframes, so it declares its own.

   transform does not affect layout, so the box holds its place and only the
   paint drifts - the gap to the label below breathes by 5px, which is the
   effect, not a bug. */
.prod .ucase__media{
  aspect-ratio:3 / 2;
  border-radius:var(--radius-lg);
  margin-bottom:var(--space-5);
  background:var(--paper);
  overflow:hidden;
}
.prod .ucase__media[data-placeholder]{
  border:1px dashed var(--border-default);
  /* Two declarations, not one. A browser that cannot parse color-mix() drops
     the whole thing, base colour included, and the slot goes transparent -
     the same way an unprefixed image-set() took the CTA photograph's fallback
     with it. The flat fill is what those get. */
  background:var(--paper);
  background:
    repeating-linear-gradient(45deg,
      transparent 0 10px,
      color-mix(in srgb, var(--rule) 45%, transparent) 10px 20px),
    var(--paper);
}
/* height:auto and flex:none, not height:100%: the card is a flex column
   stretched to the tallest card in the row, so a percentage height resolved
   against the card and the leftover space went into the photo. Cards with
   less text ended up with taller photos (237 / 209 / 265px in one row). With
   auto, the slot's own aspect-ratio sets the height, the same in every card. */
.prod img.ucase__media{display:block; width:100%; height:auto; flex:none; object-fit:cover}

@keyframes ucaseFloat{
  0%, 100% { transform:translateY(-5px); }
  50%      { transform:translateY(5px); }
}

/* Ten of these start together otherwise, and animations in lockstep read as
   the page stuttering rather than as ten separate things drifting. A fifth of
   the cycle between neighbours is enough to break it. */
@media (prefers-reduced-motion:no-preference){
  .prod .ucase__media{animation:ucaseFloat 5.2s var(--ease-smooth) infinite}
  .prod .ucase:nth-child(5n+2) .ucase__media{animation-delay:-1.04s}
  .prod .ucase:nth-child(5n+3) .ucase__media{animation-delay:-2.08s}
  .prod .ucase:nth-child(5n+4) .ucase__media{animation-delay:-3.12s}
  .prod .ucase:nth-child(5n+5) .ucase__media{animation-delay:-4.16s}
}
