/* ==========================================================================
   Case study (project detail) template
   Implements the "project_detail" design handoff. All selectors are prefixed
   `cs-` so they never collide with the Webflow classes used by the shared
   navbar and footer.
   ========================================================================== */

:root {
  --cs-blue: #272ccd;
  --cs-orange: #ff6237;
  --cs-ink: #333333;
  --cs-border: #b4b4be;
  --cs-surface: #eeeef1;
  --cs-placeholder: #dcdce1;
  --cs-placeholder-label: #8a8a94;
  --cs-white: #ffffff;
  --cs-grid-line: rgba(39, 44, 205, 0.05);

  --cs-font-mono: "Roboto Mono", monospace;
  --cs-font-ui: "Ubuntu", Helvetica, sans-serif;
  --cs-font-body: "Urbanist", sans-serif;

  --cs-pad-x: clamp(24px, 5vw, 80px);
  --cs-max: 1280px;
}

/* ---- shell ---------------------------------------------------------------- */

.cs-page {
  background: var(--cs-white);
  color: var(--cs-ink);
  font-family: var(--cs-font-body);
}

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

/* Every band shares this vertical rhythm; only the hero opts out, since it
   sizes itself to the viewport. Clamped so the height tapers on narrow
   screens rather than swamping them. */
.cs-section {
  padding: clamp(80px, 8vw, 112px) var(--cs-pad-x);
}

.cs-inner {
  max-width: var(--cs-max);
  margin: 0 auto;
}

.cs-grid-bg {
  background-image:
    linear-gradient(var(--cs-grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--cs-grid-line) 1px, transparent 1px);
  background-size: 48px 48px;
}

.cs-surface {
  background: var(--cs-surface);
}

/* ---- section eyebrow + title --------------------------------------------- */

.cs-eyebrow {
  font-family: var(--cs-font-mono);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 2px;
  color: var(--cs-orange);
  margin-bottom: 10px;
}

.cs-h2 {
  font-family: var(--cs-font-mono);
  font-weight: 700;
  font-size: clamp(28px, 3.4vw, 38px);
  line-height: 1;
  letter-spacing: -0.5px;
  text-transform: uppercase;
  color: var(--cs-ink);
  margin: 0 0 clamp(56px, 7vw, 96px);
}

/* ---- cover --------------------------------------------------------------- */

/* Cover and hero live in one section so the blueprint grid tiles through both
   without restarting at the boundary. The section itself only carries the
   background; each block keeps its own padding. */
.cs-intro {
  padding: 0;
}

.cs-cover {
  /* First band under the fixed bar, so it keeps its original tight top rather
     than the shared rhythm; the bottom still spaces it off the hero. */
  padding: 40px var(--cs-pad-x) clamp(80px, 8vw, 112px);
}

/* The cover is a composite, as it was originally: a background plate with the
   client frieze pinned to the top right, the product shot centred over it, and
   the client wordmark inside the top left corner. */
.cs-cover-stage {
  /* one value drives both wordmark offsets, so the corner inset stays square */
  --cs-cover-inset: 32px;
  /* How much of the stage the product shot may take. Named, because the
     cropped state has to work out what size the shot was at the point the
     frise gave up, and that sum needs the same two numbers. */
  --cs-shot-max-w: 0.88;
  --cs-shot-max-h: 0.9;
  /* the stage beside the copy, which the cropped state needs as the other
     bound on how large the shot may draw */
  --cs-cover-h-wide: 620px;
  position: relative;
  height: var(--cs-cover-h-wide);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #e4e4e4;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  border: 1px solid var(--cs-border);
  border-radius: 4px;
}

.cs-cover-strip {
  position: absolute;
  z-index: 0;
  top: 0;
  right: 0;
  height: 100%;
  width: auto;
  /* Sizing off the height alone works while the stage is wide, but on a tall
     narrow one the strip grows until it covers the whole cover. Capped at
     half the width it stays a band down one side; `contain` keeps the collage
     undistorted inside that cap, and the corner keeps it where the wide
     layout puts it. Above the cap none of this applies — the box already
     matches the artwork's own ratio. */
  max-width: 50%;
  object-fit: contain;
  object-position: top right;
}

/* Set by js/cover-strip.js once the cap above stops the frise reaching the
   stage's full height: at that point it is a floating block rather than a band
   down one side, so it goes rather than being shown short. */
.cs-cover-strip-off {
  display: none;
}

