/* ==========================================================================
   artCart.AI storefront
   The customer-facing shop that runs on each artist's own domain.
   Colours are set per store from the database, so everything here reads from
   --sf-menu / --sf-link rather than hard-coding a palette.
   ========================================================================== */

:root {
  --sf-bg:        #ffffff;
  --sf-sunk:      #f7f8fa;
  --sf-text:      #16181d;
  --sf-soft:      #545c6b;
  --sf-faint:     #838d9e;
  --sf-line:      #e4e7ee;
  --sf-line-firm: #ccd2dd;
  --sf-radius:    10px;
  --sf-radius-lg: 16px;
  --sf-shadow:    0 2px 10px rgba(16, 20, 30, .07);
  --sf-shadow-lg: 0 14px 34px rgba(16, 20, 30, .13);
  --sf-maxw:      1240px;

  /* Overridden inline per store. */
  --sf-menu: #16181d;
  --sf-link: #ffffff;

  --sf-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
             "Helvetica Neue", Arial, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--sf-bg);
  color: var(--sf-text);
  font-family: var(--sf-font);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { max-width: 100%; height: auto; display: block; }

h1, h2, h3, h4 {
  margin: 0 0 .5em;
  line-height: 1.22;
  font-weight: 620;
  letter-spacing: -.015em;
}
h1 { font-size: clamp(1.6rem, 1.25rem + 1.6vw, 2.3rem); }
h2 { font-size: clamp(1.3rem, 1.1rem + 1vw, 1.7rem); }
h3 { font-size: 1.12rem; }

p { margin: 0 0 1em; color: var(--sf-soft); }

a { color: inherit; text-decoration: none; }
a:hover { text-decoration: underline; }

:focus-visible { outline: 2px solid var(--sf-menu); outline-offset: 2px; }

.sf-wrap {
  width: 100%;
  max-width: var(--sf-maxw);
  margin-inline: auto;
  padding-inline: 20px;
}

.sf-skip {
  position: absolute;
  left: -9999px;
  background: var(--sf-menu);
  color: var(--sf-link);
  padding: .7rem 1rem;
  z-index: 200;
}
.sf-skip:focus { left: 0; top: 0; }

/* ---------------------------------------------------------------- header - */
.sf-head {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--sf-bg);
  border-bottom: 1px solid var(--sf-line);
}

.sf-head__bar {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 66px;
}

.sf-brand {
  display: flex;
  align-items: center;
  min-width: 0;
  font-size: clamp(1.05rem, .95rem + .6vw, 1.45rem);
  font-weight: 700;
  letter-spacing: -.02em;
}
.sf-brand:hover { text-decoration: none; }
.sf-brand img { max-height: 46px; width: auto; }

.sf-head__actions { display: flex; align-items: center; gap: 4px; margin-left: auto; }

.sf-iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4em;
  min-width: 42px;
  height: 42px;
  padding: 0 .6rem;
  border: 0;
  border-radius: var(--sf-radius);
  background: transparent;
  color: var(--sf-text);
  font: inherit;
  font-size: .9rem;
  cursor: pointer;
  position: relative;
}
.sf-iconbtn:hover { background: var(--sf-sunk); text-decoration: none; }
.sf-iconbtn svg { width: 21px; height: 21px; }

.sf-count {
  position: absolute;
  top: 4px;
  right: 2px;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--sf-menu);
  color: var(--sf-link);
  font-size: .68rem;
  font-weight: 700;
  line-height: 17px;
  text-align: center;
}

/* Category bar: the artist's tag menu. */
.sf-tags { background: var(--sf-menu); }
.sf-tags__inner {
  display: flex;
  gap: 2px;
  align-items: center;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  padding-block: 2px;
}
.sf-tags__inner::-webkit-scrollbar { display: none; }
.sf-tags a {
  padding: .7rem .85rem;
  color: var(--sf-link);
  font-size: .84rem;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: .88;
}
.sf-tags a:hover { opacity: 1; text-decoration: none; }

/* Search, revealed by the header button. */
.sf-search { border-bottom: 1px solid var(--sf-line); background: var(--sf-sunk); }
.sf-search[hidden] { display: none; }
.sf-search input {
  width: 100%;
  padding: 1rem 20px;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 1.05rem;
  color: var(--sf-text);
}
.sf-search input:focus { outline: none; }

/* Slide-out account/menu panel on small screens. */
.sf-drawer {
  position: fixed;
  inset: 0 0 0 auto;
  z-index: 90;
  width: min(310px, 84vw);
  background: var(--sf-bg);
  border-left: 1px solid var(--sf-line);
  transform: translateX(100%);
  transition: transform .22s ease;
  padding: 18px;
  overflow-y: auto;
}
.sf-drawer.is-open { transform: none; }
.sf-drawer a {
  display: block;
  padding: .8rem .2rem;
  border-bottom: 1px solid var(--sf-line);
  font-weight: 520;
}
.sf-drawer a:last-child { border-bottom: 0; }

.sf-scrim {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(12, 14, 20, .45);
  opacity: 0;
  pointer-events: none;
  transition: opacity .22s ease;
}
.sf-scrim.is-open { opacity: 1; pointer-events: auto; }

