/* Soul Creations By Kay - the shop window.
   One stylesheet, no build step, no framework.

   The palette is Kay's, sampled from her lotus logo on 28 Sept 2026: the deep
   purple of the "Soul Creations" lettering (#401070), the lotus petals
   (#683090), the gold of the linework (#b07810) and the pale pink of the disc
   (#fdf3f1). The typeface is still Open Sans, kept from Soulful Angels. */

/* Self-hosted rather than pulled from Google. One less third party in the
   page, nothing to explain in the phase 03 privacy policy, and one less thing
   between a customer and the shop loading. Open Sans is Apache 2.0. */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('brand/font/open-sans.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* The heading faces, self-hosted the same way and for the same reasons
   (29 Sept 2026). Both are SIL Open Font License 1.1, latin subset, from
   Google Fonts. Cinzel is one variable file covering 500 and 600. */
@font-face {
  font-family: 'Cinzel';
  font-style: normal;
  font-weight: 500 600;
  font-display: swap;
  src: url('brand/font/cinzel.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Cormorant Garamond';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('brand/font/cormorant-garamond.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 500;
  font-display: swap;
  src: url('brand/font/cormorant-garamond-italic.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --ink: #211834;
  --muted: #6a5f78;
  --line: #ece4ee;
  --bg: #ffffff;
  --card: #ffffff;
  --accent: #401070;
  --accent-mid: #683090;
  --accent-soft: #f4edf8;
  --gold: #b07810;
  --gold-soft: #d9b86a;
  --cream: #f3e3c3;
  --cream-soft: #fdf3f1;
  --gone: #a39bab;
  --radius: 14px;
  /* Engraved capitals for headings, an italic serif for sub-lines, Open Sans
     for everything read at length. All three are self-hosted, above. */
  --display: 'Cinzel', 'Trajan Pro', Georgia, serif;
  --serif: 'Cormorant Garamond', Georgia, serif;
  --shadow: 0 1px 2px rgba(33, 24, 52, 0.05), 0 8px 22px rgba(33, 24, 52, 0.07);
}

* { box-sizing: border-box; }

/* `hidden` has to mean hidden. The browser's own `[hidden] { display: none }`
   lives in the user-agent sheet, so ANY author `display` declaration beats it -
   specificity never comes into it, because the two rules are not in the same
   cascade origin. Every element this site shows and hides from JavaScript sits
   in a class that sets `display` (`.crumb` flex, `.grid` and `.item` grid,
   `.chips` flex), so without this line `el.hidden = true` sets an attribute and
   changes nothing on screen: the box stays in the flow with its padding and its
   margins, and the page keeps a hole where the thing used to be.

   `!important` rather than a longer selector on purpose. The point is that this
   holds for markup nobody has written yet - a per-class escape hatch has to be
   remembered once per element, and it was already forgotten three times. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.6 'Open Sans', system-ui, -apple-system, "Segoe UI", sans-serif;
  -webkit-text-size-adjust: 100%;
}

.wrap {
  /* 1280 with 20px either side: the masthead, the banner and every page's
     content share one edge. */
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 20px;
}

/* ---- the masthead ---- */
/*
   29 Sept 2026, in the manner of a high-street jeweller's site: a thin purple
   announcement bar, then the shop's name centred with page links to its left
   and a search box to its right, then a row of categories in engraved
   capitals. Sticky, so the search and the categories are always to hand.
*/

.announce {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 14px;
  padding: 7px 16px;
  background: var(--accent);
  color: #fff;
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.announce a { color: var(--gold-soft); text-underline-offset: 3px; }
.announce-dot { color: var(--gold-soft); }

/* Jumps to a section (#whats-on) stop below the sticky header. --head-h is
 measured by trackHeadHeight() in shop.js; the fallback covers the moment before
 it runs. */
html { scroll-padding-top: calc(var(--head-h, 130px) + 16px); }

.site-head {
  position: sticky;
  top: env(safe-area-inset-top, 0px);
  z-index: 30;
  background: var(--card);
  border-bottom: 1px solid var(--line);
}

.head-inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
  max-width: 1280px;
  margin: 0 auto;
  padding: 12px 20px;
}

.head-tabs { display: flex; gap: 4px; }
.head-tabs a {
  padding: 6px 10px;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--muted);
  border-bottom: 2px solid transparent;
}
.head-tabs a:hover { color: var(--accent); border-color: var(--gold); }

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  justify-self: center;
  text-decoration: none;
}
.brand img { display: block; width: 58px; height: 58px; border-radius: 50%; }
.brand-text { display: flex; flex-direction: column; line-height: 1; }
.brand-name {
  font-family: var(--display);
  font-weight: 600;
  font-size: 1.7rem;
  letter-spacing: 0.08em;
  color: var(--accent);
  white-space: nowrap;
}
.brand-by {
  margin-top: 4px;
  text-align: center;
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.15rem;
  color: var(--gold);
}

.head-search {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 8px;
  width: min(280px, 100%);
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-mid);
}
.head-search input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 0.88rem;
  color: var(--ink);
  outline: none;
}
.head-search:focus-within { box-shadow: 0 0 0 2px var(--accent-mid); }

