/* ---------------------------------------------------------------------
   Title "selected with the mouse" highlight — an inverted background/
   text bar that sweeps left-to-right (background-size 0% -> 100%, via a
   solid linear-gradient so the sweep can be animated at all — a plain
   background-color can't transition a "width") on every h1/h2/h3 across
   the site — except the home hero wordmark ([data-hero-word], not a
   heading tag anyway), journal.html's article titles ([data-journal-name],
   see the per-line group further down) and the nav logo (a <span>, never
   matched by these selectors to begin with). Text color transitions
   black->white on the SAME duration/easing as the bar itself, with no
   delay — it used to be an instant flip held back with a 0s-duration,
   fully-delayed transition until the bar had completely finished, which
   sounds right (never show white text ahead of the bar, on the bare
   page) but wasn't: the eased curve below front-loads most of its motion
   and then crawls the last stretch, so the bar visually finished
   covering the text — leaving black text sitting on an already-black
   bar, invisible — well before that instant fired. A same-timing color
   transition sidesteps the whole "which side do we get wrong" question:
   the text is always some shade of gray mid-sweep, readable against
   both the still-bare page ahead of the bar and the bar itself behind
   it, at every frame rather than only before or only after.

   Further down, the exact same mechanic is reused as the :hover/
   :focus-visible state for ordinary text links (sweeps in on hover,
   text flips white once the bar lands; on hover-out the text flips back
   instantly while the bar sweeps back out, so it's never white text
   sitting on a bare page background mid-retreat) — except the top-right
   nav menu, which needs a different trick entirely (see the [data-nav-hl]
   section at the bottom of this file, plus bindNavHighlight() in
   scripts/nm-site-logic.js) because it lives under mix-blend-mode:
   difference.

   The permanent (non-hover) elements above trigger their sweep off
   html.nm-ready — the same page-reveal class scripts/nm-transition.js
   adds to <html> once the loader/hero mask finishes (see e.g.
   `html.nm-ready [data-detail-mask]{animation:...}` in project.html) —
   so headings sweep in as part of that same reveal choreography instead
   of arriving pre-highlighted. Content rendered later — resume.json's
   work/gallery card grids, journal's article list — mounts after
   nm-ready has usually already fired, so those particular titles
   typically appear already fully swept rather than animating in — a
   CSS-only limitation, not a bug: they still end up correctly
   highlighted.

   Fully optional/disposable:
   - Turn off: set titleHighlight.enabled to false in
     settings/site-config.js (scripts/nm-site-logic.js's
     applyTitleHighlight() then drops the .nm-title-highlight class from
     <html> and this whole file goes inert — titles AND the link rollover
     below both revert to their plain look).
   - Remove entirely: delete this file, the <link> tag pulling it into
     each page (index/works/gallery/article/journal/contact/project.html),
     the TITLE_HIGHLIGHT block + titleHighlight line in
     settings/site-config.js, and applyTitleHighlight() + its call in
     scripts/nm-site-logic.js. The extra <span data-summary-text> wrapper
     in project.html around {{ detail.summary }} and the <span
     data-detail-meta-label> wrapper around {{ item.label }} can stay
     either way — they're inert without this CSS.
   --------------------------------------------------------------------- */
