/* ===========================================================================
   CE-13 · Cytaty z atrybucją (quotes with attribution) – a one-at-a-time
   slider after Figma crear-v2.0, frame 440:1505 (24.09.2026)
   Root:     section.ce-quotes (data-bg-scroll: #F4F4F4 from the start and
             for good since 26.09 – site.css kit)
   Design:   bar: eyebrow „• OPINIE KLIENTÓW” (#969B9B, 342 px box) and the
             counter „01  /  05” (15 px Expanded Medium, uppercase), on the
             right two 60 × 40 buttons (radius 4; the second one outlined
             rgba(18,18,19,.12)); 160 px below: photo 159 × 196 (radius 4;
             since 27.09 it scales with the window, 96–212 px wide),
             118 px, quote mark 28 × 25.4 in a 32 px column, 40 px, quote in
             40 px Expanded Regular (line 1.22, −1.6 px, #1D1D1E, 915 px in Figma, 780 px since 08.10.2026);
             72 px below, under the quote: name 24 px (#1D1D1E), role 18 px
             (#778181), 16 px apart. Padding 56 / 160, the page margin.
             Card and bar share one set of columns (--q-cols, 27.09): the
             counter stands over the quote, its left edge = the quote's.
   Parts:    __bar, __meta, __eyebrow (h2, with .lf-eyebrow), __count
             (__now = current number, rolls), __nav, __btn (--prev, --next,
             __arrow), __slides (.is-sizing while its height eases), __slide
             (.is-current / .is-leaving / .is-playing; a change adds
             .is-swap), __card (figure: grid of photo · mark · quote,
             attribution under the quote), __photo (img, or --empty
             placeholder), __mark, __quote, __who, __name, __role
   Rule:     name, surname, role and company are mandatory – without
             consent for the attribution the section does not go live.
             Slide 1 carries the design's sample; slides 2–5 are placeholders.
   Mechanics (ce/CE-13-quotes.js): the buttons, ←/→ inside the section and a
             horizontal swipe change the slide (in a loop). A change (26.09,
             27.09): the new photo opens over the old one from the top down
             (27.09, as the photos elsewhere; until then from the side of
             the arrow) – 0.9 s + a 1.4 s settle, ease-out-expo, from 0.18 s;
             the old photo and the mark stay put underneath, no empty frame.
             The old quote lines sink and fade, top line first (0.28 s,
             30 ms apart, all within 90 ms); the new ones rise 0.18 s after
             the click (0.5 s, 50 ms apart); name and role fade out (0.15 s)
             and in (0.3 s after 0.3 s); the height of the slides eases to
             the new slide's (0.55 s, 27.09); the counter rolls. Buttons:
             the arrow slides 4 px its way on hover, the button presses in.
             On entering the window the first slide plays (the photo opens
             from the top with a zoom, the mark pops in, the lines rise);
             the ground is #F4F4F4 from the start.
   Align:    photo, mark and the first line of the quote share one top edge:
             the cap height of the first line (Mateusz 26.09; in Figma the
             photo stands ~11 px higher, at the top of the line box). All
             slides hold the photo in the same place and size; it spans both
             rows, so name and role stay 72 px under the quote.
   Height:   the section is as tall as the current slide (27.09): set by
             CE-13-quotes.js, eased on a change, again on every resize.
   Layout:   ≤ 900 px: the photo above the quote (110 px at 375, in
             proportion), smaller type and gaps; eyebrow and counter side by
             side (no room for the counter over the text, 44 px in).
   Variants: --single (26.09 evening, Mateusz: „make it one with the section
             on Home, without the eyebrow and the carousel”): one quote, the
             card of Home as it is – no bar (eyebrow, counter, arrows), one
             slide; the section padding 160 / 160 instead of 56 / 160, the
             same #F4F4F4 ground, 152 px above it (the rhythm of the case
             page). It comes in as the first slide on Home.
             realizacje/drutplast/#opinia-klienta (in place of CE-36).
   Base:     index.html#rekomendacje · registry: ce-registry.js → CE-13
   =========================================================================== */