.head-icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--accent);
  cursor: pointer;
}
.head-icon:hover { background: var(--accent-soft); }

/* The menu button only exists on small screens. Both icons live in it and
   aria-expanded decides which one shows. */
.head-menu { display: none; }
.head-menu .ico-close { display: none; }
.head-menu[aria-expanded="true"] .ico-open { display: none; }
.head-menu[aria-expanded="true"] .ico-close { display: block; }

/* ---- the category row ---- */

.mainnav { border-top: 1px solid var(--line); }

.navlist {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 18px;
  margin: 0;
  padding: 4px 20px;
  list-style: none;
}

.navlist a {
  display: block;
  padding: 8px 4px;
  font-family: var(--display);
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.3;
  white-space: nowrap;
  text-decoration: none;
  color: var(--ink);
  border-bottom: 1px solid transparent;
}
.navlist a:hover { color: var(--accent); border-color: var(--gold); }
.navlist a.here { color: var(--accent); border-color: var(--accent); }

/* Home, About, Find Us and Contact are in the masthead's tabs on a wide
   screen, so the category row carries only categories. They come back in the
   phone menu, where the tabs are hidden. */
.navlist li.nav-page { display: none; }

/* ---- sub-folders in the nav ---- */
/*
   A category with sub-folders (Jewellery -> Bracelets, Earrings, ...) grows a
   drop-down. On a wide screen it opens on hover OR keyboard focus; below 780px
   a TAP on the category opens it instead (buildNav does that).
*/
.navlist li { position: relative; }

.nav-caret {
  font-size: 0.6em;
  margin-left: 4px;
  vertical-align: middle;
  opacity: 0.65;
}

.subnav {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 40;
  min-width: 200px;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow);
}

.navlist li.has-sub:hover > .subnav,
.navlist li.has-sub:focus-within > .subnav { display: block; }

.subnav a {
  padding: 8px 12px;
  border: 0;
  border-radius: 6px;
  font-family: inherit;
  font-size: 0.9rem;
  letter-spacing: 0;
  text-transform: none;
}
.subnav a:hover,
.subnav a:focus-visible { background: var(--accent-soft); color: var(--accent); }

/* "All Jewellery" belongs to the narrow layout only. */
.subnav-all { display: none; }

@media (max-width: 1100px) {
  .brand-name { font-size: 1.4rem; }
  .head-tabs a { padding: 6px 6px; }
}

