/* Apple Newsroom rhythm, ported to the dark product page.
 *
 * Source study: apple.com/eg/newsroom/2024/09/apple-introduces-iphone-16-iphone-16-plus
 * Four things were lifted from it, and nothing else:
 *
 *   1. ONE easing curve. The newsroom ships ~90 transitions and 58 of them use
 *      cubic-bezier(.4,0,.25,1). Everything here uses the same one.
 *   2. ONE reveal animation — opacity 0 + translateY(20%) over 800ms, fired once
 *      as the element crosses the bottom of the viewport, staggered by DISTANCE
 *      (not delay) so a grid's cards fan in and land together.
 *   3. A four-step type scale, with tracking that goes negative as size goes up.
 *      Latin only: Arabic letters join, so negative tracking closes the joins.
 *   4. Captions under visuals that state the benefit, at 12px in a muted ink.
 *
 * This file is additive. It overrides, it never removes.
 */

:root {
  --ease-apple: cubic-bezier(.4, 0, .25, 1);
  --reveal-duration: 800ms;
  --reveal-distance: 20%;

  /* The newsroom's article body sits on four sizes and nothing between them.
     The product title keeps whatever the page already set for it; the three
     section headings below it collapse onto a single step. */
  --t-section: clamp(1.75rem, 4vw, 2.25rem);
  --t-lede: clamp(1rem, 2.4vw, 1.1875rem);
  --t-caption: .75rem;

  /* SF Pro Display is already tight, so Apple only needs -0.003em at 48px.
     Inter is not, so the equivalent optical correction here is about -0.022em. */
  --track-display: -.022em;
  --track-caption: .01em;

  --rhythm-image: 44px;
  --ink-caption: #6e6e73;
}

html[data-theme="dark"] {
  /* #6e6e73 on #000 is 4.06:1 — it fails body text. #a1a1a6 is 8.1:1. */
  --ink-caption: #a1a1a6;
}

/* ─── 1. Type scale ───────────────────────────────────────────────────────── */

/* The three section headings were 28 / 26.5 / 23.2px at the same breakpoint —
   three sizes doing one job.
   responsive.css marks its own heading sizes !important inside two breakpoints,
   and apple-spec-sheet.css does the same for the specs heading, so below 900px
   the plain rule lost and the three drifted apart again. Scoping to
   body.product-page outranks both without touching either. */
.features-title,
.specs-title,
.related-title {
  font-size: var(--t-section);
}

body.product-page .features-title,
body.product-page .specs-title,
body.product-page .related-title {
  font-size: var(--t-section) !important;
  /* Same breakpoints also force -0.5px onto these headings. They are Arabic. */
  letter-spacing: 0 !important;
}

/* Deliberately NOT raised past responsive.css's
   `.static-product-page .product-specs-summary .specs-title` (0,3,0 !important).
   On the pages that wrap their spec sheet in a <details>, .specs-title is the
   <summary> label of a collapsed disclosure, not a section heading — it should
   read smaller than "المميزات" and "منتجات مشابهة", so that rule is left to win.
   Do not "fix" this by out-specificity-ing it. */

/* Tracking is applied to the Latin run, not the heading, so an Arabic heading
   sits at 0 while an embedded `iPhone 16` still gets its optical correction. */
.phero-title,
.features-title,
.specs-title,
.related-title,
.tcta-text h3 {
  letter-spacing: 0;
}

.phero-title [lang="en"] {
  letter-spacing: var(--track-display);
}

/* responsive.css pulls the product title to -0.055em !important. That is about
   the tightest SF Pro Display ever gets set, and Inter has looser sidebearings
   than SF Pro, so at 57px it was closing up the counters. live-product.js also
   rewrites the <h1> and drops the [lang="en"] wrapper, so the correction has to
   land on the heading itself — the copy in it is a Latin product name. */
/* Scoped to body.product-page rather than .static-product-page so it also covers
   the three pages that never got the second class. */
body.product-page .phero-title {
  letter-spacing: var(--track-display) !important;
}

.features-title [lang="en"],
.specs-title [lang="en"],
.related-title [lang="en"],
.tcta-text h3 [lang="en"] {
  letter-spacing: -.012em;
}

/* ─── 2. Section ledes and captions ───────────────────────────────────────── */