/* Set by the same script on a cover marked data-cs-crop, once the stage is
   narrower than it is tall. The shot stops scaling down to fit and instead
   holds the size the script works out into --cs-cover-shot-h, sitting against
   the left edge and running off the right, which the stage clips. Fitting the
   width instead leaves the interface a thumbnail on a phone. */
.cs-cover-cropped {
  justify-content: flex-start;
}

.cs-cover-cropped .cs-cover-main {
  /* no shrinking: the point is that it overflows */
  flex: 0 0 auto;
  width: auto;
  max-width: none;
  height: var(--cs-cover-shot-h);
  max-height: none;
}

.cs-cover-main {
  position: relative;
  z-index: 2;
  width: auto;
  height: auto;
  max-width: calc(var(--cs-shot-max-w) * 100%);
  max-height: calc(var(--cs-shot-max-h) * 100%);
  object-fit: contain;
  /* The product shot carries ~70px of transparent shadow along its bottom
     edge, so centring it geometrically leaves it reading high. Nudge it down
     by half that gap; the percentage keeps the correction proportional at
     every stage size. */
  transform: translateY(2.1%);
}

.cs-cover-mark {
  position: absolute;
  z-index: 3;
  top: var(--cs-cover-inset);
  left: var(--cs-cover-inset);
  height: 20px;
  width: auto;
}

/* Covers whose wordmark is the composition's anchor rather than a caption. */
.cs-cover-mark-lg {
  height: 80px;
}

/* Decorative corner shapes, between the background and the product shot.
   Sized against the stage so they hold their share of it at any width, and
   flush to their corner — each asset is already cropped to sit that way. */
.cs-cover-corner {
  position: absolute;
  z-index: 1;
  width: auto;
  height: auto;
}

.cs-cover-corner-tr {
  top: 0;
  right: 0;
  max-width: 40%;
  max-height: 45%;
}

.cs-cover-corner-bl {
  bottom: 0;
  left: 0;
  max-width: 45%;
  max-height: 40%;
}

.cs-slot {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--cs-placeholder);
  border: 1px solid var(--cs-border);
  border-radius: 4px;
  overflow: hidden;
  font-family: var(--cs-font-mono);
  font-size: 12px;
  letter-spacing: 1px;
  color: var(--cs-placeholder-label);
}

/* Media fills the slot width and keeps its own aspect ratio, so nothing is
   cropped: the slot takes whatever height the image or video needs. */
.cs-slot > img,
.cs-slot > video {
  display: block;
  width: 100%;
  height: auto;
}

/* Slots waiting on an asset still need to read as image placeholders. */
.cs-slot:not(:has(img)):not(:has(video)) {
  height: 340px;
}

.cs-caption {
  font-family: var(--cs-font-mono);
  font-size: 12px;
  letter-spacing: 1px;
  color: var(--cs-ink);
  margin-top: 14px;
  text-align: right;
}

/* ---- hero ---------------------------------------------------------------- */

/* The hero always fills a full screen, with its content centred in it.
   min-height rather than height so a long title or a tall details table is
   never clipped — on narrow screens the stacked layout simply runs longer.
   dvh, where supported, measures the viewport with mobile browser toolbars
   collapsed, so the section does not jump as they hide and show. */
.cs-hero {
  padding: 84px var(--cs-pad-x) 72px;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
}

.cs-hero > .cs-inner {
  width: 100%;
}

.cs-breadcrumb {
  font-family: var(--cs-font-mono);
  font-size: 12px;
  letter-spacing: 2px;
  color: var(--cs-blue);
  margin-bottom: 30px;
}

.cs-hero-grid {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: clamp(40px, 5vw, 72px);
  align-items: start;
}

.cs-h1 {
  font-family: var(--cs-font-mono);
  font-weight: 700;
  font-size: clamp(34px, 4vw, 52px);
  line-height: 1.06;
  letter-spacing: -1.5px;
  text-transform: uppercase;
  color: var(--cs-ink);
  margin: 0 0 44px;
}

.cs-h1 .cs-cursor {
  color: var(--cs-orange);
}

.cs-sublabel {
  font-family: var(--cs-font-mono);
  font-size: 12px;
  letter-spacing: 1px;
  color: var(--cs-blue);
  margin-bottom: 12px;
}

.cs-body-lg {
  font-family: var(--cs-font-body);
  font-weight: 300;
  font-size: 19px;
  line-height: 1.55;
  color: var(--cs-ink);
  margin: 0;
}

