/* NNP Raisins - the home hero as SLIDES (live since 2026-10-29).
   Three slides on an 8 s clock: NNP Raisins (his basket of grapes), SIAL
   Paris 2026, the BRCGS audit. The script is assets/js/home-hero-slides.js;
   the copy and the photos are in index.html itself. Scoped to body.hv.hv-s.
   BUILT by tools/build-hero-css.mjs from tools/hero-slides.src.css - edit
   the source, not this file. The other concepts and the builder of the
   previews are in archives/nnp-raisins-home-hero-concepts-2026-10/; the
   record is log/home.md, "Round six". */
.hv .v3-hero { height: 100svh; }
.hv .v3-pic { position: absolute; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; }
.hv .v3-pic img, .hv .v3-pic video { position: absolute; left: -3%; top: -3%; width: 106%; height: 106%; object-fit: cover; display: block; }
.hv .v3-pic::after { content: ''; position: absolute; inset: 0; }
.hv .v3-hero-wrap { padding-bottom: 0; }
.hv .v3-lead { color: var(--chalk); text-shadow: 0 2px 18px rgba(7,6,13,.8); }
.hv .v3-proof { margin: 26px 0 0; font-family: var(--mono); font-weight: 500; font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--chalk-dim); }
.hv .v3-proof i { font-style: normal; color: var(--violet-lt); }
.hv .v3-scrollcue { top: auto; bottom: 28px; }

/* ==========================================================================
   S: THE SLIDES (2026-10-28). His reference the same day: chelmerfoods.com,
   whose hero is a full-bleed photo slider - one headline, one line, one
   button per slide, numbered dots, an 8 s fade. "hero should say about us,
   about sial paris 2026, and brcgs (all latest events)". The architecture is
   the reference's; the look is the site's night: #07060d floor, chalk type,
   the mono labels, violet-lt accent. Three slides: ABOUT US (the drying
   field), SIAL PARIS 2026 (his frame 71 of the stand), THE BRCGS AUDIT (the
   closing meeting). The clock, the swipe and the word split are
   home-hero-slides.js.
   ROUND TWO (his "not bad, needs improvements", same evening): the next
   photo wiped in from the right and settled from a slight zoom; ROUND SIX
   (2026-10-29, "transitions are not smooth") put the reference's cross-fade
   back, done right (see "the change" below); the headline's words rise one
   by one out of a clipped slot;
   a violet grade over every photo; a darker band under the masthead; the
   rail bigger, with prev/next arrows on the right; shorter lines.
   ⚠ The copy carries its own classes (.sl-h/.sl-p/.sl-cta), not .v3-h1 /
   .v3-lead / .v3-cta: home.js's intro tweens those with gsap.from() and
   would pin the hidden slides' copy at opacity 0 inline (see the script).
   ========================================================================== */
.hv-s .v3-sky { background: #07060d; }
.hv-s .v3-hero { display: block; height: auto; min-height: 100svh; padding: 0; }
/* the slides stack in one grid cell, so the tallest sets the height and the
   section can still grow on a small phone instead of clipping the buttons */
.hv-s .sl-track { display: grid; min-height: 100svh; }
.hv-s .sl-slide { grid-area: 1 / 1; position: relative; display: flex; flex-direction: column; justify-content: center;
  padding: calc(var(--mast-h) + clamp(18px, 1.9vw, 32px)) 0 clamp(130px, 16vh, 190px);
  visibility: hidden; z-index: 0; }
.hv-s .sl-slide.is-leaving { visibility: visible; z-index: 1; }
.hv-s .sl-slide.is-current { visibility: visible; z-index: 2; }

/* ---- the picture: cover, a violet grade, the night at the foot and under the bar ---- */
.hv-s .sl-pic { position: absolute; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; }
.hv-s .sl-pic img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; display: block; }
/* ⚠ frame 71 is PORTRAIT (2200x2933): object-fit: cover scales it to the width, the team stands centre-left */
.hv-s .sl-slide[data-slide="2"] .sl-pic img { object-position: 50% 42%; }
/* slide 1, the basket of grapes on the vineyard table (his pick, 2026-10-29;
   raw/photos/basket-vineyard-original.jpg, cut to its left 5400 px so the
   basket sits right of centre): the box is 110% wide, so the basket's left
   edge lands at about 43% of the screen and the words at the left spine stay
   off the grapes; the band keeps the basket and the table, the top of the
   leaf arch is cut */
