/* =============================================================
   DRXP.SHOP — pages the prototype did not cover.

   Product, cart, artists, content pages. Built strictly on the design
   tokens defined in home.css (--acc, --line, --head, etc.) so these
   screens read as the same store. home.css stays untouched; it is the
   design contract.
   ============================================================= */

/* =============================================================
   HERO DRIFT WALL — deliberate tuning on top of the prototype

   home.css stays byte-faithful to the design; these four overrides
   live here so the deviation is visible and easy to revert.

   Asked for: the wall was hard to make out and the parallax felt
   laggy. Root cause of the murk was the veil and the image filter
   stacking on top of each other over artwork that is already dark.
   ============================================================= */

/* The design darkens each card to .7 brightness and desaturates to .6.
   Combined with the veil on top, the art underneath barely reads. Lifting
   both keeps the moody grade but lets you actually see what is on the wall.
   Hover still resolves to a full-colour, unfiltered image as designed. */
.dcard img {
  filter: grayscale(.42) contrast(1.04) brightness(.86);
}

/* The vignette was near-opaque at the centre (.95) to protect the logo.
   Easing the inner stops keeps the copy legible while letting the columns
   show through. The outer stop is left alone — it is what stops the wall
   colliding with the nav and the section below. */
.drift-veil {
  background: radial-gradient(ellipse 68% 62% at 50% 48%,
              rgba(10, 10, 10, .84) 0%,
              rgba(10, 10, 10, .66) 40%,
              rgba(10, 10, 10, .22) 70%,
              rgba(10, 10, 10, .88) 100%);
}

/* The parallax had a .6s transition on transform, so the wall kept sliding
   for over half a second after the cursor stopped — that trailing motion is
   what read as lag. Shorter feels attached to the pointer without becoming
   twitchy. */
.drift-stage {
  transition: transform .28s cubic-bezier(.16, .84, .28, 1);
}

/* Nudge the label up out of the gradient so prices stay readable against
   busy artwork. */
.dcard .dlab {
  background: linear-gradient(0deg, rgba(10, 10, 10, .96), rgba(10, 10, 10, .55) 55%, transparent);
}

/* Lifting the veil above made the wall legible but left the hero paragraph
   competing with whatever artwork drifts behind it. Rather than darkening the
   whole wall again — which is the thing we just fixed — the copy carries its
   own local scrim. The wall stays bright; only the ~700px behind the text is
   damped, and it fades out well before the card edges so there is no visible
   seam. */
.drift-copy::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: min(1120px, 100%);
  height: min(720px, 88%);
  transform: translate(-50%, -50%);
  background: radial-gradient(ellipse at center,
              rgba(10, 10, 10, .78) 0%,
              rgba(10, 10, 10, .58) 45%,
              rgba(10, 10, 10, 0) 74%);
  pointer-events: none;
  z-index: -1;
}

/* Belt and braces for the smaller copy, which sits nearest the bright
   centre of the wall. */
.hero-line,
.hero-sub {
  text-shadow: 0 2px 14px rgba(10, 10, 10, .85);
}

@media (prefers-reduced-motion: reduce) {
  .drift-stage { transition: none; }
}

/* =============================================================
   SMOOTH WITHOUT GRAPHICS ACCELERATION

   Reported as lag for some visitors. Measured with Chrome's GPU acceleration
   switched off (software rendering — what a browser with hardware
   acceleration disabled, or an old/virtual machine, actually gets), 1440x900:

     homepage hero       28fps -> 58fps
     preview open        17fps -> 60fps  (97% of frames were janky)

   Nothing below removes an effect a visitor would notice. What changed is
   how each is drawn. The rule of thumb for anything added later: a CSS
   filter (blur, drop-shadow) or backdrop-filter on something that moves, or
   sits over something that moves, is recomputed on the CPU every frame
   when there's no GPU. Animate transform and opacity; bake the rest.
   ============================================================= */

/* The scanline texture blended the whole viewport (mix-blend-mode:overlay on
   a fixed full-screen layer) on every frame of every animation. At its
   strength the blend was imperceptible; a flat, faint line reads the same. */
body::before {
  mix-blend-mode: normal;
  opacity: 1;
  background: repeating-linear-gradient(0deg, rgba(255, 255, 255, .008) 0 1px, transparent 1px 3px);
}
/* Phones and tablets: none at all. At .8% white it cannot be seen, and
   Safari's engine repainted this full-screen layer on every scroll frame:
   switching it off took a plain page from 81ms frames to 30ms in WebKit. */
@media (hover: none) and (pointer: coarse) { body::before { content: none; } }

/* Frosted glass over a moving wall re-blurs the wall every frame. At these
   opacities the frosting barely showed through anyway. */
#nav { backdrop-filter: none; -webkit-backdrop-filter: none; background: rgba(10, 10, 10, .82); }
.dhint { backdrop-filter: none; -webkit-backdrop-filter: none; background: rgba(18, 18, 17, .84); }
.wall-toggle { backdrop-filter: none; -webkit-backdrop-filter: none; background: rgba(10, 10, 10, .82); }
.has-slides .piece-frame::after { backdrop-filter: none; -webkit-backdrop-filter: none; background: rgba(10, 10, 10, .78); }
.lb::before { content: none; }

/* The single biggest cost. The logo's 46px drop-shadow sat on the same
   element as its infinite breathing animation, so the shadow was recomputed
   every frame. The breath moves to the wrapper: the shadowed image is drawn
   once and the whole thing moves as a unit, identical on screen. */
.hero-logo { animation: logoin 1.15s cubic-bezier(.16, .84, .24, 1) both; will-change: auto; }
.hero-logo-wrap { animation: logobreathe 7s ease-in-out 2.2s infinite; }
/* The glow was a radial gradient with a 22px blur on top — blurring
   something already soft, every frame of its own breathing animation. A
   gradient that fades a little further out is the same light. */
.hero-logo-wrap::before {
  filter: none;
  background: radial-gradient(ellipse at center,
              rgba(255, 107, 53, .26) 0%,
              rgba(255, 107, 53, .12) 40%,
              rgba(255, 107, 53, 0) 72%);
}
@media (prefers-reduced-motion: reduce) {
  .hero-logo, .hero-logo-wrap { animation: none; }
}

/* Decorative loops pause while scrolled out of view — site.js toggles
   .is-offscreen on anything marked data-pause-offscreen. */
.is-offscreen,
.is-offscreen *,
.is-offscreen *::before,
.is-offscreen *::after { animation-play-state: paused !important; }

/* Lite mode: site.js adds .perf-lite to <html> when the browser reports a
   software renderer, or frames come in slow. With the fixes above the site
   holds ~58fps even then, so this only stills the purely ornamental loops
   for the machines that need every frame. Motion that means something —
   the drift wall, the marquee, carousels, the logo sway — stays. */
.perf-lite .hero-logo-wrap,
.perf-lite .hero-sub .sep svg,
.perf-lite .hero-sub .sep svg circle,
.perf-lite .pill.hot::before,
.perf-lite .dhint::before,
.perf-lite .dxt-set span,
.perf-lite .discord-badge-wrap,
.perf-lite .discord-badge-wrap::before { animation: none; }
.perf-lite .hero-logo-wrap::before { animation: none; opacity: .7; }
.perf-lite .dxt-set span { opacity: 1; }
.perf-lite .lb-box::before { animation: none; clip-path: none; }
.perf-lite .lb-box::after { display: none; }
.perf-lite .ldc-card.is-active .ldc-img {
  animation: none;
  box-shadow: 0 0 12px rgb(255 107 53 / .32), 0 0 34px rgb(255 107 53 / .22);
}

