/* ==========================================================================
   Winterberg Design Studio
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

body,
h1,
h2,
h3,
p,
ul,
ol,
figure,
blockquote,
table {
  margin: 0;
}

ul[class] {
  padding: 0;
  list-style: none;
}

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

button,
input {
  font: inherit;
  color: inherit;
}

/* --- tokens --------------------------------------------------------------- */

:root {
  --bg: #fbfbfb;
  --ink: #333;
  --ink-strong: #222;
  --ink-nav: #111;
  --ink-muted: #6b6b6b;
  --ink-invert: #fbfbfb;
  --surface-dark: #111;
  /* Text on the always-dark chips (skip link, folder menu). Unlike
     --ink-invert it stays light in both themes. */
  --on-dark: #fbfbfb;
  /* Letterbox behind video and slides — near-black in both themes so the
     footage, not the frame, is the darkest thing on screen. */
  --media-bg: #111;
  --rule: #e2e2e2;
  --field-border: #8a8a8a;
  --accent: #FF6568;

  --font-display: "Jost", "Futura", "Futura PT", "Century Gothic",
    "Trebuchet MS", sans-serif;
  --font-body: "Mulish", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;

  --text: 14px;
  --leading: 1.6;
  --tracking: 0.5px;

  --gutter: 50px;
  --measure: 720px;
  --header-gap: 100px;

  --ease-out: cubic-bezier(0.2, 0, 0, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  --z-dropdown: 10;
  --z-header: 30;
  --z-overlay: 40;
  --z-skip: 100;

  color-scheme: light;
}

/* Dark theme — the same neutral ramp flipped, cooled a touch so it sits with
   the navy in the logo mark. The attribute is set by the inline script in each
   page's <head> before first paint, then toggled by site.js. */

[data-theme="dark"] {
  --bg: #14161a;
  --ink: #c8ccd2;
  --ink-strong: #f2f4f7;
  --ink-nav: #f2f4f7;
  --ink-muted: #949aa3;
  --ink-invert: #14161a;
  --surface-dark: #262b33;
  --media-bg: #0f1114;
  --rule: #2b3038;
  --field-border: #4b525c;

  color-scheme: dark;
}

/* --- base ----------------------------------------------------------------- */

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text);
  line-height: var(--leading);
  letter-spacing: var(--tracking);
}

h1,
h2,
h3 {
  text-wrap: balance;
}

p,
li,
figcaption,
blockquote {
  text-wrap: pretty;
}

a {
  color: var(--ink-strong);
}

:focus-visible {
  outline: 2px solid var(--ink-nav);
  outline-offset: 3px;
}

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

.skip-link {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: var(--z-skip);
  padding: 10px 16px;
  background: var(--surface-dark);
  color: var(--on-dark);
  font-family: var(--font-display);
  text-decoration: none;
  transition: top 0.15s var(--ease-out);
}

.skip-link:focus {
  top: 12px;
}

.canvas {
  padding: var(--gutter);
}

.measure {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
}

/* --- header --------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  display: flex;
  align-items: center;
  gap: 16px;
  /* Bleed to the canvas edges so the sticky bar's background spans full width,
     then restore the gutter inset via padding. Negative top margin collapses
     the canvas's top gutter so the bar starts flush at the top rather than
     leaving a gap that scrolls away. */
  margin: calc(-1 * var(--gutter)) calc(-1 * var(--gutter)) 0;
  /* Shave 75px off the bar's bottom padding (clamped so the smaller responsive
     header-gap can't go negative); that 75px is handed to main's top instead,
     so the pinned bar is shorter without losing space above the content. */
  padding: var(--gutter) var(--gutter) max(0px, calc(var(--header-gap) - 75px));
  background: var(--bg);
}

/* The 75px trimmed from the sticky bar lives here instead, keeping the space
   above the first content unchanged while the pinned bar sits shorter. */
#main {
  padding-top: 75px;
}

