/**
 * Velonix Labs — Layout Components
 * Header, navigation, announcement bar, footer, and the persistent bottom
 * ticker. Loaded on every page (these render via get_header()/get_footer()
 * and are identical everywhere by construction — see template-parts/).
 */

/* ===== header ===== */
header{background:var(--bg); border-bottom:1px solid var(--line); position:relative; z-index:5;}
.nav{display:grid; grid-template-columns:auto 1fr auto; align-items:center; column-gap:56px; height:var(--header-height);}
.logo{font-weight:600; font-size:18px;}
.logo span{color:var(--accent);}
/* Fixed render size for the WordPress custom logo (the_custom_logo()),
   independent of the uploaded file's native dimensions. height + width:auto
   preserves the logo's own aspect ratio automatically — upload any size,
   it always renders at the approved height. */
.logo img.custom-logo, .logo img{height:var(--header-logo-height-desktop); width:auto; max-width:none; display:block;}
@media (max-width:1023px){ .logo img{height:var(--header-logo-height-tablet);} }
@media (max-width:767px){ .logo img{height:var(--header-logo-height-mobile);} }
.navlinks{display:flex; justify-content:center; gap:40px; font-size:14px; color:var(--ink-soft);}
.navlinks a:hover{color:var(--ink);}
.navright{display:flex; align-items:center; justify-self:end; gap:20px;}
/* flex-shrink:0 on both the link and the svg — belt-and-suspenders
   against the icon collapsing to zero width if .navright's content
   ever gets tighter than expected in a real flex layout (a fixed-size
   icon button has no business shrinking at all, and without an
   explicit flex-shrink:0 it inherits the flex default of 1, i.e.
   allowed to shrink). Investigated exhaustively for a specific rule
   that could be doing this and found none, but this is correct,
   defensive sizing for a small fixed icon regardless of the exact
   cause, and removes the possibility entirely rather than leaving it
   to chance. */