/* ---- flash messages ---------------------------------------- */
.flash {
  position: fixed; top: 86px; left: 0; right: 0; z-index: 120;
  padding: 12px 0; font-weight: 800; font-size: .8rem;
  letter-spacing: .12em; text-transform: uppercase;
  transition: opacity .4s ease, transform .4s ease;
}
.flash-ok { background: var(--grn); color: #0A0A0A; }
.flash-error { background: var(--red); color: var(--tx); }
.flash-out { opacity: 0; transform: translateY(-12px); pointer-events: none; }

/* ---- generic page header ------------------------------------ */
.page-head { border-bottom: 2px solid var(--line); padding: 148px 0 44px; }
.page-head h1 { font-size: clamp(2.6rem, 6vw, 5rem); }
.page-head h1 em { font-style: normal; color: var(--acc); }
.page-head .kick { margin-bottom: 10px; }
.page-lead { color: var(--tx2); max-width: 620px; margin-top: 14px; font-size: 1.05rem; }

/* ---- long-form content -------------------------------------- */
.prose { max-width: 720px; padding: 56px 0 84px; }
.prose h2 { font-size: 2rem; margin: 36px 0 14px; scroll-margin-top: 110px; }
.prose h3 { font-size: 1.4rem; margin: 28px 0 10px; scroll-margin-top: 110px; }
.prose p { color: var(--tx2); margin-bottom: 18px; line-height: 1.75; }
.prose strong { color: var(--tx); font-weight: 800; }
.prose a { color: var(--acc); border-bottom: 1px solid var(--line2); }
.prose a:hover { border-color: var(--acc); }
.prose ul, .prose ol { color: var(--tx2); margin: 0 0 18px 22px; }
.prose li { margin-bottom: 8px; }
.prose blockquote {
  border-left: 3px solid var(--acc); padding-left: 20px;
  margin: 0 0 20px; color: var(--tx2); font-style: italic;
}

/* ---- table of contents (long legal pages) --------------------
   A self-contained index card, not a fixed sidebar — the policy pages run
   19 sections deep, so a sticky rail would either crowd a 720px column on
   desktop or eat the top of the screen on mobile. An inline card scrolls
   with the page and reads the same at every width. */
.prose .toc {
  border: 2px solid var(--line); background: var(--panel);
  padding: 22px 26px; margin: 32px 0 44px; scroll-margin-top: 110px;
}
.prose .toc-label {
  margin: 0 0 12px; font-size: .72rem; font-weight: 800;
  letter-spacing: .12em; text-transform: uppercase; color: var(--acc);
}
.prose .toc-list {
  list-style: none; margin: 0; padding: 0; columns: 2; column-gap: 28px;
}
.prose .toc-list li { margin: 0 0 6px; break-inside: avoid; }
.prose .toc-list a {
  display: block; padding: 5px 0; color: var(--tx2); border-bottom: 0;
  font-size: .92rem; line-height: 1.4;
}
.prose .toc-list a:hover, .prose .toc-list a:focus-visible { color: var(--acc); }
@media (max-width: 640px) {
  .prose .toc { padding: 18px 20px; margin: 24px 0 36px; }
  .prose .toc-list { columns: 1; }
}
/* An index grouped into parts (the partner agreement): each group label
   after the first gets room above it. */
.prose .toc-list + .toc-label { margin-top: 20px; }

/* Summary / record boxes and part dividers on long agreements. */
.prose .glance {
  border: 2px solid var(--line); border-left: 4px solid var(--acc); background: var(--panel);
  padding: 20px 24px; margin: 26px 0 30px;
}
.prose .glance ul { margin: 0 0 0 20px; }
.prose .glance li { margin-bottom: 6px; }
.prose .glance-note { margin: 10px 0 0; color: var(--tx3); font-size: .86rem; }
.prose .part {
  margin: 56px 0 -12px; padding-top: 18px; border-top: 2px solid var(--line);
  font-weight: 800; font-size: .72rem; letter-spacing: .2em; text-transform: uppercase; color: var(--acc);
}
@media (max-width: 640px) {
  .prose h2 { font-size: 1.6rem; }
  .prose p, .prose li { font-size: .98rem; }
  .prose .glance { padding: 16px 16px; }
}

/* ---- long documents: side index + back-to-index button -------
   See doc-nav.js. The rail only exists once the script has filled it
   (.has-rail), so without JS the inline index is the navigation. */
.doc-rail[hidden], .doc-top[hidden] { display: none !important; }

@media (min-width: 1100px) {
  .doc.has-rail {
    display: grid; grid-template-columns: minmax(0, 760px) 270px;
    justify-content: space-between; gap: 64px; align-items: start;
  }
  .doc.has-rail .prose { max-width: none; }
  .doc.has-rail .prose .toc { display: none; }
  .doc-rail {
    position: sticky; top: 104px; margin: 56px 0 84px;
    max-height: calc(100vh - 128px); overflow-y: auto; overscroll-behavior: contain;
    padding: 4px 4px 4px 20px; border-left: 2px solid var(--line);
    scrollbar-width: thin;
  }
  .doc-top { display: none !important; }
}
@media (max-width: 1099px) {
  .doc-rail { display: none !important; }
}

.doc-rail-title {
  margin-bottom: 10px; font-weight: 800; font-size: .68rem;
  letter-spacing: .2em; text-transform: uppercase; color: var(--tx3);
}
.doc-rail-group {
  margin: 18px 0 4px; font-weight: 800; font-size: .62rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--acc);
}
.doc-rail ul { list-style: none; margin: 0; padding: 0; }
.doc-rail a {
  display: block; margin-left: -22px; padding: 5px 8px 5px 20px;
  border-left: 2px solid transparent; font-size: .84rem; line-height: 1.35; color: var(--tx2);
  transition: color .15s, border-color .15s, background-color .15s;
}
.doc-rail a:hover { color: var(--tx); }
.doc-rail a[aria-current="true"] { color: var(--acc); border-left-color: var(--acc); background: var(--panel); }
.doc-rail a:focus-visible { outline: 2px solid var(--ylw); outline-offset: -2px; }
.doc-rail-top {
  margin: 16px 0 6px; padding: 0; background: none; border: 0; cursor: pointer;
  font-family: var(--body); font-weight: 800; font-size: .68rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--tx3);
}
.doc-rail-top:hover { color: var(--acc); }