/* ------------------------------------------------------------------ grid - */
.sf-main { min-height: 55vh; padding-block: 28px 56px; }

.sf-grid {
  display: grid;
  gap: 22px;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
}

.sf-card { display: block; }
.sf-card:hover { text-decoration: none; }

.sf-card__frame {
  background: var(--sf-sunk);
  overflow: hidden;
  aspect-ratio: 1 / 1;
}
.sf-card__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .35s ease;
}
.sf-card:hover .sf-card__frame img { transform: scale(1.04); }

.sf-card__title { margin: .7rem 0 .1rem; font-weight: 570; font-size: .98rem; }
.sf-card__meta  { margin: 0; font-size: .88rem; color: var(--sf-faint); }

/* Category tiles on the home page. */
.sf-cats {
  display: grid;
  gap: 18px;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 210px), 1fr));
}
.sf-cat { position: relative; display: block; overflow: hidden; }
.sf-cat img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.sf-cat span {
  position: absolute;
  inset: auto 0 0 0;
  padding: 2.2rem .9rem .8rem;
  background: linear-gradient(transparent, rgba(0, 0, 0, .72));
  color: #fff;
  font-weight: 650;
  font-size: .9rem;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.sf-cat:hover { text-decoration: none; }

/* ------------------------------------------------------------ art detail - */
.sf-detail { display: grid; gap: 32px; }
@media (min-width: 900px) {
  .sf-detail { grid-template-columns: minmax(0, 1.35fr) minmax(320px, 1fr); align-items: start; }
  .sf-detail__buy { position: sticky; top: 96px; }
}

.sf-detail__img {
  width: 100%;
  background: var(--sf-sunk);
}

.sf-price { font-size: 1.8rem; font-weight: 680; letter-spacing: -.02em; margin: .3rem 0 1rem; }

.sf-field { margin-bottom: 1rem; }
.sf-label {
  display: block;
  margin-bottom: .35rem;
  font-size: .8rem;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--sf-faint);
}

.sf-input, .sf-select, .sf-textarea {
  display: block;
  width: 100%;
  min-height: 46px;
  padding: .65rem .8rem;
  font: inherit;
  color: var(--sf-text);
  background: var(--sf-bg);
  border: 1px solid var(--sf-line-firm);
  border-radius: var(--sf-radius);
  -webkit-appearance: none;
  appearance: none;
}
.sf-textarea { min-height: 110px; resize: vertical; }
.sf-input:focus, .sf-select:focus, .sf-textarea:focus {
  outline: none;
  border-color: var(--sf-menu);
  box-shadow: 0 0 0 3px rgba(0, 0, 0, .06);
}
.sf-select {
  padding-right: 2.2rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%23838d9e' d='M1.4 0 6 4.6 10.6 0 12 1.4 6 7.4 0 1.4z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .8rem center;
}

.sf-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5em;
  min-height: 48px;
  padding: .7em 1.4em;
  border: 1px solid transparent;
  border-radius: var(--sf-radius);
  background: var(--sf-menu);
  color: var(--sf-link);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.sf-btn:hover { filter: brightness(1.12); text-decoration: none; }
.sf-btn--block { width: 100%; }
.sf-btn--ghost {
  background: transparent;
  color: var(--sf-text);
  border-color: var(--sf-line-firm);
}
.sf-btn--ghost:hover { background: var(--sf-sunk); filter: none; }
.sf-btn--sm { min-height: 38px; padding: .4em .9em; font-size: .9rem; }

/* Radio cards for choosing a print medium. */
.sf-options { display: grid; gap: 8px; }
.sf-option {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: .8rem .9rem;
  border: 1px solid var(--sf-line-firm);
  border-radius: var(--sf-radius);
  cursor: pointer;
}
.sf-option input { width: 18px; height: 18px; accent-color: var(--sf-menu); flex: none; }
.sf-option:has(input:checked) { border-color: var(--sf-menu); background: var(--sf-sunk); }

/* --------------------------------------------------------------- content - */
.sf-prose { max-width: 68ch; }
.sf-prose img { margin: 1.2rem 0; }
.sf-prose h2 { margin-top: 2rem; }
.sf-prose ul, .sf-prose ol { color: var(--sf-soft); padding-left: 1.3rem; }

.sf-empty {
  text-align: center;
  padding: 60px 20px;
  color: var(--sf-faint);
  border: 1px dashed var(--sf-line-firm);
  border-radius: var(--sf-radius-lg);
}

