/* ============================================================
   Luxshine — "What Is Vietnamese Remy Hair?", concept 2 (2026-10-20).
   A plain brand-site layout after the user's three references
   (greatlengths.com, kalugahair.ae, leshinehairs.com): the solid header
   above, the title over two joined photos, copy beside media, white cards
   on beige, the shared table, a three-column tier band, the textures
   beside the colour chart, then the shared contact block and footer.
   Same type as concept 1 (Bergola caps, SVN-Gilroy, the gold bar under
   the words a title leans on, Body lớn 28) and the same strong motion:
   the user chose to keep it. White and beige only, no dark blocks.
   Tokens only; spacing on the 12-step scale.
   Markup: what-is-vietnamese-remy-hair-v2.html · words: js/remy-v2.js.

   Three layers, in this order:
   1. Layout. Everything is simply there. Small screens, reduced motion
      and browsers without scroll-driven animations stop here.
   2. Entrances. js/main.js adds .is-in to [data-reveal] on first view.
   3. Scroll scenes. CSS scroll-driven animations, desktop only.
   Transform, translate, scale and opacity only.
   ============================================================ */
.rv { --rv-ease: cubic-bezier(.16, 1, .3, 1); --rv-rule: color-mix(in srgb, var(--color-black) 16%, transparent); position: relative; overflow-x: clip; background: var(--color-white); color: var(--color-black); }
.rv-contact, .rv-foot { --rv-ease: cubic-bezier(.16, 1, .3, 1); }
/* The contact block keeps the page frame: the container's 24px margins. */
.rv-contact .contact__inner { padding-inline: var(--space-6); }

/* ---------- Sections ---------- */
.rv-sec { padding-block: var(--space-24); background: var(--color-white); }
.rv-sec--beige { --rv-curtain: var(--surface-beige); background: var(--surface-beige); }
/* Whatever follows a section title starts 64px under it (32px for its opening paragraph). */
.rv-body { margin-top: var(--space-16); }

/* ---------- Type ---------- */
.rv-h1, .rv-h2 { font-family: var(--font-heading); font-weight: 400; text-transform: uppercase; color: inherit; }
/* The page title: display size on a desktop, never under the phone h1 (34px). */
.rv-h1 { font-size: max(var(--h1-size), var(--display-2-size)); line-height: var(--display-2-lh); text-align: center; }
.rv-h2 { font-size: var(--h1-size); line-height: var(--h1-lh); }
.rv-center { text-align: center; }
/* Each line of a title sits in its own mask, so it can rise into place; a line too long wraps inside it. */
.rv-line { display: block; overflow: hidden; }
.rv-line__in { display: block; text-wrap: balance; }
/* The gold bar under the words a title leans on, sized in em; it sweeps in from the left (Layer 2). */
.rv-hl { position: relative; z-index: 0; display: inline-block; }
.rv-hl::after { content: ""; position: absolute; z-index: -1; left: 0; right: 0; bottom: .16em; height: .4em; background: var(--color-primary); transform-origin: 0 50%; }
/* Body lớn 28/140, fixed on a desktop (user 2026-10-14). */
.rv-lead { max-width: 34em; font-size: var(--display-3-size); line-height: var(--display-3-lh); color: var(--color-black); text-wrap: pretty; }
.rv-h2 + .rv-lead { margin-top: var(--space-8); }
.rv-lead.rv-center { margin-inline: auto; text-wrap: balance; }
/* Links that lead on from a section: Body lớn 20 in sentence case, as on concept 1. */
.rv .label-link { font-size: var(--h6-size); line-height: var(--h6-lh); font-weight: 400; text-transform: none; }
.rv .label-link__arrow { width: 20px; height: 20px; }
.rv-more { margin-top: var(--space-12); }
.rv-more--center { display: flex; width: fit-content; margin-inline: auto; }

/* ---------- Photo frame: no stroke, no shadow; a curtain lifts off it on reveal. The picture's own scale
   is a variable, so the reveal, the hover and the scroll drift can share it (Layer 3 enlarges it). ---------- */
.rv-shot { position: relative; overflow: hidden; margin: 0; aspect-ratio: var(--ty-le-khoi_vuong); background: var(--surface-beige); }
.rv-shot img { display: block; width: 100%; height: 100%; object-fit: cover; scale: var(--rv-zoom, 1); }
.rv-shot::after { content: ""; position: absolute; inset: 0; background: var(--rv-curtain, var(--color-white)); transform: scaleY(0); transform-origin: top; pointer-events: none; }

