/* -----------------------------------------------------------------------------
   LiteRibbon Next Gen — page styles
   -----------------------------------------------------------------------------
   Layout and rhythm only. Buttons, containers, eyebrows, headings and the colour
   tokens all come from the design system (kf-about.css); restating them here is
   how the Solutions pages ended up with buttons that did not match the rest of
   the site. If something here looks like it belongs to every page, it does, and
   it should move up rather than be duplicated.
   ----------------------------------------------------------------------------- */

/* kf-about.css uppercases .kf-display/.kf-h1/.kf-h2/.kf-h4 site-wide. That is the About-era
   treatment; the press page already turns it off for its own bands (kf-press.css line 28) and
   title case is what the live pages use now. Same rule here, scoped the same way, rather than
   writing every heading in caps in content.py and losing the real casing. */
[class*="kf-lr-"] :is(.kf-display, .kf-h1, .kf-h2, .kf-h4) { text-transform: none; }

/* ---------------------------------------------------------------------- hero */
/* The section image is NOT painted on the section. YOOtheme wraps the content in
   `div.uk-background-norepeat.uk-section` and paints it there, with the container
   nested inside that — so `.kf-lr-hero > .uk-container` matches nothing and a
   min-height on the section leaves the artwork at its natural height. Target the
   background child. */
.kf-lr-hero > .uk-section {
    min-height: min(78vh, 720px);
    display: flex;
    /* Centred, not bottom-aligned. The frame has 191px of space above the eyebrow and 191 below
       the CTA; this was sitting at 286 above and 96 below. */
    align-items: center;
    background-size: cover;
    background-position: center;
}
.kf-lr-hero > .uk-section > .uk-container {
    width: 100%;
    padding-top: 96px;
    padding-bottom: 96px;
}

.kf-lr-hero__title { margin: 10px 0 0; max-width: 18ch; }
.kf-lr-hero__title .kf-lr-hero__a,
.kf-lr-hero__title .kf-lr-hero__b { display: block; }
/* Line two is the promise, line one is the fact. Same size, different weight, so the
   pair reads as one sentence rather than a headline plus a subhead. */
/* Line two is a size DOWN from line one, not the same size in another colour: 56/60 for the
   name, 36/42 for the promise. Set at the same size it wrapped to two lines and the pair stopped
   reading as one sentence. Measured off the Figma frame. */
.kf-lr-hero__title .kf-lr-hero__b {
    color: var(--kf-yellow);
    font-size: 36px;
    line-height: 42px;
}

.kf-lr-hero__deck {
    max-width: 58ch;
    margin: 20px 0 0;
    color: var(--kf-on-dark-mute);
}
.kf-lr-hero__cta { margin: 30px 0 0; }

/* ---------------------------------------------------------------------- lede */
.kf-lr-lede__copy { max-width: 74ch; }
.kf-lr-lede__copy p + p { margin-top: 18px; }

/* -------------------------------------------------------------- form factors */
/* Five across only at the large breakpoint. At 960 a fifth is ~175px and the card
   falls apart, so the grid drops to two below that — the same rule the range band
   on the announcement page needed. */
.kf-lr-ff__grid { margin-top: 34px; }

/* The class lands ON YOOtheme's .el-item, not around it, so `.kf-lr-ff__item .el-item`
   matched nothing and the cards rendered as bare text on the band. */
.kf-lr-ff__item.el-item {
    position: relative;
    background: #fff;
    border: 1px solid var(--kf-line);
    border-radius: var(--kf-card-radius, 4px);
    padding: 24px 20px 26px;
    height: 100%;
}
/* the yellow rule across the top of each card */
.kf-lr-ff__item.el-item::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: var(--kf-yellow);
    border-radius: var(--kf-card-radius, 4px) var(--kf-card-radius, 4px) 0 0;
}
.kf-lr-ff__item .el-title { margin-top: 0 !important; }
.kf-lr-ff__item .el-meta { margin-top: 6px !important; }
.kf-lr-ff__item .el-content { margin-top: 12px !important; }
.kf-lr-ff__item .el-title {
    font-family: var(--kf-display);
    font-size: 26px;
    line-height: 30px;
    font-weight: 700;
    color: var(--kf-ink);
    margin: 0;
}
.kf-lr-ff__item .el-meta {
    display: block;
    margin: 6px 0 12px;
    font-size: 11px;
    letter-spacing: .12em;
    text-transform: uppercase;
    font-weight: 700;
    color: var(--kf-mute);
}
.kf-lr-ff__item .el-content p {
    margin: 0;
    font-size: 14px;
    line-height: 22px;
    color: var(--kf-body);
}