.cs-brief {
  margin-bottom: 34px;
}

.cs-brief:last-child {
  margin-bottom: 0;
}

/* ---- details table ------------------------------------------------------- */

.cs-table {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border: 1px solid var(--cs-border);
  border-radius: 4px;
  overflow: hidden;
  background: var(--cs-white);
}

.cs-cell {
  padding: 30px 24px;
  border-bottom: 1px solid var(--cs-border);
}

.cs-cell:nth-child(odd) {
  border-right: 1px solid var(--cs-border);
}

.cs-cell:nth-last-child(-n + 2) {
  border-bottom: none;
}

.cs-key {
  font-family: var(--cs-font-mono);
  font-size: 11px;
  letter-spacing: 1px;
  color: var(--cs-orange);
}

.cs-value {
  font-family: var(--cs-font-ui);
  font-weight: 500;
  font-size: 18px;
  line-height: 1.4;
  color: var(--cs-ink);
  margin-top: 8px;
}

/* ---- constraints table --------------------------------------------------- */

.cs-constraints {
  display: flex;
  background: var(--cs-white);
  border: 1px solid var(--cs-border);
  border-radius: 4px;
  overflow: hidden;
  width: 100%;
}

/* The constraints band is given more air than the others: a taller section,
   more room between the title and the table, and roomier cells. Scoped with
   :has() because the solutions section carries the same classes. The clamps
   keep the extra height from overwhelming a narrow screen. */
.cs-constraint {
  /* deeper below the copy than above it; sides stay as designed */
  padding: clamp(32px, 3.4vw, 44px) 28px clamp(44px, 4.6vw, 64px);
  width: 100%;
}

.cs-constraint + .cs-constraint {
  border-left: 1px solid var(--cs-border);
}

.cs-constraint-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}

.cs-index {
  font-family: var(--cs-font-mono);
  font-size: 15px;
  font-weight: 400;
  color: var(--cs-border);
}

.cs-constraint-head svg {
  flex: none;
  width: 28px;
  height: 28px;
}

.cs-constraint-title {
  font-family: var(--cs-font-ui);
  font-weight: 700;
  font-size: 21px;
  line-height: 1.2;
  color: var(--cs-blue);
  margin: 0 0 12px;
}

.cs-body-sm {
  font-family: var(--cs-font-body);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.5;
  color: var(--cs-ink);
  margin: 0;
}

/* ---- numbered block ------------------------------------------------------ */

.cs-block-head {
  margin: 38px 0 28px;
  max-width: 856px;
}

.cs-block-head.cs-wide {
  max-width: 944px;
}

.cs-block-index {
  display: block;
  font-family: var(--cs-font-mono);
  font-size: 20px;
  font-weight: 400;
  line-height: 1;
  color: var(--cs-border);
  margin-bottom: 10px;
}

.cs-h3 {
  font-family: var(--cs-font-ui);
  font-weight: 700;
  font-size: 27px;
  line-height: 1.2;
  color: var(--cs-blue);
  margin: 0;
}

/* ---- strategy layout ----------------------------------------------------- */

/* Column ratio holds the media at the width it had when it was capped to 88%
   of a wider track (753px in a 1280px container), while the gap to the
   ACTION / OUTCOMES text is half what that arrangement produced. Fractions
   rather than a fixed text column so the split scales with the container. */
.cs-strategy-grid {
  display: grid;
  grid-template-columns: 1.66fr 1fr;
  gap: 74px;
  align-items: start;
}

