/**
 * expanding-panels.css — expand behaviour for the hero panel row.
 *
 * Pairs with the .hero-skills markup built in the Webflow Designer. Structural
 * styles (flex basis, sizing, colour, type) live in Webflow where they are
 * editable; this file holds only what the Designer cannot express — descendant
 * combinators and :focus-visible.
 *
 * The panels are <button> elements. They have to be focusable and tappable
 * because the badge names a skill — that content is unreachable otherwise on
 * a keyboard or a phone, where there is no hover at all.
 *
 * Behaviour is split by input mode. On pointer devices only hover and keyboard
 * (:focus-visible) open a panel — a mouse click deliberately does nothing, so
 * it cannot pin one open. On touch there is no hover and a tap does not match
 * :focus-visible, so plain :focus is what opens a panel there.
 *
 * Requires :has() (Chrome 105+, Safari 15.4+, Firefox 121+) to check focus at
 * the row level.
 *
 * There is deliberately no JavaScript. The BYQ gem this is modelled on ships a
 * script because it built the panels as an ARIA tablist, which needs roving
 * tabindex and arrow keys. A plain row of buttons needs none of that: Tab moves
 * between them natively, :hover and :focus do the reveal, and the global
 * prefers-reduced-motion guard in reset.css applies for free — which it could
 * not do if this were driven by GSAP.
 *
 * Markup contract:
 *   .hero-skills
 *   └ a.hero-skill_panel            ← one per project
 *     ├ img.hero-skill_image
 *     └ div.hero-skill_caption
 *       └ div.hero-skill_title      ← rendered as a badge
 */

/* --------------------------------------------------------- base state --- */

.hero-skill_panel {
  transition: flex-grow 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}

.hero-skill_caption {
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}

/* ------------------------------------------------- pointer + keyboard --- */

/*
 * Split by input mode rather than stacking more :not() guards on one chain,
 * because the two modes genuinely want different triggers.
 *
 * Here, focus is :focus-visible — keyboard only. A mouse click focuses a
 * button too, and keying off plain :focus would leave the clicked panel open
 * while the pointer moved on, showing two at once.
 *
 * The :not(:hover) guard on the row means hover always wins over a lingering
 * keyboard focus, so exactly one panel is ever open.
 */
@media (hover: hover) {
  .hero-skills:not(:hover):not(:has(:focus-visible))
    .hero-skill_panel:nth-child(3) {
    flex-grow: 6;
  }

  .hero-skills:not(:hover):not(:has(:focus-visible))
    .hero-skill_panel:nth-child(3)
    .hero-skill_caption {
    opacity: 1;
    transform: none;
  }

  .hero-skill_panel:hover,
  .hero-skills:not(:hover) .hero-skill_panel:focus-visible {
    flex-grow: 6;
  }

  .hero-skill_panel:hover .hero-skill_caption,
  .hero-skills:not(:hover) .hero-skill_panel:focus-visible .hero-skill_caption {
    opacity: 1;
    transform: none;
  }
}

/* ------------------------------------------------------------- touch --- */

/*
 * No hover to rely on, and a tap does NOT match :focus-visible — so here plain
 * :focus is the only thing that can open a panel. Tapping a second one moves
 * focus, so only one stays open; tapping outside the row closes back to rest.
 */
@media (hover: none) {
  .hero-skills:not(:has(:focus)) .hero-skill_panel:nth-child(3) {
    flex-grow: 6;
  }

  .hero-skills:not(:has(:focus))
    .hero-skill_panel:nth-child(3)
    .hero-skill_caption {
    opacity: 1;
    transform: none;
  }

  .hero-skill_panel:focus {
    flex-grow: 6;
  }

  .hero-skill_panel:focus .hero-skill_caption {
    opacity: 1;
    transform: none;
  }
}

/* ------------------------------------------------------- panel count --- */

/*
 * Drop a panel at a time as the row narrows. A sliver stops reading as an
 * image below roughly 75px, and eight of them plus seven gaps eat the width
 * fast.
 *
 * display:none rather than visibility/opacity, so a hidden panel also leaves
 * the tab order — nothing focusable that nobody can see.
 *
 * Fewer panels also widens what is left, which is the point: at flex-grow 6,
 * eight panels give the open one 46.2% and each sliver 7.7%; seven give 50%
 * and 8.3%; six give 54.5% and 9.1%.
 */

/* 1025-1439 — seven */
@media (max-width: 1439px) {
  .hero-skill_panel:nth-child(n + 8) {
    display: none;
  }
}

/* 992-1024 — six */
@media (max-width: 1024px) {
  .hero-skill_panel:nth-child(n + 7) {
    display: none;
  }
}

/* ------------------------------------------- hero statement alignment --- */