.hv-s .sl-slide[data-slide="1"] .sl-pic img { width: 110%; right: auto; object-position: 67% 64%; }
/* the closing-meeting photo (1280x960, a 4:3 frame on a wide screen, so only 60-70% of its height shows): the band
   sits low (object-position 54%) so the two men at the left and the man in the foreground keep their faces, and the
   words take the RIGHT, over the dark screen (data-align="right"). His note on the first live cut, which was a 112% box
   anchored at the top to push the people under the buttons: "too close, people are out of frame". */
.hv-s .sl-slide[data-slide="3"] .sl-pic img { object-position: 50% 54%; }
.hv-s .sl-pic::before { content: ''; position: absolute; inset: 0; mix-blend-mode: multiply;
  background: linear-gradient(180deg, rgba(75,30,120,.3) 0%, rgba(55,18,94,.2) 50%, rgba(12,6,25,.5) 100%); }
.hv-s .sl-pic::after { content: ''; position: absolute; inset: 0; background:
  radial-gradient(60% 60% at 50% 50%, rgba(7,6,13,.42) 0%, rgba(7,6,13,.18) 60%, rgba(7,6,13,0) 100%),
  linear-gradient(180deg, rgba(7,6,13,.66) 0%, rgba(7,6,13,.12) 26%, rgba(7,6,13,.1) 54%, rgba(7,6,13,.9) 100%); }

/* the change (round six, 2026-10-29, "transitions are not smooth"): the next
   picture CROSS-FADES in over the last one, as in his reference (Slick,
   fade: true, speed 500), a touch longer at 800 ms so two big photographs
   dissolve rather than blink. Both pictures keep drifting through the change:
   the script leaves .sl-anim on the leaving slide until it is hidden, so its
   picture no longer snaps back to rest the moment the change begins (the
   wipe's fault, a 4-5 % jump of the old photo, plus a curve that crossed the
   screen in a third of a second). The drift is one slow push, 1.0 to 1.06
   over the slide's ten seconds, the same for every slide (the 1.12 rush that
   opened each wiped slide read as motion on top of motion). The wipe is kept
   for data-transition="wipe" on the hero, by request only. */
@keyframes sl-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes sl-drift { from { transform: scale(1.0); } to { transform: scale(1.06); } }
.hv-s .sl-ready .sl-slide.is-current.sl-change .sl-pic { animation: sl-fade 900ms cubic-bezier(0.45, 0, 0.25, 1) both; }
.hv-s .sl-ready .sl-slide.sl-anim .sl-pic img { animation: sl-drift 10s linear both; }
@keyframes sl-wipe { from { clip-path: inset(0 0 0 100%); } to { clip-path: inset(0 0 0 0); } }
.hv-s .v3-slides[data-transition="wipe"].sl-ready .sl-slide.is-current.sl-change .sl-pic { animation: sl-wipe 1100ms var(--ease-in-out) both; }
/* the copy's clock: --t0 is when the title starts (after the curtain, or on a
   changed slide once the leaving copy has dissolved and the new picture is
   two thirds in); the line follows 110 ms later, the buttons 220 ms. Round
   six, same morning ("transition is not still smooth"): the title rises as
   ONE block, like the reference's, no word-by-word stagger - fewer moving
   parts, and the clipped word slots printed the text-shadow as a box around
   every word on a light photo (his "shadow box" on the BRCGS title). The
   titles carry NO shadow now: a text-shadow is cut by any clipping box (the
   rotator clips its line too), a drop-shadow filter re-blurs the headline on
   every frame it moves, and the reference's titles are plain; the grade
   under the words carries legibility. */
.hv-s .sl-slide { --t0: 140ms; }
.hv-s .sl-slide.sl-change { --t0: 450ms; }

/* ---- the copy ---- */
.hv-s .sl-copy { position: relative; z-index: 1; width: 100%; max-width: var(--max); margin: 0 auto; padding: 0 var(--gut);
  text-align: center; display: flex; flex-direction: column; align-items: center; }
