/* ==========================================================================
   BusayoDisu.com  |  Design System
   Palette: Warm Ivory, Terracotta, Deep Forest, Burnt Gold, Charcoal
   Type: Playfair Display (headings) + Space Grotesk Light (body)
   Signature shapes: arched frames, gallery frames, thread dividers.
   No pills, no square cards, no purple.
   ========================================================================== */

/* Brittany Signature is licensed, not free, so it is not served from here.
   local() picks it up on machines that have it; once a licensed web font
   file lives in assets/fonts, add it here as
   url("../assets/fonts/brittany-signature.woff2") format("woff2") and every
   wordmark switches over on its own. */
@font-face {
  font-family: "Brittany Signature";
  src: local("Brittany Signature"), local("BrittanySignature");
  font-display: swap;
}

:root {
  /* PRD palette, restored at the client's direction: warm ivory field,
     warm terracotta accent, deep forest counterpoint, burnt gold detail.
     The wine and navy names remain as aliases from an earlier exploration
     and now resolve to terracotta and forest. */
  --ivory: #FAF7F2;
  --cream: #F4F1EC;
  --sand: #EDE7DC;
  --wine: #B86F52;
  --wine-deep: #9A5741;
  --wine-soft: #E8D5CB;
  --navy: #395144;
  --navy-soft: #DDE4DE;
  --violet: #9A5741;
  --terracotta: var(--wine);
  --terracotta-deep: var(--wine-deep);
  --terracotta-soft: var(--wine-soft);
  --forest: #395144;
  --forest-deep: #2A3D33;
  --forest-soft: #DDE4DE;
  --gold: #B9905C;
  --gold-soft: #E9DCC6;
  --charcoal: #2E2E2E;
  --ink: #33302B;
  --body: #56524A;
  --faint: #857F74;
  --line: rgba(51, 48, 43, 0.14);
  --line-soft: rgba(51, 48, 43, 0.08);

  /* Two voices, at the client's request. Playfair Display speaks the
     headings and the decorative lines that read as headings — chapter
     numbers, pull quotes, stat figures, the wordmark. Everything that
     supports them, from the lede under a heading down to the smallest
     uppercase label, is set in Space Grotesk Light. */
  --serif: "Playfair Display", "Georgia", serif;
  --sans: "Space Grotesk", "Helvetica Neue", Arial, sans-serif;
  /* The wordmark alone is a signature. Brittany Signature is a licensed
     face, so it is used wherever it is installed or self hosted; Ms Madi
     carries the same hand everywhere else. To serve the real face, drop the
     file into assets/fonts and add a url() source to the @font-face below. */
  --script: "Brittany Signature", "Ms Madi", cursive;

  --wrap: 1180px;
  --gutter: clamp(20px, 4vw, 44px);
  --radius: 22px;
  --radius-sm: 12px;
  --arch: 999px 999px 22px 22px;

  --shadow-soft: 0 18px 50px -22px rgba(51, 48, 43, 0.28);
  --shadow-lift: 0 26px 60px -24px rgba(51, 48, 43, 0.35);

  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* The floating corner buttons: the Ask launcher and the theme toggle share
     this inset so they line up whichever corner they are sitting in. */
  --fab-inset: clamp(16px, 3vw, 30px);
  --fab-size: 44px;

  --veil: rgba(250, 247, 242, 0.92);
  --glass: rgba(250, 247, 242, 0.42);
  --glass-solid: rgba(250, 247, 242, 0.62);
  --glass-border: rgba(51, 48, 43, 0.08);
  /* The header tray carries no blur, so its tint has to do the whole job of
     holding the type off the page: near-solid, and solid once scrolled. */
  --tray: rgba(250, 247, 242, 0.93);
  --tray-solid: #FAF7F2;
  --wash-1: radial-gradient(60% 46% at 88% 0%, rgba(184, 111, 82, 0.07), transparent 62%);
  --wash-2: radial-gradient(46% 40% at 0% 26%, rgba(185, 144, 92, 0.08), transparent 65%);
  --wash-3: radial-gradient(52% 44% at 100% 80%, rgba(57, 81, 68, 0.055), transparent 62%);
  --wash-4: radial-gradient(40% 36% at 12% 96%, rgba(57, 81, 68, 0.05), transparent 65%);
}

/* ---------- Dark mode ---------- */

html[data-theme="dark"] {
  --ivory: #201C17;
  --cream: #272219;
  --sand: #2E2820;
  --ink: #F0E9DC;
  --body: #C7BFB0;
  --faint: #948C7D;
  --charcoal: #F0E9DC;
  --wine: #CE8A67;
  --wine-deep: #B86F52;
  --wine-soft: #463227;
  --navy: #4E6B5B;
  --navy-soft: #2E3B34;
  --forest-soft: #2E3B34;
  --gold: #C9A369;
  --gold-soft: #55462C;
  --line: rgba(240, 233, 220, 0.16);
  --line-soft: rgba(240, 233, 220, 0.08);
  --shadow-soft: 0 18px 50px -22px rgba(0, 0, 0, 0.55);
  --shadow-lift: 0 26px 60px -24px rgba(0, 0, 0, 0.65);
  --veil: rgba(32, 28, 23, 0.92);
  --glass: rgba(32, 28, 23, 0.4);
  --glass-solid: rgba(32, 28, 23, 0.62);
  --glass-border: rgba(240, 233, 220, 0.16);
  --tray: rgba(32, 28, 23, 0.94);
  --tray-solid: #201C17;
  --wash-1: radial-gradient(60% 46% at 88% 0%, rgba(184, 111, 82, 0.1), transparent 62%);
  --wash-2: radial-gradient(46% 40% at 0% 26%, rgba(185, 144, 92, 0.08), transparent 65%);
  --wash-3: radial-gradient(52% 44% at 100% 80%, rgba(57, 81, 68, 0.14), transparent 62%);
  --wash-4: radial-gradient(40% 36% at 12% 96%, rgba(57, 81, 68, 0.1), transparent 65%);
}

