/*
 * Header, navigation, footer, mobile bottom bar — Hitsi-Äijät redesign.
 * Loads after components.css. Mobile-first; the two nav systems
 * (.site-nav for desktop, .mobile-nav for small screens) are mutually
 * exclusive by breakpoint, never both visible.
 *
 * No-JS contract: .mobile-nav is visible by default below 1024px so its
 * links work with JavaScript disabled. The .js class (added inline by
 * site-header.php before paint) is what allows CSS to hide it until the
 * toggle button opens it — see navigation.js for the interaction.
 */

/* Astra's own header/footer wrappers still render (see inc/header.php and
   inc/footer.php for why) — hidden here rather than removed from the DOM.
   #masthead and #colophon are the real ids confirmed via SSH source read,
   not guesses. */
#masthead,
#colophon {
  display: none;
}

/* ---------- Top bar (Header v1.0) ----------
 * Only rendered by site-header.php when a real phone or email value already
 * exists (inc/customizer.php) — no placeholder content, ever. Built entirely
 * from existing tokens (industrial-900/on-dark/space-2/small text/motion) —
 * no new color, font, shadow, radius, or container value was introduced.
 * Sits above the sticky .site-header (not part of it), so it scrolls away
 * normally; navigation.js toggles .is-hidden on the same scroll threshold
 * already used for .site-header.is-scrolled, collapsing it via max-height
 * rather than display:none so the transition is visible, not a hard cut.
 * Markup also carries the existing .section--dark class (not just
 * .site-topbar) so it gets that class's background/text color AND its
 * dark-surface :focus-visible override (base.css) for free, instead of
 * duplicating either here.
 *
 * max-height is deliberately generous (well above one line's actual height):
 * .site-topbar__inner can wrap phone+email onto two lines on very narrow
 * viewports (flex-wrap: wrap, inherited from .cluster), and a tight
 * max-height combined with overflow:hidden would silently clip a wrapped
 * second line instead of just failing to animate it — a real contact
 * number/email disappearing is worse than an oversized transition. Reuses
 * the existing --space-9 token (96px) rather than an arbitrary new rem
 * value — STYLEGUIDE.md defines no dedicated "max-height" token, and this
 * is the closest existing spacing token with enough headroom. */
.site-topbar {
  max-height: var(--space-9);
  overflow: hidden;
  transition: max-height var(--motion-base) var(--motion-easing),
    opacity var(--motion-base) var(--motion-easing);
}

.site-topbar.is-hidden {
  max-height: 0;
  opacity: 0;
}

.site-topbar__inner {
  padding-block: var(--space-2);
  flex-wrap: wrap;
  gap: var(--space-4);
  font-size: var(--text-small-size);
}

.site-topbar__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: inherit;
  text-decoration: none;
  /* Topbar alignment fix: phone/email must never break mid-string — the
     previous "allow breaking anywhere" rule here could split the phone
     digits or the email address itself under enough width pressure, the
     opposite of what the alignment fix needs. This nowrap value is
     inherited by the <span> inside, so neither text node can wrap
     internally; if an item doesn't fit the remaining row width,
     .site-topbar__inner's own wrap-enabled layout moves that whole item
     (icon + text together, since this is itself the flex item) down to
     its own line instead — the email link is the one expected to do this
     in practice, the phone number is short enough it never needs to. */
  white-space: nowrap;
  /* A11Y-06: .site-topbar__inner's padding-block (--space-2) alone left this
     link's tap target a few px under the 44px enhanced/AAA touch-target
     target (WCAG 2.5.5) at narrower widths. min-height, not extra padding,
     so the visible text/icon size and the topbar's own compact height are
     unaffected — only the invisible hit area grows. */
  min-height: var(--touch-target-min);
}

.site-topbar__item:hover,
.site-topbar__item:focus-visible {
  text-decoration: underline;
}

/* Focus-visible fix (component-scoped, Option A): this item only had a
   text-decoration change on focus before. Astra's dynamic a:focus-visible
   (0,1,1) and the theme's own dark-surface tie (.section--dark
   :focus-visible, base.css) only won outline-color, not outline-style/
   -width — confirmed live, dotted 1px with the right color. This rule's
   own specificity (0,2,0) wins outright, no reliance on source order. */
.site-topbar__item:focus-visible {
  outline: var(--border-width-active) solid var(--color-focus-on-dark);
  outline-offset: 2px;
}