.ce-quotes {
  --q-size: clamp(1.5rem, 2.78vw, 40px);              /* quote: 40 px at 1440 */
  /* the photo scales with the window (Mateusz 27.09: „the photos must scale
     to the size of the screen”): 159 × 196 and 118 px after it at 1440, in
     proportion below and above – 96 px wide at least, 212 px (1920) at most */
  --q-photo-w: clamp(96px, 11.042vw, 212px);
  --q-photo-gap: clamp(40px, 8.194vw, 157px);
  /* one set of columns for the card and the bar: photo + its gap · the
     mark's 72 px (32 + 40) · the quote (≤ 780 px). Since 08.10.2026 no slack
     columns – photo, mark and quote stand together and the whole content
     is a narrower block centred on the page (--q-max), so the photo no
     longer sits far out at the left margin. The counter of the bar stands
     in the quote's column, its left edge = the quote's at every width. */
  --q-quote-w: 780px;
  --q-cols: calc(var(--q-photo-w) + var(--q-photo-gap)) 72px minmax(0, var(--q-quote-w));
  --q-max: calc(var(--q-photo-w) + var(--q-photo-gap) + 72px + var(--q-quote-w));
  /* the cap top of the quote's first line below its box: TT Hoves Pro Trl
     Expanded has ascent 1.0 em, descent .25 em, cap height .70 em (measured
     26.09 in Chrome) – at line-height 1.22 that is (1.22 − 1.25) / 2 +
     (1 − .70) = .285 em, 11.4 px at 40 px */
  --q-cap: calc(var(--q-size) * .285);
  padding-block: clamp(40px, 3.9vw, 56px) clamp(96px, 11.1vw, 160px);
}

/* ---- variant single: one quote, no bar -------------------------------------- */
.ce-quotes--single {
  padding-block: clamp(96px, 11.1vw, 160px);
  margin-top: clamp(72px, 10.053vw, 152px);           /* the case page rhythm: 152 px after every block (as CE-36 had) */
}

/* ---- bar --------------------------------------------------------------------- */
.ce-quotes__bar,
.ce-quotes__slides { max-width: var(--q-max); margin-inline: auto; }
.ce-quotes__bar {
  display: grid;
  grid-template-columns: var(--q-cols);
  align-items: center;
  margin-bottom: clamp(72px, 11.1vw, 160px);
}
.ce-quotes__meta { display: contents; }
.ce-quotes__eyebrow {
  grid-column: 1 / 3;
  grid-row: 1;
  margin-top: 3px;                                    /* its foot on the counter's foot (Figma: 16 px box on a 19 px one, bottoms level) */
  color: var(--ui-muted-2);
}
.ce-quotes__count { grid-column: 3; grid-row: 1; justify-self: start; }
.ce-quotes__nav { grid-column: 3; grid-row: 1; justify-self: end; }
.ce-quotes__count {
  display: flex;
  font-family: var(--font-heading);
  font-size: .9375rem;                                /* 15 px */
  font-weight: 500;
  line-height: normal;
  letter-spacing: .015em;
  text-transform: uppercase;
  white-space: pre;
  color: var(--ui-muted-2);
}
.ce-quotes__now {
  display: inline-grid;
  overflow: clip;
}
.ce-quotes__now > span {
  grid-area: 1 / 1;
  transition: transform .5s var(--ease-out-expo), opacity .5s var(--ease-out-expo);
}
.ce-quotes__now > .is-out { transform: translateY(-100%); opacity: 0; }
.ce-quotes__now > .is-in-start { transform: translateY(100%); opacity: 0; transition: none; }

