/* ==========================================================================
   Student Art Society — the art store
   Path: MITD/v5/sites/sas-home/assets/sas/css/store.css

   Loaded after sas.css, only on /store.php. Everything shared -- the band
   padding, the scroller, .btn, .chip, the hero -- already lives there; this
   sheet is only the five shapes the shop front adds.

   The headings deliberately match .emerge__title's scale and weight rather
   than inventing a shop voice: this is a room in the same building, and a
   second heading style would read as a second site.
   -------------------------------------------------------------------------- */

/* ── the heading used by every band here ─────────────────────────────────── */
.band__h {
  font-size: clamp(24px, 3.1vw, 40px); font-weight: 900; font-stretch: 106%;
  line-height: .96; letter-spacing: -.03em; text-transform: uppercase;
}
.band__h span { display: inline; }
.band__h .is-accent { color: var(--cyan); }

/* ==========================================================================
   SHELF — shop by medium
   -------------------------------------------------------------------------- */
.shelf__head {
  display: flex; flex-wrap: wrap; gap: 10px clamp(14px, 2vw, 28px);
  align-items: end; justify-content: space-between;
  margin-bottom: clamp(14px, 1.8vw, 22px);
}
.shelf__aside { display: flex; align-items: center; gap: clamp(10px, 1.4vw, 18px); }
.shelf__lede {
  margin: 0; color: var(--ash); font-size: 11.5px; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase;
}
.shelf__nav { display: flex; gap: 8px; }
/* The pager buttons are positioned against the rail elsewhere on this site;
   here they sit in the heading row, so the absolute placement has to go. */
.shelf__nav .scroller__btn,
.goods__nav .scroller__btn { position: static; }

.shelf__rail { position: relative; }
.shelf__track {
  display: grid; grid-auto-flow: column;
  grid-auto-columns: minmax(148px, 1fr);
  gap: var(--gap);
}
/* Four and a bit on a tablet, two and a bit on a phone -- always a partial
   card at the edge, which is what tells you the row scrolls. */
@media (max-width: 900px) { .shelf__track { grid-auto-columns: minmax(136px, 42%); } }
@media (max-width: 560px) { .shelf__track { grid-auto-columns: minmax(124px, 62%); } }

.dept {
  position: relative; display: grid; grid-template-rows: auto 1fr;
  min-width: 0; overflow: hidden;
  border: 1px solid var(--hairline-lo); border-radius: 14px;
  background: var(--panel);
  transition: border-color .2s var(--ease), transform .2s var(--ease);
}
.dept:hover { border-color: var(--cyan); transform: translateY(-3px); }
.dept:focus-within { border-color: var(--cyan); }

.dept__media { display: block; aspect-ratio: 4 / 3; background: var(--panel-2); }
.dept__media img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* No picture yet is a real state: a designed panel, not a broken-image icon. */
.dept.is-empty .dept__media {
  background-image:
    radial-gradient(90% 120% at 20% 0%, rgba(138, 77, 255, .5), transparent 60%),
    linear-gradient(150deg, var(--panel-2), rgba(47, 228, 255, .16));
}

.dept__body {
  display: flex; align-items: end; justify-content: space-between; gap: 10px;
  padding: 10px 12px 12px; min-width: 0;
}
.dept__text { display: grid; gap: 3px; min-width: 0; }
.dept__title { font-size: 13.5px; font-weight: 800; letter-spacing: -.01em; }
/* The anchor's ::after is what makes the whole card clickable. On a <span>
   parent it would be clipped; .dept is the positioned ancestor. */
.dept__go { color: var(--ice); text-decoration: none; }
.dept__go::after { content: ''; position: absolute; inset: 0; }
.dept__go:hover { color: var(--cyan-2); }
.dept__lines { display: grid; gap: 1px; min-width: 0; }
.dept__line { color: var(--ash); font-size: 11px; line-height: 1.35; }