html[data-theme="dark"] .band-forest { background-color: #16211B; }
html[data-theme="dark"] .btn.alt { border-color: var(--navy); color: var(--ink); }
html[data-theme="dark"] .btn.alt:hover { background: var(--navy); color: var(--ivory); }

/* Components that used deep forest as a FOREGROUND colour go invisible on a
   dark field, so they switch to a light sage in dark mode. */
html[data-theme="dark"] .textlink { color: #A9C6B4; border-color: var(--gold); }
html[data-theme="dark"] .textlink:hover { color: var(--terracotta); border-color: var(--terracotta); }
html[data-theme="dark"] .strip-nav button { border-color: #A9C6B4; color: #A9C6B4; }
html[data-theme="dark"] .strip-nav button:hover { background: var(--navy); border-color: var(--navy); color: var(--ivory); }
html[data-theme="dark"] .activation-code { color: var(--gold); }
html[data-theme="dark"] .code-row code { color: #A9C6B4; }
html[data-theme="dark"] .bridge-cta a { -webkit-text-stroke-color: var(--gold); }
html[data-theme="dark"] .bridge-cta a:hover { color: var(--gold); }
/* Ghost buttons outside the forest band (rare) need a light outline too. */
html[data-theme="dark"] .btn.ghost { border-color: var(--ink); color: var(--ink); }
html[data-theme="dark"] .btn.ghost:hover { background: var(--ink); color: var(--forest-deep); }

/* The lightened terracotta reads as a text accent but is too pale as a
   button fill, so the primary button keeps its full terracotta and light
   label in dark mode, matching the light theme. */
html[data-theme="dark"] .btn:not(.alt):not(.ghost) {
  background: #B86F52;
  border-color: #B86F52;
  color: #FAF7F2;
}
html[data-theme="dark"] .btn:not(.alt):not(.ghost):hover {
  background: #9A5741;
  border-color: #9A5741;
}

/* The book spine keeps fixed wine tones so its gold title always reads. */
html[data-theme="dark"] .book3d .spine { background: linear-gradient(180deg, #9A5741, #7C4030); }
html[data-theme="dark"] .book3d .spine span { color: #F1E4C9; }
html[data-theme="dark"] .bridge-cta a { -webkit-text-stroke-color: var(--gold); }
html[data-theme="dark"] .bridge-cta a:hover { color: var(--gold); }
html[data-theme="dark"] .gallery-frame .mat { background: #2A251E; }
html[data-theme="dark"] .frame-plaque { background: linear-gradient(150deg, #3B3222, #2E2718); color: var(--gold); }

/* ---------- Reset ---------- */

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

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  overflow-x: clip;
}

/* Grid and flex children default to min-width:auto, which lets long content
   push them past the container and cause horizontal overflow on narrow
   screens. Letting them shrink to their track keeps every layout in bounds. */
.grid-2 > *, .grid-3 > *, .grid-4 > *,
.feature-row > *, .catalog-entry > *, .footer-grid > * { min-width: 0; }

body {
  margin: 0;
  /* Parchment, not white. The ivory ground lives here; the washes that warm
     it ride on their own layer below. */
  background: var(--ivory);
  color: var(--body);
  font-family: var(--sans);
  font-size: 1.03rem;
  line-height: 1.75;
  /* Light is the reading weight. Anything that needs more presence — labels,
     buttons, the uppercase runs — asks for it in its own rule. */
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* The ambient washes of warm earth, gold and forest, held still behind the
   page. They used to be four background-attachment:fixed layers on the body,
   but WebKit cannot composite a fixed attachment — it repainted all four
   gradients across the full viewport on every scroll frame, which is most of
   why Safari crawled. As one genuinely fixed layer the compositor holds them
   in place for free and never repaints them again. Dark mode retunes the
   variables, so nothing here needs a theme rule of its own. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    var(--wash-1),
    var(--wash-2),
    var(--wash-3),
    var(--wash-4);
}

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

h1, h2, h3, h4 {
  font-family: var(--serif);
  color: var(--ink);
  font-weight: 500;
  line-height: 1.12;
  margin: 0 0 0.5em;
  letter-spacing: -0.01em;
}

h1 { font-size: clamp(2.7rem, 6vw, 4.4rem); line-height: 1.04; }
h2 { font-size: clamp(2rem, 4vw, 3rem); }
h3 { font-size: clamp(1.35rem, 2.4vw, 1.7rem); }
h4 { font-size: 1.15rem; }

p { margin: 0 0 1.1em; }

a { color: var(--terracotta-deep); text-decoration: none; transition: color .25s var(--ease); }
a:hover { color: var(--terracotta); }

em, .accent-i {
  font-style: italic;
  color: var(--terracotta);
}

/* Keeps a word and its trailing punctuation on one line when an <em> boundary
   sits between them. */
.nobr { white-space: nowrap; }

::selection { background: var(--terracotta); color: var(--ivory); }

:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- Skip link ----------
   Out of the way until a keyboard finds it, then a proper landing card at
   the top left, so a reader who tabs in is not walked through the whole
   header before reaching the page. */

.skip-link {
  position: fixed;
  top: 14px;
  left: 14px;
  z-index: 1000;
  padding: 12px 22px;
  border-radius: 999px 999px 14px 14px;
  background: var(--forest);
  color: var(--ivory);
  font-size: 0.9rem;
  letter-spacing: 0.06em;
  text-decoration: none;
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.28);
  transform: translateY(-160%);
  transition: transform 0.24s cubic-bezier(0.76, 0, 0.24, 1);
}

.skip-link:focus-visible { transform: translateY(0); }

/* ---------- Crawlable site index ----------
   js/site.js builds the real header and footer, which means a crawler that
   never runs JavaScript would otherwise find almost no links out of a page.
   Each page therefore carries a plain list of every room in the house,
   which site.js removes the moment the real footer exists. It is kept out
   of sight rather than out of the document: it is the same set of links,
   in the same order, saying the same thing. */

.site-index-fallback {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- Layout ---------- */

.wrap {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.wrap.narrow { max-width: 880px; }
.wrap.wide { max-width: 1340px; }

section { padding-block: clamp(72px, 9vw, 128px); }
section.tight { padding-block: clamp(48px, 6vw, 84px); }

.band-cream { background: var(--cream); }
.band-sand { background: var(--sand); }
/* The forest band is a permanently dark surface in both themes, so it
   pins its own light foreground tokens. Descendants that read --ivory,
   --gold-soft, --ink etc. resolve to light values here regardless of the
   global theme, which keeps headings, stats, the proverb and ghost
   buttons legible in dark mode. */
.band-forest {
  background: var(--forest);
  color: #E9E5DC;
  --ink: #FAF7F2;
  --ivory: #FAF7F2;
  --body: rgba(233, 229, 220, 0.85);
  --faint: rgba(233, 229, 220, 0.62);
  --gold: #CBA96A;
  --gold-soft: #E9DCC6;
  --line: rgba(233, 229, 220, 0.2);
  --line-soft: rgba(233, 229, 220, 0.12);
}
.band-forest h1, .band-forest h2, .band-forest h3, .band-forest h4 { color: var(--ivory); }
.band-forest p { color: rgba(233, 229, 220, 0.85); }
.band-forest a { color: var(--gold-soft); }
.band-forest a:hover { color: #fff; }
.band-forest .textlink { color: var(--gold-soft); border-color: var(--gold-soft); }
.band-forest .textlink:hover { color: #fff; }

.grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(36px, 6vw, 84px);
  align-items: center;
}

.grid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(28px, 4vw, 56px);
}

.grid-4 {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(24px, 3vw, 44px);
}

@media (max-width: 900px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
  .grid-4 { grid-template-columns: 1fr 1fr; }
}

/* ---------- Eyebrow, lede, thread divider ---------- */

.eyebrow {
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--sans);
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 1.4rem;
}

.eyebrow::before {
  content: "";
  width: 34px;
  height: 1px;
  background: var(--gold);
  flex: none;
}

.eyebrow.center { justify-content: center; }
.eyebrow.center::after {
  content: "";
  width: 34px;
  height: 1px;
  background: var(--gold);
  flex: none;
}

.band-forest .eyebrow { color: var(--gold-soft); }
.band-forest .eyebrow::before, .band-forest .eyebrow::after { background: var(--gold-soft); }

.lede {
  font-size: clamp(1.1rem, 1.7vw, 1.28rem);
  line-height: 1.7;
  color: var(--body);
  max-width: 46ch;
}

.center { text-align: center; }
.center .lede { margin-inline: auto; }

.thread {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding-block: 8px;
  border: 0;
  margin: 0 auto;
}

.thread::before, .thread::after {
  content: "";
  height: 1px;
  width: min(120px, 20vw);
  background: linear-gradient(to var(--dir, right), transparent, var(--line));
}

.thread::before { --dir: right; }
.thread::after { --dir: left; }

.thread .gem {
  width: 7px;
  height: 7px;
  background: var(--gold);
  transform: rotate(45deg);
  flex: none;
}

.thread .gem:nth-child(2) { background: var(--terracotta); width: 9px; height: 9px; }
.thread .gem:nth-child(3) { background: var(--forest); }

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--sans);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 15px 32px;
  border-radius: 55% 45% 48% 52% / 48% 52% 48% 52%;
  border: 1.5px solid var(--terracotta);
  background: var(--terracotta);
  color: var(--ivory);
  cursor: pointer;
  position: relative;
  isolation: isolate;
  animation: blobby 9s ease-in-out infinite alternate;
  transition: transform .3s var(--ease), box-shadow .3s var(--ease), background .3s var(--ease), border-color .3s var(--ease), color .3s var(--ease);
  /* The morphing silhouette repaints the button on every frame it runs.
     On its own layer that repaint is the button's alone; sharing the page's
     layer, every button was dirtying the page's rasterised tiles forever,
     and scrolling paid for it. Off screen the morph is paused outright
     (js/site.js -> initIdleScenes). */
  will-change: transform;
}

/* The living halo behind every button. The button itself keeps morphing —
   that silhouette is the whole point — but the halo holds still: under an
   11px blur the shape is unreadable anyway, and both morphing it and
   inheriting the button's animating radius forced the blur to be
   re-rasterized on every frame, for every button on the page, forever.
   A fixed radius lets the blur be rasterized once and cached. */
.btn::after {
  content: "";
  position: absolute;
  inset: -8px;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(70% 70% at 32% 30%, rgba(185, 144, 92, 0.55), rgba(184, 111, 82, 0.28) 55%, transparent 78%);
  filter: blur(11px);
  opacity: 0.75;
  transition: opacity .3s var(--ease);
}

.btn:hover::after { opacity: 1; }

.btn.alt::after {
  background: radial-gradient(70% 70% at 32% 30%, rgba(57, 81, 68, 0.3), rgba(185, 144, 92, 0.22) 60%, transparent 80%);
}

.btn.ghost::after {
  background: radial-gradient(70% 70% at 32% 30%, rgba(250, 247, 242, 0.28), transparent 75%);
}

@keyframes blobby {
  0% { border-radius: 55% 45% 48% 52% / 48% 52% 48% 52%; }
  33% { border-radius: 47% 53% 55% 45% / 55% 46% 54% 45%; }
  66% { border-radius: 52% 48% 44% 56% / 46% 55% 45% 54%; }
  100% { border-radius: 45% 55% 52% 48% / 54% 45% 55% 46%; }
}

.btn:hover {
  transform: translateY(-3px);
  box-shadow: 0 16px 30px -14px rgba(184, 111, 82, 0.55);
  background: var(--terracotta-deep);
  border-color: var(--terracotta-deep);
  color: var(--ivory);
}

.btn.alt {
  background: transparent;
  border-color: var(--forest);
  color: var(--forest);
}

.btn.alt:hover {
  background: var(--forest);
  color: var(--ivory);
  box-shadow: 0 16px 30px -14px rgba(57, 81, 68, 0.5);
}

.btn.ghost {
  background: transparent;
  border-color: var(--ivory);
  color: var(--ivory);
}

.btn.ghost:hover { background: var(--ivory); color: var(--forest); box-shadow: none; }

.btn.small { padding: 10px 22px; font-size: 0.88rem; }
.btn.small::after { inset: -5px; filter: blur(7px); opacity: 0.55; }

/* Nothing on the page is worth a permanent repaint once the reader has
   said they want less motion. */
@media (prefers-reduced-motion: reduce) {
  .btn { animation: none; border-radius: 55% 45% 48% 52% / 48% 52% 48% 52%; }
}

/* ---------- Theme toggle (floating) ----------
   A round button carrying the icon of the mode it switches to. It sits in
   the hero's bottom right corner, then docks to the right of the Ask
   launcher once the hero has scrolled away (js/site.js -> initThemeFab). */

.theme-fab {
  position: absolute;
  right: var(--fab-inset);
  bottom: var(--fab-inset);
  z-index: 3;
  width: var(--fab-size);
  height: var(--fab-size);
  border-radius: 50%;
  border: 1px solid rgba(237, 230, 218, 0.32);
  background: rgba(24, 12, 3, 0.42);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  color: #FBF8F2;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background 0.3s var(--ease), border-color 0.3s var(--ease),
              color 0.3s var(--ease), transform 0.3s var(--ease), opacity 0.18s linear;
}

.theme-fab svg { width: 19px; height: 19px; }

.theme-fab:hover { border-color: var(--gold); color: var(--terracotta); transform: translateY(-2px); }

/* Docked: it leaves the hero's dark slab for the page itself, so it takes
   the page's own glass and ink and sits at the launcher's shoulder. */
.theme-fab.docked {
  position: fixed;
  z-index: 950;
  border-color: var(--glass-border);
  /* The page ground itself, opaque. Docked, this button is fixed, so a
     backdrop blur had WebKit re-sampling and re-blurring the page beneath it
     on every scroll frame. --glass-solid is the ground colour at 62%, so
     sitting on the ground it already resolved to exactly this — the frost
     only ever showed where content passed under it. Solid costs nothing. */
  background: var(--ivory);
  color: var(--ink);
  box-shadow: 0 16px 36px -14px rgba(18, 27, 21, 0.5);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* The word hangs below the button, so the button needs a gutter under it. At
   the dock the viewport's own edge is square and the inset is gutter enough;
   in the hero that same band is curving away into its rounded corner, so the
   button lifts a little to keep the letters clear of the curve. */
.theme-fab:not(.docked) { bottom: calc(var(--fab-inset) + 15px); }

/* The fade that covers the hop between the hero corner and the dock. */
.theme-fab.shifting { opacity: 0; }

body.menu-open .theme-fab,
body.chat-open .theme-fab { opacity: 0; pointer-events: none; }

/* The launcher slides left to make room once the button docks beside it. */
body.fab-docked #chat-launcher { right: calc(var(--fab-inset) + var(--fab-size) + 10px); }

@media (max-width: 460px) {
  .theme-fab svg { width: 17px; height: 17px; }
}

/* ---------- The corner's radiance ----------
   The button does not wait to be noticed. It breathes a halo the colour of the
   light the reader is standing in — warm gold while the page is light, a pool
   of night rimmed in moonlight while it is dark — and names the mode beneath
   itself in small caps. One halo and no more: the travelling rings that used
   to pulse out through it read as a second, stray glow whenever a frame
   caught them mid-flight.

   The halo is hollow in the middle. A pseudo element paints over the button's
   own face, so its colour only begins past the rim; nothing washes the icon,
   and nothing takes a click. */

.theme-fab {
  /* Light: the sun's own colours, thrown outward. Warm enough to register on
     an ivory ground, which is the harder of the two to glow against. */
  --aura-core: rgba(206, 154, 82, 0.34);
  --aura-edge: rgba(185, 144, 92, 0.13);
  --aura-ring: rgba(216, 168, 96, 0.5);
  --aura-rim: rgba(255, 238, 205, 0.42);
  --aura-word: #6E5A38;
}

html[data-theme="dark"] .theme-fab {
  /* Dark: night pooling outward, with just enough moon on the ring's edge to
     be seen against a page that is already dark. */
  --aura-core: rgba(8, 5, 3, 0.55);
  --aura-edge: rgba(8, 5, 3, 0.22);
  --aura-ring: rgba(6, 4, 2, 0.6);
  --aura-rim: rgba(228, 216, 194, 0.4);
  --aura-word: #E4D9C4;
}

/* The steady halo, breathing under the rings. 250% of the button, so it
   reaches roughly to the corner inset and stops before the edge. */
.theme-fab::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 250%;
  height: 250%;
  border-radius: 50%;
  pointer-events: none;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle closest-side,
    transparent 40%, var(--aura-core) 57%, var(--aura-edge) 72%, transparent 90%);
  animation: fabBreathe 4.6s ease-in-out infinite;
}

/* The word hangs under the button, centred on it, and takes clicks: it is
   close enough to the target to be aimed at by mistake, and a mistake there
   should still switch the mode rather than land on the page. */
.theme-fab .fab-word {
  position: absolute;
  left: 50%;
  top: calc(100% + 7px);
  transform: translateX(-50%);
  white-space: nowrap;
  font-family: var(--sans);
  /* A caption, not a second button. At the old size and tracking the word ran
     to about twice the 44px button it hangs under, so the label read louder
     than the control it was labelling. Smaller, tighter and a shade lighter
     puts it back underneath. */
  font-size: 0.48rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* In the hero it stands on the cover photograph, which is dark in either
     mode, so it is lit there whatever the page is doing. */
  color: #FBF8F2;
  text-shadow: 0 1px 14px rgba(12, 6, 2, 0.8), 0 0 4px rgba(12, 6, 2, 0.55);
  animation: fabWord 4.6s ease-in-out infinite;
}

/* Docked, it stands on the page itself and takes the page's own ink, held off
   whatever scrolls beneath by a halo of the ground colour. */
.theme-fab.docked .fab-word {
  color: var(--aura-word);
  text-shadow: 0 0 12px var(--veil), 0 0 5px var(--veil), 0 0 2px var(--veil);
}

/* Once it is under a cursor it has done its job, so the word simply warms —
   the breath is left alone, since restarting it on hover would jump. */
.theme-fab:hover .fab-word { color: var(--gold); }

@keyframes fabBreathe {
  0%, 100% { opacity: 0.6; transform: translate(-50%, -50%) scale(0.94); }
  50%      { opacity: 1;   transform: translate(-50%, -50%) scale(1.05); }
}

@keyframes fabWord {
  0%, 100% { opacity: 0.74; }
  50%      { opacity: 1; }
}

/* Asked for less motion, the corner still glows — it simply stops pulsing. */
@media (prefers-reduced-motion: reduce) {
  .theme-fab::before,
  .theme-fab .fab-word { animation: none; }
}

/* Mode toggles inside the mobile overlay menu */

/* Appearance controls, set apart under the links so they read as a real
   control rather than a footnote. Buttons keep a 44px tap target. */
.menu-modes {
  margin-top: 30px;
  padding-top: 22px;
  border-top: 1px solid rgba(250, 247, 242, 0.14);
}

.menu-modes-label {
  display: block;
  margin-bottom: 12px;
  font-family: var(--sans);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(233, 229, 220, 0.5);
}

.menu-modes-set {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

/* ---------- Mode toggles (text form, mobile menu) ---------- */

.mode-row {
  display: flex;
  gap: 26px;
  margin-top: 1.8rem;
  flex-wrap: wrap;
}

.mode-btn {
  background: none;
  border: 0;
  padding: 4px 0;
  cursor: pointer;
  font-family: var(--sans);
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--faint);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  transition: color 0.3s var(--ease);
}

.mode-btn:hover { color: var(--ink); }

.mode-btn .gem {
  width: 9px;
  height: 9px;
  border: 1.5px solid var(--gold);
  background: transparent;
  transform: rotate(45deg);
  transition: background 0.3s var(--ease), border-color 0.3s var(--ease);
}

/* The mobile menu overlay is always dark, so its text toggles read light. */
.menu-modes .mode-btn {
  flex: 1 1 auto;
  justify-content: center;
  min-height: 46px;
  padding: 11px 14px;
  gap: 9px;
  border: 1px solid rgba(233, 229, 220, 0.2);
  border-radius: 14px;
  background: rgba(233, 229, 220, 0.05);
  color: rgba(233, 229, 220, 0.78);
  letter-spacing: 0.12em;
  transition: color .3s var(--ease), background .3s var(--ease), border-color .3s var(--ease);
}
.menu-modes .mode-btn svg { width: 17px; height: 17px; flex: none; }
.menu-modes .mode-btn:hover { color: var(--ivory); border-color: rgba(233, 229, 220, 0.4); }

.btn .arrow { transition: transform .3s var(--ease); }
.btn:hover .arrow { transform: translateX(4px); }

.textlink {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--forest);
  border-bottom: 1px solid var(--gold);
  padding-bottom: 3px;
}

.textlink:hover { color: var(--terracotta); border-color: var(--terracotta); }
.textlink:hover .arrow { transform: translateX(4px); }
.textlink .arrow { transition: transform .3s var(--ease); }

/* ---------- Header ---------- */

#site-header {
  position: fixed;
  top: clamp(10px, 1.5vw, 18px);
  left: 0;
  right: 0;
  z-index: 90;
  padding-inline: clamp(14px, 3vw, 32px);
  pointer-events: none;
}

/* On the first frame the tray has to arrive in whatever state the page's
   scroll position calls for — CTA folded away, type inverted — rather than
   animate into it, or a reload on a dark band shows the wrong tray for a beat
   and a page opening on its own button flashes a second one. */
#site-header.settling,
#site-header.settling * {
  transition: none !important;
}

/* The header rides in a floating tray, detached from every edge, deepening a
   touch once the page scrolls beneath it. Nothing behind it is blurred: the
   tray is its own opaque panel, so the page simply passes underneath. */
.header-inner {
  pointer-events: auto;
  position: relative;
  isolation: isolate;
  max-width: 1290px;
  margin-inline: auto;
  padding: 0 12px 0 18px;
  height: 66px;
  display: flex;
  align-items: center;
  gap: 12px;
  border-radius: 20px;
  background: var(--tray);
  border: 1px solid var(--glass-border);
  box-shadow:
    0 16px 40px -24px rgba(51, 48, 43, 0.4),
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    inset 0 -1px 0 rgba(255, 255, 255, 0.14);
  transition: box-shadow .4s var(--ease), background .4s var(--ease),
    border-color .4s var(--ease);
}

/* The specular sheen: light gathers along the top left of the glass and falls
   away across it, which is what separates liquid glass from flat frosting. */
.header-inner::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(158deg, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0.08) 40%, rgba(255, 255, 255, 0) 62%);
  transition: background .4s var(--ease);
}

#site-header.scrolled .header-inner {
  background: var(--tray-solid);
  box-shadow:
    0 22px 50px -22px rgba(51, 48, 43, 0.5),
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 -1px 0 rgba(255, 255, 255, 0.16);
}

/* ---------- Header over a dark band ----------
   While the tray floats over the cover photograph (or any section flagged
   dark), it stops being a pale wafer over a brown field: it fills with a deep
   roast and pins light foreground tokens, so every child — brand, links,
   toggle, burger — inverts from one place. */
#site-header.on-dark .header-inner {
  --ink: #FDFAF4;
  --body: rgba(240, 233, 221, 0.88);
  --faint: rgba(240, 233, 221, 0.66);
  --line: rgba(245, 238, 228, 0.3);
  --line-soft: rgba(245, 238, 228, 0.15);
  --gold: #E0BC86;
  --terracotta-deep: #F0BE9E;
  background: linear-gradient(150deg, rgba(42, 23, 9, 0.93) 0%, rgba(20, 11, 4, 0.95) 100%);
  border-color: rgba(250, 244, 235, 0.24);
  box-shadow:
    0 22px 50px -26px rgba(0, 0, 0, 0.7),
    inset 0 1px 0 rgba(255, 255, 255, 0.3),
    inset 0 -1px 0 rgba(0, 0, 0, 0.28);
}

