/* ==========================================================================
   MerchStamp — shared shell (nav, footer, type system, buttons, tiles)
   Loaded on every page. Page-specific files (anime.css, gag.css, dark.css,
   about.css, home.css) load after this one and only add to it.
   ========================================================================== */

:root{
  --black:        #0a0a0a;
  --charcoal:     #141414;
  --charcoal-2:   #1c1b19;
  --ink:          #1b1b1b;
  --paper:        #f7f6f3;
  --paper-dim:    #ece8e0;
  --cream:        #efece3;
  --accent:       #b3122d;
  --accent-bright:#e2213f;
  --accent-glow:  rgba(179,18,45,.45);
  --gold:         #d9a531;
  --gold-bright:  #f0c352;
  --gold-glow:    rgba(217,165,49,.32);
  --muted-light:  #6b6b6b;
  --muted-dark:   #a49e93;
  --white:        #f5f3ee;
  --line-dark:    rgba(245,243,238,.14);
  --line-light:   rgba(27,27,27,.12);

  --font-display: 'Anton', 'Arial Narrow Bold', Impact, sans-serif;
  --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  --nav-h: 76px;
}

*, *::before, *::after{ box-sizing: border-box; }
html{ scroll-behavior: smooth; }
/* Sideways-scroll safety net, added 2026-09-18. A third-party embed (the
   reCAPTCHA in the signup panel) was forcing the document 53px wider than a
   phone viewport, so the page could be dragged left and a white strip showed
   beside it. The real cause is fixed in the .sib-captcha rules at the bottom of
   this file; this is the backstop so no future embed can do it again.
   `clip` not `hidden` on purpose: overflow-x:hidden on html silently kills
   position:sticky on every descendant, which would break the nav. */