.logo {
  font-size: 0;
  line-height: 0;
  margin: 0;
  /* Pushes the nav and the toggles to the right edge. */
  margin-right: auto;
  letter-spacing: normal;
}

.logo a {
  display: block;
}

.logo img {
  width: auto;
  height: 22px;
}

/* Two lockups rather than a CSS filter: the mark's mint and cream keep their
   colours, only the navy wordmark is redrawn light. */
.logo-dark {
  display: none;
}

[data-theme="dark"] .logo-light {
  display: none;
}

[data-theme="dark"] .logo-dark {
  display: block;
}

/* --- primary nav ---------------------------------------------------------- */

.nav {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 2.5px;
  text-transform: uppercase;
}

.nav-list {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav-list > li + li {
  margin-left: clamp(18px, 3vw, 36px);
}

.nav-list a,
.nav-folder > button {
  position: relative;
  display: block;
  padding: 4px 0;
  color: var(--ink-nav);
  text-decoration: none;
  /* Accent underline, matching the reel header. */
  background-image: linear-gradient(var(--accent), var(--accent));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1px;
  transition: background-size 350ms cubic-bezier(0.2, 0.8, 0.2, 0.8);
}

.nav-list a::after,
.nav-folder > button::after {
  content: "";
  position: absolute;
  inset: -11px -6px;
}

.nav-list a:hover,
.nav-folder > button:hover {
  background-size: 100% 1px;
}

.nav-list .is-current > a,
.nav-list .is-current > button {
  background-size: 100% 1px;
}

.nav-folder > button:hover {
  background-size: 0% 1px;
}

/* folder ("Portfolio") --------------------------------------------------- */

.nav-folder {
  position: relative;
}

.nav-folder > button {
  border: 0;
  background-color: transparent;
  font: inherit;
  letter-spacing: inherit;
  /* Buttons don't inherit text-transform from the UA stylesheet. */
  text-transform: inherit;
  cursor: pointer;
}

/* inline-block keeps the hover underline off the plus — decorations don't
   propagate into an atomic inline box. */
.nav-folder > button::before {
  content: "+";
  display: inline-block;
  margin-right: 6px;
}

.nav-folder-menu {
  position: absolute;
  top: 100%;
  z-index: var(--z-dropdown);
  padding-top: 18px;
  visibility: hidden;
  transition: visibility 0s linear 180ms;
}

/* The visible surface. Phase 1 of the open sequence grows it from its
   top-left corner toward the bottom-right; the rows inside stay hidden until
   it finishes, so what expands reads as an empty container. */
.nav-folder-menu ul {
  margin: 0;
  padding: 15px 20px;
  background: var(--surface-dark);
  list-style: none;
  white-space: nowrap;
  transform: scale(0);
  transform-origin: top left;
  transition: transform 180ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* The base `text-wrap: pretty` on li resets text-wrap-mode, which undoes the
   nowrap inherited from the menu, so restate it on the rows themselves.
   Phase 2 fades each row in; the per-row delay is set on the open state. */
.nav-folder-menu li {
  white-space: nowrap;
  opacity: 0;
  transition: opacity 180ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* inline-block sizes the row to its label, so the hover underline draws
   left-to-right under the text rather than across the whole panel. */
.nav-folder-menu a {
  display: inline-block;
  padding: 6px 0;
  color: var(--on-dark);
  font-size: 11px;
  letter-spacing: 2px;
}

/* The label stays text-width for the underline, but the click target should be
   the whole row. Anchor the hit-expander pseudo to the li (position: static on
   the anchor hands the ::after's containing block to the relative li) and
   stretch it edge-to-edge, so the full row width is clickable with no vertical
   bleed into neighbouring rows. */
.nav-folder-menu li {
  position: relative;
}

.nav-folder-menu a {
  position: static;
}

.nav-folder-menu a::after {
  inset: 0;
}

.nav-folder:focus-within .nav-folder-menu,
.nav-folder > button[aria-expanded="true"] + .nav-folder-menu {
  visibility: visible;
  transition-delay: 0s;
}
.nav-folder:focus-within .nav-folder-menu ul,
.nav-folder > button[aria-expanded="true"] + .nav-folder-menu ul {
  transform: scale(1);
}
.nav-folder:focus-within .nav-folder-menu li,
.nav-folder > button[aria-expanded="true"] + .nav-folder-menu li {
  opacity: 1;
}
.nav-folder:focus-within .nav-folder-menu li:nth-child(1),
.nav-folder > button[aria-expanded="true"] + .nav-folder-menu li:nth-child(1) { transition-delay: 160ms; }
.nav-folder:focus-within .nav-folder-menu li:nth-child(2),
.nav-folder > button[aria-expanded="true"] + .nav-folder-menu li:nth-child(2) { transition-delay: 170ms; }
.nav-folder:focus-within .nav-folder-menu li:nth-child(3),
.nav-folder > button[aria-expanded="true"] + .nav-folder-menu li:nth-child(3) { transition-delay: 180ms; }
.nav-folder:focus-within .nav-folder-menu li:nth-child(4),
.nav-folder > button[aria-expanded="true"] + .nav-folder-menu li:nth-child(4) { transition-delay: 190ms; }
.nav-folder:focus-within .nav-folder-menu li:nth-child(5),
.nav-folder > button[aria-expanded="true"] + .nav-folder-menu li:nth-child(5) { transition-delay: 200ms; }

/* Hover-to-open only where hover is real; touch devices use the click
   handler in site.js */
@media (hover: hover) and (pointer: fine) {
  .nav-folder:hover .nav-folder-menu { visibility: visible; transition-delay: 0s; }
  .nav-folder:hover .nav-folder-menu ul { transform: scale(1); }
  .nav-folder:hover .nav-folder-menu li { opacity: 1; }
  .nav-folder:hover .nav-folder-menu li:nth-child(1) { transition-delay: 160ms; }
  .nav-folder:hover .nav-folder-menu li:nth-child(2) { transition-delay: 170ms; }
  .nav-folder:hover .nav-folder-menu li:nth-child(3) { transition-delay: 180ms; }
  .nav-folder:hover .nav-folder-menu li:nth-child(4) { transition-delay: 190ms; }
  .nav-folder:hover .nav-folder-menu li:nth-child(5) { transition-delay: 200ms; }
}

/* --- mobile nav ----------------------------------------------------------- */

.nav-toggle {
  display: none;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.nav-toggle span,
.nav-toggle span::before,
.nav-toggle span::after {
  display: block;
  height: 2px;
  width: 24px;
  margin-inline: auto;
  background: var(--ink-nav);
  transition: transform 0.2s var(--ease-out), opacity 0.2s var(--ease-out);
}

.nav-toggle span {
  position: relative;
}

.nav-toggle span::before,
.nav-toggle span::after {
  content: "";
  position: absolute;
  left: 0;
}

.nav-toggle span::before {
  top: -7px;
}

.nav-toggle span::after {
  top: 7px;
}

.nav-toggle[aria-expanded="true"] span {
  background: transparent;
}

.nav-toggle[aria-expanded="true"] span::before {
  transform: translateY(7px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] span::after {
  transform: translateY(-7px) rotate(-45deg);
}

.mobile-nav {
  display: none;
  padding: 0 0 40px;
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: 2px;
  text-transform: uppercase;
}

.mobile-nav[data-open="true"] {
  display: block;
}

.mobile-nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.mobile-nav a,
.mobile-nav .mobile-nav-label {
  display: block;
  padding: 12px 0;
  border-bottom: 1px solid var(--rule);
  color: var(--ink-nav);
  text-decoration: none;
  font-size: 13px;
}

.mobile-nav ul ul a {
  padding-left: 20px;
  font-size: 11px;
}

.mobile-nav .mobile-nav-label {
  color: var(--ink-muted);
}

.mobile-location {
  margin-top: 30px;
  color: var(--ink-muted);
  font-family: var(--font-body);
  font-size: 13px;
  letter-spacing: var(--tracking);
}

/* --- theme toggle --------------------------------------------------------- */

/* The sun/moon icon and its choreography come from the Masthead project. One
   glyph plays both parts: a disc, a "bite" circle that slides out of the way to
   make a full sun, and a ring of rays. */

.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-nav);
  cursor: pointer;
  transition: transform 0.1s var(--ease-out);
}

.theme-toggle:active {
  transform: scale(0.94);
}

.theme-icon {
  display: block;
  overflow: visible;
}

.ti-rays,
.ti-disc {
  transform-box: fill-box;
  transform-origin: center;
}

/* Resting — light: full sun disc (bite hole and inner arc slid clear), rays out.
   Every animating class carries .is-animating too, so one guard covers them. */
.theme-toggle:not(.is-animating) .ti-bite {
  transform: translate(9px, -7px);
}

.theme-toggle:not(.is-animating) .ti-rays {
  opacity: 1;
  transform: scale(1);
}

.theme-toggle:not(.is-animating) .ti-disc {
  opacity: 1;
  transform: none;
}

/* Resting — dark: crescent moon, rays hidden. The moon renders 50% larger than
   the sun, and the size comes from the SVG's own dimensions rather than a
   transform: scaling the masked disc as a bitmap blurs its edges. */
[data-theme="dark"] .theme-toggle:not(.is-animating) .ti-bite {
  transform: translate(0, 0);
}

[data-theme="dark"] .theme-toggle:not(.is-animating) .ti-rays {
  opacity: 0;
  transform: scale(0.3);
}

[data-theme="dark"] .theme-toggle:not(.is-animating) .theme-icon {
  width: 27px;
  height: 27px;
}

/* Icon states for the view-transition swap. The page cross-fades as a snapshot,
   so the icon is parked (hold-*) while that runs and plays (play-*) once it
   lands. The sun setting and the crescent filling happen inside the fade. */
.theme-toggle.hold-dark .ti-disc,
.theme-toggle.hold-dark .ti-rays {
  opacity: 0;
}

.theme-toggle.hold-dark .ti-bite {
  transform: translate(0, 0);
}

.theme-toggle.hold-light .ti-bite {
  transform: translate(9px, -7px);
}

.theme-toggle.hold-light .ti-disc {
  opacity: 1;
  transform: none;
}

.theme-toggle.hold-light .ti-rays {
  opacity: 0;
  transform: scale(0.3);
}

.theme-toggle.play-moonrise .ti-bite {
  transform: translate(0, 0);
}

.theme-toggle.play-moonrise .ti-disc {
  animation: ti-moon-arc 500ms var(--ease-out) both;
}

.theme-toggle.play-moonrise .ti-rays {
  opacity: 0;
}

.theme-toggle.play-rays .ti-bite {
  transform: translate(9px, -7px);
}

.theme-toggle.play-rays .ti-disc {
  opacity: 1;
  transform: none;
}

.theme-toggle.play-rays .ti-rays {
  animation: ti-rays-emerge 500ms cubic-bezier(0.175, 0.885, 0.32, 1.275) both;
}

/* Dark to light: the crescent fills into a disc alongside the page fade, then
   the rays spring out. Fallback path, for browsers without view transitions. */
.theme-toggle.anim-to-light .ti-bite {
  animation: ti-bite-open 500ms cubic-bezier(0.645, 0.045, 0.355, 1) both;
}

.theme-toggle.anim-to-light .ti-rays {
  animation: ti-rays-emerge 500ms cubic-bezier(0.175, 0.885, 0.32, 1.275) 500ms both;
}

.theme-toggle.anim-to-light .ti-disc {
  animation: ti-disc-shrink 500ms cubic-bezier(0.645, 0.045, 0.355, 1) both;
}

/* Light to dark, phase A: the sun sets — disc and rays drop and fade out. */
.theme-toggle.anim-to-dark:not(.phase-moonrise) .ti-bite {
  transform: translate(9px, -7px);
}

.theme-toggle.anim-to-dark:not(.phase-moonrise) .ti-disc {
  animation: ti-sun-set 500ms var(--ease-out) both;
}

.theme-toggle.anim-to-dark .ti-rays {
  animation: ti-sun-set 500ms var(--ease-out) both;
}

/* Light to dark, phase B: the moon arcs in from the lower left. */
.theme-toggle.anim-to-dark.phase-moonrise .ti-bite {
  transform: translate(0, 0);
}

.theme-toggle.anim-to-dark.phase-moonrise .ti-disc {
  animation: ti-moon-arc 500ms var(--ease-out) both;
}

.theme-toggle.anim-to-dark.phase-moonrise .ti-rays {
  opacity: 0;
}

@keyframes ti-bite-open {
  from {
    transform: translate(0, 0);
  }
  to {
    transform: translate(9px, -7px);
  }
}

@keyframes ti-rays-emerge {
  from {
    opacity: 0;
    transform: scale(0.3);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes ti-sun-set {
  from {
    opacity: 1;
    transform: translateY(0);
  }
  to {
    opacity: 0;
    transform: translateY(8px);
  }
}

@keyframes ti-moon-arc {
  0% {
    opacity: 0;
    transform: translate(-9px, 8px) scale(1.05);
  }
  25% {
    opacity: 1;
    transform: translate(-6.6px, 8.4px) scale(1.3);
  }
  50% {
    opacity: 1;
    transform: translate(-4.4px, 7.4px) scale(1.5);
  }
  74% {
    opacity: 1;
    transform: translate(-2.5px, 4.2px) scale(1.56);
  }
  100% {
    opacity: 1;
    transform: translate(0, 0) scale(1.5);
  }
}

@keyframes ti-disc-shrink {
  from {
    transform: scale(1.5);
  }
  to {
    transform: scale(1);
  }
}

/* Cross-fade the page as a snapshot. Fading the colours on the live DOM instead
   repaints every glyph on every frame, and that re-rasterising shows up as a
   flicker in the text — tried, still flickered, so the snapshot it is. A view
   transition rasterises each theme once and fades the two images. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 450ms;
  animation-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1);
}

/* Used when SWAP is set to "fade" in site.js, and by browsers without view
   transitions: fade the colour properties on the live DOM. Only the four that
   actually change; stroke follows currentColor and rides along with `color`. */
.is-theme-transitioning,
.is-theme-transitioning *,
.is-theme-transitioning *::before,
.is-theme-transitioning *::after {
  transition: background-color 500ms cubic-bezier(0.645, 0.045, 0.355, 1),
    color 500ms cubic-bezier(0.645, 0.045, 0.355, 1),
    border-color 500ms cubic-bezier(0.645, 0.045, 0.355, 1),
    fill 500ms cubic-bezier(0.645, 0.045, 0.355, 1) !important;
}

/* --- prose ---------------------------------------------------------------- */

.prose h1,
.prose h2,
.prose h3,
.prose .as-h1,
.prose .as-h3 {
  color: var(--ink-strong);
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 2px;
}

.prose h1,
.prose .as-h1 {
  font-size: 33.6px;
  line-height: 1.2;
  margin: 0 0 25.2px;
}

.prose h2 {
  font-size: 25.2px;
  line-height: 1.2;
  margin: 50.4px 0 18.9px;
}

.prose h3,
.prose .as-h3 {
  font-size: 16.8px;
  line-height: 1.2;
  margin: 33.6px 0 12.6px;
}

.prose > :first-child {
  margin-top: 0;
}

.prose p {
  margin: 0 0 22.4px;
}

.prose p:last-child {
  margin-bottom: 0;
}

/* Squarespace indents the themed/option paragraphs by 40px inline. */
.prose p.indent {
  margin-left: 40px;
}

.prose strong {
  color: var(--ink-strong);
  font-weight: 700;
}

.prose ul,
.prose ol {
  margin: 14px 0;
  padding-left: 40px;
}

.prose li p {
  margin-bottom: 7px;
}

.prose a {
  color: var(--ink-strong);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.prose a:hover {
  text-decoration: none;
}

/* --- content blocks ------------------------------------------------------- */

.block {
  margin-bottom: 34px;
}

.block:last-child {
  margin-bottom: 0;
}

.block-image figure {
  margin: 0;
}

.block-image img {
  width: 100%;
  height: auto;
}

.block-image figcaption,
.block-video figcaption {
  margin-top: 10px;
  color: var(--ink-muted);
  font-size: 13px;
}

/* portrait phone captures sit side by side rather than full-bleed */
.video-pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
  justify-content: center;
  max-width: 560px;
  margin-inline: auto;
}

.block-video figure {
  margin: 0;
}

.block-video video {
  width: 100%;
  height: auto;
  background: var(--media-bg);
}

/* --- animated UI captures (Masthead) -------------------------------------- */

/* Animated WebP of the live product. Each capture is a crop of a real screen, so
   it needs a hairline: the app's own cream and charcoal surfaces otherwise bleed
   into the page background in whichever theme happens to match. */

.block-anim figure {
  margin: 0;
}

.block-anim img {
  width: 100%;
  height: auto;
  border-radius: 8px;
  box-shadow: 0 0 0 1px var(--rule);
}

.block-anim figcaption {
  margin-top: 10px;
  color: var(--ink-muted);
  font-size: 13px;
}

.anim-xs { max-width: 132px; }
.anim-sm { max-width: 320px; }
.anim-md { max-width: 440px; }
.anim-lg { max-width: 540px; }

.block-anim figure[class*="anim-"] {
  margin-inline: auto;
}

/* The toggle capture is 88px of artwork; a caption under it would be wider than
   the thing it labels, so it sits alongside instead. */
.anim-aside {
  display: flex;
  align-items: center;
  gap: 24px;
}

.anim-aside img {
  flex: 0 0 auto;
  width: 88px;
}

.anim-aside figcaption {
  margin-top: 0;
}

@media (max-width: 520px) {
  .anim-aside {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* grid gallery (Kurbo) */

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}

.gallery-grid img {
  width: 100%;
  height: auto;
}

/* --- roadmap table (Shopify Retail) -------------------------------------- */

/* The original ships this as an unstyled code block, including a malformed
   <color=#ff6600> pseudo-tag. Styled here in the site's own type. */

.block-table {
  overflow-x: auto;
}

.roadmap {
  width: 100%;
  min-width: 560px;
  border-collapse: collapse;
  font-family: var(--font-display);
  letter-spacing: 1px;
}

.roadmap th,
.roadmap td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--rule);
  text-align: left;
  vertical-align: top;
}

.roadmap thead th {
  color: var(--ink-strong);
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  border-bottom: 1px solid var(--ink-strong);
}

.roadmap tbody th {
  width: 8.5em;
  color: var(--ink-muted);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  white-space: nowrap;
}

.roadmap tbody th.roadmap-focus {
  color: var(--accent);
}

.roadmap td {
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 13px;
  letter-spacing: var(--tracking);
  font-variant-numeric: tabular-nums;
}

.roadmap td.highlight {
  color: var(--ink-strong);
  font-weight: 700;
}

/* --- slideshow gallery (talk slides) ------------------------------------- */

.slideshow {
  --slide-ratio: 16 / 9;
}

.slideshow-stage {
  position: relative;
  background: var(--media-bg);
  aspect-ratio: var(--slide-ratio);
  overflow: hidden;
}

.slideshow-stage img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
  transition: opacity 0.25s var(--ease-out);
}

.slideshow-stage img[data-active="true"] {
  opacity: 1;
}

.slideshow-btn {
  position: absolute;
  top: 50%;
  z-index: var(--z-overlay);
  width: 44px;
  height: 44px;
  transform: translateY(-50%);
  border: 0;
  background: rgba(17, 17, 17, 0.55);
  color: #fff;
  font-family: var(--font-display);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s var(--ease-out), transform 0.1s var(--ease-out);
}

.slideshow-btn:hover {
  background: rgba(17, 17, 17, 0.85);
}

.slideshow-btn:active {
  transform: translateY(-50%) scale(0.94);
}

.slideshow-btn[data-dir="prev"] {
  left: 0;
}

.slideshow-btn[data-dir="next"] {
  right: 0;
}

.slideshow-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 10px;
  color: var(--ink-muted);
  font-family: var(--font-display);
  font-size: 13px;
  letter-spacing: 1px;
}

.slideshow-meta [data-slide-counter] {
  font-variant-numeric: tabular-nums;
}

.slideshow-thumbs {
  display: flex;
  gap: 8px;
  margin-top: 14px;
  padding-bottom: 6px;
  overflow-x: auto;
  scrollbar-width: thin;
}

.slideshow-thumbs button {
  flex: 0 0 auto;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  opacity: 0.45;
  transition: opacity 0.15s var(--ease-out);
}

.slideshow-thumbs button[aria-current="true"] {
  opacity: 1;
}

@media (hover: hover) and (pointer: fine) {
  .slideshow-thumbs button:hover {
    opacity: 1;
  }
}

.slideshow-thumbs img {
  width: 90px;
  height: 51px;
  object-fit: cover;
}

/* --- lock screen (password-protected case studies) ------------------------ */

.lock {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  min-height: 55vh;
  text-align: center;
}

.lock-icon {
  width: 64px;
  height: 64px;
  border: 1px solid var(--ink-strong);
  border-radius: 50%;
  padding: 18px;
}

.lock-icon svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: var(--ink-strong);
  stroke-width: 4;
}

.lock h2 {
  color: var(--ink-strong);
  font-family: var(--font-display);
  font-size: 25.2px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 2px;
}

.lock p {
  max-width: 34em;
}

.lock form {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}

.lock input {
  width: 220px;
  padding: 11px 14px;
  border: 1px solid var(--field-border);
  background: #fff;
  letter-spacing: var(--tracking);
}

.lock button {
  padding: 11px 22px;
  border: 1px solid var(--ink-strong);
  background: none;
  font-family: var(--font-display);
  letter-spacing: 1px;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.15s var(--ease-out), color 0.15s var(--ease-out),
    transform 0.1s var(--ease-out);
}

.lock button:hover {
  background: var(--ink-strong);
  color: var(--ink-invert);
}

.lock button:active {
  transform: scale(0.97);
}

.lock-note {
  color: var(--ink-muted);
  font-size: 13px;
}

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

.site-footer {
  margin-top: 30px;
  padding-top: 30px;
}

/* --- responsive ----------------------------------------------------------- */

@media (max-width: 900px) {
  :root {
    --gutter: 30px;
    --header-gap: 40px;
  }

  .nav {
    display: none;
  }

  .nav-toggle {
    display: block;
    margin-right: -10px;
  }

  .logo img {
    height: 20px;
  }

  .gallery-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 520px) {
  :root {
    --gutter: 20px;
  }

  .logo img {
    height: 18px;
  }

  .prose h1,
  .prose .as-h1 {
    font-size: 26px;
  }

  .prose h2 {
    font-size: 21px;
  }

  .prose p.indent {
    margin-left: 20px;
  }

  .slideshow-thumbs {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