.hv-s .sl-h { font-family: var(--display); font-weight: 800; color: var(--chalk); font-size: clamp(42px, 6.3vw, 92px);
  line-height: 0.96; letter-spacing: -0.035em; margin: 0; max-width: 17ch; text-wrap: balance; }
/* every title rises as one block (the first slide's is the site's own H1, v1's rotator, advanced by site.js) */
.hv-s .sl-ready .sl-slide.is-current.sl-anim .sl-h { animation: sl-rise 800ms var(--ease-out) var(--t0) both; }
@keyframes sl-word { from { transform: translateY(112%); } to { transform: none; } } /* P and T still split their titles */
.hv-s .sl-h.v3-h1 { margin: 0; line-height: 0.96; }
/* a long title (his pasted lines) at a smaller size, with a wider measure and less room kept at the foot */
.hv-s .sl-h[data-long] { font-size: clamp(34px, 4.6vw, 66px); max-width: 20ch; }
.hv-s .sl-slide:has(.sl-h[data-long]) { padding-bottom: clamp(110px, 14vh, 150px); }
.hv-s .sl-p { color: var(--chalk); opacity: .9; line-height: 1.5; font-size: clamp(16px, 1.4vw, 20px); max-width: 48ch; margin: 22px 0 0;
  text-shadow: 0 2px 18px rgba(7,6,13,.8); }
.hv-s .sl-cta { display: flex; flex-wrap: wrap; justify-content: center; gap: 14px; margin: 30px 0 0; }
/* a slide whose people stand in the middle puts its words at the right, over the free ground (his note on the SIAL frame: "text covers faces") */
.hv-s .sl-slide[data-align="right"] .sl-copy { max-width: none; padding: 0 var(--spine); align-items: flex-end; text-align: right; }
.hv-s .sl-slide[data-align="right"] .sl-h { max-width: 15ch; }
.hv-s .sl-slide[data-align="right"] .sl-h[data-long] { max-width: 18ch; }
.hv-s .sl-slide[data-align="right"] .sl-p { max-width: 36ch; }
.hv-s .sl-slide[data-align="right"] .sl-cta { justify-content: flex-end; }
.hv-s .sl-slide[data-align="right"] .sl-pic::after { background:
  linear-gradient(270deg, rgba(7,6,13,.72) 0%, rgba(7,6,13,.45) 34%, rgba(7,6,13,.06) 62%, rgba(7,6,13,0) 100%),
  linear-gradient(180deg, rgba(7,6,13,.66) 0%, rgba(7,6,13,.12) 26%, rgba(7,6,13,.1) 54%, rgba(7,6,13,.9) 100%); }
/* a slide whose subject sits right of centre (the basket) puts its words at the left spine, over the soft vineyard path;
   the brand title a size smaller here, so the longest rotator phrase ("Certified Quality", nowrap, clipped by the
   rotator) ends before the basket's left edge */
/* the left inset grows at 40% of the spine's growth: at 1920 px the spine is 360 px and the copy would run into the
   basket, whose left edge is pinned at about 43% of the screen (measured: words end 44.6%, basket starts 38.5%) */
.hv-s .sl-slide[data-align="left"] .sl-copy { max-width: none; padding: 0 var(--gut) 0 max(var(--gut), calc((50vw - 640px) * 0.4 + var(--gut))); align-items: flex-start; text-align: left; }
.hv-s .sl-slide[data-align="left"] .sl-h { font-size: clamp(36px, 4vw, 72px); max-width: none; }
.hv-s .sl-slide[data-align="left"] .sl-h[data-long] { max-width: 18ch; }
.hv-s .sl-slide[data-align="left"] .rotator { justify-items: start; text-align: left; }
.hv-s .sl-slide[data-align="left"] .sl-p { max-width: 34ch; }
.hv-s .sl-slide[data-align="left"] .sl-cta { justify-content: flex-start; }
.hv-s .sl-slide[data-align="left"] .sl-pic::after { background:
  linear-gradient(90deg, rgba(7,6,13,.74) 0%, rgba(7,6,13,.48) 34%, rgba(7,6,13,.08) 60%, rgba(7,6,13,0) 100%),
  linear-gradient(180deg, rgba(7,6,13,.6) 0%, rgba(7,6,13,.1) 26%, rgba(7,6,13,.08) 54%, rgba(7,6,13,.9) 100%); }