/* Header v2.1 — White header (docs/design/header-v2-spec.md addendum).
   Only .site-topbar (phone/email strip, above this element) stays on the
   dark/.section--dark scheme; the main header bar is now the same light
   surface as the rest of the page. A hairline border-bottom is reinstated
   here for the same reason the original v1 comment (now removed) said it
   would be needed again: --color-bg-surface (#FFFFFF) and --color-bg-page
   (#F5F5F3, base.css) are close enough in tone that a light header sitting
   directly on a light page needs an explicit seam. */
.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background-color: var(--color-bg-surface);
  color: var(--color-text-default);
  border-bottom: var(--border-width-default) solid var(--color-border-200);
}

/* .site-header__search and .mobile-nav are DOM children of <header>; both
   already used the light scheme even when the bar above them was dark
   (Header v2), so nothing here changed by the v2.1 white-header pass — kept
   explicit rather than relying on inheritance from .site-header now that
   the two happen to match, since search/mobile-nav must stay light even if
   a future pass darkens the bar again. */
.site-header__search,
.mobile-nav {
  background-color: var(--color-bg-surface);
  color: var(--color-text-default);
}

/* WordPress admin toolbar is position:fixed with z-index:99999 (confirmed
   in wp-includes/css/admin-bar.css), which sits above our own sticky header
   at the same top:0 offset once scrolled. body.admin-bar is added by WP core
   only for logged-in users viewing the front end with the toolbar enabled;
   anonymous visitors get no .admin-bar class and no override applies. */
.admin-bar .site-header {
  top: 32px;
}

@media screen and (max-width: 782px) {
  .admin-bar .site-header {
    top: 46px;
  }
}

@media screen and (max-width: 600px) {
  .admin-bar .site-header {
    top: 0;
  }
}

.site-header.is-scrolled {
  box-shadow: var(--shadow-header-sticky);
}

.site-header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: 60px;
  transition: min-height var(--motion-base) var(--motion-easing);
}

.site-header.is-scrolled .site-header__bar {
  min-height: 48px;
}

@media (min-width: 1024px) {
  .site-header__bar { min-height: 88px; }
  .site-header.is-scrolled .site-header__bar { min-height: 64px; }
}

.site-header__brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  text-decoration: none;
  color: var(--color-text-default); /* Header v2.1: light surface, see .site-header above */
  min-width: 0;
}

/* Focus-visible fix (component-scoped, Option A): found live during the
   ETAP7 preview pass, not caught by the earlier static selector inventory
   — the logo is a plain <a>, no .btn class, so Astra's bare
   a:focus-visible (0,1,1) wins dotted/1px, confirmed live on both the
   custom-logo (.custom-logo-link + .site-header__tagline-link, real
   markup when a custom logo is set) and fallback (.site-header__brand-link,
   when it isn't) shapes. .site-header__brand only ever wraps these logo/
   tagline links (site-header.php), so a single descendant selector safely
   covers every real shape without needing three separate rules. */
.site-header__brand a:focus-visible {
  outline: var(--border-width-active) solid var(--color-industrial-900);
  outline-offset: 2px;
}

/* Header v2: slightly larger than the previous 44px — the Header audit
   behind docs/design/header-v2-spec.md found the logo carried too little
   visual weight relative to the nav next to it. Mobile keeps its own
   separate 36px override below (max-width: 767.98px), untouched by this
   change — that override always wins under 768px regardless of this
   value. */
.site-header__brand img {
  max-height: 52px;
  width: auto;
}

.site-header__logo-text {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.25rem;
}

.site-header__tagline {
  display: none;
  font-size: var(--text-small-size);
  /* Header v2.1: light header, so this reuses --color-text-muted directly
     (#686868 on white measures ~5.6:1, over the 4.5:1 AA threshold for
     14px text) instead of the rgba-white-over-dark technique the previous
     dark header needed. */
  color: var(--color-text-muted);
  white-space: nowrap;
}

@media (min-width: 768px) {
  .site-header__tagline { display: inline; }
}

/* ---------- Mobile header (<768px) ---------- */

/* Compact gap (height stays the default 60px, not "is-scrolled" 48px — that
   still triggers on scroll same as always) plus a shrinkable, width-capped
   brand block so logo + search + account + cart + hamburger fit at 320px
   without overflow. Header v1.0: search is now REQUIRED visible on mobile
   (previously hidden here — see docs/STYLEGUIDE.md §18's now-resolved gap
   note), and .site-header__account is hidden below 1024px since Oma tili is
   a mobile-MENU item, not a mobile-header icon (see site-header.php). The
   old CTA-hiding rule is gone along with the CTA itself. Narrower than the
   768px tagline breakpoint above, so tablet (>=768px) and the >=1024px
   desktop block further down are both unaffected. */