.ce-quotes__nav { display: flex; gap: 8px; }
.ce-quotes__btn {
  display: grid;
  place-items: center;
  width: 60px;
  height: 40px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 4px;
  background: transparent;
  color: var(--ui-ink);
  cursor: pointer;
  transition: border-color .25s ease, background-color .25s ease, transform .15s ease;
}
.ce-quotes__btn--next { border-color: rgba(18, 18, 19, .12); }
.ce-quotes__btn:hover { border-color: rgba(18, 18, 19, .24); background: rgba(18, 18, 19, .03); }
.ce-quotes__btn:active { transform: scale(.94); }
.ce-quotes__btn:focus-visible { outline: 2px solid var(--ui-ink); outline-offset: 2px; }
.ce-quotes__arrow { width: 16px; height: 16px; transition: transform .35s var(--ease-out-expo); }
.ce-quotes__btn--prev:hover .ce-quotes__arrow { transform: translateX(-4px); }
.ce-quotes__btn--next:hover .ce-quotes__arrow { transform: translateX(4px); }

/* ---- slides -------------------------------------------------------------------- */
.ce-quotes__slides { display: grid; }
.ce-quotes__slide {
  grid-area: 1 / 1;
  align-self: start;                                  /* each slide as tall as its own content */
  position: relative;                                 /* z-index set by the script: the newest on top */
  visibility: hidden;
}
/* The height follows the current slide (Mateusz 27.09: „the height of the
   section must fit the height of the text, it cannot be fixed”):
   CE-13-quotes.js sets it in px from the current slide (again on every
   resize); on a change it eases to the new slide's height – 0.55 s
   power1.inOut, at once when it grows, 0.15 s later when it shrinks (the
   old lines are sinking meanwhile). While it eases (.is-sizing) the slides
   are clipped, but only past the section's bottom padding, so nothing
   visible is cut. Without the script: the tallest slide, as before. */
.ce-quotes__slides.is-sizing {
  overflow: clip;
  overflow-clip-margin: clamp(96px, 11.1vw, 160px);  /* = the section's bottom padding */
}
@media (prefers-reduced-motion: no-preference) {
  .ce-quotes__slides.is-sizing { transition: height .55s var(--ease-in-out-quad) var(--q-h-delay, 0ms); }
}
.ce-quotes__slide.is-current,
.ce-quotes__slide.is-leaving { visibility: visible; }
.ce-quotes__slide.is-leaving { pointer-events: none; }

/* columns (--q-cols): photo + 118 px · mark in a 32 px box + 40 px · quote
   ≤ 780 px, the block centred (--q-max) */
.ce-quotes__card {
  display: grid;
  grid-template-columns: var(--q-cols);
  grid-template-rows: auto 1fr;                       /* the photo spans both rows: name and role stay 72 px under the quote, however tall the photo (27.09) */
  row-gap: clamp(40px, 5vw, 72px);
  align-items: start;                                 /* the photo stays at the top, whatever the quote's length */
  margin: 0;
}
.ce-quotes__photo { margin: var(--q-cap) 0 0; }

/* photo */
.ce-quotes__photo {
  grid-column: 1;
  grid-row: 1 / span 2;
  width: var(--q-photo-w);
  aspect-ratio: 159 / 196;
  overflow: hidden;
  border-radius: 4px;
}
.ce-quotes__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.ce-quotes__photo--empty {
  background: #E9E9E9;                                /* a slide still without a photo */
  display: grid;
  place-items: center;
  color: var(--ui-muted);
  font-size: .75rem;
  letter-spacing: .08em;
  text-transform: uppercase;
}

/* quote mark and text */
.ce-quotes__mark {
  grid-column: 2;
  grid-row: 1;
  align-self: start;
  box-sizing: content-box;
  width: 28px;
  height: auto;
  padding-inline: 2px;                                /* the 32 px box of the design */
  margin-top: var(--q-cap);                           /* the glyph fills its box: top = cap top */
}
.ce-quotes__quote {
  grid-column: 3;
  grid-row: 1;
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--q-size);
  font-weight: 400;
  line-height: 1.22;
  letter-spacing: -.04em;                             /* −1.6 px at 40 px */
  color: var(--ui-ink);
}
.ce-quotes__who {
  grid-column: 3;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  gap: 16px;
  font-family: var(--font-heading);
  line-height: normal;
}
.ce-quotes__name {
  font-size: clamp(1.125rem, 1.67vw, 24px);
  font-weight: 400;
  letter-spacing: -.01em;
  color: var(--ui-ink);
  text-box: trim-both cap alphabetic;
}
.ce-quotes__role {
  font-size: clamp(.9375rem, 1.25vw, 18px);
  color: var(--ui-muted);
  text-box: trim-both cap alphabetic;
}