#site-header.on-dark .header-inner::before {
  background: linear-gradient(158deg, rgba(255, 255, 255, 0.24) 0%, rgba(255, 255, 255, 0.04) 42%, rgba(255, 255, 255, 0) 64%);
}

#site-header.on-dark.scrolled .header-inner {
  background: linear-gradient(150deg, rgb(38, 21, 8) 0%, rgb(18, 10, 4) 100%);
}

/* The CTA keeps its own saturated terracotta rather than inheriting the
   lightened text tokens, which would leave ivory type on a pale pill. */
#site-header.on-dark .header-cta {
  background: #C87C58;
  border-color: #C87C58;
  color: #FFF9F1;
}

#site-header.on-dark .header-cta:hover {
  background: #E0A17C;
  border-color: #E0A17C;
  color: #2C1408;
}

@media (max-width: 700px) {
  .header-inner { padding: 0 10px 0 14px; height: 60px; }
}

.brand {
  display: flex;
  align-items: center;
  gap: 13px;
  font-family: var(--serif);
  color: var(--ink);
  white-space: nowrap;
}

.brand:hover { color: var(--ink); }

.brand-word { display: flex; flex-direction: column; align-items: stretch; line-height: 1; }

/* The wordmark is her signature, so it is set in the script face and sized
   up: script lowercase reads far smaller than Playfair at the same size. */
.brand-name {
  font-family: var(--script);
  font-size: 2rem;
  font-weight: 400;
  letter-spacing: 0;
  /* Signature descenders and swashes overshoot the line box; a touch of
     padding keeps them off the tray's edge. */
  padding: 0.12em 0.06em;
  color: var(--ink);
  transition: color .35s var(--ease);
}
.brand:hover .brand-name { color: var(--ink); }

.brand .gem {
  width: 7px;
  height: 7px;
  background: var(--terracotta);
  transform: rotate(45deg) translateY(-2px);
  display: inline-block;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: clamp(12px, 1.4vw, 22px);
  margin-left: auto;
}

.nav-links a {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink);
  position: relative;
  padding-block: 6px;
  white-space: nowrap;
}

.nav-links a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1.5px;
  background: var(--terracotta);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .3s var(--ease);
}

.nav-links a:hover::after, .nav-links a[aria-current="page"]::after { transform: scaleX(1); }
.nav-links a[aria-current="page"] { color: var(--terracotta-deep); }

.header-cta {
  margin-left: 6px;
  transition: opacity .24s var(--ease) .16s, transform .3s var(--ease) .16s,
              margin-left .42s var(--ease), visibility 0s;
}

/* While a page's own Book Busayo button is on screen the header's copy steps
   aside: it fades, then folds its width away so the nav slides across into the
   space rather than leaving a gap at the right of the tray. --cta-w is the
   button's measured width, set on the header by site.js. */
#site-header.cta-quiet .header-cta {
  opacity: 0;
  transform: scale(0.94);
  visibility: hidden;
  pointer-events: none;
  transition: opacity .2s var(--ease), transform .3s var(--ease),
              margin-left .42s var(--ease) .1s, visibility 0s .2s;
}

@media (min-width: 1081px) {
  #site-header.cta-quiet .header-cta { margin-left: calc(-1 * var(--cta-w, 170px)); }
}

.menu-btn {
  display: none;
  margin-left: auto;
  background: none;
  border: 0;
  cursor: pointer;
  /* The tray is tight at the right: the fan gets the same footprint the three
     bars used to have, so it never rides over the bar's rounded edge. */
  padding: 4px 2px 4px 0;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

/* Small, quiet, and never absent: the one thing that tells a first-time
   reader the two pictures are a door and not a badge. */
.menu-btn-label {
  font-family: var(--sans);
  font-size: 0.55rem;
  line-height: 1;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--faint);
  transition: color .3s var(--ease);
}

.menu-btn:hover .menu-btn-label { color: var(--ink); }
#site-header.on-dark .menu-btn-label { color: rgba(245, 238, 228, 0.72); }

/* Two arched cards fanned like photographs left on a desk: Mrs. Disu leaning
   out behind, Our Story, Our Voice sitting in front. They splay a little
   further apart on hover, which is the whole animation. */
.menu-cards {
  display: block;
  position: relative;
  width: 34px;
  height: 34px;
}

.menu-card {
  position: absolute;
  top: 0;
  left: 0;
  width: 21px;
  height: 27px;
  border-radius: 10px 10px 3px 3px;
  overflow: hidden;
  background: var(--sand);
  border: 1px solid var(--line);
  box-shadow: 0 6px 14px -9px rgba(0, 0, 0, 0.6);
  transition: transform .38s var(--ease), border-color .35s var(--ease);
}

.menu-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* A drawn mark is laid whole on a light card, not cropped to fill one: both
   marks are drawn for a light ground, so the card holds one in either theme. */
.menu-card.is-logo,
.door-mark.is-logo { background: #FBF8F2; border-color: rgba(51, 48, 43, 0.16); }

.menu-card.is-logo img,
.door-mark.is-logo img { object-fit: contain; padding: 2px; }

.door-mark.is-logo img { padding: 4px; }

.menu-card:first-child { transform: translate(0, 5px) rotate(-12deg); }
.menu-card:last-child { transform: translate(13px, 2px) rotate(8deg); }

.menu-btn:hover .menu-card:first-child,
.menu-btn:focus-visible .menu-card:first-child { transform: translate(-1px, 4px) rotate(-18deg); }
.menu-btn:hover .menu-card:last-child,
.menu-btn:focus-visible .menu-card:last-child { transform: translate(14px, 1px) rotate(14deg); }

/* On arrival the pair deals itself apart and settles back, twice. Motion is
   what catches the eye first; the word underneath answers what it is. Hover
   takes the animation off so the splay is the reader's to hold. */
.menu-card:first-child { animation: deal-back 2.6s var(--ease) 1.1s 2; }
.menu-card:last-child { animation: deal-front 2.6s var(--ease) 1.1s 2; }
.menu-btn:hover .menu-card { animation: none; }

@keyframes deal-back {
  0%, 100% { transform: translate(0, 5px) rotate(-12deg); }
  22% { transform: translate(-2px, 1px) rotate(-22deg); }
}

@keyframes deal-front {
  0%, 100% { transform: translate(13px, 2px) rotate(8deg); }
  22% { transform: translate(15px, -2px) rotate(17deg); }
}

@media (prefers-reduced-motion: reduce) {
  .menu-card { animation: none !important; }
}

#site-header.on-dark .menu-card { border-color: rgba(250, 244, 235, 0.34); }

@media (max-width: 1080px) {
  .nav-links { display: none; }
  .menu-btn { display: flex; margin-left: 8px; }
  /* Book Busayo stays in the header, pushed to the right, wearing the same
     organic blob shape as every other button; only its padding is compact. */
  .header-cta {
    display: inline-flex;
    margin-left: auto;
    white-space: nowrap;
    padding: 10px 20px;
  }
  .header-cta::after { inset: -4px; }
  /* Above this width the quiet CTA folds its width away and the nav slides
     across the gap. There is no nav here to do that, so a hidden button would
     just hold 120-odd pixels of empty tray and push the menu off the right
     edge — on a 320 wide phone, clean off the screen. It leaves the row. */
  #site-header.cta-quiet .header-cta { display: none; }
  /* And the menu takes over the auto margin that was holding the right edge. */
  #site-header.cta-quiet .menu-btn { margin-left: auto; }
}

@media (max-width: 600px) {
  .header-cta { padding: 9px 17px; font-size: 0.82rem; }
}

/* Narrower than this the tray cannot hold the wordmark, the button and the
   menu at once, and the menu is the one that ends up off the screen — worst on
   the hubs, where the wordmark is a whole sentence. The button steps out: the
   menu card carries it, and every page has its own in the body. */
@media (max-width: 520px) {
  .header-cta { display: none; }
  #site-header .menu-btn { margin-left: auto; }
}

/* On the narrowest phones even the sentence wordmark alone crowds the menu,
   so the signature is set a size down. */
@media (max-width: 360px) {
  .brand-name { font-size: 1.72rem; }
}

/* Mobile overlay menu */

/* The menu is a card that drops from the top and stops around half the
   screen, curved at its lower corners like the hero band. Everything below it
   stays where it was, under a blur that takes a tap or a scroll to dismiss. */
#mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: grid;
  grid-template-rows: auto 1fr;
  opacity: 0;
  visibility: hidden;
  transition: opacity .4s var(--ease), visibility .4s var(--ease);
}

/* The veil covers the whole screen rather than starting where the card ends,
   so the page stays blurred in the notches beside the card's curved corners
   too. The card is opaque and sits over it; only the corners show it. */
#mobile-menu::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: rgba(250, 247, 242, 0.62);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  pointer-events: none;
}

#mobile-menu.open { opacity: 1; visibility: visible; }

.menu-panel {
  position: relative;
  z-index: 1;
  background: var(--forest-deep);
  border-bottom-left-radius: clamp(26px, 7vw, 46px);
  border-bottom-right-radius: clamp(26px, 7vw, 46px);
  box-shadow: 0 34px 60px -34px rgba(0, 0, 0, 0.65);
  padding: 72px var(--gutter) 26px;
  max-height: 64vh;
  /* The card holds its half of the screen even when the links are few. */
  min-height: 44vh;
  display: flex;
  flex-direction: column;
  justify-content: safe center;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  transform: translateY(-14px);
  transition: transform .45s var(--ease);
}

#mobile-menu.open .menu-panel { transform: translateY(0); }

/* The card carries the same three doors, the same actions and the appearance
   control as before, so it is set a shade tighter to hold them all in half a
   screen without an inner scroll. */
.menu-panel nav a { font-size: clamp(1.32rem, 4.8vw, 1.8rem); padding: 4px 0; }
.menu-panel .menu-foot { margin-top: 18px; gap: 10px; }
.menu-panel .menu-modes { margin-top: 20px; padding-top: 16px; }
.menu-panel .menu-modes-label { margin-bottom: 9px; }

/* The scrim itself is only the target and the line that names it: the veil it
   used to carry now covers the whole screen, above. */
.menu-scrim {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  border: 0;
  padding: 0;
  background: none;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  padding-top: clamp(26px, 7vh, 54px);
}

/* The blur is the close button now, so it has to say so. A finger taps once
   in a while just above the words, and the whole line breathes with it. */
.scrim-hint {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  font-family: var(--sans);
  font-size: 0.76rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #26190E;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .5s var(--ease) .18s, transform .5s var(--ease) .18s;
}

html[data-theme="dark"] #mobile-menu::before { background: rgba(18, 11, 4, 0.6); }
html[data-theme="dark"] .scrim-hint { color: #FBF7F0; }

#mobile-menu.open .scrim-hint {
  opacity: 0.9;
  transform: translateY(0);
  animation: hint-breathe 2.6s var(--ease) 0.6s infinite;
}

/* The finger: a soft disc that presses down and lets a ring go each time. */
.scrim-tap {
  position: relative;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.55;
}

.scrim-tap::before,
.scrim-tap::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1.5px solid currentColor;
}

#mobile-menu.open .scrim-tap { animation: hint-press 2.6s var(--ease) 0.6s infinite; }
#mobile-menu.open .scrim-tap::before { animation: hint-ring 2.6s var(--ease) 0.6s infinite; }
#mobile-menu.open .scrim-tap::after { animation: hint-ring 2.6s var(--ease) 0.95s infinite; }

@keyframes hint-press {
  0%, 100% { transform: scale(1); opacity: 0.55; }
  10% { transform: scale(0.74); opacity: 0.85; }
  24% { transform: scale(1); opacity: 0.55; }
}

@keyframes hint-ring {
  0% { transform: scale(0.8); opacity: 0.5; }
  55%, 100% { transform: scale(2.4); opacity: 0; }
}

@keyframes hint-breathe {
  0%, 100% { opacity: 0.72; }
  12% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  #mobile-menu.open .scrim-hint,
  #mobile-menu.open .scrim-tap,
  #mobile-menu.open .scrim-tap::before,
  #mobile-menu.open .scrim-tap::after { animation: none; }
  #mobile-menu.open .scrim-hint { opacity: 0.9; }
}

#mobile-menu nav { display: flex; flex-direction: column; gap: 4px; }

#mobile-menu nav a {
  font-family: var(--serif);
  font-size: clamp(1.5rem, 5.2vw, 2.1rem);
  /* The card is deep forest in both themes, so its type is pinned light
     rather than taking --ivory, which turns dark when the site does. */
  color: #FAF7F2;
  padding: 6px 0;
  border-bottom: 1px solid rgba(250, 247, 242, 0.08);
  transform: translateY(14px);
  opacity: 0;
  display: flex;
  align-items: center;
  gap: 14px;
  transition: transform .5s var(--ease), opacity .5s var(--ease), color .3s var(--ease);
}

#mobile-menu.open nav a { transform: translateY(0); opacity: 1; }
#mobile-menu nav a:hover { color: #E3C08C; }

/* The same arched card the tray button fans, one per door, so the brand is
   recognised before the name is finished. */
.door-mark {
  flex: none;
  width: 42px;
  height: 52px;
  border-radius: 20px 20px 5px 5px;
  overflow: hidden;
  background: rgba(250, 247, 242, 0.06);
  border: 1px solid rgba(250, 247, 242, 0.2);
  transition: transform .35s var(--ease);
}

.door-mark img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 24%;
  display: block;
}

#mobile-menu nav a:hover .door-mark { transform: translateY(-2px) rotate(-3deg); }

#mobile-menu .menu-foot {
  margin-top: 24px;
  display: flex;
  gap: 14px;
  align-items: center;
  flex-wrap: wrap;
}

/* Short screens: tighten further so the appearance controls stay in view
   without scrolling. The menu scrolls if it still does not fit. */
@media (max-height: 740px) {
  .menu-panel { padding-top: 72px; padding-bottom: 22px; max-height: 72vh; }
  #mobile-menu nav { gap: 2px; }
  #mobile-menu nav a { font-size: clamp(1.18rem, 4.2vw, 1.5rem); padding: 3px 0; gap: 11px; }
  .door-mark { width: 34px; height: 42px; border-radius: 16px 16px 4px 4px; }
  #mobile-menu .menu-foot { margin-top: 16px; }
  .menu-modes { margin-top: 16px; padding-top: 12px; }
  .menu-modes-label { margin-bottom: 9px; }
  .menu-modes .mode-btn { min-height: 42px; padding: 9px 12px; }
}

body.menu-open { overflow: hidden; }
/* Keep the floating chat launcher from overlapping the open mobile menu. */
body.menu-open #chat-launcher { opacity: 0; pointer-events: none; }

/* ---------- Hero ---------- */

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 2rem;
}

.hero-roles {
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--faint);
  margin-top: 2.6rem;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 16px;
  align-items: center;
}