.sf-table { width: 100%; border-collapse: collapse; font-size: .93rem; }
.sf-table th, .sf-table td {
  padding: 12px 14px;
  text-align: left;
  border-bottom: 1px solid var(--sf-line);
}
.sf-table th {
  font-size: .76rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--sf-faint);
}
.sf-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* ---------------------------------------------------------------- footer - */
.sf-foot {
  border-top: 1px solid var(--sf-line);
  background: var(--sf-sunk);
  padding: 40px 0 28px;
  margin-top: 56px;
}
.sf-foot__cols {
  display: flex;
  flex-wrap: wrap;
  gap: 26px;
  justify-content: space-between;
  align-items: flex-start;
}
.sf-foot nav { display: flex; flex-wrap: wrap; gap: 18px; }
.sf-foot nav a { font-size: .92rem; color: var(--sf-soft); }
.sf-foot nav a:hover { color: var(--sf-text); }
.sf-social { display: flex; gap: 10px; }
.sf-social a {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--sf-line-firm);
  border-radius: 50%;
  color: var(--sf-soft);
}
.sf-social a:hover { color: var(--sf-text); border-color: var(--sf-text); }
.sf-social svg { width: 18px; height: 18px; }
.sf-foot__base {
  margin-top: 26px;
  padding-top: 20px;
  border-top: 1px solid var(--sf-line);
  font-size: .85rem;
  color: var(--sf-faint);
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: space-between;
}

.sf-mt-2 { margin-top: 1rem; }
.sf-mt-3 { margin-top: 1.6rem; }
.sf-mb-2 { margin-bottom: 1rem; }
.sf-muted { color: var(--sf-faint); }
.sf-small { font-size: .88rem; }
.sf-center { text-align: center; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}

/* ==========================================================================
   Legacy product-option controls
   The size picker is generated by functions.js and the site_art_details_*.php
   includes, which emit .size buttons and a .radio-toolbar wrapper. Its
   behaviour is untouched; these rules just bring the appearance in line with
   the rest of the storefront. The finish picker (.tabs) has its own,
   icon-tile design further down (.sf-finish-grid).
   ========================================================================== */

.radio-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 0;
  margin-bottom: 1rem;
}

button.size {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: 84px !important;
  height: 84px !important;
  min-height: 84px;
  margin: 0 !important;
  padding: .6rem .9rem;
  font: inherit;
  font-size: .92rem;
  font-weight: 550;
  line-height: 1.35;
  text-align: center;
  color: var(--sf-text);
  background: var(--sf-bg);
  border: 1px solid var(--sf-line-firm);
  border-radius: 0;
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}

button.size:hover { background: var(--sf-sunk); border-color: var(--sf-menu); }

/* selectSize() adds .is-selected. It previously only called .focus(), so the
   choice was invisible the moment focus moved away. */
button.size.is-selected {
  background: var(--sf-menu);
  border-color: var(--sf-menu);
  color: var(--sf-link);
}

button.size:focus-visible { outline: 2px solid var(--sf-menu); outline-offset: 2px; }

/* ------------------------------------------------------------ finish picker
   A grid of icon tiles, one per available finish - each icon is CSS-only,
   no image assets, styled to hint at that finish's real-world look. */
.sf-finish-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 1rem;
}

button.sf-finish {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: 108px;
  margin: 0;
  padding: 12px 10px;
  font: inherit;
  background: var(--sf-bg);
  border: 1.5px solid var(--sf-line-firm);
  border-radius: var(--sf-radius);
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease;
}
button.sf-finish:hover { border-color: var(--sf-menu); }
button.sf-finish:focus-visible { outline: 2px solid var(--sf-menu); outline-offset: 2px; }

/* showPrices() adds .is-selected via sfMarkMedium() - same mechanism the
   size tiles use. */
button.sf-finish.is-selected {
  background: var(--sf-sunk);
  border-color: var(--sf-text);
}

.sf-finish__label {
  font-size: .82rem;
  font-weight: 600;
  line-height: 1.25;
  text-align: center;
  color: var(--sf-text);
}

.sf-finish__icon {
  position: relative;
  width: 56px;
  height: 56px;
  border-radius: 4px;
  background: #d8d8d8;
  overflow: hidden;
}