/* ---- the change of slides (26.09 – faster and overlapped, Mateusz 26.09) -----
   Quote: its lines rise out of their masks and fade in, 0.5 s power4.out,
   50 ms apart (the oci.madebybuzzworthy.com pattern measured 24.09 ran
   0.8 s, 0.1 s apart); on a change they start 0.18 s after the click
   (--rise-delay, also read by site.js for the clean-up), while the old
   lines still sink. The leaving lines (.is-leaving, split again by
   CE-13-quotes.js) sink and fade, 0.28 s power2.in, 30 ms apart (--q-step:
   a long quote packs them into 90 ms, so it is gone after 0.37 s), top line
   first – so every line of the new quote comes into a mask the old one is
   just leaving (pattern: 0.45 s power4.in, 80 ms apart, last line first;
   power4.in stood still for the first 0.2 s, power2.in moves at once). Name and
   role: out in 0.15 s, in 0.3 s after 0.3 s (the first slide: after 0.2 s).
   Photo and mark of the leaving
   slide stay – the new photo covers them. */
.ce-quotes__slide.is-leaving .ce-quotes__quote p:not(.is-split) { visibility: hidden; }   /* not split (no site.js) or already restored */
@media (prefers-reduced-motion: no-preference) {
  .ce-quotes__quote .lf-rl__in {
    opacity: 0;
    transition: transform .5s var(--ease-out-power4) calc(var(--rise-delay, 0ms) + var(--i, 0) * 50ms), opacity .5s var(--ease-out-power4) calc(var(--rise-delay, 0ms) + var(--i, 0) * 50ms);
  }
  .ce-quotes__quote .is-in .lf-rl__in { opacity: 1; }
  .ce-quotes__quote .is-still .lf-rl__in { transition: none; }
  .ce-quotes__slide.is-swap .ce-quotes__quote p { --rise-delay: 180ms; }
  .ce-quotes__slide.is-leaving .ce-quotes__quote .is-in .lf-rl__in {
    opacity: 0;
    transform: translateY(100%);
    transition: transform .28s cubic-bezier(.55, .055, .675, .19) calc(var(--i, 0) * var(--q-step, 30ms)), opacity .28s cubic-bezier(.55, .055, .675, .19) calc(var(--i, 0) * var(--q-step, 30ms));   /* GSAP power2.in */
  }
  .cr-js .ce-quotes__slide .ce-quotes__who { opacity: 0; transition: opacity .15s ease-out; }
  .cr-js .ce-quotes__slide.is-playing .ce-quotes__who { opacity: 1; transition: opacity .3s ease-in-out .2s; }
  .cr-js .ce-quotes__slide.is-swap.is-playing:not(.is-leaving) .ce-quotes__who { transition-delay: .3s; }   /* after the old quote is gone */
  .cr-js .ce-quotes__slide.is-leaving .ce-quotes__who { opacity: 0; transition: opacity .15s ease-out; }
}

/* ---- the first slide, as the section comes into view (.is-playing) ----------
   The photo opens from the top down (27.09, as the photos elsewhere on the
   site – CE-27, CE-19; until then from the bottom up) and settles from 115%. */