.hero-roles .gem {
  width: 5px;
  height: 5px;
  background: var(--gold);
  transform: rotate(45deg);
  display: inline-block;
}

/* ---------- Arch frames ---------- */

.arch-frame {
  position: relative;
  border-radius: var(--arch);
  overflow: visible;
}

.arch-frame .arch-img {
  border-radius: var(--arch);
  overflow: hidden;
  position: relative;
  z-index: 1;
  box-shadow: var(--shadow-soft);
}

.arch-frame::before {
  content: "";
  position: absolute;
  inset: -16px -16px -16px auto;
  width: 100%;
  border-radius: var(--arch);
  border: 1.5px solid var(--gold);
  opacity: 0.55;
  transform: translate(16px, 0);
  pointer-events: none;
}

.arch-frame.offset-left::before { transform: translate(-16px, 16px); inset: -16px auto -16px -16px; }

/* ---------- Hero cover ----------
   The photograph is the cover, and it is the whole cover: it fills the band to
   every edge, framed on the top of the image so Busayo's face sits high. She
   stands in the left third of her own frame, which leaves the right of the
   picture to the copy — set flush right, on the photograph itself rather than
   on a slab beside it. */
.hero-cover {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: center;
  min-height: min(90vh, 920px);
  padding-top: clamp(118px, 11vw, 146px);
  padding-bottom: clamp(52px, 6vw, 78px);
  /* The band's lower corners curve away from the page beneath it. */
  border-bottom-left-radius: clamp(26px, 3.4vw, 52px);
  border-bottom-right-radius: clamp(26px, 3.4vw, 52px);
  /* #260D01 at the photograph's edges, #361602 through its middle. */
  background:
    radial-gradient(120% 86% at 22% 4%, rgba(122, 62, 24, 0.34), transparent 62%),
    linear-gradient(180deg, #2E1202 0%, #351603 44%, #250C01 100%);
  color: #EDE6DA;
  /* A permanently dark band in both themes, so it pins light foreground
     tokens the way .band-forest does. */
  --ink: #FBF8F2;
  --ivory: #FBF8F2;
  --body: rgba(237, 230, 218, 0.86);
  --faint: rgba(237, 230, 218, 0.64);
  --gold: #D3AE72;
  --gold-soft: #EBDCC0;
  --terracotta: #DA916D;
  --terracotta-deep: #C87C58;
  --forest: #A9C6B4;
  --line: rgba(237, 230, 218, 0.22);
  --line-soft: rgba(237, 230, 218, 0.12);
}

.hero-cover > .wrap { position: relative; z-index: 1; width: 100%; }

.hero-cover h1 { color: var(--ivory); }
.hero-cover p { color: var(--body); }

/* The cover photograph: the whole section, bled to all four edges. */
.hero-cover-media {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

/* The frame fills the band and is anchored to its top, so her face sits high
   and whatever the band cannot hold falls off the bottom, where her dress is
   already dark. --cover-x slides the frame sideways on the rare shape that
   crops it horizontally, to keep her whole figure in shot. */
.hero-cover-media img {
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: var(--cover-x, 15%) 0%;
  /* Filling the whole band rather than two thirds of it puts the same figure
     against a much wider field, which reads as her having stepped back. The
     zoom walks her forward again, anchored on her own side of the frame and on
     its top, so it crops the spare backdrop and the floor rather than her.
     Each hero sets its own: how much a frame can take depends on how large she
     was drawn or photographed in it. */
  transform: scale(var(--cover-zoom, 1.18));
  transform-origin: var(--cover-x, 15%) 0%;
}

/* The words stand on the photograph now, not on a slab beside it, so what used
   to be the slab is a shadow drawn across the same picture: it gathers on the
   right, where the copy sits, and seats the band on its own floor. Her side of
   the frame keeps its colour. */
.hero-cover-media::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(to right, transparent 32%, rgba(37, 12, 1, 0.3) 58%, rgba(37, 12, 1, 0.54) 80%, rgba(32, 10, 1, 0.64) 100%),
    linear-gradient(to bottom, transparent 64%, rgba(37, 12, 1, 0.28) 88%, rgba(37, 12, 1, 0.44) 100%);
}

.hero-cover-copy {
  width: min(560px, 100%);
  margin-left: auto;
  text-align: right;
}

.hero-cover-copy .lede { margin-left: auto; max-width: 42ch; }
.hero-cover-copy .hero-actions { justify-content: flex-end; margin-top: 1.7rem; }
.hero-cover-copy .hero-roles { justify-content: flex-end; margin-top: 2rem; }

.hero-cover .btn.alt { border-color: rgba(237, 230, 218, 0.5); color: var(--ivory); }
.hero-cover .btn.alt:hover {
  background: var(--forest);
  border-color: var(--forest);
  color: #24140A;
  box-shadow: 0 16px 30px -14px rgba(0, 0, 0, 0.5);
}

@media (max-width: 1200px) {
  /* Below this the side by side leaves the copy too little room beside a
     figure this size. Rather than demote the photograph to a band with slab
     above and below it, the picture takes the whole hero — every edge, top to
     bottom — and the words come off the slab to stand on it. */
  .hero-cover {
    display: flex;
    align-items: flex-end;
    min-height: 90vh;
    min-height: min(92svh, 900px);
    padding-top: clamp(96px, 15vw, 132px);
    /* Enough floor for the words to clear the theme button in the corner. */
    padding-bottom: clamp(78px, 9vw, 104px);
  }
  .hero-cover-media {
    position: absolute;
    inset: 0;
    width: auto;
    height: auto;
    margin-bottom: 0;
    /* Nothing to feather into: the photograph ends where the band ends. */
    -webkit-mask-image: none;
    mask-image: none;
  }
  /* The shadow that used to close the band becomes the ground the words stand
     on, with a breath of it at the top so the header tray keeps its edge. */
  .hero-cover-media::after {
    background:
      linear-gradient(to bottom, rgba(20, 8, 1, 0.34) 0%, transparent 20%),
      linear-gradient(to bottom, transparent 42%, rgba(37, 12, 1, 0.52) 68%, rgba(37, 12, 1, 0.88) 86%, #250C01 100%);
  }
  /* Centre her, not the frame. She sits a third of the way across a landscape
     original, so instead of cropping to a percentage — which drifts as the
     band changes shape — the frame is scaled by height and slid until her
     centre line is the band's, which holds at any width. --cover-focus is how
     far across her own frame she stands, and each hero sets its own. */
  .hero-cover-media img {
    position: absolute;
    top: 0;
    left: 50%;
    width: auto;
    height: 100%;
    transform: translateX(calc(-100% * var(--cover-focus, 0.26)));
    /* That same slide is what can walk the frame's own left edge into the
       band: pulled left by a third of itself, the frame only still reaches the
       left edge while it is at least (50 / focus) per cent of the band wide.
       A band wider than that — a tablet on its side, a short window — would
       have shown a strip of slab down the left, so the frame is stretched to
       meet the edge and object-fit crops the surplus off the bottom instead. */
    min-width: calc(50% / var(--cover-focus, 0.26));
    object-fit: cover;
    object-position: var(--cover-x, 15%) 0%;
  }
  .hero-cover-copy { width: 100%; text-align: center; }
  .hero-cover-copy .lede { margin-inline: auto; }
  .hero-cover-copy .hero-actions { justify-content: center; }
  .hero-cover-copy .hero-roles { justify-content: center; }
}

@media (max-width: 720px) {
  /* On a phone the band stops at two thirds of the screen, so the page beneath
     it is visible without a scroll and the reader knows there is more. The
     photograph is not shrunk to fit that: it keeps the size it takes from the
     screen's width — wide enough to hold her whole figure without shearing her
     sleeves — and the surplus falls past the band's floor, where the shadow had
     already taken her. Cutting her lower half costs nothing; shrinking her
     would cost the whole picture. */
  .hero-cover {
    min-height: 66vh;
    min-height: 67svh;
    padding-top: clamp(84px, 21vw, 108px);
    padding-bottom: clamp(46px, 9vw, 64px);
  }
  /* max(), so a phone on its side — where two thirds of the height is taller
     than the width-derived frame — still has its floor covered. */
  .hero-cover-media img { height: max(100%, 158vw); }
  /* A phone is too narrow to keep her whole and still leave bare picture under
     her for the words, so the shadow climbs higher here: her face and the top
     of the jacket keep their colour, and everything from her cuffs down settles
     into the dark the title stands on. */
  .hero-cover-media::after {
    background:
      linear-gradient(to bottom, rgba(20, 8, 1, 0.34) 0%, transparent 18%),
      linear-gradient(to bottom, transparent 34%, rgba(37, 12, 1, 0.3) 50%, rgba(37, 12, 1, 0.68) 64%, rgba(32, 10, 1, 0.9) 80%, rgba(28, 9, 1, 0.97) 100%);
  }
  /* And the words carry their own shadow across her sleeves. */
  .hero-cover-copy .display-h,
  .hero-cover-copy .lede {
    text-shadow: 0 1px 2px rgba(18, 7, 1, 0.5), 0 6px 26px rgba(18, 7, 1, 0.7);
  }
  .hero-cover-copy .hero-actions { gap: 12px; margin-top: 1.4rem; }
  .hero-cover .display-h { font-size: clamp(1.55rem, 6.2vw, 2.05rem); margin-bottom: 0; }
  .hero-cover .btn { padding: 12px 22px; font-size: 0.86rem; gap: 8px; }
}

/* ---------- Placeholders (swap with real photography) ---------- */

.ph {
  position: relative;
  width: 100%;
  aspect-ratio: var(--ar, 4 / 5);
  background:
    radial-gradient(120% 90% at 20% 12%, rgba(184, 111, 82, 0.14), transparent 55%),
    radial-gradient(110% 100% at 85% 90%, rgba(57, 81, 68, 0.14), transparent 60%),
    linear-gradient(160deg, var(--sand), var(--cream) 55%, var(--gold-soft));
  overflow: hidden;
}

.ph::before {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(115deg, rgba(51, 48, 43, 0.022) 0 2px, transparent 2px 5px);
}

.ph::after {
  content: attr(data-label);
  position: absolute;
  inset: auto 0 0 0;
  padding: 40px 18px 20px;
  text-align: center;
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(51, 48, 43, 0.45);
  background: linear-gradient(to top, rgba(250, 247, 242, 0.75), transparent);
}

.ph .ph-mark {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -60%) rotate(45deg);
  width: 44px;
  height: 44px;
  border: 1.5px solid rgba(185, 144, 92, 0.55);
}

.ph .ph-mark::after {
  content: "";
  position: absolute;
  inset: 8px;
  background: rgba(184, 111, 82, 0.25);
}

.ph.landscape { --ar: 16 / 10; }
.ph.wide { --ar: 21 / 9; }
.ph.square-soft { --ar: 1 / 1; }
.ph.book { --ar: 2 / 3; }
.ph.tall { --ar: 3 / 4.4; }

.ph.tone-forest {
  background:
    radial-gradient(120% 90% at 20% 12%, rgba(185, 144, 92, 0.2), transparent 55%),
    linear-gradient(160deg, var(--forest-soft), #CBD6CD 60%, var(--sand));
}

.ph.tone-clay {
  background:
    radial-gradient(120% 90% at 80% 15%, rgba(57, 81, 68, 0.12), transparent 55%),
    linear-gradient(160deg, var(--terracotta-soft), var(--sand) 65%, var(--gold-soft));
}

/* ---------- Gallery frame (for film + featured media) ---------- */

.gallery-frame {
  position: relative;
  background: linear-gradient(150deg, #4A423A, #2E2A25);
  padding: clamp(10px, 1.6vw, 16px);
  border-radius: 6px;
  box-shadow: var(--shadow-lift), inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

.gallery-frame .mat {
  background: var(--ivory);
  padding: clamp(12px, 2.2vw, 26px);
  border-radius: 2px;
  box-shadow: inset 0 2px 10px rgba(51, 48, 43, 0.16);
}

.gallery-frame .art {
  position: relative;
  border: 1px solid var(--gold);
  padding: 5px;
  background: var(--charcoal);
}

.gallery-frame .art iframe,
.gallery-frame .art .ph {
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
}

.frame-plaque {
  margin: 26px auto 0;
  width: max-content;
  max-width: 90%;
  text-align: center;
  background: linear-gradient(150deg, var(--gold-soft), #DFCCA8);
  border: 1px solid rgba(185, 144, 92, 0.6);
  border-radius: 4px;
  padding: 10px 26px;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #6E5836;
  box-shadow: var(--shadow-soft);
}

/* ---------- Marquee ---------- */

.marquee {
  overflow: hidden;
  padding-block: 20px;
  border-block: 1px solid var(--line-soft);
  display: flex;
  user-select: none;
}

.marquee .track {
  display: flex;
  flex: none;
  align-items: center;
  gap: 44px;
  padding-right: 44px;
  animation: marquee 36s linear infinite;
  white-space: nowrap;
  font-family: var(--serif);
  font-size: clamp(1.2rem, 2.4vw, 1.75rem);
  font-style: italic;
  color: var(--faint);
}

.marquee .track .gem {
  width: 8px;
  height: 8px;
  background: var(--terracotta);
  transform: rotate(45deg);
  flex: none;
  opacity: 0.7;
}

.marquee:hover .track { animation-play-state: paused; }

@keyframes marquee {
  to { transform: translateX(-100%); }
}

.band-forest .marquee { border-color: rgba(250, 247, 242, 0.12); }
.band-forest .marquee .track { color: rgba(233, 229, 220, 0.75); }

/* ---------- Stats ---------- */

.stat { text-align: center; }

.stat .num {
  font-family: var(--serif);
  font-size: clamp(2.6rem, 5vw, 3.9rem);
  color: var(--ink);
  line-height: 1;
  display: inline-flex;
  align-items: baseline;
  gap: 2px;
}

.stat .num sup { font-size: 0.5em; color: var(--terracotta); }

.stat .label {
  margin-top: 10px;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--faint);
}

.stat::before {
  content: "";
  display: block;
  width: 30px;
  height: 2px;
  background: var(--gold);
  margin: 0 auto 18px;
}

.band-forest .stat .num { color: var(--ivory); }
.band-forest .stat .num sup { color: var(--gold-soft); }
.band-forest .stat .label { color: rgba(233, 229, 220, 0.6); }

/* ---------- Testimonials ---------- */

.quote-mark {
  font-family: var(--serif);
  font-size: 5.5rem;
  line-height: 0.6;
  color: var(--gold);
  display: block;
  margin-bottom: 26px;
}

.testimonial blockquote {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(1.3rem, 2.6vw, 1.85rem);
  font-style: italic;
  line-height: 1.5;
  color: var(--ink);
}

.testimonial .attribution {
  margin-top: 28px;
  display: flex;
  align-items: center;
  gap: 16px;
}

.testimonial .attribution .avatar {
  width: 52px;
  height: 52px;
  border-radius: 999px 999px 8px 8px;
  overflow: hidden;
  flex: none;
}

.testimonial .attribution .who .name {
  font-weight: 600;
  color: var(--ink);
  font-size: 0.98rem;
}

.testimonial .attribution .who .role {
  font-size: 0.85rem;
  color: var(--faint);
}

.band-forest .testimonial blockquote { color: var(--ivory); }
.band-forest .testimonial .who .name { color: var(--ivory); }
.band-forest .testimonial .who .role { color: rgba(233, 229, 220, 0.6); }

/* Rotator */

.rotator { position: relative; }
.rotator .slide { display: none; }
.rotator .slide.active { display: block; animation: fadeUp .7s var(--ease); }

.rotator-dots {
  display: flex;
  gap: 10px;
  margin-top: 34px;
}

.rotator-dots.center { justify-content: center; }

.rotator-dots button {
  width: 10px;
  height: 10px;
  border: 1px solid var(--gold);
  background: transparent;
  transform: rotate(45deg);
  cursor: pointer;
  padding: 0;
  transition: background .3s var(--ease);
}

.rotator-dots button.active, .rotator-dots button:hover { background: var(--gold); }

@keyframes fadeUp {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: translateY(0); }
}

/* ---------- The gratitude wall: real thank-you notes as photo prints ----------
   Handwritten cards and the odd email, kept as they arrived, pinned to the
   cream band at gentle angles. Tapping any one opens it full size to read
   (js/site.js -> initNoteWall). No fabricated quotes; the notes are the words. */
.note-wall {
  margin-top: clamp(30px, 4vw, 52px);
  columns: 3;
  column-gap: clamp(16px, 2vw, 26px);
}

@media (max-width: 1000px) { .note-wall { columns: 2; } }
@media (max-width: 560px)  { .note-wall { columns: 2; column-gap: 14px; } }

.note-card {
  display: block;
  width: 100%;
  break-inside: avoid;
  margin: 0 0 clamp(16px, 2vw, 26px);
  padding: 9px 9px 0;
  border: 0;
  cursor: pointer;
  font: inherit;
  text-align: center;
  background: var(--ivory);
  border-radius: 3px;
  box-shadow: var(--shadow-soft);
  transform: rotate(var(--tilt, 0deg));
  transition: transform .55s var(--ease), box-shadow .55s var(--ease);
}

/* a strip of washi tape holding each note to the wall */
.note-card { position: relative; }
.note-card::before {
  content: "";
  position: absolute;
  top: -11px;
  left: 50%;
  width: clamp(58px, 30%, 92px);
  height: 22px;
  transform: translateX(-50%) rotate(var(--tape, -3deg));
  background: linear-gradient(120deg, rgba(185, 144, 92, 0.32), rgba(233, 220, 198, 0.42));
  border: 1px solid rgba(185, 144, 92, 0.3);
  box-shadow: 0 2px 6px -3px rgba(51, 48, 43, 0.4);
}
.note-card:nth-child(even)::before { --tape: 4deg; }

.note-card img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 1px;
}

.note-cap {
  display: block;
  padding: 11px 8px 13px;
  font-family: var(--serif);
  font-style: italic;
  font-size: 0.9rem;
  line-height: 1.35;
  color: var(--faint);
}
.note-cap em { font-style: normal; font-size: 0.82em; color: var(--gold); }

.note-card:hover,
.note-card:focus-visible {
  transform: rotate(0deg) translateY(-8px) scale(1.025);
  box-shadow: var(--shadow-lift);
  z-index: 3;
  outline: none;
}
.note-card:focus-visible { box-shadow: var(--shadow-lift), 0 0 0 3px var(--gold); }

html[data-theme="dark"] .note-card { background: #2A251E; }
html[data-theme="dark"] .note-card::before {
  background: linear-gradient(120deg, rgba(201, 168, 118, 0.28), rgba(85, 70, 44, 0.4));
  border-color: rgba(201, 168, 118, 0.24);
}

@media (prefers-reduced-motion: reduce) {
  .note-card { transition: none; }
  .note-card:hover, .note-card:focus-visible { transform: rotate(0deg); }
}

/* ---------- The note lightbox: read a note full size ---------- */
.note-lightbox {
  position: fixed;
  inset: 0;
  z-index: 140;
  display: grid;
  place-items: center;
  padding: 4vh 5vw;
  background: rgba(33, 28, 23, 0.86);
  -webkit-backdrop-filter: blur(5px);
  backdrop-filter: blur(5px);
  opacity: 0;
  visibility: hidden;
  transition: opacity .35s var(--ease), visibility .35s var(--ease);
}
.note-lightbox.open { opacity: 1; visibility: visible; }

.note-lightbox figure {
  margin: 0;
  display: flex;
  flex-direction: column;
  max-width: min(560px, 92vw);
  max-height: 92vh;
  padding: 12px 12px 0;
  background: var(--ivory);
  border-radius: 3px;
  box-shadow: var(--shadow-lift);
  transform: scale(0.94);
  transition: transform .4s var(--ease);
}
.note-lightbox.open figure { transform: scale(1); }
html[data-theme="dark"] .note-lightbox figure { background: #2A251E; }

.note-lightbox img {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 76vh;
  object-fit: contain;
  border-radius: 1px;
}

.note-lightbox figcaption {
  padding: 12px 10px 14px;
  text-align: center;
  font-family: var(--serif);
  font-style: italic;
  font-size: 0.92rem;
  color: var(--faint);
}
.note-lightbox figcaption em { font-style: normal; color: var(--gold); }

.note-lightbox .lb-close {
  position: absolute;
  top: max(16px, 3vh);
  right: max(16px, 3vw);
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1.5px solid rgba(250, 247, 242, 0.6);
  background: rgba(33, 28, 23, 0.4);
  color: var(--ivory);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  transition: background .3s var(--ease), transform .3s var(--ease);
}
.note-lightbox .lb-close:hover { background: var(--wine); border-color: var(--wine); transform: rotate(90deg); }

@media (prefers-reduced-motion: reduce) {
  .note-lightbox, .note-lightbox figure { transition: opacity .2s linear; }
  .note-lightbox figure { transform: none; }
  .note-lightbox .lb-close:hover { transform: none; }
}

/* ---------- Horizontal gallery strip ---------- */

.strip {
  display: flex;
  gap: clamp(18px, 2.5vw, 30px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 18px;
  scrollbar-width: none;
}

.strip::-webkit-scrollbar { display: none; }

.strip.auto { scroll-snap-type: none; }

.strip > * {
  flex: none;
  width: min(340px, 74vw);
  scroll-snap-align: start;
}

.strip figure { margin: 0; }

.strip figcaption {
  margin-top: 14px;
  font-size: 0.85rem;
  color: var(--faint);
  font-style: italic;
  font-family: var(--serif);
}

.strip .shot {
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
  transition: transform .5s var(--ease), box-shadow .5s var(--ease);
}

.strip figure:hover .shot { transform: translateY(-6px); box-shadow: var(--shadow-lift); }

.strip figure:nth-child(odd) .shot { border-radius: var(--arch); }

.strip-nav { display: flex; gap: 12px; }

.strip-nav button {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1.5px solid var(--forest);
  background: transparent;
  color: var(--forest);
  font-size: 1.1rem;
  cursor: pointer;
  transition: background .3s var(--ease), color .3s var(--ease), transform .3s var(--ease);
}

.strip-nav button:hover { background: var(--forest); color: var(--ivory); transform: translateY(-2px); }

/* ---------- Editorial feature rows ---------- */

.feature-row { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(40px, 6vw, 90px); align-items: center; }
.feature-row + .feature-row { margin-top: clamp(70px, 9vw, 120px); }
.feature-row .media { position: relative; }

@media (max-width: 900px) {
  .feature-row { grid-template-columns: 1fr; }
  .feature-row .media { order: -1; }
}

/* ---------- Brand trio ---------- */

.brand-trio { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(30px, 4vw, 60px); }

@media (max-width: 900px) { .brand-trio { gap: clamp(16px, 2.6vw, 30px); } }

@media (max-width: 720px) {
  /* Chapter One keeps its three doors on one line, as on the desktop: the
     arches come down to a third of the width and the type comes down with
     them, so the trio reads as one row instead of three screens of scrolling.
     A third of a phone is narrow, so the doorway is given its own height
     rather than an aspect ratio, leaving the picture something to show above
     the words that sit in its lower edge. */
  .brand-trio { grid-template-columns: repeat(3, 1fr); gap: 11px; --arch-h: clamp(180px, 54vw, 260px); }
  .brand-trio .arch-img { height: var(--arch-h); }
  .brand-trio .brand-block h3 { margin-top: calc(var(--arch-h) * -0.22); font-size: 0.9rem; }
  .brand-trio .brand-block p { font-size: 0.7rem; line-height: 1.45; margin-top: 6px; }
  .brand-trio .textlink { font-size: 0.74rem; }
  .brand-trio .textlink .arrow { display: none; }
}

.brand-block { text-align: center; }

.brand-block .arch-img {
  border-radius: var(--arch);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
  transition: transform .5s var(--ease), box-shadow .5s var(--ease);
}

.brand-block:hover .arch-img { transform: translateY(-8px); box-shadow: var(--shadow-lift); }

.brand-block h3 { margin-top: 26px; }

/* Each door carries its own words inside the picture: the arch dissolves over
   its last third the way the hero band does, and the name and description sit
   in the clearing it leaves, so only the action stands outside the frame. */
.brand-block .arch-img {
  box-shadow: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 0 46%, rgba(0, 0, 0, 0.74) 60%, rgba(0, 0, 0, 0.3) 71%, transparent 80%);
  mask-image: linear-gradient(to bottom, #000 0 46%, rgba(0, 0, 0, 0.74) 60%, rgba(0, 0, 0, 0.3) 71%, transparent 80%);
}

/* The lift moves the whole card now, so the picture cannot slide out from
   under the words that sit on it. */
.brand-block { transition: transform .5s var(--ease); }
.brand-block:hover { transform: translateY(-8px); }
.brand-block:hover .arch-img { transform: none; box-shadow: none; }
.brand-block h3 { margin-top: -24%; }

/* ---------- The two-ink wordmarks ----------
   Busayo's own lockup and the Our Story, Our Voice mark are transparent PNGs
   drawn in two inks, so they sit on the page rather than on a slab of their
   own: the dark one on a light page, the light one once the site turns dark or
   the mark lands on a dark ground. */
.osov-mark,
.bd-mark { display: block; width: 100%; height: auto; }
.osov-mark.on-dark,
.bd-mark.on-dark { display: none; }
html[data-theme="dark"] .osov-mark.on-light,
html[data-theme="dark"] .bd-mark.on-light { display: none; }
html[data-theme="dark"] .osov-mark.on-dark,
html[data-theme="dark"] .bd-mark.on-dark { display: block; }

/* In the tray the mark takes the wordmark's place and follows the tray's own
   inversion over the hero photograph as well as the theme. It is sized by
   height, since the lockup is two lines deep and the tray is shallow. */
.brand-word-mark .osov-mark { width: auto; height: clamp(28px, 3.2vw, 38px); }

/* Busayo's lockup is one deep line rather than two, so the same optical weight
   wants a shorter box than the platform's stacked mark. */
.brand-word-bd .bd-mark { width: auto; height: clamp(21px, 2.4vw, 27px); }

/* The roundel is a badge rather than a line of type, so it is set as tall as
   the 66px tray allows: any smaller and the name inside it stops reading. */
.brand-word-roundel .mrs-mark { display: block; width: auto; height: clamp(44px, 4.6vw, 54px); }
#site-header.on-dark .osov-mark.on-light,
#site-header.on-dark .bd-mark.on-light { display: none; }
#site-header.on-dark .osov-mark.on-dark,
#site-header.on-dark .bd-mark.on-dark { display: block; }

/* In the trio the mark stands in the middle of the arch the photographs fill. */
.wordmark-tile {
  aspect-ratio: 4 / 5;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 12%;
}

.brand-block .tm { font-size: 0.55em; vertical-align: super; color: var(--gold); }

.brand-block p { max-width: 34ch; margin-inline: auto; color: var(--body); }

/* ============ Chapter Three — the day/night impact scene ============
   The forest band becomes a slow living landscape. On one 40s loop the sky
   drifts from a light sunny green to a very dark night green while a sun and
   then a moon arc over the horizon, stars surface after dusk, and children
   run along the ground in front of a treeline. Content sits over the deeper
   lower band so the ivory text stays legible through every phase. With motion
   off it rests as a still sunny day: sun overhead, kids mid-stride. */

/* Endless scenes rest while they are off screen. js/site.js -> initIdleScenes
   hangs this class on anything that would otherwise paint forever in a part
   of the page nobody is looking at. Paused, not stopped: the sky picks the
   hour back up where it left it rather than snapping to dawn. */
.scene-asleep,
.scene-asleep *,
.scene-asleep::before,
.scene-asleep::after,
.scene-asleep *::before,
.scene-asleep *::after {
  animation-play-state: paused !important;
}

.impact-scene {
  position: relative;
  overflow: hidden;
  min-height: clamp(600px, 82vh, 780px);
  display: flex;
  align-items: center;
}
.impact-scene > .wrap { position: relative; z-index: 2; width: 100%; }
.impact-scene h2,
.impact-scene .stat .num { text-shadow: 0 1px 12px rgba(9, 16, 12, 0.4); }
.impact-scene .stat .label,
.impact-scene .chapter-no { text-shadow: 0 1px 9px rgba(9, 16, 12, 0.4); }

.scene { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.scene > * { position: absolute; }

/* animated sky wash — light sunny green at noon to deep night green.
   The wash is two stacked panes rather than one animated colour: animating
   background-color repainted the whole band on the CPU every frame for as
   long as the scene was on screen, while fading a night pane over a fixed
   day pane is pure compositor work. The opacity curve traces the same
   colours the old keyframes named. */
.scene-sky-fill { inset: 0; z-index: 0; background: #87A97B; }
.scene-sky-fill::after {
  content: "";
  position: absolute;
  inset: 0;
  background: #0C1610;
  opacity: 0;
  animation: sceneNight 40s ease-in-out infinite;
}

/* stars, upper sky */
.scene-stars { top: 0; left: 0; width: 100%; height: 60%; z-index: 1; opacity: 0; animation: sceneStars 40s ease-in-out infinite; }
.scene-stars .tw { animation: sceneTwinkle 3.4s ease-in-out infinite; }

/* warm sunrise / sunset glow along the horizon */
.scene-glow {
  inset: 0; z-index: 1; opacity: 0;
  background: radial-gradient(130% 62% at 50% 94%, rgba(184, 111, 82, 0.55), rgba(201, 159, 91, 0.16) 42%, transparent 72%);
  animation: sceneGlow 40s ease-in-out infinite;
}

/* the celestial arc — a slow wheel carrying sun (up) and moon (down) */
.scene-orbit {
  left: 50%; top: 100%; z-index: 2;
  height: 172%; aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%) rotate(0deg);
  animation: sceneOrbit 40s linear infinite;
}
.scene-sun, .scene-moon { position: absolute; left: 50%; width: 68px; height: 68px; }
.scene-sun { top: 0; transform: translate(-50%, -50%); }
.scene-moon { bottom: 0; transform: translate(-50%, 50%); }
.scene-sun svg, .scene-moon svg { display: block; width: 100%; height: 100%; overflow: visible; }

/* ground: transparent up top so the sky shows, deep forest below so the
   bodies set into the horizon and the ivory text keeps its footing */
.scene-ground {
  inset: 0; z-index: 3;
  background: linear-gradient(to bottom, transparent 30%, rgba(28, 40, 32, 0.6) 52%, #1A2620 74%);
}

.scene-trees { bottom: 0; left: 0; width: 100%; height: 46%; z-index: 4; }

/* children running along the ground, evenly spaced across the band */
.kids-run { bottom: 2.4%; left: 0; width: 100%; z-index: 5; overflow: visible; }
.kids-run .kid path { fill: none; stroke: currentColor; stroke-width: 4.5; stroke-linecap: round; stroke-linejoin: round; }
.kids-run .kid .head { fill: currentColor; stroke: none; }
.kids-run .kid-inner { animation: kidBob var(--dur, 0.52s) ease-in-out infinite; animation-delay: var(--d, 0s); }
.kids-run .pose-a { animation: kidPoseA var(--dur, 0.52s) linear infinite; animation-delay: var(--d, 0s); }
.kids-run .pose-b { animation: kidPoseB var(--dur, 0.52s) linear infinite; animation-delay: var(--d, 0s); }

@keyframes sceneOrbit {
  from { transform: translate(-50%, -50%) rotate(0deg); }
  to   { transform: translate(-50%, -50%) rotate(360deg); }
}
@keyframes sceneNight {
  0%   { opacity: 0; }
  15%  { opacity: 0.1; }
  25%  { opacity: 0.48; }
  40%  { opacity: 0.94; }
  50%  { opacity: 1; }
  60%  { opacity: 0.94; }
  75%  { opacity: 0.48; }
  85%  { opacity: 0.1; }
  100% { opacity: 0; }
}
@keyframes sceneGlow {
  0%, 12% { opacity: 0; }
  25%     { opacity: 0.9; }
  38%, 62% { opacity: 0; }
  75%     { opacity: 0.9; }
  88%, 100% { opacity: 0; }
}
@keyframes sceneStars {
  0%, 22%  { opacity: 0; }
  40%, 60% { opacity: 0.92; }
  78%, 100% { opacity: 0; }
}
@keyframes sceneTwinkle {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 1; }
}
@keyframes kidBob {
  0%, 100% { transform: translateY(0); }
  25%      { transform: translateY(-3px); }
  50%      { transform: translateY(0); }
  75%      { transform: translateY(-3px); }
}
@keyframes kidPoseA { 0%, 49.9% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes kidPoseB { 0%, 49.9% { opacity: 0; } 50%, 100% { opacity: 1; } }

@media (max-width: 640px) {
  .impact-scene { min-height: clamp(520px, 90vh, 680px); }
  .scene-sun, .scene-moon { width: 54px; height: 54px; }
}

@media (prefers-reduced-motion: reduce) {
  .scene-sky-fill, .scene-sky-fill::after, .scene-glow, .scene-stars, .scene-orbit,
  .kids-run .kid-inner, .kids-run .pose-a, .kids-run .pose-b { animation: none !important; }
  .scene-sky-fill::after, .scene-glow, .scene-stars { opacity: 0; }
  .kids-run .pose-b { opacity: 0; }
}

/* ---------- Lists with gems ---------- */

.gem-list { list-style: none; padding: 0; margin: 0 0 1.4rem; }

.gem-list li {
  position: relative;
  padding-left: 28px;
  margin-bottom: 12px;
}

.gem-list li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 0.62em;
  width: 7px;
  height: 7px;
  background: var(--terracotta);
  transform: rotate(45deg);
}

/* ---------- Detail rows (services, catalog, FAQ) ---------- */

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

.detail-row {
  display: grid;
  grid-template-columns: 72px 1fr auto;
  gap: clamp(18px, 3vw, 40px);
  align-items: baseline;
  padding: clamp(24px, 3.4vw, 40px) 0;
  border-bottom: 1px solid var(--line);
  transition: background .3s var(--ease);
}

.detail-row .index {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.2rem;
  color: var(--gold);
}

.detail-row h3, .detail-row h4 { margin-bottom: 0.35em; }
.detail-row p { margin-bottom: 0; max-width: 60ch; }

.detail-row .aside {
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--faint);
  text-align: right;
  white-space: nowrap;
}

@media (max-width: 720px) {
  .detail-row { grid-template-columns: 1fr; gap: 8px; }
  .detail-row .aside { text-align: left; }
}

/* ---------- FAQ ---------- */

details.faq {
  border-bottom: 1px solid var(--line);
  padding: 6px 0;
}

details.faq summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 20px;
  padding: 20px 0;
  font-family: var(--serif);
  font-size: 1.2rem;
  color: var(--ink);
}

details.faq summary::-webkit-details-marker { display: none; }

details.faq summary .indicator {
  flex: none;
  width: 12px;
  height: 12px;
  position: relative;
}

details.faq summary .indicator::before,
details.faq summary .indicator::after {
  content: "";
  position: absolute;
  background: var(--terracotta);
  transition: transform .3s var(--ease);
}

details.faq summary .indicator::before { inset: 5px 0; }
details.faq summary .indicator::after { inset: 0 5px; }

details.faq[open] summary .indicator::after { transform: rotate(90deg); }

details.faq .faq-body { padding: 0 0 22px; max-width: 68ch; }

/* ---------- Forms ---------- */

.field { margin-bottom: 22px; }

.field label {
  display: block;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 8px;
}

.field input, .field textarea, .field select {
  width: 100%;
  font-family: var(--sans);
  font-size: 1rem;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1.5px solid var(--line);
  padding: 12px 2px;
  transition: border-color .3s var(--ease);
  border-radius: 0;
}

.field input:focus, .field textarea:focus, .field select:focus {
  outline: none;
  border-bottom-color: var(--terracotta);
}

.field textarea { resize: vertical; min-height: 120px; }

/* Newsletter inline form */

.newsletter-form {
  display: flex;
  gap: 14px;
  max-width: 560px;
  margin-inline: auto;
}

.newsletter-form input {
  flex: 1;
  font-size: 1rem;
  background: transparent;
  border: 0;
  border-bottom: 1.5px solid var(--line);
  padding: 14px 4px;
  color: var(--ink);
}

.newsletter-form input:focus { outline: none; border-bottom-color: var(--terracotta); }

.band-forest .newsletter-form input {
  color: var(--ivory);
  border-bottom-color: rgba(250, 247, 242, 0.3);
}

.band-forest .newsletter-form input::placeholder { color: rgba(233, 229, 220, 0.5); }
.band-forest .newsletter-form input:focus { border-bottom-color: var(--gold-soft); }

@media (max-width: 560px) { .newsletter-form { flex-direction: column; } }

/* ---------- Tabs (contact forms, license toggles) ---------- */

.tab-row {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 26px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 34px;
}

.tab-row button {
  background: none;
  border: 0;
  font-family: var(--sans);
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--faint);
  padding: 12px 2px;
  cursor: pointer;
  position: relative;
  transition: color .3s var(--ease);
}

.tab-row button::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  height: 2px;
  background: var(--terracotta);
  transform: scaleX(0);
  transition: transform .3s var(--ease);
}

.tab-row button.active { color: var(--ink); }
.tab-row button.active::after { transform: scaleX(1); }

.tab-panel { display: none; }
.tab-panel.active { display: block; animation: fadeUp .5s var(--ease); }

/* ---------- Product / catalog entries ---------- */

.catalog-entry {
  display: grid;
  grid-template-columns: minmax(180px, 260px) 1fr;
  gap: clamp(26px, 4vw, 56px);
  padding: clamp(34px, 5vw, 60px) 0;
  border-bottom: 1px solid var(--line);
  align-items: center;
}

.catalog-entry:first-child { border-top: 1px solid var(--line); }

.catalog-entry .cover {
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
  transition: transform .5s var(--ease);
}

.catalog-entry:hover .cover { transform: translateY(-6px) rotate(-1deg); }

.catalog-entry .kind {
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 10px;
}

.catalog-entry .pricing {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 34px;
  margin: 18px 0 22px;
  font-size: 0.92rem;
}

.catalog-entry .pricing .price b {
  font-family: var(--serif);
  font-size: 1.25rem;
  color: var(--ink);
  font-weight: 600;
}

.catalog-entry .pricing .price span {
  display: block;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--faint);
}

@media (max-width: 720px) {
  .catalog-entry { grid-template-columns: 1fr; }
  .catalog-entry .cover { max-width: 260px; }
}

/* ---------- Modal (activation / checkout) ---------- */

.modal-veil {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: rgba(42, 61, 51, 0.55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  display: none;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.modal-veil.open { display: flex; }

.modal-card {
  background: var(--ivory);
  border-radius: var(--radius);
  max-width: 560px;
  width: 100%;
  max-height: 88vh;
  overflow-y: auto;
  padding: clamp(30px, 5vw, 52px);
  position: relative;
  box-shadow: var(--shadow-lift);
  animation: fadeUp .45s var(--ease);
}

.modal-card .modal-close {
  position: absolute;
  top: 18px;
  right: 18px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: transparent;
  font-size: 1rem;
  cursor: pointer;
  color: var(--ink);
  transition: background .3s var(--ease);
}

.modal-card .modal-close:hover { background: var(--cream); }

.activation-code {
  font-family: "SF Mono", "Menlo", monospace;
  font-size: clamp(1.2rem, 3vw, 1.6rem);
  letter-spacing: 0.14em;
  text-align: center;
  color: var(--forest);
  background: var(--cream);
  border: 1px dashed var(--gold);
  border-radius: var(--radius-sm);
  padding: 20px;
  margin: 22px 0;
  user-select: all;
}

/* ---------- Timeline ---------- */

.timeline { position: relative; padding-left: 34px; }

.timeline::before {
  content: "";
  position: absolute;
  left: 8px;
  top: 6px;
  bottom: 6px;
  width: 1.5px;
  background: linear-gradient(var(--gold), var(--terracotta), var(--forest));
  opacity: 0.5;
}

.timeline .moment { position: relative; padding-bottom: clamp(34px, 4vw, 54px); }
.timeline .moment:last-child { padding-bottom: 0; }

.timeline .moment::before {
  content: "";
  position: absolute;
  left: -30.5px;
  top: 8px;
  width: 9px;
  height: 9px;
  background: var(--terracotta);
  transform: rotate(45deg);
  box-shadow: 0 0 0 5px var(--ivory);
}

.timeline .moment .when {
  font-family: var(--serif);
  font-style: italic;
  color: var(--gold);
  font-size: 1.05rem;
  margin-bottom: 4px;
}

.timeline .moment h4 { margin-bottom: 0.3em; }
.timeline .moment p { margin-bottom: 0; max-width: 58ch; }

/* ---------- Wopara embed shell ---------- */

.portal-shell {
  border-radius: 18px;
  padding: 3px;
  background: linear-gradient(140deg, var(--gold), var(--terracotta) 40%, var(--forest));
  box-shadow: var(--shadow-lift);
}

.portal-shell iframe {
  width: 100%;
  height: 640px;
  border: 0;
  border-radius: 16px;
  background: var(--cream);
}

/* ---------- Motion budget ----------
   Per-element scroll reveals were retired deliberately: content is simply
   present, and motion is reserved for a few earned moments (the thread,
   the loom, the proverb, the counters, the two scrubbed scenes and the
   arrival ritual). [data-reveal] attributes in markup are inert. */

/* ---------- Page intro (interior pages) ---------- */

.page-intro {
  padding-top: clamp(150px, 17vw, 210px);
  padding-bottom: clamp(50px, 6vw, 80px);
  position: relative;
  overflow: hidden;
}

.page-intro::before {
  content: "";
  position: absolute;
  top: -240px;
  right: -160px;
  width: 560px;
  height: 560px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(185, 144, 92, 0.14), transparent 65%);
  pointer-events: none;
}

.breadcrumb {
  font-size: 0.8rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 1.6rem;
  display: flex;
  gap: 12px;
  align-items: center;
}

.breadcrumb a { color: var(--faint); font-weight: 600; }
.breadcrumb a:hover { color: var(--terracotta); }
.breadcrumb .sep { color: var(--gold); }

/* ---------- Footer ---------- */

#site-footer {
  background: var(--cream);
  border-top: 1px solid var(--line-soft);
  padding: clamp(60px, 8vw, 100px) 0 40px;
  font-size: 0.95rem;
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1.4fr;
  gap: clamp(36px, 5vw, 70px);
  margin-bottom: 60px;
}

@media (max-width: 980px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 600px) { .footer-grid { grid-template-columns: 1fr; } }

.footer-brand .brand { margin-bottom: 16px; }
.footer-brand .brand-name { font-size: 1.75rem; }

.footer-brand p { color: var(--faint); max-width: 34ch; font-size: 0.92rem; }

#site-footer h5 {
  font-family: var(--sans);
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink);
  margin: 0 0 18px;
}

