/* =========================================================
   carlreader.com — shared styles
   v0.2, May 2026
   ========================================================= */

/* ---------- SELF-HOSTED FONTS ----------
   Fonts served from /fonts/ to keep visitor traffic on carlreader.com.
   No Google Fonts request, no third-party IP exposure, simpler CSP.
   Files licensed under SIL Open Font License (Geist, Bebas Neue) and
   Open Font License (Playfair Display).
   font-display: swap so text shows immediately in fallback while
   webfont loads. */
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/geist-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/geist-500-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/geist-600-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/geist-700-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/playfair-display-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/playfair-display-700-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Playfair Display';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/playfair-display-400-italic.woff') format('woff');
}
@font-face {
  font-family: 'Bebas Neue';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/bebas-neue-400-normal.woff2') format('woff2');
}

/* ---------- DESIGN TOKENS ---------- */
:root {
  /* Palette */
  --cream: #f0ebd8;
  --ink:   #030027;

  /* Colours follow bar position on the homepage:
     1 teal  ·  2 brown  ·  3 purple  ·  4 green  ·  5 indigo.
     The variable names below stay tied to the content (--about,
     --work, --media) but their values reflect each topic's
     current visual position. */
  --speaking: #335c67; /* position 1 — teal */
  --books:    #9a5c00; /* position 2 — brown (darkened from #b86e00 to clear WCAG AA 4.5:1 on cream) */
  --work:     #794d80; /* position 3 — purple */
  --media:    #154416; /* position 4 — green */
  --about:    #030027; /* position 5 — wordmark navy (matches --ink) */

  /* Fonts.
     DM Serif Display carries the wordmark only.
     Playfair Display Bold (700) handles all upright headlines.
     Playfair Display Italic 400 is reserved for quote callouts.
     Bebas Neue handles labels and buttons.
     Geist handles body copy. */
  --wordmark-font: 'DM Serif Display', Georgia, 'Times New Roman', serif;
  --heading-font:  'Playfair Display', Georgia, 'Times New Roman', serif;
  --quote-font:    'Playfair Display', Georgia, serif;
  --label:         'Bebas Neue', 'Arial Narrow', sans-serif;
  --body:          'Geist', system-ui, -apple-system, 'Helvetica Neue', sans-serif;

  /* Motion. ease-out-quart for a graceful, deliberate feel on
     the bar expansion. */
  --ease:     cubic-bezier(0.22, 1, 0.36, 1);
  --duration: 650ms;

  /* Each bar's width as a percentage of the viewport.
     5 bars × 7.64vw = 38.2vw (golden ratio).
     Cream area takes the remaining 61.8vw. */
  --bar-width: 7.64vw;

  /* Shared baseline: bottom of the carl. period.
     Menu labels' visible bottoms sit on this line.
     Smaller value = wordmark + labels sit lower in the viewport. */
  --baseline: 32px;
}

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

html, body {
  margin: 0;
  padding: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--body);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a { color: inherit; text-decoration: none; }
img, video { display: block; max-width: 100%; }

::selection { background: var(--ink); color: var(--cream); }


/* =========================================================
   SHARED BAR — used on homepage, topic landings and sub-topic pages
   ========================================================= */
.bar {
  width: var(--bar-width);
  flex-shrink: 0;
  position: relative;
  overflow: hidden;
  display: block;
  cursor: pointer;
  text-decoration: none;
  transition: width var(--duration) var(--ease),
              filter 90ms ease-out;
}
/* Click flash — brief darken on mousedown for tactile feedback.
   Snaps back fast when the click releases (or page navigates). */
.bar:active {
  filter: brightness(0.78);
  transition: filter 40ms ease-out;
}
.bar--speaking { background: var(--speaking); --bar-color: var(--speaking); }
.bar--books    { background: var(--books);    --bar-color: var(--books); }
.bar--about    { background: var(--about);    --bar-color: var(--about); }
.bar--work     { background: var(--work);     --bar-color: var(--work); }
.bar--media    { background: var(--media);    --bar-color: var(--media); }
.bar--legal    { background: var(--ink);      --bar-color: var(--ink); }

/* Active section indicator — matches the hover state exactly,
   so scrolling between sections feels the same as hovering. */
.subpage .bar.bar--active-section::after {
  background: rgba(3, 0, 39, 0.28);
}
/* Label dims to match the darkened bar. Applies to both hover
   and active-section so the patterns are identical. */
.subpage .bar:hover .bar__label,
.subpage .bar.bar--active-section .bar__label {
  opacity: 0.65;
  transition: opacity var(--duration) var(--ease);
}

/* Menu label, rotated, white, sits on the shared baseline.
   transform-origin: 0% 100% pins the unrotated bottom-left in place
   during rotate(-90deg) CCW; the translateX(0.5em) then shifts the
   rotated strip right by half its visible width so it sits centred
   on the bar. Visible bottom of the label sits exactly on --baseline. */
.bar__label {
  position: absolute;
  bottom: var(--baseline);
  left: 50%;
  transform: translateX(0.5em) rotate(-90deg);
  transform-origin: 0% 100%;
  white-space: nowrap;
  font-family: var(--label);
  font-size: clamp(32px, 2.8vw, 48px);
  font-weight: 400;
  letter-spacing: 0.04em;
  color: var(--cream);
  line-height: 1;
  pointer-events: none;
  transition: opacity 160ms ease;
}

/* Split-label pattern for scroll-snap topic pages. The topic span
   (e.g. "Keynote Speaker:") stays put and never animates. Only
   the section span (e.g. "Booked and Rebooked") fades between
   values as the user scrolls. */
.bar__label-topic,
.bar__label-section {
  display: inline;
}
.bar__label-section {
  transition: opacity 240ms ease;
}
.bar__label-section.is-changing { opacity: 0; }
/* Add ": " before the section name only when there's a section to
   show. Lets the first section on /media/ (and any other page that
   chooses to land without a sub-section name) read as just the
   topic, with no dangling colon. */
.bar__label-section:not(:empty)::before {
  content: ': ';
}


/* =========================================================
   HOMEPAGE
   Cream area on the left (61.8vw), 5 bars on the right (38.2vw).
   ========================================================= */
.home {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  display: flex;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: var(--cream);
}
/* CREAM area — empty flex spacer to the left of the bars. Its
   width auto-adjusts when the bars grow or shrink on hover. */
.cream {
  flex: 1 1 auto;
  min-width: 0;
}

/* Small-print legal link, homepage only. Sits below the
   wordmark in Playfair Display Regular. Low contrast, no
   underline. Picks up the small space between the wordmark
   baseline and the bottom of the viewport. Left offset matches
   the visible "c" of the wordmark, accounting for the PNG's
   ~2% transparent left padding. */
.wordmark__small-print {
  position: absolute;
  /* Left offset = baseline + the wordmark PNG's transparent left
     padding (~2.05% of its width). Drops the "c" of "click here"
     directly under the "c" of "carl." */
  left: calc(var(--baseline) + clamp(4px, 0.48vw, 9px));
  bottom: 22px;
  max-width: clamp(280px, 30vw, 480px);
  font-family: 'Playfair Display', Georgia, serif;
  font-style: normal;
  font-weight: 400;
  font-size: clamp(13px, 0.95vw, 15px);
  line-height: 1.35;
  letter-spacing: 0.01em;
  color: var(--ink);
  opacity: 0.55;
  text-decoration: none;
  transition: opacity var(--duration) var(--ease);
  z-index: 2;
}
.wordmark__small-print:hover { opacity: 1; }

