/* ==========================================================================
   HIM — Component layer
   Every value below resolves to a semantic role or a primitive scale step.
   Authority: decisions/0001-foundations.md
   ========================================================================== */

/* ==========================================================================
   BUTTONS
   Square (radius 0). Primary = ink fill. Hover introduces gold, sparingly.
   ========================================================================== */

.him-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--him-space-2);
  padding: var(--him-space-4) var(--him-space-8);
  border-radius: var(--him-radius-none);
  border: var(--him-border-hairline) solid transparent;
  font-size: var(--him-size-eyebrow);
  font-weight: var(--him-weight-medium);
  text-transform: uppercase;
  letter-spacing: var(--him-tracking-eyebrow);
  line-height: 1;
  min-height: 48px;                 /* large tap target — a11y rule */
  cursor: pointer;
  transition: background var(--him-duration-base) var(--him-ease-inout),
              color      var(--him-duration-base) var(--him-ease-inout),
              border     var(--him-duration-base) var(--him-ease-inout);
}

.him-btn-primary {
  background: var(--content);
  color: var(--content-inverse);
  border-color: var(--content);
}
.him-btn-primary:hover:not(:disabled) {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--him-black);
}

.him-btn-secondary {
  background: transparent;
  color: var(--content);
  border-color: var(--border-strong);
}
.him-btn-secondary:hover:not(:disabled) {
  border-color: var(--accent);
  color: var(--accent-text);
}

.him-btn-ghost {
  background: transparent;
  color: var(--content-muted);
  padding-inline: var(--him-space-3);
  min-height: 44px;
}
.him-btn-ghost:hover:not(:disabled) { color: var(--content); }

.him-btn-full { width: 100%; }