@media (max-width: 767.98px) {
  .site-header__bar {
    gap: var(--space-2);
  }

  .site-header__brand {
    flex: 1 1 auto;
    min-width: 0;
    max-width: min(46vw, 160px);
    overflow: hidden;
  }

  /* Custom-logo markup only (the_custom_logo() prints its own <a>, see
     site-header.php) — the fallback .site-header__brand-link path already
     has its own max-width:100% rule further down and isn't part of this
     bug (DOCX/screenshot showed the real custom-logo case cropping at
     ~320px, not the fallback). */
  .site-header__brand .custom-logo-link {
    display: flex;
    align-items: center;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    /* A11Y-06: the logo image itself stays 36px tall (below) — min-height
       here only grows the invisible tap target to the 44px enhanced/AAA
       touch-target size (WCAG 2.5.5); align-items:center keeps the 36px
       image visually centered in the taller box instead of shifting it. */
    min-height: var(--touch-target-min);
  }

  .site-header__brand img {
    display: block;
    width: 100%;
    max-width: 100%;
    height: auto;
    max-height: 36px;
    object-fit: contain;
    object-position: left center;
  }

  .site-header__actions {
    gap: var(--space-2);
  }
}

/* ---------- Desktop header layout (>=1024px) ---------- */

/* Logo-over-tagline inside the brand block, a controlled brand width, a
   nav that can actually shrink, and actions that never do — so the brand
   link's tagline (nowrap) can no longer run into the nav at the range
   where they used to collide. */
@media (min-width: 1024px) {
  /* Real markup (has_custom_logo() true): .custom-logo-link and
     .site-header__tagline-link are direct siblings inside
     .site-header__brand (the_custom_logo() prints its own <a>, never
     nested — see template-parts/header/site-header.php), so the column
     stacking has to live on .site-header__brand itself, not on a wrapper
     link that doesn't exist in this case. */
  .site-header__brand {
    flex: 0 1 auto;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2); /* Header v2: calmer spacing between wordmark and tagline (was --space-1) */
    min-width: 0;
    max-width: 20rem;
    overflow: hidden;
  }

  /* Fallback (no custom logo set): a single .site-header__brand-link wraps
     both spans itself, so it needs its own column stacking too. */
  .site-header__brand-link {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2); /* Header v2: matches .site-header__brand above */
    max-width: 100%;
  }

  .custom-logo-link,
  .site-header__tagline-link {
    max-width: 100%;
  }

  .site-header__tagline-link {
    text-decoration: none;
    line-height: var(--text-small-line-height);
  }

  .site-header__tagline {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* Header v2: a quiet divider between the brand block and navigation — the
     Header audit found no hierarchy device at all between them; this is the
     smallest one available (a hairline, not a decorative element). Header
     v2.1: reuses --color-border-200 (the same token .site-header__search's
     own border-top uses) now that the bar is light, instead of the
     low-opacity-white-over-dark technique the dark bar needed. */
  .site-nav {
    flex: 1 1 auto;
    min-width: 0;
    padding-inline-start: var(--space-6);
    border-inline-start: var(--border-width-default) solid var(--color-border-200);
  }

  /* Header v2.1: no per-bar override needed any more — .site-nav__list a
     below already sets --color-text-default (black), which is correct for
     both the desktop bar and .mobile-nav now that both are light. The old
     .site-header__bar .site-nav__list a override forced white text for the
     dark-bar era; deleted rather than recolored so there's one source of
     truth for nav-link color. */

  .site-header__actions {
    flex: 0 0 auto;
  }
}

/* 1024–1279px: brand + nav + actions no longer overlap once the tagline is
   two lines tall and nav gap is at its widest, but there still isn't room
   for all three plus the tagline on one line. Hiding just the tagline in
   this intermediate band is the documented exception; it reappears at
   1280px, the project's existing "everything fits" breakpoint
   (components.css .grid--4-up). */
@media (min-width: 1024px) and (max-width: 1279.98px) {
  .site-header__tagline {
    display: none;
  }
}

/* ---------- Desktop nav ---------- */

.site-nav { display: none; }

@media (min-width: 1024px) {
  .site-nav { display: block; }
}

.site-nav__list {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
}

@media (min-width: 1024px) {
  .site-nav__list {
    flex-wrap: nowrap;
    gap: clamp(var(--space-3), 1.5vw, var(--space-5));
  }
}

.site-nav__list a {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-target-min);
  text-decoration: none;
  font-weight: 600;
  font-size: var(--text-button-size);
  color: var(--color-text-default);
  border-bottom: 2px solid transparent;
}

.site-nav__list a:hover,
.site-nav__list li.current-menu-item > a {
  border-bottom-color: var(--color-brand-blue-600);
}