#site-footer ul { list-style: none; margin: 0; padding: 0; }
#site-footer ul li { margin-bottom: 10px; }
#site-footer ul a { color: var(--body); }
#site-footer ul a:hover { color: var(--terracotta); }

.footer-news p { color: var(--faint); font-size: 0.92rem; }

.footer-news form { display: flex; gap: 10px; margin-top: 6px; }

.footer-news input {
  flex: 1;
  background: transparent;
  border: 0;
  border-bottom: 1.5px solid var(--line);
  padding: 10px 2px;
  font-size: 0.95rem;
  color: var(--ink);
}

.footer-news input:focus { outline: none; border-bottom-color: var(--terracotta); }

.socials { display: flex; gap: 14px; margin-top: 22px; flex-wrap: wrap; }

.socials a {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--line);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink);
  transition: border-color .3s var(--ease), background .3s var(--ease), color .3s var(--ease), transform .3s var(--ease);
}

.socials a:hover {
  background: var(--forest);
  border-color: var(--forest);
  color: var(--ivory);
  transform: translateY(-3px);
}

.socials svg { width: 17px; height: 17px; }

.footer-base {
  border-top: 1px solid var(--line-soft);
  padding-top: 28px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px 30px;
  justify-content: space-between;
  align-items: center;
  font-size: 0.84rem;
  color: var(--faint);
}