.cs-media-stack {
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.cs-notes {
  display: flex;
  flex-direction: column;
  gap: 30px;
}

/* ---- bracket block ------------------------------------------------------- */

.cs-bracket {
  display: flex;
  align-items: stretch;
  gap: 16px;
}

.cs-bracket-arm {
  width: 14px;
  flex: none;
  border: 2px solid var(--cs-blue);
}

.cs-bracket-arm.cs-left {
  border-right: none;
}

.cs-bracket-arm.cs-right {
  border-left: none;
}

.cs-bracket-content {
  flex: 1;
  padding: 14px 0;
}

.cs-bracket-label {
  font-family: var(--cs-font-mono);
  font-size: 12px;
  letter-spacing: 1px;
  color: var(--cs-blue);
  margin-bottom: 10px;
}

.cs-bracket-body {
  font-family: var(--cs-font-body);
  font-size: 18px;
  line-height: 1.55;
  color: var(--cs-ink);
  margin: 0;
}

.cs-bracket.cs-accent .cs-bracket-arm {
  border-color: var(--cs-orange);
}

.cs-bracket.cs-accent .cs-bracket-label {
  color: var(--cs-orange);
}

/* ---- solutions ----------------------------------------------------------- */

.cs-problem-decision {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 44px;
  margin-bottom: 38px;
}

.cs-ui-label {
  font-family: var(--cs-font-mono);
  font-size: 13px;
  letter-spacing: 2px;
  color: var(--cs-ink);
  margin: 0 0 24px;
}

.cs-solution-row {
  display: grid;
  grid-template-columns: 300px 1fr;
  gap: 36px;
  align-items: start;
}

.cs-solution-row + .cs-solution-row {
  margin-top: 44px;
}

.cs-solution-title {
  font-family: var(--cs-font-ui);
  font-weight: 700;
  font-size: 20px;
  line-height: 1.2;
  color: var(--cs-blue);
  margin: 0;
}

.cs-solution-body {
  font-family: var(--cs-font-body);
  font-size: 17px;
  line-height: 1.5;
  color: var(--cs-ink);
  margin: 12px 0 0;
}

.cs-solution-block + .cs-solution-block {
  margin-top: 72px;
}

/* ---- impact -------------------------------------------------------------- */

.cs-impact {
  background: var(--cs-blue);
  color: var(--cs-white);
}

.cs-impact .cs-h2 {
  color: var(--cs-white);
}

.cs-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px;
}

.cs-stat-value {
  font-family: var(--cs-font-mono);
  font-weight: 700;
  font-size: 60px;
  line-height: 1;
  color: var(--cs-white);
}

.cs-stat-value .cs-suffix {
  font-size: 30px;
  color: rgba(255, 255, 255, 0.6);
}

.cs-stat-value.cs-stat-text {
  font-size: 32px;
  line-height: 1.1;
  color: var(--cs-orange);
}

.cs-stat-label {
  font-family: var(--cs-font-mono);
  font-size: 14px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.85);
  margin: 16px 0 0;
}

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

/* Wider spacing between the numbered blocks, and between the UI solutions
   inside them, once there is room for it. Mobile keeps the tighter original
   values: at these sizes they would read as gaps rather than as breathing
   room. `cs-wide` marks the heads in "What I did", so the two sections can
   take different amounts.

   The first head in each section is unaffected either way — its top margin
   collapses with the h2's larger bottom margin. */
@media (min-width: 901px) {
  /* how I worked: double, 38 -> 76 */
  .cs-block-head:not(.cs-wide) {
    margin-top: 76px;
  }

  /* what I did: triple, 72 -> 216. Collapses with the head's own top margin,
     so this is the whole gap rather than an addition to it. */
  .cs-solution-block + .cs-solution-block {
    margin-top: 216px;
  }

  /* and double between the UI solutions within a block, 44 -> 88 */
  .cs-solution-row + .cs-solution-row {
    margin-top: 88px;
  }
}

@media (max-width: 1200px) {
  .cs-hero-grid {
    grid-template-columns: 1fr;
  }

  .cs-solution-row {
    grid-template-columns: 260px 1fr;
  }
}

