/* ============================================================
   SILICA WORKS - testimonials
   ------------------------------------------------------------
   Four cards stacked on one point, fanned out across the middle
   of the section. They rise into place once the section is
   entered; hovering one straightens it and pushes its
   neighbours outward in proportion to their distance.

   Adapted from the blunt deck, retuned for this page: paper
   ground, ink type, the same pill and label vocabulary the rest
   of the site uses. Every transform is written by
   js/testimonials.js - this file owns only the resting look.

   Below 1000px there is no room to fan and no hover to drive
   it, so the deck unstacks into a plain column.
   ============================================================ */

.sw-testimonials {
  position: relative;
  width: 100%;
  /* Taller than the viewport, so the deck is not crammed between
     the heading above it and the section edge below. The head and
     the deck are both placed as percentages of the section, so
     they spread with it rather than staying bunched at the top. */
  height: 125vh;
  height: 125svh;
  /* The deck is positioned against the section itself, so the
     flex column .sw-section sets is not wanted here. */
  display: block;
  padding: 0;
  /* Cards fan past the measure at rest, so the horizontal overspill
     has to be clipped or it widens the page.

     The vertical must NOT be clipped with it. The deck flies in
     from max(75vh, 600px) BELOW its resting place (introY in
     js/testimonials.js), and the deck's origin sits at 62% of a
     125vh section - so on a normal window the cards start their
     travel past the section's own bottom edge. A plain
     `overflow: hidden` clips that, and the cards appear to be
     sliced off by an invisible line partway down the section
     instead of rising from off-screen.

     clip, not hidden, is what makes a split possible. `hidden` is a
     SCROLLING overflow value, so pairing it with `visible` on the
     other axis makes the browser compute that axis to auto - the
     section gets a scroll port and the travel is clipped anyway.
     `clip` creates no scroll port, so it composes with `visible`
     and the two axes genuinely differ.

     Per-axis clip MARGINS are not an option here:
     overflow-clip-margin-block does not exist, and the plain
     overflow-clip-margin is both limited in support and applies to
     all four sides - which would let the fan widen the page again.
     Splitting the axes does the job with neither. */
  overflow-x: clip;
  overflow-y: visible;
  background: var(--sw-paper);
}

/* The head sits absolutely so the deck can centre on the
   section rather than on whatever the head happens to be
   tall. */
.sw-tm-head {
  position: absolute;
  /* Three stacked words are taller than the two-line version this
     started as, so the head sits nearer the top of the section to
     keep the deck clear of the pill hanging off the last word.
     Tied to viewport height so a short laptop pulls it up rather
     than pushing the heading into the cards. */
  top: clamp(1.5rem, 5vh, 4rem);
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100% - 3rem);
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  text-align: center;
  /* The cards sit under the heading at the top of their travel,
     so the head must not eat their hover. */
  pointer-events: none;
}

/* The deck's origin: a zero-size point the cards are offset
   from, so every card shares one centre. */
.sw-tm-deck {
  position: absolute;
  /* Centred below the middle: the head takes the top of the
     section and the foot notes sit above the nav, so the deck
     wants the space between them rather than the true centre.
     Low enough that the last line of the heading and the pill
     hanging off it both clear the top edge of the cards. */
  top: 62%;
  left: 50%;
  width: 0;
  height: 0;
}

