/* ==========================================================================
   Team — portraits inside a drawn frame.

   Built as its own file so it could be developed while another session held
   index.html and styles.css. Every selector here is new; nothing overrides an
   existing rule. To merge, append this file to css/styles.css.

   THERE IS NO FRAME IMAGE. The silhouette is one SVG path, traced off the
   reference: straight sides, a small outward ear at each corner, a shallow peak
   at top centre and a drop to a point at bottom centre. It is used twice — as a
   clipPath for the photograph and as a stroked outline for the two hairlines —
   so the whole frame costs about 400 bytes and stays sharp at any size. An
   ornate PNG was built first and thrown away; it fought the page.

   Pure CSS cannot do this shape: border-radius has no concave cusp and no
   bottom point. The path is the minimum vector needed, and everything else —
   colour, weight, motion, the draw-on — is CSS.

   The interaction: at rest the frame holds a portrait and carries no text; on
   hover the portrait swells slightly and the booking line rises out of the
   bottom edge. (The reference's two-shot cross-fade is gone — the current set
   is one studio portrait per barber.)
   ========================================================================== */

.team{
  /* One dark red, only used for the outer hairline. It reads as the shadow the
     gilt line sits in rather than as a second colour on the page. */
  --tm-edge-dark:oklch(0.285 0.052 32);
  /* Path length in viewBox units, from getTotalLength(). Constant, because the
     viewBox is fixed at 100x154. Re-measure if the silhouette ever changes. */
  --tm-len:472;

  background:var(--ink);
  /* NO TOP PADDING. Every other section on this page runs padding-top:0 and
     lets the preceding section's bottom padding carry the junction. Team was
     the only one adding its own, which stacked 90px on top of the 108px it
     already inherited from .reviews and made that gap 198px — more than double
     any other junction on the page. Keep it at 0 unless every section changes. */
  padding:0 0 clamp(80px,12vh,160px);
  /* The reveal translates on Y only, but clip also stops any sub-pixel stroke
     overhang adding a scrollbar. `clip`, not `hidden`: hidden would make this a
     scroll container. */
  overflow-x:clip;
}

.tm-defs{position:absolute; width:0; height:0; overflow:hidden}

/* --- heading ---------------------------------------------------------- */

.team-head{
  width:min(720px,88vw); margin:0 auto clamp(38px,5vw,66px);
  text-align:center;
}
.team-h{
  margin:0 0 .46em;
  font-family:'Rye',serif; font-weight:400;
  font-size:clamp(2rem,4vw,3.15rem); line-height:1.14;
  color:var(--bone);
}
.team-intro{
  margin:0 auto; max-width:52ch;
  font-size:1.06rem; line-height:1.6;
  color:var(--bone-dim); text-wrap:pretty;
}

/* --- the grid --------------------------------------------------------- */

/* Seven barbers, four across then three. FLEX, not grid: an incomplete last row
   in a grid stays left-aligned, and centring it needs either explicit column
   spans on a 24-column track or a hard-coded nth-child. Flex wrap centres the
   remainder for free and keeps every card the same width. */
.team-grid{
  --tm-gap:clamp(14px,1.8vw,22px);
  width:min(1040px,90vw); margin:0 auto;
  display:flex; flex-wrap:wrap; justify-content:center;
  gap:var(--tm-gap);
}
/* ~245px at full width — the size the cards were cut for. */
.tm{flex:0 0 calc((100% - 3 * var(--tm-gap)) / 4); min-width:0}

/* --- one framed barber ------------------------------------------------ */

.tm{margin:0}
.tm-link{display:block; text-decoration:none; color:inherit}

/* 100:154 is the reference frame's own ratio, measured off the screenshot. */
.tm-plate{
  position:relative; display:block;
  aspect-ratio:100/154;
  transition:transform .45s var(--ease-out-quint);
}

/* inset:0 is load-bearing. An inset window is a different aspect ratio from the
   plate, and clipPathUnits="objectBoundingBox" rescales the silhouette to
   whatever box it lands in — so the photo's outline stopped matching the drawn
   one and escaped it near the bottom point. Same box, same shape, edges align
   exactly; the band comes from the widest stroke instead. */