/* Wordmark — rendered from the carl. PNG.
   Positioned absolutely against the viewport (.home is the
   containing block), so the mark NEVER moves on hover.
   Width fixed in vw so the wordmark visually occupies ~38.2% of
   the default cream area (0.382 × 61.8vw = 23.6vw).
   Left margin equals the bottom margin (--baseline), giving
   equivalent visual space on the left and beneath.

   The PNG has ~35.9% transparent padding below the "carl." text.
   translateY(35.9%) shifts the image down by that amount so the
   bottom of the period sits exactly on --baseline (the same line
   the menu labels rest on). The padding overflows below the
   viewport and is clipped by .home's overflow:hidden. */
.wordmark {
  position: absolute;
  left: var(--baseline);
  bottom: var(--baseline);
  width: clamp(220px, 23.6vw, 460px);
  height: auto;
  display: block;
  transform: translateY(35.9%);
  user-select: none;
  -webkit-user-drag: none;
  z-index: 1;
  pointer-events: none;
}
.bars {
  display: flex;
  flex-shrink: 0;
  height: 100%;
}

/* Hero image, tinted to the bar colour on hover.
   Two layers do the work:
   ::before — multiply, deepens the image with the bar colour.
              Books bar then reads as deep brown, not light yellow.
              Media bar reads as deep indigo, not washed pale.
   ::after  — color blend, locks the hue+sat of the result to the
              bar colour so the duotone is consistent. */
.bar__hero {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0;
  transform: scale(1.04);
  transition: opacity var(--duration) var(--ease),
              transform calc(var(--duration) * 1.5) var(--ease);
  pointer-events: none;
}
.bar__hero::before,
.bar__hero::after {
  content: '';
  position: absolute;
  inset: 0;
}
.bar__hero::before {
  background: var(--bar-color);
  mix-blend-mode: multiply;
  opacity: 0.6;
}
.bar__hero::after {
  background: var(--bar-color);
  mix-blend-mode: color;
  opacity: 0.85;
}
/* About bar — push the blue. The color-blend overlay at full
   opacity replaces the hue/sat of the image entirely with indigo
   (keeping only the photo's luminosity), so the image reads
   fully blue with only brightness variation from the original. */
.bar--about .bar__hero::before { opacity: 0.55; }
.bar--about .bar__hero::after  { opacity: 1; }

/* CTA pill (homepage hover only).
   Cream background. Bar-colour text and arrow. Unbold.
   Sits at 61.2% from the top so it lives in the lower third —
   roughly the golden-ratio lower split.
   The arrow is an inline SVG so it picks up the text colour
   automatically via currentColor. */
.bar__cta {
  position: absolute;
  top: 61.2%;
  left: 50%;
  transform: translate(-50%, calc(-50% + 8px));
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 18px 22px 18px 30px;
  background: var(--cream);
  color: var(--bar-color);
  font-family: var(--label);
  font-size: clamp(22px, 1.6vw, 30px);
  font-weight: 400;
  letter-spacing: 0.06em;
  border-radius: 999px;
  opacity: 0;
  /* No transition in the default state — pill disappears
     instantly on hover-out so it doesn't ghost as the bar
     collapses. Fade-in is declared on the hover/is-active
     states below. */
  pointer-events: none;
  white-space: nowrap;
}
.bar__cta-arrow {
  width: 28px;
  height: 28px;
  stroke: currentColor;
  stroke-width: 2.5;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform var(--duration) var(--ease);
}

/* ---------- HOVER CHOREOGRAPHY ----------
   Per the concept design:
   - Default: 5 bars at --bar-width each = 38.2vw total. Cream
     fills the remaining 61.8vw.
   - On hover: the hovered bar grows by 23.6vw (becomes
     7.64 + 23.6 = 31.24vw — a near-square panel that shows the
     hero image). The other four bars stay at --bar-width. The
     cream area shrinks naturally via flex from 61.8vw to 38.2vw.
   - The wordmark, anchored to the viewport, never moves.
*/
.home .bar:hover { width: calc(var(--bar-width) + 23.6vw); }
.bar:hover .bar__hero { opacity: 1; transform: scale(1); }
.bar:hover .bar__cta {
  opacity: 1;
  transform: translate(-50%, -50%);
  pointer-events: auto;
  transition:
    opacity 620ms var(--ease) 280ms,
    transform 620ms var(--ease) 280ms;
}
.bar:hover .bar__cta-arrow { transform: translateX(4px); }
.home .bar:hover .bar__label { opacity: 0; }

/* Touch fallback: JS .is-active drives the same look */
.bar.is-active .bar__hero { opacity: 1; transform: scale(1); }
.bar.is-active .bar__cta {
  opacity: 1;
  transform: translate(-50%, -50%);
  pointer-events: auto;
  transition:
    opacity 620ms var(--ease) 280ms,
    transform 620ms var(--ease) 280ms;
}
.home .bar.is-active .bar__label { opacity: 0; }
.home.has-active .bar.is-active { width: calc(var(--bar-width) + 23.6vw); }


/* =========================================================
   TOPIC LANDING + SUB-TOPIC PAGE LAYOUT
   Same bar geometry as the homepage. The active topic moves to
   the LEFT and the remaining 4 bars (sub-topics on a topic page,
   or remaining sub-topics on a sub-topic page) sit on the RIGHT.
   Cream content sits in the middle.
   NEVER more than 2 bars on the left.
   ========================================================= */
.subpage {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  display: flex;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: var(--cream);
  /* --- responsive anchors -----------------------------------
     Everything that lives near the bottom of the page (wordmark,
     testimonials, scroll hint, content fade) is driven off these
     two variables so they all scale together with viewport width.
     --wordmark-width: physical width of the carl. PNG.
     --wordmark-visible-top: vertical distance from the viewport
       BOTTOM to the visible top edge of "carl." (baseline + 64.1%
       of the PNG's height, since the PNG has ~35.9% transparent
       padding below the text). */
  --wordmark-width: clamp(220px, 23.6vw, 460px);
  --wordmark-visible-top: calc(var(--baseline) + var(--wordmark-width) * 0.641);
}

/* SCROLL-SNAP TOPIC PAGE
   Used on topic landings that have been merged into a single URL
   with multiple full-viewport sections (currently /speaking/).
   The .subpage__scroller is the scrolling viewport. Each
   .subpage__section snaps to start on scroll. */
.subpage--scroll .subpage__scroller {
  flex: 1 1 auto;
  position: relative;
  min-width: 0;
  height: 100%;
  overflow-y: scroll;
  overflow-x: hidden;
  /* Proximity (not mandatory) so mid-section scrolling can hold
     without being yanked back to a snap point. Sections snap
     with their TOP at viewport y=0 — their internal padding-top
     then puts the H1 on the back-button row naturally.
     Per-element scroll-margin-top handles the bullet offset. */
  scroll-snap-type: y proximity;
  scroll-behavior: smooth;
  /* Bottom fade scales with the wordmark area so it stays in the
     same visual zone on every viewport. Full opacity above the
     fade band; transparent just below the scroll-hint position. */
  -webkit-mask-image: linear-gradient(
    to bottom, #000 0,
    #000 calc(100% - var(--wordmark-visible-top) - 120px),
    transparent calc(100% - var(--wordmark-visible-top) - 20px));
          mask-image: linear-gradient(
    to bottom, #000 0,
    #000 calc(100% - var(--wordmark-visible-top) - 120px),
    transparent calc(100% - var(--wordmark-visible-top) - 20px));
  /* Hide scrollbar but keep functionality */
  scrollbar-width: none;
}
.subpage--scroll .subpage__scroller::-webkit-scrollbar { display: none; }

/* Sections start at full viewport height but are allowed to grow
   taller if their content demands it. Scroll-snap aligns the top
   of each section; users scroll freely within a tall section
   before the next snap point is reached. */