.doc-top {
  position: fixed; right: 14px; bottom: 18px; z-index: 140;
  display: inline-flex; align-items: center; gap: 7px; padding: 10px 14px 10px 11px;
  border: 2px solid var(--acc); background: rgba(10, 10, 10, .94); color: var(--tx);
  font-family: var(--body); font-weight: 800; font-size: .68rem; letter-spacing: .14em; text-transform: uppercase;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .55); cursor: pointer;
  opacity: 0; transform: translateY(14px); pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
}
.doc-top.show { opacity: 1; transform: none; pointer-events: auto; }
.doc-top svg { width: 16px; height: 16px; color: var(--acc); }
.doc-top:active { background: var(--acc); color: #0A0A0A; }
.doc-top:active svg { color: #0A0A0A; }
.doc-top:focus-visible { outline: 2px solid var(--ylw); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .doc-top { transition: none; }
}

/* ---- product page ------------------------------------------- */
.pdp { display: grid; grid-template-columns: 1.05fr .95fr; gap: 2px;
       background: var(--line); border: 2px solid var(--line); margin: 132px 0 0; }
.pdp-media, .pdp-info { background: var(--bg); }
.pdp-media { padding: 0; }
.pdp-main { aspect-ratio: 1/1; overflow: hidden; background: var(--panel); }
.pdp-main img { width: 100%; height: 100%; object-fit: cover; }
.pdp-thumbs { display: flex; gap: 2px; background: var(--line); border-top: 2px solid var(--line); }
.pdp-thumb { flex: 1 1 0; aspect-ratio: 1/1; overflow: hidden; background: var(--panel);
             border: none; padding: 0; cursor: pointer; }
.pdp-thumb img { width: 100%; height: 100%; object-fit: cover; opacity: .55; transition: opacity .25s; }
.pdp-thumb[aria-current="true"] img, .pdp-thumb:hover img { opacity: 1; }

.pdp-info { padding: 44px 40px; }
.pdp-info h1 { font-size: clamp(2.2rem, 4vw, 3.4rem); }
.pdp-artist { font-family: var(--mark); font-size: 1.5rem; color: var(--acc); margin-top: 6px; line-height: 1; }
.pdp-price { font-family: var(--head); font-size: 2.4rem; margin: 22px 0 4px; }
.pdp-price s { color: var(--tx3); font-family: var(--body); font-weight: 400; font-size: .95rem; margin-left: 10px; }
.pdp-blurb { color: var(--tx2); margin: 16px 0 24px; line-height: 1.75; }

.pdp-meta { list-style: none; margin: 22px 0 26px; border-top: 1px solid var(--line); }
.pdp-meta li { display: flex; justify-content: space-between; align-items: center;
               font-size: .9rem; padding: 11px 0; border-bottom: 1px solid var(--line); gap: 12px; }
.pdp-meta span { color: var(--tx3); text-transform: uppercase; letter-spacing: .12em;
                 font-size: .68rem; font-weight: 800; }
.pdp-meta b { font-weight: 800; }
.pdp-add { width: 100%; text-align: center; padding: 17px; font-size: .85rem; }

/* ---- cart ---------------------------------------------------- */
.cart-wrap { padding: 148px 0 84px; }
.cart-grid { display: grid; grid-template-columns: 1.6fr .8fr; gap: 40px; align-items: start; }
.cart-list { border: 2px solid var(--line); }
.cart-row { display: grid; grid-template-columns: 96px 1fr auto; gap: 18px;
            padding: 18px; border-bottom: 2px solid var(--line); align-items: center; }
.cart-row:last-child { border-bottom: none; }
.cart-thumb { width: 96px; aspect-ratio: 1/1; object-fit: cover; background: var(--panel); }
.cart-name { font-family: var(--head); font-size: 1.25rem; text-transform: uppercase; }
.cart-variant { color: var(--tx3); font-size: .82rem; font-weight: 700;
                letter-spacing: .08em; text-transform: uppercase; margin-top: 4px; }
.cart-by { font-family: var(--mark); color: var(--acc); font-size: 1.15rem; margin-top: 2px; }
.cart-actions { display: flex; align-items: center; gap: 14px; }
.qty { display: flex; border: 2px solid var(--line2); }
.qty button { width: 34px; height: 38px; background: none; border: none; color: var(--tx); font-size: 16px; }
.qty button:hover { color: var(--acc); }
.qty input { width: 44px; text-align: center; background: none; border: none;
             color: var(--tx); font-family: var(--body); font-weight: 800; font-size: .9rem; }
.cart-line-total { font-family: var(--head); font-size: 1.3rem; min-width: 76px; text-align: right; }
.cart-remove { background: none; border: none; color: var(--tx3); font-size: .72rem;
               font-weight: 800; letter-spacing: .12em; text-transform: uppercase; }
.cart-remove:hover { color: var(--red); }

.cart-summary { border: 2px solid var(--line); padding: 28px 26px; position: sticky; top: 100px; }
.cart-summary h2 { font-size: 1.6rem; margin-bottom: 18px; }
.sum-row { display: flex; justify-content: space-between; padding: 10px 0;
           border-bottom: 1px solid var(--line); font-size: .95rem; color: var(--tx2); }
.sum-row b { color: var(--tx); font-weight: 800; }
.sum-total { display: flex; justify-content: space-between; align-items: baseline;
             padding: 18px 0 22px; font-family: var(--head); font-size: 1.8rem; }
.cart-note { color: var(--tx3); font-size: .78rem; margin-top: 14px; line-height: 1.6; }
/* A piece that only ships to some regions (products.ship_regions). */
.cart-ships { margin-top: 6px; font-size: .78rem; font-weight: 800; letter-spacing: .02em; color: var(--tx2); }
.cart-ships.is-blocked { color: #FF8A8A; }
.cart-ship-block { margin: 4px 0 12px; padding: 12px 14px; border: 1px solid rgba(255, 138, 138, .45); background: rgba(231, 56, 67, .1); color: #FFD0D0; font-size: .86rem; font-weight: 700; line-height: 1.5; }
.cart-summary .pdp-add:disabled { opacity: .45; cursor: not-allowed; }
/* Cart: pick where it ships, because the rate depends on it. */
.ship-to { display: flex; align-items: center; gap: 10px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.ship-to label { color: var(--tx3); font-size: .72rem; letter-spacing: .12em; text-transform: uppercase; }
.ship-to select { flex: 1 1 auto; min-width: 0; padding: 8px 10px; border: 1px solid var(--line); background: var(--bg);
  color: var(--tx); font: inherit; font-size: .88rem; border-radius: 4px; }
.ship-to select:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; }
.ship-to-go { padding: 8px 12px; border: 1px solid var(--line); background: var(--bg); color: var(--tx); cursor: pointer; }
.cart-empty { text-align: center; padding: 80px 20px; border: 2px dashed var(--line2); }
.cart-empty h2 { font-size: 2rem; margin-bottom: 12px; }
.cart-empty p { color: var(--tx2); margin-bottom: 24px; }

/* ---- shop / artists grids ------------------------------------ */
/* Clearance under the fixed 78px #nav. This was once raised from 132px
   chasing a reported "sub header colliding with the header", on a guess
   about web-font swap; that was the wrong read — the collision was the
   kicker sitting on its own heading, now fixed by .kick's margin in
   home.css. Kept at 148px purely because the extra room reads well. */
.shop-wrap { padding: 148px 0 84px; }

/* "Latest DRXPs" — 3D coverflow carousel above the shop grid. Rebuilt in
   vanilla CSS transitions from a React + Framer Motion + Tailwind reference
   (codepen.io/vii120/pen/VYmmdMK): each slot gets its own perspective context,
   the active card sits flat while neighbours rotate away and shrink, and the
   track shifts to re-center whichever card is active.

   The cards are the one deliberate exception to the site's otherwise
   zero-border-radius house style — softly rounded here on request, to match
   the reference's look. Controls stay sharp-edged like the rest of the site. */
/* Stands as its own section rather than something stacked on the grid —
   the generous bottom gap is what separates it from "Shop all art" below,
   since the strip is full-bleed and has no edges of its own to read as a
   boundary. */
.latest-drxp { padding: 34px 0 108px; }
.latest-drxp .sec-head { margin-bottom: 30px; }

.ldc { display: flex; flex-direction: column; align-items: center; gap: 28px; }

.ldc-viewport {
  /* Full-bleed: the strip runs edge to edge so as many cards as the screen
     can fit stay on show, the way the reference does it. How many that is
     falls out of the viewport width on its own — no breakpoint needed. */
  width: 100%;
  overflow: hidden;
  cursor: grab;
  /* Claim horizontal gestures for the carousel but leave vertical ones to
     the page, so a touch drag down the screen still scrolls. */
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
}

.ldc-dragging .ldc-viewport { cursor: grabbing; }
/* Follow the pointer 1:1 while dragging — an easing curve mid-drag reads as
   lag, not smoothness. The transitions come back on release to animate the
   snap. */
.ldc-dragging .ldc-track,
.ldc-dragging .ldc-card { transition: none; }
.ldc-img img { -webkit-user-drag: none; user-drag: none; }

.ldc-track {
  display: flex;
  width: fit-content;
  transition: transform .7s cubic-bezier(.22, 1, .36, 1);
}

/* Wide slots so the centred piece reads large; the perspective grows with
   them, or the neighbours' tilt distorts more the bigger the card gets. */
.ldc-slot {
  flex: none;
  width: 430px;
  padding: 0 18px;
  perspective: 1400px;
}

.ldc-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  transform-style: preserve-3d;
  transition: transform .7s cubic-bezier(.22, 1, .36, 1);
  will-change: transform;
}

/* Clean frame: no hairline border, just the image with soft corners and a
   shadow to lift it off the page. The whole frame is the link. */
.ldc-img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  background: var(--panel);
  border-radius: 18px;
  overflow: hidden;
  cursor: pointer;
  box-shadow: 0 18px 40px rgba(0, 0, 0, .45);
}

.ldc-img img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .5s cubic-bezier(.22, 1, .36, 1);
}
.ldc-img:hover img { transform: scale(1.04); }
.ldc-img:focus-visible { outline: 3px solid var(--ylw); outline-offset: 4px; }
.ldc-dragging .ldc-img { cursor: grabbing; }
.ldc-dragging .ldc-img img { transition: none; transform: none; }

/* Neon orange light on whichever card is centered. box-shadow (not a blurred
   pseudo-element) so it hugs the rounded corners for free and needs no
   z-index games against the card's own 3D transform — and unlike a bare
   custom property it interpolates natively, so the offsets can drift.
   Two layers: a tight ring that only breathes, and a wider bloom whose
   offset walks a slow circle, which is what reads as light moving around
   the frame rather than just pulsing on the spot. */
.ldc-card.is-active .ldc-img {
  animation: ldcNeonOrbit 6s ease-in-out infinite;
}

@keyframes ldcNeonOrbit {
  0%, 100% { box-shadow: 0 0 10px rgb(255 107 53 / .30), -10px  -8px 34px rgb(255 107 53 / .26); }
  25%      { box-shadow: 0 0 14px rgb(255 107 53 / .40),  10px  -8px 34px rgb(255 107 53 / .30); }
  50%      { box-shadow: 0 0 10px rgb(255 107 53 / .30),  10px   8px 34px rgb(255 107 53 / .26); }
  75%      { box-shadow: 0 0 14px rgb(255 107 53 / .40), -10px   8px 34px rgb(255 107 53 / .30); }
}

/* A drifting glow has nowhere to fade to and nothing to communicate — it's
   pure decoration, so it sits still rather than shrinking to a dimmer
   version of the same motion. */
@media (prefers-reduced-motion: reduce) {
  .ldc-card.is-active .ldc-img {
    animation: none;
    box-shadow: 0 0 12px rgb(255 107 53 / .32), 0 0 34px rgb(255 107 53 / .22);
  }
}

/* Full title in the heading face, small and airy: partner in orange, a thin
   dash, then the product. */
.ldc-title {
  margin-top: 10px;
  font-family: var(--head);
  font-size: .95rem;
  font-weight: 400;
  letter-spacing: .09em;
  text-transform: uppercase;
  line-height: 1.2;
  color: var(--tx2);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  transition: opacity .7s cubic-bezier(.22, 1, .36, 1);
}
.ldc-partner { color: var(--acc); }
.ldc-sep { margin: 0 .5em; color: var(--tx3); }
.ldc-name { color: var(--tx); opacity: .85; }

.ldc-controls {
  display: flex;
  align-items: center;
  gap: 18px;
}

.ldc-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  background: var(--panel);
  border: 2px solid var(--line2);
  color: var(--tx);
  cursor: pointer;
  transition: border-color .15s, color .15s;
}

.ldc-arrow:hover:not(:disabled) { border-color: var(--acc); color: var(--acc); }
.ldc-arrow:disabled { opacity: .35; cursor: default; }

.ldc-dots { display: flex; align-items: center; gap: 10px; }

/* Pagination as the logo's crown, dark/unlit until its slide is active —
   "lights up" via currentColor so only .ldc-dot.active has to change. */
.ldc-dot {
  width: 20px;
  height: 18px;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  color: var(--line2);
  transition: color .25s, transform .25s;
}

.ldc-crown { display: block; width: 100%; height: 100%; }

.ldc-dot:hover { color: var(--tx2); }
.ldc-dot.active { color: var(--acc); transform: scale(1.2); }

@media (max-width: 640px) {
  .ldc-slot { width: min(76vw, 320px); padding: 0 10px; perspective: 1000px; }
  .ldc-title { font-size: .85rem; }
  .latest-drxp { padding: 20px 0 76px; }
  /* One crown per product: with a dozen of them the row came to 402px on
     a 393px iPhone. Tighter, and the crowns wrap rather than overflow. */
  .ldc-controls { gap: 10px; max-width: 100%; padding: 0 12px; box-sizing: border-box; }
  .ldc-arrow { flex: none; }
  .ldc-dots { gap: 6px; min-width: 0; flex-wrap: wrap; justify-content: center; }
}

/* ---- shop grid: the roomier "air" treatment -------------------
   Pairs with .gal so the existing column breakpoints (2-up at 960,
   1-up at 560) keep applying and aren't duplicated here. The base .gal
   fakes hairline rules by showing its own background through a 2px gap,
   which is the opposite of what's wanted here, so both the wrapper
   background and border are dropped and each card carries its own. */
.gal-air {
  gap: 26px;
  background: none;
  border: none;
}

.gal-air .piece { border: 2px solid var(--line); transition: border-color .25s; }
.gal-air .piece:hover { border-color: var(--line2); }

/* The card is all image now — the name and price moved into the overlay,
   so nothing sits below the frame competing with it for height. */
.gal-air .piece-frame { aspect-ratio: 1 / 1; }

.piece-hover {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 6px;
  padding: 22px;
  text-decoration: none;
  color: var(--tx);
  background: linear-gradient(to top,
              rgba(10, 10, 10, .95) 0%,
              rgba(10, 10, 10, .86) 42%,
              rgba(10, 10, 10, .45) 74%,
              rgba(10, 10, 10, .12) 100%);
  opacity: 0;
  transition: opacity .3s ease;
}

.piece:hover .piece-hover,
.piece:focus-within .piece-hover { opacity: 1; }

/* Contents drift up as the panel fades in. Transform only — the panel's
   own opacity does the fading, so nothing here repaints text twice. */
.piece-hover > * { transform: translateY(10px); transition: transform .34s cubic-bezier(.22, 1, .36, 1); }
.piece:hover .piece-hover > *,
.piece:focus-within .piece-hover > * { transform: translateY(0); }