.sw-tm-card {
  position: absolute;
  top: 0;
  left: 0;
  /* Sized against the viewport rather than fixed: the deck has to
     fit between the stacked heading above it and the foot notes
     below on a 768px laptop as well as a 1080px desktop. The JS
     reads the rendered width back when it lays the fan out, so
     these two are the only place the card's size is set. */
  /* The reference's card is a fixed 320x420. Kept proportional to
     the viewport so a small laptop is not handed a card cut for a
     desktop, but the ratio and the upper end are its own. */
  /* Pulled in a step from 22vw/320x420: the fan was sitting heavy
     under the heading. The ratio is held, so the fan's geometry -
     which JS derives from the rendered width - is unchanged. */
  width: clamp(240px, 20vw, 290px);
  height: clamp(320px, 51vh, 380px);
  display: flex;
  flex-direction: column;
  /* Stars at the top, author at the foot, quote taking the middle.
     The card is a fixed height, so the three parts hold their
     positions whatever the length of the quote. */
  justify-content: space-between;
  gap: 1.35rem;
  padding: 1.6rem;
  /* Bevelled, not rounded, to match the nav, the showreel plate and
     the showcase images - every other plate on the page cuts its
     corners at 45 degrees off the same notch. */
  --sw-plate-notch: 12px;
  clip-path: polygon(
    var(--sw-plate-notch) 0,
    calc(100% - var(--sw-plate-notch)) 0,
    100% var(--sw-plate-notch),
    100% calc(100% - var(--sw-plate-notch)),
    calc(100% - var(--sw-plate-notch)) 100%,
    var(--sw-plate-notch) 100%,
    0 calc(100% - var(--sw-plate-notch)),
    0 var(--sw-plate-notch)
  );
  background: #fff;
  /* The hairline is drawn by ::after rather than as a border: a
     clip-path cuts through the border box, so a real border would
     be sliced off at each of the eight corners. The colour lives
     here so the dark card can override it in one place. */
  --sw-card-edge: #d9d9d3;
  border: 0;
  color: #14140f;
  /* drop-shadow, not box-shadow. box-shadow is drawn from the
     rectangular border box, so it ignores the clip above and
     leaves four square corners sticking out past the bevel. A
     filter shadow is taken from the CLIPPED silhouette and follows
     all eight sides - the same reasoning as the tags in
     css/tags.css and the showcase plates.

     It has to be the filter rather than a shadow on a child: the
     clip-path clips the card's own pseudo-elements too, so a
     ::before drawn behind the card would be clipped away with it
     and cast nothing at all.

     The cards carry live GSAP transforms, but those are composited
     against an already-rasterized layer (will-change: transform
     below), so the filter is applied once per card rather than per
     frame of the fan. */
  --sw-card-shadow: drop-shadow(0 14px 30px rgba(20, 20, 15, 0.16));
  filter: var(--sw-card-shadow);
  cursor: pointer;
  will-change: transform;
}

/* The hairline, as a 1px band between two clipped rings - the same
   construction the showreel plate uses (css/intro.css). An inset
   box-shadow cannot follow a clip-path either: it would draw a
   rectangle and the bevel would slice its corners off. */
.sw-tm-card::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Above the card's own fill so the band is not painted over by
     it. It only ever covers the outermost pixel and the card has
     1.6rem of padding, so nothing in the content runs under it -
     and pointer-events stay off, so the card is still draggable
     through it. */
  z-index: 1;
  background: var(--sw-card-edge);
  clip-path: polygon(
    /* outer ring, clockwise from the top-left bevel */
    var(--sw-plate-notch) 0,
    calc(100% - var(--sw-plate-notch)) 0,
    100% var(--sw-plate-notch),
    100% calc(100% - var(--sw-plate-notch)),
    calc(100% - var(--sw-plate-notch)) 100%,
    var(--sw-plate-notch) 100%,
    0 calc(100% - var(--sw-plate-notch)),
    0 var(--sw-plate-notch),
    /* back to the start, then the inner ring anticlockwise, which
       leaves only the 1px band between them filled */
    var(--sw-plate-notch) 0,
    0 var(--sw-plate-notch),
    1px calc(var(--sw-plate-notch) + 1px),
    1px calc(100% - var(--sw-plate-notch) - 1px),
    calc(var(--sw-plate-notch) + 1px) calc(100% - 1px),
    calc(100% - var(--sw-plate-notch) - 1px) calc(100% - 1px),
    calc(100% - 1px) calc(100% - var(--sw-plate-notch) - 1px),
    calc(100% - 1px) calc(var(--sw-plate-notch) + 1px),
    calc(100% - var(--sw-plate-notch) - 1px) 1px,
    calc(var(--sw-plate-notch) + 1px) 1px,
    1px calc(var(--sw-plate-notch) + 1px)
  );
  pointer-events: none;
}

/* Alternating tone, so the fan reads as a deck rather than a
   row of the same card five times. The deck opens and closes on
   a dark card - three dark, two light - so the ink carries the
   outer edges of the fan against the white section. */
.sw-tm-card--dark {
  background: #14140f;
  /* The hairline the light card needs against the white ground
     would only read as a seam here, so it matches the fill. */
  --sw-card-edge: #14140f;
  color: #f4f4f2;
  /* A touch deeper than the light card's. An ink shadow falling
     on a near-black card all but disappears, so without this the
     dark cards sit flat in the fan while the light ones lift. */
  --sw-card-shadow: drop-shadow(0 12px 28px rgba(20, 20, 15, 0.26));
}

/* The rating is the card's one spot of colour, in the same lime
   the cursor, the draggable pill and the CTA underline carry, so
   the deck is tied to the rest of the page rather than sitting
   apart from it.

   The light card is the default, so it takes the darker of the two
   accent tokens: the full lime on #fff sits at 1.15:1 and the stars
   simply vanish. --sw-accent-ink is the same yellow-green dropped in
   lightness, and clears 4.7:1 here. The dark card overrides this
   below, where the bright lime is the one that reads. */