/* ---------- 1 · Hero: the title on white, then two photos joined edge to edge across the screen
   (Great Lengths). The header stays solid above it, as on all three references. No button. ---------- */
.rv-hero { background: var(--color-white); }
.rv-hero__head { padding-block: var(--space-16) var(--space-12); }
.rv-hero__line--b { --rv-dir: -1; }
/* Sized by the screen, not by a ratio: two halves, as tall as about half the window. */
.rv-hero__photos { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); height: clamp(320px, 56svh, 600px); overflow: hidden; }
.rv-hero__photo { position: relative; overflow: hidden; margin: 0; background: var(--surface-beige); }
.rv-hero__photo img { display: block; width: 100%; height: 100%; object-fit: cover; scale: var(--rv-zoom, 1); }
.rv-hero__photo:last-child img { object-position: 50% 40%; }
.rv-hero__photo::after { content: ""; position: absolute; inset: 0; background: var(--color-white); transform: scaleY(0); transform-origin: bottom; pointer-events: none; }

/* ---------- 2 · Introduction: the opening copy and the way on beside the factory film (Kaluga's about row) ---------- */
.rv-intro__grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--space-6); align-items: center; }
.rv-intro__copy { grid-column: 1 / span 5; display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-8); }
.rv-intro__media { grid-column: 7 / -1; position: relative; overflow: hidden; margin: 0; aspect-ratio: var(--ty-le-video); background: var(--surface-beige); }
.rv-intro__media iframe { display: block; width: 100%; height: 100%; border: 0; }
.rv-intro__media::after { content: ""; position: absolute; inset: 0; background: var(--color-white); transform: scaleY(0); transform-origin: top; pointer-events: none; }

/* ---------- 3 · Definition: the square photo first, the second one over its corner, then the title and the
   large reading copy (Great Lengths' product row). The copy keeps a column clear of the photos. ---------- */
.rv-def { padding-block: var(--space-24) calc(var(--space-16) * 2); }
.rv-def__grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--space-6); align-items: center; }
.rv-def__media { grid-column: 1 / span 5; position: relative; }
.rv-def__inset { position: absolute; right: calc(var(--space-12) * -1); bottom: calc(var(--space-12) * -1); z-index: 1; width: 40%; }
.rv-def__text { grid-column: 7 / -1; }
.rv-def__body { display: grid; gap: var(--space-6); max-width: 34em; margin-top: var(--space-12); font-size: var(--display-3-size); line-height: var(--display-3-lh); color: var(--color-black); text-wrap: pretty; }

/* ---------- 4 · Strong by Nature: three white cards on beige (Kaluga's product grid). Each card is a column
   of the grid's own rows, so the photos, the names and the copy line up across the three. ---------- */
.rv-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: var(--space-6); row-gap: 0; }
.rv-card { --rv-curtain: var(--color-white); display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 0; min-width: 0; background: var(--color-white); }
.rv-card__title { padding: var(--space-8) var(--space-8) 0; font-family: var(--font-heading); font-weight: 400; font-size: var(--h4-size); line-height: var(--h4-lh); text-transform: uppercase; color: var(--color-black); }
.rv-card__text { padding: var(--space-3) var(--space-8) var(--space-8); font-size: var(--h6-size); line-height: var(--h6-lh); color: var(--color-black); text-wrap: pretty; }

/* ---------- 5 · Comparison: the site's shared table (.dtable, css/sections.css), Remy as its gold column ---------- */
.rv-vs__table { table-layout: fixed; }
.rv-vs__table thead th:first-child { width: 20%; }
.rv-vs__table td { font-size: var(--h6-size); line-height: var(--h6-lh); }
.rv-vs__note { margin-top: var(--space-16); }

/* ---------- 6 · Quality: the three tiers as one band of three columns with a rule between them (Le Shine's
   figures band). Code in display type, name, then what it is for; the rows line up across the band. ---------- */