/*
   The small-screen masthead: the menu button on the left, the name in the
   middle, the search box on its own row beneath. The menu opens as a
   full-width list with every page and category, one per row.
*/
@media (max-width: 780px) {
  .announce-extra { display: none; }

  .head-inner {
    grid-template-columns: auto 1fr auto;
    gap: 8px 10px;
    padding: 10px 16px;
  }
  .head-tabs { display: none; }
  .head-menu { display: grid; }
  .brand { justify-self: center; }
  .brand img { width: 44px; height: 44px; }
  .brand-name { font-size: 1.1rem; }
  .brand-by { font-size: 0.95rem; }
  .head-search {
    grid-column: 1 / -1;
    grid-row: 2;
    width: 100%;
    justify-self: stretch;
  }

  .mainnav { display: none; }
  .mainnav.open { display: block; }

  .navlist {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0;
  }
  .navlist li.nav-page { display: block; }
  .navlist a {
    padding: 15px 18px;
    border-bottom: 1px solid var(--line);
  }

  .subnav-all { display: block; }

  .nav-caret {
    display: inline-block;
    float: right;
    font-size: 0.85em;
    opacity: 0.8;
  }
  .navlist li.has-sub.open > a .nav-caret { transform: rotate(180deg); }

  /* Tapping also focuses, and the desktop :focus-within rule would hold the
     drop-down open against the tap trying to close it. */
  .navlist li.has-sub:hover > .subnav,
  .navlist li.has-sub:focus-within > .subnav { display: none; }

  .subnav {
    display: none;
    position: static;
    min-width: 0;
    padding: 0;
    border: none;
    border-radius: 0;
    box-shadow: none;
    background: var(--accent-soft);
  }
  .navlist li.has-sub.open > .subnav { display: block; }
  .subnav a {
    padding: 13px 18px 13px 38px;
    border-radius: 0;
    color: var(--muted);
    border-bottom: 1px solid var(--line);
  }
}

/* ---- the banner ---- */
/*
   Kay's crystal lotus in a rounded frame, the words on the left over a purple
   fade. The lotus sits right of centre, so the picture crops at 68% across.
   On a phone the words move to the bottom and the fade turns to follow them.
*/

.hero {
  position: relative;
  display: grid;
  align-items: center;
  width: calc(100% - 40px);
  max-width: 1240px;
  min-height: 420px;
  margin: 18px auto 0;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--accent);
}

.hero img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 68% 50%;
}

.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(90deg, rgba(40, 8, 70, 0.8) 0%, rgba(40, 8, 70, 0.45) 45%, rgba(40, 8, 70, 0) 75%);
}

.hero-text {
  position: relative;
  z-index: 1;
  max-width: 540px;
  padding: 40px 48px;
  color: #fff;
}

.hero-text h1 {
  margin: 0 0 12px;
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(2rem, 4.4vw, 3.3rem);
  line-height: 1.12;
  letter-spacing: 0.02em;
  text-wrap: balance;
}

.hero-lead {
  margin: 0 0 24px;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.15rem, 2vw, 1.4rem);
  line-height: 1.4;
}

.btn-pill {
  display: inline-block;
  padding: 11px 24px;
  border-radius: 999px;
  background: #fff;
  color: var(--accent);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
}
.btn-pill:hover { background: var(--gold-soft); }

@media (max-width: 780px) {
  .hero { width: calc(100% - 32px); min-height: 460px; align-items: end; }
  .hero::after { background: linear-gradient(180deg, rgba(40, 8, 70, 0) 30%, rgba(40, 8, 70, 0.85) 80%); }
  .hero-text { padding: 28px 22px; }
}

/* ---- controls ---- */

.controls { padding: 20px 0 4px; }

.search {
  width: 100%;
  padding: 12px 16px;
  font: inherit;
  color: inherit;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.search:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: transparent;
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
}

.chip {
  font: inherit;
  font-size: 0.88rem;
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--muted);
  cursor: pointer;
}

.chip:hover { border-color: var(--accent-mid); color: var(--accent); }

.chip[aria-pressed="true"] {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}

.count {
  margin: 18px 0 0;
  color: var(--muted);
  font-size: 0.88rem;
}