.footer-base nav { display: flex; flex-wrap: wrap; gap: 8px 22px; }
.footer-base a { color: var(--faint); }
.footer-base a:hover { color: var(--terracotta); }

/* ---------- Anchor landings ---------- */

/* Hashes now carry the weight the contact page used to: every enquiry form,
   the mediation and speaking chapters, and each catalogue entry are reached
   by anchor. The glass tray floats over the page, so a target has to stop
   clear of it rather than arrive underneath. */
section[id],
article[id],
.tab-row button[id] {
  scroll-margin-top: clamp(96px, 11vw, 128px);
}

/* ---------- Utilities ---------- */

.mt-0 { margin-top: 0; }
.mt-2 { margin-top: 2rem; }
.mt-3 { margin-top: 3rem; }
.mb-2 { margin-bottom: 2rem; }
.maxw { max-width: 68ch; }
.maxw-c { max-width: 68ch; margin-inline: auto; }

.note {
  font-size: 0.9rem;
  color: var(--faint);
  border-left: 2px solid var(--gold);
  padding: 4px 0 4px 18px;
  font-style: italic;
  font-family: var(--serif);
}

.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 30px;
  margin-bottom: clamp(40px, 5vw, 64px);
}

.section-head h2 { margin-bottom: 0; }

@media (max-width: 720px) {
  .section-head { flex-direction: column; align-items: flex-start; }
}