.rv-tiers { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin-bottom: 0; padding: 0; list-style: none; }
.rv-tiers__item { position: relative; display: grid; grid-row: span 2; grid-template-rows: subgrid; row-gap: var(--space-6); justify-items: center; padding: var(--space-8) var(--space-8) var(--space-12); text-align: center; }
.rv-tiers__item + .rv-tiers__item::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 1px; background: var(--rv-rule); transform-origin: top; }
.rv-tiers__head { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); font-weight: 400; }
.rv-tiers__mask { display: block; overflow: hidden; }
.rv-tiers__code { display: block; font-family: var(--font-heading); font-size: var(--display-1-size); line-height: var(--display-1-lh); text-transform: uppercase; color: var(--color-black); }
.rv-tiers__name { font-family: var(--font-heading); font-size: var(--h4-size); line-height: var(--h4-lh); text-transform: uppercase; color: var(--color-black); }
.rv-tiers__tag { padding: var(--space-1) var(--space-3); background: var(--color-primary); font-family: var(--font-body); font-size: var(--h6-size); line-height: var(--h6-lh); text-transform: none; color: var(--color-black); }
.rv-tiers__text { max-width: 24em; font-size: var(--h6-size); line-height: var(--h6-lh); color: var(--color-black); text-wrap: balance; }

/* ---------- 7 · Look: the three texture families as rows (square photo beside its copy) on seven columns, the
   factory colour chart in a beige panel on the other five. ---------- */
.rv-look__grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--space-6); align-items: start; }
.rv-look__families { grid-column: 1 / span 7; }
.rv-tex { margin: 0; padding: 0; list-style: none; border-bottom: 1px solid var(--rv-rule); }
.rv-tex__item { display: grid; grid-template-columns: 160px minmax(0, 1fr); column-gap: var(--space-8); align-items: start; padding-block: var(--space-6); border-top: 1px solid var(--rv-rule); }
.rv-tex__item:first-child { padding-top: 0; border-top: 0; }
.rv-tex__shot { aspect-ratio: var(--ty-le-san_pham); }
.rv-tex__name { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2) var(--space-4); font-family: var(--font-heading); font-weight: 400; font-size: var(--h3-size); line-height: var(--h3-lh); text-transform: uppercase; }
.rv-tex__name a { color: var(--color-black); transition: color .2s ease; }
.rv-tex__name a:is(:hover, :focus-visible) { color: var(--color-primary); }
.rv-tex__count { font-family: var(--font-body); font-size: var(--body-size); line-height: var(--body-lh); text-transform: none; color: var(--color-font); }
.rv-tex__desc { margin-top: var(--space-2); font-size: var(--h6-size); line-height: var(--h6-lh); color: var(--color-black); text-wrap: pretty; }
.rv-tex__kinds { margin-top: var(--space-2); font-size: var(--body-size); line-height: var(--body-lh); color: var(--color-font); }
.rv-chart { grid-column: 8 / -1; padding: var(--space-8); background: var(--surface-beige); }
.rv-chart__head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-2) var(--space-6); padding-bottom: var(--space-6); }
.rv-chart__title { font-family: var(--font-heading); font-weight: 400; font-size: var(--h4-size); line-height: var(--h4-lh); text-transform: uppercase; color: var(--color-black); }
.rv-swatches { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--space-4) var(--space-3); margin: 0; padding: 0; list-style: none; }
.rv-swatch { min-width: 0; }
.rv-swatch img { display: block; width: 100%; height: auto; aspect-ratio: var(--ty-le-khoi_vuong); object-fit: cover; }
.rv-swatch__code { display: block; padding-top: var(--space-2); font-size: var(--body-size); line-height: var(--body-lh); font-weight: 600; text-align: center; color: var(--color-black); overflow-wrap: anywhere; }

/* ---------- 8 · Use: the title and the three things the hair lets a salon do, a tall photo beside them ---------- */
.rv-use__grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--space-6); align-items: center; }
.rv-use__text { grid-column: 1 / span 6; }
.rv-use__list { margin: var(--space-12) 0 0; }
.rv-use__item { padding-block: var(--space-6); border-top: 1px solid var(--rv-rule); }
.rv-use__item:last-child { border-bottom: 1px solid var(--rv-rule); }
.rv-use__item dt { font-family: var(--font-heading); font-size: var(--h4-size); line-height: var(--h4-lh); text-transform: uppercase; color: var(--color-black); }
.rv-use__item dd { max-width: 34em; margin: var(--space-2) 0 0; font-size: var(--h6-size); line-height: var(--h6-lh); color: var(--color-black); text-wrap: pretty; }
.rv-use__shot { grid-column: 8 / -1; aspect-ratio: var(--ty-le-editorial); }