.dept__chip {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 28px; height: 28px; border-radius: 999px;
  border: 1px solid var(--hairline); background: rgba(5, 6, 14, .55);
  transition: background .2s var(--ease), border-color .2s var(--ease);
}
.dept__chip .i { width: 15px; height: 15px; }
.dept:hover .dept__chip { background: rgba(47, 228, 255, .18); border-color: var(--cyan); }

/* A department with nowhere to go yet says so by being quiet, the same way
   every other unbuilt link on this site does. */
.dept.is-inert { opacity: .72; }
.dept.is-inert:hover { transform: none; border-color: var(--hairline-lo); }
.dept.is-inert .dept__chip { opacity: .5; }

/* ==========================================================================
   GOODS — featured artworks
   -------------------------------------------------------------------------- */
.goods__head {
  display: flex; flex-wrap: wrap; gap: 12px clamp(14px, 2vw, 24px);
  align-items: center; justify-content: space-between;
  margin-bottom: clamp(14px, 1.8vw, 22px);
}
.goods__filters { display: flex; flex-wrap: wrap; gap: 7px; min-width: 0; }
.goods__nav { display: flex; gap: 8px; }

.chipf {
  padding: 6px 13px;
  border: 1px solid var(--hairline-lo); border-radius: 999px;
  background: rgba(10, 13, 26, .7); color: var(--ash);
  font: inherit; font-size: 11.5px; font-weight: 600; line-height: 1.5;
  white-space: nowrap; cursor: pointer;
  transition: border-color .18s var(--ease), color .18s var(--ease),
              background .18s var(--ease);
}
.chipf:hover { border-color: var(--cyan); color: var(--ice); }
.chipf:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
/* The chosen one. The same gradient the artist page's medium filter uses when
   it is on, so the two read as the same control in two rooms. */
.chipf.is-on {
  background-image: linear-gradient(100deg, var(--violet), var(--magenta));
  border-color: transparent; color: #0B0413;
}

.goods__rail { position: relative; }
/* A CARD HAS A WIDTH. IT IS NOT "A SHARE OF THE ROW".

   .scroller__track is already a flex row, and this band overrode it to a grid
   with grid-auto-columns: minmax(176px, 1fr). 1fr means each implicit column
   takes an equal share of the VISIBLE width, so the card size depended on how
   many pieces the artist happened to have: six divided nicely and looked
   right, two gave two 659px cards, and one gave a single card 1338px wide and
   1440px tall -- which is what a visitor to an artist with one thing for sale
   actually saw.

   The featured-works rail next to it had this right all along, and said so:

       flex-basis, not a grid track: the card has to keep its width while the
       track scrolls, and a grid column would divide the visible width instead.
       .works > .work { flex: 0 0 clamp(210px, 23vw, 290px); }

   So this row now does the same thing, with the same numbers, at the same
   breakpoint. The two rails sit one above the other on an artist page, and a
   piece and the print of that piece should not be different sizes. Matching
   the values rather than inventing new ones also means the card width is one
   decision in one place, not two that drift. */
.goods__track { align-items: start; }
.goods__track > .good { flex: 0 0 clamp(210px, 23vw, 290px); }
@media (max-width: 560px) {
  .goods__track > .good { flex: 0 0 clamp(170px, 46vw, 230px); }
}

.good {
  position: relative; display: grid; min-width: 0; overflow: hidden;
  border: 1px solid var(--hairline-lo); border-radius: 14px;
  background: var(--panel);
  transition: border-color .2s var(--ease), transform .2s var(--ease);
}
.good:hover { border-color: var(--cyan); transform: translateY(-3px); }
.good:focus-within { border-color: var(--cyan); }
/* hidden by the filter -- display:none rather than visibility, so the grid
   closes the gap instead of leaving a hole where the card was. */
.good[hidden] { display: none; }

.good__media { display: block; aspect-ratio: 1 / 1; background: var(--panel-2); }
.good__media img { display: block; width: 100%; height: 100%; object-fit: cover; }
.good.is-empty .good__media {
  background-image:
    radial-gradient(90% 120% at 70% 10%, rgba(255, 61, 158, .45), transparent 60%),
    linear-gradient(150deg, var(--panel-2), rgba(138, 77, 255, .3));
}