/* Focus-visible fix (component-scoped, Option A): plain <a>, no .btn class,
   so Astra's dynamic a:focus-visible (0,1,1) otherwise wins outright
   (dotted 1px) — confirmed live on "Huoltopalvelu". This rule's own class
   (.site-nav__list) + pseudo-class + the "a" it already targets outranks
   Astra's specificity on the class column alone. Covers desktop nav AND
   .mobile-nav__secondary (same markup, <ul class="site-nav__list
   mobile-nav__secondary">), so no separate selector is needed for that
   list. */
.site-nav__list a:focus-visible {
  outline: var(--border-width-active) solid var(--color-industrial-900);
  outline-offset: 2px;
}

/* ---------- Header actions (search, phone, CTA, cart, nav toggle) ---------- */

.site-header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* Header v2.1: .icon-button's own default color (components.css) is
   already --color-text-default (near-black) — correct as-is for the light
   header, so search/account/cart need no override at all. This rule stays
   only to be explicit that it's intentional, not an oversight; the
   nav-toggle (mobile hamburger) below deliberately overrides it back to a
   blue button per the approved spec. */
.site-header .icon-button {
  color: var(--color-text-default);
}

/* Focus-visible fix (component-scoped, Option A): two separate Astra
   conflicts hit this row. .site-header__account/.site-header__cart are
   real <a> links (unclassed .btn-wise) so Astra's bare a:focus-visible
   (0,1,1) wins dotted/1px, same as any other unclassed link. .js-search-
   toggle and .js-nav-toggle are real <button> elements, so Astra's bare
   button:focus (0,1,1) wins outline:0 — a materially worse, fully
   invisible failure, confirmed live on both. Each selector below is a
   single class + :focus-visible = (0,2,0), beating both Astra rules
   outright on the class column alone. */
.site-header__account:focus-visible,
.site-header__cart:focus-visible,
.js-search-toggle:focus-visible,
.js-nav-toggle:focus-visible {
  outline: var(--border-width-active) solid var(--color-industrial-900);
  outline-offset: 2px;
}

/* Header v1.0: Oma tili is a desktop-only header icon (mobile carries it in
   the mobile-menu list instead — see site-header.php); same hidden-below-
   1024px pattern the old .site-header__phone rule used before the phone
   link and CTA were removed from this row. */
.site-header__account {
  display: none;
}

@media (min-width: 1024px) {
  .site-header__account { display: inline-flex; }
}

.site-header__cart {
  position: relative;
}

.site-header__cart-count {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 1.25rem;
  justify-content: center;
  padding-inline: 0.25rem;
}

.site-header__nav-toggle { display: inline-flex; }

/* Header v2.1: the only icon-button that does NOT take the plain black
   treatment above — approved spec calls for a filled blue button with a
   white icon (SVG uses stroke="currentColor", inc/icons.php, so setting
   color here is enough, no icons.php change needed). Three classes here
   deliberately outweigh .site-header .icon-button's two, so this wins
   regardless of source order rather than relying on it. --color-brand-blue-600
   is also reused by the unified Tuotteet mega-menu trigger
   (.site-nav__mega-trigger, mega-menu.css, Navigation v2.2) — the same
   filled-blue-button treatment, not a second ad-hoc blue. */
.site-header .icon-button.site-header__nav-toggle {
  background-color: var(--color-brand-blue-600);
  color: var(--color-text-on-dark);
  border-radius: var(--radius-control);
}

@media (min-width: 1024px) {
  .site-header__nav-toggle { display: none; }
}

.site-header__search {
  display: block;
  border-top: var(--border-width-default) solid var(--color-border-200);
  padding-block: var(--space-4);
}

/* Progressive enhancement, same principle as .mobile-nav: visible by
   default (no-JS baseline), collapsed only once .js confirms JavaScript
   ran, shown again via .is-open (toggled by navigation.js). */
.js .site-header__search { display: none; }
.js .site-header__search.is-open { display: block; }

/* ---------- Mobile nav panel ---------- */

.mobile-nav {
  display: block;
  padding: var(--space-3);
  border-top: var(--border-width-default) solid var(--color-border-200);
}

.js .mobile-nav { display: none; }