/* Pointer feedback: photos in cards and rows lean in a little, swatches lift. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  :is(.rv-card, .rv-tex__item) .rv-shot img { transition: scale .8s var(--rv-ease); }
  :is(.rv-card, .rv-tex__item):hover .rv-shot img { scale: calc(var(--rv-zoom, 1) * 1.06); }
  .rv-swatch img { transition: translate .4s var(--rv-ease); }
  .rv-swatch:hover img { translate: 0 calc(var(--space-1) * -1); }
}

/* ============================================================
   Layer 2 · Entrances. The hidden starting states exist only when
   scripting runs (.js on <html>) and motion is welcome.
   ============================================================ */
:is(.rv, .rv-contact, .rv-foot) [data-reveal-delay="1"] { --rv-d: .12s; }
:is(.rv, .rv-contact, .rv-foot) [data-reveal-delay="2"] { --rv-d: .24s; }
:is(.rv, .rv-contact, .rv-foot) [data-reveal-delay="3"] { --rv-d: .36s; }
/* Order in which the contact form's parts come up, and the footer's links and icons. */
.rv-contact .contact__form > :nth-child(3) { --i: 5; }
.rv-contact .contact__form > :nth-child(4) { --i: 6; }
.rv-contact .contact__form > :nth-child(5) { --i: 7; }
.rv-contact .form__grid > :nth-child(1), .rv-foot :is(.footer__links, .footer__social) > :nth-child(2) { --i: 1; }
.rv-contact .form__grid > :nth-child(2), .rv-foot :is(.footer__links, .footer__social) > :nth-child(3) { --i: 2; }
.rv-contact .form__grid > :nth-child(3), .rv-foot :is(.footer__links, .footer__social) > :nth-child(4) { --i: 3; }
.rv-contact .form__grid > :nth-child(4), .rv-foot :is(.footer__links, .footer__social) > :nth-child(5) { --i: 4; }
.rv-foot :is(.footer__links, .footer__social) > :nth-child(6) { --i: 5; }
.rv-foot .footer__links > :nth-child(7) { --i: 6; }
.rv-foot .footer__links > :nth-child(8) { --i: 7; }
.rv-foot .footer__links > :nth-child(9) { --i: 8; }
.rv-vs__table tbody tr:nth-child(2) { --rv-r: 1; }
.rv-vs__table tbody tr:nth-child(3) { --rv-r: 2; }
.rv-vs__table tbody tr:nth-child(4) { --rv-r: 3; }
.rv-vs__table tbody tr:nth-child(5) { --rv-r: 4; }
@media (prefers-reduced-motion: no-preference) {
  /* The hero plays once on load: the two title lines rise out of their masks, then a curtain drops off
     each photo, left then right, while the pictures settle. */
  .rv-hero .rv-line__in { animation: rv-up 1.2s var(--rv-ease) .15s both; }
  .rv-hero .rv-hero__line--b .rv-line__in { animation-delay: .27s; }
  .rv-hero .rv-hl::after { animation: rv-swipe 1s var(--rv-ease) .9s both; }
  .rv-hero__photo::after { animation: rv-lift 1.4s var(--rv-ease) .3s both; }
  .rv-hero__photo:last-child::after { animation-delay: .45s; }
  .rv-hero__photo img { animation: rv-settle 2.2s var(--rv-ease) .3s both; }

  /* Further down: title lines rise, the gold bar follows, photos lose their curtain, copy comes up. */
  .js .rv-line[data-reveal] .rv-line__in { transform: translateY(105%); transition: transform 1.1s var(--rv-ease) var(--rv-d, 0s); }
  .js .rv-line[data-reveal].is-in .rv-line__in { transform: none; }
  .js .rv [data-reveal] .rv-hl::after { transform: scaleX(0); }
  .js .rv [data-reveal].is-in .rv-hl::after { animation: rv-swipe 1s var(--rv-ease) calc(var(--rv-d, 0s) + .5s) both; }
  .js :is(.rv-shot[data-reveal], [data-reveal] .rv-shot)::after { transform: scaleY(1); transition: transform 1.2s var(--rv-ease) var(--rv-d, 0s); }
  .js :is(.rv-shot[data-reveal].is-in, [data-reveal].is-in .rv-shot)::after { transform: scaleY(0); }
  .js :is(.rv-shot[data-reveal], [data-reveal] .rv-shot) img { scale: calc(var(--rv-zoom, 1) * 1.14); transition: scale 1.8s var(--rv-ease) var(--rv-d, 0s); }
  .js :is(.rv-shot[data-reveal].is-in, [data-reveal].is-in .rv-shot) img { scale: var(--rv-zoom, 1); }
  .js .rv-rise[data-reveal] { opacity: 0; transform: translateY(32px); transition: opacity .9s var(--rv-ease) var(--rv-d, 0s), transform .9s var(--rv-ease) var(--rv-d, 0s); }
  .js .rv-rise[data-reveal].is-in { opacity: 1; transform: none; }
  .js .rv-intro__media[data-reveal]::after { transform: scaleY(1); transition: transform 1.2s var(--rv-ease) var(--rv-d, 0s); }
  .js .rv-intro__media[data-reveal].is-in::after { transform: scaleY(0); }

  /* Cards come up one after another, left to right; each card's photo loses its curtain as it lands. */
  .js .rv-card[data-reveal] { opacity: 0; transform: translateY(48px); transition: opacity .9s var(--rv-ease) var(--rv-d, 0s), transform 1.1s var(--rv-ease) var(--rv-d, 0s); }
  .js .rv-card[data-reveal].is-in { opacity: 1; transform: none; }

  /* The comparison lands a row at a time, so the gold column grows downward. */
  .js .rv-vs__table tr[data-reveal] { opacity: 0; transform: translateY(24px); transition: opacity .7s var(--rv-ease) calc(var(--rv-r, 0) * .09s), transform .7s var(--rv-ease) calc(var(--rv-r, 0) * .09s); }
  .js .rv-vs__table tr[data-reveal].is-in { opacity: 1; transform: none; }

  /* The tier band: each code rises out of its mask, the rule beside it draws downward, the copy follows. */
  .js .rv-tiers__item[data-reveal] .rv-tiers__code { transform: translateY(105%); transition: transform 1.2s var(--rv-ease) var(--rv-d, 0s); }
  .js .rv-tiers__item[data-reveal]::before { transform: scaleY(0); transition: transform 1.4s var(--rv-ease) var(--rv-d, 0s); }
  .js .rv-tiers__item[data-reveal] :is(.rv-tiers__name, .rv-tiers__tag, .rv-tiers__text) { opacity: 0; transform: translateY(24px); transition: opacity .8s var(--rv-ease) calc(var(--rv-d, 0s) + .3s), transform .8s var(--rv-ease) calc(var(--rv-d, 0s) + .3s); }
  .js .rv-tiers__item[data-reveal].is-in :is(.rv-tiers__code, .rv-tiers__name, .rv-tiers__tag, .rv-tiers__text) { opacity: 1; transform: none; }
  .js .rv-tiers__item[data-reveal].is-in::before { transform: none; }

  /* Texture rows come up in turn; the colour chart's swatches follow one after another. */
  .js .rv-tex__item[data-reveal] .rv-tex__text { opacity: 0; transform: translateY(24px); transition: opacity .8s var(--rv-ease) calc(var(--rv-d, 0s) + .2s), transform .8s var(--rv-ease) calc(var(--rv-d, 0s) + .2s); }
  .js .rv-tex__item[data-reveal].is-in .rv-tex__text { opacity: 1; transform: none; }
  .js .rv-swatches[data-reveal] .rv-swatch { opacity: 0; transform: translateY(24px); transition: opacity .6s var(--rv-ease) calc(var(--i, 0) * .025s), transform .6s var(--rv-ease) calc(var(--i, 0) * .025s); }
  .js .rv-swatches[data-reveal].is-in .rv-swatch { opacity: 1; transform: none; }

  /* Contact and footer: titles rise out of their masks, then the rest follows in order. */
  .js .rv-contact .contact__form[data-reveal] > :not(.form__grid), .js .rv-contact .contact__form[data-reveal] .form__grid > * { opacity: 0; transform: translateY(32px); transition: opacity .8s var(--rv-ease) calc(.1s + var(--i, 0) * .08s), transform .8s var(--rv-ease) calc(.1s + var(--i, 0) * .08s); }
  .js .rv-contact .contact__form[data-reveal].is-in > :not(.form__grid), .js .rv-contact .contact__form[data-reveal].is-in .form__grid > * { opacity: 1; transform: none; }
  .js .rv-foot :is(.footer__links[data-reveal], .footer__social) > * { opacity: 0; transform: translateY(24px); transition: opacity .6s var(--rv-ease) calc(.2s + var(--i, 0) * .06s), transform .6s var(--rv-ease) calc(.2s + var(--i, 0) * .06s); }
  .js .rv-foot .footer__links.is-in > *, .js .rv-foot:has(.footer__links.is-in) .footer__social > * { opacity: 1; transform: none; }
  .js .rv-foot .footer__social > * { transition-delay: calc(.6s + var(--i, 0) * .06s); }
}
@keyframes rv-up { from { transform: translateY(105%); } }
@keyframes rv-swipe { 0% { transform: scaleX(0); } 55% { transform: scaleX(1.05); } 100% { transform: none; } }
@keyframes rv-lift { from { transform: scaleY(1); } to { transform: scaleY(0); } }
@keyframes rv-settle { from { scale: calc(var(--rv-zoom, 1) * 1.14); } }