/* A second row of chips, for a filter that is not a category. The categories
   are one-of-many and this narrows whichever of them is showing, so it sits on
   its own line rather than joining a row where every other chip turns the last
   one off.

   Hiding this row used to need a `.filters[hidden]` rule of its own, because
   `.chips` sets `display:flex`. That is now the global `[hidden]` rule at the
   top of this file, which covers every element on the site rather than the one
   that happened to be noticed. */
.filters { margin-top: 10px; }

/* The sub-folder row, one level below the categories and drawn only while a
   category that has sub-folders is showing.

   It has to read as narrowing what is already chosen rather than as a second
   set of categories competing with the first, and on a phone the two rows are
   one continuous block of pills unless they are told apart. So: a size down,
   the cream ground instead of white, and a wider gap above than the row below
   it gets - the space says which row this one belongs to. */
.subchips {
  margin-top: 16px;
  gap: 6px;
}

.subchips .chip {
  font-size: 0.82rem;
  padding: 5px 12px;
  background: var(--cream-soft);
  border-color: transparent;
}

.subchips .chip:hover { border-color: var(--accent-mid); }

.subchips .chip[aria-pressed="true"] {
  background: var(--accent-soft);
  border-color: var(--accent);
}

/* ---- the grid ---- */

.grid {
  display: grid;
  /* Two columns on a phone. A single 335px card per row turns a shop of 477
     things into an awful lot of scrolling, and a browsing grid is what people
     expect. Wider screens fill by card width instead. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  padding: 18px 0 48px;
  margin: 0;
  list-style: none;
}

@media (min-width: 560px) {
  .grid {
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 22px;
  }
}

.card {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.card a {
  color: inherit;
  text-decoration: none;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.card a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/*
   The square is for the GRID: cards of one height, in tidy rows, however tall
   or wide the photographs behind them are.

   `contain`, not `cover`, and that is the whole point of this rule. `cover`
   fills the square by throwing the overflow away, and of the 403 pictures in
   img/ only 293 are actually square - so a portrait photo taken on the till
   lost an eighth off the top and an eighth off the bottom, and KA-003, which
   is 140x400, was showing about a third of itself. Nobody spots it, because
   the picture that comes back still looks like a photograph of something.

   So the box stays square and the picture sits inside it whole, with a band
   of --accent-soft above and below where it does not reach. That background
   is not decoration: without it the band is transparent and the card shows
   through.
*/
.shot {
  aspect-ratio: 1 / 1;
  background: var(--accent-soft);
  display: block;
  width: 100%;
  object-fit: contain;
}

.shot--none {
  display: grid;
  place-items: center;
  color: var(--gone);
  font-size: 0.82rem;
}

.card-body {
  padding: 14px 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
}

.card h2 {
  margin: 0;
  font-size: 0.98rem;
  font-weight: 500;
  line-height: 1.35;
}

.price {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  margin-top: auto;
  padding-top: 6px;
}

.soldout .shot { opacity: 0.45; }
.soldout h2, .soldout .price { color: var(--gone); }

.flag {
  align-self: flex-start;
  background: var(--cream-soft);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--gone);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 1px 9px;
}

/* ---- one item ---- */

.item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 40px;
  padding: 32px 0 56px;
  align-items: start;
}

@media (max-width: 700px) {
  .item { grid-template-columns: 1fr; gap: 24px; }
}

/* On the one page where a customer is deciding whether to buy the thing, the
   whole of it has to be visible - so this inherits `contain` above and the
   square becomes a mount around the picture rather than a crop of it. */
