/* Soulful Angels - the shop window.
   One stylesheet, no build step, no framework.

   The palette and the typeface are the shop's own, taken from the SumUp store
   at soulful-angels-oracleshop.sumupstore.com so the two front doors look like
   the same shop. Open Sans is what that store sets; the blues are sampled from
   the logo itself - the ring is #2e4867 at its darkest and #486c84 through the
   monogram - and the cream is the feather behind it. */

/* 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;
}

:root {
  --ink: #1c2530;
  --muted: #5f6b78;
  --line: #e3e7ec;
  --bg: #ffffff;
  --card: #ffffff;
  --accent: #2e4867;
  --accent-mid: #486c84;
  --accent-soft: #eef2f6;
  --cream: #e4d8cc;
  --cream-soft: #f7f2ec;
  --gone: #97a1ac;
  --radius: 10px;
  --shadow: 0 1px 2px rgba(28, 37, 48, 0.05), 0 8px 22px rgba(28, 37, 48, 0.06);
}

* { 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 {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 20px;
}

/* ---- header ---- */
/*
   The SumUp store's header, measured at 1265px wide rather than guessed:
   a 105px logo at x=33, the full shop name at 16px/700 beside it, the nav
   wrapping into two centred rows of 16px links, and the tools on the right.
   White, with a 1px rgba(0,0,0,.2) rule underneath.
*/

.site-head {
  background: var(--card);
  border-bottom: 1px solid rgba(0, 0, 0, 0.2);
}

.head-inner {
  display: flex;
  align-items: center;
  gap: 24px;
  max-width: 1265px;
  margin: 0 auto;
  padding: 21px 33px;
}

.head-logo {
  flex: 0 0 auto;
  display: block;
  line-height: 0;
}

.head-logo img {
  display: block;
  width: 105px;
  height: 105px;
  border-radius: 50%;
}

.head-mid {
  flex: 1 1 auto;
  min-width: 0;
  text-align: center;
}

.head-title {
  display: block;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.35;
  color: var(--ink);
  text-decoration: none;
}

.head-title:hover { color: var(--accent); }

.head-tools {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 4px;
}

.head-icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  color: var(--ink);
  border-radius: 50%;
}

.head-icon:hover { color: var(--accent); background: var(--accent-soft); }

/* ---- the nav ---- */

.mainnav { margin-top: 6px; }

.navlist {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  /* Tight enough that the first row carries the same nine links the store
     fits before it wraps: Home through Spiritual Gifts. */
  gap: 0 5px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.navlist a {
  display: block;
  padding: 5px 10px;
  color: var(--ink);
  text-decoration: none;
  font-size: 1rem;
  line-height: 1.3;
  white-space: nowrap;
}

.navlist a:hover { color: var(--accent); text-decoration: underline; }

/* The store puts the current page in bold. */
.navlist a.here { font-weight: 700; }

/* The menu button only exists on small screens. */
.head-menu { display: none; }

/* Both icons live in the button; aria-expanded decides which one shows, so
   the control cannot end up saying "open" while showing a close cross. */
.head-menu .ico-close { display: none; }
.head-menu[aria-expanded="true"] .ico-open { display: none; }
.head-menu[aria-expanded="true"] .ico-close { display: block; }

/* ---- sub-folders in the nav ---- */
/*
   A category with sub-folders (Jewellery -> Bracelets, Necklaces, ...) grows a
   drop-down. Only the categories that HAVE sub-folders get one; the rest of the
   nav is untouched, which is most of it.

   On a wide screen it opens on hover OR on keyboard focus - :focus-within is
   what makes it reachable by tab as well as by mouse. Below 780px the whole
   thing turns into an indented list that is simply always open, because a
   hover menu on a touch screen is a menu nobody can open.
*/
.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: var(--radius);
  box-shadow: var(--shadow);
}

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

.subnav a {
  padding: 7px 12px;
  border-radius: 6px;
  font-size: 0.94rem;
}

.subnav a:hover,
.subnav a:focus-visible {
  background: var(--accent-soft);
  color: var(--accent);
  text-decoration: none;
}