/* Navigation v2.2 visual refinement — real bug found while checking "does
   the bottom bar clip content": .mobile-nav is a normal in-flow block
   inside <header> (position:static, not a fixed-height overlay like
   .catalog-filters), while setupDisclosure()'s exclusiveId:'mobile-nav'
   option locks the BODY's own scroll (.has-hitsiaijat-nav-lock {
   overflow:hidden }) the instant it opens. Before Navigation v2.2 the
   panel only ever held 5 short flat links, so its content never came
   close to viewport height and this was never reachable. Now that it can
   hold a "Soita meille" CTA + every top-level category (some expanded)
   + the secondary list, content can legitimately exceed a short phone's
   viewport height — with the body locked and no scroll of its own here,
   anything below the fold would be permanently unreachable. Giving the
   OPEN, JS-enhanced panel its own max-height + overflow-y fixes that,
   without touching the shared overlay coordinator itself. The no-JS
   baseline (no .js class, body never locked) is untouched — the plain
   page scroll already reaches everything in that case.
   60px = mobile .site-header__bar's own min-height (this file, ~line 150);
   64px = .mobile-bottom-bar__item's min-height (this file, below) — the
   fixed bottom bar the drawer must never render underneath. Same
   conservative-estimate-first approach already used for
   .catalog-filters (catalog.css) and the Mega Menu panel (mega-menu.js) —
   a little extra internal scroll if the real header is shorter than this
   estimate, never overflow. */