@media (max-width: 900px) {
  .cs-hero-grid,
  .cs-strategy-grid,
  .cs-problem-decision,
  .cs-solution-row,
  .cs-stats {
    grid-template-columns: 1fr;
  }

  .cs-constraints {
    flex-direction: column;
  }

  .cs-constraint + .cs-constraint {
    border-left: none;
    border-top: 1px solid var(--cs-border);
  }

  /* Read as ACTION, then the media, then OUTCOMES. Flattening .cs-notes lets
     its two brackets sit directly in the grid so the media can be ordered
     between them. Within the strategy grid the accented bracket is always
     OUTCOMES. */
  .cs-notes {
    display: contents;
  }

  /* descendant, not child: display:contents changes box generation but the
     brackets are still DOM children of .cs-notes */
  .cs-strategy-grid .cs-bracket:not(.cs-accent) {
    order: 1;
  }

  .cs-strategy-grid > .cs-media-stack {
    order: 2;
  }

  .cs-strategy-grid .cs-bracket.cs-accent {
    order: 3;
  }

  /* Stacked, the media reads ACTION, then the image, then OUTCOMES, all one
     tight column: the row gap carries the same 37px above and below the media. */
  .cs-strategy-grid {
    row-gap: 37px;
  }

  /* how I worked, between blocks: triple, 38 -> 114 */
  .cs-block-head:not(.cs-wide) {
    margin-top: 114px;
  }

  /* what I did: problem and decision read as one pair, so halve the gap
     between them, 44 -> 22 */
  .cs-problem-decision {
    row-gap: 22px;
  }

  /* double between the UI solutions, 44 -> 88 */
  .cs-solution-row + .cs-solution-row {
    margin-top: 88px;
  }

  /* and half again between blocks, 72 -> 108. Collapses with the head's own
     top margin, so this is the whole gap. */
  .cs-solution-block + .cs-solution-block {
    margin-top: 108px;
  }

  .cs-slot:not(:has(img)):not(:has(video)) {
    height: 260px;
  }

  /* On a phone the cover is the whole first screen rather than a band at the
     top of it, so it takes the viewport less the fixed bar and a small inset
     above and below. dvh, where supported, measures with the browser's own
     toolbars collapsed so the stage does not jump as they hide and show. */
  .cs-cover {
    /* declared here so both the padding and the stage below can read it */
    --cs-cover-gap: 16px;
    padding-top: var(--cs-cover-gap);
  }

  .cs-cover-stage {
    --cs-cover-inset: 18px;
    height: calc(100vh - var(--sc-nav-h, 64px) - 2 * var(--cs-cover-gap));
    height: calc(100dvh - var(--sc-nav-h, 64px) - 2 * var(--cs-cover-gap));
  }

  .cs-cover-mark {
    height: 16px;
  }

  .cs-cover-mark-lg {
    height: 64px;
  }
}

/* ==========================================================================
   Next project — the card pinned to the bottom-right of a case study
   ========================================================================== */

/* The card is pinned, but its right edge has to land on the page's content
   edge, which is the gutter or the centring margin — whichever is wider once
   the content hits its 1280 cap. Rather than compute that, the card rides a
   fixed rail shaped exactly like the content column, the same way the nav row
   is. The rail ignores pointer events so it does not swallow clicks across
   the full width of the page. */
.cs-next-rail {
  position: fixed;
  left: 0;
  right: 0;
  bottom: clamp(16px, 3vw, 32px);
  /* under the fixed nav, which sits at 50 */
  z-index: 40;
  box-sizing: border-box;
  width: 100%;
  max-width: calc(var(--cs-max) + 2 * var(--cs-pad-x));
  margin: 0 auto;
  padding: 0 var(--cs-pad-x);
  display: flex;
  justify-content: flex-end;
  pointer-events: none;
}

.cs-next {
  position: relative;
  pointer-events: auto;
  display: flex;
  align-items: stretch;
  box-sizing: border-box;
  max-width: 100%;
  background: var(--cs-white);
  border: 1px solid var(--cs-border);
  border-radius: 4px;
  overflow: hidden;
  text-decoration: none;
  box-shadow: 0 8px 28px rgba(39, 44, 205, 0.12);
  transition: transform 0.25s ease, border-color 0.2s ease,
    box-shadow 0.25s ease, opacity 0.3s ease, visibility 0.3s ease;
}

.cs-next * {
  box-sizing: border-box;
}

.cs-next:hover,
.cs-next:focus-visible {
  transform: translateY(-3px);
  border-color: var(--cs-orange);
  box-shadow: 0 12px 32px rgba(39, 44, 205, 0.18);
}

.cs-next-thumb {
  flex: 0 0 auto;
  width: 92px;
  border-right: 1px solid var(--cs-border);
  background: var(--cs-surface);
  overflow: hidden;
}

.cs-next-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cs-next-text {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  padding: 14px 18px;
  min-width: 0;
}

.cs-next-label {
  font-family: var(--cs-font-mono);
  font-size: 11px;
  letter-spacing: 1px;
  color: var(--cs-blue);
}