.him-btn:disabled,
.him-btn-disabled,
.him-btn[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

/* A text link that behaves like a CTA — the editorial alternative to a button. */
.him-link-underline {
  display: inline-block;
  font-size: var(--him-size-eyebrow);
  font-weight: var(--him-weight-medium);
  text-transform: uppercase;
  letter-spacing: var(--him-tracking-eyebrow);
  padding-bottom: var(--him-space-1);
  border-bottom: var(--him-border-hairline) solid var(--border-strong);
}
.him-link-underline:hover { color: var(--accent-text); border-bottom-color: var(--border-accent); }

/* ==========================================================================
   FORM FIELDS
   ========================================================================== */

.him-field { display: flex; flex-direction: column; gap: var(--him-space-2); }

.him-label {
  font-size: var(--him-size-eyebrow);
  font-weight: var(--him-weight-medium);
  text-transform: uppercase;
  letter-spacing: var(--him-tracking-eyebrow);
  color: var(--content-muted);
}

.him-input,
.him-textarea,
.him-select {
  width: 100%;
  padding: var(--him-space-4);
  min-height: 48px;
  background: transparent;
  color: var(--content);
  border: 0;
  border-bottom: var(--him-border-hairline) solid var(--border-interactive);
  border-radius: var(--him-radius-none);
  font-size: var(--him-size-body);
  transition: border-color var(--him-duration-base) var(--him-ease-inout);
}
.him-input::placeholder,
.him-textarea::placeholder { color: var(--content-subtle); }

.him-input:hover,
.him-textarea:hover,
.him-select:hover { border-bottom-color: var(--content-subtle); }

.him-input:focus,
.him-textarea:focus,
.him-select:focus {
  outline: none;
  border-bottom-color: var(--border-strong);
  border-bottom-width: var(--him-border-emphasis);
}
.him-input:focus-visible,
.him-textarea:focus-visible,
.him-select:focus-visible { outline: var(--him-border-emphasis) solid var(--focus-ring); outline-offset: 2px; }

.him-textarea { min-height: 120px; resize: vertical; }

.him-select {
  appearance: none;
  padding-right: var(--him-space-8);
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 14px) center, calc(100% - 9px) center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

/* Invalid state preserves entered data (checkout edge case) — visual only. */
.him-field[data-invalid="true"] .him-input,
.him-field[data-invalid="true"] .him-textarea,
.him-field[data-invalid="true"] .him-select {
  border-bottom-color: var(--state-error);
  border-bottom-width: var(--him-border-emphasis);
}
.him-field-error {
  font-size: var(--him-size-caption);
  color: var(--state-error);
}
.him-field-hint { font-size: var(--him-size-caption); color: var(--content-subtle); }

/* ---------- Size selector (product detail) ---------- */
.him-size-group { display: flex; flex-wrap: wrap; gap: var(--him-space-2); }
.him-size-option {
  min-width: 52px;
  min-height: 48px;
  padding: var(--him-space-3) var(--him-space-4);
  border: var(--him-border-hairline) solid var(--border-interactive);
  border-radius: var(--him-radius-none);
  background: transparent;
  color: var(--content);
  font-size: var(--him-size-caption);
  letter-spacing: var(--him-tracking-eyebrow);
  text-transform: uppercase;
  transition: border-color var(--him-duration-base) var(--him-ease-inout);
}
.him-size-option:hover:not(:disabled) { border-color: var(--content-subtle); }
.him-size-option[aria-pressed="true"] {
  border-color: var(--border-strong);
  border-width: var(--him-border-emphasis);
}
.him-size-option:disabled {
  opacity: 0.3;
  cursor: not-allowed;
  text-decoration: line-through;
}

/* ---------- Quantity stepper ---------- */
.him-qty {
  display: inline-flex;
  align-items: center;
  border: var(--him-border-hairline) solid var(--border-interactive);
}
.him-qty button {
  width: 48px; height: 48px;
  display: grid; place-items: center;
  color: var(--content-muted);
  transition: color var(--him-duration-base) var(--him-ease-inout);
}
.him-qty button:hover:not(:disabled) { color: var(--content); }
.him-qty button:disabled { opacity: 0.3; cursor: not-allowed; }
.him-qty input {
  width: 48px;
  text-align: center;
  border: 0;
  background: transparent;
  font-size: var(--him-size-body);
  -moz-appearance: textfield;
}
.him-qty input::-webkit-outer-spin-button,
.him-qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* ==========================================================================
   CARDS  — flat by design. No shadow, no hover-lift (ADR 0001 §7).
   ========================================================================== */

.him-card {
  display: flex;
  flex-direction: column;
  gap: var(--him-space-4);
  background: transparent;
  border-radius: var(--him-radius-none);
}

/* Image frame: fixed ratio, overflow-clipped so the reveal scale has room. */
.him-media {
  position: relative;
  overflow: hidden;
  background: var(--surface-sunken);
  border-radius: var(--him-radius-none);
}
.him-media > img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform var(--him-duration-cinematic) var(--him-ease-out),
              opacity   var(--him-duration-slow) var(--him-ease-out);
}
.him-ratio-portrait { aspect-ratio: 3 / 4; }
.him-ratio-square   { aspect-ratio: 1 / 1; }
.him-ratio-editorial{ aspect-ratio: 4 / 5; }
.him-ratio-wide     { aspect-ratio: 16 / 9; }

/* Only the image moves on hover — the card itself never lifts. */
.him-card:hover .him-media > img,
a:hover > .him-media > img { transform: scale(1.04); }

/* Scrim for type over photography — the one permitted gradient. */
.him-media-scrim::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--him-scrim-image);
  pointer-events: none;
}

.him-card-body { display: flex; flex-direction: column; align-items: flex-start; gap: var(--him-space-2); }
.him-price { font-size: var(--him-size-body); color: var(--content); }
.him-price-accent { color: var(--accent); }

/* Editorial card — same shell, prose-led rather than image-led. Grid/flex
   parents already stretch every card in a row to the tallest one's height
   (.him-scroll-row, .him-stack-lg); this makes that stretch land as evenly
   distributed content instead of dead space under a short excerpt. */
.him-card-editorial { display: flex; flex-direction: column; height: 100%; }
.him-card-editorial .him-card-body { gap: var(--him-space-3); flex: 1; }
.him-card-editorial .him-card-body > :last-child { margin-top: auto; }

/* Horizontal scroll strip — for the journal row, where a wide grid would force
   a tall page just to fit a few stories. Scrollbar stays visible (not hidden)
   so touch and mouse users both get the affordance that there's more to see. */