.icon-btn{color:var(--ink-soft); display:flex; position:relative; flex-shrink:0; min-width:var(--icon-md);}
.icon-btn svg{width:var(--icon-md); height:var(--icon-md); flex-shrink:0; color:inherit;}
.icon-btn .cart-count{position:absolute; top:-6px; right:-8px; background:var(--accent); color:#0D1017; font-family:'IBM Plex Mono',monospace; font-size:10px; font-weight:600; min-width:16px; height:16px; border-radius:8px; display:flex; align-items:center; justify-content:center; padding:0 4px;}

/* ===== mobile navigation ===== */
/* Desktop default: .nav-panel is invisible as a wrapper (display:contents
   means its children participate directly in the parent .nav grid, as
   if .nav-panel weren't there at all), so .navlinks still lands in the
   grid's middle auto/1fr/auto column exactly as before, and the
   mobile-only CTA duplicate stays hidden. */
.nav-panel{ display:contents; }
.nav-panel-cta{ display:none; }
.navright > a.btn-secondary{ display:inline-flex; }
/* Same display:contents technique as .nav-panel above — on desktop
   this wrapper is invisible, so .nav-toggle (hidden anyway via
   display:none below) and .navright still participate directly in
   the grid's third column exactly as if this wrapper didn't exist. */
.nav-mobile-cluster{ display:contents; }

/* ===== mobile navigation ===== */
.nav-toggle{
  display:none; /* shown only below the breakpoint, see media query */
  flex-direction:column; align-items:center; justify-content:center;
  gap:5px; width:36px; height:36px; padding:0;
  background:transparent; border:none; cursor:pointer;
}
.nav-toggle span{
  display:block; width:20px; height:2px; background:var(--ink);
  border-radius:1px;
  transition:transform 0.2s ease, opacity 0.2s ease;
}
/* aria-expanded is the single source of truth for open/closed —
   navigation.js only ever toggles that attribute, both the icon
   animation and the panel visibility read from it, so they can never
   drift out of sync with each other. */
.nav-toggle[aria-expanded="true"] span:nth-child(1){ transform:translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2){ opacity:0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3){ transform:translateY(-7px) rotate(-45deg); }

@media (max-width:900px){
  .nav-toggle{ display:flex; }

  /* .nav-panel (not .navlinks itself) is what gets taken out of the
     grid's normal flow (position:absolute), because it also has to
     carry .nav-panel-cta below the links — see the header.php doc
     comment for why that duplicate link exists. Using .is-open on
     .nav (toggled by navigation.js alongside aria-expanded, never
     instead of it — aria-expanded is set first and is what assistive
     tech reads; the class is purely this CSS hook) rather than a
     sibling-combinator selector off aria-expanded directly: the
     toggle button isn't even a direct sibling of .nav-panel at all
     (it's nested inside .nav-mobile-cluster — see header.php), so a
     `~`/`+` selector from the button could never reach .nav-panel. */
  .nav-panel{
    display:flex; flex-direction:column; align-items:stretch; gap:0;
    position:absolute; top:100%; left:0; right:0;
    background:var(--bg); border-bottom:1px solid var(--line);
    max-height:0; overflow:hidden; visibility:hidden;
    transition:max-height 0.25s ease, visibility 0.25s ease;
  }
  .nav.is-open .nav-panel{
    max-height:70vh; overflow-y:auto; visibility:visible;
  }
  .navlinks{ display:flex; flex-direction:column; }
  .navlinks a{ padding:16px 40px; border-bottom:1px solid var(--line); }
  .nav-panel-cta{ display:flex; margin:20px 40px; }
  .navright > a.btn-secondary{ display:none; }

  /* Root cause of a reported "basket icon positioned partially
     off-screen on mobile": .nav's column-gap (56px, tuned for the
     desktop layout's generous 3-column spacing) was never reduced for
     mobile, and — the more important part — was never actually robust
     against a real uploaded logo image being wider than the short
     text logo used while testing (which happened to still fit,
     narrowly, masking the underlying fragility).
     .nav-panel is position:absolute at this breakpoint (above), which
     removes it from grid placement entirely — so the grid genuinely
     only has two in-flow items to place at mobile: the logo, and this
     cluster. Reducing to two explicit tracks and letting the cluster
     hug the second track's right edge (justify-self:end) means the
     available width is spent on real content instead of a fixed,
     oversized gap between three separately-placed items. */
  .nav{ grid-template-columns:auto 1fr; }
  .nav-mobile-cluster{
    display:flex; align-items:center; gap:16px;
    justify-self:end;
  }
  /* Reorders to Logo -> Basket -> Hamburger — requested because it's
     the convention most ecommerce sites use, and because it stops the
     basket being the single rightmost, edge-hugging element (it now
     has the hamburger to its right instead, with a comfortable 16px
     gap of its own). Flex order only, scoped to this media query —
     desktop's .nav-mobile-cluster is display:contents (no flex
     context at all there), so this has zero effect outside mobile. */
  .navright{ order:1; }
  .nav-toggle{ order:2; }

  /* Hamburger menu now stays focused on secondary navigation — the
     Peptide Calculator link (auto-injected by
     velonix_add_calculator_to_primary_nav(), inc/template-tags.php,
     tagged with this exact class for this purpose) and the My Account
     icon are both reachable from the mobile bottom navigation instead
     (template-parts/bottom-nav.php), so showing them here too would
     just be a duplicate path to the same two destinations. Neither
     rule touches desktop: the calculator link keeps its place in the
     top nav there, and .my-account-icon has no bottom nav to be
     redundant with. */
  .navlinks .nav-item-calculator{ display:none; }
  .navright .my-account-icon{ display:none; }
}

/* ===== announcement bar ===== */
.announce-bar{background:var(--accent-deep); border-bottom:1px solid rgba(0,0,0,0.2); padding:15px 0; position:relative; box-shadow:0 2px 8px rgba(0,0,0,0.18);}
.announce-bar .wrap{display:flex; align-items:center; justify-content:center; gap:12px; flex-wrap:wrap; font-size:14.5px; font-weight:600; letter-spacing:0.01em; color:#F5F7FF; text-align:center; position:relative; padding-left:32px; padding-right:32px;}
.announce-bar .code{font-family:'IBM Plex Mono',monospace; color:#FFFFFF; font-weight:700; letter-spacing:0.03em; background:rgba(255,255,255,0.16); padding:2px 8px; border-radius:4px;}
.announce-bar .sep{color:rgba(255,255,255,0.45);}
.announce-bar .dismiss{position:absolute; right:0; top:50%; transform:translateY(-50%); background:none; border:none; color:rgba(255,255,255,0.7); cursor:pointer; font-size:18px; line-height:1; padding:4px 6px;}
.announce-bar .dismiss:hover{color:#fff;}

/* ===== announcement bar — mobile ===== */
@media (max-width:767px){
  /* Root cause of the stray dot: .announce-bar .wrap is display:flex
     with flex-wrap:wrap (above) — on desktop the two message segments
     and the .sep bullet between them all fit on one line, so the wrap
     never triggers. At mobile widths the two text segments each need
     their own line, and flex-wrap doesn't know the bullet is meant to
     sit "between" them semantically — it just wraps each of the three
     span elements independently, so .sep (real content, a genuine
     <span>, not a pseudo-element or a slider dot) ends up alone on its
     own orphaned middle line. Confirmed by rendering and measuring the
     actual computed position of each span before writing this fix, not
     assumed.

     flex-direction:column makes the two message spans stack onto their
     own full-width lines deterministically (not "however flex-wrap
     happens to fit them" — an actual designed 2-row layout, not 3).
     .sep is then display:none — not visibility:hidden or opacity:0,
     which would still occupy layout space and leave a gap where the
     dot used to orphan itself; display:none removes it from the
     render tree entirely, which is what "remove it completely" means
     here. A bullet only makes sense as an inline conjunction between
     two segments on the same line anyway, so hiding it once they're
     stacked isn't a workaround — it's the correct treatment once the
     two segments no longer share a line. */
  .announce-bar{padding:10px 0;}
  .announce-bar .wrap{
    flex-direction:column;
    gap:4px;
    padding-left:40px;
    padding-right:44px;
    font-size:13.5px;
  }
  .announce-bar .sep{display:none;}
  .announce-bar .code{font-size:12px; padding:1px 6px;}

  /* Larger invisible tap area around the same visual glyph, rather
     than a bigger icon — keeps the compact feel while bringing the
     tappable area close to the ~44px touch-target guideline (WCAG
     2.5.5). The bar's own height (padding above + two ~19px text
     lines + 4px gap ≈ 62px total) comfortably contains this without
     the button visually overflowing the bar's edges — verified by
     rendering and measuring both together, not assumed independently. */
  .announce-bar .dismiss{padding:12px 14px;}
}

/* ===== footer — journal back-matter style ===== */
.footer-v2{padding-top:76px; border-top:1px solid var(--line);}
.footer-masthead{display:flex; align-items:center; justify-content:space-between; padding-bottom:32px;}
.footer-masthead-brand{font-family:'Plus Jakarta Sans',sans-serif; font-weight:600; font-size:20px;}
.footer-masthead-brand img.custom-logo, .footer-masthead-brand img{height:var(--footer-logo-height-desktop); width:auto; max-width:none; display:block;}
@media (max-width:1023px){ .footer-masthead-brand img{height:var(--footer-logo-height-tablet);} }
@media (max-width:767px){ .footer-masthead-brand img{height:var(--footer-logo-height-mobile);} }
.footer-masthead-tag{font-size:12px; color:var(--ink-faint); font-family:'IBM Plex Mono',monospace; letter-spacing:0.02em;}
.footer-index{display:grid; grid-template-columns:repeat(4,1fr); gap:40px; padding:44px 0 40px; border-bottom:1px solid var(--line);}
@media (max-width:1023px){ .footer-index{grid-template-columns:repeat(2,1fr); gap:32px 24px;} }
@media (max-width:767px){ .footer-index{grid-template-columns:1fr; gap:32px;} }
.footer-index-num{font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--ink-faint); margin-bottom:14px;}
.footer-index-col h5{font-size:12px; text-transform:uppercase; letter-spacing:0.05em; color:var(--ink-soft); font-weight:600; margin-bottom:16px;}
.footer-index-col a{display:block; font-size:var(--text-body-sm); color:var(--ink-soft); margin-bottom:11px;}
.footer-index-col a:hover{color:var(--ink);}
.footer-subscribe p{font-size:var(--text-body-sm); color:var(--ink-soft); line-height:1.6; margin-bottom:14px;}

/* .footer-inline-form (below) was the old static, non-functional
   placeholder markup's styling — no longer used by the current
   WPForms-driven markup (see footer.php), but kept rather than
   deleted, per project convention, in case of rollback. The rules
   below reproduce the exact same visual treatment
   (flex row, borderless underline field, accent text-only button) on
   top of WPForms' own generated markup instead. */
.footer-inline-form{display:flex; border-bottom:1px solid var(--line); padding-bottom:8px;}
.footer-inline-form input{flex:1; background:transparent; border:none; color:var(--ink); font-family:'Inter',sans-serif; font-size:var(--text-body-sm); outline:none;}
.footer-inline-form input::placeholder{color:var(--ink-faint);}
.footer-inline-form button{background:none; border:none; color:var(--accent); font-size:14px; cursor:pointer;}

/* ===== footer newsletter — WPForms Lite CSS-only reskin =====
   Everything below targets WPForms' own default, documented, stable
   class names (.wpforms-container, .wpforms-field-email,
   .wpforms-submit, etc.) — no template override, nothing plugin-side
   touched. Scoped under .footer-subscribe specifically so none of this
   can leak into the Contact page's own, separately-configured WPForms
   instance. Reproduces the exact same look .footer-inline-form had:
   one flex row, a shared bottom border, a borderless input, and a
   text-only accent-coloured submit button — visitors shouldn't be
   able to tell it's a plugin.

   !important is used only on .wpforms-submit: WPForms commonly applies
   its own button colour/padding via an ID-based selector or an inline
   style from the form's own Style settings in wp-admin, either of
   which would otherwise out-specificity a plain class selector here. */
.footer-subscribe .wpforms-container{ margin:0; }
.footer-subscribe .wpforms-form{
  display:flex; align-items:center; gap:8px;
  border-bottom:1px solid var(--line); padding-bottom:8px;
  transition:border-color 0.18s ease;
}
.footer-subscribe .wpforms-form:focus-within{ border-color:var(--accent); }

.footer-subscribe .wpforms-field-container{ flex:1; }
.footer-subscribe .wpforms-field{ margin:0; padding:0; }
.footer-subscribe .wpforms-field-label,
.footer-subscribe .wpforms-required-label{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;
}
.footer-subscribe .wpforms-field-email input,
.footer-subscribe .wpforms-field input[type="email"]{
  width:100%; max-width:none; background:transparent; border:none; padding:0;
  color:var(--ink); font-family:'Inter',sans-serif; font-size:var(--text-body-sm);
  outline:none; box-shadow:none;
}
.footer-subscribe .wpforms-field input::placeholder{ color:var(--ink-faint); opacity:1; }

.footer-subscribe .wpforms-submit-container{ margin:0; }
.footer-subscribe .wpforms-submit{
  background:none !important; border:none !important; box-shadow:none !important;
  color:var(--accent) !important; font-family:'Inter',sans-serif; font-weight:600; font-size:14px;
  padding:0 !important; margin:0 !important; border-radius:0 !important; text-transform:none !important;
  cursor:pointer; white-space:nowrap;
}
.footer-subscribe .wpforms-submit:hover{ color:var(--accent-deep) !important; }

.footer-subscribe .wpforms-error{ color:#E0857D; font-size:12px; margin-top:6px; }
.footer-subscribe .wpforms-confirmation-container-full{ color:var(--ink-soft); font-size:var(--text-body-sm); margin:0; }
.footer-subscribe noscript.wpforms-error-noscript{ display:none; }

/* Colophon + imprint — previously the smallest, lowest-contrast text on
   the entire site (11.5px, --ink-faint) despite being genuine prose
   meant to be read, not a caption. Brought up to the same body-text
   scale as everything else (research-notice, trust cards) and the more
   readable --ink-soft tone, consistent with the rest of the footer. */
/* Legal block — previously three separate stacked elements (colophon,
   legal, copy) with inconsistent spacing and an unstyled right column.
   Now one balanced two-column block: disclaimer + Janoshik statement on
   the left, company registration + copyright on the right — mirroring
   the same two-column grid pattern already used throughout the site
   (.quality-grid, .why-grid), rather than a left-aligned stack.
   Gap values (12px, 64px) and padding (28px/56px) reuse existing spacing
   already established elsewhere in the theme, not new one-off values. */
.footer-legal-block{display:grid; grid-template-columns:1fr 1fr; gap:12px 64px; padding:28px 0 56px;}
.footer-legal-col p{font-size:var(--text-body-sm); color:var(--ink-soft); line-height:var(--text-body-sm-line-height); margin-bottom:12px;}
.footer-legal-col p:last-child{margin-bottom:0;}

@media (max-width:767px){
  .footer-legal-block{grid-template-columns:1fr; gap:20px;}
}

/* ===== bottom announcement ticker — REMOVED =====
   Replaced entirely by the announcement popup (template-parts/
   announcement-popup.php), per an explicit decision to remove the
   ticker rather than keep it — unlike other retired code in this
   theme (e.g. the old static newsletter placeholder), this was a
   deliberate, unambiguous "remove it completely" instruction, not an
   ambiguous case where keeping unused CSS around was the safer
   default. template-parts/ticker.php and its Customizer setting
   (velonix_ticker_message) are gone too. The body{padding-bottom}
   this component needed (to keep its fixed position from covering
   footer content) has been replaced by an equivalent rule for the new
   .bottom-nav below, which needs the same kind of space reserved for
   the same reason. */

/* ===== mobile bottom navigation =====
   Hidden entirely by default (desktop reaches Catalogue/Track/
   Calculator/Account the existing way — top nav + navright icons — so
   this never needs to exist there at all, not just be visually hidden)
   and only becomes a real fixed bar inside the mobile media query
   below. Reuses the exact same 900px breakpoint as the hamburger
   toggle elsewhere in this header, for the same reason: that's the
   verified width where the standard top nav genuinely stops fitting,
   not a guessed number. */
.bottom-nav{ display:none; }

@media (max-width:900px){
  .bottom-nav{
    display:flex;
    position:fixed; left:0; right:0; bottom:0; z-index:45;
    background:var(--bg); border-top:1px solid var(--line);
    box-shadow:0 -2px 12px rgba(0,0,0,0.25);
    /* iPhone safe-area support: on notched/home-indicator devices this
       keeps the row of icons clear of the gesture bar rather than
       sitting underneath it. env() falls back to 0 on devices without
       a safe area, so this is a no-op everywhere else. */
    padding-bottom:env(safe-area-inset-bottom, 0px);
  }
  .bottom-nav-item{
    flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center;
    gap:3px; padding:9px 4px 7px; color:var(--ink-faint); text-decoration:none;
    font-size:10.5px; font-weight:600; letter-spacing:0.01em;
    transition:color 0.18s ease;
  }
  .bottom-nav-item svg{ width:22px; height:22px; }
  .bottom-nav-item.is-active{ color:var(--accent); }

  /* Reserves space at the bottom of the viewport so this fixed bar
     never covers footer content — the same purpose (and the same
     technique) the old ticker's body{padding-bottom} served. Height
     budget: ~9px top padding + 22px icon + 3px gap + ~13px label text
     + 7px bottom padding ≈ 54px content, plus the safe-area inset on
     top of that for notched devices. */
  body{ padding-bottom:calc(54px + env(safe-area-inset-bottom, 0px)); }
}

/* ===== announcement popup =====
   Replaces the bottom ticker entirely — see the note above .bottom-nav
   and in footer.php. Site-wide (every page except Cart/Checkout, where
   template-parts/announcement-popup.php simply doesn't render it), so
   this lives in layout.css alongside the other global chrome rather
   than a page-scoped file.

   General-purpose announcement content (title + message, both
   Customizer-editable — velonix_popup_title/velonix_popup_message,
   inc/customizer.php), not a form — this used to embed a WPForms
   newsletter signup and had a matching CSS reskin for that plugin
   markup; both are gone now that the popup is plain text, along with
   the old .newsletter-popup class names throughout. */
.announcement-popup{ display:none; }
.announcement-popup.is-open{ display:block; }

.announcement-popup-backdrop{
  position:fixed; inset:0; z-index:300;
  background:rgba(10,12,16,0.7);
  opacity:0; transition:opacity 0.25s ease;
}
.announcement-popup.is-open .announcement-popup-backdrop{ opacity:1; }

.announcement-popup-card{
  position:fixed; top:50%; left:50%; z-index:301;
  transform:translate(-50%,-50%) scale(0.96);
  width:calc(100% - 48px); max-width:440px;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--radius-lg);
  padding:40px; text-align:center;
  opacity:0; transition:opacity 0.25s ease, transform 0.25s ease;
}
.announcement-popup.is-open .announcement-popup-card{ opacity:1; transform:translate(-50%,-50%) scale(1); }
.announcement-popup-card .eyebrow{ justify-content:center; }
.announcement-popup-card h2{ font-size:24px; margin:8px 0 12px; }
.announcement-popup-card p{ color:var(--ink-soft); font-size:var(--text-body-sm); line-height:1.7; margin:0; }

.announcement-popup-close{
  position:absolute; top:16px; right:16px;
  background:none; border:none; color:var(--ink-faint);
  font-size:22px; line-height:1; cursor:pointer; padding:8px;
}
.announcement-popup-close:hover{ color:var(--ink); }

body.announcement-popup-open{ overflow:hidden; }

@media (max-width:600px){
  .announcement-popup-card{ padding:32px 24px; }
}