.good__body {
  display: flex; align-items: start; justify-content: space-between; gap: 10px;
  padding: 10px 12px 2px; min-width: 0;
}
.good__text { display: grid; gap: 2px; min-width: 0; }
.good__title { font-size: 13px; font-weight: 800; letter-spacing: -.01em; }
.good__go { color: var(--ice); text-decoration: none; }
.good__go::after { content: ''; position: absolute; inset: 0; }
.good__go:hover { color: var(--cyan-2); }
.good__artist { color: var(--ash); font-size: 11.5px; }
.good__kind   { color: var(--ash-dim); font-size: 10.5px; line-height: 1.35; }

.good__price {
  padding: 0 12px 12px;
  font-size: 15px; font-weight: 800; letter-spacing: -.01em;
}

/* THE BASKET BUTTON, and the z-index is the whole trick: the card's title
   anchor covers the card with its ::after, so without lifting this above it
   the basket would be unclickable the day the shop opens. */
.good__cart {
  position: relative; z-index: 2; flex: 0 0 auto;
  display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 999px;
  border: 1px solid var(--hairline); background: rgba(5, 6, 14, .6);
  color: var(--ice); text-decoration: none;
  transition: background .18s var(--ease), border-color .18s var(--ease);
}
.good__cart .i { width: 16px; height: 16px; }
.good__cart:hover { background: rgba(47, 228, 255, .18); border-color: var(--cyan); }
.good__cart:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
/* Nothing to sell yet. Dimmed and unclickable rather than live-looking --
   see the note in bands/goods.php. */
.good__cart[aria-disabled="true"] {
  opacity: .38; pointer-events: none; cursor: default;
}

/* ==========================================================================
   PROMO — one wide picture with a few words on it
   -------------------------------------------------------------------------- */
/* NO BACKGROUND ON THE PANEL ITSELF, and that is not a style choice.
   isolation: isolate makes this a stacking context, and a child at a NEGATIVE
   z-index paints behind its stacking context's own background -- so an opaque
   background here hid every picture these panels were given. The art and the
   veil are layered at 0 and 1 instead, and the fallback gradient moves onto
   .is-empty, which is the only state that needs one. */
.promo {
  position: relative; overflow: hidden; isolation: isolate;
  min-height: clamp(190px, 24vw, 280px);
  display: grid; align-items: center;
  border: 1px solid var(--hairline-lo); border-radius: 18px;
}
.promo__art {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
}
/* The copy gets its own gradient rather than sitting on the raw photograph:
   this panel cannot know what it will be given, and white text on a pale
   upload is a contrast failure waiting for the day somebody makes one. */
.promo__veil {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(94deg,
    rgba(5, 6, 14, .95) 0%, rgba(5, 6, 14, .82) 34%, rgba(5, 6, 14, .18) 68%,
    rgba(5, 6, 14, .05) 100%);
}
.promo.is-empty {
  background-color: var(--panel);
  background-image:
    radial-gradient(70% 140% at 85% 20%, rgba(47, 228, 255, .3), transparent 62%),
    linear-gradient(110deg, var(--panel-2), rgba(138, 77, 255, .35));
}
.promo__copy {
  position: relative; z-index: 2; max-width: 34ch;
  padding: clamp(20px, 3vw, 38px) clamp(18px, 3vw, 42px);
}
.promo__h { font-size: clamp(26px, 3.4vw, 44px); font-weight: 900; font-stretch: 106%;
            line-height: .96; letter-spacing: -.03em; text-transform: uppercase; }
.promo__h span { display: block; }
.promo__h .is-accent { color: var(--cyan); }
.promo__text { margin-top: 10px; color: var(--ash); font-size: 13.5px; line-height: 1.5; }
.promo__go { margin-top: clamp(14px, 1.8vw, 20px); }