.him-scroll-row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(280px, 340px);
  gap: var(--him-space-8);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding-bottom: var(--him-space-4);
  scrollbar-width: thin;
  scrollbar-color: var(--him-neutral-450) transparent;
}
.him-scroll-row > * { scroll-snap-align: start; }
.him-scroll-row::-webkit-scrollbar { height: 6px; }
.him-scroll-row::-webkit-scrollbar-track { background: transparent; }
.him-scroll-row::-webkit-scrollbar-thumb { background: var(--him-neutral-450); border-radius: 999px; }

@media (prefers-reduced-motion: reduce) {
  .him-scroll-row { scroll-behavior: auto; }
}

/* Collection tile — full-bleed image with type laid over it. */
.him-tile { position: relative; display: block; overflow: hidden; }
.him-tile-content {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  padding: var(--him-space-8);
  color: var(--him-paper);
  z-index: 1;
}

/* ==========================================================================
   BADGES / TAGS
   ========================================================================== */

.him-badge {
  display: inline-flex;
  align-items: center;
  padding: var(--him-space-1) var(--him-space-3);
  border: var(--him-border-hairline) solid var(--border);
  border-radius: var(--him-radius-none);
  font-size: 0.6875rem;
  font-weight: var(--him-weight-medium);
  text-transform: uppercase;
  letter-spacing: var(--him-tracking-eyebrow);
  color: var(--content-muted);
}
.him-badge-accent { border-color: var(--border-accent); color: var(--accent-text); }
.him-badge-out    { border-color: var(--border); color: var(--content-subtle); }

/* ==========================================================================
   TEXT CLAMPING — equal-height cards
   Journal cards carry variable-length excerpts; without a clamp the tallest
   card in a row sets an arbitrary height and shorter ones just float in
   whitespace (CSS grid already stretches every column to match — see
   .him-scroll-row — this is what makes that stretch look intentional rather
   than empty).
   ========================================================================== */
.him-clamp-2, .him-clamp-3 {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Reserves the second line's height even for a one-line title, so a short
   title sits top-aligned with empty space below it instead of the whole
   card shrinking — every title in a row occupies the same footprint whether
   it wraps or not. Only used on the journal-card title (js/app.js storyCard). */
.him-clamp-2 {
  -webkit-line-clamp: 2;
  min-height: calc(2em * var(--him-leading-heading));
}
.him-clamp-3 { -webkit-line-clamp: 3; }

/* ==========================================================================
   FADED SECTION — for content that exists but isn't the point yet (the shop,
   pre-launch). Muted, not hidden: the section and its links stay fully
   usable, they just visually recede behind the editorial content above them.
   ========================================================================== */
.him-shop-teaser {
  opacity: 0.6;
  filter: grayscale(0.4);
  transition: opacity var(--him-duration-slow) var(--him-ease-out);
}
.him-shop-teaser:hover,
.him-shop-teaser:focus-within {
  opacity: 0.9;
  filter: grayscale(0.15);
}
@media (prefers-reduced-motion: reduce) {
  .him-shop-teaser { transition: none; }
}

/* ==========================================================================
   HEADER / NAVIGATION
   ========================================================================== */

.him-header {
  position: sticky;
  top: 0;
  z-index: var(--him-z-header);
  background: var(--surface);
  border-bottom: var(--him-border-hairline) solid var(--border);
  transition: background var(--him-duration-base) var(--him-ease-inout);
}
.him-header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--him-space-8);
  min-height: 72px;
}

.him-wordmark {
  font-size: var(--him-size-title);
  font-weight: var(--him-weight-light);
  text-transform: uppercase;
  letter-spacing: var(--him-tracking-eyebrow);
}

.him-nav { display: none; gap: var(--him-space-8); }
@media (min-width: 1024px) { .him-nav { display: flex; } }

.him-nav-link {
  position: relative;
  font-size: var(--him-size-eyebrow);
  font-weight: var(--him-weight-medium);
  text-transform: uppercase;
  letter-spacing: var(--him-tracking-eyebrow);
  color: var(--content-muted);
  padding-block: var(--him-space-2);
}
.him-nav-link:hover { color: var(--content); }
/* Gold marks the active nav item and nothing else (ADR 0001 §5). */
.him-nav-link[aria-current="page"] {
  color: var(--content);
  border-bottom: var(--him-border-emphasis) solid var(--border-accent);
}