/* ============================================================
   Layer 3 · Scroll scenes. Desktop, a viewport tall enough to hold
   a pinned scene, motion welcome, and a browser that can tie an
   animation to the scroll position. No scroll listeners anywhere.
   ============================================================ */
@media (min-width: 1025px) and (min-height: 680px) and (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    /* Photos that drift inside their frames are enlarged enough to keep their edges hidden. */
    .rv-hero__photo img, .rv-def__shot img, .rv-card .rv-shot img, .rv-tex__shot img, .rv-use__shot img { --rv-zoom: 1.14; }

    /* 1 · As the hero leaves, the two photos slide past each other (left down, right up) and the two
       title lines part sideways. */
    .rv-hero { view-timeline: --rv-hero block; }
    .rv-hero__photo img { animation: rv-settle 2.2s var(--rv-ease) .3s both, rv-shear linear both; animation-timeline: auto, --rv-hero; animation-range: normal, exit 0% exit 100%; }
    .rv-hero__photo:last-child img { --rv-par: -6%; }
    .rv-hero .rv-line { animation: rv-part linear both; animation-timeline: --rv-hero; animation-range: exit 0% exit 100%; }

    /* 2 · The film grows to its full size as it comes in (its copy no longer inks in: comment cmvoqy7bxuznp). */
    .rv-intro__media { animation: rv-grow linear both; animation-timeline: view(); animation-range: entry 0% cover 45%; }

    /* (The held definition whose copy inked in word by word is gone: comment cmvoqy7bxuznp, 2026-10-26.) */

    /* 4, 7, 8 · Photos in cards, texture rows and "Use" drift inside their frames as they cross the screen. */
    .rv-card .rv-shot img, .rv-tex__shot img, .rv-use__shot img { animation: rv-drift linear both; animation-timeline: view(); animation-range: cover 0% cover 100%; }

    /* 6 · The tier codes grow into place as the band comes up, all three together. */
    .rv-tiers__code { animation: rv-code linear both; animation-timeline: view(); animation-range: entry 0% cover 40%; }

    /* Parallax to the foot of the page: the "Use" photo frame and the contact copy slide past the columns
       beside them; the footer picture sinks back. */
    .rv-use__shot, .rv-contact .contact__info { animation: rv-depth linear both; animation-timeline: view(); animation-range: cover 0% cover 100%; }
    .rv-contact .contact__info { --rv-depth: 40px; }
    .rv-foot .footer__bg img { animation: rv-foot linear both; animation-timeline: view(); animation-range: entry 0% entry 100%; }
  }
}
@keyframes rv-shear { to { translate: 0 var(--rv-par, 6%); } }
@keyframes rv-part { to { translate: calc(var(--rv-dir, 1) * 6%) 0; } }
@keyframes rv-grow { from { scale: .86; } }
@keyframes rv-drift { from { translate: 0 -5%; } to { translate: 0 5%; } }
@keyframes rv-float { from { translate: 0 64px; } to { translate: 0 -64px; } }
@keyframes rv-code { from { scale: .6; opacity: .15; } }
@keyframes rv-depth { from { translate: 0 var(--rv-depth, 48px); } to { translate: 0 calc(var(--rv-depth, 48px) * -1); } }
@keyframes rv-foot { from { transform: translateY(-10%) scale(1.25); } to { transform: scale(1.1); } }