.item .shot {
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

/* The thumbnail rail under a product photograph. It is only built when an item
   has more than one published picture, so most products never draw it at all.
   Buttons rather than links: this swaps the picture above, it does not go
   anywhere, and a screen reader should be told which of the two it is. */
.gallery {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}

.thumb {
  width: 62px;
  height: 62px;
  padding: 0;
  overflow: hidden;
  line-height: 0;
  cursor: pointer;
  border: 2px solid var(--line);
  border-radius: 8px;
  background: var(--accent-soft);
}

/* Same reason as .shot, and it is the same decision: a product is shown whole.
   A tall photograph sits on the soft band rather than being cropped square,
   so the thumbnail matches the picture it opens. Do not "tidy" this to cover
   - tests/gallery.js guards it, the way tests/photo-fit.js guards .shot. */
.thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.thumb[aria-current="true"] { border-color: var(--accent); }
.thumb:hover { border-color: var(--accent-mid); }
.thumb:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.item h1 {
  margin: 0 0 6px;
  font-family: var(--display);
  font-size: clamp(1.4rem, 3vw, 1.9rem);
  font-weight: 500;
  line-height: 1.25;
  color: var(--accent);
}

.item .price { font-size: 1.3rem; padding-top: 0; }

/* The description is built as real paragraphs and lists by descNode() in
   shop.js. A single line break inside a paragraph is deliberate wording, so
   pre-line keeps it; a blank line is what separates one block from the next. */
.item .desc p {
  white-space: pre-line;
  margin: 0 0 12px;
}

.item .desc ul {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
}

/* Hanging indent: the marker sits in the gutter and wrapped text lines up
   under the first word rather than running back to the margin. */
.item .desc li {
  position: relative;
  padding-left: 1.15em;
  margin-bottom: 5px;
}

.item .desc li::before {
  content: '•';
  position: absolute;
  left: 0;
  top: 0;
  color: var(--accent-mid);
}

.item .desc > :last-child { margin-bottom: 0; }

.avail {
  display: inline-block;
  font-size: 0.85rem;
  border-radius: 999px;
  padding: 4px 12px;
  margin: 10px 0;
}

.avail--yes { background: #e7f0e9; color: #2f6046; }
.avail--no { background: var(--cream-soft); color: #7d6a55; }

.back {
  display: inline-block;
  margin: 22px 0 0;
  color: var(--accent);
  text-decoration: none;
  font-size: 0.92rem;
}

.back:hover { text-decoration: underline; }

.visit {
  margin: 22px 0 0;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  color: var(--muted);
  font-size: 0.92rem;
}

/* ---- choosing between variants ---- */
/*
   Most products in this shop came off SumUp as several items sharing a name -
   a colour, a stone, a scent each. The list folds them into one card and the
   item page offers the choice here.

   A real <select> rather than a row of pills: it is a form control doing a form
   control's job, it is reachable from the keyboard with no work, and on a phone
   it opens the native list instead of wrapping a dozen buttons over four lines.
*/

.picker {
  margin: 16px 0 4px;
  display: grid;
  gap: 6px;
}

.picker label {
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

.variant {
  font: inherit;
  font-size: 0.95rem;
  width: 100%;
  max-width: 26rem;
  padding: 10px 12px;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.variant:focus {
  outline: none;
  border-color: var(--accent-mid);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Two things sold together for less. Said in the shop's own words rather than
   as a discount badge - it is a kindness, not a promotion. */
.set-note {
  margin: 12px 0 0;
  padding: 9px 13px;
  background: var(--cream-soft);
  border-radius: 8px;
  color: #7d6a55;
  font-size: 0.9rem;
}

/* On a card in the list: how many there are to choose between. Quiet, because
   the name and the price are what a customer is scanning for. */
/* A mix-and-match offer, on every card in it. Reads as a fact about the item
   rather than a shout: the shop window is not a discount site, and the price
   above it is still the price of this one thing on its own. */
/* The offer on a product page. Says more than the card badge does, because
   this is where somebody decides whether to go and find the second thing. */
.deal-note {
  margin: 12px 0 0;
  padding: 11px 14px;
  border-left: 3px solid var(--accent-mid);
  background: var(--accent-soft);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: 15px;
  line-height: 1.55;
}

.deal-flag {
  display: inline-block;
  margin: 6px 0 0;
  padding: 3px 9px;
  border: 1px solid var(--accent-mid);
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 12px;
  font-weight: 700;
  line-height: 1.5;
}

.card-opts {
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 0.8rem;
}

/* ---- states ---- */

.status {
  padding: 48px 20px;
  text-align: center;
  color: var(--muted);
}

.status.error { color: #8a3a3a; }

/* ---- footer ---- */

.site-foot {
  margin-top: 56px;
  padding-top: 40px;
  background: var(--cream-soft);
  color: var(--muted);
  font-size: 0.88rem;
}

/* The front page ends on the lavender strip, which already makes the break. */
.promise + .site-foot,
main:has(> .promise:last-child) + .site-foot { margin-top: 0; }

.foot-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
  gap: 24px;
}

.foot-h {
  margin: 0 0 10px;
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}

.foot-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.foot-list a { color: var(--muted); text-decoration: none; overflow-wrap: anywhere; }
.foot-list a:hover { color: var(--accent); text-decoration: underline; }

.foot-brand { text-align: center; }
.foot-brand img { border-radius: 50%; }
.foot-brand p {
  margin: 6px 0 0;
  font-family: var(--display);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  color: var(--accent);
}

.foot-base {
  margin-top: 30px;
  padding: 14px 20px 20px;
  border-top: 1px solid var(--line);
  text-align: center;
  font-size: 0.8rem;
}
.foot-base p { margin: 4px 0; }

@media (max-width: 1000px) {
  .foot-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .foot-brand { grid-column: 1 / -1; }
}

#version { font-variant-numeric: tabular-nums; opacity: 0.7; }

/* Visible to a screen reader, not to the eye. The search box has a placeholder
   but a placeholder is not a label. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.more-row { text-align: center; padding: 0 0 52px; margin: 0; }

.more {
  font: inherit;
  font-size: 0.92rem;
  padding: 10px 24px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--accent);
  cursor: pointer;
  box-shadow: var(--shadow);
}

.more:hover { border-color: var(--accent); }


/* ---- the front page ---- */

/* Category tiles, one per category, each a product photograph from the till
   with the name in engraved capitals over a purple fade. Until the photograph
   arrives - or if it never does - a tile is a plain purple square. */
.tiles { padding-top: 18px; }

.tile-row {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 12px;
}

.tile {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius);
  text-decoration: none;
  background: var(--accent-mid);
}

.tile .feature-shot {
  aspect-ratio: 3 / 4;
  background: linear-gradient(160deg, var(--accent-mid), var(--accent));
}

.tile .feature-shot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.4s ease;
}
.tile:hover .feature-shot img { transform: scale(1.05); }

.tile::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(40, 8, 70, 0) 45%, rgba(40, 8, 70, 0.85) 100%);
}

.tile-label {
  position: absolute;
  z-index: 1;
  left: 8px;
  right: 8px;
  bottom: 14px;
  text-align: center;
  font-family: var(--display);
  font-size: 0.9rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #fff;
  text-wrap: balance;
}

/* Our story beside Where to find us. */
.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  padding-top: 18px;
}

.panel {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 36px 40px;
  border-radius: var(--radius);
}

.panel h2 {
  margin: 0;
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(1.4rem, 2.4vw, 1.9rem);
  line-height: 1.2;
}

.panel p { margin: 0; }

.eyebrow {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
}

.panel-story {
  color: #fff;
  text-decoration: none;
  background: var(--accent) radial-gradient(circle at 90% 20%, rgba(217, 184, 106, 0.22), transparent 45%);
}
.panel-story .eyebrow,
.panel-story .link-arrow { color: var(--gold-soft); }
.panel-story p { color: rgba(255, 255, 255, 0.9); }

.panel-find { background: var(--cream-soft); }
.panel-find h2 { color: var(--accent); }

.link-arrow {
  margin-top: 6px;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--gold);
}
.link-arrow::after { content: ' \2192'; }

