/* Tư-Trà Nav v5.85.0 — structural, class-scoped */
/* Header hold sentinels (v5.2.1). Injected by bootHold into the element AFTER
   each .tt-header-hold section — the one that actually scrolls. v5.2.0 put
   them inside the hold section itself and that broke the sticky retrofit: a
   hold div set to position sticky keeps its box pinned in viewport
   coordinates, so nothing absolutely positioned inside it ever crosses the
   line, engage never released, and the header stayed at full size forever.
   The sliding sibling is the only element whose motion tracks the release.
   Position is DECLARED, never measured. Each sentinel top edge sits ABOVE the
   host top by its threshold, so the moment that edge crosses the viewport top
   is the moment the host top reaches the threshold: offset minus band for the
   release sentinel, offset plus band for the engage one.
   Both are tall on purpose. The observer reports a state change when a
   sentinel edge crosses the viewport top edge, and only a tall target
   guarantees that change is seen at momentum-scroll velocity — a short marker
   gets jumped whole in a single frame.
   Caveat on the record: the overhang above the host top is clipped when the
   host sets overflow hidden. The decision reads the rect sign rather than the
   intersection flag, so a clipped host delays a wakeup by at most offset plus
   band px of scroll; it cannot invert the state. */
.tt-el-nv-hold-host {
	position: relative;
}
.tt-el-nv-hold-sentinel {
	position: absolute;
	left: 0;
	width: 1px;
	height: 60vh;
	pointer-events: none;
}
.tt-el-nv-hold-sentinel-release {
	top: calc(var(--tt-el-nv-hold-band, 6px) - var(--tt-el-nv-hold-offset, 40px));
}
.tt-el-nv-hold-sentinel-engage {
	top: calc(0px - var(--tt-el-nv-hold-offset, 40px) - var(--tt-el-nv-hold-band, 6px));
}
.tt-el-nv-wrap {
	position: relative;
	display: flex;
	flex-direction: row;
	align-items: center;
	width: 100%;
	box-sizing: border-box;
	--tt-el-nv-ind-x: 0px;
	--tt-el-nv-ind-y: 0px;
	--tt-el-nv-ind-w: 0px;
	--tt-el-nv-ind-o: 0;
	--tt-el-nv-ind-h: 1px;
	--tt-el-nv-ind-speed: 450ms;
	--tt-el-nv-shift-x: 0px;
	--tt-el-nv-logo-h: 3rem;
	color: var(--tt-el-nv-color, currentColor);
}
/* Background layer — sits behind the nav content. The eased gradient is
   applied inline (generated per-instance from the easing curve). This is the
   foundation for the future progressive-blur (::before/::after backdrop-filter
   stack) and scroll-state fade — both layer onto .tt-el-nv-bg without touching
   the flex content. Content (sides, menu, indicator) is raised above it. */
.tt-el-nv-wrap .tt-el-nv-bg {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	z-index: 1;
	pointer-events: none;
	user-select: none;
	-webkit-user-select: none;
	/* Adaptive tint: transparent (image) sections set --tt-el-nv-tint-bg-opacity
	   to 0 so the backdrop gradient fades out and the image shows through. The
	   var is unset (defaults to 1) when tint is off or no transparent section is
	   active, so this is a no-op then. */
	opacity: var(--tt-el-nv-tint-bg-opacity, 1);
	transition: opacity 600ms cubic-bezier(.4, 0, .2, 1);
}
/* v5.16.0 — COMPOSITE TINT FILLS. Two identical gradient layers inside
   .tt-el-nv-bg; only their local --tt-el-nv-tint-color differs. A tint change
   paints the idle layer once, then cross-fades the pair on OPACITY, which the
   compositor animates without the main thread — background-color never can be.
   The two nested opacities (box tint-bg-opacity x fill crossfade) multiply,
   and both are composited, so the transparent-section fade still works.
   will-change:opacity keeps each fill on its own layer so the crossfade never
   forces a re-rasterization of the gradient. */
.tt-el-nv-wrap .tt-el-nv-bg-fill {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	pointer-events: none;
	will-change: opacity;
	-webkit-backface-visibility: hidden;
	backface-visibility: hidden;
	transition: opacity var(--tt-el-nv-tint-fade, 600ms) cubic-bezier(.4, 0, .2, 1);
}
/* Fill A is the resting layer, B the incoming one. JS swaps which is which by
   writing inline opacity; these are only the initial states. */
.tt-el-nv-wrap .tt-el-nv-bg-fill--a { opacity: 1; }
.tt-el-nv-wrap .tt-el-nv-bg-fill--b { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
	.tt-el-nv-wrap .tt-el-nv-bg-fill { transition-duration: 1ms; }
}
/* Progressive blur layer — sits BELOW the gradient (lower z-index), blurring
   the page content scrolling under the nav. Forked from the progressive-blur
   kit: stacked backdrop-filter layers, each masked to a vertical band, ramping
   heavy→light top to bottom. GPU wins kept: half-resolution rendering
   (200% size + scale(.5) ≈ 4x cheaper fill), per-layer compositor promotion,
   strict containment. */
.tt-el-nv-wrap .tt-el-nv-bg-blur {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	z-index: 0;
	pointer-events: none;
	user-select: none;
	-webkit-user-select: none;
	contain: strict;
	isolation: isolate;
}
.tt-el-nv-wrap .tt-el-nv-bg-blur-layer {
	position: absolute;
	/* Half-resolution trick: 200% box scaled to 0.5 -> blur rasterizes at 1/4
	   the pixels. Invisible because the output is already blurred. inset:-50%
	   counteracts the scale offset. This scale(0.5) ALSO promotes each layer to
	   its own GPU compositor surface -- the same stabilization the demo
	   translateZ(0) flicker-fix provided, so the heaviest layer does not re-
	   rasterize per scroll frame. (We keep half-res rather than swapping to
	   translateZ: per the GPU analysis it renders the proven Silas geometry at 1/4
	   the fill cost -- clean AND cheap.)
	   em NOTE: the blur radii are em-based; em resolves against the layer
	   font-size, which inherits from .tt-el-nv-wrap (the nav) and therefore scroll-
	   shrinks with the header. */
	top: -50%;
	left: -50%;
	width: 200%;
	height: 200%;
	transform: scale(0.5) translateZ(0);
	transform-origin: center center;
	pointer-events: none;
	will-change: backdrop-filter, transform;
	-webkit-backface-visibility: hidden;
	backface-visibility: hidden;
}
@media (prefers-reduced-motion: reduce) {
	.tt-el-nv-wrap .tt-el-nv-bg-blur-layer {
		backdrop-filter: none !important;
		-webkit-backdrop-filter: none !important;
	}
}
/* ============ v5.17.0 COMPOSITE SHRINK ============
   When data-tt-shrink-composite="1" the layout properties stop animating
   entirely and the shrink becomes transform-only, so the compositor owns it
   and the measured header box never changes size. transition-property is
   swapped rather than duration-zeroed, so a stylesheet-declared
   --tt-el-nv-scroll-dur still controls the timing in both modes.
   transform-origin choices: the bg stack scales from its top edge (the
   header hangs from the top), type scales about its own inline start so the
   menu does not drift sideways, and the logo scales about its centre because
   it is centred in the bar. */
/* RESTING IDENTITY. scale/translate default to the keyword `none`, and a
   transition from `none` to a number is not reliably interpolated in WebKit —
   it lands discretely, which is exactly the A-to-B jump v5.17.1 showed. Both
   endpoints must be numeric, so the rest state is declared explicitly. */
/* One shared anchor line: the top of the nav content. The menu is the tallest
   child, so its own top edge IS that line. The side sits lower by a fixed
   layout offset, so its origin is lifted by exactly that offset and it scales
   about the same line. Nothing translates, so nothing can travel-then-resize:
   the top edge is invariant and size is the only animated quantity. */