.sw-tm-stars {
  display: flex;
  gap: 0.25rem;
  line-height: 1;
  color: var(--sw-accent-ink);
}

/* On ink the bright accent is the readable one - 16:1 - and it is
   the colour the rest of the page's accents are set in, so the dark
   card carries the lime the deck is meant to echo. */
.sw-tm-card--dark .sw-tm-stars {
  color: var(--sw-accent);
}

.sw-tm-stars svg {
  width: 0.85rem;
  height: 0.85rem;
  fill: currentColor;
}

/* Takes the slack between the stars and the author block, so the
   author always sits on the foot of the card.

   Set as display copy rather than body copy: the quote is the
   reason the card exists, and at body size it sat flat against
   the role line under it. The medium face and the tighter
   tracking are the page's own - the headings are set the same
   way. Note this is the TYPE only; the card around it stays as
   plain as the reference's. */
.sw-tm-quote {
  flex: 1;
  /* The Söhne faces are separate families in styles.css rather
     than weights of one, so the family has to be named - weight
     alone would leave this on Inter Tight with a fake bold. */
  font-family: "sohne-medium", "Inter Tight", sans-serif;
  font-size: clamp(1.0625rem, 1.15vw, 1.25rem);
  /* Tighter than body copy. A short measure set loose reads as
     scattered; a quote wants to hold together as one shape. */
  line-height: 1.32;
  letter-spacing: -0.02em;
}

/* A hairline separates the attribution from the quote, so the
   card reads as two parts - what was said, and who said it -
   rather than one run of text. It runs the full measure between
   the card's padding, which is what makes it read as a rule
   rather than a stray underline. */
.sw-tm-author {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding-top: 1.25rem;
  border-top: 2px solid #ebebe7;
}

.sw-tm-card--dark .sw-tm-author {
  /* Lifted off the card rather than dropped into it - an ink rule
     on a near-black ground would disappear. */
  border-top-color: rgba(244, 244, 242, 0.16);
}

.sw-tm-avatar {
  /* Up from the reference's 2.25rem: the quote above it is set
     larger here, and at 2.25 the portrait was the smallest thing
     on the card by some way. */
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  overflow: hidden;
  flex-shrink: 0;
  background: #e4e4e0;
  /* The portraits are photographs dropped straight onto the card,
     so a hairline contains them - inset rather than a border, so
     the ring sits inside the circle and cannot change its size. */
  box-shadow: inset 0 0 0 2px rgba(20, 20, 15, 0.1);
}

.sw-tm-card--dark .sw-tm-avatar {
  box-shadow: inset 0 0 0 2px rgba(244, 244, 242, 0.18);
}