/* Every newsroom section is eyebrow → heading → one paragraph saying what the
   section is for → the visual. The paragraph was the missing step here. */
.ar-lede {
  font-size: var(--t-lede);
  line-height: 1.55;
  color: var(--ink-caption);
  max-width: 46ch;
  margin: .9rem auto 0;
}

.features-head .ar-lede,
.specs-head .ar-lede,
.related-head .ar-lede {
  text-align: center;
}

.features .ar-lede {
  color: rgba(255, 255, 255, .62);
}

/* 12px, muted, one sentence, and it sells the benefit rather than naming the
   thing in the picture — that is the whole of Apple's caption convention. */
.ar-caption {
  font-size: var(--t-caption);
  line-height: 1.45;
  letter-spacing: var(--track-caption);
  color: var(--ink-caption);
  text-align: center;
  max-width: 42ch;
  margin-inline: auto;
}

/* Sits in the grid's second row under the photo column, so the hero's existing
   two-column centring is untouched. */
.phero-caption {
  grid-column: 2;
  margin-top: calc(var(--rhythm-image) / -2);
  padding-inline: 1rem;
}

/* A comparative number under each feature card. The newsroom never states a
   figure on its own — it is always "30 percent faster than A16". */
.feature-metric {
  display: block;
  margin-top: .7rem;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: var(--track-caption);
  color: rgba(255, 255, 255, .78);
}

.feature-metric b,
.feature-metric [lang="en"] {
  font-family: var(--font-en);
}

.feature-metric b {
  font-weight: 800;
  color: #fff;
}

/* The hero is a two-column grid on desktop, so the caption is parked in row 2 of
   the photo column. On the one-column layout that column does not exist — left
   as `grid-column: 2` it would invent an implicit second column. */
@media (max-width: 900px) {
  .phero-caption {
    grid-column: 1;
    order: 1;
    margin-top: .75rem;
  }
}

/* ─── 3. One reveal, one curve ────────────────────────────────────────────── */