.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-menu {
	scale: 1;
	translate: 0 0;
	transform-origin: center center;
	/* v5.26.0 — REAL layer promotion, the way the stage gets it. will-change:
	   scale is not a reliable promotion trigger in WebKit: its heuristics key
	   on transform, opacity and filter, not on the independent scale property.
	   The logo stage has carried transform: translateZ(0) since v4.15.4 and is
	   the one subject that has always animated cleanly on iOS. The menu had
	   only the will-change hint, so its scale was running off the main thread
	   in name only. translateZ(0) composes with the existing centring shift,
	   and transform is not animated on this element, so it is free to hold it. */
	transform: translateX(var(--tt-el-nv-shift-x, 0px)) translateZ(0);
	will-change: transform;
	backface-visibility: hidden;
	-webkit-backface-visibility: hidden;
}
/* The side slots hug their content and are anchored to the outer edge of
   their column (--left is justify-content:flex-start, --right is flex-end).
   Scaling about 50% would pull that content inward toward the slot centre as
   it shrinks, which is what broke the horizontal alignment. The X origin must
   be the edge the slot is anchored to, so the outer edge stays put and the
   box shrinks inward exactly as the layout engine narrows it. */
.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-side {
	scale: 1;
	translate: 0 0;
	transform-origin: center center;
	/* The side animates `transform` for its reveal, so it cannot hold a fixed
	   translateZ(0) without fighting the hidden-state offset. will-change:
	   transform promotes reliably in WebKit and leaves the reveal intact. */
	will-change: transform;
	backface-visibility: hidden;
	-webkit-backface-visibility: hidden;
}
.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-side--left {
	transform-origin: left center;
}
.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-side--right {
	transform-origin: right center;
}
/* v5.27.0 — PER-ITEM LAYER PROMOTION, the stage recipe applied to every item.
   v5.21.0 added scale to the winning !important list on .tt-el-nv-menu, which
   is the parent of BOTH the nav items and the logo, so all three began
   transitioning in the same release and only the logo came out clean. What
   separates them therefore has to be something the logo already had, not
   something the transition gave it. It is the promoted layer: when an ancestor
   scales a promoted descendant, the compositor transforms that finished layer
   instead of re-rasterising its contents. The nav text had no layer of its
   own, so every frame of the menu scale re-rastered the menu layer and all of
   its glyphs on the main thread.
   Each item now gets exactly what the stage has carried since v4.15.4. The
   logo li is excluded: the stage inside it is already promoted.
   No geometry changes. translateZ(0) is a no-op transform, the scale still
   lives on the menu, spacing and gaps are untouched. */
.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-menu > li:not(.tt-el-nv-logo-li),
.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-side > * {
	transform: translateZ(0);
	backface-visibility: hidden;
	-webkit-backface-visibility: hidden;
}
/* v5.28.0 — SCALE-ONLY TRANSITION ON THE REVEALED SIDE.
   The side is the only subject that runs its scale on an element also carrying
   live transition state for transform, visibility, opacity and font-size — five
   terms across three durations. None of those change during a scroll; they
   exist for the reveal and the collapse. But WebKit keeps transition state for
   all of them on a layer it is scaling every frame, and the side is the only
   place that happens. The logo stage runs one term, the menu three, and both
   are clean.
   Once .tt-el-nv-side-revealed is on, the reveal is finished and the only
   property that ever changes on this element is scale, so the revealed state
   gets a single-term list matching the stage. The unrevealed state keeps the
   full list, so collapse still animates.
   TRADE-OFF, stated plainly: the reveal itself now resolves against the
   scale-only list, so the side appears without its 220ms fade on first load.
   That is a one-time load animation, not a scroll one. Say the word and it
   comes back on a separate carrier. */
.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-side.tt-el-nv-side-revealed {
	transition: scale var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease-in-out),
		translate var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease-in-out);
}
/* v5.40.0 — rAF TRANSITION SUPPRESSION, IN THE STYLESHEET.
   The trace showed the menu cancelling and restarting its scale and translate
   transitions every ~17ms for an entire run — every inline write from the rAF
   loop restarted a CSS transition that was still live, roughly 100 transition
   events per shrink on the main thread. SIZE SOURCE confirmed why: the menu
   computed transition-property still read [opacity, font-size, scale,
   translate], so the inline transition-property !important written by
   rafSuppressTransitions never took effect.
   Rather than chase why an inline longhand lost, the suppression moves into
   the stylesheet, where .tt-el-nv-raf (added to the root at boot whenever the
   rAF engine is active) makes it deterministic. Each rule repeats the terms
   that must survive — the reveal, the collapse, the tint crossfade — and drops
   only scale and translate, which rAF now owns.
   The inline version is kept as a belt-and-braces; it costs nothing. */
.tt-el-nv-wrap.tt-el-nv-raf.tt-el-nv-revealed .tt-el-nv-menu {
	transition:
		opacity 150ms ease-out,
		font-size var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease) !important;
}
.tt-el-nv-wrap.tt-el-nv-raf .tt-el-nv-menu {
	transition:
		opacity 150ms ease-out,
		font-size var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease) !important;
}
.tt-el-nv-wrap.tt-el-nv-raf .tt-el-nv-side {
	transition:
		opacity var(--tt-el-nv-collapse-dur, 0.22s) var(--tt-el-nv-collapse-ease, ease),
		transform var(--tt-el-nv-collapse-dur, 0.22s) var(--tt-el-nv-collapse-ease, ease),
		visibility 0s linear var(--tt-el-nv-collapse-dur, 0.22s),
		font-size var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease) !important;
}
.tt-el-nv-wrap.tt-el-nv-raf .tt-el-nv-logo-link,
.tt-el-nv-wrap.tt-el-nv-raf .tt-el-nv-logo-stage {
	transition: none !important;
}
.tt-el-nv-wrap.tt-el-nv-raf .tt-el-nv-bg,
.tt-el-nv-wrap.tt-el-nv-raf .tt-el-nv-bg-blur {
	transition: opacity 600ms ease !important;
}
/* v5.41.0 — the composite bar may legitimately hold a menu that fits at the
   shrunk scale but not in layout (that is how the shrunk bar expands a menu
   the full bar had to cramp). The scale draws it inside the wrap; the layout
   still overflows. overflow-x: clip stops that overflow widening the document,
   and unlike hidden it creates no scroll container, so sticky/fixed
   positioning and the vertical axis are untouched. */
.tt-el-nv-wrap[data-tt-shrink-composite="1"] {
	overflow-x: clip;
}
.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-logo-link {
	scale: 1;
	transform-origin: center center;
	/* No will-change here: the stage is ALREADY promoted by its translateZ(0),
	   and a second promotion hint on the same box gains nothing. */
}
.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-bg,
.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-bg-blur {
	scale: 1;
	transform-origin: top center;
	will-change: scale;
}
/* TRANSITION LISTS. These carry .tt-el-nv-anim so they are 0-4-0 and beat the
   0-3-0 .tt-el-nv-anim rules further down the sheet regardless of source
   order — equal specificity plus later source is what silently dropped the
   scale term in v5.17.1.
   Every existing term is REPEATED here, not just the new ones: a shorthand at
   winning specificity REPLACES the list, and dropping a sibling term is the
   v5.4.0 side-reveal bug and the v5.9.2 menu-reveal bug both over again. */