/* Journal dropdown — every category reachable from the (already sticky)
   header, per Francisca's request. Hover/focus-within on desktop; mobile
   gets .him-nav-mobile-categories instead (always expanded, no hover). */
.him-nav-item { position: relative; display: flex; align-items: center; }
.him-nav-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: var(--him-space-4);
  min-width: 200px;
  display: grid;
  gap: var(--him-space-1);
  padding: var(--him-space-4);
  background: var(--surface-raised);
  border: var(--him-border-hairline) solid var(--border);
  box-shadow: var(--him-shadow-overlay);
  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  transition: opacity var(--him-duration-base) var(--him-ease-out),
              transform var(--him-duration-base) var(--him-ease-out),
              visibility var(--him-duration-base);
}
.him-nav-item:hover .him-nav-dropdown,
.him-nav-item:focus-within .him-nav-dropdown {
  opacity: 1;
  visibility: visible;
  transform: none;
}
.him-nav-dropdown-link {
  font-size: var(--him-size-eyebrow);
  color: var(--content-muted);
  padding: var(--him-space-2) var(--him-space-2);
  white-space: nowrap;
}
.him-nav-dropdown-link:hover { color: var(--content); }
.him-nav-dropdown-all {
  border-top: var(--him-border-hairline) solid var(--border);
  margin-top: var(--him-space-2);
  padding-top: var(--him-space-3);
  font-weight: var(--him-weight-medium);
}

.him-nav-mobile-categories {
  display: grid;
  gap: var(--him-space-2);
  padding-left: var(--him-space-6);
  margin-top: var(--him-space-2);
}
.him-nav-mobile-categories .him-nav-dropdown-link {
  font-size: var(--him-size-caption);
  padding-block: var(--him-space-1);
}

.him-header-actions { display: flex; align-items: center; gap: 0; }
@media (min-width: 640px) { .him-header-actions { gap: var(--him-space-2); } }

.him-cart-count {
  display: inline-grid;
  place-items: center;
  min-width: 18px; height: 18px;
  padding-inline: 4px;
  background: var(--content);
  color: var(--content-inverse);
  font-size: 0.625rem;
  font-weight: var(--him-weight-semibold);
}

/* ==========================================================================
   OVERLAYS — search, cart drawer, modal. The only elevated surfaces.
   ========================================================================== */

.him-scrim {
  position: fixed;
  inset: 0;
  background: var(--him-scrim);
  z-index: var(--him-z-overlay);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--him-duration-base) var(--him-ease-inout),
              visibility var(--him-duration-base);
}
.him-scrim[data-open="true"] { opacity: 1; visibility: visible; }

.him-drawer {
  position: fixed;
  top: 0; right: 0;
  height: 100dvh;
  width: min(440px, 100vw);
  z-index: var(--him-z-modal);
  display: flex;
  flex-direction: column;
  background: var(--surface-raised);
  box-shadow: var(--him-shadow-overlay);
  transform: translateX(100%);
  transition: transform var(--him-duration-slow) var(--him-ease-out);
}
.him-drawer[data-open="true"] { transform: translateX(0); }

.him-drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--him-space-6);
  border-bottom: var(--him-border-hairline) solid var(--border);
}
.him-drawer-body   { flex: 1; overflow-y: auto; padding: var(--him-space-6); }
.him-drawer-footer { padding: var(--him-space-6); border-top: var(--him-border-hairline) solid var(--border); }

.him-search-overlay {
  position: fixed;
  inset-inline: 0; top: 0;
  z-index: var(--him-z-modal);
  background: var(--surface);
  border-bottom: var(--him-border-hairline) solid var(--border);
  padding-block: var(--him-space-12);
  transform: translateY(-100%);
  transition: transform var(--him-duration-slow) var(--him-ease-out);
}
.him-search-overlay[data-open="true"] { transform: translateY(0); }
.him-search-input {
  width: 100%;
  border: 0;
  border-bottom: var(--him-border-hairline) solid var(--border);
  background: transparent;
  padding-block: var(--him-space-4);
  font-size: var(--him-size-headline-2);
  font-weight: var(--him-weight-light);
  letter-spacing: var(--him-tracking-heading);
}
.him-search-input:focus { outline: none; border-bottom-color: var(--border-strong); }