.subpage__section {
  min-height: 100%;
  scroll-snap-align: start;
  padding: clamp(40px, 6vh, 80px) clamp(48px, 6vw, 96px) calc(var(--wordmark-visible-top) + 40px) var(--baseline);
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
}
.subpage--scroll.subpage--has-logos .subpage__section {
  padding-right: calc(clamp(80px, 8vw, 140px) + clamp(144px, 14vw, 220px) + 40px);
}

/* On scroll pages the logos column sits outside the scroller, so
   right offset must account for the right bars width (4 bars on
   topic pages). The heading above it shares the same right offset
   so it stays centred over the marquee. */
.subpage--scroll.subpage--has-logos .subpage__logos,
.subpage--scroll.subpage--has-logos .subpage__logos-heading {
  right: calc(var(--bar-width) * 4 + clamp(40px, 4vw, 80px));
}

/* Scroll hint — single bouncing chevron per scroll page. Anchored
   to the viewport via .subpage (position: fixed) so it stays put
   in the blank space to the right of the wordmark, near the top
   of the wordmark area. JS updates its target as the user moves
   between sections. */
/* Scroll controls — a row of three buttons next to the wordmark:
   "Last section", "Scroll" (one viewport down within current section),
   "Next section". The end controls disable themselves at the
   boundaries (first / last section). */
.scroll-controls {
  position: absolute;
  /* Sits in the empty space just past the wordmark on its right
     side, with the button bottoms aligned to the wordmark baseline
     (= var(--baseline)). */
  left: calc(var(--bar-width) + var(--baseline) + var(--wordmark-width) + clamp(40px, 3.5vw, 80px));
  bottom: var(--baseline);
  z-index: 4;
  display: flex;
  align-items: flex-end;
  gap: clamp(14px, 1.4vw, 24px);
}
.scroll-control {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  font-family: var(--label);
  font-size: clamp(11px, 0.85vw, 14px);
  /* Match the menu bar labels — same compact letter-spacing. */
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--page-color, var(--ink));
  text-decoration: none;
  opacity: 0.55;
  cursor: pointer;
  transition: opacity var(--duration) var(--ease);
  white-space: nowrap;
}
.scroll-control:hover,
.scroll-control:focus-visible { opacity: 1; }
.scroll-control:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: 4px;
  border-radius: 2px;
}
.scroll-control.is-disabled {
  opacity: 0.15;
  pointer-events: none;
  cursor: default;
}
.scroll-control__icon {
  width: clamp(22px, 1.9vw, 30px);
  height: clamp(22px, 1.9vw, 30px);
  stroke: currentColor;
  stroke-width: 2;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}
@media (prefers-reduced-motion: reduce) {
  .subpage--scroll .subpage__scroller { scroll-behavior: auto; }
}

/* Per-section "page colour" — drives the colour of testimonial
   attributions and any other content that should pick up the
   active topic's hue. Set on each topic and sub-topic page. */
.subpage--speaking { --page-color: var(--speaking); }
.subpage--books    { --page-color: var(--books); }
.subpage--work     { --page-color: var(--work); }
.subpage--media    { --page-color: var(--media); }
.subpage--about    { --page-color: var(--about); }
.subpage--legal    { --page-color: var(--ink); }
.subpage__bars-left,
.subpage__bars-right {
  display: flex;
  flex-shrink: 0;
  height: 100%;
}
.subpage__content {
  flex: 1 1 auto;
  position: relative;
  min-width: 0;
  /* Left padding matches --baseline so the heading, body text
     and wordmark all share the same left edge. Bottom padding
     keeps content from physically reaching the wordmark. */
  padding: clamp(40px, 6vh, 80px) clamp(48px, 6vw, 96px) calc(var(--wordmark-visible-top) + 40px) var(--baseline);
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
  /* Mask the bottom of the rendered content area so scrolling
     body text fades into the cream well before reaching the
     wordmark. Fade band is anchored to --wordmark-visible-top
     so it scales with the wordmark on every viewport. The
     wordmark itself sits OUTSIDE this element, on top of the fade. */
  -webkit-mask-image: linear-gradient(
    to bottom,
    #000 0,
    #000 calc(100% - var(--wordmark-visible-top) - 120px),
    transparent calc(100% - var(--wordmark-visible-top) - 20px)
  );
          mask-image: linear-gradient(
    to bottom,
    #000 0,
    #000 calc(100% - var(--wordmark-visible-top) - 120px),
    transparent calc(100% - var(--wordmark-visible-top) - 20px)
  );
}

/* Sub-page bars are clickable navigation. Hover gives a clear
   signal: the whole bar darkens slightly, the hovered bar grows,
   and the other bars in the same group shrink to balance. */
.subpage .bar {
  cursor: pointer;
  transition: width var(--duration) var(--ease);
}

/* Darkening overlay sits above the bar background but below the
   label and back graphic, so those stay readable on hover. */
.subpage .bar::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(3, 0, 39, 0);
  z-index: 1;
  pointer-events: none;
  transition: background var(--duration) var(--ease);
}
.subpage .bar:hover::after {
  background: rgba(3, 0, 39, 0.28);
}
.subpage .bar__label,
.subpage .bar__back {
  z-index: 2;
}

/* Subpage bars do not expand on hover. They only darken (via the
   ::after overlay above). The page layout never shifts when the
   user moves between bars, so the cream content stays anchored. */

/* Two-bar left group (sub-topic pages):
   - Parent topic bar fades to act as breadcrumb context.
   - Active sub-topic bar inherits the topic's colour (e.g. teal
     for any Speaker sub-topic), reinforcing where you are. */
.subpage__bars-left:has(.bar + .bar) .bar:first-child {
  opacity: 0.7;
}
.subpage__bars-left:has(.bar + .bar) .bar:last-child {
  background: var(--page-color);
  --bar-color: var(--page-color);
}


/* =========================================================
   VERTICAL LOGO SCROLLER
   Appears on topic pages that opt in via .subpage--has-logos.
   A narrow vertical column on the right of the cream content,
   continuously scrolling upward. Logos render as a darker
   version of the cream via CSS mask + a tinted background;
   on hover each logo lifts to the page's topic colour.
   ========================================================= */
.subpage--has-logos .subpage__content {
  /* Reserve room on the right for the logo column. */
  padding-right: calc(clamp(80px, 8vw, 140px) + clamp(144px, 14vw, 220px) + 40px);
}
.subpage__logos {
  position: absolute;
  top: clamp(110px, 14vh, 170px);
  right: clamp(80px, 8vw, 140px);
  bottom: var(--baseline);
  width: clamp(144px, 14vw, 220px);
  /* Bottom fades into the cream surround. The heading sits at the
     top of the column with a cream background and z-index 2 — it
     occludes any logo rising into its band. Mask stays solid at the
     top so the heading itself is rendered (the previous transparent
     band was masking the heading invisible). */
  -webkit-mask-image: linear-gradient(to bottom,
    #000 0,
    #000 88%,
    transparent 100%);
          mask-image: linear-gradient(to bottom,
    #000 0,
    #000 88%,
    transparent 100%);
}
/* Heading sits ABOVE the logos column at the height of the page H1
   so it doesn't compete with the marquee underneath. Positioned
   absolutely on the .subpage so it's outside the column's
   overflow:hidden — the scrolling logos can't reach it. */
.subpage__logos-heading {
  position: absolute;
  top: clamp(60px, 8.5vh, 110px);
  right: clamp(80px, 8vw, 140px);
  width: clamp(144px, 14vw, 220px);
  font-family: var(--label);
  font-size: clamp(11px, 0.85vw, 14px);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: center;
  color: var(--page-color, var(--ink));
  margin: 0;
  z-index: 3;
}
.subpage__logos-track {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 36px;
  animation: scroll-logos-up 80s linear infinite;
}
/* WCAG 2.2.2: auto-updating content must offer a pause control.
   Pause the marquee when the user hovers or any logo inside it
   receives keyboard focus. */