.tt-el-nv-wrap.tt-el-nv-anim[data-tt-shrink-composite="1"] .tt-el-nv-menu {
	transition:
		font-size var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease-in-out),
		scale var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease-in-out),
		translate var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease-in-out);
}
.tt-el-nv-wrap.tt-el-nv-anim[data-tt-shrink-composite="1"] .tt-el-nv-side {
	transition:
		opacity var(--tt-el-nv-collapse-dur, 0.22s) var(--tt-el-nv-collapse-ease, ease),
		transform var(--tt-el-nv-collapse-dur, 0.22s) var(--tt-el-nv-collapse-ease, ease),
		visibility 0s linear var(--tt-el-nv-collapse-dur, 0.22s),
		font-size var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease-in-out),
		scale var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease-in-out),
		translate var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease-in-out);
}
.tt-el-nv-wrap.tt-el-nv-anim[data-tt-shrink-composite="1"] .tt-el-nv-logo-link {
	transition: scale var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease-in-out);
}
.tt-el-nv-wrap.tt-el-nv-anim[data-tt-shrink-composite="1"] .tt-el-nv-bg,
.tt-el-nv-wrap.tt-el-nv-anim[data-tt-shrink-composite="1"] .tt-el-nv-bg-blur {
	transition:
		opacity 600ms cubic-bezier(.4, 0, .2, 1),
		scale var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease-in-out);
}
/* v5.17.6 — THE MEASURING PASS NO LONGER TOUCHES THE COMPOSITE PROPERTIES.
   There is deliberately no rule here.

   The layout engine needs this guard because font-size and height ARE layout
   inputs, so a measure pass taken mid-transition would read a half-shrunk box.
   scale and translate are not layout inputs — they change a post-layout
   mapping — so offsetWidth, offsetHeight and offsetLeft are already identical
   whether the header is scaled or not. v5.17.3 established exactly that, then
   kept `transition: none !important` anyway "matching what measuring does
   elsewhere". That was the bug.

   Setting transition:none on an element with a RUNNING transition does not
   pause it: it cancels it, and the property snaps to its computed end value
   in that same frame. measureNatural runs several times per shrink, so every
   pass snapped scale and translate straight to their endpoints. Two symptoms
   fell out of it:
     - the logo jumping to its final position and only then scaling. Up to
       v5.17.5 this guard still named .tt-el-nv-logo-svg, stale since v5.17.4
       moved the scale onto the stage — so the menu translate was snapped
       while the stage scale was left running. Position instant, size
       animated: precisely the reported artefact.
     - the whole shrink finishing well short of --tt-el-nv-scroll-dur, because
       a transition cancelled and restarted several times never runs its
       configured duration. That is the "too fast" report, same single cause.

   Nothing replaces it. If some future measurement genuinely needs untransformed
   geometry it must read layout metrics or divide by the known ratio, never
   cancel a running animation to get it. */
@media (prefers-reduced-motion: reduce) {
	.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-menu,
	.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-side,
	.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-logo-link,
	.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-bg,
	.tt-el-nv-wrap[data-tt-shrink-composite="1"] .tt-el-nv-bg-blur {
		transition-duration: 1ms;
	}
}
.tt-el-nv-wrap .tt-el-nv-side,
.tt-el-nv-wrap .tt-el-nv-menu {
	position: relative;
	z-index: 2;
}
.tt-el-nv-wrap .tt-el-nv-indicator {
	z-index: 3;
}
/* Side slots (nestable) flank the center menu. CSS order positions them
   regardless of DOM order: left (0), menu (1), right (2). Sides hug their
   content and stay anchored; only the MENU is translated to center the logo,
   so shifting the logo never drags the sides off-screen.

   Inner content aligns to the OUTER edge: left side → left, right side →
   right, both vertically centered. Sides receive the same item padding as
   the menu items so the whole nav shares one spacing rhythm. */
.tt-el-nv-wrap .tt-el-nv-side {
	display: flex;
	flex-direction: row;
	align-items: center;
	flex: 0 0 auto;
	width: auto;
	max-width: max-content;
}
.tt-el-nv-wrap .tt-el-nv-side--left {
	order: 0;
	justify-content: flex-start;
}
.tt-el-nv-wrap .tt-el-nv-menu        { order: 1; }
.tt-el-nv-wrap .tt-el-nv-side--right {
	order: 2;
	justify-content: flex-end;
}

/* ── Action zone (nestable) ──────────────────────────────────────
   A third flex sibling holding dropped action buttons. Positioned by
   flex order relative to the menu via the data-tt-actions-anchor on the
   root. The logo is centered WITHIN the menu, so before/after-menu sit
   the buttons just left/right of the centered group. Hugs its content
   like the side slots; never translated, so centering never drags it. */
.tt-el-nv-wrap {
	--tt-el-nv-actions-gap: 13px;
	--tt-el-nv-action-badge-bg: #b8945f;
	--tt-el-nv-action-badge-fg: #fffaf0;
}
.tt-el-nv-wrap .tt-el-nv-actions {
	display: flex;
	flex-direction: row;
	align-items: center;
	gap: var(--tt-el-nv-actions-gap, 13px);
	flex: 0 0 auto;
	width: auto;
	max-width: max-content;
}
/* Anchor → flex order. Base layout is: left side 0, menu 1, right side 2.
   Each anchor slots the action zone into that order without disturbing the
   others, except before-menu/after-menu which renumber the menu and right
   side so the zone sits cleanly beside the centered menu group. */
/* far-left: before everything. */
.tt-el-nv-wrap[data-tt-actions-anchor="far-left"]  .tt-el-nv-actions     { order: -1; }
/* far-right: after everything. */
.tt-el-nv-wrap[data-tt-actions-anchor="far-right"] .tt-el-nv-actions     { order: 3; }
/* before-menu: left-side(0) · zone(1) · menu(2) · right-side(3). */
.tt-el-nv-wrap[data-tt-actions-anchor="before-menu"] .tt-el-nv-actions   { order: 1; }
.tt-el-nv-wrap[data-tt-actions-anchor="before-menu"] .tt-el-nv-menu      { order: 2; }
.tt-el-nv-wrap[data-tt-actions-anchor="before-menu"] .tt-el-nv-side--right { order: 3; }
/* after-menu (default): left-side(0) · menu(1) · zone(2) · right-side(3). */
.tt-el-nv-wrap[data-tt-actions-anchor="after-menu"] .tt-el-nv-actions    { order: 2; }
.tt-el-nv-wrap[data-tt-actions-anchor="after-menu"] .tt-el-nv-side--right { order: 3; }
/* Hidden entirely when disabled. */
/* v5.12.0 — CONTENT OFFSET, absorbed from the Content Offset kit and renamed
   into the naming scheme of this element. Put .tt-el-nv-offset on the first
   section of a page and it clears the overlaying header. Padding rather than
   margin, so the background of that section still starts at the top of the
   viewport and the header has something to be translucent over.
   --tt-el-nv-header-h is the TALLEST height the header reaches in the current
   layout, not its live height. The padding is set once and the header animates
   over the top of it. Publishing the live height instead was tried in v5.12.0
   and looked terrible: the page crept upward for the whole 600ms.
   .tt-body-offset-padding is the old class from that kit, kept so live pages
   survive it being deactivated. Move sections over and drop it. */
.tt-el-nv-offset,
.tt-body-offset-padding {
	padding-top: var(--tt-el-nv-header-h, 0px);
}

/* v5.9.0 — the action children appear as menu items or not at all. With
   relocation off the row used to sit on the right; it is hidden outright now.
   With relocation on, the JS hides the emptied zone itself after moving the
   children, so this covers the other half. Keyed on the existing control
   attribute, so the builder still drives it. */
.tt-el-nv-wrap:not([data-tt-actions-in-menu="1"]) .tt-el-nv-actions {
	display: none !important;
}
.tt-el-nv-wrap[data-tt-actions="0"] .tt-el-nv-actions { display: none !important; }