/*
 * Positions .hero-statement-wrapper: its left edge aligns with the panel that
 * is open at rest (:nth-child(3)) — two slivers and two gaps in from the row's
 * padding — and it sits directly above the panel column.
 *
 * max-width runs the wrapper from the left edge of the panel that is open at
 * rest to the RIGHT edge of the next one along — the open panel, the gap after
 * it, and one sliver. So the statement spans two slices rather than sitting
 * inside the open one, and its right edge lands on a real panel edge:
 *
 *   width = (grow + 1) * (100% - 2P - (n-1)g) / (n - 1 + grow) + g
 *
 * Because the wrapper is also the query container (container-type: inline-size),
 * constraining it here means the statement's clamp(..cqi..) font-size scales
 * with that span rather than with the viewport — the type and the box it aligns
 * to move together.
 *
 * SO WIDENING THE SPAN ALSO ENLARGES THE TYPE, and by the same ratio: the
 * statement does not fit more words per line, it renders larger with the same
 * line breaks. Measured against the published sandbox: 40px -> 41.2px at a
 * 1440 viewport, 47.8px -> 56.2px at 1920. If the type should hold still while
 * the box grows, the font-size has to stop reading cqi from this element.
 *
 * margin-left rather than left: the wrapper is in normal flow now, not
 * absolutely positioned.
 *
 *   left = P + 2g + 2 * (row - 2P - (n-1)g) / (n - 1 + grow)
 *
 * where P is the site padding token, g the 0.5rem gap, n the panel count at
 * that breakpoint and grow is 6. The sliver width is flex-derived, so this
 * cannot be a fixed percentage — it changes at every panel-count step.
 *
 * 100% not 100vw: percentages on `left` resolve against .hero, which excludes
 * the scrollbar. 100vw includes it, and the row does not — so vw would drift
 * by the scrollbar width whenever one is present.
 *
 * Scoped to >= 992px because the sub-991 layout is still an open design
 * decision; below that the class keeps its own Webflow value.
 *
 * .hero prefix is for specificity only — it has to beat the `left` set on
 * .hero-statement in the Designer regardless of stylesheet order.
 *
 * COUPLED: if the gap, flex-grow, panel counts or the default-open index
 * change, these change with them.
 */

/*
 * Base — applies at EVERY width, so the wrapper always has a margin-left.
 * It is container-type: inline-size, which implies contain: inline-size, so it
 * cannot size itself from its own content; the panel-aligned values below only
 * override this one.
 *
 * Vertical placement is not set here. The hero is a column flex container and
 * the wrapper carries margin-block: auto (Designer), so it centres itself in
 * whatever space is left between the hero's padding edge and .hero_panels-col.
 * That adapts to viewport height on its own, which no calc could have done —
 * see the optical correction below for why centring alone is not enough.
 */
.hero .hero-statement-wrapper {
  margin-left: var(--_layout---site-padding--desktop);
  max-width: calc(
    7 * (100% - 2 * var(--_layout---site-padding--desktop) - 2.5rem) / 11 + 0.5rem
  );
}

/* 1440+ — eight panels, 13 shares */
@media (min-width: 992px) {
  .hero .hero-statement-wrapper {
    margin-left: calc(
      var(--_layout---site-padding--desktop) + 1rem +
        2 * (100% - 2 * var(--_layout---site-padding--desktop) - 3.5rem) / 13
    );
    max-width: calc(
      7 * (100% - 2 * var(--_layout---site-padding--desktop) - 3.5rem) / 13 + 0.5rem
    );
  }
}

/* 1025-1439 — seven panels, 12 shares */
@media (min-width: 992px) and (max-width: 1439px) {
  .hero .hero-statement-wrapper {
    margin-left: calc(
      var(--_layout---site-padding--desktop) + 1rem +
        2 * (100% - 2 * var(--_layout---site-padding--desktop) - 3rem) / 12
    );
    max-width: calc(
      7 * (100% - 2 * var(--_layout---site-padding--desktop) - 3rem) / 12 + 0.5rem
    );
  }
}

/* 992-1024 — six panels, 11 shares */
@media (min-width: 992px) and (max-width: 1024px) {
  .hero .hero-statement-wrapper {
    margin-left: calc(
      var(--_layout---site-padding--desktop) + 1rem +
        2 * (100% - 2 * var(--_layout---site-padding--desktop) - 2.5rem) / 11
    );
    max-width: calc(
      7 * (100% - 2 * var(--_layout---site-padding--desktop) - 2.5rem) / 11 + 0.5rem
    );
  }
}

/* ------------------------------- statement optical centring --- */

/*
 * Equalises the gap ABOVE the statement (to the header) with the gap BELOW it
 * (to the panel row). margin-block: auto already centres the wrapper exactly —
 * but it centres against the hero's padding edge, and that edge is not where
 * the header visually ends.
 *
 * .hero reserves the full --site-nav-height as padding-top so its background
 * runs up under the sticky nav. The nav's own block padding (2rem) sits inside
 * that height, so the nav's TEXT stops 2rem short of the padding edge, while
 * the panel row below starts at its own top edge with nothing to spare. Perfect
 * geometric centring therefore reads as low: measured ink-to-ink at 1440x900,
 * 97.5px above versus 64.6px below.
 *
 * padding-bottom on the wrapper fixes it in layout rather than with a nudge.
 * It makes the wrapper 2rem taller, so each auto margin shrinks by 1rem and the
 * text rises by half the error — which is exactly the correction, because the
 * error is split between two margins. Measured after: 81.5 / 80.6 at 1440x900,
 * and the same 0.8-0.9px residual at 1440x1200, 1920x900, 1280x720, 1000x800.
 * That residual is the type's own half-leading, not a layout error.
 *
 * A transform would have been the tempting fix. It would have shifted the ink
 * without telling the layout, so the wrapper's box and the space it reserves
 * would have disagreed from then on.
 *
 * Block padding only — the wrapper is the inline-size query container, so this
 * does not touch the statement's cqi font-size.
 *
 * COUPLED to the nav's block padding. If the nav's vertical padding changes in
 * the Designer, this changes with it.
 *
 * Scoped to >= 992px with the rest of the statement rules: the sub-991 layout
 * is still an open design decision.
 */
@media (min-width: 992px) {
  .hero .hero-statement-wrapper {
    padding-bottom: 2rem;
  }
}

/* ------------------------------------------------------------- focus --- */

/*
 * Inset rather than offset: a positive outline-offset would sit outside the
 * capsule the image draws and read as a detached rectangle.
 */
.hero-skill_panel:focus-visible {
  outline: 2px solid var(--border--accent, #4ca077);
  outline-offset: -2px;
}