/* ==========================================================================
   STATES — empty, loading, toast, 404
   ========================================================================== */

.him-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--him-space-6);
  padding-block: var(--him-space-24);
}

/* Skeletons mirror the shape of what they replace. Opacity pulse only. */
.him-skeleton {
  background: var(--surface-sunken);
  border-radius: var(--him-radius-none);
  animation: him-pulse 1.6s var(--him-ease-inout) infinite;
}
@keyframes him-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }

.him-skeleton-text { height: 1em; }
.him-skeleton-text + .him-skeleton-text { margin-top: var(--him-space-2); }

.him-spinner {
  width: 24px; height: 24px;
  border: var(--him-border-emphasis) solid var(--border);
  border-top-color: var(--content);
  border-radius: 50%;
  animation: him-spin 900ms linear infinite;
}
@keyframes him-spin { to { transform: rotate(360deg); } }

.him-toast {
  position: fixed;
  bottom: var(--him-space-8);
  left: 50%;
  z-index: var(--him-z-modal);
  display: flex;
  align-items: center;
  gap: var(--him-space-4);
  padding: var(--him-space-4) var(--him-space-6);
  background: var(--surface-inverse);
  color: var(--content-inverse);
  box-shadow: var(--him-shadow-overlay);
  transform: translate(-50%, calc(100% + var(--him-space-8)));
  transition: transform var(--him-duration-slow) var(--him-ease-out);
}
.him-toast[data-open="true"] { transform: translate(-50%, 0); }

/* ==========================================================================
   SCROLL REVEAL  (ADR 0001 §8)

   Opt-IN, deliberately. The hidden state only applies once js/animations.js
   has confirmed it can observe and un-hide these elements. If JS fails, is
   blocked, or IntersectionObserver misbehaves, `.him-reveal` means nothing and
   the content is simply visible — a shop whose products need JavaScript to
   become visible is a shop that sometimes sells nothing.

   Deliberately restrained: opacity plus a 12px rise, no horizontal movement,
   no scale on text. At editorial scale a big element sliding far reads as a
   template; a short settle reads as the page arriving.
   ========================================================================== */

.him-reveal-ready .him-reveal {
  opacity: 0;
  /* KingFizzy, 2026-07-23: wanted a more noticeable fade + slide-up as pages
     scroll — 24px (was 12px), same restrained single-axis rise, no scale or
     horizontal movement, per decisions/0009. */
  transform: translateY(24px);
  transition: opacity   var(--him-duration-slow) var(--him-ease-out),
              transform var(--him-duration-slow) var(--him-ease-out);
  transition-delay: var(--him-reveal-delay, 0ms);
}
.him-reveal-ready .him-reveal[data-revealed="true"] {
  opacity: 1;
  transform: none;
}

/* Media inside a revealing block also un-scales — the camera-move feel. */
.him-reveal-ready .him-reveal > img,
.him-reveal-ready .him-reveal .him-media > img {
  transform: scale(1.04);
  transition: transform var(--him-duration-cinematic) var(--him-ease-out);
}
.him-reveal-ready .him-reveal[data-revealed="true"] > img,
.him-reveal-ready .him-reveal[data-revealed="true"] .him-media > img {
  transform: scale(1);
}

/* A hero must never wait for an observer — it is already in view on load. */
.him-hero .him-reveal { opacity: 1; transform: none; }

/* ==========================================================================
   UTILITIES
   ========================================================================== */

.him-divider   { border-top: var(--him-border-hairline) solid var(--border); }
.him-flex      { display: flex; }
.him-between   { display: flex; align-items: center; justify-content: space-between; }
.him-center    { display: flex; align-items: center; justify-content: center; }
.him-gap-2     { gap: var(--him-space-2); }
.him-gap-4     { gap: var(--him-space-4); }
.him-gap-6     { gap: var(--him-space-6); }