@keyframes sl-rise { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
.hv-s .sl-ready .sl-slide.is-current.sl-anim .sl-p { animation: sl-rise 800ms var(--ease-out) both; animation-delay: calc(var(--t0) + 110ms); }
.hv-s .sl-ready .sl-slide.is-current.sl-anim .sl-cta { animation: sl-rise 800ms var(--ease-out) both; animation-delay: calc(var(--t0) + 220ms); }
/* the leaving slide's copy goes first, up and out, under the fade */
@keyframes sl-out { to { opacity: 0; } }
.hv-s .sl-slide.is-leaving .sl-copy { animation: sl-out 320ms ease-out both; }

/* ---- the rail: names with a hairline that fills over the slide's eight seconds, arrows at the right ---- */
.hv-s .sl-nav { position: absolute; left: var(--spine); bottom: clamp(26px, 5vh, 54px); z-index: 3; display: flex; gap: 22px; }
.hv-s .sl-dot { appearance: none; -webkit-appearance: none; background: none; border: 0; margin: 0; padding: 10px 0; cursor: pointer;
  display: grid; grid-template-columns: auto 1fr; gap: 10px 0; width: auto; min-width: 88px; color: var(--chalk-dim); font-family: var(--mono); font-weight: 500;
  font-size: 12px; letter-spacing: .16em; text-transform: uppercase; text-align: left; line-height: 1.2; transition: color 200ms ease; }
.hv-s .sl-dot .sl-bar { grid-column: 1 / -1; }
.hv-s .sl-dot:hover, .hv-s .sl-dot.is-active { color: var(--chalk); }
.hv-s .sl-dot:focus-visible { outline: 2px solid var(--violet-lt); outline-offset: 4px; }
.hv-s .sl-dot .sl-n { display: inline; margin-right: .8em; color: var(--violet-lt); }
.hv-s .sl-dot .sl-l { white-space: nowrap; }
.hv-s .sl-dot .sl-bar { display: block; height: 2px; background: rgba(242,237,248,.2); position: relative; overflow: hidden; }
.hv-s .sl-dot .sl-bar::after { content: ''; position: absolute; inset: 0; background: var(--violet-lt); transform: scaleX(0); transform-origin: 0 50%; }
@keyframes sl-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.hv-s .sl-bar.is-running::after { animation: sl-fill 8s linear forwards; }
.hv-s .sl-nav.is-paused .sl-bar.is-running::after, .hv-s .sl-nav.is-off .sl-bar.is-running::after { animation-play-state: paused; }
.hv-s .sl-arrows { position: absolute; right: var(--spine); bottom: clamp(26px, 5vh, 54px); z-index: 3; display: flex; gap: 10px; }
.hv-s .sl-arrow { appearance: none; -webkit-appearance: none; width: 48px; height: 48px; border-radius: 999px; cursor: pointer; margin: 0; padding: 0;
  display: grid; place-items: center; color: var(--chalk); background: rgba(6,2,14,.4); border: 1px solid rgba(242,237,248,.22);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); transition: border-color 200ms ease, background 200ms ease, transform var(--t-press) var(--ease-out); }
.hv-s .sl-arrow svg { width: 18px; height: 18px; }
.hv-s .sl-arrow:hover { border-color: var(--chalk); background: rgba(242,237,248,.1); }
.hv-s .sl-arrow:active { transform: translateY(1px); }
.hv-s .sl-arrow:focus-visible { outline: 2px solid var(--violet-lt); outline-offset: 3px; }