.subpage__logos:hover .subpage__logos-track,
.subpage__logos:focus-within .subpage__logos-track {
  animation-play-state: paused;
}
@keyframes scroll-logos-up {
  from { transform: translateY(0); }
  to   { transform: translateY(-50%); }
}
/* Continuous proximity highlight. JS writes --glow as a 0..1
   value every frame; CSS resolves the mix and scale directly
   off that variable. No transition — the per-frame updates
   already give smooth motion, and a transition only fights them. */
.logo-mark {
  /* 80% leaves horizontal room so the centred logo can scale up
     to 1.25x without being clipped by the column edges. */
  width: 80%;
  height: clamp(54px, 5vh, 72px);
  flex-shrink: 0;
  --glow: 0;
  /* Base colour is full-opacity ink (deep navy) so logos read
     clearly even when not in the glow band. */
  background-color: color-mix(
    in srgb,
    var(--ink),
    var(--page-color, var(--ink)) calc(var(--glow) * 100%)
  );
  transform: scale(calc(1 + 0.25 * var(--glow)));
  -webkit-mask-image: var(--m);
          mask-image: var(--m);
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: center;
          mask-position: center;
  -webkit-mask-size: contain;
          mask-size: contain;
  transform-origin: center;
}
/* No hover state — the scroller animates logos continuously and
   the proximity glow already provides visual feedback. A hover
   rule would suddenly recolour a logo as the cursor passed over,
   which read as the logo "disappearing" against the colour shift. */
@media (prefers-reduced-motion: reduce) {
  .subpage__logos-track { animation: none; }
}

/* Keep the back graphic at its current scale (no shift). */
.subpage .bar--current:hover .bar__back {
  transform: translateX(-50%);
}

/* Back graphic — sits INSIDE the active (rightmost-left) bar.
   Uses the master back-button PNG (a cream circle with a white
   chevron). Clicking anywhere on the bar navigates up one level,
   so this graphic is purely visual. */
.bar__back {
  position: absolute;
  top: clamp(40px, 6vh, 80px);
  left: 50%;
  width: clamp(56px, 4.5vw, 80px);
  height: clamp(56px, 4.5vw, 80px);
  display: block;
  transform: translateX(-50%);
  transition: transform var(--duration) var(--ease),
              opacity var(--duration) var(--ease);
  z-index: 5;
  pointer-events: none;
}
/* Back graphic dims to 0.65 on hover, matching .bar__label so the
   whole bar reads as a single interactive element. */
.subpage .bar:hover .bar__back {
  opacity: 0.65;
}
.bar--current:hover .bar__back {
  transform: translateX(-50%) translateX(-4px);
}

/* Subpage wordmark — small carl. mark anchored bottom-left of
   the cream content. Bottom sits on --baseline so it lines up
   with the menu labels on every bar. PNG offset compensates for
   the asset's transparent bottom padding. */
/* The wordmark on subpages is anchored to the viewport (not the
   scrolling cream content), so long content scrolls ABOVE it and
   never overruns. Sibling of .subpage__content. Left offset
   accounts for the left bars (1 bar on topic landings, 2 on
   sub-topic pages). Filled with var(--page-color) via mask. */
.subpage__wordmark {
  position: absolute;
  /* Default: single left bar (topic landing) */
  left: calc(var(--bar-width) + var(--baseline));
  bottom: var(--baseline);
  width: var(--wordmark-width);
  aspect-ratio: 1 / 1;
  display: block;
  background: var(--page-color, var(--ink));
  -webkit-mask: url('/img/logo.png') no-repeat center / contain;
          mask: url('/img/logo.png') no-repeat center / contain;
  transform: translateY(35.9%);
  user-select: none;
  pointer-events: none;
  z-index: 3;
}
/* Sub-topic pages have two left bars — shift the wordmark over. */
.subpage:has(.subpage__bars-left > .bar + .bar) .subpage__wordmark {
  left: calc(var(--bar-width) * 2 + var(--baseline));
}

/* CREAM CONTENT — typography and rhythm
   Title style: lowercase, period, big serif. */
.subpage__eyebrow {
  font-family: var(--label);
  font-size: clamp(13px, 1vw, 16px);
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin: 0 0 24px 0;
  color: var(--ink);
  opacity: 0.55;
}
.subpage__title {
  font-family: var(--heading-font);
  font-weight: 700;
  font-size: clamp(26px, 2.8vw, 44px);
  line-height: 1.05;
  letter-spacing: -0.01em;
  margin: 0 0 24px 0;
  color: var(--page-color, var(--ink));
}
/* Every paragraph on a subpage reads at one scale — no separate
   "lede" treatment anywhere. The first paragraph after the H1
   is just a normal paragraph; subsequent paragraphs match it.
   Whatever <strong> defaults the browser applies stay (browser
   bold is consistent across both lede and body). */
.subpage__section p {
  font-size: clamp(15px, 1.05vw, 18px);
  line-height: 1.55;
  margin: 0 0 16px 0;
  max-width: 64ch;
}

/* Sticky H1 for sections that step through bullets. The section
   title stays pinned at the back-arrow row (its natural position)
   while the user pages through the .bullet items beneath. No
   margin/padding absorbing — the H1's box is identical whether
   sticky is engaged or not, so there's no visible shift. */
.subpage--scroll .subpage__section:has(.bullet) .subpage__title {
  position: sticky;
  top: clamp(40px, 6vh, 80px);
  background: var(--cream);
  padding-bottom: clamp(8px, 1.2vh, 16px);
  margin-bottom: clamp(12px, 2vh, 20px);
  z-index: 5;
}
/* Bullets in sticky-H1 sections need extra scroll-margin so each
   bullet lands BELOW the sticky title band, not behind it.
   = section padding-top + H1 height + buffer. */
.subpage--scroll .subpage__section:has(.bullet) .bullet {
  scroll-margin-top: clamp(96px, 14vh, 168px);
}

/* Bullet — a sub-section page within a scroll-snap section.
   Each h3 + its content lives in a .bullet. It's a snap point
   (scroll-snap-align: start) AND has a min-height equal to the
   visible content area, so when the Scroll button advances to
   one bullet, the next bullet is pushed into the fade zone. */
.subpage__body .bullet {
  /* Snap target. scroll-margin-top extends the bullet's snap
     area upward by paddingTop, so when the bullet snaps to the
     top of the scrollport, its h3 lands paddingTop below the
     viewport top — i.e. on the back-arrow row. Sections (which
     have padding-top of their own) don't need this and snap
     naturally with their top at y=0. */
  scroll-snap-align: start;
  scroll-margin-top: clamp(40px, 6vh, 80px);
  min-height: calc(100vh - clamp(40px, 6vh, 80px) - var(--wordmark-visible-top) - 40px);
  min-height: calc(100dvh - clamp(40px, 6vh, 80px) - var(--wordmark-visible-top) - 40px);
  margin: 0;
  padding: 0;
}
/* First bullet's heading sits in the same place as if it were
   a normal h3 directly after the section's lede — no extra
   space before the rule. */