.js .mobile-nav.is-open {
  display: block;
  max-height: calc(100vh - 60px - 64px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* navigation.js's setupMobileNavMaxHeight() measures the panel's REAL
   current top edge (accounts for the optional top bar's real height,
   which the static estimate above can't know) and the real bottom bar
   height, then sets both this custom property and this class together in
   one operation — so this rule can never apply while the property is
   still unset. Added after the static rule specifically so it wins on
   source order once JS has run (same relationship the two mega-menu.css
   max-height rules already have to each other). */
.js .mobile-nav.is-open.has-measured-max-height {
  max-height: var(--mobile-nav-js-max-height);
}

.mobile-nav .site-nav__list {
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-1);
}

.mobile-nav .site-nav__list a {
  min-height: var(--touch-target-min);
}

@media (min-width: 1024px) {
  .mobile-nav { display: none; }
}

/* ---------- Mobile nav: "Soita meille" (Navigation v2.2, refined) ----------
   Compact SECONDARY cta — a tinted pill, not a full-bleed solid-brand-blue
   banner (the first version read as a primary CTA competing with the
   catalog for visual priority, which this drawer's real hierarchy is
   category-browsing first, "call us" as a fast-access option second).
   min-height stays var(--touch-target-min) (44px) — "compact" here means
   less visual weight/padding, never a smaller-than-44px hit area; that
   floor is an explicit, preserved requirement, not something this pass
   is allowed to trade away. inline-flex (not a full-width flex block) so
   it reads as a pill-shaped control, not a banner spanning the drawer. */
.mobile-nav__call {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--touch-target-min);
  margin-block-end: var(--space-3);
  padding-inline: var(--space-3);
  background-color: rgba(3, 61, 167, 0.12);
  border: var(--border-width-default) solid var(--color-brand-blue-600);
  border-radius: var(--radius-control);
  color: var(--color-text-default);
  font-weight: 600;
  font-size: var(--text-small-size);
  text-decoration: none;
}

.mobile-nav__call:hover {
  background-color: rgba(3, 61, 167, 0.2);
}

/* ---------- Mobile nav: category accordion (Navigation v2.2) ----------
   Same no-JS-safe contract as every other disclosure in this theme: a
   branch is real, in-flow, visible markup by default (inc/mega-menu.php's
   hitsiaijat_render_mobile_category_item()); only once navigation.js
   confirms the accordion elements exist (.mobile-nav-ready, mirroring
   catalog.css's .catalog-filters-ready — not the sitewide .js, so a failed
   script load never hides categories behind a broken toggle) does CSS
   collapse a non-open branch. */
.mobile-nav__section-title {
  margin: 0 0 var(--space-1);
  padding-inline: var(--space-2);
  font-size: var(--text-small-size);
  font-weight: 600;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.mobile-nav__cat-list,
.mobile-nav__cat-branch {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* Nesting must be unmistakable, not just technically present: a 2px
   (not 1px) accent-toned line reads clearly at a glance, matching the
   same "make the hierarchy obvious" intent as the catalog tree's own
   nested-list border (catalog.css). */
.mobile-nav__cat-branch {
  margin-inline-start: var(--space-4);
  padding-inline-start: var(--space-3);
  border-left: 2px solid var(--color-border-active);
  margin-block-start: var(--space-1);
}

.mobile-nav__cat-row {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 44px;
}

.mobile-nav__cat-toggle,
.mobile-nav__cat-toggle-spacer {
  flex: 0 0 auto;
}

.mobile-nav__cat-toggle {
  min-height: var(--touch-target-min);
  min-width: var(--touch-target-min);
}

.mobile-nav__cat-toggle svg {
  transition: transform var(--motion-fast) var(--motion-easing);
}

.mobile-nav__cat-toggle[aria-expanded='true'] svg {
  transform: rotate(180deg);
}

/* Focus-visible fix (component-scoped, Option A): real <button>, no .btn
   class — Astra's static button:focus (0,1,1) wins outline:0, confirmed
   live on the desktop tree-toggle sibling (same icon-button family). */
.mobile-nav__cat-toggle:focus-visible {
  outline: var(--border-width-active) solid var(--color-industrial-900);
  outline-offset: 2px;
}

/* Same width as the toggle button so a leaf category's name still starts at
   the same left edge as a category with children — see the spacer's own
   PHP-side comment in hitsiaijat_render_mobile_category_item(). */
.mobile-nav__cat-toggle-spacer {
  width: var(--touch-target-min);
  height: var(--touch-target-min);
}

.mobile-nav__cat-link {
  flex: 1 1 auto;
  min-width: 0;
  padding-inline: var(--space-1);
  text-decoration: none;
  font-weight: 500;
  color: var(--color-text-default);
}

/* Focus-visible fix (component-scoped, Option A): plain <a>, Astra's bare
   a:focus-visible (0,1,1) wins dotted/1px otherwise. */
.mobile-nav__cat-link:focus-visible {
  outline: var(--border-width-active) solid var(--color-industrial-900);
  outline-offset: 2px;
}

.mobile-nav-ready .mobile-nav__cat-branch {
  display: none;
}

.mobile-nav-ready .mobile-nav__cat-branch.is-open {
  display: flex;
}

/* Option B (mobile-catalog-depth audit, 2026-08-13): a depth-2/boundary
   category with real, currently-unrendered children (inc/mega-menu.php's
   hitsiaijat_mobile_annotate_node()) gets this one extra link, pointing at
   its own category page — where the catalog filter drawer already shows
   the full tree. Deliberately a quiet text row, not a second CTA: same
   left-edge alignment as the row's own name text (toggle/spacer width +
   the row's gap), muted color by default, and only the existing sitewide
   :focus-visible / hover states make it stand out — no new color token,
   no button styling. The small arrow reuses --color-brand-blue-600 (the
   same brand blue already used for the active-category accent elsewhere
   in this theme) rather than introducing a new hue. */
.mobile-nav__cat-more-link {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--touch-target-min);
  margin-inline-start: calc(var(--touch-target-min) + var(--space-1));
  padding-inline: var(--space-1);
  font-size: var(--text-small-size);
  font-weight: 500;
  text-decoration: none;
  color: var(--color-text-muted);
}

.mobile-nav__cat-more-link::after {
  content: '';
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-right: 2px solid var(--color-brand-blue-600);
  border-bottom: 2px solid var(--color-brand-blue-600);
  transform: rotate(-45deg);
}

.mobile-nav__cat-more-link:hover,
.mobile-nav__cat-more-link:focus-visible {
  color: var(--color-text-default);
  text-decoration: underline;
}

/* Focus-visible fix (component-scoped, Option A): a separate rule (not
   folded into the :hover,:focus-visible pair above) so the new outline
   applies on keyboard focus only, never on hover. Plain <a>, same Astra
   a:focus-visible conflict as every other unclassed link in this file. */
.mobile-nav__cat-more-link:focus-visible {
  outline: var(--border-width-active) solid var(--color-industrial-900);
  outline-offset: 2px;
}

/* ---------- Mobile nav: secondary list (Navigation v2.2) ----------
   Huoltopalvelu / Yhteystiedot / Oma tili / Ostoskori — visually separated
   from the category accordion above it, so the catalog isn't mixed into
   the same flat list with these account/service links (approved spec:
   "separate Huoltopalvelu/Yhteystiedot/Oma tili from the catalog list"). */
.mobile-nav__secondary {
  margin-block-start: var(--space-3);
  padding-block-start: var(--space-3);
  border-top: var(--border-width-default) solid var(--color-border-200);
}

/* Scroll lock applied by navigation.js while the mobile panel is open. */
.has-hitsiaijat-nav-lock {
  overflow: hidden;
}

/* ---------- Mobile bottom bar ---------- */

.mobile-bottom-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: var(--z-sticky);
  display: flex;
  background-color: var(--color-bg-dark);
  padding-bottom: env(safe-area-inset-bottom, 0);
}

.mobile-bottom-bar__item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: 64px;
  text-decoration: none;
  color: var(--color-text-on-dark);
  /* Live root font-size on this site is 14.592px, not the 16px assumed
     the first time — confirmed via getComputedStyle(document.documentElement)
     on the real staging page, not guessed. That made the earlier 0.75rem
     resolve to only 10.944px, still below the 12px floor the owner asked
     for. max() guarantees an actual 12px regardless of the site's real
     root size, while staying rem-based (0.75rem) so it still scales up
     for a visitor's own larger browser/zoom font-size setting. */
  font-size: max(0.75rem, 12px);
  font-weight: 600;
}