/* ==========================================================================
   PAIR — two panels
   -------------------------------------------------------------------------- */
.pair {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--gap); list-style: none;
}
@media (max-width: 760px) { .pair { grid-template-columns: minmax(0, 1fr); } }

.duo {
  position: relative; overflow: hidden; isolation: isolate; min-width: 0;
  min-height: clamp(160px, 18vw, 210px);
  display: grid; align-items: center;
  border: 1px solid var(--hairline-lo); border-radius: 18px;
}
.duo__art {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
}
.duo__veil {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(96deg,
    rgba(5, 6, 14, .94) 0%, rgba(5, 6, 14, .78) 42%, rgba(5, 6, 14, .22) 100%);
}
.duo.is-empty {
  background-color: var(--panel);
  background-image:
    radial-gradient(80% 130% at 80% 10%, rgba(255, 61, 158, .34), transparent 62%),
    linear-gradient(120deg, var(--panel-2), rgba(138, 77, 255, .3));
}
.duo__copy {
  position: relative; z-index: 2; display: grid; gap: 7px; max-width: 32ch;
  padding: clamp(18px, 2.4vw, 30px);
}

/* WORDS ON THE RIGHT, picture clear on the left.
   justify-self rather than a second grid definition: the panel is a one-cell
   grid, so moving the copy within it is one property, and the veil only has
   to be mirrored to follow. */
.duo.is-flip .duo__copy {
  justify-self: end; text-align: right;
  /* A CLEARANCE FLOOR, not a width. Just above the stacking breakpoint the two
     panels are at their narrowest while still side by side, and 32ch of copy
     is wider than half of that -- it measured 69% of the panel covered at
     900px, which gives the artwork less room than before the flip. min()
     keeps 32ch wherever it fits and otherwise guarantees the left 38% stays
     clear, which is the whole point of flipping. */
  max-width: min(32ch, 62%);
}
.duo.is-flip .duo__veil {
  background: linear-gradient(264deg,
    rgba(5, 6, 14, .94) 0%, rgba(5, 6, 14, .78) 42%, rgba(5, 6, 14, .22) 100%);
}
/* The button is a grid item in that column, so it needs telling too --
   text-align does not move it. */
.duo.is-flip .duo__go { justify-self: end; }
/* Stacked, there is no "beside" to clear, and right-aligned copy over a
   full-width picture just reads as a mistake. */
@media (max-width: 760px) {
  .duo.is-flip .duo__copy { justify-self: start; text-align: left; }
  .duo.is-flip .duo__go { justify-self: start; }
  .duo.is-flip .duo__veil {
    background: linear-gradient(96deg,
      rgba(5, 6, 14, .94) 0%, rgba(5, 6, 14, .78) 42%, rgba(5, 6, 14, .22) 100%);
  }
}
.duo__eyebrow {
  color: var(--cyan); font-size: 10.5px; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase;
}
.duo__h { font-size: clamp(19px, 2.1vw, 28px); font-weight: 900;
          line-height: 1.04; letter-spacing: -.02em; }
.duo__h span { display: inline; }
.duo__h .is-accent { color: var(--cyan); }
.duo__text { color: var(--ash); font-size: 12.5px; line-height: 1.5; }
.duo__go { margin-top: 5px; }

/* ==========================================================================
   FIND — search, and a few ready-made searches
   -------------------------------------------------------------------------- */
.find {
  position: relative; overflow: hidden; isolation: isolate;
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: clamp(16px, 2.4vw, 34px); align-items: center;
  padding: clamp(18px, 2.6vw, 32px);
  border: 1px solid var(--hairline-lo); border-radius: 18px;
}
/* The gradient is the EMPTY state, not the panel's background. On the panel it
   would sit over the picture -- the same stacking-context trap the limited
   editions banner fell into. */