/* Handpicked: a row that scrolls sideways, five across on a wide screen. */
.picks { padding-top: 44px; }

.section-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 16px;
}
.section-head h2 {
  margin: 0;
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(1.4rem, 2.6vw, 2rem);
  color: var(--accent);
}

.pick-row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - 4 * 14px) / 5);
  gap: 14px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 10px;
  scrollbar-width: thin;
}

.pick {
  display: flex;
  flex-direction: column;
  gap: 4px;
  scroll-snap-align: start;
  text-decoration: none;
  color: var(--ink);
}
.pick img {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  margin-bottom: 6px;
  border-radius: 10px;
  background: var(--accent-soft);
}
.pick-name { font-size: 0.9rem; line-height: 1.35; }
.pick-price { font-weight: 600; color: var(--accent); }
.pick:hover .pick-name { color: var(--accent-mid); text-decoration: underline; }

/* The four-point strip. */
.promise {
  margin-top: 44px;
  background: var(--accent-soft);
  border-block: 1px solid var(--line);
}
.promise-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px;
  padding-block: 30px;
  text-align: center;
}
.promise-ic { font-size: 1.4rem; color: var(--gold); }
.promise-item h3 {
  margin: 6px 0 4px;
  font-family: var(--display);
  font-weight: 500;
  font-size: 0.95rem;
  letter-spacing: 0.06em;
  color: var(--accent);
}
.promise-item p { margin: 0; color: var(--muted); font-size: 0.88rem; overflow-wrap: anywhere; }
.promise-item a { color: inherit; }