.sw-tm-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.sw-tm-meta {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.sw-tm-name {
  /* Named as a family for the same reason the quote is - the
     Söhne faces are separate families, not weights. */
  font-family: "sohne-medium", "Inter Tight", sans-serif;
  font-size: 0.9375rem;
  font-weight: 500;
  letter-spacing: -0.015em;
  line-height: 1.2;
}

/* The same small-caps label .sw-section-label uses, so the
   attribution belongs to the page's vocabulary rather than being
   a label style of its own. */
.sw-tm-role {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  line-height: 1.2;
  color: #76766f;
}

.sw-tm-card--dark .sw-tm-role {
  color: #9a9a92;
}

/* ------------------------------------------------------------
   The margin note
   ------------------------------------------------------------
   The capabilities column's handwritten note (.sw-cap-note in
   css/slider.css), set in the band under the fan and off to the
   right. The fan runs nearly the full measure, so beside it there
   is no room; under it there is. The arrow sits off the note's
   left edge, mirrored, so it curls up and back at the cards.
   ------------------------------------------------------------ */
.sw-tm-note {
  position: absolute;
  right: clamp(3rem, 16vw, 18rem);
  bottom: clamp(3rem, 9vh, 7rem);
  z-index: 1;
  width: 9.5em;
  margin: 0;
  text-wrap: balance;
  font-family: "Shadows Into Light", "Inter Tight", cursive;
  font-size: clamp(1.15rem, 0.55vw + 0.85rem, 1.7rem);
  line-height: 1.22;
  letter-spacing: 0.03em;
  -webkit-text-stroke: 0.018em currentColor;
  color: #4a4a44;
  transform: rotate(-6deg);
  transform-origin: 0 0;
  /* A note, not a control - hovering the cards past it must still
     reach them. */
  pointer-events: none;
}

.sw-tm-arrow {
  position: absolute;
  right: 100%;
  bottom: 55%;
  width: clamp(4.5rem, 6vw, 7rem);
  height: auto;
  margin-right: 0.5rem;
  overflow: visible;
  /* The capabilities arrow runs up and to the right; flipped, it
     runs up and to the left, back toward the fan. */
  transform: scaleX(-1);
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Drawn in once the words are written; with no script (or reduced
   motion, where .is-writing is never set) it simply shows. */
.sw-tm-arrow path {
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
}
.sw-tm-note.is-writing .sw-tm-arrow path {
  stroke-dashoffset: 1;
}
.sw-tm-note.is-written .sw-tm-arrow path {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 0.7s cubic-bezier(0.65, 0, 0.35, 1);
}
.sw-tm-note.is-written .sw-tm-arrow path + path {
  transition-delay: 0.55s;
  transition-duration: 0.3s;
}

/* ------------------------------------------------------------
   Unstacked column. Matches the 1000px breakpoint the rest of
   the page switches at.
   ------------------------------------------------------------ */
@media (max-width: 1000px) {
  .sw-testimonials {
    height: auto;
    min-height: 0;
    overflow: visible;
    padding: 4rem 1.5rem 8rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2.5rem;
  }

  .sw-tm-head {
    position: relative;
    top: auto;
    left: auto;
    transform: none;
    max-width: 100%;
    pointer-events: auto;
  }

  .sw-tm-deck {
    position: relative;
    top: auto;
    left: auto;
    width: 100%;
    height: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.25rem;
  }

  /* Under the column of cards, in the flow. The cards are above
     it rather than off to one side, so the arrow is dropped. */
  .sw-tm-note {
    position: relative;
    right: auto;
    bottom: auto;
    align-self: flex-end;
    margin-right: 8%;
    transform: rotate(-4deg);
  }
  .sw-tm-arrow {
    display: none;
  }

  .sw-tm-card {
    position: relative;
    width: min(100%, 360px);
    height: auto;
    min-height: 320px;
    cursor: default;
    will-change: auto;
  }
}

/* ------------------------------------------------------------
   Archive deck
   ------------------------------------------------------------
   The same deck, under the featured section's wide three-word
   title instead of the stacked one. Only what the wider heading
   changes is set here - the cards, the fan and the unstacked
   column all come from the rules above.
   ------------------------------------------------------------ */

/* The stacked head is a centred max-content block. This one
   carries .sw-featured-title, which spreads its three words
   across the full measure with space-between, so it needs the
   whole width rather than shrinking to its content. */
.sw-archive-head {
  left: 0;
  right: 0;
  transform: none;
  width: auto;
  max-width: none;
  padding: 0 2.5rem;
  display: block;
  text-align: left;
  /* Proportional rather than the fixed rem offset the stacked
     head uses. The section runs to 125vh now, so a heading pinned
     a few rem from the top sat stranded above the deck with the
     extra height all falling below it; this keeps the gap between
     heading and cards roughly constant as the window grows. */
  top: 12%;
}

/* No font-size override: the heading is left at the full
   clamp(2.5rem, 6.8vw, 7.25rem) .sw-featured-title sets, so the
   two display headings on the page set identically. The deck is
   pushed down to clear it instead - see .sw-archive .sw-tm-deck
   below.

   The pill hangs off the heading and has to stay draggable, the
   same way .sw-tm-title gives it its pointer events back after
   the head switched them off. */
.sw-archive-head .sw-tag {
  pointer-events: auto;
}

/* The heading runs at the full featured size, so it is a tall
   single line and the deck has to sit below it.

   64% was right when the section was one viewport tall. Now that
   it runs to 125vh, the same percentage is a longer drop in
   pixels and left the deck sitting low with a gap under the
   heading. 68% keeps the heading and the deck clearly separated -
   the cards read as their own band rather than crowding the
   words above them.

   Back to 64% now the heading sets smaller: the shorter words left
   the band under them reading as dead space rather than breathing
   room. Then 60%, once the card shrank too - the deck had gained
   its own headroom from the top and the gap reopened. */
.sw-archive .sw-tm-deck {
  top: 60%;
}

@media (max-width: 1000px) {
  /* Unstacked, the head is an ordinary block at the top of the
     column and the side padding is the section's own. */
  .sw-archive-head {
    padding: 0;
  }

  /* The three words no longer have the width to sit in a row, so
     they stack and centre over the column of cards. */
  .sw-archive-head .sw-featured-title {
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 0;
    text-align: center;
  }
}