@media (max-width: 900px) {
  .hv-s .sl-slide { justify-content: flex-end; padding: calc(var(--mast-h) + 20px) 0 100px; min-height: 100svh; }
  .hv-s .sl-copy { align-items: flex-start; text-align: left; }
  .hv-s .sl-h { font-size: clamp(34px, 9.6vw, 46px); max-width: none; }
  .hv-s .sl-h[data-long], .hv-s .sl-slide[data-align="right"] .sl-h[data-long] { font-size: clamp(27px, 7.4vw, 34px); max-width: none; }
  .hv-s .sl-p { max-width: none; margin-top: 16px; }
  .hv-s .sl-cta { justify-content: flex-start; margin-top: 22px; }
  .hv-s .sl-pic img { object-position: 50% 40%; }
  /* the SIAL frame on a phone: the team sits higher so the words at the foot stay off the faces */
  /* on a phone the photo box is taller than the screen and anchored to its floor, so the people rise into the free upper third, above the words */
  .hv-s .sl-slide[data-slide="2"] .sl-pic img { height: 150%; top: auto; bottom: 0; object-position: 40% 50%; }
  .hv-s .sl-slide[data-slide="3"] .sl-pic img { width: 100%; height: 170%; left: 0; top: auto; bottom: 0; object-position: 15% 50%; }
  /* the basket slide on a phone: the words at the TOP (the basket is too tall to share the foot with them),
     the picture box 135% tall from the top edge so the basket fills the lower screen under the words */
  .hv-s .sl-slide[data-slide="1"] { justify-content: flex-start; padding-top: calc(var(--mast-h) + 26px); }
  .hv-s .sl-slide[data-slide="1"] .sl-pic img { width: 100%; height: 135%; right: auto; top: 0; bottom: auto; object-position: 67% 0; }
  .hv-s .sl-pic::after, .hv-s .sl-slide[data-align="right"] .sl-pic::after { background: linear-gradient(180deg, rgba(7,6,13,.5) 0%, rgba(7,6,13,.14) 30%, rgba(7,6,13,.3) 52%, rgba(7,6,13,.94) 100%); }
  /* the words at the top need the top dark instead: the sky and the leaf arch are bright */
  .hv-s .sl-slide[data-align="left"] .sl-pic::after { background: linear-gradient(180deg, rgba(7,6,13,.82) 0%, rgba(7,6,13,.62) 34%, rgba(7,6,13,.14) 52%, rgba(7,6,13,.3) 80%, rgba(7,6,13,.9) 100%); }
  .hv-s .sl-slide[data-align="left"] .sl-copy { padding: 0 var(--gut); }
  .hv-s .sl-slide[data-align="left"] .sl-h { font-size: clamp(34px, 9.6vw, 46px); max-width: none; }
  .hv-s .sl-slide[data-align="left"] .sl-p { max-width: none; }
  .hv-s .sl-slide[data-align="right"] .sl-copy { padding: 0 var(--gut); align-items: flex-start; text-align: left; }
  .hv-s .sl-slide[data-align="right"] .sl-h { max-width: none; }
  .hv-s .sl-slide[data-align="right"] .sl-p { max-width: none; }
  .hv-s .sl-slide[data-align="right"] .sl-cta { justify-content: flex-start; }
  .hv-s .sl-nav { left: var(--gut); bottom: 26px; gap: 14px; }
  .hv-s .sl-dot { min-width: 44px; font-size: 11px; }
  .hv-s .sl-dot .sl-n { margin: 0; color: inherit; }
  .hv-s .sl-dot .sl-l { display: none; }
  .hv-s .sl-arrows { display: none; }
}
@media (max-width: 620px) {
  .hv-s .sl-cta .btn { width: 100%; justify-content: center; }
}
/* reduced motion (his laptop reports it: Windows with "animation effects" off):
   the slides STILL CHANGE, by the same opacity-only cross-fade, and the bar
   still fills, because the first live version stopped the clock here and the
   hero never left slide 1 for him. What goes: the drift (a zoom) and the
   rising copy (translate); the copy fades in instead. */
@keyframes sl-fadein { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .hv-s .sl-pic img { animation: none !important; transform: none !important; }
  .hv-s .sl-ready .sl-slide.is-current.sl-anim .sl-h,
  .hv-s .sl-ready .sl-slide.is-current.sl-anim .sl-p,
  .hv-s .sl-ready .sl-slide.is-current.sl-anim .sl-cta { animation-name: sl-fadein; animation-duration: 600ms; }
}
