/* ============================================================
   Ink Fusion v28 — layout: nav, footer, section frame, hero shell
   ============================================================ */

/* line-hover link */
.lh { position: relative; }
.lh::after {
  content: ""; position: absolute; left: 0; bottom: -3px; width: 100%; height: 2.5px;
  background: var(--ink); transform: scaleX(0); transform-origin: right; transition: transform 0.3s var(--ease);
}
@media (pointer: fine) {
  .lh:hover::after { transform: scaleX(1); transform-origin: left; }
}
/* Keyboard users got no nav feedback at all — the underline was hover-only. */
.lh:focus-visible::after { transform: scaleX(1); transform-origin: left; }
.lh:focus-visible { outline: 3px solid var(--ink); outline-offset: 4px; }

/* nav */
header { position: sticky; top: 0; z-index: 900; background: var(--paper); border-bottom: 2px solid var(--ink); }

/*
 * The PHP templates lose the chrome to GeneratePress, two ways.
 *
 * Measured on /login/ and /cart/ 2026-08-27, and live on production:
 *
 * 1. BACKGROUND. Those templates emit <header class="site-header">, which is
 *    the exact class GeneratePress styles. Its `.site-header { background:#fff }`
 *    is specificity (0,1,0) and beats the bare `header` rule above at (0,0,1),
 *    so the header rendered WHITE instead of paper. Static pages emit a bare
 *    <header> with no class, which is the only reason they escaped it.
 *
 * 2. LINKS. GeneratePress also emits inline `a { color: var(--accent) }` and
 *    `a { text-decoration: underline }`. Both are bare `a` at (0,0,1) and land
 *    LATER in the cascade than base.css's `a { color: inherit; ... }`, so they
 *    win on source order — the nav rendered in WordPress blue, underlined, on
 *    cart, checkout, login, signup, my-account and 404.
 *
 * Fixed on specificity rather than by renaming the class or reordering
 * stylesheets: `header.site-header` is (0,1,1) and `header a` is (0,0,2), so
 * both win wherever they are loaded from and whatever order the theme emits.
 * Scoped to the chrome, so nothing in a page body or a builder is touched.
 *
 * These are no-ops on the static pages, which already render correctly.
 */
header.site-header { background: var(--paper); }
header { color: var(--ink); }
header a, footer a { color: inherit; text-decoration: none; }
.nav { max-width: var(--maxw); margin: 0 auto; padding: 14px 48px; display: flex; align-items: center; justify-content: space-between; }
.brand {
  font-family: var(--f-display); font-weight: 800; font-size: 22px; letter-spacing: -0.02em;
  text-transform: uppercase; display: flex; align-items: center; gap: 10px;
}
.brand .sq { display: flex; gap: 2px; }
.brand .sq i { width: 7px; height: 18px; }
.brand .sq i:nth-child(1) { background: var(--cyan); }
.brand .sq i:nth-child(2) { background: var(--mag); }
.brand .sq i:nth-child(3) { background: var(--yel); }
.nav .links { display: flex; gap: 22px; align-items: center; }
.nav .links a { font-weight: 600; font-size: 14px; }
.nav .links a.active::after { transform: scaleX(1); transform-origin: left; }
.nav .cta {
  font-weight: 700; font-size: 14px; background: var(--ink); color: var(--paper);
  padding: 11px 20px; border: 2px solid var(--ink); box-shadow: 4px 4px 0 var(--cyan);
  transition: transform var(--dur-state) var(--ease-state), box-shadow var(--dur-state) var(--ease-state);
}
.nav .cta:hover { box-shadow: 2px 2px 0 var(--mag); transform: translate(2px, 2px); }
.nav .burger { display: none; flex-direction: column; gap: 4px; }
.nav .burger i { width: 22px; height: 2.5px; background: var(--ink); }
/* Burger takes over at 1240px — RAISED from 1100px, 2026-09-01.

   The 1100 figure below was measured correctly and then invalidated twice: the
   header cart (44px) was added to .nav afterwards, and the nav grew a "Start a
   print" CTA. Re-measured on staging with a nowrap probe: wordmark 246 + link
   row 799 + cart 44 + 96px padding = a 1185px viewport minimum, against a
   breakpoint of 1100. So between 1101 and 1185 the desktop nav rendered with
   nowhere to go.

   It did not overflow, which is why nobody saw it. .links is flex-wrap: nowrap,
   so instead of the ROW wrapping, the anchors shrank and the LABELS wrapped
   inside them: at 1150px "Gang Sheets", "Custom DTF" and "My Account" each
   rendered 42px tall instead of 21, three names broken in half, burger still
   hidden. (The labels are now bound with &nbsp; in the renderer as well —
   inc/v28-chrome.php — so they can no longer break at all; that fix ALONE would
   have converted the squeeze into real horizontal overflow, which is worse.
   The two changes are one change and must ship together.)

   1240 is not a round number chosen for looks: it is --maxw. At or above it the
   nav is at its designed width; below it the nav is being squeezed, and that is
   exactly when the burger should take over. Nine items would need 1244 — which
   is why adding "Trade" to the nav (D1) cannot be done without also shortening
   a label or dropping one.

   Superseded note, kept for the arithmetic:
   Burger takes over at 1100px, not 820px — 2026-08-10 (T2-3).
   MEASURED, not guessed: with the links forced to nowrap the row needs 675px,
   plus a 246px wordmark and 96px of nav padding = a 1065px viewport minimum.
   Below 820px the burger appeared; between 821 and 1064 the desktop nav rendered
   inline and wrapped. That was ALREADY broken before this change — production
   showed 2 rows and 93px of overflow at 958px with the old nav — so this fixes a
   pre-existing defect rather than one the new nav introduced.
   1100 leaves a small margin over 1065 and stays clear of real laptop widths.
   The 820px query at .fgrid below is the FOOTER grid and is unrelated. */
