/* ===========================================================
   OnFinance, Lender panel
   A grid of ~67 lender brands. Two problems shape everything
   here. First, the logo files arrive over time rather than all
   at once. Every tile is built to look finished without an
   image, so a half-delivered set never looks broken.
   Second, these tiles carry sixty-odd different brand palettes.
   An earlier version desaturated them at rest and brought the
   colour up on hover, on the theory that they would otherwise
   fight each other. With the real logos in place that was
   plainly wrong. The marks are small and mostly restrained, so
   they sit together perfectly well in colour, and draining them
   turned recognisable banks into grey smudges. Recognition is
   the entire reason the panel is on the page, so they are shown
   as they are.
=========================================================== */

/* ---- Filter bar ------------------------------------------
   Chips rather than a <select>, because on a phone the whole
   set stays visible and one thumb tap switches view. */
.lender-filters{
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  margin-block-end: var(--space-sm);
}

.lender-filter{
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  min-block-size: var(--tap-min);
  padding: 0.5em 1em;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-full);
  background: var(--surface);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 650;
  line-height: 1.2;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-standard),
              border-color var(--duration-fast) var(--ease-standard),
              color var(--duration-fast) var(--ease-standard);
}
.lender-filter:hover{ background: var(--ink-050); border-color: var(--ink-400); }

/* The active chip is filled rather than merely outlined, so the
   current view is obvious at a glance on a small screen. */
.lender-filter[aria-pressed="true"]{
  background: var(--brand-red-500);
  border-color: var(--brand-red-500);
  color: var(--color-accent-contrast);
}

/* Per-chip tally. Dimmed inside the active chip so it informs
   without competing with the label it belongs to. */
.lender-filter__count{
  font-variant-numeric: tabular-nums;
  font-size: 0.85em;
  font-weight: 700;
  opacity: 0.55;
}
.lender-filter[aria-pressed="true"] .lender-filter__count{ opacity: 0.75; }

/* ---- Result count ---------------------------------------- */
.lender-count{
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  margin-block-end: var(--space-sm);
}
.lender-count strong{ color: var(--color-text); font-variant-numeric: tabular-nums; }

/* ---- The grid --------------------------------------------
   auto-fill rather than auto-fit: with a filter applied the
   last row keeps its column width instead of stretching two
   surviving tiles across the full page. */
.lender-grid{
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--space-2xs);
}
@media (min-width: 700px){
  .lender-grid{ grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: var(--space-xs); }
}

.lender-tile{
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 0.55em;
  padding: var(--space-xs) var(--space-2xs);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--surface);
  text-align: center;
  transition: border-color var(--duration-fast) var(--ease-standard),
              box-shadow var(--duration-fast) var(--ease-standard),
              transform var(--duration-fast) var(--ease-out-quart);
}
.lender-tile:hover{
  border-color: var(--color-border-strong);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

/* Logo slot. A fixed block-size keeps every tile on the same
   baseline no matter how tall or wide the individual mark is,
   which is what stops a mixed set of logos looking ragged. */
.lender-tile__logo{
  display: block;             /* only ever emitted when the file really exists */
  inline-size: 100%;
  block-size: 64px;
  object-fit: contain;
  object-position: center;
}
/* expressive.css gives every lazy image a sunken placeholder background
   while it loads. That reads well behind the large illustrations it was
   written for, but behind a transparent logo it paints a grey slab across
   the tile, and with object-fit: contain the slab is wider than the mark.
   That rule is img[loading="lazy"], specificity (0,1,1), so a lone class
   loses to it; a class plus the same attribute is (0,2,0) and wins. */
.lender-tile__logo[loading="lazy"]{ background: transparent; }

/* Name. Doubles as the whole visual when no logo file exists yet,
   so it is set as a wordmark in its own right rather than as a
   caption waiting for something better.
   Weighted deliberately lighter than it first was. Set at 700 in
   near-black it outweighed the real logos sitting beside it, which
   left the handful of lenders with no artwork reading as the most
   prominent brands on the page. This sits at about the visual
   weight of a small logo instead. */
.lender-tile__name{
  font-family: var(--font-display);
  font-weight: 650;
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-tight);
  line-height: 1.2;
  color: var(--ink-600);
  text-wrap: balance;
}

/* Once the logo is up the name is still needed by screen
   readers only if the image alt does not already carry it,
   it does, so the visible duplicate is dropped. */