html, body{ overflow-x: clip; }
body{
  margin: 0;
  max-width: 100%;
  font-family: var(--font-body);
  background: var(--paper);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img{ max-width: 100%; display: block; }
a{ color: inherit; text-decoration: none; }
ul{ margin: 0; padding: 0; list-style: none; }
h1,h2,h3{
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: .01em;
  line-height: .98;
  margin: 0;
  font-weight: 400;
}
p{ margin: 0; }
.eyebrow{
  font-family: var(--font-body);
  font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
  font-size: .72rem;
}

@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- layout helpers ---------- */
.wrap{ max-width: 1180px; margin: 0 auto; padding: 0 28px; }
main{ display: block; }

/* ---------- buttons ---------- */
.btn{
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: .82rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  padding: 15px 28px;
  border-radius: 3px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform .18s ease, background-color .18s ease, color .18s ease, border-color .18s ease;
  white-space: nowrap;
}
.btn:hover{ transform: translateY(-2px); }
.btn-accent{ background: var(--accent); color: var(--white); }
.btn-accent:hover{ background: var(--accent-bright); }
.btn-outline-dark{ background: transparent; color: var(--white); border-color: var(--line-dark); }
.btn-outline-dark:hover{ border-color: var(--white); }
.btn-outline-light{ background: transparent; color: var(--ink); border-color: var(--line-light); }
.btn-outline-light:hover{ border-color: var(--ink); }

/* ---------- promo bar ----------
   Sitewide announcement strip, sits above the nav on every page. Deliberately
   a slim single row — it scrolls away with the page (the nav below it is the
   sticky element), so it never competes with a page's own hero. The <form>
   inside is wired for the hidden-iframe POST trick (see js/promo.js) so it
   never navigates away, but it has no live endpoint yet — see the HTML
   comment next to the <form> tag on each page for the two placeholder values
   that need swapping in before this goes live. */
.promo-bar{
  background: var(--accent-bright);
  color: var(--white);
}
.promo-bar-inner{
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px 22px;
  flex-wrap: wrap;
  padding: 11px 28px;
  text-align: center;
}
.promo-headline{
  font-size: .84rem;
  font-weight: 600;
  letter-spacing: .01em;
}
.promo-headline strong{
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: .03em;
  text-transform: uppercase;
  margin-right: 2px;
}
.promo-form{
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}
/* .promo-form sets its own display:flex, which as an author rule beats the
   UA stylesheet's [hidden]{display:none} — without this, toggling the
   `hidden` attribute via JS (see js/promo.js) does nothing visible. */
.promo-form[hidden]{ display: none; }
.promo-input{
  font-family: var(--font-body);
  font-size: .82rem;
  padding: 8px 12px;
  min-width: 210px;
  border-radius: 3px;
  border: 1px solid rgba(245,243,238,.45);
  background: rgba(10,10,10,.16);
  color: var(--white);
}
.promo-input::placeholder{ color: rgba(245,243,238,.75); }
.promo-input:focus{ outline: 2px solid var(--white); outline-offset: 1px; background: rgba(10,10,10,.26); }
.promo-submit{
  font-family: var(--font-body);
  font-weight: 700;
  font-size: .76rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: 8px 20px;
  border-radius: 3px;
  border: none;
  background: var(--black);
  color: var(--white);
  cursor: pointer;
  white-space: nowrap;
  transition: background-color .15s ease, transform .15s ease;
}
.promo-submit:hover{ background: var(--charcoal-2); transform: translateY(-1px); }
.promo-thanks{
  font-size: .84rem;
  font-weight: 700;
}
.sr-only{
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

@media (max-width: 640px){
  .promo-bar-inner{
    flex-direction: column;
    padding: 14px 20px;
    gap: 10px;
  }
  .promo-form{ width: 100%; max-width: 380px; }
  .promo-input{ flex: 1; min-width: 0; }
}

/* ---------- nav ---------- */
.site-nav{
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  background: var(--charcoal);
  border-bottom: 1px solid var(--line-dark);
}
.site-nav .wrap{
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.brand{
  font-family: var(--font-display);
  color: var(--white);
  font-size: 1.35rem;
  letter-spacing: .04em;
  display: flex;
  align-items: baseline;
  gap: 2px;
}
.brand span{ color: var(--accent); }
/* Gap was 34px with seven items. With the 2026-10-08 collections the bar holds
   nine, and 28px is what fits one line at 1200px+ with room left beside the
   brand (measured headless: items 727px + 8 gaps, brand 128px, inside 1124px). */
.nav-links{
  display: flex;
  align-items: center;
  gap: 28px;
}
/* The brand mark already links home on desktop, so the text "Home" only shows
   inside the phone menu, where the brand is not part of the list. */
@media (min-width: 1200px){
  .nav-links a.nav-home{ display: none; }
}
.nav-links a,
.nav-group-toggle{
  font-family: var(--font-body);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted-dark);
  padding: 8px 2px;
  border-bottom: 2px solid transparent;
  transition: color .15s ease, border-color .15s ease;
}
.nav-links a:hover,
.nav-links a[aria-current="page"]{
  color: var(--white);
  border-color: var(--accent);
}

/* ---------- Tees dropdown ----------
   Added 2026-10-08 when the shop grew past tees. Twelve top-level links did
   not fit one desktop line, so the three tee collections sit under one "Tees"
   disclosure button (W3C disclosure-navigation pattern: a real <button> with
   aria-expanded, not a link pretending to be one). Hover opens it for a mouse;
   click, Enter or Space opens it for touch and keyboard (js/nav.js); Escape
   and an outside click close it. In the phone menu it becomes a tap-to-fold
   group that starts open, so every link is listed. */
.nav-group{
  position: relative;
  display: flex;
  align-items: center;
}
.nav-group-toggle{
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: none;
  border-top: 0; border-left: 0; border-right: 0;
  cursor: pointer;
  line-height: inherit;
}
.nav-group-toggle::after{
  content: "";
  width: 6px; height: 6px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform .18s ease;
}
.nav-group.open .nav-group-toggle::after{ transform: translateY(2px) rotate(-135deg); }
.nav-group-toggle:hover,
.nav-group-toggle.is-current,
.nav-group.open .nav-group-toggle{
  color: var(--white);
  border-color: var(--accent);
}
.nav-group-toggle:focus-visible{ outline: 2px solid var(--accent-bright); outline-offset: 3px; }
.nav-sub{
  position: absolute;
  top: calc(100% + 19px);
  left: -22px;
  min-width: 224px;
  padding: 8px 0;
  background: var(--charcoal);
  border: 1px solid var(--line-dark);
  border-top: 2px solid var(--accent);
  box-shadow: 0 22px 44px rgba(0,0,0,.5);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity .16s ease, transform .16s ease, visibility .16s;
}
/* Invisible bridge over the gap between the button and the panel, so a mouse
   travelling down to the panel does not drop the hover on the way. */
.nav-sub::before{
  content: "";
  position: absolute;
  left: 0; right: 0;
  top: -21px;
  height: 21px;
}
.nav-group.open .nav-sub{ opacity: 1; visibility: visible; transform: none; }
.nav-links .nav-sub a{
  display: block;
  padding: 12px 22px;
  border-bottom: 0;
  white-space: nowrap;
}
.nav-links .nav-sub a:hover{ background: rgba(245,243,238,.05); }
.nav-links .nav-sub a[aria-current="page"]{
  color: var(--white);
  box-shadow: inset 3px 0 0 var(--accent);
}
/* Hover-to-open only where a real mouse exists. On touch screens a tap would
   trigger :hover AND the click toggle at once and the panel would stick open. */
@media (min-width: 1200px) and (hover: hover) and (pointer: fine){
  .nav-group:hover .nav-sub{ opacity: 1; visibility: visible; transform: none; }
  .nav-group:hover .nav-group-toggle{ color: var(--white); border-color: var(--accent); }
}
.nav-cta{
  margin-left: 6px;
  padding: 10px 20px;
  font-size: .72rem;
}
/* `.nav-links a` (0,1,1) out-specifies `.btn-accent` (0,1,0), so the red CTA
   was rendering its label in the muted grey used by the plain nav links.
   Pre-existing; caught on a headless screenshot 2026-09-18. */
.nav-links a.nav-cta{ color: var(--white); }
/* "Shop All" is the one nav item that has to survive being skimmed, so it gets
   the white treatment while the rest sit muted. */
.nav-links a.nav-shop{ color: var(--white); }
.nav-links a.nav-shop::before{
  content: "";
  display: inline-block;
  width: 5px; height: 5px;
  background: var(--accent);
  border-radius: 50%;
  margin-right: 8px;
  vertical-align: middle;
}

/* ---------- menu button ----------
   Reworked 2026-09-18. It was a bare 40px hamburger with no label and no
   border, and a real visitor did not see it at all — he could not find the
   products. NN/g's current guidance (June 2025, on top of their 2016 study
   measuring a 20%+ drop in discoverability for hidden navigation) is to label
   the icon with the word "Menu" and give it enough contrast and padding to
   read as a control. So: bars + the word, inside a visible bordered pill. */
.nav-toggle{
  display: none;
  align-items: center;
  gap: 10px;
  height: 40px;
  padding: 0 14px;
  border: 1px solid rgba(245,243,238,.38);
  border-radius: 3px;
  background: rgba(245,243,238,.07);
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease;
}
.nav-toggle:hover{ background: rgba(245,243,238,.14); border-color: var(--white); }
.nav-toggle:focus-visible{ outline: 2px solid var(--accent-bright); outline-offset: 2px; }
.nav-toggle-word{
  font-family: var(--font-body);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--white);
  line-height: 1;
}
.nav-toggle-bars{
  position: relative;
  display: block;
  flex: 0 0 18px;
  width: 18px;
  height: 2px;
  background: var(--white);
  transition: background-color .2s ease;
}
.nav-toggle-bars::before,
.nav-toggle-bars::after{
  content: "";
  position: absolute;
  left: 0; right: 0;
  height: 2px;
  background: var(--white);
  transition: transform .2s ease, top .2s ease;
}
.nav-toggle-bars::before{ top: -6px; }
.nav-toggle-bars::after{ top: 6px; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars{ background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before{ top: 0; transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after{ top: 0; transform: rotate(-45deg); }

/* Breakpoint moved from 860px to 1199px on 2026-10-08: below 1200px the nine
   desktop items no longer fit one line (measured), so the labelled Menu button
   takes over. The phone-only shop bar further down keeps its own 860px rule. */
@media (max-width: 1199px){
  .nav-links{
    /* Hangs off the bottom of the header, not from a fixed 76px down the
       viewport. It used to be `position:fixed; inset: var(--nav-h) 0 0 0`,
       which assumed the header was flush to the top of the screen. It is not:
       the promo bar sits above it and pushes it down, so the open panel was
       overlapping the header and swallowing the brand and the Close button.
       .site-nav is position:sticky, so it is the positioning ancestor here. */
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    height: calc(100dvh - var(--nav-h));
    background: var(--charcoal);
    flex-direction: column;
    justify-content: flex-start;
    align-items: stretch;
    gap: 0;
    padding: 10px 28px 28px;
    transform: translateY(-8px);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity .18s ease, transform .18s ease, visibility .18s;
  }
  .nav-links.open{
    opacity: 1;
    transform: translateY(0);
    visibility: visible;
    pointer-events: auto;
  }
  .nav-links a{
    padding: 14px 2px;
    border-bottom: 1px solid var(--line-dark);
    width: 100%;
    font-size: .92rem;
  }
  /* Thirteen rows plus the CTA run past a phone screen, so the panel scrolls.
     js/nav.js also sizes it to the space actually left under the header (the
     promo bar can sit above it), so the last row is never stranded offscreen. */
  .nav-links{ overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
  .nav-links a.nav-shop{
    font-size: 1.05rem;
    color: var(--white);
    border-bottom-color: rgba(179,18,45,.55);
  }
  /* Tees group: a full-width row that folds its three links in and out. It
     starts open whenever the menu opens (js/nav.js), so nothing is hidden. */
  .nav-group{ display: block; width: 100%; }
  .nav-group-toggle{
    width: 100%;
    justify-content: space-between;
    padding: 14px 2px;
    font-size: .92rem;
    border-bottom: 1px solid var(--line-dark);
  }
  .nav-group-toggle:hover,
  .nav-group-toggle.is-current,
  .nav-group.open .nav-group-toggle{ border-color: var(--line-dark); }
  .nav-group-toggle::after{ margin-right: 4px; }
  .nav-sub{
    position: static;
    display: none;
    min-width: 0;
    padding: 0 0 0 18px;
    background: transparent;
    border: 0;
    box-shadow: none;
    opacity: 1;
    visibility: visible;
    transform: none;
  }
  .nav-sub::before{ display: none; }
  .nav-group.open .nav-sub{ display: block; }
  .nav-links .nav-sub a{
    padding: 13px 2px;
    font-size: .86rem;
    border-bottom: 1px solid var(--line-dark);
    white-space: normal;
  }
  .nav-links .nav-sub a:hover{ background: transparent; }
  .nav-links .nav-sub a[aria-current="page"]{ box-shadow: none; border-bottom-color: var(--accent); }
  .nav-cta{ margin: 18px 0 0; text-align: center; justify-content: center; }
  .nav-toggle{ display: flex; }
}

/* ---------- mobile shop bar ----------
   Added 2026-09-18. Phone-only, and it only appears once the hero has scrolled
   past, so it never covers the opening statement. Deliberately the ONLY extra
   shop affordance on mobile: the header already carries a labelled Menu button,
   and stacking a second header link on top of this would just be clutter.
   Left in normal DOM order at the end of <body> and focus is never forced into
   it, so keyboard and screen-reader order stay predictable. */
.shop-bar{
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 90;
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 11px 18px calc(11px + env(safe-area-inset-bottom));
  background: rgba(10,10,10,.94);
  backdrop-filter: blur(8px);
  border-top: 1px solid rgba(217,165,49,.34);
  transform: translateY(105%);
  transition: transform .26s ease;
}
.shop-bar.visible{ transform: translateY(0); }
.shop-bar-text{
  display: flex;
  flex-direction: column;
  line-height: 1.25;
  min-width: 0;
}
.shop-bar-text strong{
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: .98rem;
  color: var(--white);
}
.shop-bar-text span{
  font-size: .7rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--gold);
}
.shop-bar .btn{
  padding: 12px 20px;
  font-size: .72rem;
  flex-shrink: 0;
}
@media (max-width: 860px){
  .shop-bar{ display: flex; }
  /* Stop the bar sitting on top of the last line of the footer. */
  .site-footer{ padding-bottom: 96px; }
}

/* ---------- footer ---------- */
.site-footer{
  background: var(--black);
  color: var(--muted-dark);
  padding: 56px 0 28px;
  border-top: 1px solid var(--line-dark);
}
.footer-top{
  display: flex;
  flex-wrap: wrap;
  gap: 32px;
  justify-content: space-between;
  align-items: flex-start;
  padding-bottom: 32px;
  border-bottom: 1px solid var(--line-dark);
}
.footer-brand .brand{ margin-bottom: 10px; }
.footer-brand p{
  max-width: 320px;
  font-size: .88rem;
  line-height: 1.6;
  color: var(--muted-dark);
}
.footer-links{
  display: flex;
  gap: 56px;
  flex-wrap: wrap;
}
.footer-col h4{
  font-family: var(--font-body);
  font-size: .7rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--white);
  margin-bottom: 14px;
}
.footer-col a{
  display: block;
  font-size: .86rem;
  color: var(--muted-dark);
  padding: 6px 0;
  transition: color .15s ease;
}
.footer-col a:hover{ color: var(--white); }
.footer-col a[aria-current="page"]{ color: var(--white); }
/* The Shop column carries nine links since 2026-10-08. Set as two short
   columns that read top to bottom, instead of one tall column that dwarfs the
   other two. Grid rather than CSS columns, which size badly inside a flex row. */
.footer-col-list{
  display: grid;
  grid-template-rows: repeat(5, auto);
  grid-auto-flow: column;
  column-gap: 36px;
}
.footer-bottom{
  padding-top: 22px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: space-between;
  font-size: .76rem;
}

/* ---------- generic section rhythm ---------- */
.section{ padding: 96px 0; }
.section-tight{ padding: 64px 0; }

/* ---------- solo product block ----------
   Added 2026-09-17 for the single-print drops (devil girl, both cats, Vex,
   the support hoodie). The anime page's flip-card only makes sense for a
   front+back design, and the gag page's frame is scoped to gag.css, so this
   is the one shared pattern every page can use. Inherits the light/dark
   section colours already defined per page rather than setting its own. */
.solo-section{ padding: 96px 0; }
.solo-layout{
  display: grid;
  grid-template-columns: minmax(0, 420px) minmax(0, 1fr);
  gap: 56px;
  align-items: center;
}
.solo-frame{
  position: relative;
  border: 1px solid var(--line-light);
  background: #050505;
  overflow: hidden;
}
.solo-section.dark .solo-frame,
.dark-page .solo-frame{ border-color: var(--line-dark); }
/* height:auto added 2026-10-08: an <img> that carries width/height attributes
   (they reserve its space while loading) otherwise takes the height attribute
   literally, and a 420px-wide frame got a 1000px-tall stretched picture. */
.solo-frame img{ width: 100%; height: auto; display: block; }
.solo-frame .solo-tag{
  position: absolute;
  left: 0; bottom: 0;
  background: var(--accent);
  color: var(--white);
  font-family: var(--font-display);
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: 7px 13px;
}
.solo-info .price{ display: block; margin: 6px 0 14px; }
@media (max-width: 860px){
  .solo-layout{ grid-template-columns: 1fr; gap: 30px; }
  .solo-frame{ max-width: 420px; }
}

/* The .specs chip row is defined per page (anime.css / gag.css) and scoped to
   parents the solo block doesn't have, so without this the specs render as one
   run-together lowercase sentence. Caught on a headless screenshot pass. */
.solo-info .specs{
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
  margin-bottom: 30px;
  font-size: .78rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  font-weight: 700;
}
.solo-info .specs span{ opacity: .65; }
.solo-section.light .solo-info .specs{ color: var(--ink); }
.solo-section.dark .solo-info .specs,
.dark-page .solo-info .specs{ color: var(--white); }
/* Heading and blurb sizing to match the existing product cards — without this
   the new drops render visibly smaller than Goodgirl and the raccoon and read
   as second-class. */
.solo-info h2{ font-size: clamp(1.8rem, 4vw, 2.6rem); margin-bottom: 6px; }
.solo-info .price{
  font-family: var(--font-display);
  font-size: 1.4rem;
  color: var(--accent);
  margin-bottom: 20px;
}
.solo-info p.blurb{ font-size: 1.02rem; line-height: 1.7; margin-bottom: 22px; }

/* ---------- product card (shared) ----------
   Added 2026-09-18 for the Shop All page and the home page's featured strip.
   One definition, two users — do not fork a second copy into home.css. */
.p-card{
  display: flex;
  flex-direction: column;
  background: #ffffff;
  border: 1px solid var(--line-light);
  overflow: hidden;
  transition: transform .22s ease, box-shadow .22s ease, border-color .22s ease;
}
.p-card:hover{
  transform: translateY(-5px);
  box-shadow: 0 20px 44px rgba(0,0,0,.16);
  border-color: rgba(179,18,45,.42);
}
.p-card.is-hidden{ display: none; }

.p-media{
  position: relative;
  background: #050505;
  aspect-ratio: 1 / 1;
  overflow: hidden;
}
.p-media img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s ease;
}
.p-card:hover .p-media img{ transform: scale(1.035); }

/* ---------- front/back flip on the card ----------
   Added 2026-09-18 at Lycan's request: the three front+back designs flip to
   the back print on hover, so a visitor sees both sides without leaving for
   Etsy. Hover does it on a mouse; js/flip.js adds tap and keyboard for touch,
   which never holds :hover reliably.
   The chip and flag deliberately sit OUTSIDE .p-flip-inner so they stay put
   and readable while the artwork turns. */
.p-flip{ perspective: 1200px; }
.p-flip-inner{
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transition: transform .6s cubic-bezier(.2,.7,.2,1);
}
.p-card:hover .p-flip .p-flip-inner,
.p-flip.flipped .p-flip-inner{ transform: rotateY(180deg); }
.p-face{
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  overflow: hidden;
  background: #050505;
}
.p-back{ transform: rotateY(180deg); }
/* The zoom-on-hover and a 3D flip fight each other — the scale is applied to
   the same element being rotated and makes the turn wobble. Flip cards keep
   the flip, plain cards keep the zoom. */
.p-card:hover .p-flip img{ transform: none; }
/* No third badge: the chip (top-left) and the "Front + Back" flag
   (bottom-right) already say everything, and a 170px card at two-up on a
   phone cannot carry more furniture than that. */
.p-chip{
  position: absolute;
  top: 12px; left: 12px;
  background: rgba(10,10,10,.82);
  color: var(--white);
  font-family: var(--font-body);
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: 6px 11px;
  backdrop-filter: blur(3px);
}
/* Bottom-right, not top-right: at two-up on a phone the card is narrow enough
   that a top-right flag collided with the category chip. Caught on a headless
   phone screenshot, not by Lycan. */
.p-flag{
  position: absolute;
  bottom: 12px; right: 12px;
  background: var(--gold);
  color: #1a1206;
  font-family: var(--font-display);
  font-size: .6rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: 6px 10px;
}
.p-body{
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 20px 20px 22px;
}
.p-name{
  font-family: var(--font-display);
  text-transform: uppercase;
  font-size: 1.3rem;
  line-height: 1.02;
  color: var(--ink);
  margin: 0 0 8px;
  font-weight: 400;
}
.p-price{
  font-family: var(--font-display);
  font-size: 1.12rem;
  color: var(--accent);
  margin-bottom: 11px;
}
.p-blurb{
  font-size: .87rem;
  line-height: 1.55;
  color: var(--muted-light);
  margin-bottom: 18px;
}
.p-buy{
  margin-top: auto;
  width: 100%;
  justify-content: center;
  padding: 13px 18px;
  font-size: .74rem;
}
@media (max-width: 620px){
  .p-body{ padding: 15px 14px 17px; }
  .p-name{ font-size: 1.08rem; }
  .p-price{ font-size: 1rem; }
  .p-blurb{ display: none; }   /* keep two-up cards scannable on a phone */
  .p-buy{ padding: 12px 10px; font-size: .68rem; letter-spacing: .07em; }
  /* At two-up the card is ~170px wide and "Gag & Cartoon" at full size nearly
     spanned it. Shrink the tags rather than truncate the category name. */
  .p-chip{ font-size: .54rem; letter-spacing: .1em; padding: 5px 8px; top: 9px; left: 9px; }
  .p-flag{ font-size: .54rem; letter-spacing: .1em; padding: 5px 8px; bottom: 9px; right: 9px; }
}

/* ---------- signup section (Brevo embedded form) ----------
   Added 2026-09-17. The promo bar can no longer hold the form inline because a
   visible reCAPTCHA is a ~78px widget, so the bar links down here instead.
   Brevo's markup is embedded verbatim so their JS, captcha and inline success
   and error messages keep working; everything below is override-only styling so
   it reads as part of this site rather than a pasted widget. */
.signup-section{
  background: var(--black);
  color: var(--white);
  padding: 92px 0;
  border-top: 1px solid var(--line-dark);
}
/* One enclosing panel so the offer and the email field read as a single
   thing. Lycan's note, and he was right: heading left, box right, nothing
   tying them together meant people could scroll past the 10% entirely. */
.signup-section .wrap{ display: block; }
.signup-panel{
  position: relative;
  border: 1px solid var(--gold);
  background:
    radial-gradient(120% 140% at 0% 0%, rgba(217,165,49,.10) 0%, rgba(217,165,49,0) 55%),
    linear-gradient(180deg, #151317 0%, #0d0c0f 100%);
  box-shadow: 0 0 0 1px rgba(217,165,49,.16), 0 24px 60px -28px var(--gold-glow);
  padding: 54px 52px 50px;
}
.signup-panel::before{
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 38%, rgba(240,195,82,.07) 50%, transparent 62%);
}
.signup-badge{
  position: absolute;
  top: 0; left: 52px;
  transform: translateY(-50%);
  background: linear-gradient(180deg, var(--gold-bright) 0%, var(--gold) 100%);
  color: #1a1206;
  font-family: var(--font-display);
  font-size: .78rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  padding: 9px 18px;
  box-shadow: 0 6px 18px -8px var(--gold-glow);
}
.signup-grid{
  display: grid;
  grid-template-columns: minmax(0,1fr) minmax(0,440px);
  gap: 56px;
  align-items: center;
}
.signup-copy .eyebrow{ color: var(--gold) !important; }
.signup-copy h2{ font-size: clamp(1.9rem, 4vw, 2.7rem); margin: 6px 0 14px; }
.signup-copy p{ font-size: 1rem; line-height: 1.7; color: var(--muted-dark); max-width: 46ch; }

/* --- Brevo overrides. Their embed ships its own <style>; these win on
       specificity without touching their HTML. --- */
.signup-form .sib-form{ padding: 0 !important; background: transparent !important; }
.signup-form #sib-container{
  background: transparent !important;
  border: 1px solid var(--line-dark) !important;
  padding: 28px !important;
  max-width: none !important;
}
.signup-form .sib-form-block__button{
  background: var(--accent) !important;
  color: var(--white) !important;
  font-family: var(--font-display) !important;
  font-size: 14px !important;
  font-weight: 700 !important;
  letter-spacing: .08em !important;
  text-transform: uppercase !important;
  border: 0 !important;
  border-radius: 0 !important;
  padding: 14px 24px !important;
}
.signup-form .sib-form-block__button:hover{ background: var(--accent-bright) !important; }
.signup-form .entry__field{
  background: #ffffff !important;
  border: 0 !important;
  border-radius: 0 !important;
}
.signup-form .entry__label,
.signup-form .sib-text-form-block p,
.signup-form .entry__specification{ color: var(--muted-dark) !important; }
/* Brevo's duplicate heading and subtitle are removed from the MARKUP in
   index.html, not hidden here. A CSS rule that hid bare .sib-form-block also
   hid the submit button, because the button's wrapper carries the same class
   and nothing else. Lycan caught it live: an email field with no button and no
   way to know you had to press Enter. Do not reintroduce that rule. */
.signup-form #sib-container{ padding: 26px !important; }
.signup-form .entry__label{
  color: var(--white) !important;
  font-family: var(--f-mono, inherit);
  font-size: 12px !important;
  letter-spacing: .12em !important;
  text-transform: uppercase !important;
  font-weight: 700 !important;
}
.signup-form .entry__specification{ font-size: 12px !important; opacity: .7; }
.signup-form .sib-form-message-panel{ margin-bottom: 14px !important; }
.signup-form form,
.signup-form .sib-form-container{ padding: 0 !important; }
@media (max-width: 900px){
  .signup-section .wrap{ grid-template-columns: 1fr; gap: 32px; }
}
/* The input sits on white but inherited the section's white text, so anything
   typed was invisible. Caught live by Lycan. Pin both the text and the
   placeholder rather than relying on inheritance. */
.signup-form .entry__field input,
.signup-form input.input,
.signup-form input[type="text"],
.signup-form input[type="email"]{
  color: #16151a !important;
  background: #ffffff !important;
  -webkit-text-fill-color: #16151a !important;
}
.signup-form .entry__field input::placeholder,
.signup-form input::placeholder{ color: #8a8590 !important; opacity: 1 !important; }
/* Typed text was white on a white input because it inherited the dark section's
   colour. Caught live by Lycan. Pin text and placeholder explicitly. */
.signup-form .entry__field input,
.signup-form input.input,
.signup-form input[type="text"],
.signup-form input[type="email"]{
  color: #16151a !important;
  background: #ffffff !important;
  -webkit-text-fill-color: #16151a !important;
}
.signup-form .entry__field input::placeholder,
.signup-form input::placeholder{ color: #8a8590 !important; opacity: 1 !important; }
.signup-form #sib-container{ border-color: rgba(217,165,49,.32) !important; }
@media (max-width: 900px){
  .signup-panel{ padding: 46px 24px 38px; }
  .signup-badge{ left: 24px; }
  .signup-grid{ grid-template-columns: 1fr; gap: 30px; }
}

/* ---------- reCAPTCHA mobile fit (THE sideways-scroll bug) ----------
   Added 2026-09-18. Google's reCAPTCHA v2 checkbox is a hard 304x78px iframe.
   Inside this panel on a phone that did not fit, and because it is a real
   layout box it dragged the whole document wider than the viewport: measured
   443px against a 390px screen. Result was a page you could scroll sideways,
   a white strip down the side, and the "Get 10% off your first order" heading
   cut in half.

   The widget is scaled down and the wrapper clipped to the scaled footprint so
   the layout box shrinks with it. js/captcha-fit.js sets --cap-scale from the
   real measured width; the 1 here is the no-JS fallback, which combined with
   html{overflow-x:clip} degrades to "slightly clipped" rather than "page is
   broken". Do not scale the image-challenge popup — Google appends that to
   document.body, outside this container, and transforming it is a known source
   of positioning bugs. Full reasoning in js/captcha-fit.js. */
.signup-form .sib-captcha .form__label-row{
  width: calc(304px * var(--cap-scale, 1));
  height: calc(78px * var(--cap-scale, 1));
  overflow: hidden;
}
.signup-form .sib-captcha #sib-captcha{
  transform: scale(var(--cap-scale, 1));
  transform-origin: 0 0;
  width: 304px;
  height: 78px;
}
/* The email field had picked up the captcha's 304px as its width. Pin it fluid
   so it fills whatever the panel actually gives it. */
.signup-form .sib-input .entry__field,
.signup-form .sib-input input.input{
  width: 100% !important;
  max-width: 100% !important;
}
/* Nothing inside a third-party embed gets to set its own minimum width —
   EXCEPT the captcha subtree. Squashing that iframe to the container width
   does not make the widget responsive, it just clips Google's own content
   inside the frame (the logo and the "I'm not a robot" label get cut off).
   The captcha has to stay at its native 304px and be scaled instead. Measured:
   with the blanket rule applied the iframe rendered at 250px with its right
   edge cut. */
.signup-form,
.signup-form *:not(.sib-captcha *):not(.sib-captcha){ min-width: 0; max-width: 100%; }
.signup-form .sib-captcha #sib-captcha,
.signup-form .sib-captcha #sib-captcha > div,
.signup-form .sib-captcha #sib-captcha iframe{
  width: 304px !important;
  max-width: none !important;
  min-width: 304px !important;
}

/* Tighter gutters on a phone. 28px each side is a lot of a 390px screen, and
   every pixel reclaimed here is a pixel the captcha does not have to be scaled
   down by. */
@media (max-width: 620px){
  .wrap{ padding: 0 18px; }
  .signup-section{ padding: 64px 0; }
  .signup-panel{ padding: 40px 16px 32px; }
  .signup-badge{ left: 16px; }
  .signup-form #sib-container{ padding: 18px !important; }
}

/* ---------- image preview (js/lightbox.js) ---------- */
.p-media img, .flip-card img, .solo-frame img, .product-frame img{ cursor: zoom-in; }
.lb-lock, .lb-lock body{ overflow: hidden; }
.lb{
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  background: rgba(10,10,10,.92);
  opacity: 0; visibility: hidden;
  transition: opacity .2s ease, visibility .2s ease;
}
.lb.open{ opacity: 1; visibility: visible; }
.lb-fig{ margin: 0; text-align: center; }
.lb-img{
  display: block;
  max-width: min(92vw, 1100px); max-height: 84vh;
  object-fit: contain;
  background: var(--white);
  box-shadow: 0 20px 60px rgba(0,0,0,.55);
}
.lb-cap{
  margin-top: 14px; min-height: 1em;
  color: var(--muted-dark);
  font-size: .78rem; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
}
.lb button{
  position: absolute;
  background: transparent; border: 0;
  color: var(--white); cursor: pointer;
  line-height: 1; opacity: .8;
  transition: opacity .15s ease;
}
.lb button:hover, .lb button:focus-visible{ opacity: 1; }
.lb button:focus-visible{ outline: 2px solid var(--gold); outline-offset: 4px; }
.lb-close{ top: 18px; right: 24px; font-size: 2.6rem; }
.lb-nav{ top: 50%; transform: translateY(-50%); font-size: 4rem; padding: 0 18px; }
.lb-prev{ left: 12px; }
.lb-next{ right: 12px; }
.lb-nav[hidden]{ display: none; }
@media (max-width: 600px){
  .lb-nav{ font-size: 3rem; padding: 0 8px; }
  .lb-img{ max-height: 76vh; }
}

/* ==========================================================================
   Collection pages, shared furniture. Added 2026-10-08 with sweatshirts,
   journals, totes, home & desk and digital. Each of those pages styles its
   own hero in its own file; these are the parts they have in common.
   ========================================================================== */

/* Small facts row under a hero lede: "20 designs . From $49.99 . ..." */
.hero-meta{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 0;
  margin: 0 0 30px;
  font-size: .76rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.hero-meta li{ display: inline-flex; align-items: center; }
.hero-meta li + li::before{
  content: "";
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--accent);
  margin: 0 14px;
}
.hero-meta strong{ font-family: var(--font-display); font-weight: 400; font-size: 1.02rem; letter-spacing: .04em; }
/* On a phone the row wraps, and a wrapped line would start with a stray dot,
   so the dots give way to plain spacing there. */
@media (max-width: 620px){
  .hero-meta{ gap: 8px 20px; }
  .hero-meta li + li::before{ display: none; }
}

/* Four-up spec strip under a collection hero (same rhythm as the home
   page's trust strip, so the two read as one family). */
.spec-strip{
  background: var(--charcoal-2);
  border-top: 1px solid var(--line-dark);
  border-bottom: 1px solid var(--line-dark);
  color: var(--white);
}
.spec-strip .wrap{
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 24px;
  padding-top: 28px;
  padding-bottom: 28px;
}
.spec{ display: flex; align-items: flex-start; gap: 13px; }
.spec .num{ font-family: var(--font-display); font-size: 1.5rem; line-height: 1; color: var(--accent); }
.spec strong{ display: block; font-size: .92rem; line-height: 1.3; }
.spec .label{ display: block; margin-top: 4px; font-size: .76rem; line-height: 1.45; color: var(--muted-dark); }
@media (max-width: 900px){ .spec-strip .wrap{ grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 24px; } }
@media (max-width: 520px){ .spec-strip .wrap{ grid-template-columns: 1fr; gap: 16px; } }

/* Heading row above a product grid. */
.coll-head{
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 24px;
  margin-bottom: 26px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line-light);
}
.coll-head h2{ font-size: clamp(1.5rem, 3.4vw, 2.1rem); color: var(--ink); }
.coll-head p{ font-size: .86rem; line-height: 1.55; color: var(--muted-light); max-width: 60ch; }

/* "Keep browsing" band at the foot of a collection page. */
.aisle-links{
  background: var(--black);
  color: var(--white);
  padding: 64px 0 72px;
  border-top: 1px solid var(--line-dark);
  text-align: center;
}
.aisle-links h2{ font-size: clamp(1.5rem, 4vw, 2.2rem); margin-bottom: 10px; }
.aisle-links p{ color: var(--muted-dark); font-size: .95rem; line-height: 1.6; margin-bottom: 26px; }
.aisle-row{
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  max-width: 820px;
  margin: 0 auto;
}
.aisle-row a{
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted-dark);
  border: 1px solid var(--line-dark);
  border-radius: 999px;
  padding: 10px 18px;
  transition: color .15s ease, border-color .15s ease, background-color .15s ease;
}
.aisle-row a:hover{ color: var(--white); border-color: var(--white); }
.aisle-row a.aisle-all{ color: var(--white); background: var(--accent); border-color: var(--accent); }
.aisle-row a.aisle-all:hover{ background: var(--accent-bright); border-color: var(--accent-bright); }

/* Wide 4:3 card image for the digital bundles, whose previews carry five
   designs edge to edge and must not be cropped square. */
.p-media.p-media-wide{ aspect-ratio: 4 / 3; }
