/* 
  custom.css
  This file is automatically injected into the <head> of every template by scripts/build.js.
  Use this file for global Vanilla CSS overrides, modern design tweaks, and animations.
*/

:root {
  /* Define custom CSS variables here */
  --custom-primary-color: #000;
}

/* Example generic style */
body {
  /* Add custom body styles if needed */
}

/* =====================================================================
   BFA LOGO SIZING FIXES
   ===================================================================== */

/* 1. Global fix: prevent the square logo from being distorted by the old 1845x570 HTML attributes */
img[src*="bfa_white_logo"] {
  height: auto !important;
  object-fit: contain;
  filter: invert(1); /* The logo is white, so invert it to black for light backgrounds */
}

/* 2. Header Logo: Ensure it fits neatly within the header container */
.max-w-\[var\(--logo-max-width\)\] img[src*="bfa_white_logo"] {
  width: 100% !important;
  max-width: 90px !important; 
}

/* 3. Footer Logo: The old logo was a wide banner that took up width: 100% (w-full).
      A square logo at 100% width would be massive. This limits it and centers it. */
.shopify-section-group-footer-group img[src*="bfa_white_logo"] {
  width: auto !important;
  max-width: 120px !important;
  max-height: 120px !important;
  margin: 2rem auto !important;
  display: block;
}

/* =====================================================================
   ENTRY ANIMATION — the storm
   =====================================================================
   Every seal in the library rains down a black screen, and the black
   slides away with them, top to bottom.

   Structural only. Every number belonging to a particular seal — its
   size, speed, drift, spin, cell in the sprite sheet — is set as a
   custom property by assets/intro.js from data/intro.json, so retuning
   the storm never means editing this file.

   The curtain is a pseudo-element on <html> rather than a real node, so
   it can paint on the very first frame, before <body> exists. It only
   appears when the arming stub in the <head> adds .bfa-intro, so a
   visitor without JavaScript never sees a black screen — the one
   failure worth designing against, since it would hide the site
   completely.
   ===================================================================== */

html.bfa-intro,
html.bfa-intro body {
  overflow: hidden;
}

/* The curtain slides down and off the bottom rather than fading, which
   is what makes the reveal read top-to-bottom: the first thing you see
   is the top of the page, and the black leaves with the rain.

   It is taller than the viewport and starts shifted up by its own
   feather, so the soft leading edge sits off-screen until it moves.
   Transform, not height — height would relayout every frame while 150
   seals are already animating. */
html.bfa-intro::before {
  content: "";
  position: fixed;
  left: 0;
  right: 0;
  top: calc(var(--bfa-feather, 110px) * -1);
  height: calc(100vh + var(--bfa-feather, 110px));
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0, #000 var(--bfa-feather, 110px));
  z-index: 2147483646;
  pointer-events: none;
  transform: translate3d(0, 0, 0);
  transition: transform var(--bfa-intro-wipe, 2100ms) cubic-bezier(.42, .04, .58, 1);
}

html.bfa-intro.bfa-intro-lift::before {
  transform: translate3d(0, calc(100vh + var(--bfa-feather, 110px)), 0);
}

/* Above the curtain, so the seals read against the black and then keep
   falling across the page once it has gone. */