.find.is-empty {
  background-color: var(--panel);
  background-image:
    radial-gradient(90% 180% at 100% 50%, rgba(138, 77, 255, .22), transparent 62%);
}
.find__art {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
}
/* The picture shows through the MIDDLE, not the right-hand end.
   A veil that simply clears left-to-right puts its thinnest point exactly
   where the popular-search chips sit, and those chips are inert -- opacity .5
   takes their own dark pill down to about .35 alpha. Over a bright photograph
   that measured 3.8:1 across the chip strip, which is a washed-out smear.
   So the clear window sits at 62%: the gap between the copy and the chips,
   which is empty on every width. The picture is still plainly visible there,
   and both ends have a floor to read against. */
.find__veil {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(95deg,
    rgba(5, 6, 14, .95) 0%, rgba(5, 6, 14, .88) 34%, rgba(5, 6, 14, .44) 62%,
    rgba(5, 6, 14, .74) 84%, rgba(5, 6, 14, .80) 100%);
}
/* Stacked at narrow widths, so there is no left-and-right to grade between --
   one even floor instead, or the chips fall under the clear window again. */
@media (max-width: 760px) {
  .find__veil { background: rgba(5, 6, 14, .86); }
}
.find__copy, .find__pop { position: relative; z-index: 2; }
@media (max-width: 760px) { .find { grid-template-columns: minmax(0, 1fr); } }

.find__copy { display: grid; gap: clamp(12px, 1.6vw, 18px); min-width: 0; }
.find__h { font-size: clamp(20px, 2.4vw, 32px); font-weight: 900;
           line-height: 1.02; letter-spacing: -.025em; }
.find__h span { display: inline; }
.find__h .is-accent { color: var(--cyan); }

.find__form { display: flex; gap: 8px; min-width: 0; }
.find__field { flex: 1 1 auto; min-width: 0; }
.find__in {
  width: 100%; padding: 11px 14px;
  border: 1px solid var(--hairline); border-radius: 999px;
  background: rgba(5, 6, 14, .66); color: var(--ice);
  font: inherit; font-size: 13.5px;
}
.find__in::placeholder { color: var(--ash-dim); }
.find__in:focus { outline: 2px solid var(--cyan); outline-offset: 1px; border-color: transparent; }
.find__btn {
  flex: 0 0 auto; display: grid; place-items: center;
  width: 42px; height: 42px; border-radius: 999px;
  border: 1px solid var(--hairline); background: rgba(47, 228, 255, .12);
  color: var(--ice); cursor: pointer;
}
.find__btn:hover { background: rgba(47, 228, 255, .24); border-color: var(--cyan); }
.find__btn:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.find__soon { color: var(--ash); font-size: 13px; line-height: 1.55; }
.find__soon a { color: var(--cyan-2); }

.find__pop { display: grid; gap: 9px; min-width: 0; justify-items: start; }
@media (min-width: 761px) { .find__pop { justify-items: end; } }
.find__poplab {
  color: var(--ash-dim); font-size: 10.5px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
}
.find__chips { display: flex; flex-wrap: wrap; gap: 7px; list-style: none; }
@media (min-width: 761px) { .find__chips { justify-content: end; } }

/* A WORD PILL, which .chip in sas.css is not -- that one is a 34px round icon
   button, and six words dropped into six of them stacked into an unreadable
   smear. Same shape as the filter chips above so the page has one pill. */
.chipt {
  display: inline-block; padding: 6px 13px;
  border: 1px solid var(--hairline-lo); border-radius: 999px;
  background: rgba(10, 13, 26, .7); color: var(--ash);
  font-size: 11.5px; font-weight: 600; line-height: 1.5;
  text-decoration: none; white-space: nowrap;
  transition: border-color .18s var(--ease), color .18s var(--ease);
}
.chipt:hover { border-color: var(--cyan); color: var(--ice); text-decoration: none; }
.chipt:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
/* Nowhere to go yet, said the way every other unbuilt link here says it. */
.chipt[aria-disabled="true"] { opacity: .5; cursor: default; }
.chipt[aria-disabled="true"]:hover { border-color: var(--hairline-lo); color: var(--ash); }