@media (max-width: 1000px) {
  .tile-row {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 38%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
  }
  .tile { scroll-snap-align: start; }
  .pick-row { grid-auto-columns: 42%; }
  .promise-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 780px) {
  .split { grid-template-columns: 1fr; }
  .panel { padding: 28px 24px; }
  .tile-row { grid-auto-columns: 44%; }
  .pick-row { grid-auto-columns: 62%; }
  .promise-row { gap: 18px 12px; }
}

@media (prefers-reduced-motion: reduce) {
  .tile .feature-shot img { transition: none; }
}

/* ---- buttons shared by the other pages ---- */

.feature-link {
  display: inline-block;
  margin-top: 6px;
  padding: 11px 26px;
  border: 1px solid var(--accent);
  border-radius: 999px;
  color: var(--accent);
  text-decoration: none;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.feature-link:hover { background: var(--accent); color: #fff; }

.feature-note {
  margin: 6px 0 0;
  font-style: italic;
  color: var(--gone);
  font-size: 0.92rem;
}

/* ---- what's on ---- */
/*
   The diary. Kept inside the page's existing language on purpose - the same
   Open Sans, the same accent, the same pill button as the section rows - so a
   list of dates does not read as a widget bolted on from somewhere else.

   A list rather than a card grid: there are a handful of these, they have a
   natural order, and a date wants to be read down a column.
*/

.whatson-intro {
  margin: 0;
  max-width: 46rem;
  color: var(--muted);
  line-height: 1.7;
}

.events {
  list-style: none;
  margin: 26px 0 0;
  padding: 0;
  display: grid;
  gap: 14px;
}

.event {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 22px;
  align-items: center;
  padding: 16px 20px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

/* The date block. Cream rather than blue so the page keeps one accent colour
   and the button stays the thing that looks pressable. */
.event-when {
  display: grid;
  place-items: center;
  min-width: 82px;
  padding: 10px 12px;
  background: var(--cream-soft);
  border-radius: 8px;
}

.event-when time { display: block; text-align: center; }

.event-wd,
.event-mon {
  display: block;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--muted);
}

.event-day {
  display: block;
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--accent);
}

.event-kind {
  margin: 0 0 3px;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--accent-mid);
}

.event-what h3 {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1.35;
}

.event-meta {
  margin: 5px 0 0;
  color: var(--muted);
  font-size: 0.92rem;
}

.event-act .feature-link { margin-top: 0; white-space: nowrap; }

.event-ask {
  margin: 0;
  font-style: italic;
  color: var(--gone);
  font-size: 0.92rem;
  white-space: nowrap;
}