/* ==========================================================================
   Signature layer: the woven thread, storybook typesetting
   ========================================================================== */

/* ---------- The woven thread ----------
   A single terracotta thread, drawn by scroll, stitches every page together.
   Built by js/site.js; hidden on small screens where the margins vanish. */

#story-thread {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  pointer-events: none;
  opacity: 0.62;
  /* Its own compositor layer. The thread redraws on every scroll frame, and
     without this it shared a layer with the page itself — so each redraw
     threw away the rasterised tiles of everything on screen and painted the
     whole viewport again. Alone on its own mostly-empty layer, a redraw
     costs a thin line, not the page. */
  will-change: transform;
  transform: translateZ(0);
}

#story-thread .thread-line {
  fill: none;
  stroke: var(--terracotta);
  stroke-width: 1.5;
  stroke-linecap: round;
}

#story-thread .thread-shadow {
  fill: none;
  stroke: var(--gold);
  stroke-width: 1.5;
  stroke-linecap: round;
  opacity: 0.35;
}

#story-thread .thread-line.navy {
  stroke: var(--navy);
  opacity: 0.42;
}

#story-thread .gem-node {
  fill: var(--gold);
  stroke: var(--ivory);
  stroke-width: 2;
  opacity: 0;
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
  transform-origin: center;
  transform-box: fill-box;
  transform: rotate(45deg) scale(0.4);
}

#story-thread .gem-node.lit {
  opacity: 1;
  transform: rotate(45deg) scale(1);
}

@media (max-width: 1080px) {
  #story-thread { display: none; }
}

/* ---------- Storybook typesetting ---------- */

.chapter-no {
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--gold);
  margin-bottom: 12px;
  letter-spacing: 0.06em;
}

.chapter-no.center, .center .chapter-no { text-align: center; }

.chapter-no::after {
  content: "";
  display: inline-block;
  width: 5px;
  height: 5px;
  background: var(--terracotta);
  transform: rotate(45deg) translateY(-4px);
  margin-left: 12px;
  opacity: 0.7;
}

.band-forest .chapter-no { color: var(--gold-soft); }

.dropcap::first-letter {
  font-family: var(--serif);
  font-size: 3.6em;
  line-height: 0.78;
  float: left;
  padding: 8px 14px 0 0;
  color: var(--terracotta);
  font-style: normal;
  font-weight: 500;
}

.colophon {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: clamp(34px, 5vw, 56px) 0 0;
  background: var(--ivory);
}

.colophon::before, .colophon::after {
  content: "";
  height: 1px;
  width: min(90px, 16vw);
  background: linear-gradient(to right, transparent, var(--line));
}

.colophon::after { background: linear-gradient(to left, transparent, var(--line)); }

.colophon .gem {
  width: 6px;
  height: 6px;
  background: var(--gold);
  transform: rotate(45deg);
}

.colophon .gem:nth-child(2) { background: var(--terracotta); width: 8px; height: 8px; }
.colophon .gem:nth-child(3) { background: var(--forest); }

/* ==========================================================================
   Experience engine: grain, preloader, masked type, unveils, cursor, cadence
   ========================================================================== */

/* ---------- Film grain (unifies every section, kills the flat look) ---------- */

.grain {
  position: fixed;
  inset: 0;
  z-index: 80;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.72' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
  background-repeat: repeat;
  /* Compositor layer of its own, so blending the noise over the page never
     asks the page's own tiles to repaint. */
  transform: translateZ(0);
}

/* ---------- Reading progress thread ---------- */

#progress-thread {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 2px;
  background: var(--gold);
  transform-origin: 0 50%;
  transform: scaleX(0);
  z-index: 96;
  pointer-events: none;
}

/* ---------- Preloader (once per session) ---------- */

.preloader {
  position: fixed;
  inset: 0;
  z-index: 999;
  background: var(--cream);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 26px;
}

.preloader .pre-mark {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 26px;
  transition: transform 0.45s cubic-bezier(0.76, 0, 0.24, 1), opacity 0.45s cubic-bezier(0.76, 0, 0.24, 1);
}

.preloader .brand-word { align-items: center; }
.preloader .brand-name { font-size: clamp(3rem, 9vw, 4.4rem); }

.preloader .pre-kicker {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--gold);
  display: flex;
  align-items: center;
  gap: 14px;
}

.preloader .pre-kicker::before, .preloader .pre-kicker::after {
  content: "";
  width: 30px;
  height: 1px;
  background: var(--gold);
  opacity: 0.6;
}

.preloader .pre-thread {
  width: min(220px, 40vw);
  height: 1.5px;
  background: var(--line-soft);
  overflow: hidden;
}

.preloader .pre-thread i {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--terracotta);
  transform: scaleX(0);
  transform-origin: 0 50%;
}

.preloader.arming .pre-thread i { transform: scaleX(1); transition: transform 1.15s cubic-bezier(0.65, 0, 0.35, 1); }
.preloader.leaving .pre-mark { transform: translateY(-34px); opacity: 0; }
.preloader.lift { transform: translateY(-101%); transition: transform 1s cubic-bezier(0.87, 0, 0.13, 1); }
html.no-preloader .preloader { display: none; }
body.is-loading { overflow: hidden; }

/* ---------- Masked line reveals (letterpress type) ---------- */

.pre-split { visibility: hidden; }

.msk {
  display: block;
  overflow: hidden;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}

.msk-in {
  display: block;
  transform: translateY(118%);
  will-change: transform;
}

.rise .msk-in {
  transform: translateY(0);
  transition: transform 0.95s cubic-bezier(0.22, 1, 0.36, 1);
  transition-delay: calc(var(--l, 0) * 90ms);
}

/* ---------- Image unveils (colour panel slides off, image settles) ---------- */

.unveil { position: relative; }

.unveil::after {
  content: "";
  position: absolute;
  inset: -1px;
  background: var(--terracotta-soft);
  z-index: 2;
  transition: transform 1.1s cubic-bezier(0.19, 1, 0.22, 1);
}

.unveil.u2::after { background: var(--gold-soft); }
.unveil.u3::after { background: var(--forest-soft); }

.unveil > :first-child {
  transform: scale(1.14);
  transition: transform 1.35s cubic-bezier(0.19, 1, 0.22, 1);
}

.unveil.done::after { transform: translateY(-103%); }
.unveil.done > :first-child { transform: scale(1); }

/* ---------- Display headline ----------
   Sized for the hero's right hand column, where it runs four or five lines
   against the photograph's negative space. */
.display-h {
  font-size: clamp(2.25rem, 4.3vw, 3.75rem);
  line-height: 1.04;
  letter-spacing: -0.02em;
  position: relative;
  z-index: 2;
  margin-bottom: 1.05rem;
  text-wrap: balance;
}

@media (max-width: 900px) {
  .display-h { font-size: clamp(2.2rem, 8.4vw, 3.1rem); }
}

/* ---------- Proverb interlude (the griot's pause) ---------- */

.proverb {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  text-align: center;
  padding-block: clamp(6rem, 14vh, 10rem);
  padding-bottom: clamp(9rem, 22vh, 15rem);
}

.proverb .wrap {
  position: relative;
  z-index: 2;
}

/* ---------- Rain: the section weeps for the river ---------- */

.proverb .rain {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}

.proverb .rain .drop {
  position: absolute;
  top: 0;
  width: 1px;
  height: var(--len, 12vh);
  border-radius: 1px;
  opacity: var(--op, 0.3);
  background: linear-gradient(
    to bottom,
    rgba(222, 233, 227, 0) 0%,
    rgba(222, 233, 227, 0.7) 55%,
    rgba(222, 233, 227, 0) 100%
  );
  animation: proverb-rain linear infinite;
  will-change: transform;
}

@keyframes proverb-rain {
  0% { transform: translate(0, -25vh); }
  100% { transform: translate(-4vh, 125vh); }
}

/* ---------- River: it flows along the bottom, never forgetting ---------- */

.proverb .river {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: clamp(72px, 13vh, 130px);
  z-index: 1;
  pointer-events: none;
  overflow: hidden;
}

.proverb .river svg {
  display: block;
  width: 100%;
  height: 100%;
}

.proverb .river-layer,
.proverb .river-line {
  will-change: transform;
}

.proverb .river-back {
  fill: rgba(83, 122, 110, 0.45);
  animation: river-flow 19s linear infinite;
}

.proverb .river-mid {
  fill: rgba(96, 140, 126, 0.6);
  animation: river-flow 13s linear infinite;
}

.proverb .river-front {
  fill: rgba(120, 165, 148, 0.85);
  animation: river-flow 9s linear infinite;
}

.proverb .river-line {
  fill: none;
  stroke: rgba(233, 220, 198, 0.35);
  stroke-width: 1.5;
  animation: river-flow 9s linear infinite;
}

@keyframes river-flow {
  from { transform: translateX(0); }
  to { transform: translateX(-1440px); }
}

.proverb .yo {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.9rem, 4.2vw, 3.3rem);
  line-height: 1.35;
  color: var(--ivory);
  max-width: 24ch;
  margin: 0 auto;
}

.proverb .yo .w {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.35em);
}

.proverb.spoken .yo .w {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.55s ease-out, transform 0.55s ease-out;
  transition-delay: calc(var(--w, 0) * 90ms);
}

.proverb .tr {
  margin-top: 30px;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--gold-soft);
}

.proverb .attr {
  margin-top: 10px;
  font-size: 0.8rem;
  color: rgba(233, 229, 220, 0.55);
  font-style: italic;
  font-family: var(--serif);
}

/* ---------- Bridge CTA (the final act before the footer) ---------- */

.bridge-cta {
  text-align: center;
  padding: clamp(80px, 11vw, 150px) var(--gutter) clamp(30px, 4vw, 50px);
  background: var(--ivory);
}

.bridge-cta .small-line {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 20px;
}

.bridge-cta a {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(2.4rem, 6.6vw, 5.4rem);
  line-height: 1.1;
  color: transparent;
  -webkit-text-stroke: 1.2px var(--forest);
  transition: color 0.5s var(--ease);
  display: inline-block;
  border: 0;
}

.bridge-cta a:hover { color: var(--forest); }

/* ---------- Footer meta: dual clocks + colophon ---------- */


.footer-meta {
  border-top: 1px solid var(--line-soft);
  margin-top: 28px;
  padding-top: 24px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 30px;
  justify-content: space-between;
  font-size: 0.8rem;
  color: var(--faint);
}

.footer-meta .clocks {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
  display: flex;
  gap: 18px;
}

.footer-meta .clocks b { color: var(--gold); font-weight: 600; }
.footer-meta .colophon-line { font-style: italic; font-family: var(--serif); }

/* ---------- The Loom ----------
   The old scrolling ticker is gone. Here the words stand still, in
   Yorùbá with English beneath, and the thread weaves over and under
   them as the reader scrolls, lighting each word it passes. */

.loom {
  position: relative;
  padding: 48px 0 42px;
  border-block: 1px solid var(--line-soft);
}

.loom .loom-thread {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.loom .loom-thread path {
  fill: none;
  stroke: var(--terracotta);
  stroke-width: 1.5;
  stroke-linecap: round;
}

.loom .loom-thread path.echo {
  stroke: var(--gold);
  opacity: 0.4;
  stroke-dasharray: 1 6;
}

.loom-words {
  position: relative;
  display: flex;
  justify-content: space-around;
  gap: 18px;
  flex-wrap: wrap;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.loom-word {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.15rem, 2vw, 1.5rem);
  color: var(--faint);
  transition: color 0.7s var(--ease), transform 0.7s var(--ease);
}

.loom-word small {
  font-family: var(--sans);
  font-style: normal;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--faint);
  opacity: 0.8;
  transition: color 0.7s var(--ease);
}

.loom-word .dot {
  width: 5px;
  height: 5px;
  background: var(--line);
  transform: rotate(45deg);
  transition: background 0.7s var(--ease);
}

.loom-word.lit { color: var(--ink); transform: translateY(-2px); }
.loom-word.lit small { color: var(--gold); }
.loom-word.lit .dot { background: var(--terracotta); }

/* The loom is a wide gesture: the thread needs room to wave and the words
   need one line. On a phone it wraps into a stack that reads as filler, so it
   sits the small screens out. */
@media (max-width: 720px) {
  .loom { display: none; }
}

/* ---------- Awards teaser: three previews and the stack ---------- */

.award-teaser {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(18px, 2.5vw, 30px);
  align-items: stretch;
}

@media (max-width: 900px) { .award-teaser { grid-template-columns: 1fr 1fr; } }

.award-teaser figure { margin: 0; }

.award-teaser .shot {
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
  height: 100%;
}

.award-teaser figure:nth-child(odd) .shot { border-radius: var(--arch); }

.award-teaser .shot img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4 / 5; }

.shot.await {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 4 / 5;
  background:
    radial-gradient(110% 90% at 25% 15%, rgba(184, 111, 82, 0.14), transparent 55%),
    linear-gradient(160deg, var(--sand), var(--gold-soft));
}

.shot.await::after {
  content: "Award Photo";
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(51, 48, 43, 0.45);
}

.photo-stack {
  position: relative;
  display: block;
  aspect-ratio: 4 / 5;
}

.photo-stack .card {
  position: absolute;
  inset: 6% 4%;
  border-radius: var(--radius);
  background: var(--ivory);
  border: 1px solid var(--gold);
  box-shadow: var(--shadow-soft);
  transition: transform 0.5s var(--ease);
}

.photo-stack .c1 { transform: rotate(-5deg); background: var(--forest-soft); }
.photo-stack .c2 { transform: rotate(3deg); background: var(--terracotta-soft); }

.photo-stack .top {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
  padding: 20px;
  transform: rotate(-1deg);
}

.photo-stack .top b {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.25rem;
  line-height: 1.3;
  color: var(--ink);
}

.photo-stack .top small {
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--faint);
}

