/* ============================================================
   Parts + featured ranges

   Two bands. The vertical rhythm is the reference's, measured at
   1440x900; the horizontal figures below are what THIS token set
   actually produces, which is wider than the reference on purpose.

     Band A  #f2f2f2 ground, 50px top / 55px bottom padding,
             36px centred title, 18px/30px left-aligned intro,
             2 cards in one row, 37px column gap, 3:2 media, caption bar.
     Band B  white ground, 50px vertical padding,
             4 banners (3:2) in 2 columns, 50px row and column gap.

   Measured widths at a 1440px viewport, in the browser, today:
     --container 1320px - 2 x 48px gutter = 1224px content box
     part card   (1224 - 37) / 2 = 593.5px
     promo       (1224 - 50) / 2 = 587px, so 587 x 391.3 at 3:2

   The reference runs a 1160px content box, which would give 561.5px
   and 555px. We do not match it and should not: `--container:1320px`
   in tokens.css is a project-wide decision that hero, categories and
   parts all share, and narrowing it here alone would make this the one
   band whose gutters disagree with the section above it. Read the
   figures above as "what we ship", not "what the reference measured".

   The part card is the category tile scaled up: identical anatomy,
   identical hover contract. That is deliberate — two card shapes that
   behave differently on the same page is the thing that makes a build
   feel assembled rather than designed.
   ============================================================ */

/* The sprite carries artwork only; it must never take up space.
   Same treatment as .cats__sprite — the width/height attributes alone
   still leave an inline box in some engines. */
.parts__sprite{position:absolute;width:0;height:0;overflow:hidden}

/* Alternating band ground. This belongs in base.css, but Parts is the
   only section using it today and a token with one caller is a guess.
   Move it the moment a second section needs it, so two stylesheets do
   not both claim ownership of the same class. */
.section--muted{background:var(--grey-100)}

/* Band padding overrides the .section default: the reference runs a
   tighter, asymmetric rhythm here (50 / 55) than the page default. */
.parts{padding-block:clamp(var(--sp-6),3.6vw,3.125rem) clamp(var(--sp-7),4vw,3.4375rem)}
.promos{background:var(--gps-white);padding-block:clamp(var(--sp-6),3.6vw,3.125rem)}

/* ---------- Band A head ----------
   Centred title over a left-aligned intro. The reference runs the intro
   at full container width; kept, because narrowing it breaks the band's
   proportions — the copy is written short instead, so the measure stays
   near 100 characters at 1440 rather than running to the edge of sense. */
.parts__head{margin:0 0 clamp(var(--sp-6),3vw,var(--sp-7));text-align:center}
.parts__head .section-head__title{margin:0 0 var(--sp-5)}

.parts__intro{
  text-align:left;
  color:var(--grey-600);
  font-size:clamp(var(--fs-base),1.25vw,1.125rem);   /* tops out at 18px */
  line-height:1.6667;                                /* 30px at 18px     */
}
.parts__intro p:last-child{margin-bottom:0}

/* ---------- Band A grid ---------- */
.parts__grid{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:35px 37px;                 /* row gap only bites once the grid wraps */
  margin:0;padding:0;list-style:none;
}
.parts__item{display:flex}       /* stretches both cards to the row height */

/* ---------- Part card ----------
   Mirrors .cat-card, with the ground inverted: the category tiles are
   grey on white, these are white on grey. Same border, radius, shadow
   and transition set, so the two read as one component family. */
.part-card{
  display:flex;flex-direction:column;width:100%;
  background:var(--gps-white);
  border:1px solid var(--grey-300);
  border-radius:var(--radius-tile);
  box-shadow:0 2px 8px rgba(0,0,0,.10);
  overflow:hidden;               /* keeps the media square with the radius */
  text-decoration:none;
  transition:background var(--dur) var(--ease),
             border-color var(--dur) var(--ease),
             box-shadow var(--dur) var(--ease),
             transform var(--dur) var(--ease);
}

.part-card__media{
  display:block;position:relative;
  background:var(--gps-white);
  border-bottom:1px solid var(--grey-300);
  aspect-ratio:3/2;
}
/* Generous inset: these symbols carry five or six components each and
   need more air than the single-object category icons. */
.part-card__art{
  position:absolute;inset:0;width:100%;height:100%;
  padding:clamp(var(--sp-4),2.6vw,var(--sp-6));
}