.whatson-none {
  margin: 22px 0 0;
  color: var(--muted);
  font-size: 0.98rem;
}

/* On a phone the button drops to its own row rather than squeezing the title
   into a column two words wide. */
@media (max-width: 640px) {
  .event {
    grid-template-columns: auto minmax(0, 1fr);
    gap: 6px 16px;
    padding: 14px 16px;
  }
  .event-act {
    grid-column: 1 / -1;
    margin-top: 8px;
  }
  .event-act .feature-link { display: block; text-align: center; }
}

/* Inside the front page's "Where to find us" panel, which is half the page
   wide on a computer: the button or "Just come along" goes UNDER the stall's
   details rather than beside them, so a long fair name keeps its width and
   every row lines up the same whether it has a link or not. The date block
   runs down the left of both lines. Stronger than the phone rule above, so
   the button stays a neat pill instead of stretching across the card. */
.panel-find .event {
  grid-template-columns: auto minmax(0, 1fr);
  gap: 6px 18px;
  align-items: start;
}
.panel-find .event-when { grid-row: span 2; }
.panel-find .event-act { grid-column: 2; margin-top: 2px; }
.panel-find .event-act .feature-link {
  display: inline-block;
  margin-top: 0;
  padding: 7px 16px;
  font-size: 0.72rem;
  text-align: left;
}
.panel-find .event-ask {
  color: var(--gold);
  font-size: 0.88rem;
}

/* The full-bleed "Wrapped in Angelic Light" band that sat between Crystals
   and Jewellery was Soulful Angels' and was removed on 28 Sept 2026. */

/* ---- closing ---- */

.closing {
  text-align: center;
  padding: 20px 20px 70px;
}

.closing p {
  margin: 0 0 16px;
  color: var(--muted);
}

a.more {
  display: inline-block;
  text-decoration: none;
  padding: 12px 30px;
  color: var(--accent);
}

/* ---- sorting ---- */

.count-row {
  margin-top: 14px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 16px;
}
.count-row .count { margin: 0; }

.sort {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}
.sort select {
  font: inherit;
  font-size: 0.9rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
  padding: 7px 30px 7px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  cursor: pointer;
}
.sort select:focus-visible { outline: 2px solid var(--accent-mid); outline-offset: 2px; }

/* ---- the shop page ---- */

/* Where you are, above the heading. Present only when something is filtered,
   so the whole-shop view looks exactly as it did before. */
.crumb {
  margin: 26px 0 0;
  font-size: 0.88rem;
  color: var(--muted);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 7px;
}

.crumb a { color: var(--accent-mid); text-decoration: none; }
.crumb a:hover { text-decoration: underline; }
.crumb .sep { color: var(--gone); }
.crumb .crumb-now { color: var(--ink); font-weight: 600; }

/* The same trail on a product page, inside the existing .count line. */
.trail-link { color: var(--accent-mid); text-decoration: none; }
.trail-link:hover { text-decoration: underline; }

/* The heading tucks up under the trail when there is one.

   This is not the [hidden] display trap wearing a different hat, and it does
   not go away now that rule exists: `display: none` does not stop an element
   matching a selector, so without the `:not()` guard the heading would tuck up
   under a trail that is not being drawn and lose 24px of the gap it wants on
   the whole-shop view. */
.crumb:not([hidden]) + .page-title { margin-top: 6px; }

.page-title {
  margin: 30px 0 0;
  font-family: var(--display);
  font-size: clamp(1.5rem, 3vw, 2.1rem);
  font-weight: 500;
  color: var(--accent);
}

/* ---- plain pages ---- */

.prose {
  max-width: 46rem;
  padding: 44px 20px 70px;
}

.prose h1 {
  margin: 0 0 20px;
  font-family: var(--display);
  font-size: clamp(1.7rem, 3.4vw, 2.4rem);
  font-weight: 500;
  color: var(--accent);
}

.prose p {
  margin: 0 0 18px;
  color: var(--muted);
  line-height: 1.75;
}