@media (max-width: 1100px) {
  .head-inner { gap: 16px; padding: 16px 20px; }
  .head-title { font-size: 0.92rem; }
  .navlist a { font-size: 0.92rem; padding: 4px 7px; }
}

/*
   The small-screen header, as the store has it: the menu on the LEFT, the logo
   centred, the tools on the right. Opening the menu swaps the button to a
   cross and drops a full-width list underneath, one item per row with a rule
   between - which is what that menu looks like on a phone.
*/
@media (max-width: 780px) {
  .head-inner {
    flex-wrap: wrap;
    padding: 10px 16px;
    gap: 8px;
  }

  .head-title { display: none; }
  .head-menu { display: grid; }

  /* Auto margins either side centre the logo between the button and the
     tools, and keep it centred whatever those two end up measuring. */
  .head-logo { margin: 0 auto; }
  .head-logo img { width: 88px; height: 88px; }

  /* The nav lives inside .head-mid, so it is .head-mid that has to break onto
     its own full-width row - telling the nav to do it only made it full width
     of its parent, which was 263px of a 375px screen. */
  .head-mid {
    flex: 1 0 100%;
    order: 4;
    text-align: left;
  }
  .head-tools { order: 2; }

  .mainnav {
    display: none;
    /* Full bleed: the rules between items run edge to edge, so they have to
       escape the padding on .head-inner. */
    margin: 8px -16px 0;
    border-top: 1px solid var(--line);
  }
  .mainnav.open { display: block; }

  .navlist {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }

  .navlist a {
    padding: 16px 18px;
    font-size: 1rem;
    border-bottom: 1px solid var(--line);
  }

  /* The store shows the page you are on in bold and underlined. */
  .navlist a.here {
    font-weight: 700;
    text-decoration: underline;
  }

  /* No hovering on a phone. The sub-folders are just there, indented under
     their category, inside the menu that is already open. */
  .nav-caret { display: none; }

  .subnav {
    display: block;
    position: static;
    min-width: 0;
    padding: 0;
    border: none;
    border-radius: 0;
    box-shadow: none;
    background: var(--accent-soft);
  }

  .subnav a {
    padding: 13px 18px 13px 38px;
    border-radius: 0;
    font-size: 0.95rem;
    color: var(--muted);
    border-bottom: 1px solid var(--line);
  }
}

/* ---- the banner ---- */
/*
   Built to match the hero on the SumUp store rather than approximate it: the
   picture behind, a flat black scrim at 40%, and white Open Sans 700 centred
   over the top with a soft shadow. Those numbers are read off that page, not
   chosen - bg-black at opacity .4, and text-shadow rgba(0,0,0,.6) 0 0 6px.
*/

.hero {
  position: relative;
  margin: 0;
  display: grid;
  place-items: center;
  min-height: 400px;
  overflow: hidden;
  background: #1c2530;
  border-bottom: 1px solid var(--line);
}

@media (min-width: 480px) { .hero { min-height: 480px; } }
@media (min-width: 1024px) { .hero { min-height: 530px; } }

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

/* The scrim. Without it the white text is unreadable wherever the photograph
   is pale, which on this picture is most of it. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  background: #000;
  opacity: 0.4;
  pointer-events: none;
}

.hero-text {
  position: relative;
  z-index: 1;
  padding: 40px 24px;
  max-width: 46rem;
  text-align: center;
  color: #fff;
  text-shadow: rgba(0, 0, 0, 0.6) 0 0 6px;
}

.hero-text h1,
.hero-text h2 {
  margin: 0;
  font-size: clamp(1.3rem, 3.6vw, 1.72rem);
  font-weight: 700;
  line-height: 1.35;
}

.hero-text h1 span,
.hero-text h2 span {
  display: block;
}

.hero-text h1 .gap,
.hero-text h2 .gap {
  height: 0.85em;
}

.hero-text p {
  margin: 18px 0 0;
  font-size: 1rem;
  line-height: 1.6;
}

.hero-text .blessing {
  margin-top: 14px;
  font-style: italic;
}

@media (max-width: 560px) {
  .hero-text { padding: 32px 20px; }
  .hero-text p { font-size: 0.94rem; }
}

/* ---- 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 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-size: clamp(1.4rem, 3vw, 1.9rem);
  font-weight: 600;
  line-height: 1.25;
}

.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. */
.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 ---- */