/* Acrylic: a glossy diagonal highlight. */
.sf-finish__icon--acrylic {
  background: linear-gradient(135deg, #cfcfcf 45%, #efefef 55%, #cfcfcf 65%);
}

/* Canvas Rolled: plain and flat - the roll itself only shows on the real
   preview, not this small icon. */
.sf-finish__icon--rolled { background: #d3d3d3; }

/* Canvas Wrapped: a darker strip down the left edge hints at the wrapped
   side, echoing the real .is-wrapped preview's canvas-edge. */
.sf-finish__icon--wrapped {
  background: #d8d8d8;
}
.sf-finish__icon--wrapped::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 8px;
  background: #a9a9a9;
}

/* Matted Print: a white mat inset within the grey icon. */
.sf-finish__icon--matted {
  background: #d3d3d3;
  display: flex;
  align-items: center;
  justify-content: center;
}
.sf-finish__icon--matted::before {
  content: '';
  width: 60%;
  height: 60%;
  background: #fff;
}

/* Paper Lustre: a subtle glossy sheen. */
.sf-finish__icon--lustre {
  background: linear-gradient(160deg, #dcdcdc 40%, #f0f0f0 50%, #dcdcdc 60%);
}

/* Paper Matte: flat, no sheen at all. */
.sf-finish__icon--matte { background: #d3d3d3; }
.sf-detail__buy br[style*="clear"] { display: none; }

.sf-buybox {
  border: 1px solid var(--sf-line);
  border-radius: var(--sf-radius-lg);
  padding: 18px;
  background: var(--sf-sunk);
  margin-top: 1.2rem;
}
.sf-buybox #displayPrice {
  font-size: 1.6rem;
  font-weight: 680;
  letter-spacing: -.02em;
  min-height: 2rem;
}
.sf-buybox #displayPrice h4 { margin: 0; font-size: inherit; font-weight: inherit; }

.sf-fav {
  display: inline-flex;
  align-items: center;
  gap: .4em;
  margin-top: .8rem;
  font-size: .9rem;
  color: var(--sf-soft);
  cursor: pointer;
}
.sf-fav:hover { color: var(--sf-text); }

/* --------------------------------------------------------- artwork gallery */
.sf-gallery__main {
  position: relative;
  background: var(--sf-sunk);
  overflow: hidden;
}
.sf-gallery__main img { width: 100%; height: auto; }
.sf-gallery__main.is-portrait img {
  width: auto;
  max-height: 72vh;
  margin-inline: auto;
}

/* ------------------------------------------------- finish-specific previews
   Chosen by sfSetFinishEffect() in site_art_image.php as the shopper picks a
   Finish tab. */

/* Matted Print: a solid white mat around the print, like a real mount board -
   overflow has to open up so the mat has room; .sf-gallery__main is
   overflow:hidden by default for the other finishes. */
.sf-gallery__main.is-matted {
  overflow: visible;
  background: #fff;
  padding: 8%;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .12);
}
.sf-gallery__main.is-matted img#mainImg {
  box-shadow: 0 1px 3px rgba(0, 0, 0, .15);
}

/* Canvas Wrapped: a real 3D box, not a faked one - the artwork is the front
   face and the left-hand side of the stretcher stands at 90 degrees to it in
   the same 3D scene (transform-style: preserve-3d on .canvas-panel), so the
   wrap edge meets the artwork exactly along its left border at whatever angle
   the panel is turned. #canvas3d itself lives in site_art_image.php and
   mockup-render.php, starts hidden, and carries an inline aspect-ratio taken
   from the artwork's own pixel dimensions.

   Two things this has to survive, both of which broke the previous version:

   - Portrait artwork. Sizing the panel by height against a fixed landscape
     box squeezed every portrait piece into a sliver. The panel is now a
     share of a box that already has the artwork's own ratio, so it inherits
     that ratio and the image is never distorted.

   - .sf-gallery__main's overflow:hidden. The old panel was wider than its
     container and offset further right again, so the right-hand side of
     every piece was simply cut off. Everything now sits well inside the
     box - which matters beyond the crop, because the Node/Puppeteer service
     screenshots exactly this element for the Etsy previews, so whatever
     falls outside it is lost from those images rather than merely hidden. */
/* #canvas3d carries both of the turned finishes, Canvas Wrapped and Acrylic -
   same box, same turn, same shadow. Only the edge tells them apart, and the
   edge is the whole difference: a canvas wraps the artwork around a deep
   wooden stretcher, so its side is thick and carries the picture, while a
   print face-mounted to acrylic sits behind a thin sheet whose polished edge
   carries no picture at all, only light. The element keeps its original id
   from when canvas was the only finish that used it. */
.sf-gallery__main.is-wrapped,
.sf-gallery__main.is-acrylic {
  background: var(--sf-sunk);
}
.sf-gallery__main.is-wrapped #canvas3d,
.sf-gallery__main.is-acrylic #canvas3d {
  width: 100%;
  /* Makes cqw below resolve against this box, so the turn is identical in the
     fluid storefront gallery and in the fixed 900px Etsy render. */
  container-type: inline-size;
}
.canvas-frame {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Proportional to the artwork's own width, not a fixed pixel distance: a
     px perspective makes the turn strong on a wide desktop gallery and nearly
     flat on a phone, so the on-site preview and the Etsy image it is supposed
     to match would disagree. The px value is the fallback for browsers
     without container query units - without it they would parse cqw as
     invalid, drop perspective entirely and flatten the canvas completely. */
  perspective: 1900px;
  perspective: 290cqw;
}
/* A share of a box that already carries the artwork's aspect ratio, so the
   panel carries it too. The space left over is what the turn, the wrap edge
   and the shadow need in order to stay inside the crop. The nudge right
   balances the wrap edge, which only ever sticks out on the left; the nudge
   up balances the shadow, which only ever falls below. */
.canvas-panel {
  position: relative;
  width: 72%;
  height: 72%;
  transform-style: preserve-3d;
  transform: translate(1.5%, -2%) rotateY(22deg);
}
/* Addressed through #canvas3d so that .sf-gallery__main.is-portrait img
   (width:auto; max-height:72vh; margin-inline:auto) cannot reach it - that
   rule is meant for the plain product photo hanging in the gallery box, and
   inside the canvas it resizes the front face out from under the wrap edge.
   Every one of its declarations has to be answered here, max-height above
   all: the edge is 100% of the panel's height, so a face clamped to 72vh
   while the edge is not leaves the two at different vertical scales - the
   seam splits open, and it re-splits differently at every zoom level,
   because that is when vh changes. */