/* ---------- Below 900px (portrait tablet and phone): everything stacks; no pinned scene. ---------- */
@media (max-width: 899px) {
  .rv-sec { padding-block: var(--space-16); }
  .rv-body { margin-top: var(--space-12); }
  .rv-hero__head { padding-block: var(--space-12) var(--space-8); }
  .rv-hero__photos { height: clamp(240px, 44svh, 420px); }
  .rv-intro__grid, .rv-def__grid, .rv-look__grid, .rv-use__grid { grid-template-columns: minmax(0, 1fr); row-gap: var(--space-12); }
  .rv-intro__copy, .rv-intro__media, .rv-def__text, .rv-def__media, .rv-look__families, .rv-chart, .rv-use__text, .rv-use__shot { grid-column: 1; }
  /* Definition: title and copy first, then the photos, the second one hanging off the right corner. */
  .rv-def { padding-block: var(--space-16) var(--space-24); }
  .rv-def__media { grid-row: 2; width: min(100%, 560px); padding-right: var(--space-12); }
  .rv-def__inset { right: 0; }
  .rv-def__body { margin-top: var(--space-8); }
  /* Cards one under another, each its photo beside its copy (over it on a phone, below). */
  .rv-cards { grid-template-columns: minmax(0, 1fr); row-gap: var(--space-6); }
  .rv-card { grid-row: auto; grid-template-rows: auto minmax(0, 1fr); grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); align-content: start; }
  .rv-card .rv-shot { grid-row: 1 / span 2; }
  .rv-card__title { align-self: end; padding: var(--space-6) var(--space-6) 0; font-size: var(--h5-size); line-height: var(--h5-lh); }
  .rv-card__text { padding: var(--space-2) var(--space-6) var(--space-6); }
  /* Tiers one under another, a rule between them. */
  .rv-tiers { grid-template-columns: minmax(0, 1fr); }
  .rv-tiers__item { grid-row: auto; grid-template-rows: auto; row-gap: var(--space-4); padding: var(--space-8) 0; }
  .rv-tiers__item + .rv-tiers__item::before { right: 0; bottom: auto; width: auto; height: 1px; transform-origin: left; }
  .js .rv-tiers__item[data-reveal]::before { transform: scaleX(0); }
  .rv-tiers__code { font-size: clamp(var(--h1-size), 16vw, calc(var(--h2-size) * 2)); }
  /* Look: the families, then the chart across the width. */
  .rv-chart { padding: var(--space-6); }
  .rv-swatches { grid-template-columns: repeat(9, minmax(0, 1fr)); }
  /* Use: title and list, then the photo. */
  .rv-use__shot { width: min(100%, 420px); }
}
@media (max-width: 599px) {
  .rv-card { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto; }
  .rv-card .rv-shot { grid-row: auto; }
  .rv-card__title { padding-top: var(--space-6); }
  .rv-tex__item { grid-template-columns: 96px minmax(0, 1fr); column-gap: var(--space-4); }
  .rv-tex__name { font-size: var(--h4-size); line-height: var(--h4-lh); }
  .rv-swatches { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .rv-swatch__code { font-size: var(--caption-size); line-height: var(--caption-lh); }
}
@media (max-width: 480px) {
  .rv-card__text, .rv-tiers__text, .rv-tex__desc, .rv-use__item dd, .rv-vs__table td { font-size: var(--body-size); line-height: var(--body-lh); }
}
/* Phone (as concept 1, user comments 2026-10-14 at 375px). */
@media (max-width: 767px) {
  .rv-vs__table tbody tr { --rv-r: 0; }
  .rv-vs__table td { font-size: var(--body-size); line-height: var(--body-lh); }
  .rv-contact .contact__submit { height: 52px; font-size: var(--h6-size); line-height: var(--h6-lh); }
  .rv-foot .footer__cta p br { display: none; }
  .rv-foot :is(.footer__cta p, .footer__copy) { text-wrap: balance; }
}
/* Footer social links: 44px targets with larger icons, at every width (user 2026-10-14). */
.rv-foot .soc { width: 44px; height: 44px; }
.rv-foot .soc:not(.soc--ring) img { width: 100%; height: 100%; }
.rv-foot .soc--ring img { width: 18px; height: auto; }
@media (max-width: 359px) {
  .rv-foot .footer__social { gap: var(--space-1); }
  .rv-foot .soc { width: 40px; height: 40px; }
}
@media (prefers-reduced-motion: reduce) {
  .rv-tex__name a { transition: none; }
}