footer {
  border-top: 1px solid var(--line);
  background: var(--card);
  padding: 26px 0 34px;
  color: var(--muted);
  font-size: 0.85rem;
  text-align: center;
}

footer p { margin: 4px 0; }

#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); }


/* ---- feature rows ---- */
/*
   The store lays these out as a 1200px row: a 584px square picture beside the
   words, with a 40px bold heading.

   Which side each picture takes is set per section in the markup, by putting
   feature--flip on every other one. It is NOT computed here, because these
   sections are siblings of the full-bleed band and the What's On block, so an
   nth-child rule would count those too and quietly go out of step the first
   time anything was inserted.

   That leaves the pattern the markup's job to keep, so tests/frontpage.js
   checks it holds. Until 26 Aug 2026 the sides copied the store's own
   irregular order; they now run a strict zig-zag all the way down.
*/

.feature {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 56px;
  align-items: center;
  padding: 60px 20px;
}

.feature-shot { order: 2; }
.feature-text { order: 1; }

.feature--flip .feature-shot { order: 1; }
.feature--flip .feature-text { order: 2; }

.feature-shot img {
  display: block;
  width: 100%;
  /* height:auto is NOT optional. The width/height attributes on the tag - which
     are there to reserve space and stop the page jumping as pictures load -
     land as a presentational hint of height:720px, and that BEATS aspect-ratio.
     Without this every section picture rendered 335 wide by 720 tall on a
     phone and object-fit:cover sliced a narrow vertical strip out of it. */
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.feature-text h2 {
  margin: 0 0 18px;
  font-size: clamp(1.6rem, 3.4vw, 2.5rem);
  font-weight: 700;
  line-height: 1.2;
  color: var(--ink);
}

.feature-text p {
  margin: 0 0 16px;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.7;
}

.feature-text strong { color: var(--ink); }

.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.95rem;
}

.feature-link:hover { background: var(--accent); color: #fff; }

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

@media (max-width: 760px) {
  .feature {
    grid-template-columns: 1fr;
    gap: 22px;
    padding: 40px 20px;
  }
  /* Picture first on a phone, whichever side it takes on a wide screen. */
  .feature-shot, .feature--flip .feature-shot { order: 1; }
  .feature-text, .feature--flip .feature-text { order: 2; }
}

/* ---- 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 {
  padding: 48px 20px 8px;
}

.whatson h2 {
  margin: 0 0 10px;
  font-size: clamp(1.6rem, 3.4vw, 2.5rem);
  font-weight: 700;
  line-height: 1.2;
}

.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;
}

.whatson-also {
  margin: 18px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.94rem;
}

/* 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; }
}

/* ---- the full-bleed band ---- */

.band {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 340px;
  overflow: hidden;
  background: #1c2530;
}

@media (min-width: 1024px) { .band { min-height: 600px; } }

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

.band::after {
  content: '';
  position: absolute;
  inset: 0;
  background: #000;
  opacity: 0.4;
}

.band h2 {
  position: relative;
  z-index: 1;
  margin: 0;
  padding: 0 24px;
  text-align: center;
  color: #fff;
  font-size: clamp(2rem, 5.6vw, 4rem);
  font-weight: 700;
  line-height: 1.15;
  text-shadow: rgba(0, 0, 0, 0.6) 0 0 6px;
}

/* ---- 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);
}

/* ---- 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-size: clamp(1.4rem, 3vw, 1.9rem);
  font-weight: 700;
  color: var(--ink);
}

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

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

.prose h1 {
  margin: 0 0 20px;
  font-size: clamp(1.6rem, 3.4vw, 2.3rem);
  font-weight: 700;
  color: var(--ink);
}

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

/*
   Three of the section pictures have words printed into them - SPECIAL OFFERS,
   the Crafted Gifts logo, the SA monogram. Forcing those into a square either
   cuts the words off or pads 13% of the frame with blurred filler, and on a
   phone the filler is obvious and the artwork ends up small. So these keep
   their own shape: whole picture, no crop, no padding.
*/
.feature-shot--whole img {
  aspect-ratio: auto;
  height: auto;
  object-fit: contain;
}