/* ==========================================================================
   WORDMARK
   Rendered as a CSS mask, not an <img>. An <img src="logo.svg"> is a separate
   document: `currentColor` inside it resolves against ITS root, not the host
   page, so the mark stayed black on an ink ground. A mask takes its colour
   from background-color on this element, which does inherit — so the wordmark
   themes with everything else. Verified in-browser 2026-07-21.

   Consumers set height only; width follows the glyph's measured aspect ratio.
   Needs role="img" + aria-label, since a mask carries no alt text.
   ========================================================================== */

.him-logo {
  display: block;
  height: 28px;
  aspect-ratio: 1348 / 714;          /* measured glyph bounds, ADR 0001 §2 */
  background-color: currentColor;
  -webkit-mask: url("../assets/images/logo.svg") no-repeat center / contain;
          mask: url("../assets/images/logo.svg") no-repeat center / contain;
}

/* Below ~20px the ball terminal and the thin strokes break up. */
.him-logo-sm { height: 20px; }
.him-logo-lg { height: 48px; }

/* ==========================================================================
   MOBILE NAV
   ========================================================================== */
.him-mobile-nav {
  border-top: var(--him-border-hairline) solid var(--border);
  background: var(--surface);
}
.him-mobile-nav .him-nav-link { display: block; }

/* ==========================================================================
   FOOTER
   ========================================================================== */
.him-footer { padding-block: var(--him-space-16) var(--him-space-8); margin-top: var(--him-space-24); }
.him-footer-top {
  display: grid;
  gap: var(--him-space-12);
  grid-template-columns: 1fr;
  padding-bottom: var(--him-space-12);
}
@media (min-width: 768px) {
  .him-footer-top { grid-template-columns: 2fr 1fr 1fr; gap: var(--him-space-16); }
}
.him-footer-bottom {
  display: flex; flex-wrap: wrap; gap: var(--him-space-4);
  justify-content: space-between;
  padding-top: var(--him-space-8);
  border-top: var(--him-border-hairline) solid var(--border);
}
.him-footer a:hover { color: var(--accent-text); }

/* ==========================================================================
   CART LINE
   ========================================================================== */
.him-cart-line { display: flex; gap: var(--him-space-4); padding-block: var(--him-space-6); }
.him-cart-line + .him-cart-line { border-top: var(--him-border-hairline) solid var(--border); }
.him-cart-line .him-qty button { width: 36px; height: 36px; }
.him-cart-line .him-qty input  { width: 36px; }

/* ==========================================================================
   HERO — full-bleed image with type over it
   ========================================================================== */
.him-hero { position: relative; min-height: 78dvh; display: grid; align-items: end; overflow: hidden; }
.him-hero-media { position: absolute; inset: 0; }
.him-hero-media img { width: 100%; height: 100%; object-fit: cover; }
.him-hero-content { position: relative; z-index: 1; padding-block: var(--him-space-16); color: var(--him-paper); }
.him-hero-content .him-eyebrow { color: inherit; opacity: 0.75; }

/* ---------- Homepage hero carousel (decisions/0010, 0011) ---------------
   Every slide is deliberately the same ~16:9 landscape aspect as the
   original static hero — mixing a portrait-shot photo into a wide hero
   band is what cropped a face out entirely regardless of device size. If a
   future slide is a different aspect, give it its own object-position
   override rather than trusting the default centre crop. */
