/* ============================================================================
   PORTFOLIO GRID — the Kinsey "Portfolio Masonry Grid" widget.

   Two components, both belonging to that one widget: its SECTION HEADING
   ("All Projects") and its FILTER ROW ("ALL DISCIPLINES  COPY  IDENTITY …",
   with a 2px underline that slides between items).

   This row was hidden with `display: none !important` on `page-id-3121` until
   26 Jul 2026, which also overrode the widget's own "Enable Grid Filter"
   toggle. It is now controlled from Elementor and styled here.

   ---------------------------------------------------------------------------

   SEVERAL THINGS HERE ARE NOT CSS, AND MUST NOT BE

   The widget has native controls for all of these, in
   Elementor -> Portfolio Masonry Grid -> Settings -> Filter:

     the counters ("1", "*")    Show Terms Counters   ->  off
     the "All" wording          All Label             ->  "All Disciplines"
     left alignment             Justify Filter Items  ->  Start
     the mobile treatment       Filter Mobile Style   ->  Dropdown

   Hiding the counters with CSS here would recreate exactly the bug that was
   just removed from 05-masthead.css: a stylesheet quietly overruling a control
   that still looks live in the editor. If numbers reappear, the toggle got
   switched back on — fix it there, not here.

   ---------------------------------------------------------------------------

   THE UNDERLINE IS POSITIONED BY JAVASCRIPT, NOT BY CSS

   modules/sectionGrid/sectionGrid.min.js -> updateLinePosition() tweens it
   with GSAP on every filter change:

       width  = $('.filter__item-label').innerWidth()
       x      = label.position().left + inner.position().left
       y      = label.offset().top - filterContainer.offset().top
       ease   = expo.inOut, duration 0.5s

   Consequences worth knowing before editing anything below:

     - Its WIDTH is measured from `.filter__item-label`. Changing that
       element's font-size, letter-spacing or padding moves the underline.
       Changing the padding on `.filter__item` (the column) does not.
     - The counter span is absolutely positioned and sits OUTSIDE the label,
       so switching counters off does not change the underline geometry.
     - `width`, `x`, `y`, `scale` and `transform-origin` are written as inline
       styles by GSAP. Do not set them here — GSAP wins on the next tween and
       the two fight. Colour, height and margin are safe; geometry is not.

   The smooth travel is entirely GSAP's. Nothing here should add a CSS
   `transition` to the underline, or the two easings compound and it drifts.
   ============================================================================ */


/* ===========================================================================
   SECTION HEADING — "All Projects"
   ===========================================================================

   Rendered as `<h1 class="my-0 xl arts-split-text …>`. The `xl` class is one
   of Kinsey's global type presets, so it must NOT be restyled directly — it
   is used elsewhere. Everything below is scoped inside `.section-grid`, which
   only this widget carries.

   BOTH VALUES ARE SET BY REDEFINING KINSEY'S OWN VARIABLES rather than by
   writing `font-size` / `line-height` outright. `.xl` computes its size from
   them with a fluid formula:

       font-size: calc(var(--xl-min-font-size) * 1px
                  + (var(--xl-max-font-size) - var(--xl-min-font-size))
                    * (100vw - 320px) / 1600)

   Overriding `font-size` with a flat value would win, and would throw away
   that whole formula — the heading would stop scaling and sit at one size
   from phone to desktop. Overriding the VARIABLE leaves the formula intact
   and just moves its ceiling, so the type still grows with the viewport.

     --xl-max-font-size   102 -> 64. This is the size at >=1920px; the 102 you
                          measured was that ceiling. The floor stays 46px at
                          320px, so phones are barely affected.

     --xl-line-height     1.18 -> 1.35. Gives the line box room to contain
                          Vulf Sans's descenders. Necessary for the rule
                          below to have anything to expand into, but NOT
                          sufficient on its own — see the descender fix. */
     --xl-letter-spacing  -2 -> 0. Kinsey tightens its display sizes
                          optically (-2px here, -4 on xxl, -10 on xxxl). At
                          64px that tracking reads as a squeeze rather than
                          as refinement, so it is removed. One value, so it
                          goes at every viewport — there is no separate
                          mobile figure to also change. */
.section-grid .xl {
	--xl-max-font-size: 64;
	--xl-line-height: 1.35;
	--xl-letter-spacing: 0;
}