.lender-tile.has-logo .lender-tile__name{
  position: absolute;
  inline-size: 1px; block-size: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

.lender-tile__desc{
  font-size: var(--text-xs);
  line-height: 1.4;
  color: var(--color-text-muted);
  text-wrap: pretty;
}

/* An inactive lender stays listed but reads as clearly retired
   rather than silently disappearing mid-application. */
.lender-tile--inactive{ opacity: 0.6; }
.lender-tile--inactive .lender-tile__desc{ color: var(--brand-red-600); }

.lender-tile[hidden]{ display: none; }

/* ---- Empty state ----------------------------------------- */
.lender-empty{
  padding: var(--space-md);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-md);
  text-align: center;
  color: var(--color-text-muted);
}

/* ---- Homepage strip --------------------------------------
   A trimmed, denser version of the same grid. No descriptions
   and fewer tiles, because its only job is to convey scale and
   hand off to the full page. */
.lender-strip{
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
  gap: var(--space-2xs);
}
@media (min-width: 700px){
  .lender-strip{ grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
}
.lender-strip .lender-tile{ padding: var(--space-2xs); min-block-size: 86px; justify-content: center; }
.lender-strip .lender-tile__logo{ block-size: 48px; }

/* Motion is decorative here and goes away entirely when the
   visitor has asked for less of it. */
@media (prefers-reduced-motion: reduce){
  .lender-tile{ transition: none; }
  .lender-tile:hover{ transform: none; }
}


/* ===========================================================
   Homepage marquee
   The teaser used to be a static grid of sixteen tiles that
   animated in once and then sat there. Sixty-six accreditations
   is the single strongest claim on the site, and a still grid
   does not carry scale.

   Two rows running in opposite directions do. It is also the
   only element on the homepage that is moving before the
   visitor has scrolled or pointed at anything, which is the
   whole point: an entrance animation is invisible by the time
   you are looking at the thing it animated.

   Pure CSS. The tile list is emitted twice by build-lenders.py
   and the track translates exactly minus fifty percent, so the
   second copy lands precisely where the first began and the
   loop has no seam. The duplicate is aria-hidden, so assistive
   technology reads the panel once.
=========================================================== */

/* Full bleed. A marquee inset inside the content column reads as a
   widget, and a marquee running off both edges of the screen reads as
   a wall that carries on past the page, which is the actual claim.
   html and body already carry overflow-x: clip, so the negative
   margin cannot introduce a horizontal scrollbar. */
.lender-marquees{
  margin-inline: calc(50% - 50vw);
  margin-block: var(--space-md);
}

.marquee{
  position: relative;
  overflow: clip;
  /* Feathered edges, so brands enter and leave rather than being
     chopped off at a hard boundary. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.marquee + .marquee{ margin-block-start: var(--space-2xs); }

.marquee__track{
  display: flex;
  gap: var(--space-2xs);
  inline-size: max-content;
  list-style: none;
  margin: 0;
  padding: 0;
  will-change: transform;
}

.marquee__track .lender-tile{
  inline-size: 158px;
  flex: none;
  padding: var(--space-2xs);
  min-block-size: 92px;
  justify-content: center;
}
.marquee__track .lender-tile__logo{ block-size: 46px; }

@media (max-width: 560px){
  .marquee__track .lender-tile{ inline-size: 132px; min-block-size: 82px; }
  .marquee__track .lender-tile__logo{ block-size: 38px; }
}

@media (prefers-reduced-motion: no-preference){
  .marquee__track{
    animation: marquee-run var(--marquee-duration, 64s) linear infinite;
  }
  .marquee--reverse .marquee__track{ animation-direction: reverse; }

  @keyframes marquee-run{
    from{ transform: translate3d(0, 0, 0); }
    to  { transform: translate3d(-50%, 0, 0); }
  }

  /* Stops under the pointer so a brand can actually be read, and
     stops while anything inside has keyboard focus so a tab stop
     never runs away from the person using it. */
  .marquee:hover .marquee__track,
  .marquee:focus-within .marquee__track{
    animation-play-state: paused;
  }
}

/* No animation means no reason to hide the overflow. The rows
   become ordinary scrollable strips instead. */
@media (prefers-reduced-motion: reduce){
  .marquee{
    overflow-x: auto;
    -webkit-mask-image: none;
            mask-image: none;
  }
}