.piece-hover-name { font-family: var(--head); font-size: 1.45rem; line-height: 1.1; }
.piece-hover-by { font-family: var(--mark); font-size: 1.15rem; color: var(--acc); line-height: 1; }
.piece-hover-desc { font-family: var(--body); font-size: .82rem; line-height: 1.55; color: var(--tx2); margin-top: 2px; }
.piece-hover-price { font-family: var(--head); font-size: 1.35rem; margin-top: 6px; }
.piece-hover-price s { color: var(--tx3); font-family: var(--body); font-weight: 400; font-size: .8rem; margin-left: 8px; }

/* Same orange-to-yellow logic as the classic buy bar, so the two layouts
   agree on what "this is the button" looks like. */
.piece-cta {
  align-self: flex-start;
  margin-top: 10px;
  padding: 11px 18px;
  background: var(--acc);
  color: #0A0A0A;
  font-family: var(--body);
  font-weight: 800;
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  transition: background .2s;
}

.piece-hover:hover .piece-cta { background: var(--ylw); }

/* No hover to reveal it on touch, and the name and price live nowhere else
   now — so the panel is always up there. The blurb is what gets dropped:
   it's the longest part and the least load-bearing of the four. */
@media (hover: none) {
  .piece-hover {
    opacity: 1;
    background: linear-gradient(to top,
                rgba(10, 10, 10, .94) 0%,
                rgba(10, 10, 10, .72) 46%,
                rgba(10, 10, 10, 0) 82%);
  }
  .piece-hover > * { transform: none; }
  .piece-hover-desc { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .piece-hover > * { transition: none; transform: none; }
}

.filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 26px; }
/* The row grew from four buttons to one per category in the catalogue, so
   the count rides along inside the button: it is the difference between
   tapping Buttons and finding four pieces or finding one. Dimmed, because
   it is a footnote to the word, and it inherits the button's colour so it
   stays legible when the button is the active accent one. */
.filters-n { opacity: .55; font-variant-numeric: tabular-nums; margin-left: 2px; }
/* On a phone the row would otherwise stack into four or five lines and push
   the grid off the screen; one swipeable line keeps the products in view. */
@media (max-width: 720px) {
  .filters { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
             margin-inline: -16px; padding-inline: 16px; scroll-padding-inline: 16px; }
  .filters::-webkit-scrollbar { display: none; }
  .filters .btn { flex: 0 0 auto; }
}
.artists-full { grid-template-columns: repeat(3, 1fr); }

/* ---- checkout result ----------------------------------------- */
.result { text-align: center; padding: 172px 24px 120px; max-width: 640px; margin: 0 auto; }
.result h1 { font-size: clamp(2.4rem, 6vw, 4.4rem); }
.result h1 em { font-style: normal; color: var(--grn); }
.result p { color: var(--tx2); margin: 18px 0 28px; line-height: 1.75; }
.result .order-no { font-family: var(--head); font-size: 1.4rem; color: var(--acc); }

@media (max-width: 960px) {
  .pdp, .cart-grid { grid-template-columns: 1fr; }
  .pdp { margin-top: 110px; }
  .artists-full { grid-template-columns: 1fr 1fr; }
  .cart-summary { position: static; }
}
@media (max-width: 640px) {
  .pdp-info { padding: 30px 22px; }
  .cart-row { grid-template-columns: 72px 1fr; }
  .cart-thumb { width: 72px; }
  .cart-actions { grid-column: 1 / -1; justify-content: space-between; }
  .artists-full { grid-template-columns: 1fr; }
  .page-head { padding: 120px 0 34px; }
  .flash { top: 70px; }
}

/* ---- homepage product preview (lightbox) ---------------------
   Overrides the prototype's .lb rules in home.css, which loads first.
   The preview is the one place with softened corners; the rest of the
   site stays sharp-edged. */
.lb-box {
  border: 1px solid var(--line2);
  border: 1px solid color-mix(in srgb, var(--acc) 30%, transparent);
  border-radius: 18px;
}
.lb-img { position: relative; border-radius: 17px 0 0 17px; }

/* Animated border, adapted from codepen.io/Rplus/pen/abPLGx ("pure CSS
   border animation without SVG"). Two outlines trace the frame half a lap
   apart: each is an inset box-shadow line, and a clip window walks it
   around the four sides. The original's `clip: rect()` is deprecated, so
   this uses clip-path: inset(), which is the same window and animates
   everywhere. Its debug hover (a red fill on the pseudo-elements) is left
   out, and the colours come from the site's own accent and yellow. */
.lb-box::before,
.lb-box::after {
  content: '';
  position: absolute;
  inset: -7px;
  border-radius: 24px;
  box-shadow: inset 0 0 0 2px var(--acc);
  pointer-events: none;
  z-index: -1;
  animation: lbTrace 8s linear infinite;
}
.lb-box::after {
  box-shadow: inset 0 0 0 2px var(--ylw);
  animation-delay: -4s;
}
@keyframes lbTrace {
  0%, 100% { clip-path: inset(0 0 calc(100% - 2px) 0); }
  25%      { clip-path: inset(0 calc(100% - 2px) 0 0); }
  50%      { clip-path: inset(calc(100% - 2px) 0 0 0); }
  75%      { clip-path: inset(0 0 0 calc(100% - 2px)); }
}

/* -- image slideshow -- */
.lb-slides {
  display: flex;
  height: 100%;
  transition: transform .45s cubic-bezier(.16, .84, .28, 1);
}
.lb-slide { flex: 0 0 100%; height: 100%; }
.lb-slide img { width: 100%; height: 100%; object-fit: cover; display: block; }

.lb-slide-btn {
  position: absolute;
  top: 50%;
  z-index: 2;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  transform: translateY(-50%);
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, .22);
  background: rgba(10, 10, 10, .72);
  color: #F0ECE0;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  transition: background .2s, border-color .2s, color .2s;
}
.lb-slide-btn.prev { left: 12px; }
.lb-slide-btn.next { right: 12px; }
.lb-slide-btn:hover { background: var(--acc); border-color: var(--acc); color: #0A0A0A; }
.lb-slide-btn[hidden] { display: none; }

.lb-dots {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 12px;
  z-index: 2;
  display: flex;
  justify-content: center;
  gap: 6px;
}
.lb-dots button {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 99px;
  background: rgba(255, 255, 255, .45);
  cursor: pointer;
  transition: width .25s, background-color .25s;
}
.lb-dots button[aria-selected="true"] { width: 22px; background: var(--acc); }

/* -- options -- */
.lb-form { display: flex; flex-direction: column; gap: 16px; margin-top: 18px; }
.lb-opt[hidden] { display: none; }
.lb-opt-label {
  display: block;
  margin-bottom: 8px;
  font-family: var(--body);
  font-weight: 800;
  font-size: .7rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--tx3);
}
.lb-opt-label b {
  margin-left: 6px;
  font-size: .85rem;
  letter-spacing: .02em;
  text-transform: none;
  color: var(--tx);
}

.lb-swatches { display: flex; flex-wrap: wrap; gap: 10px; }
.lb-swatch {
  display: inline-flex;
  align-items: center;
  padding: 3px;
  border: 2px solid var(--line2);
  border-radius: 99px;
  background: transparent;
  cursor: pointer;
  transition: border-color .2s, transform .2s;
}
.lb-swatch span {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .2);
}
.lb-swatch em {
  padding: 3px 10px;
  font-style: normal;
  font-family: var(--body);
  font-weight: 700;
  font-size: .8rem;
  color: var(--tx);
}
.lb-swatch:hover { border-color: var(--tx3); }
.lb-swatch[aria-checked="true"] { border-color: var(--acc); transform: scale(1.06); }
.lb-swatch:focus-visible { outline: 2px solid var(--ylw); outline-offset: 2px; }

/* A native select, restyled: it keeps the phone's own picker, keyboard
   support and screen readers for free, which a hand-built menu would have
   to recreate. */
.lb-select { position: relative; }
.lb-select::after {
  content: '';
  position: absolute;
  top: 50%;
  right: 18px;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--tx2);
  border-bottom: 2px solid var(--tx2);
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}
.lb-select select {
  width: 100%;
  appearance: none;
  -webkit-appearance: none;
  padding: 13px 46px 13px 16px;
  border: 1px solid var(--line2);
  border-radius: 12px;
  background: var(--panel);
  color: var(--tx);
  font-family: var(--body);
  font-weight: 700;
  font-size: .95rem;
  cursor: pointer;
  transition: border-color .2s, box-shadow .2s;
}
.lb-select select:hover { border-color: var(--tx3); }
.lb-select select:focus {
  outline: none;
  border-color: var(--acc);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 22%, transparent);
}
.lb-select select:disabled { opacity: .75; cursor: default; }
.lb-select select option { background: var(--panel); color: var(--tx); }

.lb-form #lbBuy { width: 100%; }
.lb-form #lbBuy:disabled { opacity: .5; cursor: not-allowed; }
.lb-more {
  align-self: center;
  padding-bottom: 3px;
  border-bottom: 1px solid var(--line2);
  font-family: var(--body);
  font-weight: 800;
  font-size: .76rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--tx2);
  transition: color .2s, border-color .2s;
}
.lb-more:hover { color: var(--acc); border-color: var(--acc); }
.lb-info .lb-meta { margin: 22px 0 0; }

/* The preview's job is to pick and buy; the full story is one click away
   on the product page. Four lines keeps the colour and size controls
   near the top instead of pushing them below the fold, and hides the
   supplier blurb's hard cut at 400 characters. */
#lbDesc {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Side-by-side layout: the options column is taller than the square image,
   so the image rides along at the top of the column as the preview scrolls
   rather than leaving an empty block beneath it. Sticky still positions the
   slide arrows and dots, which need a positioned parent. */