/* The photo variant only: the still sits above the name and is deliberately short,
   so it reads as atmosphere rather than as a product photograph. */
.kf-lr-ff__item--photo .el-image {
    aspect-ratio: 4 / 3;
    object-fit: cover;
    margin-bottom: 14px;
}
.kf-lr-ff__note {
    margin: 16px 0 0;
    font-size: 12px;
    color: var(--kf-mute);
}

/* ------------------------------------------------------------- key features */
.kf-lr-feats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    /* 12px gaps and separate cards. This was a 1px gap over a filled wrapper, which merged the
       eight cells into one slab with hairlines through it. */
    gap: 12px;
    margin-top: 30px;
    background: transparent;
    border: 0;
}
.kf-lr-feat {
    background: #232320;
    border-radius: var(--kf-card-radius, 4px);
    padding: 20px 22px 22px;
}
.kf-lr-feat__k {
    display: block;
    font-family: var(--kf-display);
    font-size: 18px;
    line-height: 22px;
    font-weight: 700;
    color: var(--kf-on-dark);
}
.kf-lr-feat__v {
    display: block;
    margin-top: 6px;
    font-size: 13px;
    line-height: 20px;
    color: var(--kf-on-dark-mute);
}

/* --------------------------------------------------- built from experience */
.kf-lr-exp__copy { max-width: 52ch; }
.kf-lr-exp__copy p + p { margin-top: 16px; }
/* The image runs to the page edge on its side; the copy keeps the house measure.
   .kf-bleed on the section is what allows that — do not re-solve it here. */
.kf-lr-exp__img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ------------------------------------------------------------------ cta band */
.kf-lr-cta-band > .uk-section {
    background-size: cover;
    background-position: center;
}
.kf-lr-cta-band > .uk-section > .uk-container { padding-block: 80px; }
.kf-lr-cta-band__actions { margin: 26px 0 0; }

/* -------------------------------------------------------------------- modal */
.kf-lr-modal__lede {
    margin: 0 0 18px;
    color: var(--kf-body);
    font-size: 15px;
    line-height: 23px;
}
.kf-lr-modal__note,
.kf-lr-modal__unset {
    margin: 14px 0 0;
    font-size: 12.5px;
    color: var(--kf-mute);
}

@media (max-width: 959px) {
    .kf-lr-hero > .uk-section { min-height: 0; }
    .kf-lr-hero > .uk-section > .uk-container { padding-top: 64px; padding-bottom: 64px; }
}

/* ------------------------------------------------------------------ color engines
   A three-column list, not a table: there is one value per column and a table's
   header semantics buy nothing here. The spec matrix below IS a table, because
   there the row and column headers are what make a cell mean anything. */
.kf-lr-engs {
    margin-top: 30px;
    border-top: 1px solid var(--kf-line);
}
.kf-lr-eng {
    display: grid;
    grid-template-columns: 200px 1fr 260px;
    gap: 20px;
    align-items: center;
    padding: 16px 0;
    border-bottom: 1px solid var(--kf-line);
}
.kf-lr-eng--head {
    padding: 10px 0;
    font-size: 11px;
    letter-spacing: .12em;
    text-transform: uppercase;
    font-weight: 700;
    color: var(--kf-mute);
}
.kf-lr-eng--head .kf-lr-eng__name { font-family: inherit; font-size: inherit; }

.kf-lr-eng__name {
    font-family: var(--kf-display);
    font-size: 20px;
    line-height: 26px;
    font-weight: 700;
    color: var(--kf-ink);
}
.kf-lr-eng__chips { display: flex; flex-wrap: wrap; gap: 8px; }
.kf-lr-chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 4px 11px 4px 7px;
    border: 1px solid var(--kf-line);
    border-radius: 30px;
    font-size: 12px;
    line-height: 18px;
    color: var(--kf-body);
    white-space: nowrap;
}
/* The dot carries a hairline because the 6000K and 2700K chips are near-white and
   would otherwise vanish against the card. */
.kf-lr-chip i {
    width: 12px; height: 12px;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1px rgba(0,0,0,.18);
}
.kf-lr-eng__forms {
    font-size: 13px;
    line-height: 20px;
    color: var(--kf-mute);
}