@media (max-width: 1240px) {
  .nav .links a:not(.cta) { display: none; }
  .nav .burger { display: flex; }
  .nav { padding: 14px 20px; }

  /* CLUSTER THE CONTROLS RIGHT — 2026-08-10.
     .nav is justify-content: space-between, which is correct with a full nav but
     wrong once it collapses: with only brand / CTA / cart / burger left, the
     browser spread all four evenly and stranded "Start a print" and the cart in
     the middle of the header (measured at 1068px: CTA at x=454, cart at x=766,
     burger at x=999). Pushing the brand's auto-margin does the grouping. */
  .nav { justify-content: flex-start; gap: 10px; }
  .nav .brand { margin-right: auto; }
}
/* No header-cart styles here. The cart lives in the plugin
   (inkfusion-core/assets/header-cart.css) and injects itself as a direct child
   of .nav, so it is not affected by the .links collapse above. */

/* section frame */
section.blk { position: relative; padding: 92px 0; }
.tag {
  display: flex; align-items: center; gap: 14px; margin-bottom: 30px;
  font-family: var(--f-mono); font-size: 12px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
}
.tag .n { background: var(--ink); color: var(--paper); padding: 4px 10px; }
.tag .bar { height: 2px; flex: 1; background: var(--ink); }
.hd { max-width: 700px; margin-bottom: 46px; }
.hd h2 {
  font-family: var(--f-display); font-weight: 800; text-transform: uppercase; line-height: 0.94;
  font-size: clamp(34px, 5vw, 60px); letter-spacing: -0.02em; position: relative; display: inline-block;
}
.hd h2 em { font-style: normal; color: var(--mag); }
.hd p { margin-top: 14px; font-size: 17px; max-width: 520px; color: #3a352d; }

/* hero shell */
.hero { position: relative; padding: 52px 0 44px; overflow: hidden; }
.herobottom { display: grid; grid-template-columns: 1fr 0.82fr; gap: 48px; align-items: end; margin-top: 40px; }
@media (max-width: 860px) { .herobottom { grid-template-columns: 1fr; gap: 34px; } }
.hero p.sub { font-size: clamp(15px, 1.6vw, 18px); max-width: 440px; margin: 26px 0 30px; color: #3a352d; }
.actions { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; }
.spec { margin-top: 32px; display: flex; gap: 22px; flex-wrap: wrap; font-family: var(--f-mono); font-size: 12px; color: #3a352d; }
.spec b { color: var(--ink); background: var(--paper-2); padding: 2px 6px; border: 1px solid var(--line); }

/* footer */
footer { background: var(--ink); color: var(--paper); padding: 64px 0 34px; }
.fgrid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: 30px; margin-bottom: 44px; }
/* h3, not h5 — the footer columns were <h5> on every page, which skipped a
   level after page content that stops at h2/h3 and was axe's most common
   heading-order violation sitewide. h3 cannot skip from any preceding level.
   Both selectors kept so nothing depending on the old tag loses its styling. */
.fgrid h3, .fgrid h5 { font-family: var(--f-mono); font-size: 11px; letter-spacing: 0.16em; color: #b7b1a4; text-transform: uppercase; margin-bottom: 16px; }
.fgrid a { display: inline-block; color: #e6dfcd; font-size: 14px; padding: 5px 0; }
.fbrand .brand { color: var(--paper); margin-bottom: 14px; }
.fbrand p { color: #b7b1a4; font-size: 14px; max-width: 280px; }
/* social icon row (ACF-driven; only set networks render) — v28 CMYK motion */
.fsocial { display: flex; gap: 10px; margin-top: 18px; }
.fsocial a { position: relative; width: 38px; height: 38px; padding: 0; display: grid; place-items: center; border: 2px solid rgba(239, 233, 219, 0.28); color: var(--paper); transition: background .15s ease, color .15s ease, border-color .15s ease; }
.fsocial a svg { display: block; width: 19px; height: 19px; fill: currentColor; }
.fsocial__gly, .fsocial__layer { display: grid; place-items: center; }
.fsocial__layer { position: absolute; inset: 0; }
.fsocial__layer--c, .fsocial__layer--m { opacity: 0; }
.fsocial a:hover { color: var(--ink); }
.fsocial a:nth-child(1):hover { background: var(--cyan); border-color: var(--cyan); }
.fsocial a:nth-child(2):hover { background: var(--mag); border-color: var(--mag); }
.fsocial a:nth-child(3):hover { background: var(--yel); border-color: var(--yel); }
.fsocial a:nth-child(4):hover { background: var(--orange); border-color: var(--orange); }

/* one signature motion per network, always gently looping (staggered) */
@keyframes fsIgPress { 0%,72%,100% { transform: scale(1); } 78% { transform: scale(.82); } 86% { transform: scale(1.06); } 92% { transform: scale(1); } }
@keyframes fsIgRing  { 0%,72% { transform: scale(.55); opacity: 0; } 79% { opacity: .85; } 100% { transform: scale(1.7); opacity: 0; } }
@keyframes fsTtBase  { 0%,60%,100% { transform: translate(0,0); } 70% { transform: translate(1px,-1px); } 82% { transform: translate(-1px,1px); } }
@keyframes fsTtC { 0%,60%,100% { transform: translate(0,0); opacity: 0; } 66% { opacity: .6; } 72% { transform: translate(-1.5px,.5px); } 80% { transform: translate(1px,-.5px); } 90% { transform: translate(-.5px,0); opacity: .3; } }
@keyframes fsTtM { 0%,60%,100% { transform: translate(0,0); opacity: 0; } 66% { opacity: .6; } 72% { transform: translate(1.5px,-.5px); } 80% { transform: translate(-1px,.5px); } 90% { transform: translate(.5px,0); opacity: .3; } }
@keyframes fsFbPop { 0%,60%,100% { transform: scale(1); } 70% { transform: scale(.8); } 80% { transform: scale(1.16); } 88% { transform: scale(.96); } 94% { transform: scale(1.02); } }
@keyframes fsYtPulse { 0%,55%,100% { transform: scale(1); } 72% { transform: scale(1.18); } 85% { transform: scale(.98); } }
@keyframes fsYtScan { 0%,55% { transform: translateY(-120%); opacity: 0; } 60% { opacity: .5; } 78% { transform: translateY(120%); opacity: .5; } 80%,100% { opacity: 0; } }

.fsocial__link--ig .fsocial__gly { animation: fsIgPress 5s ease-in-out infinite; }
.fsocial__link--ig::after { content: ""; position: absolute; inset: 5px; border: 2px solid var(--cyan); opacity: 0; pointer-events: none; animation: fsIgRing 5s ease-out infinite; }
.fsocial__link--tt .fsocial__layer--base { animation: fsTtBase 5s .4s ease infinite; }
.fsocial__link--tt .fsocial__layer--c { color: var(--cyan); mix-blend-mode: screen; animation: fsTtC 5s .4s ease infinite; }
.fsocial__link--tt .fsocial__layer--m { color: var(--mag); mix-blend-mode: screen; animation: fsTtM 5s .4s ease infinite; }
.fsocial__link--fb .fsocial__gly { animation: fsFbPop 5s .8s ease-in-out infinite; }
.fsocial__link--yt .fsocial__gly { animation: fsYtPulse 5s 1.2s ease-in-out infinite; }
.fsocial__link--yt::before { content: ""; position: absolute; left: 4px; right: 4px; top: 0; height: 34%; background: linear-gradient(var(--orange), transparent); opacity: 0; pointer-events: none; animation: fsYtScan 5s 1.2s ease-in-out infinite; }

@media (prefers-reduced-motion: reduce) {
  .fsocial__link *, .fsocial__link::before, .fsocial__link::after { animation: none !important; }
  .fsocial__link--yt::before, .fsocial__link--ig::after { opacity: 0 !important; }
}
.colophon {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px;
  font-family: var(--f-mono); font-size: 11px; color: #8f897c; letter-spacing: 0.06em;
  padding-top: 22px; border-top: 2px solid rgba(239, 233, 219, 0.16);
}
footer .lh::after { background: var(--yel); }
@media (max-width: 820px) { .fgrid { grid-template-columns: 1fr 1fr; } }

/* ── WP-environment defenses (added 2026-07-08 after live audit) ──
   Legacy theme css is dequeued on v28 pages, but keep element-level
   declarations explicit so any theme/plugin bleed cannot restyle controls. */
button, input, select, textarea { color: inherit; font-family: inherit; }
body.admin-bar header.site-header { top: 32px; }  /* logged-in admin bar offset */

/* …and the same for the STATIC pages, whose header is a classless <header> and
   therefore never matched the rule above. It is position:sticky; top:0, so once
   you scrolled it slid under the admin bar. Admin-only — a logged-out visitor
   has no admin bar — which is why it survived this long unnoticed.
   The bar is 32px, grows to 46px under 782px, and stops being fixed under 600px. */
body.admin-bar > header { top: 32px; }
@media screen and (max-width: 782px) { body.admin-bar > header { top: 46px; } }
@media screen and (max-width: 600px) { body.admin-bar > header { top: 0; } }

/* ── Mobile nav + headline fixes (2026-07-08 live mobile audit) ── */
.nav .cta { white-space: nowrap; }
/* Was 34x28 measured — under the 44px touch-target floor on the ONE control
   that every mobile visitor has to hit. Centring the bars keeps the visual size
   identical while the hit area grows to 44x44. */
.nav .burger { background: none; border: 0; padding: 6px; cursor: pointer;
  min-width: 44px; min-height: 44px; align-items: center; justify-content: center; }
.nav .burger:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
/* Paired with the burger breakpoint above — both must move together, or the
   burger appears with no dropdown to open. */
@media (max-width: 1240px) {
  .nav { position: relative; }
  .nav .cta { padding: 9px 14px; font-size: 13px; box-shadow: 3px 3px 0 var(--cyan); }
  .nav .burger { display: flex; }
  /* ── THE DROPDOWN, IN THE v28 LANGUAGE — 2026-08-10 ──────────────────────
     It was an unstyled paper rectangle with a 2px bottom rule and 16px links:
     the only part of the site that did not look like the rest of it. The site's
     vocabulary is square corners, 2.5px ink borders, hard offset shadows, Syne
     display caps and CMYK accents — so the menu now uses exactly those, and
     nothing invented. */
  header.nav-open .links {
    display: flex; flex-direction: column; align-items: stretch; gap: 0;
    position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 950;
    background: var(--paper);
    border: 2.5px solid var(--ink);
    box-shadow: 8px 8px 0 var(--ink);
    padding: 10px;
  }
  header.nav-open .links a:not(.cta) {
    display: flex; align-items: center; gap: 12px;
    font-family: var(--f-display); font-weight: 700; text-transform: uppercase;
    font-size: 17px; letter-spacing: -0.01em; line-height: 1;
    padding: 13px 12px; border-bottom: 1.5px solid var(--paper-2);
    transition: background 0.15s var(--ease), padding-left 0.15s var(--ease);
  }
  /* A CMYK square per row — the same four-colour motif as .chips and .calib,
     cycling C/M/Y/K down the list so the menu reads as a print pass. */
  header.nav-open .links a:not(.cta)::before {
    content: ""; width: 11px; height: 11px; flex: 0 0 11px;
    border: 1.5px solid var(--ink); background: transparent;
  }
  header.nav-open .links a:not(.cta):nth-of-type(4n+1)::before { background: var(--cyan); }
  header.nav-open .links a:not(.cta):nth-of-type(4n+2)::before { background: var(--mag); }
  header.nav-open .links a:not(.cta):nth-of-type(4n+3)::before { background: var(--yel); }
  header.nav-open .links a:not(.cta):nth-of-type(4n+4)::before { background: var(--ink); }
  header.nav-open .links a:not(.cta):last-of-type { border-bottom: 0; }
  header.nav-open .links a:not(.cta):hover,
  header.nav-open .links a:not(.cta):focus-visible {
    background: var(--ink); color: var(--paper); padding-left: 18px;
  }
  /* The CTA is the one filled control, full width, and keeps its hard shadow. */
  header.nav-open .links .cta {
    margin: 10px 2px 2px; text-align: center; justify-content: center;
    padding: 14px 16px; font-size: 14px;
    box-shadow: 4px 4px 0 var(--ink);
  }
}

/* Logo CMYK bars: "print-in" entrance (staggered, once per page load).
   Delayed to ~2s so it plays AS the preloader lifts — otherwise it fires at
   ~0.1-0.8s behind the opaque #pre overlay (z-10000, clears ~2.3s) and is already
   static when revealed. Both animations start at first paint, so this stays in
   sync on any device / first-paint speed. */
@keyframes ifSqPrintIn {
  0%   { transform: scaleY(0);    opacity: 0; }
  60%  { transform: scaleY(1.15); opacity: 1; }
  100% { transform: scaleY(1);    opacity: 1; }
}
.brand .sq i {
  transform-origin: bottom center;
  animation: ifSqPrintIn .55s cubic-bezier(.2, .75, .3, 1) both;
}
/* Retimed 2026-08-10 with the 900 ms preloader cap (components.css #pre).
   These two are coupled: the bars must play AS the overlay lifts, so when one
   moves the other has to move in the same commit or the entrance fires behind
   an opaque overlay and is already static when revealed — the exact bug the
   note above describes. Overlay now clears at 0.90s. */
.brand .sq i:nth-child(1) { animation-delay: 0.66s; }
.brand .sq i:nth-child(2) { animation-delay: 0.77s; }
.brand .sq i:nth-child(3) { animation-delay: 0.88s; }
@media (prefers-reduced-motion: reduce) { .brand .sq i { animation: none; } }

/* ── Smallest-screen nav hardening (2026-07-14 mobile bleed audit) ──
   The header row (brand ~192px + "Start a print" CTA ~109px + burger 34px + gaps)
   can't fit ≤380px and pushed the burger ~45px past the viewport on every page.
   Drop the standalone top-bar CTA on small screens — it stays in the open menu. */
@media (max-width: 480px) { header:not(.nav-open) .nav .links { display: none; } }