/* Active item: filled brand-blue background + white text (same pairing as
   .btn--brand) instead of the previous underline-only treatment — reads
   clearly against the bar's dark background at a glance. */
.mobile-bottom-bar__item.is-active {
  background-color: var(--color-brand-blue-600);
  color: var(--color-text-on-dark);
}

/* Focus-visible fix (component-scoped, Option A, dark group): this bar's
   own background-color is --color-bg-dark directly (not wrapped in
   .section--dark), so it gets none of that class's dark-surface
   :focus-visible tie either — plain <a>, Astra's bare a:focus-visible
   (0,1,1) wins dotted/1px otherwise. --color-focus-on-dark (not
   industrial-900, which would disappear against this dark bar) — same
   reasoning already used for .hitsiaijat-scroll-top and
   .site-topbar__item. */
.mobile-bottom-bar__item:focus-visible {
  outline: var(--border-width-active) solid var(--color-focus-on-dark);
  outline-offset: 2px;
}

/* Legacy Code Snippets bottom bar (class `.hitsi-mobile-bar`, Code Snippets
   plugin id=7, registered on wp_footer at priority 40 — read via read-only
   SSH/WP-CLI audit, not guessed) renders after and visually on top of our
   own bar above: its mobile-width rule is `.hitsi-mobile-bar{display:grid}`
   at specificity (0,1,0), so `body .hitsi-mobile-bar` at (0,1,1) overrides
   it without !important. Only suppresses that one class's display; the
   snippet itself, its footer grid, and its other hitsi-* elements are
   untouched. */
body .hitsi-mobile-bar {
  display: none;
}

@media (min-width: 1024px) {
  .mobile-bottom-bar { display: none; }
}

/* Reserve room so the fixed bar never covers page content; only applied
   when the bar is actually rendered (inc/header.php skips both the bar
   and this body class on checkout). */
body.has-hitsiaijat-bottom-bar {
  padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px) + var(--space-4));
}

@media (min-width: 1024px) {
  body.has-hitsiaijat-bottom-bar { padding-bottom: 0; }
}

/* ---------- Scroll to top (Phase B3) ----------
 * #ast-scroll-top is Astra's own confirmed real id (not a guessed
 * selector) for its native scroll-to-top <div> — see inc/scroll-top.php
 * for exactly why it's replaced rather than restyled. Hidden outright,
 * not just visually de-emphasized: Astra's own frontend.min.js keeps
 * re-setting this element's inline `style="display:block"` on every
 * scroll event, and only an !important stylesheet rule outranks that. */
#ast-scroll-top {
  display: none !important;
}

/* .icon-button (components.css) already supplies display:inline-flex,
   centering, background:none, border:none, cursor:pointer AND (Phase
   B3.1) padding:0 — this only adds what a fixed, floating, sized-and-
   colored control needs on top of that shared base (same technique as
   .site-header__nav-toggle, Phase B1). Explicit width/height (not
   min-width/min-height) so it's exactly 48x48, not just "at least" 48x48;
   the padding:0 this needed locally before B3.1 now lives in .icon-button
   itself, since the same Astra padding leak turned out to affect every
   icon-only control in the theme, not just this one — see that rule's
   own comment in components.css for the full mechanism and the audit
   confirming every .icon-button usage is icon-only. */
.hitsiaijat-scroll-top {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: var(--z-sticky);
  width: 48px;
  height: 48px;
  border-radius: var(--radius-control);
  background-color: var(--color-bg-dark);
  color: var(--color-text-on-dark);
  box-shadow: var(--shadow-header-sticky);
  transition: background-color var(--motion-fast) var(--motion-easing),
    color var(--motion-fast) var(--motion-easing);
}

/* Belt-and-suspenders with the [hidden] attribute assets/js/scroll-top.js
   toggles: the UA default `[hidden]{display:none}` already covers this,
   but being explicit here means it can never be silently defeated by a
   more specific display rule added to this file later. */
.hitsiaijat-scroll-top[hidden] {
  display: none;
}

.hitsiaijat-scroll-top:hover,
.hitsiaijat-scroll-top:focus-visible {
  background-color: var(--color-brand-blue-700);
  color: var(--color-text-on-dark);
}