/* A featured image is not a symbol and must not be treated like one.
   The registered `gps-card` crop is 700x400 (7:4) and this media box is
   3:2, so with the default object-fit:fill a photograph arrives ~14%
   stretched — round parts render as ellipses, which on a page about
   rotors and sprockets is the one distortion nobody will miss. cover
   crops instead, and holds for any other ratio a client uploads.
   The padding goes with it: inset air is right for a line symbol on a
   white card, wrong for a photograph that should fill its frame.
   Scoped to `img` so the inline <svg> keeps both the padding and its
   own preserveAspectRatio, which already does the right thing. */
img.part-card__art{padding:0;object-fit:cover}

.part-card__title{
  display:flex;align-items:center;justify-content:center;
  flex:1 0 auto;                 /* equalises the caption bars across the row */
  min-height:5rem;
  margin:0;padding:var(--sp-4) var(--sp-5);
  font-family:var(--font-head);
  font-size:clamp(1.0625rem,1.65vw,1.375rem);
  font-weight:var(--fw-bold);
  letter-spacing:var(--tr-snug);
  line-height:1.3;
  text-align:center;text-wrap:balance;
  color:var(--gps-black);
  transition:color var(--dur) var(--ease);
}

/* Hover / focus — identical to .cat-card, including the :focus-within
   pairing so a keyboard user landing on the <a> gets the same state a
   pointer gets. White on German Red is 5.15:1, an approved pairing.
   The affordance is a colour change, not the 3px lift: under
   prefers-reduced-motion the tokens.css guard collapses the transition
   and the lift simply snaps, but the card still fills red. */
.part-card:hover,
.part-card:focus-within{
  background:var(--gps-red);
  border-color:var(--gps-red);
  box-shadow:0 10px 24px rgba(17,17,17,.18);
  transform:translateY(-3px);
}
.part-card:hover .part-card__title,
.part-card:focus-within .part-card__title{color:var(--gps-white)}

/* The media band keeps its white ground so the artwork stays legible;
   only its hairline takes the fill, which reads as the colour sweeping
   up behind the illustration. */
.part-card:hover .part-card__media,
.part-card:focus-within .part-card__media{border-bottom-color:var(--gps-red)}

/* ---------- Band B grid ---------- */
.promos__grid{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:50px;
  margin:0;padding:0;list-style:none;
}
.promos__item{display:flex}

/* ---------- Promo banner ----------
   Full-bleed artwork with live HTML text over it. Black ground behind
   the SVG so a slow paint never flashes white behind white text.

   One grid cell, two layers. The media and the body are both placed in
   row 1 / column 1, so the row resolves to max(media, body) and the
   card is as tall as whichever layer needs more. The obvious version of
   this — abspos body over an aspect-ratio media — makes the card height
   a pure function of its width, and then `overflow:hidden` quietly eats
   whatever the copy needs beyond it. Measured before this was changed:
   at a 320px viewport with the browser text size at 150% the body ran
   288.4px inside a 173.3px card and the first line of every title was
   clipped away, a WCAG 1.4.4 failure; at 100% an editor title running
   to five lines did the same. aspect-ratio is not a rem, so it does not
   grow with the text — the grid row does. */
.promo-card{
  position:relative;width:100%;
  display:grid;
  grid-template-columns:minmax(0,1fr);
  grid-template-rows:auto;
  background:var(--gps-black);
  border-radius:var(--radius-tile);
  overflow:hidden;
  text-decoration:none;
  box-shadow:0 2px 8px rgba(0,0,0,.10);
  transition:box-shadow var(--dur) var(--ease);
}

/* aspect-ratio sets the FLOOR the row is sized from; align-self:stretch
   then lets the artwork grow to whatever the row became, so a card the
   copy has made taller is still covered edge to edge rather than
   leaving the black ground showing above the banner. */
.promo-card__media{
  grid-area:1/1;align-self:stretch;
  display:block;position:relative;aspect-ratio:3/2;overflow:hidden;
  /* width is NOT optional here. align-self:stretch gives this box a
     definite block size, and aspect-ratio would then derive the inline
     size from it -- so a card made taller by long copy would grow the
     artwork wider than the card. Pinning the width keeps aspect-ratio
     doing its only job: setting the row-height floor. */
  width:100%;
}
.promo-card__art{
  position:absolute;inset:0;width:100%;height:100%;
  transform-origin:50% 40%;      /* the subject sits above centre in all four */
  transition:transform var(--dur-slow) var(--ease);
}

/* Same guard as the part card. `gps-banner` is 900x600 and already
   matches this box, but a client can drop any crop into a featured
   image and the default fill would stretch it. */
img.promo-card__art{object-fit:cover}