.subpage__body .bullet > h3:first-child {
  margin-top: 0;
}
.subpage__body h2 {
  font-family: var(--heading-font);
  font-weight: 700;
  font-size: clamp(26px, 2.2vw, 36px);
  line-height: 1.15;
  margin: clamp(40px, 6vh, 64px) 0 18px 0;
}
.subpage__body h3 {
  font-family: var(--heading-font);
  font-weight: 700;
  font-size: clamp(18px, 1.5vw, 22px);
  line-height: 1.2;
  margin: 28px 0 10px 0;
}
.subpage__body ul {
  /* Same size, line-height and width as body paragraphs so lists
     read as one continuous block with surrounding p text. */
  font-size: clamp(15px, 1.05vw, 18px);
  line-height: 1.55;
  margin: 0 0 16px 0;
  padding-left: 22px;
  max-width: 64ch;
}
.subpage__body li {
  font-size: inherit;
  margin-bottom: 6px;
}
.subpage__body .last-updated {
  font-family: var(--label);
  font-size: 14px;
  letter-spacing: 0.1em;
  margin: 0 0 24px 0;
  color: var(--page-color, var(--ink));
  opacity: 0.7;
}
.subpage__body a {
  color: var(--page-color, var(--ink));
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Testimonial template — pushed lower on the page to sit closer
   to the vertical centre. Attribution picks up the page colour. */
.subpage__quote {
  /* Auto top margin pushes the quote to the bottom of the section
     content area, so every section's quote lines up at the same
     vertical position regardless of the content above it. */
  margin-top: auto;
  margin-bottom: 0;
  max-width: 56ch;
}
.subpage__quote-text {
  font-family: var(--quote-font);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(17px, 1.3vw, 22px);
  line-height: 1.4;
  margin: 0 0 12px 0;
  color: var(--ink);
}
.subpage__quote-text::before { content: '"'; }
.subpage__quote-text::after { content: '"'; }
.subpage__quote-attrib {
  font-family: var(--label);
  font-size: clamp(13px, 0.95vw, 17px);
  font-weight: 400;
  letter-spacing: 0.08em;
  color: var(--page-color, var(--ink));
}

/* Quote rotator — fades between testimonials at a fixed cadence.
   Used on the "What Others Say" section. Slides share a single
   grid cell so the container's height tracks the tallest slide;
   only the .is-active slide is visible at a time. */
.subpage__quote--rotator {
  display: grid;
  position: relative;
}
.subpage__quote-slide {
  grid-area: 1 / 1;
  opacity: 0;
  transition: opacity 350ms ease;
  pointer-events: none;
}
.subpage__quote-slide.is-active {
  opacity: 1;
  pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
  .subpage__quote-slide { transition: none; }
}

/* ENQUIRY FORM
   Brought across from the old site with field IDs and structure
   intact. 2-column grid (matching the OG) so it fits inside the
   section without overflowing into the wordmark fade. Compact
   spacing/typography so all 7 fields + submit are visible on
   typical desktop heights. */
.form {
  /* Compressed sizing — the form has to fit fully in the enquire
     section's content area without the submit button being clipped
     by the wordmark fade. */
  margin-top: clamp(8px, 1.2vh, 14px);
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: clamp(14px, 1.5vw, 22px);
  row-gap: clamp(6px, 0.9vh, 12px);
  max-width: 620px;
}
.form__field {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.form__field--full {
  grid-column: 1 / -1;
}
.form__label {
  font-family: var(--label);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--page-color, var(--ink));
}
.form__input,
.form__textarea {
  font-family: var(--body);
  font-size: 14px;
  line-height: 1.35;
  color: var(--ink);
  background: transparent;
  border: none;
  border-bottom: 1px solid color-mix(in srgb, var(--ink), transparent 70%);
  padding: 4px 0;
  outline: none;
  border-radius: 0;
  width: 100%;
  transition: border-color var(--duration) var(--ease);
}
.form__input:focus,
.form__textarea:focus {
  border-bottom-color: var(--page-color, var(--ink));
}
.form__input::placeholder,
.form__textarea::placeholder {
  color: color-mix(in srgb, var(--ink), transparent 60%);
}
.form__textarea {
  min-height: 36px;
  resize: vertical;
  font-family: var(--body);
}
/* Replaces the form after a successful submit. Same typographic
   scale as body paragraphs (lede / body p unified earlier). */
.form__thanks {
  font-size: clamp(15px, 1.05vw, 18px);
  line-height: 1.55;
  max-width: 64ch;
}
.form__thanks p { margin: 0 0 12px 0; }
.form__thanks p:last-child { margin-bottom: 0; }

.form__status {
  grid-column: 1 / -1;
  font-family: var(--label);
  font-size: 12px;
  letter-spacing: 0.1em;
  color: var(--page-color, var(--ink));
  min-height: 1.2em;
}
.form__submit-row {
  grid-column: 1 / -1;
  margin-top: 0;
  display: flex;
}
/* Compound selectors so these modifiers beat the bare .btn rule
   regardless of declaration order. */
.btn.btn--brass {
  background: var(--page-color, var(--ink));
  color: var(--cream);
}
.btn.btn--big {
  font-size: clamp(18px, 1.4vw, 22px);
  font-weight: 400;
  letter-spacing: 0.06em;
  padding: 18px 32px;
  margin-top: 0;
}
.btn.btn--big .btn__arrow {
  width: 36px;
  height: 36px;
}
/* Drop to a single column when the content column is too narrow
   to host two side-by-side fields comfortably. */
@media (max-width: 1100px) {
  .form { grid-template-columns: 1fr; }
}

/* Partner logo on the work-with-carl brand sections. Rendered
   from the full-colour PNG (not the mask treatment used by the
   speaking page logo scroller). */
.partner-logo {
  display: block;
  max-width: clamp(96px, 9vw, 150px);
  max-height: clamp(48px, 5.5vh, 80px);
  width: auto;
  height: auto;
  object-fit: contain;
  margin: 0 0 18px 0;
}

/* Multi-brand logo grid for the "Vodafone, Intuit & more" section.
   Auto-fits N logos in a single row on desktop and wraps gracefully
   on narrower screens. Each logo capped so the largest doesn't
   crowd out the smaller ones. */
.partner-logos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
  gap: clamp(16px, 2vw, 32px);
  align-items: center;
  margin: 0 0 28px 0;
  max-width: clamp(360px, 42vw, 620px);
}
.partner-logos img {
  display: block;
  width: 100%;
  max-height: clamp(36px, 4.5vh, 56px);
  height: auto;
  object-fit: contain;
}

/* Current category caption above the gallery — updates via JS as
   the user scrolls the gallery horizontally so the active group is
   always visible above the photo row. */
.press-gallery__caption {
  margin: clamp(8px, 1.4vh, 18px) 0 clamp(10px, 1.6vh, 22px) 0;
  font-family: var(--label);
  font-size: clamp(13px, 1vw, 16px);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--page-color, var(--ink));
  font-weight: 500;
  transition: opacity var(--duration) var(--ease);
}
.press-gallery__caption.is-changing { opacity: 0.4; }

/* Press photo gallery on /media/ Photos section. Horizontal-
   scroll strip of click-to-download photos. Each anchor wraps
   the image and a download CTA chip; the anchor's `download`
   attribute triggers a save dialog on click. Photos are sized
   by a uniform display height so portrait and landscape sit
   nicely on the same row. */
.press-gallery {
  display: flex;
  align-items: flex-start;
  gap: clamp(12px, 1.4vw, 22px);
  margin: clamp(12px, 2vh, 24px) 0 0 0;
  padding: 0 0 12px 0;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  /* Native scrollbar hidden on Safari/Chrome; trackpads still scroll. */
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--page-color, var(--ink)), transparent 60%) transparent;
  /* Keep the gallery within the content column. */
  max-width: 100%;
}
.press-gallery::-webkit-scrollbar { height: 6px; }
.press-gallery::-webkit-scrollbar-track { background: transparent; }
.press-gallery::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--page-color, var(--ink)), transparent 60%);
  border-radius: 3px;
}
/* Topics accordion: all 4 numbered topic titles visible at all
   times. Only the active item's body is shown. Scroll button steps
   the active state down the list — the viewer always sees there are
   four items to come. */