@keyframes ar-reveal {
  from {
    opacity: 0;
    transform: translateY(var(--ar-distance, var(--reveal-distance)));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Keyed on the attribute, which a blocking snippet in <head> sets before first
   paint and a watchdog clears if the engine never starts. Content is therefore
   only ever hidden while something is guaranteed to bring it back. */
html[data-reveal] [data-reveal-item]:not(.ar-in) {
  opacity: 0;
}

html[data-reveal] [data-reveal-item].ar-in {
  animation: ar-reveal var(--reveal-duration) var(--ease-apple) both;
}

/* The engine drops [data-reveal-item] on animationend, so nothing here outlives
   the reveal — a card's :hover transform is never left fighting a finished
   animation's `transform: none`. */

@media (prefers-reduced-motion: reduce) {
  html[data-reveal] [data-reveal-item],
  html[data-reveal] [data-reveal-item]:not(.ar-in) {
    opacity: 1;
    animation: none;
  }
}

/* The page's hover transitions were all on the browser default `ease`. */
.feature-card,
.related-card,
.storage-opt,
.color-swatch,
.btn,
.tcta-btn,
.nav-cta {
  transition-timing-function: var(--ease-apple);
}

/* ─── 4. Dark-theme contrast ──────────────────────────────────────────────── */

/* .related-* was never given a dark rule, so the cards kept their light #f0f0f2
   background while `html[data-theme=dark] a` painted the text white — the name
   and the price were rendering at 1.06:1. */
html[data-theme="dark"] .related-card {
  background: #101010;
  border: 1px solid #2a2a2a;
}

html[data-theme="dark"] .related-card:hover,
html[data-theme="dark"] .related-card:focus-visible {
  background: #181818;
  box-shadow: none;
}

html[data-theme="dark"] .related-name,
html[data-theme="dark"] .related-price {
  color: #f5f5f7;
}

html[data-theme="dark"] .related-cat,
html[data-theme="dark"] .phero-tagline {
  color: var(--ink-caption);
}

/* Product shots stay on white — the same call the catalog cards already make. */
html[data-theme="dark"] .related-img {
  background: #fff;
}

/* ═══════════════════════════════════════════════════════════════════════════
 * ADDENDUM — apple.com/eg-ar/iphone-16/specs/
 *
 * The blocks above were lifted from the Newsroom *article*. This addendum comes
 * from the *specs* page, which is a different animal: it is the calmest page
 * Apple ships. Measured from source, the whole 604 KB stylesheet carries
 * FIVE transitions, ZERO @keyframes and ZERO will-change.
 *
 * Only what this page can actually use was ported. Deliberately skipped:
 *
 *   · U+200F (RLM) after Latin runs. Apple ships 134 of them. Here the same job
 *     is already done by `[lang="en"]{unicode-bidi:plaintext}` in css/i18n.css,
 *     and editing the Arabic text nodes to insert RLM would change the strings
 *     the i18n dictionary is keyed on — every touched line would silently lose
 *     its English translation.
 *   · One composited lineup image for the five colours. Apple can do that
 *     because their swatch strip is decorative; ours is five focusable buttons.
 *   · Apple's 24/17/12 ramp inside the sheet. This page's spec sheet follows the
 *     iPad Pro three-column card layout, which is a different Apple pattern —
 *     re-ramping it would fight apple-spec-sheet.css for no gain.
 * ══════════════════════════════════════════════════════════════════════════ */

/* ─── 5. The four-duration motion budget ──────────────────────────────────── */

/* Every transition on the specs page falls into one of four buckets. Nothing
   else moves. The product page had grown eleven distinct durations
   (.16 .18 .2 .22 .25 .3 .35 .45 .5 .7 .8s), which is why its hovers never
   felt like one system. */
:root {
  --dur-hover: 100ms;   /* colour/opacity under the cursor — Apple uses linear */
  --dur-color: 240ms;   /* a colour or background that is a state change */
  --dur-panel: 320ms;   /* something opening or closing */
  --dur-image: 500ms;   /* an image arriving */

  /* The two curves the specs page actually ships. --ease-apple above is the
     Newsroom's; these are the nav/menu and hover curves from ac-localnav. */
  --ease-nav: cubic-bezier(.4, 0, .6, 1);
  --ease-hover: cubic-bezier(.28, .11, .32, 1);
}

/* Hover feedback: 100ms, linear. Apple never eases a hover — at 100ms an easing
   curve is imperceptible and only delays the response. */
body.product-page .btn,
body.product-page .nav-cta,
body.product-page .tcta-btn,
body.product-page .storage-opt,
body.product-page .color-swatch,
body.product-page .tl-thumb {
  transition-duration: var(--dur-hover);
  transition-timing-function: linear;
}

/* State changes that carry a bit more weight get the 240ms hover curve. */
body.product-page .feature-card,
body.product-page .related-card,
body.product-page .spec-row {
  transition-duration: var(--dur-color);
  transition-timing-function: var(--ease-hover);
}

/* `transition: all` appears three times in this page's own <style>. It makes the
   browser watch every animatable property, and it is why a card's hover could
   drag its box-shadow and its border into the same frame as its transform.
   Naming the properties costs nothing and is what Apple does everywhere. */
body.product-page .feature-card,
body.product-page .related-card {
  transition-property: transform, border-color, background-color, box-shadow, color;
}

/* Same treatment for the two that were given a duration above but left on the
   `all` default — a spec row that animates `all` will happily transition its own
   grid-column when html.text-zoom flips the sheet from three tracks to two. */
body.product-page .spec-row {
  transition-property: background-color, border-color, color;
}

body.product-page .tl-lightbox {
  transition-property: opacity, transform;
}

body.product-page .btn,
body.product-page .nav-cta,
body.product-page .tcta-btn {
  transition-property: background-color, border-color, color, opacity, transform;
}

/* Anything that opens or closes. */
body.product-page .tl-lightbox,
body.product-page details > *,
body.product-page .nav-menu {
  transition-duration: var(--dur-panel);
  transition-timing-function: var(--ease-nav);
}

/* An image arriving is the one place Apple spends half a second, and it spends
   it on opacity alone — no scale, no slide. The hero photo carries an inline
   `transition:opacity 0.25s`, so this one needs !important to reach it.
   No will-change: the photo also carries a drop-shadow filter, and promoting a
   filtered layer is what made this shot disappear on iOS Safari before. */
body.product-page .product-photo {
  transition: opacity var(--dur-image) ease-out !important;
}

/* The related-card thumbnail already owns `transform .3s` for its hover zoom, so
   the fade has to be ADDED to that list rather than replace it — a bare
   `transition: opacity` here would silently make the zoom instant. */
body.product-page .related-img img {
  transition:
    transform var(--dur-color) var(--ease-hover),
    opacity var(--dur-image) ease-out;
}

body.product-page .tl-thumb img {
  transition: opacity var(--dur-image) ease-out;
}

/* responsive.css restricts these cards to `transform, opacity, background-color`
   under (max-width: 768px), with !important, under a heading that says why:
   phones must not animate paint-heavy properties. That decision is left standing
   — only its timing is pulled onto the budget, so a card reads the same on a
   phone as on a desktop even though it animates fewer properties.
   Duration and timing-function only. Do not add transition-property here. */
@media (max-width: 768px) {
  body.product-page .feature-card,
  body.product-page .related-card {
    transition-duration: var(--dur-color) !important;
    transition-timing-function: var(--ease-hover) !important;
  }
}

/* Buttons are deliberately NOT in the block above. responsive.css restricts
   their transition-property on phones but never touches their duration, so the
   100ms hover rule already reaches them — listing them here only made a tap
   respond slower on the device where it matters most. */

/* ─── 6. Apple's actual frosted-glass recipe ──────────────────────────────── */

/* The sticky sub-nav already blurs. Apple's localnav pairs the blur with a
   saturation boost, and that is the whole trick: blurring alone greys out the
   colour behind the bar, so the page reads as washed rather than as glass.
   Guarded exactly the way Apple guards it, because a browser without
   backdrop-filter must keep the opaque background it already has. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  body.product-page .apple-spec-subnav {
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
  }
}

/* ─── 7. Text-zoom adaptation ─────────────────────────────────────────────── */

/* js/apple-rhythm.js measures a probe span with a ResizeObserver and sets
   html.text-zoom when the browser's minimum-font-size floor lifts the rendered
   size above what was asked for. This is Apple's own mechanism, and the specs
   page uses it to re-tune anything whose size was hand-set.
   Everything below only ever gives text MORE room, so a false positive is
   harmless. */

/* The spec sheet is a fixed three-column grid. At a raised font floor the
   values wrap to four and five lines inside a 112px-min card and start
   colliding with the hairline. Two columns, then one. */
html.text-zoom body.product-page .specs-table {
  grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
}

@media (max-width: 900px) {
  html.text-zoom body.product-page .specs-table {
    grid-template-columns: minmax(0, 1fr) !important;
  }
}

/* The last-row grid-column fixups above assume three tracks. At two, a trailing
   odd row should span both rather than leave half a row of unpainted hairline. */
html.text-zoom body.product-page .specs-table .spec-row:last-child:nth-child(3n + 1),
html.text-zoom body.product-page .specs-table .spec-row:last-child:nth-child(3n + 2) {
  grid-column: 1 / -1 !important;
}

/* Measures set in `ch` already track the font size. These two are the ones set
   in absolute terms, so they need lifting by hand. */
html.text-zoom .ar-lede { max-width: 54ch; }
html.text-zoom .ar-caption { max-width: 50ch; }

/* ─── 8. Rhythm that scales with the text, not with the root ──────────────── */

/* Apple sets the specs section's padding in em — 3.588em top, 3.294em bottom,
   against a 17px body — so the whitespace grows with the type. This page had it
   in rem, which is measured against the root and therefore stays put while the
   text inside it grows.
   Loaded after apple-spec-sheet.css, so equal specificity plus !important wins.
   The clamp keeps the existing responsive behaviour; only the middle term and
   the unit change. */
body.product-page .specs {
  padding-block: clamp(3.588em, 6vw, 5.6em) !important;
}

/* ─── 9. Collapsing the type ramp ─────────────────────────────────────────── */

/* Measured on the rendered page before this block: FIFTEEN distinct rendered
   font sizes. The specs page at apple.com/eg-ar/iphone-16/specs/ renders three.
   The damage was concentrated in one band — 13px on 49 elements, 14px on 28,
   15px on 33 — three steps splitting two jobs (label and body) so finely that
   the difference reads as inconsistency rather than hierarchy. Worse, a feature
   card's <h3> was 15px sitting directly above its own 14px description: a 1px
   "hierarchy" is not one.
   These four steps are all the page's running text needs.
   The display sizes above them (28px section heading, 34/58px product title) are
   already single steps and are not touched. */
:root {
  --t-label: .8125rem;  /* 13px — eyebrows, spec labels, metrics, counters */
  --t-body: .9375rem;   /* 15px — every sentence the visitor actually reads */

  /* A card heading has to clear its own body copy by a real interval, not by a
     pixel. Scales with the viewport because it is a heading, unlike body copy,
     which should stay put. */
  --t-subhead: clamp(1.1875rem, 1.6vw, 1.375rem);
}

/* Apple's reading size is 17px and the lede is the one paragraph on the page
   doing that job. The clamp's floor was 16. */
:root {
  --t-lede: clamp(1.0625rem, 2.4vw, 1.1875rem);
}

/* The home page's own two display steps. They are separate variables from
   --t-section because the home page's headings live on a different, larger scale
   than a product page's — the point is one step per job, not one number sitewide.

   These are clamps rather than fixed values because their peers already are:
   .sec-title alone is declared EIGHT different ways across breakpoints in
   home.css and responsive.css (1.8rem, 2.6rem, 26px!important, and five separate
   clamps). Chasing exact parity with that through a variable is not possible, so
   these were set and then verified against .sec-title at mobile, tablet and
   desktop widths — which is the only check that actually means anything here. */
:root {
  --t-home-subhead: clamp(1.1875rem, 1.8vw, 1.375rem);   /* 19 → 22 */
}

/* 14px → body. These are sentences, and they were a pixel below the 15px used by
   every other sentence on the page for no reason anyone could point at.
   !important throughout: responsive.css sets several of these inside breakpoint
   blocks that are themselves !important, and a ramp that only holds above 900px
   is not a ramp. */
body.product-page .feature-desc,
body.product-page .ac-block p {
  font-size: var(--t-body) !important;
}

/* .spec-value needs the .specs-table qualifier to reach (0,3,1): apple-spec-sheet
   .css steps it 15px → 14px inside its own breakpoint block at that specificity,
   and a plain `body.product-page .spec-value` loses to it below 900px.
   The step-down is not load-bearing — the sheet is already a single column at
   that width, so there is room for the reading size. This file loads after
   apple-spec-sheet.css, so equal specificity plus !important carries it. */
body.product-page .specs-table .spec-value {
  font-size: var(--t-body) !important;
}

/* .storage-opt is deliberately NOT here. responsive.css pins it to 13.5px twice,
   once in a breakpoint and once at
   `.static-product-page .catalog-storage-config .storages:has(...) .storage-opt`,
   which is (0,4,0) !important. Beating that means (0,5,0), and it would be
   fighting a fit decision rather than a type decision: these are pills whose
   label ("512GB") has to stay on one line inside a fixed radius. A control label
   is closer to the label step than the body step anyway, and 13.5 against 13 is
   half a pixel nobody can see. Left alone on purpose. */

/* 14px → label. An eyebrow is not body copy; it belongs with the spec labels and
   the metrics, which were already at 13. */
body.product-page .sboxes-eyebrow {
  font-size: var(--t-label) !important;
}

/* The last six strays, found by re-measuring the rendered page after the block
   above landed. Each one is a label sitting a pixel off the label step, or a
   sentence sitting a pixel off the reading step — nothing that needed its own
   size, which is exactly how a ramp grows to fifteen steps in the first place. */
body.product-page .sbox span,
body.product-page .catalog-color-name .selected,
body.product-page span.selected {
  font-size: var(--t-label) !important;
}

body.product-page .tax-paid-warranty-copy,
body.product-page .tax-paid-warranty-copy strong {
  font-size: var(--t-body) !important;
}

/* The one size that goes UP. A feature card now reads heading-then-description
   instead of two lines of nearly the same size. */
body.product-page .feature-name {
  font-size: var(--t-subhead) !important;
  line-height: 1.3;
}

/* The trade-in block's <h3> was rendering at 32px against the 28px shared by
   "المميزات", "المواصفات" and "منتجات مشابهة". It introduces a section like they
   do, so it takes the same step. */
body.product-page .tcta-text h3 {
  font-size: var(--t-section) !important;
}

/* Deliberately left off the ramp, so nobody "finishes the job" later:
   · the price (30px, weight 800) is a display figure, not running text;
   · .product-specs-summary .specs-title (23px) is a <summary> label on the pages
     that collapse their spec sheet — section 1 above explains why it must stay
     smaller than a real section heading;
   · .product-specs-summary-icon (22px) is the "+" affordance, not type. */

/* ─── 10. The shared chrome ───────────────────────────────────────────────── */

/* Everything above stopped at the product content. Re-measuring the rendered
   page found ~34 more elements still on 0.2s, and they were all in the furniture
   the product page shares with the rest of the site: the top nav, the breadcrumb,
   the footer columns, the configurator's controls, the social rail.
   Every one of them is the same interaction — a link or a control answering the
   cursor — which is Apple's 100ms linear bucket. At 100ms an easing curve is
   below the threshold of perception and only delays the answer, which is why
   apple.com sets exactly `100ms linear` on its own nav links.

   DURATION AND CURVE ONLY. No transition-property here: these selectors reach
   components owned by other files (the global nav, the footer, social-fab.js),
   and narrowing what they animate from this file would be editing their
   behaviour blind. Timing is cosmetic; property lists are not.

   Scoped to body.product-page because apple-rhythm.css only loads on product
   pages. The home, catalog and checkout pages keep their own timings — bringing
   them onto the budget is a separate job with a much wider blast radius. */
body.product-page .site-nav a,
body.product-page .site-nav button,
body.product-page .nav-links a,
body.product-page .nav-actions a,
body.product-page .nav-actions button,
body.product-page .breadcrumb a,
body.product-page footer a,
body.product-page .footer-col a,
body.product-page .social-link,
body.product-page .product-configurator a,
body.product-page .product-configurator button,
body.product-page .product-configurator label {
  transition-duration: var(--dur-hover);
  transition-timing-function: linear;
}

/* The stragglers, found by measuring again after section 10 landed. Each is a
   control the earlier selectors missed because it does not live where its name
   suggests — the swatches and capacity pills sit outside .product-configurator,
   and the social rail's own furniture is not .social-link.

   !important here, unlike section 10, because several of these are pinned by
   breakpoint blocks in responsive.css. Overriding a duration is safe in a way
   that overriding a property list is not: the worst case is that a hover answers
   faster than its author expected. */
body.product-page .skip-link,
body.product-page .theme-toggle,
body.product-page .color-swatch,
body.product-page .storage-opt,
body.product-page .catalog-gallery-thumb,
body.product-page .tl-thumb,
body.product-page .social-fab-toggle {
  transition-duration: var(--dur-hover) !important;
  transition-timing-function: linear !important;
}

/* These two open and close rather than respond to a cursor, so they belong in the
   panel bucket with the nav curve. */
body.product-page .social-fab,
body.product-page .social-fab-options {
  transition-duration: var(--dur-panel) !important;
  transition-timing-function: var(--ease-nav) !important;
}

/* The disclosure "+" is a state change, not a hover and not a panel. */
body.product-page .product-specs-summary-icon {
  transition-duration: var(--dur-color) !important;
  transition-timing-function: var(--ease-hover) !important;
}

/* The last five, all inside components that inject their own inline styles at
   runtime (social-fab.js, the sticky buy bar). Their svg children inherit a
   transition from the button, so the child is named too. */
body.product-page .social-fab-link,
body.product-page .social-fab-link svg,
body.product-page .tip-sticky-buy,
body.product-page .tip-sticky-buy svg,
body.product-page .tip-sticky-buy button {
  transition-duration: var(--dur-hover) !important;
  transition-timing-function: linear !important;
}

/* ═══════════════════════════════════════════════════════════════════════════
 * 11. THE HOME PAGE
 *
 * Everything above this line is scoped to body.product-page. This section is
 * scoped to body.home-page, and the two share only the :root budget — which is
 * the point of putting them in one file rather than two: one set of durations
 * and one set of type steps for the whole site, not a copy that drifts.
 *
 * Checked before wiring this file into index.html: of every class the sections
 * above style unscoped, only .social-link exists on the home page, and its rule
 * up there is scoped to body.product-page. Nothing above leaks here.
 *
 * Measured on the rendered home page first. It was worse than any product page:
 * SEVENTEEN type steps and ELEVEN durations, with 300 elements off the budget.
 * ══════════════════════════════════════════════════════════════════════════ */

/* ─── 11a. Type ─────────────────────────────────────────────────────────────
 * Three separate crowds, each doing one job with several sizes:
 *   · 12 / 13 / 14 — 434 elements of labels and badges
 *   · 18 / 20 / 22 — three sizes of card heading
 *   · 26 / 29      — two sizes of section heading
 * Each collapses onto the step that already carried the most of its own kind.
 */

/* → label. .drop-label alone is 77 elements; .rv-name and .cat-name are card
   labels that were sitting a pixel above the badges beside them. */
body.home-page .drop-label,
body.home-page .rv-name,
body.home-page .cat-name {
  font-size: var(--t-label) !important;
}

/* .rv-price goes the OTHER way, to the body step. It was the same 14px as the
   name above it, so the recently-viewed card had a name and a price rendering
   identically. Splitting them across two steps that already exist gives the card
   a hierarchy without inventing a size. */
body.home-page .rv-price {
  font-size: var(--t-body) !important;
}

/* Emphasis inside a sentence was rendering LARGER than the sentence — 17px
   <strong> inside 15px copy. That is not a ramp problem, it is a bug: <strong>
   means important, not bigger. Inherit, and let the weight carry it. */
body.home-page .store-gateway-copy strong {
  font-size: inherit !important;
}

/* → subhead. .store-name was 18, .rv-title 20, .why-title and
   .portal-card-title 22 — four card headings across three sizes. */
body.home-page .store-name,
body.home-page .why-title,
body.home-page .portal-card-title {
  font-size: var(--t-home-subhead) !important;
}

/* → section heading. .tradein-title is NOT handled here, and that is the point.
   The first attempt gave it `--t-home-section`, a single clamp. Measuring at
   1280px showed why that cannot work: .sec-title is declared eight different
   ways across breakpoints and reaches 51.2px there, while any one clamp that
   also has to land near 26px on mobile tops out around 38px. The variable made
   the gap WIDER than the 3px it was sent to close.
   The fix is upstream instead: `.tradein-title` was added to the selector list of
   every rule that already sets `.sec-title`'s font-size — four in home.css, four
   in responsive.css. One declaration, two elements, and no third place to drift.
   Do not re-add a font-size for it here. */

/* ─── 11b. Motion ───────────────────────────────────────────────────────────
 * The same four buckets. Every duration below was measured on the page, not
 * guessed: plain links were split across 0.15s and 0.2s, the cards across 0.18,
 * 0.2, 0.25 and 0.3, and the choice buttons sat on 0.16.
 */

/* Hover feedback → 100ms linear. `a` at 0.15s is 86 elements, the single largest
   group on the page. */
body.home-page a,
body.home-page button,
body.home-page .cat-arrow,
body.home-page .device-choice,
body.home-page .capacity-choice,
body.home-page .condition-choice,
body.home-page .repair-state-choice,
body.home-page .repair-quality-choice {
  transition-duration: var(--dur-hover) !important;
  transition-timing-function: linear !important;
}

/* Cards are a state change, not a hover tick → 240ms on the hover curve. Listed
   after the block above on purpose: .prod-card and .rv-card are anchors and
   .cat-card is a button, so they match up there too and need to win here. */
body.home-page .prod-card,
body.home-page .rv-card,
body.home-page .cat-card,
body.home-page .why-card,
body.home-page .store-card,
body.home-page .store-gateway,
body.home-page .photo-slot {
  transition-duration: var(--dur-color) !important;
  transition-timing-function: var(--ease-hover) !important;
}

/* A card's photo zooms on hover. That zoom belongs to the card, so it takes the
   card's timing — NOT the 500ms image bucket, which is for an image arriving.
   Half a second of scale on hover reads as lag, not as polish. */
body.home-page .prod-card img,
body.home-page .cat-card img,
body.home-page .cat-img,
body.home-page .store-card img {
  transition-duration: var(--dur-color) !important;
  transition-timing-function: var(--ease-hover) !important;
}

/* This one IS an image arriving — live-product covers fade in when they load. */
body.home-page .live-cover-ready {
  transition-duration: var(--dur-image) !important;
  transition-timing-function: ease-out !important;
}