/* ------------------------------------------------------------------ spec matrix */
.kf-lr-matrix { background: var(--kf-paper, #f7f7f5); }
.kf-lr-matrix__wrap {
    margin-top: 30px;
    overflow-x: auto;              /* the grid is 6 columns; never let the PAGE scroll sideways */
    -webkit-overflow-scrolling: touch;
}
.kf-lr-matrix__table {
    width: 100%;
    min-width: 680px;
    border-collapse: collapse;
    background: #fff;
    border: 1px solid var(--kf-line);
    font-variant-numeric: tabular-nums;
}
.kf-lr-matrix__table th,
.kf-lr-matrix__table td {
    padding: 13px 14px;
    border-bottom: 1px solid var(--kf-line);
    text-align: center;
}
.kf-lr-matrix__table thead th {
    font-family: var(--kf-display);
    font-size: 12px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--kf-mute);
    border-bottom: 1px solid var(--kf-line-dark, #d3d0c8);
    white-space: nowrap;
}
.kf-lr-matrix__table tbody th[scope="row"] {
    text-align: left;
    font-family: var(--kf-display);
    font-size: 16px;
    font-weight: 700;
    color: var(--kf-ink);
    white-space: nowrap;
}
.kf-lr-matrix__table tbody tr:last-child th,
.kf-lr-matrix__table tbody tr:last-child td { border-bottom: 0; }
.kf-lr-matrix__table tbody tr:nth-child(even) th,
.kf-lr-matrix__table tbody tr:nth-child(even) td { background: #fbfaf8; }

/* Availability is not carried by colour alone — the tick and the dash are different
   glyphs with different aria-labels, so it survives greyscale and a screen reader. */
.kf-lr-tick { color: #2f7d4f; font-size: 15px; font-weight: 700; }
.kf-lr-matrix__table td.is-off { color: #b8b6b0; }

.kf-lr-matrix__foot {
    margin: 16px 0 0;
    font-size: 13px;
    line-height: 21px;
    color: var(--kf-mute);
    max-width: 74ch;
}

@media (max-width: 959px) {
    .kf-lr-eng {
        grid-template-columns: 1fr;
        gap: 10px;
        padding: 18px 0;
    }
    .kf-lr-eng--head { display: none; }   /* column labels mean nothing once it stacks */
}

/* ============================================================================
   Updated UI pass — matches the Figma frame
   ============================================================================ */

/* Hero and CTA carry the photograph with a gradient scrim over it rather than a
   flat wash, so the image stays visible on the side away from the copy. In Figma
   this is a stacked fill on one rect (solid, image, gradient); in CSS the section
   holds the image and this ::after holds the gradient. */
.kf-lr-hero > .uk-section,
.kf-lr-cta-band > .uk-section { position: relative; }
.kf-lr-hero > .uk-section::after,
.kf-lr-cta-band > .uk-section::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(90deg,
        rgba(0,0,0,.92) 0%,
        rgba(0,0,0,.82) 34%,
        rgba(0,0,0,.35) 66%,
        rgba(0,0,0,.05) 100%);
}
.kf-lr-hero > .uk-section > .uk-container,
.kf-lr-cta-band > .uk-section > .uk-container { position: relative; z-index: 1; }

/* The copy column no longer spans the band — it sits in the dark half. The title measure is set
   in px, not ch: `ch` is the width of a "0" in the BODY font, and the title is set in the display
   face at 56px, so 15ch measured about 420px and broke "LiteRibbon Next Gen." across two lines
   where the design has it on one. */
.kf-lr-hero__title { max-width: 640px; }
/* 580px, not 46ch. The frame draws the deck at 579px wide over three lines; `ch` is the width of
   a zero in the body font and 46 of them came out around 390px, wrapping it to five. */
.kf-lr-hero__deck  { max-width: 580px; }

/* -------------------------------------------------------------- lede render */
/* The band clips the render; the render is bigger than the band on purpose and
   runs off the right edge. Nothing is allowed to widen the page — the section is
   the clipping boundary, not the viewport. */
.kf-lr-lede { position: relative; overflow: hidden; }
/* YOOtheme's .uk-panel is position:relative and only as wide as the 1200 content measure, so it
   was the render's containing block and `right: 0` stopped 193px short of the band edge. Making
   the panel static hands the job back to the section, which is the full-bleed box the render is
   meant to be cropped by. Safe here: this band holds nothing but text elements. */
.kf-sec.kf-lr-lede .uk-panel { position: static; }
.kf-lr-lede__render {
    position: absolute;
    right: 0;
    /* The landscape crop already carries the diagonal, so there is no rotate here — rotating it
       again would double the angle. It is cropped to a right-hand box rather than oversized and
       hidden: the source's corners are transparent either side of the ribbon, so a box crop shows
       no hard edge, which is what made the square version need to be 1.7x the band just to keep
       its own boundary out of frame. */
    /* NO object-fit: cover. Cover crops to fill the box, and the box is taller-and-narrower than
       the 1.74:1 source, so it was cutting the ribbon's top-left run — the source itself is not
       cropped. Natural aspect instead: the whole render is shown, sized by width, centred in the
       band. The transparent area above and below is exactly what the source provides. */
    top: 50%;
    transform: translateY(-50%);
    width: 60%;
    height: auto;
    /* The theme sets object-fit on images; `fill` here means the natural aspect from the width /
       height attributes is what shows, with nothing cropped. */
    object-fit: fill;
    aspect-ratio: auto;
    pointer-events: none;
    user-select: none;
    /* Feather the left edge. The render's soft glow does not reach full transparency before the
       crop boundary, so the box put a hard vertical seam down the middle of the band where the
       image started. The mask fades that edge out instead of relying on the source's alpha. */
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 22%);
            mask-image: linear-gradient(90deg, transparent 0, #000 22%);
}
/* the copy must never run under the ribbon */
.kf-lr-lede__copy,
.kf-lr-lede .kf-h2,
.kf-lr-lede .kf-eyebrow { position: relative; max-width: 56ch; }

/* ------------------------------------------------------------------- the film */
/* Three columns of production stills scrolling continuously. Each track holds the tiles
   TWICE, so translating it by exactly -50% lands the duplicate where the original started
   and the loop is seamless. Different durations and directions per column so it does not
   read as one block sliding. */
/* The film bleeds to the section edge while the copy keeps the 1200 measure, so it is taken out
   of the grid and positioned against the band. Same pattern as the lede render, and the same
   reason: inside the container it stopped 193px short of the edge. */
.kf-sec.kf-lr-exp { overflow: hidden; }

/* The film sits INSIDE the right column, not bled to the section edge. The frame ends it 200px
   from the edge on the same 1200 measure as the copy; flush to the viewport put it hard against
   the right instead of sitting in the middle of its column.
   Tile size: the frame draws 150px squares in a ~470px block, so the block is capped rather than
   left to fill a half-width column, which had produced 300px tiles. */
.kf-lr-film {
    margin-inline: auto;
    max-width: 560px;
    width: 100%;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    /* An explicit window, not 100%. Back in flow, `height: 100%` resolves against an auto-height
       parent and becomes auto, so the film showed its ENTIRE track — ten tiles per column — and
       the band grew to about 1600px. This is the viewport the tracks scroll behind. */
    height: 560px;
    overflow: hidden;
    /* fade the ends so tiles enter and leave rather than being chopped off */
    -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 12%, #000 88%, transparent 100%);
            mask-image: linear-gradient(180deg, transparent 0, #000 12%, #000 88%, transparent 100%);
}
.kf-lr-film__col { overflow: hidden; }
.kf-lr-film__track {
    display: flex;
    flex-direction: column;
    gap: 10px;
    will-change: transform;
    /* Slow. This is ambient texture behind the copy, not something to watch: at 42s a tile
       crossed the band in a couple of seconds and pulled the eye off the text. Roughly 2.5x
       slower, and the three columns stay on different durations so they never sync up. */
    animation: kf-lr-film-up 110s linear infinite;
}
.kf-lr-film__col:nth-child(2) .kf-lr-film__track { animation-duration: 88s; animation-direction: reverse; }
.kf-lr-film__col:nth-child(3) .kf-lr-film__track { animation-duration: 130s; }
.kf-lr-film__t {
    width: 100%;
    /* square, as drawn */
    aspect-ratio: 1 / 1;
    object-fit: cover;
    display: block;
    background: #1c1c1a;
    border-radius: 3px;
}
/* -50% is one full copy of the tile list, which is why the tiles are emitted twice. */
@keyframes kf-lr-film-up {
    from { transform: translateY(0); }
    to   { transform: translateY(-50%); }
}
.kf-lr-film:hover .kf-lr-film__track { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
    .kf-lr-film__track { animation: none; }
    .kf-lr-film { mask-image: none; -webkit-mask-image: none; }
}

@media (max-width: 959px) {
    .kf-lr-hero > .uk-section::after,
    .kf-lr-cta-band > .uk-section::after {
        /* stacked, so the copy sits over the middle of the image, not beside it */
        background: linear-gradient(180deg, rgba(0,0,0,.55) 0%, rgba(0,0,0,.88) 62%);
    }
    .kf-lr-hero__title, .kf-lr-hero__deck { max-width: none; }
    .kf-lr-lede__render { display: none; }   /* it would sit under the copy at this width */
    .kf-lr-mosaic__t:nth-child(n) { transform: none; }
}

/* ============================================================================
   Fidelity pass — measured against the Figma frame, band by band
   ----------------------------------------------------------------------------
   Every value below is a diff against the design, not a preference. What the
   audit found, in order of how much it was hurting:

   1. MEASURE. `kf-bleed` makes a band span the page, and the design system
      expects `.kf-container` INSIDE it to restore the 1200 measure. Without it
      the copy ran to 40px from the viewport edge instead of starting at 200 in
      a 1600 frame, so every bleed band was far too wide.
   2. BODY FONT. Body copy was rendering in Nunito Sans, the theme's default —
      the design is Roboto throughout.
   3. TYPE SCALE. .kf-h2 is 36/44 site-wide; this page is drawn at 40/48, and
      the hero display at 56/60 against the 40/44 it was inheriting.
   4. COLOUR. Eyebrow-on-light, body copy and the on-dark greys were all the
      theme's values rather than the frame's.
   5. GROUNDS. The features band was picking up the theme's #58595b secondary
      instead of #1c1c1a, and the form-factor band was white instead of #f7f7f5.
   ============================================================================ */

/* ---- 1. the 1200 measure inside full-bleed bands --------------------------
   The container is `.uk-container-expand`, which sets max-width:none — so a plain
   `.uk-container` rule loses. `.kf-sec` in front takes this to (0,3,0) and wins.
   Two shapes to cover: a band WITH a section image nests an extra
   `.uk-background-norepeat.uk-section` wrapper, a band without one does not. */
.kf-sec[class*="kf-lr-"] > .uk-container,
.kf-sec[class*="kf-lr-"] > .uk-section > .uk-container {
    max-width: 1280px;          /* 1200 content + 40 padding each side */
    margin-inline: auto;
    width: 100%;
    padding-inline: 40px;
    /* The container is content-box here, so max-width:1280 plus 40px of padding each
       side measured 1360 and put the copy 47px left of where the design has it. The
       1280 is a BOX measurement, not a content measurement. */
    box-sizing: border-box;
}

/* ---- 2 + 3. type ---------------------------------------------------------- */
[class*="kf-lr-"] .kf-lr-hero__a { font-size: 56px; line-height: 60px; }
[class*="kf-lr-"] .kf-h2 { font-size: 40px; line-height: 48px; }

/* Body copy is Roboto in the design; the theme's default is Nunito Sans and it
   was winning everywhere prose was emitted as plain <p>. */
.kf-lr-hero__deck,
.kf-lr-lede__copy p,
.kf-lr-exp__copy p,
.kf-lr-ff .kf-sub,
.kf-lr-cta-band .kf-sub,
.kf-lr-ff__item .el-content p,
.kf-lr-feat__v,
.kf-lr-eng__forms,
.kf-lr-chip,
.kf-lr-matrix__foot {
    font-family: Roboto, system-ui, -apple-system, "Helvetica Neue", sans-serif;
}
.kf-lr-hero__deck,
.kf-lr-lede__copy p,
.kf-lr-exp__copy p,
.kf-lr-ff .kf-sub,
.kf-lr-cta-band .kf-sub { font-size: 17px; line-height: 27px; }

/* ---- 4. colour ------------------------------------------------------------ */
.kf-lr-lede .kf-eyebrow,
.kf-lr-ff .kf-eyebrow,
.kf-lr-exp .kf-eyebrow,
.kf-lr-engines .kf-eyebrow,
.kf-lr-matrix .kf-eyebrow { color: #212c34; }

.kf-lr-lede__copy p,
.kf-lr-exp__copy p,
.kf-lr-ff .kf-sub,
.kf-lr-ff__item .el-content p { color: #414243; }

.kf-lr-hero__deck,
.kf-lr-cta-band .kf-sub,
.kf-lr-feat__v { color: #d3d4d5; }
.kf-lr-feat__k { color: #fff; }

/* ---- 5. grounds -----------------------------------------------------------
   `.uk-section-secondary` paints #58595b and is (0,1,0); these need to outrank it,
   hence the doubled class. The ground is on the section element itself — there is
   no inner wrapper on bands without an image. */
.kf-sec.kf-lr-features { background-color: #1c1c1a; }
.kf-sec.kf-lr-ff { background-color: #f7f7f5; }
.kf-sec.kf-lr-matrix { background-color: #f7f7f5; }
.kf-sec.kf-lr-lede,
.kf-sec.kf-lr-exp,
.kf-sec.kf-lr-engines { background-color: #ffffff; }

/* ---- card kicker ---------------------------------------------------------- */
/* Was inheriting the site's uppercase 11px meta treatment. The frame draws it as
   a plain 13/20 caption in the body face. */
.kf-lr-ff__item .el-meta {
    font-family: Roboto, system-ui, sans-serif;
    font-size: 13px;
    line-height: 20px;
    letter-spacing: 0;
    text-transform: none;
    font-weight: 400;
    color: #717275;
}

/* ---- band rhythm ---------------------------------------------------------- */
/* Heights in the frame: hero 700, lede 400, form factors 560, features 520,
   experience 560, cta 460. Set as padding so the bands breathe the same way. */
/* The band was 665 tall for 325 of content: 90px of my padding at each end, and then UIkit's own
   .uk-grid-margin on the row and the trailing margin on the last paragraph stacking on top of it,
   which is where the extra 70 above and 90 below came from. The frame draws this band at 400 with
   ~70 either side of the copy, so the padding is set to that and the stray margins are zeroed
   rather than being padded around. */
.kf-sec.kf-lr-lede > .uk-container { padding-block: 80px; }
.kf-sec.kf-lr-lede > .uk-container > .uk-grid { margin-top: 0; }
.kf-sec.kf-lr-lede .uk-panel > :first-child { margin-top: 0; }
.kf-sec.kf-lr-lede .uk-panel > :last-child { margin-bottom: 0; }
/* ---- band rhythm ----------------------------------------------------------
   80 on desktop, 56 once the layout narrows. Every content band uses the same
   pair; they were 70 / 80 / 78 / 86 before, which read as noise rather than a
   scale. Two deliberate exceptions: the hero keeps its own larger figure, and
   the experience band is 0 on wide screens because the film runs the full band
   height there by design. */
.kf-lr-ff > .uk-container { padding-block: 80px; }
.kf-lr-features > .uk-container { padding-block: 80px; }
.kf-lr-exp > .uk-container { padding-block: 0; }

/* ---- the CTA pill ---------------------------------------------------------
   The label was rendering WHITE on yellow. .kf-btn--primary sets the ink colour
   at (0,1,0), and the theme's on-dark link rule is more specific, so on the two
   dark bands the anchor was taking the theme's white. Contrast on yellow was
   about 1.7:1 — effectively unreadable, and the screenshot showed it.

   The background was never wrong; #fed208 just reads washed out over a dark
   photograph. Only the label colour and its size needed correcting: the frame
   draws 13px with 1.1 letter-spacing, not the 15px it was inheriting. */
.kf-sec[class*="kf-lr-"] a.kf-lr-cta,
.kf-sec[class*="kf-lr-"] a.kf-lr-cta:hover,
.kf-sec[class*="kf-lr-"] a.kf-lr-cta:focus {
    color: #161616;
    background-color: var(--kf-yellow);
    font-size: 13px;
    letter-spacing: 1.1px;
}
.kf-sec[class*="kf-lr-"] a.kf-lr-cta:hover { background-color: #e6bd00; }

/* ---- hero vertical rhythm -------------------------------------------------
   Measured against the frame: eyebrow -> title 18, the two title lines 6,
   title -> deck 15, deck -> CTA 30. What was rendering was 40 / 0 / 40 / 30.

   The 40s are the theme's own element spacing on the Builder wrappers, which
   `tight` on the element does not reach — it removes the element's margin, not
   the panel's. So the wrappers are zeroed and the gaps set explicitly, which is
   also why these need !important: the theme ships
   `* + .uk-margin { margin-top: 20px !important }`. */
.kf-sec.kf-lr-hero .uk-panel > * { margin-top: 0 !important; margin-bottom: 0 !important; }
.kf-sec.kf-lr-hero .uk-panel + .uk-panel,
.kf-sec.kf-lr-hero .uk-margin { margin-top: 0 !important; }

/* The heading carries its own 20px bottom margin, which stacked on the deck's 15px top margin
   and made the gap 35. Zeroed, so the 15 is the whole gap. */
.kf-sec.kf-lr-hero .kf-lr-hero__title { margin-top: 18px !important; margin-bottom: 0 !important; }
.kf-lr-hero__title .kf-lr-hero__b { margin-top: 6px; }
.kf-sec.kf-lr-hero .kf-lr-hero__deck { margin-top: 15px !important; }
.kf-sec.kf-lr-hero .kf-lr-hero__cta  { margin-top: 30px !important; }

/* ---- band padding lives on the container, nowhere else ---------------------
   A band's vertical space must be ONE number in ONE place, or it silently doubles.
   It did, twice: this rule used to be scoped to .kf-bleed and to the outer section
   only, so .kf-lr-ff (not a bleed band) kept YOOtheme's 70px section padding on top
   of its container's 80, and .kf-lr-cta-band kept 70 on its nested background
   .uk-section on top of its container's 86. Both landed near 150 against the 70-78
   of their neighbours. Zeroing every section level here leaves the container as the
   single source of truth, which is what the rhythm block below sets.
   Scoped to this page, not to .kf-bleed itself: that utility is shared with the
   press page and the blog, and this is a rhythm decision for this layout. */
.kf-sec[class*="kf-lr-"],
.kf-sec[class*="kf-lr-"] > .uk-section { padding-top: 0; padding-bottom: 0; }

/* ---- experience band: centre the copy against the film --------------------
   The row is a 1-2/1-2 split where the right column is a 560px film and the left
   is a short block of copy. UIkit stretches both to the row height, so the copy
   sat at the top with a large empty gap beneath it. Centring the columns puts the
   copy against the middle of the film, which is what the frame shows. */
/* Centre the copy in the band. Taking the film out of flow removed the tall row that was
   holding the copy down the middle, so the container does that job instead: it fills the band's
   min-height and centres its one child, the grid.

   NOT display:flex on the grid's CHILDREN — that turned the eyebrow, heading and copy into flex
   items and laid them side by side across the column. */
/* With the film back in flow it is the tall element again, so centring the grid's columns is all
   that holds the copy down the middle. */
.kf-sec.kf-lr-exp > .uk-container > .uk-grid { align-items: center; }

/* ---- gap between a band's intro and its cards -----------------------------
   Was 74px in the form-factor band and 70 in features: UIkit puts 40px of
   `.uk-grid-margin` on the second row, and my own 34/30 margin-top landed on top
   of it. Zero the row's margin so one deliberate value controls the gap. */
.kf-sec.kf-lr-ff > .uk-container > .uk-grid-margin,
.kf-sec.kf-lr-features > .uk-container > .uk-grid-margin { margin-top: 0; }

.kf-lr-ff__grid { margin-top: 34px; }
.kf-lr-feats    { margin-top: 34px; }

/* The shared modal chrome uppercases its title. House convention is title case for headings, so
   this modal opts out the same way the page bands do.
   Doubled class: kf-product-inquiry.css sets it at the same (0,2,0) and is enqueued AFTER this
   sheet, so an equal-specificity rule loses on source order. */
.kf-inquiry-modal.kf-lr-modal .kf-inquiry-modal__title { text-transform: none; }

/* ---- form-factor card gutter ---------------------------------------------
   UIkit's default grid gutter is 40px, applied as a negative margin on the grid
   and matching padding on each column. At five across that pushed the cards to
   208px and left more air between them than inside them. 16px. */
.kf-lr-ff__grid > .uk-grid { margin-left: -16px; }
.kf-lr-ff__grid > .uk-grid > * { padding-left: 16px; }
.kf-lr-ff__grid > .uk-grid > .uk-grid-margin { margin-top: 16px; }

/* ============================================================================
   Responsive
   ----------------------------------------------------------------------------
   The form-factor grid was left to UIkit's own child-width classes and the
   ladder came out wrong in exactly the range that matters: 2-up from 640 all
   the way to 1200, which made each card 545px wide, then 3-up at 1440 and 5-up
   only at 1600. Explicit breakpoints instead, so the card width stays in a sane
   band the whole way up.

       < 640    1 up
    640-1319    2 up   (2x2 — a 3-up here would strand a single card on its own row)
      >= 1320   4 up   (one row, was 5 before Pixel came off the page)
   ============================================================================ */
.kf-lr-ff__grid > .uk-grid > * { width: 100%; }

@media (min-width: 640px) {
    .kf-lr-ff__grid > .uk-grid > * { width: 50%; }
}
@media (min-width: 1320px) {
    .kf-lr-ff__grid > .uk-grid > * { width: 25%; }
}

/* ---- hero type ------------------------------------------------------------
   56/36 is the desktop pair. Held at that size the title ran four lines on a
   phone and pushed the CTA off the first screen. */
@media (max-width: 1199px) {
    [class*="kf-lr-"] .kf-lr-hero__a { font-size: 44px; line-height: 50px; }
    .kf-lr-hero__title .kf-lr-hero__b { font-size: 30px; line-height: 36px; }
    [class*="kf-lr-"] .kf-h2 { font-size: 34px; line-height: 42px; }
}
@media (max-width: 639px) {
    [class*="kf-lr-"] .kf-lr-hero__a { font-size: 34px; line-height: 40px; }
    .kf-lr-hero__title .kf-lr-hero__b { font-size: 24px; line-height: 30px; }
    [class*="kf-lr-"] .kf-h2 { font-size: 28px; line-height: 34px; }
    .kf-lr-hero__deck,
    .kf-lr-lede__copy p,
    .kf-lr-exp__copy p,
    .kf-lr-ff .kf-sub,
    .kf-lr-cta-band .kf-sub { font-size: 16px; line-height: 25px; }
    .kf-lr-hero__title { max-width: none; }
}

/* ---- the film -------------------------------------------------------------
   Three columns in a phone-width container gives ~85px tiles, which is noise
   rather than imagery. Two columns below 640, and the window shortens so the
   band does not become a wall of pictures above the copy. */
/* superseded: below 1440 the film is the horizontal strip, not a column grid */

/* ---- band rhythm on small screens ----------------------------------------- */
@media (max-width: 959px) {
    .kf-sec.kf-lr-lede > .uk-container,
    .kf-lr-ff > .uk-container,
    .kf-sec.kf-lr-exp > .uk-container,
    .kf-lr-features > .uk-container { padding-block: 56px; }
    .kf-lr-cta-band > .uk-section > .uk-container { padding-block: 56px; }

}

/* ---- the film: side to side on narrow screens -----------------------------
   Three vertical columns in a stacked mobile layout is a wall of pictures the
   reader has to scroll past to reach the next band. Below 960 the columns are
   swapped for a single horizontal strip that carries the WHOLE set and takes one
   band's worth of height. The two structures are mutually exclusive, so only one
   is ever painted. */
.kf-lr-film__row { display: none; }

/* 1439, not 959. Measured: the experience row only goes side by side at 1440 — below that the
   film sits UNDER the copy, and three vertical columns there made the band 900px tall. The strip
   is the right layout wherever the row is stacked, which is everywhere below 1440. */
/* Stacked but still wide: the experience band takes the desktop figure. Ranged so it
   cannot overlap the 56px narrow rule above. */
@media (min-width: 960px) and (max-width: 1439px) {
    .kf-sec.kf-lr-exp > .uk-container { padding-block: 80px; }
}

@media (max-width: 1439px) {
    /* The band runs padding-block:0 on desktop, where the copy is centred against a tall film
       beside it and the film is MEANT to reach the band edges. Once the row stacks, the film sits
       under the copy and that same 0 leaves the eyebrow flush against the dark band above and the
       strip flush against the one below. These belong at 1439 with the stack, not at 959: between
       960 and 1439 the row was already stacked but still had desktop's zero padding. */
    .kf-sec.kf-lr-exp > .uk-container > .uk-grid { row-gap: 20px; }
    .kf-sec.kf-lr-exp .kf-lr-exp__copy > p:last-child { margin-bottom: 0; }

    .kf-lr-film {
        display: block;
        height: auto;
        max-width: none;
        /* No fade on the strip. The vertical film fades its ends because tiles are cut mid-frame
           by the band edge; the strip runs to the band edges and reads as a strip already, so the
           fade only washed the first and last images out. */
        -webkit-mask-image: none;
                mask-image: none;
    }
    .kf-lr-film__col { display: none; }

    /* Full-bleed: the strip escapes the container's measure and runs edge to edge, while the copy
       above it keeps its padding. 100vw includes the scrollbar, which would normally widen the
       page — .kf-lr-exp already clips with overflow:hidden, so it cannot. */
    .kf-lr-film {
        margin-left: calc(50% - 50vw);
        margin-right: calc(50% - 50vw);
        width: 100vw;
    }
    .kf-lr-film__row { display: block; overflow: hidden; }
    .kf-lr-film__rtrack {
        display: flex;
        flex-direction: row;
        gap: 10px;
        width: max-content;
        will-change: transform;
        animation: kf-lr-film-left 90s linear infinite;
    }
    .kf-lr-film__rtrack .kf-lr-film__t {
        width: 200px;
        height: 200px;
        flex: 0 0 auto;
    }
    .kf-lr-film:hover .kf-lr-film__rtrack { animation-play-state: paused; }
}

/* the vertical film's own sizing only applies where it is actually used */
@media (min-width: 1440px) {
    .kf-lr-film__row { display: none; }
}

@media (max-width: 639px) {
    .kf-lr-film__rtrack .kf-lr-film__t { width: 150px; height: 150px; }
    .kf-lr-film__rtrack { animation-duration: 70s; }
}

/* -50% is one full copy of the strip, which is why the tiles are emitted twice. */
@keyframes kf-lr-film-left {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
    .kf-lr-film__rtrack { animation: none; }
    .kf-lr-film__row { overflow-x: auto; }   /* still reachable, just by hand */
}