.topic-accordion {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin-top: clamp(16px, 2vh, 28px);
}
.topic-item {
  display: flex;
  flex-direction: column;
  border-top: 1px solid color-mix(in srgb, var(--page-color, var(--ink)), transparent 80%);
  padding: clamp(10px, 1.4vh, 18px) 0;
}
/* The clickable target is the <button> inside .topic-heading.
   The h3 wrapper is purely for heading semantics. */
.topic-heading {
  margin: 0;
  font: inherit;
}
.topic-item:last-child {
  border-bottom: 1px solid color-mix(in srgb, var(--page-color, var(--ink)), transparent 80%);
}
/* .topic-header is a real <button>. Reset native button styling so
   it looks like the rest of the typography, but keep it focusable
   and announced as a button to assistive tech. */
.topic-header {
  margin: 0;
  font-family: var(--label);
  font-size: clamp(14px, 1.1vw, 18px);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  /* Full-opacity page colour so all topic colours clear WCAG AA on
     cream. Active state differentiated by font-weight, not opacity. */
  color: var(--page-color, var(--ink));
  font-weight: 400;
  transition: font-weight var(--duration) var(--ease);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.topic-header:focus-visible {
  outline: 3px solid var(--page-color, var(--ink));
  outline-offset: 4px;
}
.topic-item.is-active .topic-header {
  font-weight: 600;
}
/* Click-affordance chevron on accordion headers — rotates when
   active. Applies to BOTH bios and topics accordions so users see
   the same drop-down affordance everywhere on /media/. */
[data-bios-accordion] .topic-header::after,
[data-topics-accordion] .topic-header::after {
  content: '';
  width: 10px;
  height: 10px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  margin-right: 4px;
  transition: transform var(--duration) var(--ease);
  flex: 0 0 auto;
}
[data-bios-accordion] .topic-item.is-active .topic-header::after,
[data-topics-accordion] .topic-item.is-active .topic-header::after {
  transform: rotate(-135deg);
  margin-top: 4px;
}
.topic-body {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows .35s var(--ease), opacity .25s var(--ease), padding-top .25s var(--ease);
  padding-top: 0;
}
.topic-body > * {
  /* Required so the grid row collapses cleanly. */
  min-height: 0;
  overflow: hidden;
}
.topic-item.is-active .topic-body {
  grid-template-rows: 1fr;
  opacity: 1;
  padding-top: clamp(10px, 1.4vh, 18px);
}
.topic-body p {
  margin: 0;
  font-size: clamp(15px, 1.05vw, 18px);
  line-height: 1.55;
}

/* Vertical group divider between gallery categories. Slim
   left-rule + rotated label so the category reads alongside its
   photos without consuming horizontal real estate. */
.press-gallery__divider {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  padding: 0 4px;
  scroll-snap-align: none;
}
.press-gallery__divider-label {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--page-color, var(--ink));
  white-space: nowrap;
  padding: 18px 0 18px 14px;
  border-left: 1px solid color-mix(in srgb, var(--page-color, var(--ink)), transparent 70%);
  opacity: 0.85;
}

/* Each gallery item: figure wrapping the click-to-download photo and
   a meta block underneath with file size, photographer, and IG link. */
.press-photo {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  scroll-snap-align: start;
}
.press-photo__link {
  position: relative;
  display: block;
  height: clamp(170px, 28vh, 240px);
  border-radius: 2px;
  overflow: hidden;
  background: color-mix(in srgb, var(--ink), transparent 92%);
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}
.press-photo__link img {
  display: block;
  height: 100%;
  width: auto;
  object-fit: cover;
  transition: transform var(--duration) var(--ease);
}
.press-photo__link:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px color-mix(in srgb, var(--ink), transparent 75%);
}
/* Keep a visible focus ring for keyboard users — WCAG SC 2.4.13. */
.press-photo__link:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px color-mix(in srgb, var(--ink), transparent 75%);
  outline: 3px solid var(--ink);
  outline-offset: 4px;
}
.press-photo__link:hover img,
.press-photo__link:focus-visible img {
  transform: scale(1.03);
}
.press-photo__download {
  position: absolute;
  left: 50%;
  bottom: 12px;
  transform: translate(-50%, 8px);
  font-family: var(--label);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cream);
  background: var(--page-color, var(--ink));
  padding: 6px 12px;
  border-radius: 999px;
  opacity: 0;
  transition: opacity var(--duration) var(--ease), transform var(--duration) var(--ease);
  pointer-events: none;
  white-space: nowrap;
}
.press-photo__link:hover .press-photo__download,
.press-photo__link:focus-visible .press-photo__download {
  opacity: 1;
  transform: translate(-50%, 0);
}
/* Meta block: file size, photographer, IG handle. All caps, label
   typography, tight line height so the three lines stack closely.
   Coloured in the page topic colour (green on the media page). */
.press-photo__meta {
  margin: 0;
  font-family: var(--label);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--page-color, var(--ink));
  line-height: 1.5;
}
.press-photo__meta p { margin: 0; }
.press-photo__handle {
  display: inline-block;
  color: var(--page-color, var(--ink));
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color var(--duration) var(--ease);
}
.press-photo__handle:hover,
.press-photo__handle:focus-visible {
  border-bottom-color: var(--page-color, var(--ink));
  outline: none;
}

/* Book promotional assets — single cover image used on Startup
   Coach / Franchising Handbook sections, and a three-up image
   row on the BOSS IT section (cover + two quote tiles). */
.book-cover {
  display: block;
  max-width: clamp(160px, 22vw, 260px);
  height: auto;
  margin: clamp(16px, 2.5vh, 32px) 0;
  border-radius: 2px;
}
.book-images {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(10px, 1.4vw, 20px);
  margin: clamp(16px, 2.5vh, 32px) 0;
  max-width: 100%;
}
.book-images img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 2px;
}

/* Awards callout on the BOSS IT section. Tight Bebas Neue lines
   in the page colour, sitting between lede and body. */
.book-awards {
  margin: clamp(12px, 2vh, 24px) 0 clamp(16px, 2.5vh, 28px) 0;
}
.book-awards p {
  font-family: var(--label);
  font-size: clamp(11px, 0.9vw, 14px);
  letter-spacing: 0.08em;
  line-height: 1.4;
  margin: 0 0 6px 0;
  color: var(--page-color, var(--ink));
}

/* CTA button on subpages. Works for both <a class="btn"> and
   <button class="btn"> — explicit border/cursor reset stops the
   native button user-agent border showing through.
   justify-content + symmetric padding + line-height: 1 keep the
   text exactly centred horizontally and vertically. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 16px 24px;
  background: var(--ink);
  color: var(--cream);
  font-family: var(--label);
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1;
  border: none;
  cursor: pointer;
  border-radius: 999px;
  transition: transform var(--duration) var(--ease);
  margin-top: 16px;
}
.btn__arrow {
  width: 36px;
  height: 36px;
  display: inline-block;
  background-image: url('/img/back-button.png');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  transform: scaleX(-1);
  transition: transform var(--duration) var(--ease);
}
.btn:hover { transform: translateY(-2px); }
.btn:hover .btn__arrow { transform: translateX(4px) scaleX(-1); }


/* =========================================================
   PLACEHOLDER watermark — for pages whose content is not yet final
   ========================================================= */
.subpage--placeholder .subpage__content::before {
  content: 'PLACEHOLDER';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotate(-22deg);
  font-family: var(--label);
  font-size: clamp(90px, 14vw, 220px);
  font-weight: 700;
  letter-spacing: 0.18em;
  color: var(--ink);
  opacity: 0.08;
  pointer-events: none;
  z-index: 50;
  white-space: nowrap;
}