@media (min-width: 961px) {
  /* home.css also caps the square image at 52vh. Past that cap the browser
     keeps it square by narrowing it, which left a strip beside the image in
     its own column (447px wide in a 560px column on a 1280x860 screen). Fill
     the column and stay square; being sticky, it stays in view regardless of
     height. */
  .lb-img {
    position: sticky;
    top: 0;
    align-self: start;
    width: 100%;
    aspect-ratio: 1 / 1;
    max-height: none;
  }
}

@media (max-width: 960px) {
  /* home.css gives the stacked image aspect-ratio 16/10 plus a max-height.
     Once the height cap kicks in, the browser keeps the ratio by shrinking
     the width instead — so on tablets (a preview wider than ~545px) the image
     sat left-aligned with an empty strip beside it. A full width and a set
     height let object-fit: cover do the cropping. */
  .lb-img {
    width: 100%;
    aspect-ratio: auto;
    height: min(62vw, 360px);
    max-height: none;
    border-radius: 17px 17px 0 0;
  }

  /* The prototype pins the previous/next piece buttons to the bottom-left of
     the screen and the close button to the top-right. Now that the preview
     carries a form, on a phone the pinned pair sat on top of Add to cart and
     the close button on top of the image. Here the preview starts below the
     close button, and the pair sits under the preview instead of over it. */
  /* justify-content must be flex-start here: the prototype's `center`, in a
     column, pushes a preview taller than the screen up past the top edge,
     where no amount of scrolling reaches it — the image was cut off. */
  .lb { flex-direction: column; justify-content: flex-start; align-items: stretch; padding-top: 76px; padding-bottom: 32px; }
  .lb-box { margin: 0 auto; }
  .lb-nav { position: static; justify-content: center; margin: 18px auto 0; }
}

@media (prefers-reduced-motion: reduce) {
  .lb-box::before { animation: none; clip-path: none; }
  .lb-box::after { display: none; }
  .lb-slides { transition: none; }
}

/* ---- product page: more by this artist ------------------------ */
.pdp-more { padding: 84px 0 96px; }
.pdp-more-empty { color: var(--tx2); border: 2px dashed var(--line2); padding: 22px 24px; }
.pdp-more-cta { display: flex; justify-content: center; margin-top: 40px; }
@media (max-width: 640px) {
  .pdp-more { padding: 60px 0 72px; }
  .pdp-more-cta .btn { width: 100%; text-align: center; }
}

/* ---- product page option picker ------------------------------
   Real radio buttons, visually replaced: swatches for colour, chips for
   size and style. The inputs stay in the page (just invisible), so keyboard
   arrows, focus rings and screen readers behave as a native radio group. */
.pk-picker[hidden] { display: none; }
.pk-group { border: 0; margin: 0 0 24px; padding: 0; min-width: 0; }
.pk-label {
  display: flex; align-items: baseline; gap: 10px; width: 100%; margin-bottom: 12px; padding: 0;
  font-weight: 800; font-size: .7rem; letter-spacing: .2em; text-transform: uppercase; color: var(--tx3);
}
.pk-label b { font-size: .92rem; letter-spacing: .02em; text-transform: none; color: var(--tx); }
.pk-guide {
  margin-left: auto; font-size: .66rem; letter-spacing: .14em; color: var(--tx2);
  border-bottom: 1px solid var(--line2); padding-bottom: 2px;
}
.pk-guide:hover { color: var(--acc); border-color: var(--acc); }

.pk-picker input[type="radio"] {
  position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; pointer-events: none;
}
.pk-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

.pk-swatches { display: flex; flex-wrap: wrap; gap: 12px; }
.pk-swatch {
  position: relative; display: inline-flex; padding: 4px; cursor: pointer;
  border: 2px solid var(--line2); border-radius: 50%;
  transition: border-color .2s, transform .2s;
}
.pk-dot {
  display: block; width: 34px; height: 34px; border-radius: 50%;
  background: var(--sw, var(--panel2)); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22);
}
.pk-swatch.no-fill { border-radius: 99px; }
.pk-name { padding: 7px 13px; font-weight: 800; font-size: .8rem; color: var(--tx); }
.pk-swatch:hover { border-color: var(--tx3); }
.pk-swatch:has(input:checked) { border-color: var(--acc); transform: scale(1.08); }
.pk-swatch:has(input:focus-visible) { outline: 2px solid var(--ylw); outline-offset: 3px; }
/* A colour the chosen style isn't made in: dimmed and struck through. */
.pk-swatch.is-off { opacity: .35; cursor: not-allowed; }
.pk-swatch.is-off::after {
  content: ''; position: absolute; left: 50%; top: 5px; bottom: 5px; width: 2px;
  background: var(--tx); transform: translateX(-50%) rotate(45deg);
}

.pk-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.pk-chip span {
  display: flex; align-items: center; justify-content: center; min-width: 58px; min-height: 48px;
  padding: 8px 14px; border: 2px solid var(--line2); cursor: pointer;
  font-weight: 800; font-size: .84rem; letter-spacing: .05em; line-height: 1.2; text-align: center;
  color: var(--tx2); transition: border-color .15s, color .15s, background-color .15s;
}
.pk-chip:hover span { border-color: var(--tx3); color: var(--tx); }
.pk-chip input:checked + span { background: var(--acc); border-color: var(--acc); color: #0A0A0A; }
.pk-chip input:focus-visible + span { outline: 2px solid var(--ylw); outline-offset: 2px; }
.pk-chip input:disabled + span {
  color: var(--tx3); border-style: dashed; text-decoration: line-through; cursor: not-allowed; opacity: .55;
}
.pk .pdp-add { margin-top: 4px; }
.pk .pdp-add:disabled { opacity: .5; cursor: not-allowed; }
.pk .pdp-meta { margin-top: 26px; }

@media (max-width: 640px) {
  .pk-chip span { min-width: 54px; min-height: 46px; padding: 8px 11px; }
  .pk-dot { width: 32px; height: 32px; }
}
@media (prefers-reduced-motion: reduce) {
  .pk-swatch { transition: none; }
  .pk-swatch:has(input:checked) { transform: none; }
}

/* ---- cookie consent ------------------------------------------
   The familiar Shopify-store pattern: a slim bar with equal-weight Accept
   and Decline (declining must be as easy as accepting), plus a dialog with
   a switch per category. See consent.js and partials/consent.php. */
.cc[hidden], .cc-modal[hidden] { display: none !important; }
.cc {
  position: fixed; left: 16px; right: 16px; bottom: 16px; z-index: 150;
  max-width: 1080px; margin: 0 auto;
  background: var(--bg2); border: 2px solid var(--line2); border-top: 3px solid var(--acc);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .6);
  animation: ccIn .45s cubic-bezier(.16, .84, .28, 1) .6s both;
}
.cc.cc-out { transform: translateY(calc(100% + 24px)); opacity: 0; transition: transform .26s ease-in, opacity .26s ease-in; }
@keyframes ccIn { from { transform: translateY(calc(100% + 24px)); opacity: 0; } }
.cc-in { display: flex; align-items: center; gap: 16px 28px; padding: 18px 22px; flex-wrap: wrap; }
.cc-text { flex: 1 1 420px; font-size: .92rem; line-height: 1.6; color: var(--tx2); }
.cc-text strong { color: var(--tx); font-weight: 800; margin-right: 4px; }
.cc-text a { color: var(--acc); border-bottom: 1px solid var(--line2); white-space: nowrap; }
.cc-text a:hover { border-color: var(--acc); }
.cc-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cc-btn { padding: 11px 22px; font-size: .74rem; }
.cc-manage {
  background: none; border: 0; border-bottom: 1px solid var(--line2); padding: 6px 2px; margin-right: 8px;
  font-family: var(--body); font-weight: 800; font-size: .7rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--tx2);
}
.cc-manage:hover { color: var(--acc); border-color: var(--acc); }

.cc-modal {
  position: fixed; inset: 0; z-index: 400; display: flex; align-items: center; justify-content: center;
  padding: 20px; overflow-y: auto; background: rgba(5, 5, 5, .88); opacity: 0; transition: opacity .2s;
}
.cc-modal.cc-show { opacity: 1; }
.cc-panel {
  width: 100%; max-width: 560px; margin: auto; padding: 28px 28px 22px;
  background: var(--bg); border: 2px solid var(--line2); border-top: 3px solid var(--acc);
  transform: translateY(12px); transition: transform .25s cubic-bezier(.16, .84, .28, 1);
}
.cc-show .cc-panel { transform: none; }
.cc-head { display: flex; justify-content: space-between; align-items: center; gap: 16px; }
.cc-head h2 { font-size: 2.1rem; }
.cc-head h2 em { font-style: normal; color: var(--acc); }
.cc-x { flex: none; width: 38px; height: 38px; background: none; border: 2px solid var(--line2); color: var(--tx); font-size: 15px; }
.cc-x:hover { border-color: var(--acc); color: var(--acc); }
.cc-intro { margin: 10px 0 16px; color: var(--tx2); font-size: .92rem; line-height: 1.6; }
.cc-intro b { color: var(--tx); }
.cc-cat { display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 16px 0; border-top: 1px solid var(--line); }
label.cc-cat { cursor: pointer; }
.cc-cat h3, .cc-h3 { display: block; font-family: var(--head); font-weight: 400; font-size: 1.2rem; line-height: 1.1; text-transform: uppercase; color: var(--tx); }
.cc-cat p, .cc-p { display: block; margin-top: 5px; color: var(--tx3); font-size: .86rem; line-height: 1.55; }
.cc-always { flex: none; font-weight: 800; font-size: .66rem; letter-spacing: .14em; text-transform: uppercase; color: var(--grn); }
.cc-switch {
  flex: none; position: relative; width: 48px; height: 28px; margin: 0; cursor: pointer;
  appearance: none; -webkit-appearance: none; border-radius: 99px; background: var(--line2); transition: background-color .2s;
}
.cc-switch::after {
  content: ''; position: absolute; top: 4px; left: 4px; width: 20px; height: 20px; border-radius: 50%;
  background: var(--tx); transition: transform .2s;
}
.cc-switch:checked { background: var(--acc); }
.cc-switch:checked::after { transform: translateX(20px); background: #0A0A0A; }
.cc-switch:focus-visible { outline: 2px solid var(--ylw); outline-offset: 3px; }
.cc-panel-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; padding-top: 18px; border-top: 1px solid var(--line); }
body.cc-lock { overflow: hidden; }