html.nm-title-highlight h1:not([data-hero-word]),
html.nm-title-highlight h2:not([data-journal-name]),
html.nm-title-highlight h3 {
  display: inline-block;
  width: fit-content;
  max-width: 100%;
  padding: 0.04em 0.14em;
  color: inherit;
  background-image: linear-gradient(var(--nm-title-hl-bg, #000000), var(--nm-title-hl-bg, #000000));
  background-repeat: no-repeat;
  background-position: left center;
  background-size: 0% 100%;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  transition: background-size var(--nm-reveal-ms, 900ms) var(--nm-reveal-ease, cubic-bezier(.22, 1, .36, 1)),
              color var(--nm-reveal-ms, 900ms) var(--nm-reveal-ease, cubic-bezier(.22, 1, .36, 1));
}
html.nm-ready.nm-title-highlight h1:not([data-hero-word]),
html.nm-ready.nm-title-highlight h2:not([data-journal-name]),
html.nm-ready.nm-title-highlight h3 {
  background-size: 100% 100%;
  color: var(--nm-title-hl-fg, #ffffff);
}

/* The intro paragraph wraps across several lines and stays centered via
   its parent <p>'s text-align — so unlike the single-line titles above,
   this targets an inline <span> (never blockified, fragments per line on
   its own) instead of inline-block+width:fit-content, which would draw one
   rectangle sized to the widest line instead of hugging each line. The
   meta grid labels ([data-detail-meta-label] — YEAR/CATEGORY/CLIENT/ROLE/
   TEAM, not the facts beside them) share this treatment for consistency,
   even though a short caption like that realistically never wraps.
   box-decoration-break:clone means every wrapped line gets its own cloned
   background layer, so the sweep plays out identically on each line at
   once rather than as one rectangle sized to the whole paragraph.

   [data-journal-name] (journal.html's article <h2>) and the project-card
   names — [data-work-name] on the home "Selected Work" track,
   [data-gallery-name] on gallery.html's grid — belong here for the same
   reason: that text runs long enough to wrap, and the h1/h2/h3 group
   above draws one rectangle sized to the widest line. On a wrapped
   title, a short second line could end up fully covered by the bar
   long before a longer first line was, reading as one line going dark
   well ahead of the other rather than both sweeping in together. Each
   wraps its text in an inner
   <span data-summary-text> — journal.html does it directly in markup;
   the card names do it via enhanceCard() in scripts/nm-signature-fx.js,
   since that's also where the hover hand-off lives (see the comment on
   [data-nm-card-title-inner] in nm-signature-fx.css). */
html.nm-title-highlight [data-summary-text],
html.nm-title-highlight [data-detail-meta-label] {
  padding: 0.04em 0.14em;
  color: inherit;
  background-image: linear-gradient(var(--nm-title-hl-bg, #000000), var(--nm-title-hl-bg, #000000));
  background-repeat: no-repeat;
  background-position: left center;
  background-size: 0% 100%;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  transition: background-size var(--nm-reveal-ms, 900ms) var(--nm-reveal-ease, cubic-bezier(.22, 1, .36, 1)),
              color var(--nm-reveal-ms, 900ms) var(--nm-reveal-ease, cubic-bezier(.22, 1, .36, 1));
}
html.nm-ready.nm-title-highlight [data-summary-text],
html.nm-ready.nm-title-highlight [data-detail-meta-label] {
  background-size: 100% 100%;
  color: var(--nm-title-hl-fg, #ffffff);
}

/* ---------------------------------------------------------------------
   Link rollover — the same left-to-right sweep, triggered by :hover/
   :focus-visible instead of html.nm-ready, and quicker (a hover
   micro-interaction, not a page-reveal beat). Unlike the permanent
   elements above, color flips instantly in BOTH directions here (0s,
   no delay) rather than waiting for the bar to finish sweeping — a
   deliberate choice for this hover micro-interaction, even though it
   means the text is briefly white ahead of the bar's leading edge.
   The opacity:1 (plus the extra specificity from the two leading
   selectors) is what beats each page's plain a:hover{opacity:.6} rule
   instead of just stacking a dim on top of the highlight bar.

   Excluded below and left on their ordinary opacity hover: the top nav
   and mobile fullscreen menu ([data-nav], [data-mobile-menu] — sit on
   mix-blend-mode:difference/already-black surfaces where a solid bar
   would either fight the blend trick or be invisible), project.html's
   own difference-blend hero controls ([data-detail-back],
   [data-detail-scroll], [data-project-switcher]), and every card-style
   link that wraps a thumbnail image ([data-card] on the home page,
   [data-work-card] on works.html, [data-gallery-card] on gallery.html,
   [data-journal-row] on journal.html) — those already carry their own
   permanent title-highlight on the name/heading inside (see above), so
   sweeping a bar across the whole card would double up and paint behind
   the image too. [data-detail-back] and [data-detail-scroll] are also
   excluded from the PERMANENT (non-hover) rule above, not just this
   hover one — their own color:#fff is load-bearing for the
   mix-blend-mode:difference trick against the hero, and the permanent
   rule's color:inherit would otherwise win on specificity and paint
   them black, invisible against a dark hero. [data-project-switcher] a
   needs no such exclusion up there since its own color/blend-mode are
   already !important. Opt any other individual link out with
   data-no-link-highlight. */
html.nm-title-highlight a:not([data-detail-back]):not([data-detail-scroll]) {
  color: inherit;
  background-image: linear-gradient(var(--nm-title-hl-bg, #000000), var(--nm-title-hl-bg, #000000));
  background-repeat: no-repeat;
  background-position: left center;
  background-size: 0% 100%;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  transition: background-size 0.28s var(--nm-reveal-ease, cubic-bezier(.22, 1, .36, 1)),
              color 0s linear 0s;
}
html.nm-title-highlight a:hover,
html.nm-title-highlight a:focus-visible {
  background-size: 100% 100%;
  /* !important: a lot of links across the site carry their own inline
     style="...;color:inherit;..." (footer/CTA/card links etc.) — an
     inline style always wins over any selector-based rule regardless of
     specificity, so without !important this color never actually
     applied and the swept-in bar just sat there with the original
     (usually black) text on top of it, unreadable. */
  color: var(--nm-title-hl-fg, #ffffff) !important;
  opacity: 1;
  transition: background-size 0.28s var(--nm-reveal-ease, cubic-bezier(.22, 1, .36, 1)),
              color 0s linear 0s;
}

html.nm-title-highlight [data-nav] a:hover,
html.nm-title-highlight [data-nav] a:focus-visible,
html.nm-title-highlight [data-mobile-menu] a:hover,
html.nm-title-highlight [data-mobile-menu] a:focus-visible,
html.nm-title-highlight [data-detail-back]:hover,
html.nm-title-highlight [data-detail-back]:focus-visible,
html.nm-title-highlight [data-detail-scroll]:hover,
html.nm-title-highlight [data-detail-scroll]:focus-visible,
html.nm-title-highlight [data-project-switcher] a:hover,
html.nm-title-highlight [data-project-switcher] a:focus-visible,
html.nm-title-highlight [data-card]:hover,
html.nm-title-highlight [data-card]:focus-visible,
html.nm-title-highlight [data-work-card]:hover,
html.nm-title-highlight [data-work-card]:focus-visible,
html.nm-title-highlight [data-gallery-card]:hover,
html.nm-title-highlight [data-gallery-card]:focus-visible,
html.nm-title-highlight [data-journal-row]:hover,
html.nm-title-highlight [data-journal-row]:focus-visible,
html.nm-title-highlight a[data-no-link-highlight]:hover,
html.nm-title-highlight a[data-no-link-highlight]:focus-visible {
  background-size: 0% 100%;
  color: inherit;
}

/* ---------------------------------------------------------------------
   Top-right nav menu highlight — [data-nav] sits under mix-blend-mode:
   difference (so its rendered pixels auto-invert against whatever
   scrolls underneath the fixed bar), and that blending is computed on
   nav's ENTIRE composited subtree as one flattened image. A regular
   solid black/white box painted *inside* that subtree would get
   differenced right along with it — against a white section that turns
   into a white box with white text, invisible. There's no way to opt a
   descendant back out of an ancestor's blend-mode from CSS alone (its
   own mix-blend-mode only ever governs blending against siblings within
   the same isolated group, not the group's own blend against the page).

   So this one small box is a genuine DOM sibling of [data-nav] instead
   (appended to <body>, see bindNavHighlight() in scripts/nm-site-logic.js),
   painted after nav in a later paint pass with no blend mode of its own —
   a solid black/white rectangle regardless of what's behind the bar.
   JS tracks the hovered/focused link in [data-navlinks] and positions
   this one shared element over it (position:fixed, same viewport
   coordinates as the link's own getBoundingClientRect() — nav is fixed
   too, so no scroll-offset math needed). overflow:hidden plus animating
   width (not background-size) is what gives the left-to-right reveal
   here: the white text sits there from the start, and simply becomes
   visible as the box's right edge sweeps past it — no separate delayed
   color flip required, unlike the box-decoration-break elements above.

   (Briefly tried a bottom-up/height version instead, to read more
   distinctly from nav punch's permanent underline reappearing once the
   box retracts — reverted: anchoring the box by its bottom edge while
   bottom-aligning the text put the text visibly lower than the real
   link underneath during the reveal, an offset the width version never
   had. Back to matching the left-to-right sweep every other link on the
   site already uses.) */
[data-nav-hl] {
  position: fixed;
  z-index: 125;
  top: 0;
  left: 0;
  width: 0;
  visibility: hidden;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  white-space: nowrap;
  pointer-events: none;
  background: var(--nm-title-hl-bg, #000000);
  color: var(--nm-title-hl-fg, #ffffff);
  transition: width 0.28s var(--nm-reveal-ease, cubic-bezier(.22, 1, .36, 1));
}