/* Explicit override, not the sitewide default outline (base.css,
   industrial-900): this button floats over arbitrary page backgrounds —
   sometimes dark ones (its own fill is --color-bg-dark) — where a near-
   black outline could disappear. --color-focus-on-dark (white) stays
   visible against both light and dark backdrops, the same reasoning
   .section--dark :focus-visible already uses.
   Focus-visible audit (2026-08-13/14) found this color-only override was
   never actually visible: Astra's static button:focus (0,1,1) sets
   outline:0px, and the sitewide base :focus-visible rule this was
   assumed to layer on top of (outline-style/-width) loses to that same
   Astra rule for any unclassed <button> — confirmed live, an outline of
   zero width. Now sets the full shorthand itself instead of relying on
   the losing base rule for style/width. */
.hitsiaijat-scroll-top:focus-visible {
  outline: var(--border-width-active) solid var(--color-focus-on-dark);
  outline-offset: 2px;
}

/* Overlay coordination: hidden and inert (display:none removes it from
   the tab order too) whenever the shared mobile-nav/catalog-drawer lock
   is active (window.hitsiaijatOverlays, navigation.js / catalog-
   filters.js) — it must never sit on top of, or stay keyboard-reachable
   underneath, an open drawer. The search panel deliberately does not set
   this class (it's non-modal, doesn't lock scroll — see navigation.js)
   and isn't positioned anywhere near this button, so no separate rule is
   needed for it. Desktop's mega-menu dropdown doesn't use this lock class
   either, but its own z-index (--z-dropdown, 200) already outranks this
   button's (--z-sticky, 100), so it renders above without needing a rule
   here. */
body.has-hitsiaijat-nav-lock .hitsiaijat-scroll-top {
  display: none !important;
}

/* Mobile/tablet: clear the fixed .mobile-bottom-bar (64px) plus its own
   safe-area inset, plus a visible gap, instead of the desktop 24px
   offset — reuses the exact same height + env() this bar's own
   body.has-hitsiaijat-bottom-bar padding-bottom rule above uses, so the
   two can never drift apart. Scoped to that body class the same way that
   rule is, so checkout (which skips the bottom bar entirely) correctly
   falls back to the plain desktop offset instead of leaving a phantom
   gap. */
@media (max-width: 1023.98px) {
  body.has-hitsiaijat-bottom-bar .hitsiaijat-scroll-top {
    bottom: calc(64px + env(safe-area-inset-bottom, 0px) + var(--space-4));
  }
}

@media (prefers-reduced-motion: reduce) {
  .hitsiaijat-scroll-top {
    transition: none;
  }
}

/* ---------- Footer ---------- */

/* Phase B4: compact + lighter-feeling, still dark. padding-block was
   coming entirely from the shared .section class (components.css,
   --space-8/64px below 1024px, --space-9/96px at/above it) — this
   selector has equal specificity (one class each) but loads later in the
   enqueue chain (hitsiaijat-header-footer depends on hitsiaijat-
   components), so it wins by source order without needing !important.
   The top border is the "visually lighter/structured" seam against the
   lighter content above it — brand blue, not the neutral alternative, to
   tie back to the same accent used by the hero's own accent-bar and the
   active nav underline. (TASK UI-2, owner-approved: supersedes an earlier
   decision that had explicitly ruled out blue for this one component —
   the full-site yellow-removal pass now covers it too.) */
.site-footer {
  padding-block: var(--space-6);
  border-block-start: var(--border-width-active) solid var(--color-brand-blue-600);
}

.site-footer__nav-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.site-footer__nav-list a,
.site-footer .stack a {
  color: var(--color-text-on-dark);
  text-decoration: none;
}

/* Focus-visible fix (component-scoped, Option A, dark group): <footer
   class="site-footer section section--dark"> already ties Astra's
   a:focus-visible via .section--dark :focus-visible (base.css), but that
   only wins outline-color (source-order tiebreak on an equal-specificity
   tie) — outline-style/-width still come from the losing bare
   :focus-visible and stay Astra's dotted/1px, confirmed live on the
   topbar's identical partial-fix pattern. .site-footer .stack a also
   covers .site-footer__brand (the brand link is itself inside a .stack),
   so no separate selector is needed for it. */
.site-footer__nav-list a:focus-visible,
.site-footer .stack a:focus-visible {
  outline: var(--border-width-active) solid var(--color-focus-on-dark);
  outline-offset: 2px;
}

.site-footer__brand {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-h3-size-mobile);
  color: var(--color-text-on-dark);
  text-decoration: none;
}