.foot-cc {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit;
}
.foot-cc:hover { color: var(--acc); }

@media (max-width: 640px) {
  .cc { left: 10px; right: 10px; bottom: 10px; }
  .cc-in { padding: 16px; gap: 14px; }
  .cc-text { flex-basis: 100%; font-size: .88rem; }
  .cc-actions { width: 100%; display: grid; grid-template-columns: 1fr 1fr; }
  .cc-manage { grid-column: 1 / -1; order: 3; justify-self: center; margin: 0; }
  .cc-btn { text-align: center; }
  .cc-panel { padding: 22px 18px 18px; }
  .cc-panel-actions { display: grid; grid-template-columns: 1fr 1fr; }
  .cc-panel-actions [data-cc-accept] { grid-column: 1 / -1; order: -1; }
}
@media (prefers-reduced-motion: reduce) {
  .cc { animation: none; }
  .cc.cc-out, .cc-modal, .cc-panel { transition: none; }
}

/* ---- size guide ---------------------------------------------- */
.sg { max-width: 820px; padding: 44px 0 84px; }
.sg-units { display: inline-flex; border: 2px solid var(--line2); margin-bottom: 34px; }
.sg-unit {
  padding: 12px 20px; border: 0; background: transparent; color: var(--tx2);
  font-family: var(--body); font-weight: 800; font-size: .76rem; letter-spacing: .12em; text-transform: uppercase;
  transition: background-color .15s, color .15s;
}
.sg-unit span { color: var(--tx3); letter-spacing: .04em; }
.sg-unit:hover { color: var(--tx); }
.sg-unit[aria-pressed="true"] { background: var(--acc); color: #0A0A0A; }
.sg-unit[aria-pressed="true"] span { color: #0A0A0A; }
.sg-unit:focus-visible { outline: 2px solid var(--ylw); outline-offset: 2px; }

.sg-guide { margin-bottom: 44px; }
.sg-guide-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px 18px; flex-wrap: wrap; margin-bottom: 16px; }
.sg-guide-head h2 { font-size: clamp(1.8rem, 4vw, 2.6rem); }
.sg-blank { font-weight: 800; font-size: .72rem; letter-spacing: .14em; text-transform: uppercase; color: var(--tx3); }

.sg-table[hidden] { display: none; }
.sg-scroll { overflow-x: auto; border: 2px solid var(--line); }
.sg table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.sg th, .sg td { padding: 13px 18px; text-align: right; border-bottom: 1px solid var(--line); white-space: nowrap; }
.sg thead th {
  background: var(--panel); color: var(--tx3); font-weight: 800; font-size: .7rem;
  letter-spacing: .14em; text-transform: uppercase; border-bottom: 2px solid var(--line);
}
.sg thead th:first-child, .sg tbody th { text-align: left; }
.sg-u { color: var(--acc); letter-spacing: .06em; text-transform: none; }
.sg tbody th { font-family: var(--head); font-weight: 400; font-size: 1.15rem; color: var(--tx); }
.sg td { color: var(--tx); font-weight: 700; font-size: .98rem; }
.sg tbody tr:last-child th, .sg tbody tr:last-child td { border-bottom: 0; }
.sg tbody tr:hover th, .sg tbody tr:hover td { background: var(--panel); }
.sg tbody tr:hover th { color: var(--acc); }
.sg-note { margin-top: 12px; color: var(--tx2); font-size: .9rem; }
.sg-note b { color: var(--tx); }
.sg-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

.sg-how { margin-top: 28px; border-top: 2px solid var(--line); padding-top: 22px; }
.sg-how h3 { font-size: 1.3rem; margin-bottom: 12px; }
.sg-how dl { display: grid; gap: 12px; }
.sg-how dl > div { display: grid; grid-template-columns: 130px 1fr; gap: 16px; }
.sg-how dt { font-weight: 800; font-size: .72rem; letter-spacing: .14em; text-transform: uppercase; color: var(--acc); padding-top: 3px; }
.sg-how dd { color: var(--tx2); line-height: 1.6; }
.sg-other { color: var(--tx2); border: 2px dashed var(--line2); padding: 18px 20px; line-height: 1.7; }
.sg-other a { color: var(--acc); border-bottom: 1px solid var(--line2); }

@media (max-width: 640px) {
  .sg { padding-top: 30px; }
  .sg-units { display: flex; }
  .sg-unit { flex: 1; padding: 12px 8px; }
  .sg th, .sg td { padding: 12px 10px; }
  .sg td { font-size: .92rem; }
  .sg-how dl > div { grid-template-columns: 1fr; gap: 2px; }
}

/* Per-blank charts: the product a visitor came from, and where each chart applies. */
.sg-guide.is-focus { border-left: 4px solid var(--acc); padding-left: 18px; }
.sg-focus { margin-bottom: 8px; font-weight: 800; font-size: .72rem; letter-spacing: .14em; text-transform: uppercase; color: var(--acc); }
.sg-focus b { color: var(--tx); letter-spacing: .04em; }
.sg-used { margin-top: 12px; color: var(--tx3); font-size: .86rem; line-height: 1.6; }
.sg-used a { color: var(--tx2); border-bottom: 1px solid var(--line2); }
.sg-used a:hover { color: var(--acc); border-color: var(--acc); }

/* The same chart, inline on a product page under the size picker. */
.sg-inline { max-width: none; padding: 14px 0 4px; }
.sg-inline .sg-units { margin-bottom: 14px; }
.sg-inline .sg-unit { padding: 9px 14px; font-size: .68rem; }
.sg-inline th, .sg-inline td { padding: 10px 12px; }
.sg-more { margin-top: 10px; font-size: .84rem; }
.sg-more a { color: var(--acc); border-bottom: 1px solid var(--line2); }
.pk-sizechart { margin: 0 0 22px; border: 2px solid var(--line); }
.pk-sizechart > summary {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 13px 16px; cursor: pointer; list-style: none;
  font-weight: 800; font-size: .72rem; letter-spacing: .16em; text-transform: uppercase; color: var(--tx2);
}
.pk-sizechart > summary::-webkit-details-marker { display: none; }
.pk-sizechart > summary::after { content: '+'; color: var(--acc); font-size: 1.1rem; letter-spacing: 0; }
.pk-sizechart[open] > summary::after { content: '−'; }
.pk-sizechart > summary small { margin-left: auto; font-size: .66rem; letter-spacing: .08em; color: var(--tx3); }
.pk-sizechart > summary:hover { color: var(--tx); }
.pk-sizechart > .sg { padding: 0 16px 14px; }

/* ---- "by [artist]" credit line -------------------------------
   Raleway SemiBold instead of the Permanent Marker hand. Self-hosted
   variable fonts (one file covers every weight); only these credit lines
   use it, so the browser fetches it only on pages that show one. */
@font-face {
  font-family: 'Raleway';
  src: url('/assets/fonts/Raleway-VariableFont_wght.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Raleway';
  src: url('/assets/fonts/Raleway-Italic-VariableFont_wght.woff2') format('woff2');
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}
.piece-by,
.piece-hover-by,
.pdp-artist,
.cart-by,
.lb-info .lb-artist {
  font-family: 'Raleway', var(--body);
  font-weight: 600;
  font-size: .9rem;
  line-height: 1.3;
}

/* ---------------- footer social icons: 3D cut-out tiles ----------------
   A raised dark tile sitting on a hard shadow (the same language as
   .btn-press), with the brand glyph cut into its face: a dark edge above and
   a light lip below make the glyph read as recessed. Hover lifts the tile and
   lights it orange; press pushes it down onto its shadow. Only transform and
   box-shadow animate, so it stays cheap without GPU acceleration. */
.foot-soc { gap: 12px; }
.foot-soc a.soc-3d {
  position: relative; width: 42px; height: 42px; border: 0; border-radius: 12px;
  background: linear-gradient(160deg, #262624 0%, #161615 55%, #0f0f0e 100%);
  color: var(--acc);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .09), inset 0 -3px 0 rgba(0, 0, 0, .55), 0 4px 0 #000, 0 8px 16px rgba(0, 0, 0, .45);
  transition: transform .14s ease, box-shadow .14s ease, background-color .2s ease, color .2s ease;
}
.foot-soc a.soc-3d svg {
  width: 19px; height: 19px; fill: currentColor;
  filter: drop-shadow(0 -1px 0 rgba(0, 0, 0, .9)) drop-shadow(0 1px 0 rgba(255, 255, 255, .16));
}
.foot-soc a.soc-3d:hover, .foot-soc a.soc-3d:focus-visible {
  transform: translateY(-3px); color: #0A0A0A; background: var(--acc);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35), inset 0 -3px 0 rgba(0, 0, 0, .25), 0 7px 0 #000, 0 14px 22px rgba(255, 107, 53, .22);
}
.foot-soc a.soc-3d:hover svg, .foot-soc a.soc-3d:focus-visible svg {
  filter: drop-shadow(0 -1px 0 rgba(0, 0, 0, .35)) drop-shadow(0 1px 0 rgba(255, 255, 255, .45));
}
.foot-soc a.soc-3d:active { transform: translateY(3px); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .09), inset 0 -1px 0 rgba(0, 0, 0, .55), 0 1px 0 #000; }
.foot-soc a.soc-3d:focus-visible { outline: 2px solid var(--tx); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .foot-soc a.soc-3d, .foot-soc a.soc-3d:hover, .foot-soc a.soc-3d:active { transform: none; } }

/* Footer logo: the artwork is 1350x750 (9:5). home.css only fixed its height,
   so the img's width attribute squeezed it; keep the real proportions. */
.foot-logo img { height: 75px; width: auto; max-width: 100%; aspect-ratio: 9 / 5; object-fit: contain; }
@media (max-width: 560px) { .foot-logo img { height: 64px; } }

/* ---------------- wishlist heart (partials/wish-button.php) ---------------- */
.wish-form { position: absolute; top: 12px; right: 12px; z-index: 4; margin: 0; }
.wish-btn { width: 40px; height: 40px; border-radius: 50%; border: 0; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; background: rgba(10, 10, 10, .72); color: var(--tx); box-shadow: 0 6px 16px rgba(0, 0, 0, .35); transition: transform .15s ease, background-color .2s, color .2s; }
.wish-btn svg { width: 20px; height: 20px; fill: transparent; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; transition: fill .15s; }
.wish-btn:hover { transform: scale(1.1); color: var(--acc); }
.wish-btn.is-saved { color: var(--acc); }
.wish-btn.is-saved svg { fill: currentColor; }
.wish-btn:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; }
.wish-btn.pop { animation: wish-pop .35s ease; }
@keyframes wish-pop { 40% { transform: scale(1.3); } }
.pdp-add-row { display: flex; gap: 10px; align-items: stretch; }
.pdp-add-row .pdp-add { flex: 1 1 auto; }
.pdp-add-row .wish-btn { width: 54px; height: auto; border-radius: 0; border: 2px solid var(--line2); background: transparent; box-shadow: none; flex: 0 0 54px; }
.pdp-add-row .wish-btn:hover { border-color: var(--acc); transform: none; }
.pdp-add-row .wish-btn svg { width: 22px; height: 22px; }
@media (prefers-reduced-motion: reduce) { .wish-btn.pop { animation: none; } }
/* The card's tag badge also sits top-right; step it aside for the heart. */
.piece-frame:has(.wish-form) .piece-tag { right: 62px; }
/* Above the air card's hover panel (z-index 4), so the heart stays tappable. */
.wish-form { z-index: 6; }

/* ---------------- product page: photos follow the scroll ----------------
   The media column still stretches the full height of the details (so its
   background fills and no grid line shows below), while .pdp-stick inside it
   stays pinned under the fixed nav. On shorter windows the main photo gives
   up height so the thumbnails stay on screen. Desktop only: stacked on phones. */
@media (min-width: 961px) {
  .pdp-stick { position: sticky; top: 90px; }
  .pdp-stick .pdp-main { max-height: max(360px, calc(100vh - 240px)); }
}

/* ---------------- glowing card edges (glow.js) ----------------
   A rounded card with a faint orange rim. On hover the part of the rim
   facing the pointer brightens, and a soft halo shows outside it, both
   stronger the nearer the pointer is to the edge.
   The rim (::before) is a masked ring above the content. The halo (::after)
   sits behind the card (z-index -1 on a card that is not a stacking
   context), so the card background hides its inner part and only the blur
   outside the rounded edge shows. No mask on the halo, so nothing is cut square. */
.glow-card {
  --glow-angle: 45deg;
  --glow-edge: 0;
  --glow-rgb: 255, 107, 53;
  position: relative;
  border-radius: 18px;
}
.glow-card::before,
.glow-card::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
}
.glow-card::before {
  z-index: 3;
  padding: 1.5px;
  background:
    conic-gradient(from calc(var(--glow-angle) - 70deg),
      rgba(var(--glow-rgb), 0) 0deg,
      rgba(var(--glow-rgb), calc(.35 + var(--glow-edge) * .65)) 70deg,
      rgba(var(--glow-rgb), 0) 140deg,
      rgba(var(--glow-rgb), 0) 360deg),
    linear-gradient(rgba(var(--glow-rgb), .24), rgba(var(--glow-rgb), .1));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
.glow-card::after {
  z-index: -1;
  background: conic-gradient(from calc(var(--glow-angle) - 60deg),
      rgba(var(--glow-rgb), 0) 0deg,
      rgba(var(--glow-rgb), .6) 60deg,
      rgba(var(--glow-rgb), 0) 120deg,
      rgba(var(--glow-rgb), 0) 360deg);
  filter: blur(16px);
  opacity: 0;
  transition: opacity .35s ease;
}
.glow-card.is-glowing::after { opacity: calc(.2 + var(--glow-edge) * .8); }
.perf-lite .glow-card::after { display: none; }

/* Product page: photos and details together in one glowing card. overflow:
   clip (not hidden) rounds the photo corners without making a scroll
   container, so the pinned photos (.pdp-stick) keep working. */
.pdp-card { margin-top: 132px; box-shadow: 0 24px 60px -34px rgba(255, 107, 53, .35); }
.pdp-card .pdp {
  margin: 0; gap: 0; border: 0; border-radius: inherit; overflow: clip;
  background: linear-gradient(170deg, #141413 0%, #0d0d0c 60%);
}
.pdp-card .pdp-media, .pdp-card .pdp-info { background: transparent; }
.pdp-card .pdp-media { border-right: 1px solid var(--line); }
.pdp-card .pdp-thumbs { border-top: 1px solid var(--line); }
@media (max-width: 960px) {
  .pdp-card { margin-top: 110px; border-radius: 14px; }
  .pdp-card .pdp-media { border-right: 0; border-bottom: 1px solid var(--line); }
}

/* The 80/20 explainer (partials/split-explainer.php). Plain typography so it
   reads as an explanation rather than a pitch, with the receipt set apart
   because that is the part people scan for. */
.sx { color: var(--tx2); font-size: .96rem; line-height: 1.75; }
.sx > p + p { margin-top: 14px; }
.sx strong { color: var(--tx); }
.sx-title { font-family: 'Anton', sans-serif; font-size: clamp(1.3rem, 2.6vw, 1.9rem);
            letter-spacing: .02em; text-transform: uppercase; color: var(--tx); margin-bottom: 14px; }
.sx-receipt { margin: 18px 0; padding: 18px 20px; background: var(--panel2, var(--panel)); border: 2px solid var(--line); }
.sx-receipt-title { font-family: 'Permanent Marker', cursive; color: var(--acc); font-size: 1rem; margin-bottom: 10px; }
.sx-receipt ul { list-style: none; margin: 0; padding: 0; }
.sx-receipt li { display: flex; justify-content: space-between; gap: 16px; padding: 7px 0;
                 border-bottom: 1px dashed var(--line); font-size: .93rem; }
.sx-receipt li:last-child { border-bottom: 0; }
.sx-receipt li b { font-variant-numeric: tabular-nums; color: var(--tx); white-space: nowrap; }
.sx-receipt .sx-net { border-top: 2px solid var(--line); border-bottom: 2px solid var(--line); margin-top: 4px; }
.sx-receipt .sx-net b { color: var(--tx); }
.sx-receipt .sx-you b { color: var(--grn); }
.sx-receipt-note { margin-top: 10px; color: var(--tx3); font-size: .84rem; line-height: 1.6; }
.sx-compact { font-size: .93rem; margin-bottom: 22px; }
.sx-compact .sx-receipt { padding: 14px 16px; }
.sx-rules { margin: 18px 0; }
.sx-rules-title { font-family: 'Permanent Marker', cursive; color: var(--acc); font-size: .98rem; margin-bottom: 8px; }
.sx-rules ul { margin: 0; padding-left: 20px; }
.sx-rules li { margin-bottom: 9px; font-size: .93rem; line-height: 1.7; }
.sx-rules li b { color: var(--tx); }
.sx-rules li em { font-style: italic; color: var(--tx); }
.sx-legal { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--line);
            color: var(--tx3); font-size: .82rem; line-height: 1.65; }
.sx-legal a { color: var(--acc); border-bottom: 1px solid var(--line2); }
.sx-offer { padding: 12px 14px; border-left: 3px solid var(--acc); background: rgba(255, 107, 53, .07); }

/* ---- uploads (assets/js/upload.js): what was chosen, and the progress bar ---- */
.up-list { list-style: none; margin: 6px 0 0; padding: 0; font-size: .78rem; color: var(--tx2); line-height: 1.6; flex-basis: 100%; }
.up-list li { overflow-wrap: anywhere; }
.up-list .is-bad { color: var(--red); font-weight: 800; }
.up-progress { flex-basis: 100%; margin: 10px 0; }
.up-progress-track { height: 8px; border-radius: 999px; background: var(--line); overflow: hidden; }
.up-progress-track span { display: block; height: 100%; width: 0; background: var(--acc); transition: width .2s linear; }
.up-progress-text { margin: 6px 0 0; font-size: .8rem; font-weight: 700; color: var(--tx2); }
.up-progress.is-bad .up-progress-track span { background: var(--red); }
.up-progress.is-bad .up-progress-text { color: var(--red); }
form[aria-busy="true"] { cursor: progress; }

/* ---------------- scrollbars, everywhere, in the page's own colour ----------------
   The thumb is the page's accent: the shop's orange, a partner's Dash or
   admin colour (their --acc), a partner page's own palette, an Alley
   artist's chosen colour (--scroll-acc, set on <html> by the layout or by
   the partner's stylesheet). The track is clear, so light pages and dark
   pages both look right.

   The page's own scrollbar reads <html>; everything that scrolls inside
   the page inherits from <body>, which is where the Dash and admin set
   their colour — so both are set. scrollbar-color is the standard (Firefox,
   Chrome 121+); the ::-webkit-scrollbar rules are Safari's. A box that
   hides its bar (scrollbar-width: none) still does. */
html, body {
  scrollbar-color: color-mix(in srgb, var(--scroll-acc, var(--acc)) 62%, transparent) transparent;
}
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background: transparent; }
::-webkit-scrollbar-thumb {
  border-radius: 999px; border: 3px solid transparent; background-clip: padding-box;
  background-color: color-mix(in srgb, var(--scroll-acc, var(--acc)) 62%, transparent);
}
::-webkit-scrollbar-thumb:hover { background-color: var(--scroll-acc, var(--acc)); }