/* Hover deepen, as a flat wash on its own layer. It has to be a separate
   element animated with opacity: gradient backgrounds do not interpolate
   reliably across engines, so transitioning the scrim itself would jump. */
.promo-card__media::after{
  content:"";position:absolute;inset:0;
  background:rgba(17,17,17,.40);
  opacity:0;
  transition:opacity var(--dur) var(--ease);
}

/* ---------- Promo copy + scrim ----------
   The scrim lives on the body, and its ramp is measured in rem rather
   than % so it always finishes exactly at the padding edge where the
   title starts. Percent stops would drift as soon as a title wrapped to
   two lines, and the text would creep into the transparent part.

   Contrast, computed against the lightest pixel the artwork can put
   under the text (#ffffff — the worst case of the six palette fills):
     rest   .66 over #ffffff          -> #626262 -> white text  6.10:1  AA
     hover  the .40 wash, then the .66 -> #424242 -> white text 10.05:1  AAA
   Every other fill lands higher (#ffce00 7.77:1, #cccccc 7.94:1,
   #dd0000 14.50:1), so the title clears 4.5:1 over any of the four
   banners at any crop. The CTA's white border is a non-text component
   and needs 3:1; at 6.10:1 it clears that too. */
.promo-card__body{
  --promo-scrim-ramp:4.5rem;
  grid-area:1/1;align-self:end;   /* sits on the media, sizes the row */
  position:relative;              /* paints above the media, still in flow */
  display:flex;flex-direction:column;align-items:flex-start;
  gap:var(--sp-4);
  padding:var(--promo-scrim-ramp) clamp(var(--sp-5),2.6vw,var(--sp-7))
          clamp(var(--sp-5),2.2vw,var(--sp-6));
  background:linear-gradient(180deg,
    rgba(17,17,17,0) 0,
    rgba(17,17,17,.66) var(--promo-scrim-ramp),
    rgba(17,17,17,.88) 100%);
}

.promo-card__title{
  font-family:var(--font-head);
  font-size:clamp(1.25rem,2.1vw,1.75rem);
  font-weight:var(--fw-bold);
  letter-spacing:var(--tr-snug);
  line-height:1.22;
  color:var(--gps-white);
  text-wrap:balance;
}

/* Sharp corners, not a rounded pill: the brand is flat and .btn sets
   --radius-0 everywhere else. Sized and tracked like .btn so the two
   read as the same control at two weights. */
.promo-card__cta{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:2.75rem;padding:var(--sp-2) var(--sp-6);
  border:2px solid var(--gps-white);
  border-radius:var(--radius-0);
  font-family:var(--font-head);
  font-size:var(--fs-xs);
  font-weight:var(--fw-bold);
  letter-spacing:var(--tr-wide);
  text-transform:uppercase;
  color:var(--gps-white);
  transition:background var(--dur) var(--ease),
             border-color var(--dur) var(--ease),
             color var(--dur) var(--ease);
}

/* Hover / focus. Same :focus-within pairing as the part card. The pill
   inverts to solid yellow with black text — an approved pairing, and
   the same fill as .btn--primary, which is the site's one CTA colour. */
.promo-card:hover,
.promo-card:focus-within{box-shadow:0 10px 24px rgba(17,17,17,.18)}
.promo-card:hover .promo-card__art,
.promo-card:focus-within .promo-card__art{transform:scale(1.06)}
.promo-card:hover .promo-card__media::after,
.promo-card:focus-within .promo-card__media::after{opacity:1}
.promo-card:hover .promo-card__cta,
.promo-card:focus-within .promo-card__cta{
  background:var(--gps-yellow);
  border-color:var(--gps-yellow);
  color:var(--gps-black);
}

/* ---------- Narrower viewports ----------
   Breakpoints are the canonical ladder declared at the top of base.css
   so the page steps down in one motion instead of section by section. */
@media (width < 64rem){
  .parts__grid{gap:35px 24px}
  .promos__grid{gap:32px}
  .promo-card__body{--promo-scrim-ramp:3.5rem}
}

/* Single column from tablet portrait down. Two 3:2 banners side by side
   below this width leave the title on three lines. */
@media (width < 48rem){
  .parts__grid{grid-template-columns:minmax(0,1fr);gap:35px}
  .promos__grid{grid-template-columns:minmax(0,1fr);gap:25px}
}

@media (width < 30rem){
  .part-card__title{min-height:0;font-size:var(--fs-base)}
  .promo-card__body{--promo-scrim-ramp:3rem;gap:var(--sp-3)}
}