/* Action button base — applies to whatever is dropped (button, link, icon). */
/* Unified color + size for the actions ZONE itself (v5.0.5). Until now the
   unified treatment lived only on the RELOCATED form (li.tt-el-nv-act-li),
   which exists only after the frontend JS moves the buttons into the menu — so
   in the BUILDER canvas (no relocation runs there) and with flow-into-menu off,
   action buttons fell back to UA styles and looked detached from the menu
   words. Mirror the same variable consumption here (the variables are the
   single integration surface, handbook I.3). On the frontend with flow on, the
   zone is emptied by relocation and these rules are inert. Known limitation,
   deliberate: the zone is NOT added to the scroll-shrink state lists — the
   builder never scrolls, the zone is empty on the frontend when flow is on,
   and the planned action-flow bake-in retires the zone-resident state. */
.tt-el-nv-wrap .tt-el-nv-actions {
	color: var(--tt-el-nv-color, var(--tt-header-fg, currentColor));
	font-size: var(--tt-el-nv-size, inherit);
}
.tt-el-nv-wrap .tt-el-nv-actions > * {
	display: inline-flex;
	align-items: center;
	position: relative;
	color: inherit;
	font: inherit;
	font-size: inherit;
	background: none;
	border: none;
	padding: 0;
	margin: 0;
	line-height: inherit;
	cursor: pointer;
}
.tt-el-nv-wrap .tt-el-nv-actions svg,
.tt-el-nv-wrap .tt-el-nv-actions i,
.tt-el-nv-wrap .tt-el-nv-actions [class*="icon"] {
	width: 1em;
	height: 1em;
	font-size: inherit;
	color: inherit;
	fill: currentColor;
	stroke: currentColor;
}

/* Cart badge — a count bubble on a button marked tt-el-nv-act--cart. The JS
   injects a .tt-el-nv-action-badge span and writes data-count. Hidden at zero
   when data-tt-badge-hide-zero is on. */