/* =========================================================
   RESPONSIVE
   ========================================================= */
@media (max-width: 1024px) {
  :root { --bar-width: 9vw; }
}
@media (max-width: 720px) {
  /* =========================================================
     MOBILE PORTRAIT
     Golden-ratio split: cream/content area takes 61.8% of the
     viewport height; the bar strip takes the lower 38.2%.
     When a bar is tapped/active, cream drops to 38.2% and the
     active bar absorbs the 23.6% gain (other bars stay put).
     All bars become horizontal full-width bands. Bar colours,
     order, wording and fonts match desktop verbatim.
  ========================================================= */

  /* ---------- HOMEPAGE ---------- */
  .home {
    flex-direction: column;
  }
  .cream {
    flex: 0 0 61.8vh;
    flex: 0 0 61.8dvh;
    transition: flex-basis var(--duration) var(--ease);
  }
  .bars {
    flex: 0 0 38.2vh;
    flex: 0 0 38.2dvh;
    flex-direction: column;
    width: 100%;
    transition: flex-basis var(--duration) var(--ease);
  }
  .home .bar {
    width: 100%;
    height: 7.64vh;
    height: 7.64dvh;
    flex: 0 0 7.64vh;
    flex: 0 0 7.64dvh;
    transition: flex-basis var(--duration) var(--ease),
                filter 90ms ease-out;
  }
  /* Bar tap/hover: cream shrinks to 38.2vh, active bar absorbs the
     extra 23.6vh, other bars hold at 7.64vh. Same proportions as
     the desktop hover expansion. */
  .home:has(.bar:hover) .cream,
  .home.has-active .cream {
    flex: 0 0 38.2vh;
    flex: 0 0 38.2dvh;
  }
  .home:has(.bar:hover) .bars,
  .home.has-active .bars {
    flex: 0 0 61.8vh;
    flex: 0 0 61.8dvh;
  }
  .home .bar:hover,
  .home .bar.is-active {
    flex: 0 0 31.24vh;
    flex: 0 0 31.24dvh;
    height: 31.24vh;
    height: 31.24dvh;
  }

  /* Wordmark: 38.2vw wide, anchored to bottom-left of cream area,
     sitting just above the bar strip. translateY(35.9%) compensates
     for the PNG's transparent bottom padding so the visible "carl."
     baseline lines up with the configured bottom value. The added
     translateX(-2.05%) compensates for the PNG's 41/2000 transparent
     LEFT padding — without it, the visible "c" sits ~3px to the
     right of the bar labels' first letter, which looks unaligned.
     With it, "c" starts at the same x as "Keynote Speaker" etc. */
  .wordmark {
    width: 38.2vw;
    left: clamp(16px, 4vw, 32px);
    bottom: calc(38.2vh + clamp(8px, 2vh, 24px));
    bottom: calc(38.2dvh + clamp(8px, 2vh, 24px));
    transform: translate(-2.05%, 35.9%);
  }
  .home:has(.bar:hover) .wordmark,
  .home.has-active .wordmark {
    bottom: calc(61.8vh + clamp(8px, 2vh, 24px));
    bottom: calc(61.8dvh + clamp(8px, 2vh, 24px));
  }
  .wordmark__small-print {
    display: block;
    left: clamp(16px, 4vw, 32px);
    bottom: calc(38.2vh - clamp(20px, 3vh, 32px));
    bottom: calc(38.2dvh - clamp(20px, 3vh, 32px));
    max-width: 60vw;
    font-size: 12px;
  }

  /* Bar labels: horizontal, left-aligned. Same font and casing as
     desktop — just rotated 0° and re-placed. */
  .home .bar__label {
    position: absolute;
    top: 50%;
    left: clamp(16px, 4vw, 32px);
    bottom: auto;
    transform: translateY(-50%);
    transform-origin: center;
    font-size: clamp(18px, 5vw, 24px);
    letter-spacing: 0.04em;
    text-align: left;
  }
  /* On mobile the hero image still uses the base rule
     (opacity 0 by default, opacity 1 on .is-active) — but with
     full-width bars the image now fills the whole bar when tapped.
     CTA pill stays hidden until the bar is active, then appears so
     the user knows the second tap will navigate. */
  .bar__cta { display: none; }
  .home .bar.is-active .bar__cta {
    display: inline-flex;
    opacity: 1;
    /* Override the absolute placement from desktop. On mobile bars
       the pill sits centred at the bottom of the expanded bar so
       it's obviously the next thing to tap. */
    top: auto;
    left: 50%;
    bottom: clamp(16px, 3vh, 32px);
    transform: translateX(-50%);
    font-size: clamp(14px, 4vw, 18px);
    padding: 12px 24px;
    z-index: 2;
  }


  /* ---------- SUBPAGES ---------- */
  /* Layout: a horizontal "current" bar at the top, content cream
     in the middle (61.8% of remaining), the right-nav strip as
     stacked horizontal bars at the bottom. */
  .subpage {
    flex-direction: column;
  }
  .subpage__bars-left {
    flex: 0 0 7.64vh;
    flex: 0 0 7.64dvh;
    width: 100%;
    flex-direction: row;
    height: 7.64vh;
    height: 7.64dvh;
  }
  .subpage__bars-left .bar {
    width: 100%;
    height: 7.64vh;
    height: 7.64dvh;
    flex: 1 1 auto;
  }
  .subpage__content,
  .subpage--has-logos .subpage__content,
  .subpage--scroll .subpage__scroller {
    flex: 1 1 auto;
    width: 100%;
    height: auto;
    padding: clamp(20px, 4vh, 40px) clamp(16px, 4vw, 32px);
    /* Clear the desktop fade masks — on mobile the text should
       run all the way down to the bar strip without fading. */
    -webkit-mask-image: none;
            mask-image: none;
  }
  .subpage__bars-right {
    flex: 0 0 30.56vh;
    flex: 0 0 30.56dvh;
    width: 100%;
    flex-direction: column;
    height: 30.56vh;
    height: 30.56dvh;
  }
  .subpage__bars-right .bar {
    width: 100%;
    height: 7.64vh;
    height: 7.64dvh;
    flex: 1 1 0;
  }

  /* Horizontal labels on every subpage bar. */
  .subpage .bar__label {
    position: absolute;
    top: 50%;
    left: clamp(56px, 14vw, 88px);
    bottom: auto;
    transform: translateY(-50%);
    transform-origin: center;
    font-size: clamp(15px, 4vw, 20px);
    letter-spacing: 0.04em;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: calc(100% - 96px);
  }
  /* Right-bar labels don't have a back graphic — pull them left. */
  .subpage__bars-right .bar__label {
    left: clamp(16px, 4vw, 32px);
    max-width: calc(100% - 32px);
  }

  /* Back graphic: small circle pinned to the left of the top bar. */
  .bar__back {
    position: absolute;
    top: 50%;
    left: clamp(8px, 2vw, 16px);
    width: clamp(36px, 8vw, 56px);
    height: clamp(36px, 8vw, 56px);
    transform: translateY(-50%);
  }
  .subpage .bar--current:hover .bar__back {
    transform: translateY(-50%) translateX(-4px);
  }

  /* Mobile: hide things that don't fit the portrait layout. */
  .subpage__wordmark { display: none; }
  .scroll-controls { display: none; }
  .subpage__logos { display: none; }

  /* Scroll-snap turned off on mobile — native scrolling is fine. */
  .subpage--scroll .subpage__scroller {
    scroll-snap-type: none;
    overflow-y: auto;
  }
  .subpage__section {
    min-height: auto;
    padding: clamp(20px, 4vh, 40px) 0 clamp(28px, 6vh, 56px) 0;
    scroll-snap-align: none;
  }
  .subpage__body .bullet {
    min-height: auto;
    scroll-snap-align: none;
    scroll-margin-top: 0;
  }

  /* ---------- MOBILE FIXES (post-test review) ---------- */

  /* Hide the "STAGES CARL HAS SPOKEN AT" / "CARL HAS APPEARED IN"
     heading on mobile — the logos column itself is hidden so the
     dangling label served no purpose. */
  .subpage__logos-heading { display: none; }

  /* Photos gallery: the rotated category labels stop making sense
     when the gallery is a vertical grid. Caption header gets hidden
     too — the grid is mixed AW/SS so a single "Formal: Cold Weather"
     label was misleading. */
  .press-gallery__divider { display: none; }
  .press-gallery__caption { display: none; }

  /* Photos gallery: switch from horizontal scroll to a 2-column
     vertical grid (Instagram-style). Each photo keeps its caption
     block underneath. */
  .press-gallery {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: clamp(8px, 2vw, 16px);
    overflow: visible;
    scroll-snap-type: none;
    padding: 0;
  }
  .press-photo {
    width: 100%;
  }
  .press-photo__link {
    height: auto;
    aspect-ratio: 3 / 4;
  }
  .press-photo__link img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  /* "Download" pill always visible on mobile since hover doesn't
     apply on touch. */
  .press-photo__download {
    opacity: 1;
    transform: translate(-50%, 0);
    font-size: 10px;
    padding: 4px 10px;
  }

  /* Body text — make sure the content column truly fills the screen
     width on mobile (was capped at 64ch which is wider than a phone
     viewport, so technically fine, but list bullets had a 60ch cap
     before — leave both at 100% for safety). */
  .subpage__section p,
  .subpage__body ul {
    max-width: 100%;
  }

  /* Sticky H1 on .subpage__section:has(.bullet) was making the
     section title float over scrolling content on legal page (and
     would on books / startup-coach too). On mobile we use native
     scroll, no sticky needed — the title sits in flow like any other
     heading. */
  .subpage--scroll .subpage__section:has(.bullet) .subpage__title {
    position: static;
    background: transparent;
  }

  /* Topics + bios accordions get a touch more breathing room on
     mobile so tap targets are comfortable. */
  .topic-header {
    padding: clamp(6px, 1.2vh, 12px) 0;
    min-height: 44px; /* WCAG SC 2.5.5 minimum target size */
  }

  /* Homepage bars: re-enable a small "tap to view" affordance so
     users know each bar is interactive (touch devices don't show
     the desktop hover CTA pill). Subtle chevron at the right edge. */
  .home .bar::after {
    content: '';
    position: absolute;
    top: 50%;
    right: clamp(16px, 4vw, 32px);
    width: 18px;
    height: 18px;
    border-right: 2px solid var(--cream);
    border-bottom: 2px solid var(--cream);
    transform: translateY(-65%) rotate(-45deg);
    opacity: 0.65;
    transition: opacity 240ms ease, transform 240ms ease;
    pointer-events: none;
  }
  .home .bar.is-active::after {
    opacity: 0;
    transform: translateY(-50%) rotate(45deg);
  }

  /* Homepage hero image: per-bar focal point. The source images
     have different aspect ratios — two are portraits (Carl full-body
     for /work-with-carl/ and /about/), one is landscape (Carl on
     stage for /speaking/), two are square. The desktop CSS sets
     background-position via inline style on each bar — tuned for a
     TALL NARROW desktop bar. On mobile bars (wide and short) those
     values crop Carl out. Override here so each bar keeps the
     subject in frame. */
  .home .bar.is-active .bar__hero {
    background-position: center 30% !important;
  }
  /* hero-work.jpg and hero-about.jpg are portraits — Carl's face
     sits in the upper third. Bias the crop toward the top so the
     mobile-bar window catches his head, not his shoes / belt. */
  .home .bar--work.is-active .bar__hero,
  .home .bar--about.is-active .bar__hero {
    background-position: center 12% !important;
  }
  /* hero-keynote.jpg is landscape (2000×1333) — centre crop works. */
  .home .bar--speaking.is-active .bar__hero {
    background-position: center center !important;
  }

  /* ---------- HIGH-SPECIFICITY OVERRIDES ----------
     The desktop CSS has several rules with 3+ classes of specificity
     that win against plain `.home .bar` (2 classes) and `.subpage__section`
     (1 class) inside this media query. We restate them here with the
     same selectors so the cascade resolves cleanly on mobile. */

  /* Homepage: when a bar is active/hovered the desktop rule expands
     its WIDTH by 23.6vw. On mobile each bar is already full-width;
     only the HEIGHT changes when active. */
  .home .bar:hover,
  .home .bar.is-active,
  .home.has-active .bar.is-active,
  .home:has(.bar:hover) .bar:hover {
    width: 100%;
  }

  /* Subpage scroll-section: the desktop rule pads the section's right
     side by 244-300px to make room for the absolute-positioned logos
     column. On mobile the column is hidden so all that padding does
     is squash content into the left third of the screen. Zero it. */
  .subpage--scroll.subpage--has-logos .subpage__section {
    padding-right: 0;
  }

  /* First section of every subpage fills the available scroller
     viewport on mobile so the SECOND section (topics, on /speaking/
     and /media/) sits below the fold. Initial landing shows only
     the landing copy; the topics live behind a deliberate scroll or
     a right-nav tap.
     The mobile chrome takes ~38% of the viewport (top bar 7.64vh +
     right-bars column 30.56vh), so the scroller is ~61.8vh. We use
     61dvh (not min-height: 100%) because the scroller's height
     comes from flex sizing, and percentage min-heights don't
     resolve against flex-sized parents reliably. */
  .subpage--scroll .subpage__section:first-of-type {
    min-height: 61dvh;
  }

  /* Media topics + biographies sections: fill at least the full
     scroller height so the next section's heading never peeks in.
     Mobile chrome (top bar 7.6vh + right-bars column 30.6vh) eats
     ~38.2vh — the same proportion on every phone size because the
     bars are sized in vh. The scroller therefore always renders at
     ~61.8% of the dynamic viewport, so 62dvh covers it with a
     1-2px safety margin without overshooting onto the right bars.
     Topics section additionally gets a tightened top-padding so all
     4 accordion headers fit in the viewport once scrolled in. */
  .subpage--scroll .subpage__section--topics,
  .subpage__section--topics {
    padding-top: clamp(16px, 3vh, 32px);
    min-height: 62dvh;
  }
  .subpage--scroll #biographies,
  #biographies {
    min-height: 62dvh;
  }
  .subpage__section--topics .subpage__title {
    margin-bottom: clamp(8px, 1.4vh, 16px);
  }
  .subpage__section--topics .topic-header {
    padding: clamp(8px, 1.4vh, 14px) 0;
  }

  /* Partner logos: max-width clamp(96px, 9vw, 150px) was fine on
     desktop but on mobile 9vw = 34px (collapsed to the 96px floor)
     while the section now has 0 right-padding. Force them to a
     consistent comfortable size — full visibility, no squashing. */
  .partner-logo {
    max-width: clamp(120px, 38vw, 180px);
    max-height: clamp(56px, 8vh, 88px);
    margin: 0 0 clamp(16px, 2.2vh, 24px) 0;
  }
  .partner-logos {
    max-width: 100%;
    grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
    gap: clamp(14px, 3vw, 20px);
  }
}


/* =========================================================
   ACCESSIBILITY
   ========================================================= */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
  .bar__hero { transform: none; }
}
.bar:focus-visible,
.btn:focus-visible,
.subpage__back:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: 4px;
}