#canvas3d .canvas-panel > img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin-inline: 0;
  object-fit: cover;
  /* Barely there, and meant to be: a stretched canvas has a soft corner where
     the fabric turns rather than a cut one, but any more than a hint of it
     stops reading as canvas and starts reading as a rounded photo frame. */
  border-radius: 4px;
  /* Falling down and to the left, away from a light source up and to the
     right - which is the side the panel is turned towards, so the lit face and
     the cast shadow agree with each other. The second, tighter shadow is the
     contact one directly beneath: without it the canvas floats rather than
     stands. */
  box-shadow:
    -16px 24px 34px -16px rgba(0, 0, 0, .38),
    -2px 10px 16px -8px rgba(0, 0, 0, .28);
}
/* The wrap itself: the same artwork again, hinged along the front face's left
   border and receding backwards from it. background-size:auto 100% scales the
   artwork to the panel's own height, which makes its scaled width the panel's
   own width - so this strip shows precisely the leftmost slice of the piece,
   which is the part that really does wrap around a stretched canvas. */
.canvas-edge {
  position: absolute;
  top: 0;
  left: 0;
  width: 12%;
  height: 100%;
  /* Rounded on its back corners only - those are the leftmost outline of the
     canvas on screen, so they are what needs softening. The hinge corners stay
     square: rounding the side that meets the front face would open a notch in
     the seam the two share. */
  border-radius: 0 4px 4px 0;
  transform-origin: left center;
  transform: rotateY(90deg);
  background-size: auto 100%;
  background-position: left center;
  background-repeat: no-repeat;
}
/* Shaded with a gradient rather than a filter: filter is a grouping property,
   so applying one inside a preserve-3d scene flattens that element out of the
   3D and the edge stops meeting the front face. Darker towards the back,
   where less light reaches it.

   How dark is set per artwork by js/canvas-edge.js, which measures the strip
   that actually wraps. The values here are the fallback for a picture it could
   not read - a cross-origin image taints the canvas it samples from - and are
   pitched for a mid-toned piece. A single fixed pair cannot serve every
   artwork: it took the same share of brightness off a cream ground as off a
   near-black one, which left pale pieces with an edge that read as black. */
.canvas-edge::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to right,
    var(--edge-near, rgba(0, 0, 0, .42)),
    var(--edge-far,  rgba(0, 0, 0, .78)));
}

/* Acrylic: the same turned panel as Canvas Wrapped, wearing a sheet of
   acrylic instead of a stretched canvas.

   Two changes carry that. The edge is much shallower - a face-mount sheet is a
   few millimetres against a canvas stretcher's inch and a half - and it is
   pale rather than dark, because a polished acrylic edge gathers and throws
   light where a canvas side falls into its own shadow. It also carries no
   artwork: nothing wraps around it, so the picture stops at the face. That is
   why the edge's artwork background is left unset for this finish rather than
   overridden here - an inline style would win over a stylesheet rule anyway,
   so site_art_image.php and mockup-render.php simply never set one. */
.sf-gallery__main.is-acrylic .canvas-edge {
  width: 4.5%;
  background-size: 100% 100%;
  background-image: linear-gradient(
    to right,
    rgba(232, 244, 250, .98) 0%,
    rgba(255, 255, 255, .94) 32%,
    rgba(198, 220, 233, .96) 72%,
    rgba(150, 178, 195, .98) 100%);
}
/* The wrapped edge's shading would only muddy a surface that is meant to look
   lit. */
.sf-gallery__main.is-acrylic .canvas-edge::after {
  background: none;
}
/* The bright inner line where the sheet meets the picture - the giveaway that
   the artwork sits behind acrylic rather than being printed on the surface. */
.sf-gallery__main.is-acrylic .canvas-panel::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 1.4%;
  background: linear-gradient(to right, rgba(255, 255, 255, .9), rgba(255, 255, 255, 0));
  pointer-events: none;
  z-index: 2;
}

.sf-gallery__strip {
  display: flex;
  gap: 10px;
  margin-top: 12px;
  overflow-x: auto;
  padding-bottom: 4px;
  -webkit-overflow-scrolling: touch;
}
.sf-gallery__thumb {
  flex: none;
  width: 76px;
  height: 76px;
  padding: 0;
  border: 1px solid var(--sf-line-firm);
  background: var(--sf-sunk);
  overflow: hidden;
  cursor: pointer;
}
.sf-gallery__thumb img { width: 100%; height: 100%; object-fit: cover; }
.sf-gallery__thumb:hover { border-color: var(--sf-menu); }

/* ==========================================================================
   Shop home, browse and listing components
   ========================================================================== */

/* ------------------------------------------------------------------ hero - */
.sf-hero {
  display: grid;
  gap: 28px;
  align-items: center;
  padding-block: 8px 40px;
}
@media (min-width: 860px) {
  .sf-hero { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); gap: 48px; }
}