.him-hero-carousel .him-hero-slide {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity 1.4s ease;
}
.him-hero-carousel .him-hero-slide[data-active="true"] { opacity: 1; }
.him-hero-carousel .him-hero-slide img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 30%;   /* biases toward faces, which sit high in these crops */
}
.him-hero-carousel .him-hero-slide[data-active="true"] img { animation: him-hero-ken-burns 9s ease-out forwards; }
@keyframes him-hero-ken-burns {
  from { transform: scale(1.06); }
  to   { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .him-hero-carousel .him-hero-slide[data-active="true"] img { animation: none; }
}

.him-hero-dots {
  position: absolute;
  left: var(--him-gutter);
  bottom: var(--him-space-8);
  display: flex;
  gap: var(--him-space-3);
  z-index: 2;
}
.him-hero-dot {
  width: 28px; height: 3px;
  background: rgba(250, 250, 248, 0.35);
  border: 0;
  cursor: pointer;
  transition: background var(--him-duration-base) var(--him-ease-out);
}
.him-hero-dot[aria-current="true"] { background: var(--him-paper); }

/* ---------- Hero text entrance: kinetic headline + staggered rest --------
   Deliberately slow and sequential — eyebrow, then the headline word by
   word, then the subtitle, then the CTA row, each waiting for the previous
   to finish rather than all firing at once. Delays are computed in
   js/app.js from the actual word count, not hardcoded, so this survives a
   headline rewrite. Load-triggered, not scroll-triggered — a hero is
   already in view, so .him-reveal's IntersectionObserver path doesn't apply. */
.him-hero-kinetic-word {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.5em);
  animation: him-hero-kinetic-in 1.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: var(--word-delay, 0ms);
}
@keyframes him-hero-kinetic-in {
  to { opacity: 1; transform: translateY(0); }
}

.him-hero-content [data-hero-reveal] {
  opacity: 0;
  transform: translateY(16px);
  animation: him-hero-kinetic-in 1s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: var(--reveal-delay, 0ms);
}

@media (prefers-reduced-motion: reduce) {
  .him-hero-kinetic-word,
  .him-hero-content [data-hero-reveal] { animation: none; opacity: 1; transform: none; }
}

/* ==========================================================================
   PRODUCT DETAIL
   ========================================================================== */
.him-product { display: grid; gap: var(--him-space-12); grid-template-columns: 1fr; }
@media (min-width: 1024px) {
  .him-product { grid-template-columns: 1.15fr 1fr; gap: var(--him-space-16); align-items: start; }
  .him-product-info { position: sticky; top: calc(72px + var(--him-space-12)); }
}
.him-gallery { display: grid; gap: var(--him-space-4); }

/* ==========================================================================
   FILTER BAR
   ========================================================================== */
.him-filters { display: flex; flex-wrap: wrap; gap: var(--him-space-2); }
.him-filter {
  padding: var(--him-space-3) var(--him-space-4);
  min-height: 44px;
  border: var(--him-border-hairline) solid var(--border-interactive);
  font-size: var(--him-size-eyebrow);
  text-transform: uppercase;
  letter-spacing: var(--him-tracking-eyebrow);
  color: var(--content-muted);
  transition: border-color var(--him-duration-base) var(--him-ease-inout),
              color var(--him-duration-base) var(--him-ease-inout);
}
.him-filter:hover { color: var(--content); }
.him-filter[aria-pressed="true"] {
  color: var(--content);
  border-color: var(--border-strong);
  border-width: var(--him-border-emphasis);
}

/* ==========================================================================
   EDITORIAL ARTICLE
   ========================================================================== */
.him-article-body > p { font-size: var(--him-size-body-lg); line-height: var(--him-leading-body); }
.him-article-body > p + p { margin-top: var(--him-space-6); }
.him-article-meta { display: flex; flex-wrap: wrap; gap: var(--him-space-4); align-items: center; }

/* ==========================================================================
   ORDER / CHECKOUT SUMMARY
   ========================================================================== */
.him-checkout { display: grid; gap: var(--him-space-12); grid-template-columns: 1fr; }
@media (min-width: 1024px) {
  .him-checkout { grid-template-columns: 1.3fr 1fr; gap: var(--him-space-16); align-items: start; }
  .him-checkout-summary { position: sticky; top: calc(72px + var(--him-space-12)); }
}
.him-summary-line { display: flex; justify-content: space-between; gap: var(--him-space-4); }
.him-summary-line + .him-summary-line { margin-top: var(--him-space-3); }
.him-summary-total {
  display: flex; justify-content: space-between; gap: var(--him-space-4);
  padding-top: var(--him-space-4); margin-top: var(--him-space-4);
  border-top: var(--him-border-hairline) solid var(--border);
}