.tm-window{
  position:absolute; inset:0;
  overflow:hidden;
  clip-path:url(#tmFrame);
  background:var(--ink-raised);
}

.tm-shot,
.tm-shot img{position:absolute; inset:0; width:100%; height:100%; object-fit:cover}
/* Barely graded, like the reviews mosaic: these sources are already dark and
   warm, and grading them further just loses the faces. */
.tm-shot img{filter:grayscale(.20) brightness(1.02) contrast(1.03)}

/* There is no second "at work" shot any more — the new set is one studio
   portrait per barber, so the hover pushes the portrait instead of cross-fading
   to another frame. Scale only; nothing here changes layout. */
.tm-shot--rest img{transition:transform .6s var(--ease-out-quint)}
.tm-link:hover .tm-shot--rest img,
.tm-link:focus-visible .tm-shot--rest img{transform:scale(1.045)}

/* --- the drawn edge --------------------------------------------------- */

.tm-edge{
  position:absolute; inset:0; z-index:2;
  width:100%; height:100%;
  pointer-events:none;
  overflow:visible;
}
/* Two concentric strokes on one path, thick dark under thin bronze, which
   renders as dark / gilt / dark across the line — the reference's three bands
   without needing three paths.

   The SVG scales UNIFORMLY (no preserveAspectRatio="none") because .tm-plate is
   already locked to the viewBox's own 100:154. That matters twice over: a
   stretched viewBox draws the top and bottom edges thinner than the sides, and
   the usual fix, vector-effect:non-scaling-stroke, puts dash lengths into screen
   pixels while pathLength="1" normalises the path to one unit — the two do not
   compose, and the drawn line comes out in fragments. Uniform scaling needs
   neither. Widths are therefore in user units: 100 across the card, so 1 unit
   is about 3.3px at desktop size. */
.tm-ln{
  fill:none;
  stroke-linejoin:round;
  transition:stroke .45s var(--ease-out-quint),
             stroke-width .45s var(--ease-out-quint),
             stroke-opacity .45s var(--ease-out-quint);
}
/* Three concentric strokes on one path. Widest first, in the ground colour: it
   covers the clipped photograph's edge and IS the dark band. The two coloured
   lines sit centred inside it, so a cross-section reads
   ink | oxblood | gilt | oxblood | ink — the reference's banding from one path.
   The band does not animate; only the two coloured lines draw themselves on. */
/* Held at 70% against the ground on purpose. At full strength --bronze is the
   page's signal colour and a closed loop of it around every card shouted louder
   than the reference's hairline; dimming beats inventing a second gold. */
.tm-ln--band{stroke:var(--ink);          stroke-width:6}
.tm-ln--out {stroke:var(--tm-edge-dark); stroke-width:1.1}
.tm-ln--in  {stroke:var(--bronze);       stroke-width:.34; stroke-opacity:.70}

/* --- the booking line ------------------------------------------------- */

.tm-veil{
  position:absolute; inset:0; z-index:1; opacity:0;
  background:linear-gradient(
    to top,
    oklch(0.172 0.006 62 / .93) 0%,
    oklch(0.172 0.006 62 / .58) 44%,
    oklch(0.172 0.006 62 / 0)   80%);
  transition:opacity .5s var(--ease-out-quint);
}

.tm-cta{
  position:absolute; inset:auto 0 0 0; z-index:2;
  /* Clear of the bottom point, or the name sits in the V. */
  padding:0 9% 13%;
  text-align:center;
  opacity:0; transform:translateY(9px);
  transition:opacity .5s var(--ease-out-quint),
             transform .5s var(--ease-out-quint);
}
.tm-cta em{
  display:block; font-style:italic;
  font-size:clamp(.92rem,1.05vw,1.04rem); line-height:1.1;
  color:var(--bone-dim);
}
.tm-cta strong{
  display:block; margin-top:.3em;
  font-weight:600;
  font-size:clamp(.82rem,.92vw,.94rem); letter-spacing:.19em;
  text-transform:uppercase;
  color:var(--bone);
}

.tm-link:hover .tm-veil,
.tm-link:focus-visible .tm-veil{opacity:1}
.tm-link:hover .tm-cta,
.tm-link:focus-visible .tm-cta{opacity:1; transform:none}
/* The line lighting up is the hover's quietest half — it reads before the
   photograph has finished changing. */
.tm-link:hover .tm-ln--in,
.tm-link:focus-visible .tm-ln--in{stroke:var(--bronze-lit); stroke-width:.5; stroke-opacity:1}
.tm-link:hover .tm-plate,
.tm-link:focus-visible .tm-plate{transform:translateY(-7px)}

/* Without a pointer there is no hover, so the name would never appear and the
   card would be an unlabelled photograph. Show the line permanently instead;
   the portrait stays put because there is nothing to trigger the swap. */
@media (hover:none){
  .tm-veil,
  .tm-cta{opacity:1; transform:none}
}

/* --- motion ----------------------------------------------------------- */

/* Longhand only. The `animation:` shorthand would set animation-duration to 0s,
   and a scroll-driven animation with a zero duration snaps to its end state —
   the effect silently does nothing while every check still passes.
   Each range also ENDS partway through `cover`; a range of cover 0% cover 100%
   never settles, so nothing would come fully to rest.

   Both the dasharray and the starting offset live INSIDE this block, so a
   browser without scroll timelines gets a solid, fully drawn line rather than
   an invisible one. Enhance a visible default; never gate content on it. */
@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    .tm{
      animation-name:tm-rise;
      animation-duration:auto;
      animation-timing-function:linear;
      animation-fill-mode:both;
      animation-timeline:view();
      animation-range:entry 5% cover 26%;
    }
    /* Stagger RESTARTS on the second row. These were written for three cards;
       with seven, 4-7 all silently fell back to the base range, so the fourth
       card popped on the first card's timing and the bottom row had none at
       all. Row 1 is 1-4, row 2 is 5-7, and 5 uses the base rule above. */
    .tm:nth-child(2),
    .tm:nth-child(6){animation-range:entry 5% cover 31%}
    .tm:nth-child(3),
    .tm:nth-child(7){animation-range:entry 5% cover 36%}
    .tm:nth-child(4){animation-range:entry 5% cover 41%}

    /* --tm-len is the path's real length in viewBox units, measured once with
       getTotalLength(). It is a constant: the viewBox is fixed at 100x154, so
       the length does not change with card size and needs no JS at runtime.

       pathLength="1" was tried first and does NOT work here — Chrome resolves a
       CSS stroke-dasharray in pixels and ignores the attribute's normalisation,
       so `stroke-dasharray:1` drew a 1px dotted line instead of one full dash. */
    .tm-ln--out,
    .tm-ln--in{
      stroke-dasharray:var(--tm-len);
      stroke-dashoffset:var(--tm-len);
      animation-name:tm-draw;
      animation-duration:auto;
      animation-timing-function:linear;
      animation-fill-mode:both;
      animation-timeline:view();
      animation-range:entry 7% cover 30%;
    }
    /* Same restart on row two. Every range still ENDS partway through `cover` —
       a range that ends too late leaves the line permanently part-drawn. */
    .tm:nth-child(2) .tm-ln--out, .tm:nth-child(2) .tm-ln--in,
    .tm:nth-child(6) .tm-ln--out, .tm:nth-child(6) .tm-ln--in{animation-range:entry 7% cover 36%}
    .tm:nth-child(3) .tm-ln--out, .tm:nth-child(3) .tm-ln--in,
    .tm:nth-child(7) .tm-ln--out, .tm:nth-child(7) .tm-ln--in{animation-range:entry 7% cover 42%}
    .tm:nth-child(4) .tm-ln--out,
    .tm:nth-child(4) .tm-ln--in{animation-range:entry 7% cover 48%}
  }
}
@keyframes tm-rise{
  from{opacity:0; transform:translateY(40px)}
  to  {opacity:1; transform:none}
}
@keyframes tm-draw{
  to{stroke-dashoffset:0}
}

@media (prefers-reduced-motion:reduce){
  .tm-shot--rest img,.tm-veil,.tm-cta,.tm-ln,.tm-plate{transition:none}
}

/* --- breakpoints ------------------------------------------------------ */

/* Just the per-card basis — flex-wrap re-flows and re-centres the remainder on
   its own, so no last-child special case is needed at any width. */
@media (max-width:880px){
  .team-grid{width:min(720px,92vw)}
  .tm{flex-basis:calc((100% - 2 * var(--tm-gap)) / 3)}
}
@media (max-width:560px){
  .team-grid{width:min(420px,92vw)}
  .tm{flex-basis:calc((100% - var(--tm-gap)) / 2)}
}