.sf-hero h1 {
  font-size: clamp(1.9rem, 1.4rem + 2.4vw, 3.1rem);
  letter-spacing: -.03em;
  margin-bottom: .4em;
}
.sf-hero__lede {
  font-size: clamp(1rem, .95rem + .35vw, 1.14rem);
  color: var(--sf-soft);
  max-width: 46ch;
}
.sf-hero__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 1.6rem; }
.sf-hero__meta { margin: 1.1rem 0 0; font-size: .88rem; color: var(--sf-faint); }

.sf-hero__art {
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--sf-sunk);
  box-shadow: var(--sf-shadow-lg);
}
.sf-hero__art img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform .5s ease;
}
.sf-hero__art:hover img { transform: scale(1.03); }
.sf-hero__art:hover { text-decoration: none; }
.sf-hero__tag {
  position: absolute;
  left: 14px;
  bottom: 14px;
  padding: .4rem .8rem;
  border-radius: var(--sf-radius-pill, 999px);
  background: rgba(12, 14, 20, .68);
  backdrop-filter: blur(6px);
  color: #fff;
  font-size: .85rem;
  font-weight: 600;
}

/* --------------------------------------------------------------- sections - */
.sf-section { padding-block: 34px; }
.sf-section__head {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 18px;
}
.sf-section__head h1,
.sf-section__head h2 { margin: 0; }
.sf-more { font-size: .92rem; font-weight: 600; color: var(--sf-soft); white-space: nowrap; }
.sf-more:hover { color: var(--sf-text); }

/* ------------------------------------------------------------------ chips - */
.sf-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 22px;
}
.sf-chip {
  display: inline-block;
  padding: .4rem .85rem;
  border: 1px solid var(--sf-line-firm);
  border-radius: 999px;
  font-size: .88rem;
  font-weight: 550;
  color: var(--sf-soft);
  text-transform: capitalize;
  white-space: nowrap;
}
.sf-chip:hover { border-color: var(--sf-menu); color: var(--sf-text); text-decoration: none; }
.sf-chip.is-active {
  background: var(--sf-menu);
  border-color: var(--sf-menu);
  color: var(--sf-link);
}

/* ------------------------------------------------------------ breadcrumbs - */
.sf-crumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-bottom: 16px;
  font-size: .86rem;
  color: var(--sf-faint);
}
.sf-crumbs a { color: var(--sf-soft); }
.sf-crumbs a:hover { color: var(--sf-text); }
.sf-crumbs span { color: var(--sf-faint); }

/* ------------------------------------------------------------ trust strip - */
.sf-trust {
  display: grid;
  gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  padding: 26px;
  margin-block: 34px;
  background: var(--sf-sunk);
  border-radius: var(--sf-radius-lg);
}
.sf-trust div { display: flex; flex-direction: column; gap: 3px; }
.sf-trust strong { font-size: .95rem; }
.sf-trust span { font-size: .86rem; color: var(--sf-faint); }

/* ------------------------------------------------------------------ about - */
.sf-about {
  display: grid;
  gap: 26px;
  align-items: center;
  padding-block: 34px;
  border-top: 1px solid var(--sf-line);
}
@media (min-width: 760px) {
  .sf-about { grid-template-columns: minmax(0, 320px) minmax(0, 1fr); gap: 38px; }
}
.sf-about img { width: 100%; object-fit: cover; }
.sf-about h2 { margin-bottom: .5rem; }

/* ----------------------------------------------------------------- pager -- */
.sf-pager {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: center;
  justify-content: center;
  margin-top: 34px;
}

/* ----------------------------------------------------------- related work - */
.sf-related { padding-top: 40px; margin-top: 40px; border-top: 1px solid var(--sf-line); }

/* --------------------------------------------------- artwork detail extras - */
.sf-detail__title { margin-bottom: .3rem; }
.sf-from {
  font-size: 1.05rem;
  color: var(--sf-soft);
  margin-bottom: 1.2rem;
}
.sf-from strong { color: var(--sf-text); font-size: 1.35rem; font-weight: 680; }

.sf-notes {
  margin-top: 1.2rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--sf-line);
  font-size: .89rem;
  color: var(--sf-faint);
  display: grid;
  gap: .5rem;
}
.sf-notes div { display: flex; gap: .6rem; align-items: flex-start; }
.sf-notes strong { color: var(--sf-soft); font-weight: 600; }

/* ---------------------------------------------------------------- contact - */
.sf-contact {
  display: grid;
  gap: 32px;
  padding-block: 8px 40px;
}
@media (min-width: 820px) {
  .sf-contact { grid-template-columns: minmax(0, 1fr) minmax(0, 460px); gap: 48px; align-items: start; }
}

.sf-form {
  background: var(--sf-bg);
  border: 1px solid var(--sf-line);
  border-radius: var(--sf-radius-lg);
  padding: 24px;
  box-shadow: var(--sf-shadow);
}