.cs-next-name {
  font-family: var(--cs-font-ui);
  font-weight: 500;
  font-size: 17px;
  line-height: 1.2;
  color: var(--cs-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cs-next-arrow {
  flex: 0 0 auto;
  width: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* a rule rather than a filled block: on white it reads as part of the card
     instead of competing with the page for attention */
  border-left: 1px solid var(--cs-border);
  background: var(--cs-white);
  color: var(--cs-blue);
  font-family: var(--cs-font-mono);
  font-size: 18px;
  transition: color 0.2s ease, border-color 0.2s ease;
}

.cs-next:hover .cs-next-arrow,
.cs-next:focus-visible .cs-next-arrow {
  color: var(--cs-orange);
  border-left-color: var(--cs-orange);
}

/* Out of the way while the cover is still on screen and once the footer is
   reached. Set by js/next-project.js — without it the card simply stays. */
.cs-next-off {
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  pointer-events: none;
}

@media (max-width: 700px) {
  /* the thumbnail is the first thing to go when the card has to share the
     screen with the content it sits over */
  .cs-next-thumb {
    display: none;
  }

  .cs-next-text {
    padding: 10px 14px;
  }

  .cs-next-name {
    font-size: 15px;
  }

  .cs-next-arrow {
    width: 34px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cs-next {
    transition: opacity 0.3s ease, visibility 0.3s ease;
  }

  .cs-next:hover,
  .cs-next:focus-visible {
    transform: none;
  }

  .cs-next-off {
    transform: none;
  }
}

/* A block or a single row kept in the page but not shown, for one whose media
   is still to come. Remove the class from the element in the page to bring it
   back; nothing else has to change, since the numbering runs from the blocks
   that remain. */
.cs-block-hidden,
.cs-row-hidden {
  display: none;
}

/* ==========================================================================
   Carousel — a solution slot holding several stills instead of one
   ========================================================================== */

/* Built on native scroll snapping rather than transform maths: touch swipe,
   momentum and keyboard scrolling all come free, and the buttons only have to
   ask the track to scroll. */
.cs-carousel {
  position: relative;
  border: 1px solid var(--cs-border);
  border-radius: 4px;
  overflow: hidden;
  background: var(--cs-placeholder);
}

.cs-carousel-track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* the dots are the affordance; the bar would sit across the artwork */
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.cs-carousel-track::-webkit-scrollbar {
  display: none;
}

.cs-carousel-slide {
  flex: 0 0 100%;
  scroll-snap-align: start;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
}

/* The stills are not all the same shape, and the track is as tall as the
   tallest of them — left alone, the squarest slide sets a frame the wide ones
   float in with a third of it empty. Capping the height keeps the frame to a
   screenful; `contain` means the cap crops nothing, it only letterboxes. */
.cs-carousel-slide > img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 70vh;
  object-fit: contain;
}

/* a slide still waiting on its asset, matching the empty solution slots */
.cs-carousel-slide:not(:has(img)) {
  height: 340px;
  font-family: var(--cs-font-mono);
  font-size: 12px;
  letter-spacing: 1px;
  color: var(--cs-placeholder-label);
}

.cs-carousel-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  appearance: none;
  -webkit-appearance: none;
  padding: 0;
  cursor: pointer;
  background: var(--cs-white);
  border: 1px solid var(--cs-border);
  border-radius: 4px;
  font-family: var(--cs-font-mono);
  font-size: 16px;
  line-height: 1;
  color: var(--cs-blue);
  transition: color 0.2s ease, border-color 0.2s ease, opacity 0.2s ease;
}

.cs-carousel-nav:hover,
.cs-carousel-nav:focus-visible {
  color: var(--cs-orange);
  border-color: var(--cs-orange);
}

/* at either end the button has nowhere to go, so it steps back */
.cs-carousel-nav[disabled] {
  opacity: 0.35;
  cursor: default;
  color: var(--cs-blue);
  border-color: var(--cs-border);
}

.cs-carousel-prev {
  left: 12px;
}

.cs-carousel-next {
  right: 12px;
}

.cs-carousel-dots {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 12px;
  display: flex;
  justify-content: center;
  gap: 6px;
}

.cs-carousel-dot {
  appearance: none;
  -webkit-appearance: none;
  width: 22px;
  height: 4px;
  padding: 0;
  cursor: pointer;
  border: 0;
  border-radius: 2px;
  background: rgba(39, 44, 205, 0.25);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.6);
  transition: background 0.2s ease;
}

.cs-carousel-dot[aria-selected="true"] {
  background: var(--cs-blue);
}

.cs-carousel-dot:hover {
  background: var(--cs-orange);
}

@media (max-width: 700px) {
  .cs-carousel-nav {
    width: 32px;
    height: 32px;
    font-size: 14px;
  }

  .cs-carousel-prev {
    left: 8px;
  }

  .cs-carousel-next {
    right: 8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cs-carousel-track {
    scroll-behavior: auto;
  }
}