.tt-el-nv-wrap .tt-el-nv-act--cart {
	position: relative;
	overflow: visible;
}
.tt-el-nv-wrap .tt-el-nv-action-badge {
	position: absolute;
	top: -0.4em;
	right: -0.6em;
	min-width: 1.5em;
	height: 1.5em;
	padding: 0 0.35em;
	box-sizing: border-box;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border-radius: 999px;
	background: var(--tt-el-nv-action-badge-bg, #b8945f);
	color: var(--tt-el-nv-action-badge-fg, #fffaf0);
	font-size: 0.6em;
	font-weight: 600;
	line-height: 1;
	font-variant-numeric: tabular-nums;
	pointer-events: none;
	transform: translateZ(0);
}
.tt-el-nv-wrap[data-tt-badge-hide-zero="1"] .tt-el-nv-action-badge[data-count="0"] { display: none; }

/* Search marker — the toggle button. The search BAR itself is the
   element/template the user supplies (we just toggle a class on it).
   aria-expanded carries state. */
.tt-el-nv-wrap .tt-el-nv-act--search { cursor: pointer; }
/* Relocated action items (v4.13.0): when "flow into menu" is on, each action
   button is moved into the menu <ul> as an <li class="tt-el-nv-act-li">. These
   rules make it sit as a clean menu cell — centered content, no list marker,
   and explicitly NOT eligible for the active-item underline/indicator (it is a
   control, not a page link). The existing .tt-el-nv-menu > li gap/padding apply
   automatically since it is a real <li> in the list. */
.tt-el-nv-wrap .tt-el-nv-menu > li.tt-el-nv-act-li {
	display: inline-flex;
	align-items: center;
	list-style: none;
	/* Unified color + size (v4.13.3): read the SAME variables the menu links
	   consume (.tt-el-nv-menu > li > a), so the action toggles flip color with the
	   adaptive tint engine (--tt-el-nv-color) and scale with the Size control +
	   scroll-shrink (--tt-el-nv-size) exactly like the words HOME / MENU / etc.
	   Before this they fell back to their own inherited color/size and looked
	   detached. The variable chain is the single integration surface (§I.3). */
	color: var(--tt-el-nv-color, var(--tt-header-fg, currentColor));
	/* v5.7.0 — see the menu link note: inherit must carry !important to beat
	   the direct ID-specificity control rule. */
	font-size: inherit !important;
}
.tt-el-nv-wrap .tt-el-nv-menu > li.tt-el-nv-act-li > * {
	display: inline-flex;
	align-items: center;
	/* Inherit the unified color + size from the <li> onto the button/link itself
	   (and anything Bricks rendered inside), so a <button>/<a> with its own UA
	   color does not override the menu foreground. */
	color: inherit;
	font: inherit;
	font-size: inherit;
	background: none;
	border: none;
	padding: 0;
	margin: 0;
	line-height: inherit;
	cursor: pointer;
}
/* Icons (SVG or icon-font) inside an action item scale to the text size — 1em —
   and take the unified foreground via currentColor, so a search glyph matches the
   cap height and color of the menu words next to it. */
.tt-el-nv-wrap .tt-el-nv-menu > li.tt-el-nv-act-li svg,
.tt-el-nv-wrap .tt-el-nv-menu > li.tt-el-nv-act-li i,
.tt-el-nv-wrap .tt-el-nv-menu > li.tt-el-nv-act-li [class*="icon"] {
	width: 1em;
	height: 1em;
	font-size: inherit;
	color: inherit;
	fill: currentColor;
	stroke: currentColor;
}

/* ── Smart collapse (forked from smart-header-nav-collapse v2.3.0) ──
   States the JS state machine sets on the nav root, root-scoped:
     .tt-el-nv-hiding   — items fading out (uniform opacity, no transforms)
     .tt-el-nv-cramped  — collapsed at rest (items out of flow)
     .tt-el-nv-showing  — items re-entered flow invisible, transitions off
     .tt-el-nv-measuring— transitions killed for the strip-measure window
   Duration token --tt-el-nv-collapse-dur (forked --tt-header-nav-dur). */
.tt-el-nv-wrap {
	--tt-el-nv-collapse-dur: 0.22s;
	--tt-el-nv-collapse-ease: cubic-bezier(.2,.8,.2,1);
}
.tt-el-nv-wrap .tt-el-nv-menu {
	overflow: hidden;
}
/* Logo cutoff fix (v4.11.0): the menu overflow:hidden was clipping a tall
   logo (the logo is taller than the menu row by design). The per-item ellipsis
   lives on each link (.tt-el-nv-menu > li > a { overflow:hidden;text-overflow }),
   and collapse moves items off-screen (left:-9999px), not via this clip — so the
   menu-level clip serves no purpose except cutting the logo. When the
   logo-overflow feature is on, let the menu show overflow. Freeing the logo li
   alone did nothing because the CLIP is on the menu (the parent of the li), and a
   child overflow value cannot un-clip its parent. */
.tt-el-nv-wrap.tt-el-nv-logo-overflow .tt-el-nv-menu {
	overflow: visible;
}
.tt-el-nv-wrap .tt-el-nv-menu > li:not(.tt-el-nv-logo-li) {
	opacity: 1;
	pointer-events: auto;
	position: static;
	transition: opacity var(--tt-el-nv-collapse-dur, 0.22s) var(--tt-el-nv-collapse-ease, ease);
}
/* Logo always visible regardless of phase */
.tt-el-nv-wrap .tt-el-nv-menu > li.tt-el-nv-logo-li {
	opacity: 1 !important;
	position: static !important;
	pointer-events: auto !important;
}
/* Legacy menu-baked logo slot (.tt-header-nav-logo) from the kit-era header
   renders as an empty <a> here since the element injects its own logo. Hide it
   so it does not occupy a menu cell or catch clicks. The kit-era search item is
   left visible (it may be a real control); only the empty logo slot is hidden. */
.tt-el-nv-wrap .tt-el-nv-menu > li.tt-header-nav-logo,
.tt-el-nv-wrap .tt-el-nv-menu > li.header-nav-logo {
	display: none !important;
}
/* Phase: hiding — uniform fade out */
.tt-el-nv-wrap.tt-el-nv-hiding .tt-el-nv-menu > li:not(.tt-el-nv-logo-li) {
	opacity: 0;
	pointer-events: none;
}
/* Phase: cramped — items out of flow, logo recenters */
.tt-el-nv-wrap.tt-el-nv-cramped .tt-el-nv-menu {
	position: relative;
}
.tt-el-nv-wrap.tt-el-nv-cramped .tt-el-nv-menu > li:not(.tt-el-nv-logo-li) {
	position: absolute;
	left: -9999px;
}
/* Phase: showing — back in flow, invisible, transitions suppressed */
.tt-el-nv-wrap.tt-el-nv-showing .tt-el-nv-menu > li:not(.tt-el-nv-logo-li) {
	opacity: 0;
	pointer-events: none;
	transition: none !important;
}
/* Measurement guard — nothing moves during strip-measure-restore. Crucially,
   truncation (overflow:hidden + text-overflow:ellipsis) is DISABLED here so
   the links expand to their natural width: the collapse detector measures the
   true intrinsic width, not the shrunk-to-fit width. Without this the ellipsis
   absorbs all overflow and the nav never reports as overflowing, so collapse
   never fires (it just truncates instead). overflow:visible + nowrap lets
   scrollWidth exceed clientWidth when the items genuinely do not fit. */
.tt-el-nv-wrap.tt-el-nv-measuring .tt-el-nv-menu > li {
	min-width: auto !important;
}
/* Transition kill scoped AWAY from act-lis (v5.0.10): the act-li is the only
   li carrying its shrink transition ON the li itself, and the SHRINK TRACE
   proved measureNatural forced-layout flush (with this rule computed) was
   CANCELLING its in-flight font-size transition mid-shrink — the intermittent
   cut. The measure window is synchronous (no frame paints inside it) and
   nothing it changes is in any transition list, so the kill protects only
   against a future transition:all landing on a menu li — insurance kept for
   real menu lis, dropped for the proven victim. */
.tt-el-nv-wrap.tt-el-nv-measuring .tt-el-nv-menu > li:not(.tt-el-nv-act-li) {
	transition: none !important;
}
.tt-el-nv-wrap.tt-el-nv-measuring .tt-el-nv-menu {
	overflow: visible !important;
}
.tt-el-nv-wrap.tt-el-nv-measuring .tt-el-nv-menu > li > a {
	overflow: visible !important;
	text-overflow: clip !important;
	min-width: auto !important;
}
/* Indicator hidden during fade-out and while cramped */
.tt-el-nv-wrap.tt-el-nv-hiding .tt-el-nv-indicator,
.tt-el-nv-wrap.tt-el-nv-cramped .tt-el-nv-indicator {
	opacity: 0 !important;
	transition: none !important;
}

/* Sides: hidden by default, fly out (fade + slight slide) when the nav
   collapses and the JS adds .tt-el-nv-side-revealed. Left slides in from
   the left, right from the right — symmetric with the kit. */
.tt-el-nv-wrap .tt-el-nv-side {
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
	transition:
		opacity var(--tt-el-nv-collapse-dur, 0.22s) var(--tt-el-nv-collapse-ease, ease),
		transform var(--tt-el-nv-collapse-dur, 0.22s) var(--tt-el-nv-collapse-ease, ease),
		visibility 0s linear var(--tt-el-nv-collapse-dur, 0.22s),
		/* v5.4.0: APPENDED, not declared in a new rule. A separate rule at
		   equal or higher specificity would replace this shorthand and kill
		   the reveal animation. */
		font-size var(--tt-el-nv-scroll-dur, 0.6s) ease;
}
.tt-el-nv-wrap .tt-el-nv-side--left  { transform: translate3d(10px, 0, 0); }
.tt-el-nv-wrap .tt-el-nv-side--right { transform: translate3d(-10px, 0, 0); }
.tt-el-nv-wrap .tt-el-nv-side.tt-el-nv-side-revealed {
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
	transform: translate3d(0, 0, 0);
	transition:
		opacity var(--tt-el-nv-collapse-dur, 0.22s) var(--tt-el-nv-collapse-ease, ease),
		transform var(--tt-el-nv-collapse-dur, 0.22s) var(--tt-el-nv-collapse-ease, ease),
		visibility 0s,
		font-size var(--tt-el-nv-scroll-dur, 0.6s) ease;
}
/* In the BUILDER only (body lacks .bricks-is-frontend), side visibility
   follows the Builder preview state control:
   - Expanded preview (default): sides HIDDEN, matching the true frontend
     expanded look. Edit their children via the Structure panel (they stay
     selectable there even when not shown in the canvas).
   - Collapsed preview (.tt-el-nv-preview-collapsed): sides fully revealed,
     exactly as they fly out on the frontend when the menu collapses.
   The frontend carries .bricks-is-frontend and is unaffected. */
/* EXPANDED builder preview: hide the sides with display:none, NOT just
   visibility/opacity. A placed child (or Bricks wrapper) can compute to
   visibility:visible and REVERSE an ancestor visibility:hidden value — which is why
   the sides reappeared in expanded preview once something was placed in them.
   display:none cannot be reversed by any descendant, so the sides stay hidden
   regardless of their contents. Children remain editable via the Structure
   panel (Bricks keeps structure selectability independent of canvas display).
   Scoped to builder + NOT-collapsed-preview only; frontend and the collapsed
   preview are untouched. (v4.3.5) */
body:not(.bricks-is-frontend) .tt-el-nv-wrap:not(.tt-el-nv-preview-collapsed) .tt-el-nv-side {
	display: none !important;
}
body:not(.bricks-is-frontend) .tt-el-nv-wrap.tt-el-nv-preview-collapsed .tt-el-nv-side {
	display: flex !important;
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
	transform: none;
}
.tt-el-nv-wrap .tt-el-nv-menu {
	display: flex;
	flex-direction: row;
	align-items: center;
	flex: 1 1 auto;
	min-width: 0;
	list-style: none;
	margin: 0;
	padding: 0;
	flex-wrap: nowrap;
	justify-content: center;
	touch-action: pan-y;
	transform: translateX(var(--tt-el-nv-shift-x, 0px));
	/* v5.4.0: the menu container now carries the size, and the links inherit
	   it. Previously the container declared none, which is precisely why each
	   link had to declare its own and why a shrink meant ~22 transitions. */
	font-size: var(--tt-el-nv-size, inherit);
}
/* The menu shift transform deliberately has NO transition (v4.17): the centring
   position of the logo is always corrected INSTANTLY, matching the Code Kit, which
   is rock-solid precisely because there is no animated position for a layout change
   to race against. (The v4.16 glide was removed; see updateShiftImmediate for the
   atomic same-frame correction used at collapse flips.) */
.tt-el-nv-wrap .tt-el-nv-menu > li {
	display: flex;
	align-items: center;
	min-width: 0;
}
.tt-el-nv-wrap .tt-el-nv-menu > li > a {
	display: inline-flex;
	align-items: center;
	text-decoration: none;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	min-width: 0;
	/* v5.7.0: inherit ALONE loses to the Type size control, which emits
	   font-size directly onto this element at Bricks ID specificity. The side
	   rail got inherit !important for exactly this in v5.4.1, with a note that
	   the menu would need the same if it ever showed. It showed. */
	font-size: inherit !important;
	color: var(--tt-el-nv-color, var(--tt-header-fg, currentColor));
}
/* iOS edge-clip, the real clipper (v5.0.4, diag-proven): the truncation clip
   above exists for TEXT links, but the logo anchor matches the same
   > li > a selector — and the HUD logo diagnostic showed it was the ONLY
   overflow:hidden left in the whole logo chain, sitting at exactly the
   artwork box (fractional at dpr 3), shaving the anti-aliased fringe and
   swallowing the v5.0.3 stage halo. The logo never truncates — free its
   anchor. Applies to both the inline-svg and img variants (the clip was on
   the shared anchor). */
.tt-el-nv-wrap .tt-el-nv-menu > li.tt-el-nv-logo-li > a {
	overflow: visible;
	text-overflow: clip;
}
/* Unified color + size reach every element inside the side slots — text,
   links, buttons, and icon/SVG toggles. Icons that size off font-size scale
   with --tt-el-nv-size; their fill/stroke follow the foreground via
   currentColor. */
.tt-el-nv-wrap .tt-el-nv-side {
	color: var(--tt-el-nv-color, var(--tt-header-fg, currentColor));
	font-size: var(--tt-el-nv-size, inherit);
}
.tt-el-nv-wrap .tt-el-nv-side * {
	color: inherit;
}
.tt-el-nv-wrap .tt-el-nv-side svg,
.tt-el-nv-wrap .tt-el-nv-side svg *,
.tt-el-nv-wrap .tt-el-nv-side [class*="icon"],
.tt-el-nv-wrap .tt-el-nv-side i {
	fill: currentColor;
	color: inherit;
}
/* SVG icons size off font-size: a Bricks/inline SVG uses its own width/height
   (px), so the font-size the Size knob writes would not reach it. Tying the SVG
   box to 1em makes it follow the same unified Size as icon-font glyphs and text
   — so an SVG-based side icon scales with the knob too, with or without a link
   wrapper. Only constrains side-slot SVGs; the logo SVG is elsewhere. (v4.3.4) */
.tt-el-nv-wrap .tt-el-nv-side svg {
	width: 1em;
	height: 1em;
}
/* v5.4.1: the side descendants have to be TOLD to inherit. .tt-el-nv-side *
   above declares color: inherit but never font-size, and the children here
   are Bricks-generated (button.brxe-toggle, i.brxe-icon,
   a.bricks-link-wrapper) which Bricks gives their own font-size. Inheritance
   cannot reach past a declaration on the element itself, so before v5.4.0
   the only thing that moved them was the per-element !important in the
   scrolled rule. That pinning was load-bearing; the per-element TRANSITIONS
   were not, and the two are separable.
   These declare inheritance ONLY, and carry no transition, so each child
   renders the animating container size frame-accurately while a flip still
   produces two transitions rather than twenty-two. !important is required
   to outrank the Bricks declaration; the value is inherit, so it pins
   nothing of its own.
   .tt-el-nv-action-badge is excluded on purpose: its 0.6em is deliberate and
   relative, so it already scales with the inherited parent size. A blanket
   .tt-el-nv-side * rule would have flattened it to full text size. */
.tt-el-nv-wrap .tt-el-nv-side > *:not(.tt-el-nv-action-badge),
.tt-el-nv-wrap .tt-el-nv-side a,
.tt-el-nv-wrap .tt-el-nv-side button,
.tt-el-nv-wrap .tt-el-nv-side .brxe-icon,
.tt-el-nv-wrap .tt-el-nv-side i,
.tt-el-nv-wrap .tt-el-nv-side svg,
.tt-el-nv-wrap .tt-el-nv-side [class*="icon"]:not(.tt-el-nv-action-badge) {
	font-size: inherit !important;
}
/* Logo li never truncates */
.tt-el-nv-wrap .tt-el-nv-logo-li {
	flex: 0 0 auto;
	overflow: visible;
}
.tt-el-nv-wrap .tt-el-nv-logo-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	line-height: 0;
	text-decoration: none;
	position: relative;
	color: var(--tt-el-nv-color, var(--tt-header-fg, currentColor));
	-webkit-user-drag: element;
}
.tt-el-nv-wrap .tt-el-nv-logo-stage {
	display: grid;
	place-items: center;
	/* Promote to a dedicated GPU layer so the two crossfade layers rasterise on a
	   stable surface. Without this, during the opacity transition the compositor
	   repaints the stage region and re-snaps its sub-pixel position frame to frame —
	   the ~1px crossfade jitter. translateZ(0) + backface-visibility give it a
	   crisp, stable layer; the centering shift is now integer-px (see updateShift)
	   so the stage itself sits on whole pixels. (v4.15.4) */
	transform: translateZ(0);
	-webkit-backface-visibility: hidden;
	backface-visibility: hidden;
	/* iOS edge-clip fix (v5.0.3): the GPU layer above rasterises with bounds equal
	   to this box, which fits the artwork exactly — so on iOS the outermost
	   anti-aliased pixels of the logo are cropped at the layer edge (the logo ring
	   looked slightly clipped around the edge). Symmetric padding grows the layer
	   bounds past the artwork; the equal negative margin cancels it in layout, so
	   the outer footprint, the centering measurement, and the crossfade-layer
	   alignment are all byte-identical. Paint-only. */
	padding: 2px;
	margin: -2px;
}
.tt-el-nv-wrap .tt-el-nv-logo-layer {
	grid-area: 1 / 1;
	display: grid;
	place-items: center;
	pointer-events: none;
}
.tt-el-nv-wrap .tt-el-nv-logo-img {
	display: block;
	width: auto;
	height: var(--tt-el-nv-logo-h, 3rem);
	pointer-events: none;
	-webkit-user-drag: none;
}
/* Inline SVG logo: the mount span sizes by height; the injected <svg>
   scales to it and inherits the unified color via fill:currentColor. */
.tt-el-nv-wrap .tt-el-nv-logo-svg {
	display: block;
	height: var(--tt-el-nv-logo-h, 3rem);
	width: auto;
	line-height: 0;
	color: var(--tt-el-nv-color, var(--tt-header-fg, currentColor));
}
.tt-el-nv-wrap .tt-el-nv-logo-svg svg {
	display: block;
	height: 100%;
	width: auto;
	/* iOS edge-clip fix (v5.0.3): an <svg> clips its content to its viewport by
	   default (UA overflow:hidden). The logo height is rem-derived and animates
	   between sizes, and width:auto follows the viewBox aspect — both routinely
	   fractional on iOS — so the viewport rect lands on fractional device pixels
	   and Safari shaves the anti-aliased fringe of artwork drawn out to the
	   viewBox boundary. Freeing the overflow lets the fringe paint; the stage,
	   layer, and logo li above are all overflow-visible, so nothing re-clips. */
	overflow: visible;
}
.tt-el-nv-wrap .tt-el-nv-logo-svg svg,
.tt-el-nv-wrap .tt-el-nv-logo-svg svg * {
	fill: currentColor;
}
/* Inline SVG logo (if mounted as <svg>, not <img>) inherits the unified color. */
.tt-el-nv-wrap .tt-el-nv-logo-layer svg,
.tt-el-nv-wrap .tt-el-nv-logo-layer svg path,
.tt-el-nv-wrap .tt-el-nv-logo-layer svg g {
	fill: currentColor;
}
.tt-el-nv-wrap .tt-el-nv-logo-text {
	display: block;
	width: auto;
	color: var(--tt-el-nv-color, currentColor);
	pointer-events: none;
	-webkit-user-drag: none;
}
.tt-el-nv-wrap .tt-el-nv-logo-layer--main { opacity: 1; transition: opacity 0.6s ease; }
.tt-el-nv-wrap .tt-el-nv-logo-layer--inverse { opacity: 0; transition: opacity 0.6s ease; }
.tt-el-nv-wrap.tt-el-nv-scrolling .tt-el-nv-logo-link[data-tt-has-inverse="1"] .tt-el-nv-logo-layer--main { opacity: 0; }
.tt-el-nv-wrap.tt-el-nv-scrolling .tt-el-nv-logo-link[data-tt-has-inverse="1"] .tt-el-nv-logo-layer--inverse { opacity: 1; }
/* ============================================================
   SCROLL-SHRINK ANIMATION (ported from the header code kit).
   The transition lives ONLY on .tt-el-nv-anim (emitted server-side
   when the toggle is on), so when the feature is off there is zero
   transition on these elements. The shrink VALUES are CSS variables
   written by the Animation controls, each with a working fallback so
   enabling the animation shrinks IMMEDIATELY even before you set a
   value. Duration is --tt-el-nv-scroll-dur (default 0.6s, the kit
   value). font-size + height + padding transition; color is
   INTENTIONALLY absent — the tint/adaptive-color engine owns
   foreground color per-frame and a CSS color transition would
   compete with it. */
.tt-el-nv-wrap.tt-el-nv-anim {
	transition: padding var(--tt-el-nv-scroll-dur, 0.6s) ease;
}
/* v5.4.0: ONE animated subject for the menu. The side rail carries its own
   font-size transition appended to the collapse shorthands above. Every
   descendant is a pure inheritor and runs no transition of its own, so a
   flip produces 2 transitionstart events rather than the ~22 that every
   trace in the v5.0.9-v5.2.6 arc recorded. */
.tt-el-nv-wrap.tt-el-nv-anim .tt-el-nv-menu {
	transition: font-size var(--tt-el-nv-scroll-dur, 0.6s) ease;
}
.tt-el-nv-wrap.tt-el-nv-anim .tt-el-nv-logo-img,
.tt-el-nv-wrap.tt-el-nv-anim .tt-el-nv-logo-svg {
	transition: height var(--tt-el-nv-scroll-dur, 0.6s) ease;
}
/* Scrolled-state SIZES — rebuilt to MATCH THE HEADER KIT EXACTLY (see its
   code.css: header.scrolling #tt-header-nav font-size: var(--step--1) ).
   Hand-authored CSS, .tt-el-nv-scrolling scope, the kit own --step design
   tokens written LITERALLY — this is the bulletproof path the kit uses, with
   no Bricks control scoping (which cannot match .scrolling on the root) and no
   token-drop (tokens are literal CSS here, never routed through a number+units
   control). The controls remain as OPTIONAL overrides: they publish
   --tt-el-nv-scrolled-size / --tt-el-nv-scrolled-logo-h, and var(token, kit
   default) means a set raw value wins, otherwise the kit token is used. So out
   of the box you get the kit exact shrink (--step--1 type), and you can
   override with a raw size. !important + the .tt-el-nv-anim.tt-el-nv-scrolling
   scope beats the Bricks ID-scoped menu Typography. color is never
   transitioned (the tint engine owns it per-frame). */
/* v5.5.2 NEUTRALISER. Forces off every property that could move the logo but
   that this element never writes. If the scaling stops under ?ttnv-off=foreign
   the cause is external, and the logo forensics rows name the property. This
   also removes the translateZ(0) promotion on the stage, since that is itself
   a transform — a deliberate consequence of the test, not an oversight. */
.tt-el-nv-wrap.tt-el-nv-off-foreign .tt-el-nv-logo-link,
.tt-el-nv-wrap.tt-el-nv-off-foreign .tt-el-nv-logo-stage,
.tt-el-nv-wrap.tt-el-nv-off-foreign .tt-el-nv-logo-svg,
.tt-el-nv-wrap.tt-el-nv-off-foreign .tt-el-nv-logo-img,
.tt-el-nv-wrap.tt-el-nv-off-foreign .tt-el-nv-logo-text {
	transform: none !important;
	scale: none !important;
	width: auto !important;
}
/* v5.29.0 — `side` bisect key. Pins the side scale back to rest while the
   header shrinks, so the sides simply do not participate in the morph. Same
   pattern as the type and logo keys above: freeze the property at its resting
   value rather than killing the transition, so every other animation keeps
   behaving normally and cannot be mistaken for the artifact.
   This is the decisive test for the side stutter. Scroll with it on:
     - stutter GONE  -> the cause is inside the side subtree (its own scale, or
       the Bricks child elements and their custom CSS, which this element does
       not own and cannot see).
     - stutter STAYS -> the sides were never the cause. Something at header
       level is janking the whole bar and the sides only made it legible,
       which would also explain why five straight fixes to the side changed
       nothing.
   Set the bisect switch to `side` in the panel to arm it. */
/* v5.30.0 — `sideorg` bisect key. Unlike the `side` key, this one leaves the
   scale RUNNING and changes only where it pivots, so the animation is still
   there to watch — the mistake in the `side` key was freezing the very thing
   being observed.
   The solved origin (v5.25.0) puts the side pivot roughly 110px ABOVE a box
   only ~40px tall, because the maths that lands the centre correctly has a
   1/(1-r) term that blows up as the ratio approaches 1. The menu pivots about
   84px above a 100px box, so the sides sit at a far more extreme ratio of
   pivot distance to box size — the one geometric quantity that is genuinely
   lopsided between the two.
   With this key on, the sides pivot about their own centre. They will sit at
   the WRONG vertical position while scrolled; that is expected and is not
   what is being judged. The only question is whether the motion is smooth. */
.tt-el-nv-wrap.tt-el-nv-off-sideorg .tt-el-nv-side,
.tt-el-nv-wrap.tt-el-nv-off-sideorg .tt-el-nv-side--left,
.tt-el-nv-wrap.tt-el-nv-off-sideorg .tt-el-nv-side--right {
	transform-origin: center center !important;
}
.tt-el-nv-wrap.tt-el-nv-off-side.tt-el-nv-anim.tt-el-nv-scrolling .tt-el-nv-side {
	scale: 1 !important;
}
/* v5.5.1 property-level bisect. These pin the frozen property back to its
   resting value in the scrolled state rather than killing the transition, so
   every other animation — the side rail collapse in particular — keeps
   behaving normally and cannot be mistaken for the artifact. */
.tt-el-nv-wrap.tt-el-nv-off-type.tt-el-nv-anim.tt-el-nv-scrolling .tt-el-nv-menu,
.tt-el-nv-wrap.tt-el-nv-off-type.tt-el-nv-anim.tt-el-nv-scrolling .tt-el-nv-side {
	font-size: var(--tt-el-nv-size, inherit) !important;
}
.tt-el-nv-wrap.tt-el-nv-off-logo.tt-el-nv-anim.tt-el-nv-scrolling .tt-el-nv-logo-img,
.tt-el-nv-wrap.tt-el-nv-off-logo.tt-el-nv-anim.tt-el-nv-scrolling .tt-el-nv-logo-svg {
	height: var(--tt-el-nv-logo-h, 3rem) !important;
}
/* v5.23.0 — GUARDED. These are the LAYOUT engine shrink rules and they had no
   composite guard, so in composite mode they fired ON TOP of the scale from
   the scoped payload. Text was shrunk twice: font-size to the scrolled size
   AND scale to the same ratio, landing at ratio squared instead of ratio.
   The logo was shrunk three times: its height rule below, the menu scale, and
   the stage corrective. Only the layout engine may apply these. */
.tt-el-nv-wrap:not([data-tt-shrink-composite="1"]).tt-el-nv-anim.tt-el-nv-scrolling .tt-el-nv-menu,
.tt-el-nv-wrap:not([data-tt-shrink-composite="1"]).tt-el-nv-anim.tt-el-nv-scrolling .tt-el-nv-side {
	/* v5.10.0: no !important on an animated property — Safari 27 lets one
	   override the running transition. Specificity is won by the per-instance
	   block emitted in render() instead. */
	font-size: var(--tt-el-nv-scrolled-size, var(--step--1, 0.85em));
}
.tt-el-nv-wrap:not([data-tt-shrink-composite="1"]).tt-el-nv-anim.tt-el-nv-scrolling .tt-el-nv-logo-img,
.tt-el-nv-wrap:not([data-tt-shrink-composite="1"]).tt-el-nv-anim.tt-el-nv-scrolling .tt-el-nv-logo-svg {
	height: var(--tt-el-nv-scrolled-logo-h, var(--step-5, 2.4rem));
}
/* Header HOLD suppression (ported from tu-tra-header-hold, CSS-specificity
   approach): while .tt-el-nv-held is on, override the scroll-shrink back to the
   BASE (non-scrolled) size so the header stays full size even though
   .tt-el-nv-scrolling is set. Higher specificity (extra .tt-el-nv-held class) +
   !important beats the shrink rule above. The menu link base size reads the same
   Type-size control variable the non-scrolled state uses; the logo returns to its
   own --tt-el-nv-logo-h. The transition still animates in/out. (v4.10.6) */
.tt-el-nv-wrap.tt-el-nv-anim.tt-el-nv-scrolling.tt-el-nv-held .tt-el-nv-menu,
.tt-el-nv-wrap.tt-el-nv-anim.tt-el-nv-scrolling.tt-el-nv-held .tt-el-nv-side {
	font-size: var(--tt-el-nv-size, 1rem);
}
.tt-el-nv-wrap.tt-el-nv-anim.tt-el-nv-scrolling.tt-el-nv-held .tt-el-nv-logo-img,
.tt-el-nv-wrap.tt-el-nv-anim.tt-el-nv-scrolling.tt-el-nv-held .tt-el-nv-logo-svg {
	height: var(--tt-el-nv-logo-h, 3rem);
}
/* Allow logo overflow: free ONLY the logo li from the menus
   overflow:hidden (which exists for link ellipsis) so a tall logo is
   not cropped. Other items keep clipping. Gated on the toggle class. */
.tt-el-nv-wrap.tt-el-nv-logo-overflow .tt-el-nv-logo-li {
	overflow: visible;
}
/* Allow logo overflow: free ONLY the logo li from the menus
   overflow:hidden (which exists for link ellipsis) so a tall logo is
   not cropped. Other items keep clipping. Gated on the toggle class. */
.tt-el-nv-wrap .tt-el-nv-indicator {
	position: absolute;
	left: 0;
	top: 0;
	height: var(--tt-el-nv-ind-h, 1px);
	width: var(--tt-el-nv-ind-w, 0px);
	transform: translate(var(--tt-el-nv-ind-x, 0px), var(--tt-el-nv-ind-y, 0px));
	background: var(--tt-el-nv-ind-color, var(--tt-el-nv-color, var(--tt-el-nv-ind-snap, var(--tt-header-fg, currentColor))));
	opacity: var(--tt-el-nv-ind-o, 0);
	pointer-events: none;
	transition: transform var(--tt-el-nv-ind-speed, 450ms) cubic-bezier(0.08, 0.82, 0.17, 1), width var(--tt-el-nv-ind-speed, 450ms) cubic-bezier(0.12, 0.82, 0.20, 1) 25ms, opacity 260ms cubic-bezier(0.25, 0.1, 0.25, 1);
	will-change: transform, width, opacity;
	backface-visibility: hidden;
	-webkit-backface-visibility: hidden;
}
.tt-el-nv-wrap.tt-snap .tt-el-nv-indicator {
	transition: transform 0s, width 0s, opacity 200ms cubic-bezier(0.25, 0.1, 0.25, 1) !important;
}
.tt-el-nv-wrap.tt-el-nv-cramped .tt-el-nv-indicator {
	opacity: 0 !important;
	transition: none !important;
}
/* No-flash: the server emits data-tt-centering on the nav, so this rule is
   active from the first byte (the sheet is in <head>). The row is hidden
   before it ever paints; JS removes the attribute once the logo is slotted,
   then .tt-el-nv-revealed fades it in. The action zone (.tt-el-nv-actions) is
   handled by a SEPARATE flag, data-tt-actions-pending, because the zone is
   relocated INTO the menu by JS after boot and the flash (the search toggle
   appearing unstyled next to the side block on first paint) must be suppressed
   even when centering is OFF — data-tt-centering is only emitted with centering
   on. JS removes data-tt-actions-pending right after relocation; the items then
   live in the menu (revealed with it) and the emptied zone is display:none. The
   builder emits neither flag, so both stay visible there (correct). */
.tt-el-nv-wrap[data-tt-centering] .tt-el-nv-menu {
	opacity: 0 !important;
	transition: none !important;
}
.tt-el-nv-wrap[data-tt-actions-pending] .tt-el-nv-actions {
	opacity: 0 !important;
	transition: none !important;
}
.tt-el-nv-wrap.tt-el-nv-revealed .tt-el-nv-menu {
	opacity: 1 !important;
	/* v5.9.2: BOTH terms. This rule used to declare opacity alone with
	   !important, and .tt-el-nv-revealed is permanent, so it silently wiped the
	   font-size transition for the entire life of the page — the menu shrank with
	   no animation at all. Same mistake v5.4.0 recorded for the side rail: a
	   competing rule REPLACING a shorthand instead of extending it. */
	/* v5.21.0 — the scale term. This list is !important and
	   .tt-el-nv-revealed is permanent, so it is the ONLY transition the menu
	   ever gets: it beats every other rule on the element regardless of
	   specificity, for the whole life of the page. Composite mode animates
	   `scale` on the menu, `scale` was not in this list, so the menu scale
	   applied INSTANTLY while the logo stage (untouched by this rule) eased.
	   That is the snap-to-80%-then-morph: the menu jumps straight to the text
	   ratio, then the logo corrective animates the rest of the way down.
	   v5.9.2 fixed this exact rule once by adding font-size after it wiped
	   that transition the same way. Any property composite mode ever animates
	   on the menu MUST be repeated here. */
	transition:
		opacity 150ms ease-out,
		font-size var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease),
		scale var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease-in-out),
		translate var(--tt-el-nv-scroll-dur, 0.6s) var(--tt-el-nv-scroll-ease, ease-in-out) !important;
}
@media (prefers-reduced-motion: reduce) {
	.tt-el-nv-wrap .tt-el-nv-indicator {
		transition: transform 0s, width 0s, opacity 0.1s ease-out !important;
	}
}
/* v5.50.0 — PWA MODE. In a home-screen app the bottom nav carries navigation,
   so the header keeps only the logo, the tint and the blur. Keyed on the class
   the PWA plugin sets before first paint, so there is no flash and the plugin
   override (?ttpwa=) applies. The display-mode queries are the fallback for
   when the plugin is absent; they step aside when the plugin forces browser
   mode. Builder-canvas rules on the side never match here, since the canvas
   is never standalone, so this wins wherever it can apply.
   v5.51.0: the side SLOTS stay; only their direct children are hidden, unless
   a child carries .tt-el-nv-pwa-keep. PWA-only elements (the PWA header
   button) opt in with that class, and the slots keep moving, scaling and
   tinting with the shrink as before, so a kept child follows for free. */
html.tt-pl-pw-standalone .tt-el-nv-wrap .tt-el-nv-side > :not(.tt-el-nv-pwa-keep),
html.tt-pl-pw-standalone .tt-el-nv-wrap .tt-el-nv-actions,
html.tt-pl-pw-standalone .tt-el-nv-wrap .tt-el-nv-menu > li:not(.tt-el-nv-logo-li),
html.tt-pl-pw-standalone .tt-el-nv-wrap .tt-el-nv-indicator {
	display: none !important;
}
@media (display-mode: standalone), (display-mode: fullscreen), (display-mode: minimal-ui) {
	html:not(.tt-pl-pw-browser) .tt-el-nv-wrap .tt-el-nv-side > :not(.tt-el-nv-pwa-keep),
	html:not(.tt-pl-pw-browser) .tt-el-nv-wrap .tt-el-nv-actions,
	html:not(.tt-pl-pw-browser) .tt-el-nv-wrap .tt-el-nv-menu > li:not(.tt-el-nv-logo-li),
	html:not(.tt-pl-pw-browser) .tt-el-nv-wrap .tt-el-nv-indicator {
		display: none !important;
	}
}