/* DESCENDER FIX — stops the "y" and "g" of "Everything" being cut off.

   WHY THE OBVIOUS FIXES DO NOT WORK, so nobody spends an afternoon on them
   again:

   Kinsey's split-text plugin wraps every line in a `.overflow` mask
   (`overflow: hidden`) so GSAP can slide the line up from `y: 100%` behind
   it. The mask takes its height from the line inside it. And GSAP's
   SplitText writes an EXPLICIT INLINE PIXEL HEIGHT onto that line
   (`height = d - L + "px"` in SplitText.min.js) at the moment it splits.

   That inline height is measured tight to the text and does not allow for
   glyphs that hang below the line box. It also outranks every stylesheet
   rule, which is why:

     - raising `--xl-line-height` alone changes nothing. The line-height is
       real, but the inline `height` pins the box regardless, so the mask
       never grows.
     - padding the mask helps only partially. Tested at 0.22em: the cut moves
       down but the descender is still caught.
     - `overflow: visible` on the mask "works" and breaks the reveal — the
       line becomes visible sitting below its slot before it animates in.

   Releasing the line back to its natural height is what actually fixes it.
   `!important` in a stylesheet outranks a non-important inline style, which
   is the one lever available against JS-written geometry. The line then
   takes its height from `--xl-line-height` above, which is why that value
   matters — the two rules only work together.

   Verified by reproducing the inline height in a static harness and
   comparing all three approaches side by side.

   The animation is unaffected: `y: 100%` is relative to the line's own
   height, so a taller line still travels fully out of the mask. */
.section-grid .xl .arts-split-text__line {
	height: auto !important;
}


/* ===========================================================================
   FILTER ROW
   =========================================================================== */

/* --- State colours -------------------------------------------------------

   Kinsey carries the active/inactive distinction with OPACITY — `.5` on every
   item, `1` on the active one — over a single inherited colour. That cannot
   produce the two values this design asks for: #333333 at 50% over the
   #E4E4E4 page computes to roughly #8C8C8C, which is neither #7a7a7a nor
   anything intended.

   So opacity is pinned to 1 and the states are carried by real colour. The
   `opacity` overrides are load-bearing, not tidying — without them every
   colour below is halved.

   `.filter` is included in each selector purely to out-specify
   sectionGrid.min.css, which Kinsey's asset loader injects at RUNTIME — it is
   not a <link> in the page source, and it lands after this file.

   THE COLOUR MUST BE SET ON THE INNER ELEMENTS, NOT JUST THE ITEM. Setting it
   only on `.filter__item` looks right and does nothing: `.filter__item-inner`
   also carries the `h6` utility class, and Kinsey's `h6` rule sets
   `color: var(--h6-color-dark)` on that element directly. An inherited colour
   from the parent loses to a colour set on the child, so the text would keep
   Kinsey's heading colour and only the gap around it would change. */
.filter .filter__item,
.filter .filter__item .filter__item-inner,
.filter .filter__item .filter__item-label,
.filter .filter__item .block-counter__counter {
	opacity: 1 !important;
	color: var(--evm-ink-muted) !important;
}

.filter .filter__item_active,
.filter .filter__item_active .filter__item-inner,
.filter .filter__item_active .filter__item-label,
.filter .filter__item_active .block-counter__counter {
	opacity: 1 !important;
	color: var(--evm-ink-active) !important;
}

/* Kinsey's hover rule only restored opacity, which now does nothing. Hover
   previews the active colour instead. The active item is `pointer-events:
   none` upstream, so it can never be in a hover state itself. */
.filter .filter__item:not(.filter__item_active):hover,
.filter .filter__item:not(.filter__item_active):hover .filter__item-inner,
.filter .filter__item:not(.filter__item_active):hover .filter__item-label {
	opacity: 1 !important;
	color: var(--evm-ink-active) !important;
}


/* --- Type ----------------------------------------------------------------

   The eyebrow treatment (see 03-base.css): mono / 500 / caps / 0.1em. Stated
   here rather than by adding `evm-eyebrow` to the markup, because the class
   list on these items is generated by the widget and is not ours to edit.

   Note `h6` is also on this element. That class sets a fluid font-size via
   Kinsey's clamp variables, which is why the size below needs !important.

   LINE-HEIGHT IS SET EXPLICITLY. Kinsey's `--h6-line-height: 1.8` gives 23.4px
   of box for 13px of type — generous for a heading, loose for a row of filter
   labels. 18.4px is that minus the 5px asked for. Stated in px rather than as
   a ratio so it stays put if the font-size is ever touched, and because the
   underline offset below was inspected against this exact value. */
.filter .filter__item-inner {
	font-family: 'JetBrains Mono' !important;
	font-weight: 500 !important;
	font-size: 13px !important;
	text-transform: uppercase !important;
	letter-spacing: 0.1em !important;
	line-height: 18.4px !important;
}