.bfa-intro-stage {
  position: fixed;
  inset: 0;
  z-index: 2147483647;
  overflow: hidden;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Once the page is uncovered the storm is decoration; it must not eat
   clicks on the site behind it. */
.bfa-intro-stage.is-open {
  pointer-events: none;
  cursor: auto;
}

/* Only appears when an uncached atlas takes long enough to notice. The mark reassures without
   competing with the seals; its one moving line stops before the storm begins. */
.bfa-intro-loader {
  position: fixed;
  left: 50%;
  top: 50%;
  width: 9rem;
  color: #fff;
  font: 500 11px/1 system-ui, sans-serif;
  letter-spacing: .18em;
  text-align: center;
  opacity: 0;
  transform: translate3d(-50%, -50%, 0);
  transition: opacity 160ms linear;
}

.bfa-intro-loader::after {
  content: "";
  display: block;
  height: 1px;
  margin-top: 10px;
  background: currentColor;
  transform: scaleX(.08);
  transform-origin: left center;
}

.bfa-intro-stage.is-loading .bfa-intro-loader {
  opacity: .72;
}

.bfa-intro-stage.is-loading .bfa-intro-loader::after {
  animation: bfa-intro-loading 850ms cubic-bezier(.45, 0, .55, 1) infinite alternate;
}

.bfa-intro-stage.is-running .bfa-intro-loader {
  opacity: 0;
}

.bfa-seal {
  position: absolute;
  top: 0;
  left: var(--x);
  width: var(--s);
  height: var(--s);
  margin-left: calc(var(--s) / -2);
  opacity: 1;
  /* One image for all 154 seals; the cell is chosen by index. Sizing the
     background to the whole grid in multiples of the element means the
     seal scales with it and the sheet's own pixel size never appears
     here — so changing sheet.cellPx needs no CSS change. */
  background-image: var(--sheet);
  background-repeat: no-repeat;
  background-size: calc(var(--s) * var(--cols)) calc(var(--s) * var(--rows));
  background-position: calc(var(--s) * var(--col) * -1) calc(var(--s) * var(--row) * -1);
  transform: translate3d(0, -125%, 0) rotate(var(--r0));
}

/* The nodes exist while the shared sprite sheet loads so the whole screen remains skippable, but
   they have no animation timeline at all until the image is decoded. Creating a paused timeline
   can still let its delay age in some browser/tooling combinations; attaching the keyframes only
   at readiness makes a cold and warm load begin on the same first frame. */
.bfa-intro-stage.is-running .bfa-seal {
  animation: bfa-rain var(--dur) linear var(--delay) both;
}

/* No will-change here on purpose. It would promote 154 elements to their
   own compositor layers at once, which costs more GPU memory than the
   animation saves; transform animations are composited anyway. */
@keyframes bfa-rain {
  from { transform: translate3d(0, -125%, 0) rotate(var(--r0)); opacity: 1; }
  80%  { opacity: 1; }
  to   { transform: translate3d(var(--dx), calc(100vh + 125%), 0) rotate(var(--r1)); opacity: 0; }
}

@keyframes bfa-intro-loading {
  from { transform: scaleX(.08); }
  to   { transform: scaleX(1); }
}

/* A skip has to feel instant, so the storm is abandoned where it stands
   rather than hurried along. */
.bfa-intro-stage.is-skipped {
  opacity: 0;
  transition: opacity 150ms linear;
  pointer-events: none;
}

/* Belt and braces. The stub declines to play at all under a reduced-motion
   preference; this only matters if the curtain is somehow on screen
   anyway, and it removes the motion rather than the reveal. */
@media (prefers-reduced-motion: reduce) {
  html.bfa-intro::before { transition-duration: 1ms !important; }
  .bfa-seal { animation-duration: 1ms !important; animation-delay: 0ms !important; }
  .bfa-intro-loader::after { animation: none !important; }
}

/* Optional GA4 consent uses the storefront's square buttons, type and gridline rhythm. It is a
   hard-edged footer-like strip rather than a rounded third-party bubble. The z-index sits below
   the entry storm, so a first visit completes its reveal before asking for a privacy choice. */
.bfa-analytics-consent {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2147483000;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 1.5rem;
  align-items: end;
  padding: 1.5rem var(--section-horizontal-spacing);
  border-top: var(--gridline-width) solid rgb(var(--color-gridline));
  background: rgb(var(--color-scheme-background));
  color: rgb(var(--color-scheme-text));
}

.bfa-analytics-consent__copy {
  display: grid;
  gap: .6rem;
  max-width: 58rem;
}

.bfa-analytics-consent__actions,
.bfa-analytics-controls {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  align-items: center;
}

.bfa-analytics-controls {
  margin-top: 1.5rem;
}

.bfa-analytics-controls__status {
  flex-basis: 100%;
  margin-bottom: .25rem;
}

@media (max-width: 700px) {
  .bfa-analytics-consent {
    grid-template-columns: 1fr;
    align-items: stretch;
    gap: 1rem;
  }

  .bfa-analytics-consent__actions > *,
  .bfa-analytics-controls > button {
    flex: 1 1 auto;
  }
}

/* =====================================================================
   HOMEPAGE CATEGORY NAVIGATION — bracketed magnetic roll
   =====================================================================
   Scoped to the large SHOP row immediately beneath the shared header.
   The header navigation, product rails and footer retain their existing
   interaction. Two real text layers keep the large letters sharp while
   the clipped vertical roll runs; the duplicate is hidden from assistive
   technology in scripts/lib/home.js.
   ===================================================================== */

[data-bfa-category-nav] ul {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: clamp(1.25rem, 4vw, 5rem);
}

[data-bfa-category-nav] {
  /* The inherited display scale was designed for bare words. Brackets add enough width to wrap
     the third label at ordinary laptop sizes, so this keeps the three-title composition a row. */
  font-size: clamp(3rem, 6vw, 7.5rem) !important;
}

[data-bfa-category-nav] li {
  display: block;
  margin: 0 !important;
}

[data-bfa-category-link] {
  --bfa-category-x: 0px;
  --bfa-category-y: 0px;
  display: inline-flex;
  color: inherit;
  text-decoration: none;
  transform: translate3d(var(--bfa-category-x), var(--bfa-category-y), 0);
  transition: transform 600ms cubic-bezier(.34, 1.3, .64, 1);
  will-change: transform;
}

.bfa-category-link__visual {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: .95;
  text-transform: uppercase;
  white-space: nowrap;
}

.bfa-category-link__window {
  position: relative;
  display: inline-grid;
  height: .95em;
  margin-inline: .12em;
  overflow: hidden;
  align-items: center;
}

.bfa-category-link__label,
.bfa-category-link__bracket {
  display: block;
  transform: translate3d(0, 0, 0);
}

.bfa-category-link__label {
  grid-area: 1 / 1;
  padding-inline: .04em;
  transition: transform 500ms cubic-bezier(.65, 0, .35, 1);
}

.bfa-category-link__label--echo {
  transform: translate3d(0, 120%, 0);
}

.bfa-category-link__bracket {
  font-family: ui-monospace, "Roboto Mono", monospace;
  font-weight: 400;
  transition: transform 400ms cubic-bezier(.34, 1.56, .64, 1);
}

@media (min-width: 1025px) and (hover: hover) and (pointer: fine) {
  [data-bfa-category-link]:hover .bfa-category-link__label--primary,
  [data-bfa-category-link]:focus-visible .bfa-category-link__label--primary {
    transform: translate3d(0, -120%, 0);
  }

  [data-bfa-category-link]:hover .bfa-category-link__label--echo,
  [data-bfa-category-link]:focus-visible .bfa-category-link__label--echo {
    transform: translate3d(0, 0, 0);
  }

  [data-bfa-category-link]:hover .bfa-category-link__bracket--open,
  [data-bfa-category-link]:focus-visible .bfa-category-link__bracket--open {
    transform: translate3d(-10px, 0, 0);
  }

  [data-bfa-category-link]:hover .bfa-category-link__bracket--close,
  [data-bfa-category-link]:focus-visible .bfa-category-link__bracket--close {
    transform: translate3d(10px, 0, 0);
  }
}

@media (max-width: 1024px) {
  [data-bfa-category-nav] ul {
    justify-content: flex-start;
  }
}

@media (max-width: 640px) {
  [data-bfa-category-nav] {
    font-size: clamp(2.8rem, 15vw, 5.75rem) !important;
  }

  [data-bfa-category-nav] ul {
    display: grid;
    gap: .35em;
    justify-items: start;
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-bfa-category-link],
  .bfa-category-link__label,
  .bfa-category-link__bracket {
    transition: none !important;
  }

  [data-bfa-category-link] {
    transform: none !important;
    will-change: auto;
  }
}
/* Journal copy stays readable inside the original theme's article column. */
.bfa-journal-copy {
  max-width: 65ch;
  font-size: clamp(16px, 1.3vw, 19.2px);
  line-height: 1.65;
}