.sf-alert {
  padding: .8rem 1rem;
  border-radius: var(--sf-radius);
  font-size: .92rem;
  margin: 0 0 1rem;
}
.sf-alert--ok  { background: #e6f6ec; color: #14603a; }
.sf-alert--bad { background: #fdeaec; color: #96202f; }

/* ==========================================================================
   Cart
   ========================================================================== */
.sf-cart {
  display: grid;
  gap: 28px;
  align-items: start;
  padding-bottom: 40px;
}
@media (min-width: 900px) {
  .sf-cart { grid-template-columns: minmax(0, 1fr) minmax(0, 340px); gap: 40px; }
  .sf-summary { position: sticky; top: 96px; }
}

.sf-line {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr);
  gap: 16px;
  padding: 18px 0;
  border-bottom: 1px solid var(--sf-line);
}
@media (min-width: 620px) {
  .sf-line { grid-template-columns: 120px minmax(0, 1fr) auto; gap: 20px; align-items: start; }
}
.sf-line:first-child { border-top: 1px solid var(--sf-line); }

.sf-line__img {
  display: block;
  overflow: hidden;
  background: var(--sf-sunk);
}
.sf-line__img img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; }

.sf-line__title { font-weight: 620; font-size: 1.02rem; }
.sf-line__meta  { margin: .2rem 0 .5rem; font-size: .88rem; color: var(--sf-faint); }
.sf-line__price { margin: 0 0 .8rem; font-size: .95rem; }
.sf-line__price del { color: var(--sf-faint); margin-right: .4em; }
.sf-line__price strong { font-weight: 650; }

.sf-line__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}
.sf-qty { display: flex; gap: 8px; align-items: center; }
.sf-qty input {
  width: 68px;
  min-height: 38px;
  padding: .35rem .5rem;
  text-align: center;
  font: inherit;
  color: var(--sf-text);
  background: var(--sf-bg);
  border: 1px solid var(--sf-line-firm);
  border-radius: var(--sf-radius);
}

.sf-linkbtn {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: .9rem;
  color: var(--sf-faint);
  text-decoration: underline;
  cursor: pointer;
}
.sf-linkbtn:hover { color: var(--sf-text); }

.sf-line__total {
  grid-column: 2;
  font-size: 1.05rem;
  font-weight: 680;
  white-space: nowrap;
}
@media (min-width: 620px) {
  .sf-line__total { grid-column: auto; text-align: right; }
}

/* ---------------------------------------------------------------- summary - */
.sf-summary {
  background: var(--sf-sunk);
  border: 1px solid var(--sf-line);
  border-radius: var(--sf-radius-lg);
  padding: 22px;
}
.sf-summary h2 { font-size: 1.15rem; margin-bottom: 1rem; }
.sf-summary__row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: .45rem 0;
  font-size: .95rem;
  color: var(--sf-soft);
}
.sf-summary__row--total {
  margin-top: .4rem;
  padding-top: .9rem;
  border-top: 1px solid var(--sf-line-firm);
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--sf-text);
}

.sf-coupon { margin-top: 1.2rem; }
.sf-coupon__row { display: flex; gap: 8px; }
.sf-coupon__row .sf-input { flex: 1 1 auto; }
.sf-coupon__msg { margin: .5rem 0 0; font-size: .86rem; }
.sf-coupon__msg--ok  { color: #14603a; }
.sf-coupon__msg--bad { color: #96202f; }

.sf-hint { margin: .6rem 0 0; font-size: .84rem; color: var(--sf-faint); }

/* ==========================================================================
   Account forms (create account, sign in)
   ========================================================================== */
.sf-account {
  display: grid;
  gap: 30px;
  align-items: start;
  padding-bottom: 40px;
}
@media (min-width: 860px) {
  .sf-account { grid-template-columns: minmax(0, 1fr) minmax(0, 520px); gap: 48px; }
  .sf-account__intro { position: sticky; top: 96px; }
}

.sf-form__legend {
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--sf-faint);
  margin: 1.8rem 0 .9rem;
  padding-bottom: .5rem;
  border-bottom: 1px solid var(--sf-line);
}
.sf-form__legend:first-of-type { margin-top: 0; }

.sf-row2 { display: grid; gap: 0 14px; }
@media (min-width: 520px) {
  .sf-row2 { grid-template-columns: 1fr 1fr; }
}

/* account_check.php replies with its own coloured span; keep it readable. */
#uname_response span { font-size: .84rem; }

/* ==========================================================================
   Checkout and simple panels
   ========================================================================== */
.sf-panel {
  max-width: 480px;
  margin-inline: auto;
  padding: 28px;
  background: var(--sf-bg);
  border: 1px solid var(--sf-line);
  border-radius: var(--sf-radius-lg);
  box-shadow: var(--sf-shadow);
}
.sf-panel .sf-form { border: 0; box-shadow: none; padding: 0; background: none; }
.sf-choices { display: grid; gap: 10px; margin-top: 1.6rem; }

.sf-check {
  display: flex;
  gap: .6rem;
  align-items: center;
  cursor: pointer;
  font-size: .95rem;
}
.sf-check input { width: 18px; height: 18px; accent-color: var(--sf-menu); flex: none; }

.sf-checkout {
  display: grid;
  gap: 28px;
  align-items: start;
  padding-bottom: 40px;
}
@media (min-width: 940px) {
  .sf-checkout { grid-template-columns: minmax(0, 1fr) minmax(0, 350px); gap: 40px; }
  .sf-checkout__summary { position: sticky; top: 96px; }
}

/* Mini line items in the checkout summary. */
.sf-mini {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px solid var(--sf-line);
}
.sf-mini img {
  width: 46px; height: 46px;
  object-fit: cover;
  background: var(--sf-bg);
}
.sf-mini div { display: flex; flex-direction: column; min-width: 0; }
.sf-mini strong { font-size: .9rem; font-weight: 600; }
.sf-mini__price { font-size: .9rem; font-weight: 620; white-space: nowrap; }
.sf-mini + .sf-summary__row { margin-top: .8rem; }

/* The summary figures are divs written to by functions.js. */
.sf-summary__row div { display: inline; }

/* Square's card iframe container. */
#card-container {
  min-height: 90px;
  padding: 4px 0;
}