/* --- Spacing -------------------------------------------------------------

   HORIZONTAL. The row is Bootstrap `gx-3` — a 1rem gutter, meaning 0.5rem of
   padding on each side of every item, so 16px between neighbours. Doubled to
   32px here.

   SET THE GUTTER VARIABLE, DO NOT SET PADDING. Bootstrap 5 derives two things
   from `--bs-gutter-x`: the columns' horizontal padding, AND the row's own
   negative margins, which exist to cancel the first and last column's padding
   so the row still sits flush with its container. Hardcoding
   `padding-left/right` on the items changes only half of that pair — the row
   keeps its old -8px margins, the outer 16px no longer cancels, and the whole
   filter ends up indented 8px off the 1299px measure that the logo, nav and
   grid all align to. Changing the variable keeps the two in step.

   Safe to change even though GSAP positions the underline: the tween
   re-measures `.filter__item-label` from the live layout on every click, so
   this moves the text and the underline together. What is NOT safe is setting
   width/x/y here — see the header. */
.filter .row {
	--bs-gutter-x: 2rem !important;
}

/* VERTICAL, i.e. the gap between wrapped rows of items. Kinsey's 0.5em of
   padding per item, reduced by 70% to 0.15em as asked. `.filter__inner`
   carries matching negative margins upstream to cancel the first and last
   row's share, so both move together or the row sits off-centre. */
.filter .filter__item {
	padding-top: 0.15em !important;
	padding-bottom: 0.15em !important;
}

.filter .filter__inner {
	margin-top: -0.15em !important;
	margin-bottom: -0.15em !important;
}

/* `.block-counter` reserves 0.75em on the right for the counter, and that
   padding is applied whether or not a counter is actually rendered. With
   counters off it is just a dead gap that widens every item unevenly.

   Removed by default and given back only when a counter is really present, so
   this survives the Elementor toggle being switched either way. */
.filter .filter__item-inner.block-counter {
	padding-right: 0 !important;
}

.filter .filter__item-inner.block-counter:has(.block-counter__counter) {
	padding-right: 0.75em !important;
}


/* --- Underline -----------------------------------------------------------

   Colour and thickness only. Read the header above before touching this:
   width, x and y belong to GSAP.

   `margin-top` is the one piece of underline geometry GSAP does NOT write, so
   it is the knob. But it is NOT the gap you see, and reading it as one will
   waste your afternoon:

     GSAP sets y = label.offset().top - filter.offset().top — the TOP of the
     label. `margin-top` is then measured DOWN FROM THAT TOP, straight through
     the text. The visible gap is whatever is left over:

         visible gap  =  margin-top  -  distance from label top to glyph bottom

   The label box is taller than the letters — the line-height above plus all
   caps, which leave the descender space unused — so a good part of this value
   is spent crossing the type before any gap begins.

   25px IS AN INSPECTED VALUE, TAKEN FROM THE RUNNING PAGE IN DEVTOOLS. Do not
   "correct" it against a calculation or a static mock-up; both will be wrong,
   for a specific reason:

     Kinsey runs its split-text plugin on these items
     (`data-arts-split-text="lines, words"`), which REWRAPS the label content
     into generated `.split-line` / `.split-word` divs after the page loads.
     The element GSAP measures is therefore not the element in the page
     source, and its box is several pixels different. A mock-up without that
     JS measured this same design at 33px — 8px out.

   If this needs changing: change it in DevTools on a loaded page and read the
   number off. That is the only measurement that counts here.

   IN PIXELS, ON PURPOSE. Kinsey uses `2em`, but this element inherits its
   font-size from `body` (`font-size: 100%` = 16px), NOT from
   `.filter__item-inner`. Its `em` never responded to the type size at all —
   2em was a flat 32px whether the items were 18px or 12px.

   IT DOES NOT SCALE. Change the type size or the line-height above and this
   must be re-inspected. (Dropping the line-height by 5px moved the rule 1px.) */
.filter .filter__underline {
	background-color: var(--evm-ink-active) !important;
	height: 2px !important;
	margin-top: 25px !important;
}


/* --- Mobile dropdown -----------------------------------------------------

   Under 992px the widget swaps the row for a native <select>, per
   Filter -> Mobile Style -> Dropdown. Most of a select's appearance belongs
   to the OS; what is set here is the type, so the two modes do not read as
   different components.

   13px is not an arbitrary pick — it is the size of the discipline chips
   under each project card. Those chips are `.evm-chip` inside a `.small`
   wrapper, and Kinsey's `small` preset is fluid from 12px to 13px. Matching
   the top of that range makes the dropdown, the desktop filter row and the
   card chips one size, which is what stops the page reading as three
   different type systems.

   The wrapper's margin is separate from the select's own box: `d-lg-none`
   already removes this whole block on desktop, so the spacing below only
   ever applies where the dropdown actually exists. */
.filter .filter__wrapper-dropdown {
	margin-top: 24px !important;
}

.filter .js-filter__select {
	font-family: 'JetBrains Mono' !important;
	font-weight: 500 !important;
	font-size: 13px !important;
	text-transform: uppercase !important;
	letter-spacing: 0.1em !important;
	color: var(--evm-ink-active) !important;
}