.photo-stack .top .arrow { color: var(--terracotta); font-size: 1.2rem; transition: transform 0.3s var(--ease); }
.photo-stack:hover .c1 { transform: rotate(-9deg) translate(-6px, 4px); }
.photo-stack:hover .c2 { transform: rotate(7deg) translate(6px, -3px); }
.photo-stack:hover .top .arrow { transform: translateX(5px); }

/* ---------- Morph frame: the person becomes the character ----------
   A draggable gold seam wipes between Busayo's photograph and the
   Mrs. Disu illustration drawn from it, pose for pose. */

.morph {
  position: relative;
  border-radius: var(--arch);
  overflow: hidden;
  aspect-ratio: 2 / 3;
  box-shadow: var(--shadow-soft);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  --x: 50%;
  cursor: ew-resize;
}

.morph > img, .morph .over img {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  object-fit: cover;
  max-width: none;
  pointer-events: none;
}

.morph .over {
  position: absolute;
  inset: 0;
  width: var(--x);
  overflow: hidden;
}

.morph .over img { width: auto; aspect-ratio: 1023 / 1523; }

.morph::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 80px;
  background: linear-gradient(to top, rgba(46, 46, 46, 0.45), transparent);
  pointer-events: none;
  z-index: 1;
}

.morph .seam {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--x);
  width: 2px;
  margin-left: -1px;
  background: var(--gold);
  z-index: 2;
  pointer-events: none;
}

.morph .knob {
  position: absolute;
  top: 50%;
  left: var(--x);
  transform: translate(-50%, -50%) rotate(45deg);
  width: 36px;
  height: 36px;
  background: var(--ivory);
  border: 1.5px solid var(--gold);
  box-shadow: var(--shadow-soft);
  z-index: 3;
  cursor: ew-resize;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

.morph .knob span {
  transform: rotate(-45deg);
  display: block;
  font-size: 0.95rem;
  line-height: 1;
  color: var(--wine);
}

.morph .tag {
  position: absolute;
  bottom: 16px;
  z-index: 2;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ivory);
  pointer-events: none;
}

.morph .tag-l { left: 18px; }
.morph .tag-r { right: 18px; }

/* ---------- Scroll-scrubbed 3D book ----------
   The real cover on a real spine: the book turns in space as the
   reader scrolls through its chapter. Static three-quarter view
   without JavaScript or under reduced motion. */

.book3d-stage {
  perspective: 1400px;
  display: flex;
  justify-content: center;
  padding: 26px 0;
}

.book3d {
  position: relative;
  width: min(320px, 68vw);
  aspect-ratio: 2 / 3;
  transform-style: preserve-3d;
  transform: rotateY(-22deg) rotateX(4deg);
  --t: 36px;
}

.book3d .face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
}

.book3d .front {
  transform: translateZ(calc(var(--t) / 2));
  border-radius: 4px 14px 14px 4px;
  overflow: hidden;
  box-shadow: 0 34px 70px -32px rgba(51, 48, 43, 0.55);
}

.book3d .front img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.book3d .back {
  transform: translateZ(calc(var(--t) / -2)) rotateY(180deg);
  background: linear-gradient(160deg, var(--forest), var(--forest-deep));
  border-radius: 4px 14px 14px 4px;
}

.book3d .spine {
  inset: 0 auto 0 calc(var(--t) / -2);
  width: var(--t);
  transform: rotateY(-90deg);
  background: linear-gradient(180deg, var(--wine), var(--wine-deep));
  display: flex;
  align-items: center;
  justify-content: center;
}

.book3d .spine span {
  writing-mode: vertical-rl;
  font-family: var(--serif);
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  color: var(--gold-soft);
  white-space: nowrap;
}

.book3d .pages {
  inset: 0 calc(var(--t) / -2) 0 auto;
  width: var(--t);
  transform: rotateY(90deg);
  background: repeating-linear-gradient(to right, #F4EDDF 0 2px, #E3D8C2 2px 3px);
  border-radius: 0 3px 3px 0;
}

/* ---------- Real photography ---------- */

img.photo {
  width: 100%;
  height: auto;
  display: block;
  object-fit: cover;
  aspect-ratio: var(--ar, 3 / 4);
  filter: saturate(1.04) contrast(1.02) sepia(0.03);
}

.arch-img img.photo, .shot img.photo, .cover img.photo { height: 100%; }

.brand-accent-wine .textlink { color: var(--wine); border-color: var(--wine); }
.brand-accent-navy .textlink { color: var(--navy); border-color: var(--navy); }
.brand-accent-gold .textlink { color: var(--gold); border-color: var(--gold); }

/* ---------- Motion safety ---------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .msk-in { transform: none; }
  .unveil::after { display: none; }
  .unveil > :first-child { transform: none; }
  .proverb .yo .w { opacity: 1; transform: none; }
  .proverb .rain { display: none; }
  .pre-split { visibility: visible; }
  .preloader { display: none; }
}

/* ============ Site assistant (DeepSeek chat) ============ */
#chat-launcher {
  position: fixed;
  right: var(--fab-inset);
  bottom: var(--fab-inset);
  z-index: 950;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px 10px 11px;
  border: 1px solid rgba(233, 220, 198, 0.26);
  border-radius: 999px;
  background: linear-gradient(177deg, #41594b, #33473c);
  color: #FAF7F2;
  font: 500 0.96rem/1 var(--serif, "Playfair Display", serif);
  letter-spacing: 0.2px;
  cursor: pointer;
  box-shadow: 0 16px 36px -12px rgba(18, 27, 21, 0.6);
  transition: transform 0.3s var(--ease, ease), box-shadow 0.3s ease, opacity 0.25s ease,
              right 0.4s var(--ease, ease);
}
#chat-launcher:hover { transform: translateY(-2px); box-shadow: 0 22px 46px -12px rgba(18, 27, 21, 0.66); }
#chat-launcher .cl-ic { flex: none; width: 32px; height: 32px; display: grid; place-items: center; border-radius: 50%; background: rgba(203, 169, 106, 0.16); }
#chat-launcher .cl-ic svg { width: 18px; height: 18px; color: #E7C989; }
.chat-launcher-label { padding-right: 2px; }
body.chat-open #chat-launcher { opacity: 0; pointer-events: none; transform: scale(0.86); }

/* At the width where the nav folds into the menu button, the two floating
   controls fold in with it: Ask joins the doors and Appearance is already
   there, which leaves the bottom corners of a phone to the page itself. */
@media (max-width: 1080px) {
  #chat-launcher,
  .theme-fab { display: none; }
}

#chat-scrim {
  position: fixed;
  inset: 0;
  z-index: 949;
  background: rgba(16, 24, 19, 0);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease, background 0.3s ease;
}
#chat-scrim.show { opacity: 1; pointer-events: auto; }

#chat-panel {
  position: fixed;
  right: clamp(16px, 3vw, 30px);
  bottom: clamp(16px, 3vw, 30px);
  z-index: 951;
  width: min(392px, calc(100vw - 32px));
  height: auto;
  max-height: min(600px, 78vh);
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  background: var(--cream, #FAF7F2);
  border: 1px solid rgba(57, 81, 68, 0.12);
  border-radius: 22px;
  overflow: hidden;
  box-shadow: 0 34px 74px -22px rgba(18, 27, 21, 0.55), 0 3px 12px rgba(18, 27, 21, 0.12);
  opacity: 0;
  transform: translateY(18px) scale(0.97);
  transform-origin: bottom right;
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.34s cubic-bezier(0.2, 0.75, 0.2, 1);
}
#chat-panel.open { opacity: 1; transform: none; pointer-events: auto; }

.chat-head {
  position: relative;
  flex: none;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 15px 14px 16px 16px;
  background: linear-gradient(178deg, #3e5749, #344a3d);
  color: #FAF7F2;
}
.chat-head::after {
  content: "";
  position: absolute; left: 16px; right: 16px; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(203, 169, 106, 0.55), transparent);
}
.chat-emblem { flex: none; width: 36px; height: 36px; display: grid; place-items: center; border-radius: 50%; background: rgba(203, 169, 106, 0.14); border: 1px solid rgba(203, 169, 106, 0.36); }
.chat-emblem svg { width: 20px; height: 20px; color: #E7C989; }
.chat-head-txt { flex: 1 1 auto; min-width: 0; }
.chat-title { display: block; font: 500 1.08rem/1.12 var(--serif, "Playfair Display", serif); }
.chat-sub { display: block; margin-top: 3px; font-size: 0.72rem; letter-spacing: 0.02em; color: rgba(233, 229, 220, 0.6); }
.chat-close { flex: none; display: inline-grid; place-items: center; width: 32px; height: 32px; border: 0; border-radius: 50%; background: rgba(250, 247, 242, 0.12); color: #FAF7F2; cursor: pointer; transition: background 0.2s ease; }
.chat-close:hover { background: rgba(250, 247, 242, 0.24); }
.chat-close svg { width: 16px; height: 16px; }

.chat-log { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 11px; }
.chat-log::-webkit-scrollbar { width: 8px; }
.chat-log::-webkit-scrollbar-thumb { background: rgba(57, 81, 68, 0.2); border-radius: 8px; }
.chat-msg { display: flex; }
.chat-msg.chat-user { justify-content: flex-end; }
.chat-bubble {
  max-width: 86%;
  padding: 11px 14px;
  border-radius: 16px;
  /* Running text, so it follows the page into Space Grotesk — but at 400
     rather than Light, since these sit small and on coloured grounds. */
  font: 400 0.98rem/1.5 var(--sans, "Helvetica Neue", Arial, sans-serif);
}
.chat-bot .chat-bubble { background: #EEE7D8; color: #2A3A30; border-bottom-left-radius: 6px; }
.chat-user .chat-bubble { background: linear-gradient(178deg, #bd7657, #b0684c); color: #FDF7F2; border-bottom-right-radius: 6px; }
.chat-bubble strong { font-weight: 600; }

.chat-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.chat-chips { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.chat-action {
  display: block;
  position: relative;
  min-width: 0;
  padding: 10px 13px 10px 27px;
  border: 1px solid rgba(57, 81, 68, 0.2);
  border-radius: 13px;
  background: rgba(255, 255, 255, 0.5);
  color: #37503f;
  font: 500 0.9rem/1.3 var(--serif, "Playfair Display", serif);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  overflow-wrap: break-word;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease, transform 0.15s ease;
}
.chat-action::before {
  content: "";
  position: absolute;
  left: 13px; top: 1.02em;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: #CBA96A;
  transition: background 0.2s ease;
}
.chat-action:hover { background: #3e5749; border-color: #3e5749; color: #FAF7F2; transform: translateY(-1px); }
.chat-action:hover::before { background: #E7C989; }

.chat-input { flex: none; display: flex; align-items: flex-end; gap: 8px; padding: 12px; border-top: 1px solid rgba(57, 81, 68, 0.1); }
.chat-input textarea {
  flex: 1;
  resize: none;
  max-height: 120px;
  padding: 11px 14px;
  border: 1px solid rgba(57, 81, 68, 0.2);
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.75);
  color: #2A3A30;
  font: 400 0.96rem/1.45 var(--sans, "Helvetica Neue", Arial, sans-serif);
}
.chat-input textarea::placeholder { color: rgba(57, 81, 68, 0.5); }
.chat-input textarea:focus { outline: none; border-color: #B9905C; box-shadow: 0 0 0 3px rgba(185, 144, 92, 0.16); }
#chat-send { flex: none; display: inline-grid; place-items: center; width: 44px; height: 44px; border: 0; border-radius: 13px; background: #3e5749; color: #FAF7F2; cursor: pointer; transition: background 0.2s ease, opacity 0.2s ease; }
#chat-send:hover { background: #48644f; }
#chat-send:disabled { opacity: 0.45; cursor: default; }
#chat-send svg { width: 19px; height: 19px; }

.chat-dots { display: inline-flex; gap: 4px; padding: 2px 0; }
.chat-dots i { width: 6px; height: 6px; border-radius: 50%; background: #8a9990; animation: chatDot 1.2s ease-in-out infinite; }
.chat-dots i:nth-child(2) { animation-delay: 0.18s; }
.chat-dots i:nth-child(3) { animation-delay: 0.36s; }
@keyframes chatDot { 0%, 60%, 100% { transform: translateY(0); opacity: 0.5; } 30% { transform: translateY(-4px); opacity: 1; } }

html[data-theme="dark"] #chat-panel { background: #17221C; border-color: rgba(233, 220, 198, 0.12); }
html[data-theme="dark"] .chat-bot .chat-bubble { background: #24342B; color: #E9E5DC; }
html[data-theme="dark"] .chat-input textarea { background: rgba(233, 220, 198, 0.06); color: #E9E5DC; border-color: rgba(233, 220, 198, 0.16); }
html[data-theme="dark"] .chat-input textarea::placeholder { color: rgba(233, 220, 198, 0.4); }
html[data-theme="dark"] .chat-action { background: rgba(233, 220, 198, 0.05); color: #E4DAC6; border-color: rgba(233, 220, 198, 0.18); }
html[data-theme="dark"] .chat-action:hover { background: #E7C989; color: #1a251f; border-color: #E7C989; }
html[data-theme="dark"] .chat-action:hover::before { background: #1a251f; }

@media (max-width: 560px) {
  #chat-panel {
    right: 0; left: 0; bottom: 0;
    width: 100%;
    max-height: 84vh;
    border-radius: 22px 22px 0 0;
    transform: translateY(100%);
    transform-origin: bottom center;
  }
  #chat-panel.open { transform: none; }
  #chat-scrim.show { background: rgba(16, 24, 19, 0.44); }
}
@media (max-width: 380px) {
  .chat-launcher-label { display: none; }
  #chat-launcher { padding: 10px; }
}

/* ==========================================================================
   Mobile legibility and tap-target polish
   Floors small labels at 12px and gives standalone links and small buttons
   comfortable touch areas on phones, without altering the desktop look.
   ========================================================================== */

@media (max-width: 600px) {
  .morph .tag,
  .chat-sub,
  .detail-row .aside,
  .photo-stack .top small,
  .frame-plaque { font-size: 12px; }

  /* Title links inside list rows get a taller touch area. */
  .detail-row h3 a, .detail-row h4 a { display: inline-block; padding-block: 6px; }

  /* Rotator dots keep their small look but gain an invisible 36px hit area. */
  .rotator-dots button { position: relative; }
  .rotator-dots button::after { content: ""; position: absolute; inset: -13px; }

  /* Standalone links get a taller touch area (inline prose links stay inline). */
  .textlink { padding-block: 8px; }
  #site-footer ul a,
  .footer-base nav a,
  .footer-brand .socials a { display: inline-flex; align-items: center; min-height: 40px; }
  #site-footer ul li { margin-bottom: 4px; }
  .breadcrumb a { display: inline-block; padding-block: 6px; }

  /* Mobile menu appearance buttons, easier to hit. */
  .menu-modes { gap: 10px 22px; }
  .menu-modes .mode-btn { padding: 12px 2px; }
}