@media (prefers-reduced-motion: no-preference) {
  .cr-js .ce-quotes__slide .ce-quotes__photo img {
    clip-path: inset(0 0 100% 0);
    transform: scale(1.15);
  }
  .cr-js .ce-quotes__slide.is-playing .ce-quotes__photo img {
    clip-path: inset(0);
    transform: none;
    transition: clip-path .9s var(--ease-out-expo), transform 1.4s var(--ease-out-expo);
  }
  .cr-js .ce-quotes__slide .ce-quotes__photo--empty,
  .cr-js .ce-quotes__slide .ce-quotes__mark {
    opacity: 0;
    transform: scale(.6);
  }
  .cr-js .ce-quotes__slide.is-playing .ce-quotes__photo--empty,
  .cr-js .ce-quotes__slide.is-playing .ce-quotes__mark {
    opacity: 1;
    transform: none;
    transition: opacity .5s var(--ease-out-quart) .15s, transform .7s var(--ease-out-expo) .15s;
  }
}

/* ---- a coming slide (.is-swap) ------------------------------------------------
   One frame for all photos: the slides lie on top of each other, the photo
   in the same place, the newest slide above. The new photo opens over the
   old one from the top down (Mateusz 27.09: „the photos come in from the
   top, as elsewhere – not from the side”; 26.09 it wiped in from the side
   of the arrow – the arrow no longer steers the photo); the old photo
   stays whole underneath until it is covered – no empty frame, no grey.
   The mark is the same glyph in the same place: it just stays.
   Tempo (Mateusz 26.09 evening: „the previous tempo, now too fast”, kept
   27.09): the frame opens in 0.9 s and the picture settles from 115% in
   1.4 s, both ease-out-expo, together with the lines of the new quote
   (--q-photo-delay = the quote's --rise-delay, 180 ms), so the new photo
   never runs ahead of its own quote; the old photo leaves with the old
   quote. */
@media (prefers-reduced-motion: no-preference) {
  .ce-quotes__slide.is-swap { --q-photo-delay: 180ms; }
  .cr-js .ce-quotes__slide.is-swap .ce-quotes__photo { clip-path: inset(0 0 100% 0 round 4px); }
  .cr-js .ce-quotes__slide.is-swap .ce-quotes__photo img {
    clip-path: none;
    transform: scale(1.15);
  }
  .cr-js .ce-quotes__slide.is-swap.is-playing .ce-quotes__photo {
    clip-path: inset(0 round 4px);
    transition: clip-path .9s var(--ease-out-expo) var(--q-photo-delay, 0ms);
  }
  .cr-js .ce-quotes__slide.is-swap.is-playing .ce-quotes__photo img {
    transform: none;
    transition: transform 1.4s var(--ease-out-expo) var(--q-photo-delay, 0ms);
  }
  .cr-js .ce-quotes__slide.is-swap .ce-quotes__photo--empty,
  .cr-js .ce-quotes__slide.is-swap .ce-quotes__mark {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ---- narrow ------------------------------------------------------------------------ */
@media (max-width: 900px) {
  .ce-quotes { --q-photo-w: clamp(88px, 29.333vw, 150px); }   /* 110 px at 375, in proportion (27.09) */
  .ce-quotes__card { grid-template-columns: 32px minmax(0, 1fr); grid-template-rows: none; row-gap: 28px; }
  .ce-quotes__photo { grid-column: 1 / -1; grid-row: 1; margin: 0; }   /* a row of its own: top of the slide */
  .ce-quotes__mark { grid-column: 1; grid-row: 2; margin: var(--q-cap) 0 0; width: 22px; }
  .ce-quotes__quote { grid-column: 2; grid-row: 2; padding-left: 12px; }
  .ce-quotes__who { grid-column: 2; grid-row: 3; padding-left: 12px; }
  /* the bar: the eyebrow and the counter side by side (no room for the
     counter over the quote's text, 44 px in), the arrows on the right */
  .ce-quotes__bar { display: flex; justify-content: space-between; gap: 1rem; }
  .ce-quotes__meta { display: flex; align-items: flex-end; gap: 9px; }
  .ce-quotes__eyebrow { margin-top: 0; }
}
@media (max-width: 480px) {
  .ce-quotes__meta { flex-direction: column; align-items: flex-start; gap: 6px; }
}