/* Page-level state machine — [data-state] swaps loading / empty / ready. */
[data-state="loading"] .is-ready, [data-state="loading"] .is-empty,
[data-state="empty"]   .is-ready, [data-state="empty"]   .is-loading,
[data-state="ready"]   .is-empty, [data-state="ready"]   .is-loading { display: none; }

/* ==========================================================================
   ICON BUTTONS — hamburger + theme toggle
   Both are 48px targets with a visible label for screen readers only.
   ========================================================================== */

.him-icon-btn {
  display: inline-grid;
  place-items: center;
  width: 48px; height: 48px;
  color: var(--content-muted);
  border-radius: var(--him-radius-none);
  transition: color var(--him-duration-base) var(--him-ease-inout);
}
.him-icon-btn:hover { color: var(--content); }
.him-icon-btn svg { width: 20px; height: 20px; }

/* Below 640px the header ran out of room and clipped the hamburger off the
   right edge — so Search and Bag collapse to icons and only their labels go. */
.him-action { gap: var(--him-space-2); }
.him-action-icon { width: 20px; height: 20px; }
.him-action-text { display: none; }
@media (min-width: 640px) {
  .him-action-icon { display: none; }
  .him-action-text { display: inline; }
}

/* Hamburger — three rules that become an X. Mobile only; the full nav shows
   from 1024px up, where this button is display:none. */
.him-burger { display: inline-grid; }
@media (min-width: 1024px) { .him-burger { display: none; } }

.him-burger-box { width: 20px; height: 14px; position: relative; }
.him-burger-box span {
  position: absolute; left: 0;
  width: 100%; height: var(--him-border-hairline);
  background: currentColor;
  transition: transform var(--him-duration-base) var(--him-ease-inout),
              opacity   var(--him-duration-instant) var(--him-ease-inout);
}
.him-burger-box span:nth-child(1) { top: 0; }
.him-burger-box span:nth-child(2) { top: 50%; transform: translateY(-50%); }
.him-burger-box span:nth-child(3) { bottom: 0; }

.him-burger[aria-expanded="true"] .him-burger-box span:nth-child(1) { top: 50%; transform: translateY(-50%) rotate(45deg); }
.him-burger[aria-expanded="true"] .him-burger-box span:nth-child(2) { opacity: 0; }
.him-burger[aria-expanded="true"] .him-burger-box span:nth-child(3) { bottom: 50%; transform: translateY(50%) rotate(-45deg); }

/* Theme toggle — sun and moon swap on the current theme.
   Scoped to .him-icon-btn so these beat `.him-icon-btn svg`; at bare class
   specificity the generic svg rule won and both icons rendered at once. */
.him-icon-btn .him-theme-sun  { display: block; }
.him-icon-btn .him-theme-moon { display: none; }
:root[data-theme="dark"] .him-icon-btn .him-theme-sun  { display: none; }
:root[data-theme="dark"] .him-icon-btn .him-theme-moon { display: block; }

/* ==========================================================================
   ADDRESS COMBOBOX
   The list overlays following content, so it needs a stacking context above
   the sticky order summary but below any modal.
   ========================================================================== */

.him-combobox { position: relative; }

.him-suggestions {
  position: absolute;
  inset-inline: 0;
  top: 100%;
  z-index: var(--him-z-overlay);
  max-height: 280px;
  overflow-y: auto;
  background: var(--surface-raised);
  border: var(--him-border-hairline) solid var(--border-interactive);
  border-top: 0;
  box-shadow: var(--him-shadow-overlay);
}

.him-suggestion {
  padding: var(--him-space-4);
  min-height: 48px;                    /* tap target, same floor as buttons */
  display: flex;
  align-items: center;
  font-size: var(--him-size-caption);
  color: var(--content);
  cursor: pointer;
  border-bottom: var(--him-border-hairline) solid var(--border);
}
.him-suggestion:last-child { border-bottom: 0; }
.him-suggestion:hover,
.him-suggestion[aria-selected="true"] {
  background: var(--surface-sunken);
}
/* Keyboard highlight needs to survive on a hovered list, so mark it distinctly. */
.him-suggestion[aria-selected="true"] {
  box-shadow: inset 3px 0 0 var(--border-strong);
}