/* ------------------------------------------------------------- busy state --
   Placing an order is not instant: the card is authorised with the provider,
   then submit_order.php verifies the payment, writes the order and sends two
   emails. Without feedback that gap invites a second click, and a second click
   on a payment button is the one thing a checkout must never allow.

   Mirrors .ac-btn.is-loading in artcart.css, in storefront clothing. */
.sf-btn.is-loading {
  position: relative;
  color: transparent !important;
  pointer-events: none;
}
.sf-btn.is-loading::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 18px; height: 18px;
  margin: -9px 0 0 -9px;
  border: 2px solid rgba(255, 255, 255, .45);
  border-top-color: #fff;
  border-radius: 50%;
  animation: sf-spin .7s linear infinite;
}
@keyframes sf-spin { to { transform: rotate(360deg); } }

/* The whole-page block, so nothing else on the checkout can be touched while
   the payment is in flight - including the browser's own back button being
   used mid-authorisation. */
.sf-busy {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 16px;
  background: rgba(255, 255, 255, .92);
  text-align: center;
  padding: 24px;
}
.sf-busy[hidden] { display: none; }
.sf-busy__spin {
  width: 42px; height: 42px;
  border: 3px solid rgba(0, 0, 0, .12);
  border-top-color: var(--sf-menu, #1e2a5a);
  border-radius: 50%;
  animation: sf-spin .7s linear infinite;
}
.sf-busy__title { font-weight: 600; font-size: 1.05rem; margin: 0; }
.sf-busy__note  { font-size: .875rem; color: #555; margin: 0; max-width: 30rem; }

@media (prefers-reduced-motion: reduce) {
  .sf-btn.is-loading::after, .sf-busy__spin { animation-duration: 2s; }
}

/* ------------------------------------------------------------ framed print
   The moulding round the print, and the swatches it is chosen from. These
   live here as well as in artcart.css because the storefront loads only this
   stylesheet - admin/frames.php previews the same frames inside the admin
   shell, which loads the other one. */

/* One generated nine-patch (lib/ac_frames.php) serves every frame at every
   size; the border-width is what decides how heavy it looks, and js/frames.js
   sets that from the moulding's face width against the print size. The value
   here is only what shows before that script runs. */
.fr-preview {
  border-style: solid;
  border-width: 26px;
  border-image-slice: 33.333% fill;
  border-image-repeat: round;
  background: #fff;
  line-height: 0;
  max-width: 100%;
}
.fr-preview img { width: 100%; height: auto; display: block; }

/* Square, because a corner sample is square and a row of them reads as a set
   of choices rather than a gallery. */
.sf-frames { display: flex; flex-wrap: wrap; gap: 10px; margin: 6px 0 10px; }
.sf-frame {
  width: 66px;
  height: 66px;
  padding: 0;
  border: 2px solid #ccd2dd;
  border-radius: 8px;
  background: none;
  cursor: pointer;
  overflow: hidden;
  line-height: 0;
}
.sf-frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sf-frame:hover { border-color: #888; }
.sf-frame.is-selected { border-color: #222; box-shadow: 0 0 0 2px rgba(0, 0, 0, .12); }

/* The border a print is matted with. White board is what a mat nearly always
   is, and it has to read as board rather than as a gap in the page - so the
   frame's padding is painted white and the print sits on it with the faint
   shadow a print in a mount casts. */
.fr-preview { background: #fff; }
.fr-preview img { box-shadow: 0 0 0 1px rgba(0, 0, 0, .07); }

.sf-mats { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 10px; }
.sf-mat {
  min-width: 58px;
  padding: 9px 12px;
  border: 2px solid #ccd2dd;
  border-radius: 8px;
  background: #fff;
  font: inherit;
  font-size: .92rem;
  cursor: pointer;
}
.sf-mat:hover { border-color: #888; }
.sf-mat.is-selected { border-color: #222; box-shadow: 0 0 0 2px rgba(0, 0, 0, .12); }

/* .sf-gallery__main sets img { width: 100% } for the plain photo; the framed
   preview is a block of its own inside it and must not be stretched past the
   box its border was measured against. */
.sf-gallery__main .fr-preview { width: 100%; }