/* ---------------- The header: one dark glass bar (the smart bar) ----------------
   Clear over the top of a page, dark glass once you scroll: a frosted
   panel with a hairline edge and a soft shadow, so the header always reads
   as the top layer. (Lite mode keeps it solid, no blur.) On a page that
   hands the header its own context (partials/nav.php — an artist's tabs),
   the shop links make way for it once its bar scrolls up behind the
   header, and move under Menu. */
#nav { background: rgba(10, 10, 10, .38); border-bottom: 1px solid transparent; box-shadow: none; }
#nav.solid {
  background: rgba(12, 11, 9, .64);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  backdrop-filter: blur(18px) saturate(160%);
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  box-shadow: 0 14px 34px rgba(0, 0, 0, .38), inset 0 -1px 0 rgba(255, 255, 255, .03);
}
.perf-lite #nav.solid { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(10, 10, 10, .93); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { #nav.solid { background: rgba(10, 10, 10, .93); } }

/* The middle: the shop links, or the page's context, in the same place. */
.nav-mid { flex: 1; min-width: 0; display: grid; justify-items: center; align-items: center; }
.nav-mid > * { grid-area: 1 / 1; }
.nav-links { transition: opacity .28s ease, transform .32s cubic-bezier(.2, .8, .2, 1), visibility .32s; }
.nav-links a { position: relative; transition: color .2s; }
.nav-links a::after { content: ''; position: absolute; left: 0; right: 0; bottom: -6px; height: 2px; background: var(--acc); transform: scaleX(0); transform-origin: left; transition: transform .25s ease; }
.nav-links a:hover::after, .nav-links a:focus-visible::after { transform: scaleX(1); }
.nav-ctx { display: flex; align-items: center; gap: 4px; max-width: 100%; opacity: 0; visibility: hidden; transform: translateY(10px); transition: opacity .28s ease, transform .32s cubic-bezier(.2, .8, .2, 1), visibility .32s; }
html.nav-docked .nav-links { opacity: 0; visibility: hidden; transform: translateY(-12px); }
html.nav-docked .nav-ctx { opacity: 1; visibility: visible; transform: none; }
.nav-ctx-me { display: grid; place-items: center; flex: none; width: 30px; height: 30px; margin-right: 8px; overflow: hidden; border: 2px solid #E8C15A; border-radius: 8px; background: #1d1810; color: #FFF1B8; font-size: .7rem; font-weight: 900; box-shadow: 0 0 14px rgba(232, 193, 90, .3); }
.nav-ctx-me img { width: 100%; height: 100%; object-fit: cover; display: block; }
.nav-ctx-name { flex: none; margin-right: 10px; font-family: var(--head); font-weight: 400; font-size: 1.15rem; text-transform: uppercase; letter-spacing: .02em; color: var(--tx); max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-ctx-tabs { display: flex; gap: 2px; min-width: 0; overflow-x: auto; scrollbar-width: none; }
.nav-ctx-tabs::-webkit-scrollbar { display: none; }
.nav-ctx-tabs a { flex: none; padding: 8px 12px; border-radius: 9px; color: var(--tx2); font-weight: 800; font-size: .72rem; letter-spacing: .13em; text-transform: uppercase; white-space: nowrap; transition: color .2s, background-color .2s; }
.nav-ctx-tabs a:hover { color: var(--tx); background: rgba(255, 255, 255, .05); }
.nav-ctx-tabs a.is-here { color: #FFF1B8; background: rgba(232, 193, 90, .14); box-shadow: inset 0 0 0 1px rgba(232, 193, 90, .35); }

/* While docked: Menu holds the shop links, Hire sits by the cart. */
.nav-menu, .nav-ctx-act { display: none; }
html.nav-docked .nav-menu { display: block; }
html.nav-docked .nav-ctx-act { display: inline-flex; }
html.nav-docked #nav .nav-login { display: none; }
.nav-menu { position: relative; flex: none; margin-left: -6px; }
.nav-menu > summary { list-style: none; display: inline-flex; align-items: center; gap: 7px; padding: 9px 13px; border: 1px solid rgba(255, 255, 255, .1); border-radius: 10px; color: var(--tx2); font-weight: 900; font-size: .7rem; letter-spacing: .14em; text-transform: uppercase; cursor: pointer; transition: color .2s, border-color .2s, background-color .2s; animation: navIn .3s ease both; }
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu > summary svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; }
.nav-menu > summary:hover, .nav-menu[open] > summary { color: var(--tx); border-color: rgba(255, 255, 255, .22); background: rgba(255, 255, 255, .05); }
.nav-menu ul { position: absolute; top: calc(100% + 10px); left: 0; min-width: 200px; margin: 0; padding: 8px; list-style: none; border: 1px solid rgba(255, 255, 255, .1); border-radius: 14px; background: rgba(14, 13, 10, .92); -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px); box-shadow: 0 18px 40px rgba(0, 0, 0, .5); animation: navIn .22s ease both; }
.nav-menu li a { display: block; padding: 10px 12px; border-radius: 9px; color: var(--tx2); font-weight: 800; font-size: .78rem; letter-spacing: .12em; text-transform: uppercase; }
.nav-menu li a:hover { color: var(--tx); background: rgba(255, 255, 255, .06); }
.nav-ctx-act { animation: navIn .3s ease both; }
.btn-gold { background: linear-gradient(115deg, #8C6418 0%, #E8C15A 22%, #FFF1B8 38%, #D6A73E 52%, #9C7019 70%, #F2D27A 88%, #B8862A 100%); background-size: 200% 100%; color: #1a1204; border-color: transparent; transition: background-position .5s, box-shadow .25s; }
.btn-gold:hover { background-position: 100% 50%; color: #1a1204; box-shadow: 0 0 22px rgba(232, 193, 90, .45); }
.nav-actions .nav-hire { padding: 11px 18px; }
@keyframes navIn { from { opacity: 0; transform: translateY(-6px); } }
@media (max-width: 1240px) { .nav-ctx-name { display: none; } }
@media (prefers-reduced-motion: reduce) {
  .nav-links, .nav-ctx, .nav-menu > summary, .nav-menu ul, .nav-ctx-act { transition: none; animation: none; }
}

/* ---------------- Shop merch / Hire for art (partials/two-sides) ----------------
   One person's two pages as two sides of one profile. A pill slides to the
   side you are on; the other side is one tap away. Orange on the standard
   partner page; the Alley profile gilds it (alley.css). */
.ts-sw { position: relative; display: inline-grid; grid-template-columns: 1fr 1fr; margin: 16px 0 4px; padding: 4px; border-radius: 99px; background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .12); isolation: isolate; }
.ts-sw::before { content: ''; position: absolute; z-index: -1; top: 4px; bottom: 4px; left: 4px; width: calc(50% - 4px); border-radius: 99px; background: var(--acc); box-shadow: 0 6px 18px rgba(0, 0, 0, .35); transition: transform .45s cubic-bezier(.2, 1.2, .3, 1); }
.ts-sw.is-hire::before { transform: translateX(100%); }
.ts-sw a { display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 10px 18px; border-radius: 99px; color: var(--tx2); font-weight: 900; font-size: .74rem; letter-spacing: .1em; text-transform: uppercase; white-space: nowrap; transition: color .25s; }
.ts-sw a svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.ts-sw a[aria-current="page"] { color: #121008; }
.ts-sw a:not([aria-current="page"]):hover { color: var(--tx); }
.ts-sw a:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.ts-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--grn); box-shadow: 0 0 8px var(--grn); }
@media (prefers-reduced-motion: reduce) { .ts-sw::before { transition: none; } }

/* The Shop / Hire for art slide (site.js, layouts/app.php): pages opt in to
   cross-page transitions, and only a move between someone's two sides
   keeps one (everything else skips it). Toward Hire the page slides out to
   the left; back to Shop, out to the right. */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) { @view-transition { navigation: none; } }
::view-transition-group(root) { animation-duration: .45s; }
html:active-view-transition-type(to-hire)::view-transition-old(root) { animation: tsOutLeft .42s cubic-bezier(.4, 0, .2, 1) both; }
html:active-view-transition-type(to-hire)::view-transition-new(root) { animation: tsInRight .46s cubic-bezier(.2, .8, .2, 1) both; }
html:active-view-transition-type(to-shop)::view-transition-old(root) { animation: tsOutRight .42s cubic-bezier(.4, 0, .2, 1) both; }
html:active-view-transition-type(to-shop)::view-transition-new(root) { animation: tsInLeft .46s cubic-bezier(.2, .8, .2, 1) both; }
@keyframes tsOutLeft { to { transform: translateX(-12%); opacity: 0; filter: blur(4px); } }
@keyframes tsInRight { from { transform: translateX(14%); opacity: 0; } }
@keyframes tsOutRight { to { transform: translateX(12%); opacity: 0; filter: blur(4px); } }
@keyframes tsInLeft { from { transform: translateX(-14%); opacity: 0; } }

/* Gradient-filled words (background-clip: text) only paint inside their own
   box, and our display fonts' capitals reach above it — which is what kept
   slicing the tops off headings. Inline words take vertical padding without
   moving anything around them, so every inline gradient word gets room
   above and below here. Any new gradient-filled inline word belongs in
   this list too. (Block-level ones carry their own padding where they are
   defined: .al-title em, .mz-h, the Midz name layers.) */
.sl h2 em,
.al-gold .al-sec-head h2 em, .al-gold .al-gems-head h2 em,
#commissions .apg-sec-head h2 em,
.gg-title span, .gg-tagline span,
.km-title span,
.lv-title span,
.mp-title span, .mp-tagline span,
.mm-title em, .mm-name span,
.hy-h em, .hy-h3 em {
  padding-block: .18em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
