/* ==========================================================================
   ts-sheet.css, the click-to-open work experience for the TypeSafe portfolio.
   Prefix tsv-. Pairs with assets/js/ts-sheet.js. Loaded after ts.css.

   Parts
   1. .tsv-card, .tsv-grid, .tsv-row   visual work cards and their layouts
   2. .tsv-sheet                        the dialog panel (right on desktop, bottom on phones)
   3. .tsv-media                        the carousel of screenshots, replays and diagrams
   4. .tsv-story, .tsv-block, .tsv-how  the story: Overview, My role, Outcome (Note and More are optional)
   5. .tsv-chips                        the tech tag row
   6. .tsv-lightbox                     image zoom

   Every transition and animation is 400 ms or less where blur is involved.
   Motion lives in a no-preference block, so the base state is the finished,
   readable state, and prefers-reduced-motion gets it for free.
   ========================================================================== */

:root {
  --tsv-surface: #0e0e10;
  --tsv-surface-2: #151518;
  --tsv-surface-3: #1b1b1f;
  --tsv-fg: #f5f5f6;
  --tsv-soft: rgba(245, 245, 246, .76);
  --tsv-muted: #8e8e93;
  --tsv-line: rgba(255, 255, 255, .12);
  --tsv-line-2: rgba(255, 255, 255, .24);
  --tsv-wash: rgba(255, 255, 255, .06);
  --tsv-accent: var(--teal, #67A6B6);
  --tsv-accent-dark: var(--teal-dark, #5590A0);
  --tsv-accent-soft: rgba(103, 166, 182, .16);
  --tsv-warn: #d6bb80;
  --tsv-r1: 20px;
  --tsv-r2: 28px;
  --tsv-ease: cubic-bezier(.22, 1, .36, 1);
  --tsv-ease-io: cubic-bezier(.2, 0, 0, 1);
  --tsv-font: var(--font, system-ui, -apple-system, "Segoe UI", sans-serif);
  --tsv-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

  /* icons, drawn as masks so they take the colour of the text around them */
  --tsv-i-screenshot: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='16' rx='3'/%3E%3Ccircle cx='9' cy='10' r='1.6'/%3E%3Cpath d='M4 18l5-5 4 4 3-3 4 4'/%3E%3C/svg%3E");
  --tsv-i-replay: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M10.2 8.6l5 3.4-5 3.4z' fill='%23000'/%3E%3C/svg%3E");
  --tsv-i-diagram: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3.5' width='7' height='5.5' rx='1.6'/%3E%3Crect x='14' y='3.5' width='7' height='5.5' rx='1.6'/%3E%3Crect x='8.5' y='15' width='7' height='5.5' rx='1.6'/%3E%3Cpath d='M6.5 9v3h11V9M12 12v3'/%3E%3C/svg%3E");
  --tsv-i-code: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 8l-4 4 4 4M16 8l4 4-4 4M13.5 5l-3 14'/%3E%3C/svg%3E");
  --tsv-i-terminal: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='16' rx='3'/%3E%3Cpath d='M7.5 10l3 2-3 2M13 15h4'/%3E%3C/svg%3E");
  --tsv-i-dot: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='4.5' fill='%23000'/%3E%3C/svg%3E");
  --tsv-i-open: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 17L17 7M8.5 7H17v8.5'/%3E%3C/svg%3E");
  --tsv-i-zoom: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 4h6v6M10 20H4v-6M20 4l-7 7M4 20l7-7'/%3E%3C/svg%3E");
  --tsv-i-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  --tsv-i-overview: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 11v5M12 8h.01'/%3E%3C/svg%3E");
  --tsv-i-role: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 7l2 2 3.5-3.5M4 17l2 2 3.5-3.5M13 8h7M13 18h7'/%3E%3C/svg%3E");
  --tsv-i-outcome: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 17l5-5 4 4 7-8M15 8h5v5'/%3E%3C/svg%3E");
  --tsv-i-note: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 21V4M5 5h12l-2.5 4L17 13H5'/%3E%3C/svg%3E");
}

/* focus ring colour, read by the site rule and by ours */
:is(.tsv-card, .tsv-media, .tsv-how, .tsv-btn) {
  --focus-ring: var(--tsv-accent-dark);
}

:is(.tsv-sheet, .tsv-lightbox) {
  --focus-ring: var(--tsv-accent);
}

/* ==========================================================================
   Kind badge, used on cards and on media frames
   ========================================================================== */

.tsv-kind {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 6px 11px 6px 9px;
  font-family: var(--tsv-font);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: .02em;
  white-space: nowrap;
  color: var(--tsv-fg);
  background: rgba(14, 14, 16, .8);
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 999px;
}

.tsv-kind::before {
  content: "";
  flex: none;
  width: 13px;
  height: 13px;
  background: var(--tsv-accent);
  -webkit-mask: var(--tsv-i, var(--tsv-i-dot)) center / contain no-repeat;
  mask: var(--tsv-i, var(--tsv-i-dot)) center / contain no-repeat;
}

.tsv-kind[data-kind="screenshot"] { --tsv-i: var(--tsv-i-screenshot); }
.tsv-kind[data-kind="replay"],
.tsv-kind[data-kind="video"] { --tsv-i: var(--tsv-i-replay); }
.tsv-kind[data-kind="diagram"] { --tsv-i: var(--tsv-i-diagram); }
.tsv-kind[data-kind="code"] { --tsv-i: var(--tsv-i-code); }
.tsv-kind[data-kind="terminal"] { --tsv-i: var(--tsv-i-terminal); }

/* ==========================================================================
   1. Cards and layouts
   ========================================================================== */

.tsv-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(16px, 2vw, 24px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.tsv-grid > * {
  min-width: 0;
}

.tsv-grid > li {
  display: grid;
}

@media (max-width: 1023px) {
  .tsv-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 639px) {
  .tsv-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* horizontal row for the home page. --tsv-bleed lets it run to the screen edge:
   set it to the page gutter, for example style="--tsv-bleed: 20px". */
.tsv-row {
  --tsv-bleed: 0px;
  --tsv-rowpad: max(var(--tsv-bleed), 8px);
  display: flex;
  gap: clamp(14px, 1.6vw, 20px);
  margin: -8px calc(var(--tsv-rowpad) * -1) 0;
  padding: 8px var(--tsv-rowpad) 18px;
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--tsv-rowpad);
  scrollbar-width: thin;
  scrollbar-color: rgba(128, 128, 128, .45) transparent;
}

.tsv-row > * {
  flex: 0 0 clamp(264px, 30vw, 384px);
  min-width: 0;
  scroll-snap-align: start;
}

.tsv-row > li {
  display: grid;
}

.tsv-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  min-width: 0;
  margin: 0;
  padding: 0;
  overflow: hidden;
  isolation: isolate;
  font-family: var(--tsv-font);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  text-align: left;
  text-decoration: none;
  color: var(--tsv-fg);
  background: var(--tsv-surface);
  border: 1px solid var(--tsv-line);
  border-radius: var(--tsv-r1);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .35s var(--tsv-ease), border-color .25s var(--tsv-ease-io), box-shadow .35s var(--tsv-ease);
}

.tsv-card:focus-visible {
  border-color: var(--tsv-line-2);
  transform: translateY(-4px);
  box-shadow: 0 22px 44px -24px rgba(0, 0, 0, .75);
}

@media (hover: hover) and (pointer: fine) {
  .tsv-card:hover {
    border-color: var(--tsv-line-2);
    transform: translateY(-4px);
    box-shadow: 0 22px 44px -24px rgba(0, 0, 0, .75);
  }
}

.tsv-card:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 4px;
}

.tsv-card:active {
  transform: translateY(-1px) scale(.992);
  transition-duration: .12s;
}

.tsv-card__media {
  position: relative;
  flex: none;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: #08080a;
}

.tsv-card__media img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: var(--tsv-pos, 50% 0%);
  transition: transform .6s var(--tsv-ease);
  will-change: transform;
}

.tsv-card__media::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to top, rgba(8, 8, 10, .5), rgba(8, 8, 10, 0) 32%);
}

.tsv-card__kinds {
  position: absolute;
  left: 12px;
  bottom: 12px;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  max-width: calc(100% - 24px);
}

/* the open mark, top right of the cover */
.tsv-card::after {
  content: "";
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 3;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background-color: rgba(14, 14, 16, .8);
  border: 1px solid rgba(255, 255, 255, .16);
  pointer-events: none;
  transition: background-color .25s var(--tsv-ease-io), border-color .25s var(--tsv-ease-io), transform .35s var(--tsv-ease);
}

/* the arrow is a second layer, painted with a mask so it can change colour */
.tsv-card__media::before {
  content: "";
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 4;
  width: 36px;
  height: 36px;
  background: var(--tsv-fg);
  -webkit-mask: var(--tsv-i-open) center / 16px 16px no-repeat;
  mask: var(--tsv-i-open) center / 16px 16px no-repeat;
  pointer-events: none;
  transition: background-color .25s var(--tsv-ease-io), transform .35s var(--tsv-ease);
}

.tsv-card:focus-visible::after {
  background-color: var(--tsv-accent);
  border-color: transparent;
}

.tsv-card:focus-visible .tsv-card__media::before {
  background: #0b1316;
  transform: rotate(45deg);
}

@media (hover: hover) and (pointer: fine) {
  .tsv-card:hover::after {
    background-color: var(--tsv-accent);
    border-color: transparent;
  }
  .tsv-card:hover .tsv-card__media::before {
    background: #0b1316;
    transform: rotate(45deg);
  }
}

.tsv-card__body {
  display: grid;
  flex: 1;
  align-content: start;
  gap: 6px;
  padding: 18px 20px 22px;
}

.tsv-card__title {
  margin: 0;
  font-size: clamp(18px, 1.5vw, 21px);
  font-weight: 500;
  letter-spacing: -.02em;
  line-height: 1.2;
  text-wrap: balance;
  color: var(--tsv-fg);
}

.tsv-card__line {
  display: -webkit-box;
  margin: 0;
  overflow: hidden;
  font-size: 15px;
  font-weight: 400;
  line-height: 1.5;
  text-wrap: pretty;
  color: var(--tsv-soft);
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* ==========================================================================
   2. The sheet
   ========================================================================== */

.tsv-sheet {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  overflow: hidden;
  font-family: var(--tsv-font);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  color: var(--tsv-fg);
  background: transparent;
}

.tsv-sheet::backdrop,
.tsv-lightbox::backdrop {
  background: transparent;
}

/* the dim layer is the dialog itself, so a click on it is a click outside the panel */
.tsv-sheet {
  background: rgba(4, 4, 5, 0);
  transition: background-color .3s var(--tsv-ease-io), backdrop-filter .3s var(--tsv-ease-io), -webkit-backdrop-filter .3s var(--tsv-ease-io);
}

.tsv-sheet.is-open {
  background: rgba(4, 4, 5, .6);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

/* 768 px and wider: the panel is a modal in the exact middle of the window */
.tsv-sheet[open] {
  display: grid;
  place-items: center;
}

.tsv-sheet__panel {
  position: relative;
  width: min(900px, 92vw);
  max-height: 90vh;
  max-height: 90dvh;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, .22) transparent;
  background: var(--tsv-surface);
  border: 1px solid var(--tsv-line);
  border-radius: 24px;
  box-shadow: 0 32px 90px -24px rgba(0, 0, 0, .75), 0 8px 24px -12px rgba(0, 0, 0, .5);
  outline: none;
  /* closed state, also the exit: fade, shrink a little, soften. Exit is the quick one. */
  opacity: 0;
  transform: scale(.96);
  filter: blur(6px);
  transition: opacity .2s ease-out, transform .2s ease-out, filter .2s ease-out;
}

.tsv-sheet.is-open .tsv-sheet__panel {
  opacity: 1;
  transform: none;
  filter: none;
  transition: opacity .3s cubic-bezier(.22, .8, .3, 1), transform .34s cubic-bezier(.22, .8, .3, 1), filter .3s cubic-bezier(.22, .8, .3, 1);
}

.tsv-sheet__bar {
  position: sticky;
  top: 0;
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 14px 14px clamp(18px, 3vw, 28px);
  background: rgba(14, 14, 16, .9);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  backdrop-filter: blur(14px) saturate(1.2);
  border-bottom: 1px solid var(--tsv-line);
}

.tsv-sheet__heading {
  flex: 1;
  min-width: 0;
}

.tsv-sheet__eyebrow {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--tsv-muted);
}

.tsv-sheet__eyebrow::before {
  content: "";
  flex: none;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--tsv-accent);
}

.tsv-sheet__eyebrow[hidden] {
  display: none;
}

.tsv-sheet__title {
  display: -webkit-box;
  margin: 0;
  overflow: hidden;
  font-size: clamp(18px, 2vw, 22px);
  font-weight: 500;
  letter-spacing: -.02em;
  line-height: 1.2;
  text-wrap: balance;
  color: var(--tsv-fg);
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.tsv-sheet__nav {
  display: flex;
  flex: none;
  align-items: center;
  gap: 8px;
}

.tsv-sheet__nav[hidden] {
  display: none;
}

.tsv-sheet__count {
  margin-right: 4px;
  font-family: var(--tsv-mono);
  font-size: 12.5px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
  color: var(--tsv-muted);
}

.tsv-sheet__close {
  margin-left: 4px;
}

/* round icon buttons, shared by the sheet, the carousel and the lightbox */
.tsv-ibtn {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 40px;
  height: 40px;
  margin: 0;
  padding: 0;
  font: inherit;
  color: var(--tsv-fg);
  background: transparent;
  border: 1px solid var(--tsv-line);
  border-radius: 50%;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color .2s var(--tsv-ease-io), border-color .2s var(--tsv-ease-io), transform .2s var(--tsv-ease), opacity .2s var(--tsv-ease-io);
}

.tsv-ibtn svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {
  .tsv-ibtn:hover {
    background: var(--tsv-wash);
    border-color: var(--tsv-line-2);
  }
}

.tsv-ibtn:active {
  transform: scale(.92);
}

.tsv-ibtn[aria-disabled="true"] {
  opacity: .3;
  cursor: default;
  pointer-events: none;
}

.tsv-sheet :is(button, a, summary, [tabindex]):focus-visible,
.tsv-lightbox :is(button, a, [tabindex]):focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
}

dialog.tsv-sheet .tsv-sheet__panel:focus,
dialog.tsv-sheet .tsv-sheet__panel:focus-visible {
  outline: none;
}

.tsv-sheet__content {
  display: grid;
  gap: 18px;
  min-width: 0;
  padding: 18px clamp(18px, 3vw, 28px) clamp(24px, 3vw, 32px);
}

.tsv-sheet__content > * {
  min-width: 0;
}

.tsv-sheet .tsv-article__title {
  display: none;
}

.tsv-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* below 768 px: the sheet rises from the bottom and takes the full height */
@media (max-width: 767px) {
  .tsv-sheet[open] {
    display: block;
  }

  .tsv-sheet .tsv-sheet__panel {
    position: absolute;
    top: max(8px, env(safe-area-inset-top));
    right: 0;
    bottom: 0;
    left: 0;
    width: auto;
    max-height: none;
    border-bottom: 0;
    border-radius: 24px 24px 0 0;
    opacity: 1;
    filter: none;
    transform: translate3d(0, 100%, 0);
    transition: transform .36s var(--tsv-ease);
  }

  .tsv-sheet.is-open .tsv-sheet__panel {
    opacity: 1;
    filter: none;
    transform: none;
    transition: transform .36s var(--tsv-ease);
  }

  .tsv-sheet__bar {
    padding: 20px 12px 12px 18px;
    gap: 8px;
    touch-action: none;
  }

  .tsv-sheet__bar::before {
    content: "";
    position: absolute;
    top: 7px;
    left: 50%;
    width: 36px;
    height: 4px;
    margin-left: -18px;
    border-radius: 2px;
    background: rgba(255, 255, 255, .22);
  }

  .tsv-sheet__nav {
    gap: 6px;
  }

  .tsv-sheet__count {
    display: none;
  }

  .tsv-ibtn {
    width: 44px;
    height: 44px;
  }

  .tsv-sheet__content {
    padding-bottom: calc(28px + env(safe-area-inset-bottom));
  }
}

/* a short window (a laptop, 800 px high or less): the modal tightens its rhythm a little so
   Overview, My role, Outcome and Note stay in view without scrolling */
@media (min-width: 768px) and (max-height: 800px) {
  .tsv-sheet .tsv-sheet__content {
    gap: 14px;
    padding-top: 14px;
  }

  .tsv-sheet .tsv-block {
    padding: 12px 0;
  }
}

/* ==========================================================================
   3. Media carousel
   Small by design: about a third of the sheet height, capped near 300 px on
   desktop and about 200 px on phones. One slide at a time, the neighbours peek
   in, and every stop (arrow, dot, key, drag, swipe) lands with a slide exactly
   in place: first flush left, last flush right, the rest centred. The scroll
   bar is hidden.
   ========================================================================== */

.tsv-media {
  --tsv-peek: 40px;
  --tsv-gap: 12px;
  --tsv-mh: clamp(170px, 31vh, 300px);
  --tsv-edge: 56px;
  --tsv-slide: min(calc(var(--tsv-mh) * 1.6), calc(100% - var(--tsv-edge)));
  position: relative;
  display: flex;
  gap: var(--tsv-gap);
  min-width: 0;
  font-family: var(--tsv-font);
  color: var(--tsv-fg);
}

@media (max-width: 767px) {
  .tsv-media {
    --tsv-mh: clamp(196px, 24vh, 230px);
    --tsv-edge: 64px;
  }
}

/* without the script the figures still scroll sideways */
.tsv-media:not(.is-ready) {
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}

.tsv-media:not(.is-ready) > figure {
  flex: 0 0 calc(100% - var(--tsv-peek));
  scroll-snap-align: start;
}

.tsv-media.is-ready {
  display: grid;
  gap: 10px;
}

.tsv-media__track {
  position: relative;
  display: flex;
  gap: var(--tsv-gap);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

.tsv-media__track::-webkit-scrollbar {
  display: none;
  width: 0;
  height: 0;
}

/* while the pointer drags, and while a release or an arrow glides to its stop,
   the script moves the scroll itself, so snapping steps aside until it lands */
.tsv-media__track.is-dragging,
.tsv-media__track.is-settling {
  scroll-snap-type: none;
}

.tsv-media__track.is-dragging,
.tsv-media__track.is-dragging * {
  cursor: grabbing !important;
}

.tsv-media__item {
  display: grid;
  flex: 0 0 var(--tsv-slide);
  gap: 8px;
  align-content: start;
  min-width: 0;
  margin: 0;
  scroll-snap-align: center;
  scroll-snap-stop: always;
}

/* the first slide stops flush left, the last flush right, the ones between in the middle,
   so no slide is ever cut and no empty band opens up at either end */
.tsv-media__item:first-child {
  scroll-snap-align: start;
}

.tsv-media__item:last-child {
  scroll-snap-align: end;
}

.tsv-media__frame {
  position: relative;
  height: var(--tsv-mh);
  overflow: hidden;
  background: #08080a;
  border: 1px solid var(--tsv-line);
  border-radius: var(--tsv-r1);
}

.tsv-media__frame :is(img, video) {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: contain;
  -webkit-user-drag: none;
  user-select: none;
  -webkit-user-select: none;
}

.tsv-media__item[data-fit="cover"] .tsv-media__frame :is(img, video) {
  object-fit: cover;
  object-position: top center;
}

.tsv-media__frame > .tsv-kind {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 3;
  padding: 5px 10px 5px 8px;
  font-size: 11px;
  pointer-events: none;
}

.tsv-media__zoom {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  color: inherit;
  background: none;
  border: 0;
  border-radius: inherit;
  cursor: inherit;
  -webkit-tap-highlight-color: transparent;
}

.tsv-media__zoom::after {
  content: "";
  position: absolute;
  right: 10px;
  bottom: 10px;
  width: 30px;
  height: 30px;
  background-color: rgba(14, 14, 16, .82);
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: 50%;
  opacity: 0;
  transition: opacity .25s var(--tsv-ease-io);
  pointer-events: none;
}

.tsv-media__zoom::before {
  content: "";
  position: absolute;
  right: 10px;
  bottom: 10px;
  z-index: 1;
  width: 30px;
  height: 30px;
  background: var(--tsv-fg);
  -webkit-mask: var(--tsv-i-zoom) center / 14px 14px no-repeat;
  mask: var(--tsv-i-zoom) center / 14px 14px no-repeat;
  opacity: 0;
  transition: opacity .25s var(--tsv-ease-io);
  pointer-events: none;
}

.tsv-media__zoom:hover::after,
.tsv-media__zoom:hover::before,
.tsv-media__zoom:focus-visible::after,
.tsv-media__zoom:focus-visible::before {
  opacity: 1;
}

@media (hover: none) {
  .tsv-media__zoom::after,
  .tsv-media__zoom::before {
    opacity: .9;
  }
}

.tsv-media__play {
  position: absolute;
  left: 10px;
  bottom: 10px;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  margin: 0;
  padding: 0;
  color: var(--tsv-fg);
  background: rgba(14, 14, 16, .82);
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: 50%;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color .2s var(--tsv-ease-io), transform .2s var(--tsv-ease);
}

.tsv-media__play:hover {
  background: rgba(14, 14, 16, .95);
}

.tsv-media__play:active {
  transform: scale(.92);
}

.tsv-media__play svg {
  width: 14px;
  height: 14px;
  fill: currentColor;
  pointer-events: none;
}

.tsv-media__play .tsv-ico-play,
.tsv-media__play.is-paused .tsv-ico-pause {
  display: none;
}

.tsv-media__play.is-paused .tsv-ico-play {
  display: block;
}

/* one line, always */
.tsv-media__cap {
  margin: 0;
  padding: 0 2px;
  overflow: hidden;
  font-size: 13px;
  line-height: 18px;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--tsv-soft);
}

/* compact control line: dots left, count and small arrows right */
.tsv-media__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 28px;
}

.tsv-media__dots {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  min-width: 0;
}

.tsv-dot {
  position: relative;
  display: block;
  flex: none;
  width: 20px;
  height: 28px;
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.tsv-dot::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 3px;
  background: rgba(255, 255, 255, .28);
  transition: width .3s var(--tsv-ease), margin .3s var(--tsv-ease), background-color .25s var(--tsv-ease-io);
}

.tsv-dot:hover::before {
  background: rgba(255, 255, 255, .55);
}

.tsv-dot[aria-current="true"]::before {
  width: 18px;
  margin-left: -9px;
  background: var(--tsv-accent);
}

.tsv-media__nav {
  display: flex;
  flex: none;
  align-items: center;
  gap: 6px;
}

.tsv-media__count {
  margin-right: 2px;
  font-family: var(--tsv-mono);
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--tsv-muted);
}

.tsv-media__nav .tsv-ibtn {
  width: 28px;
  height: 28px;
}

.tsv-media__nav .tsv-ibtn svg {
  width: 14px;
  height: 14px;
}

@media (pointer: coarse) {
  .tsv-sheet__bar .tsv-ibtn {
    width: 44px;
    height: 44px;
  }

  .tsv-media__nav .tsv-ibtn {
    width: 32px;
    height: 32px;
  }

  .tsv-dot {
    width: 22px;
    height: 32px;
  }
}

.tsv-media__track:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 4px;
}

/* ==========================================================================
   4. Story blocks, optional details, small parts
   ========================================================================== */

.tsv-story {
  container: tsv-story / inline-size;
  display: grid;
  min-width: 0;
  border-top: 1px solid var(--tsv-line);
  font-family: var(--tsv-font);
  color: var(--tsv-fg);
}

.tsv-block {
  display: grid;
  gap: 8px;
  min-width: 0;
  padding: 16px 0;
  border-bottom: 1px solid var(--tsv-line);
}

@container tsv-story (min-width: 520px) {
  .tsv-block {
    grid-template-columns: 148px minmax(0, 1fr);
    gap: 24px;
  }
}

/* wide enough for the label column: a short list of role lines runs in one row to save height */
@container tsv-story (min-width: 520px) {
  .tsv-block[data-block="role"] .tsv-block__body ul {
    display: flex;
    flex-wrap: wrap;
    gap: 3px 22px;
  }
}

.tsv-block__label {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--tsv-muted);
}

.tsv-block__label::before {
  content: "";
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 1px;
  background: var(--tsv-accent);
  -webkit-mask: var(--tsv-bi, var(--tsv-i-overview)) center / contain no-repeat;
  mask: var(--tsv-bi, var(--tsv-i-overview)) center / contain no-repeat;
}

.tsv-block[data-block="overview"] { --tsv-bi: var(--tsv-i-overview); }
.tsv-block[data-block="role"] { --tsv-bi: var(--tsv-i-role); }
.tsv-block[data-block="outcome"] { --tsv-bi: var(--tsv-i-outcome); }
.tsv-block[data-block="note"] { --tsv-bi: var(--tsv-i-note); }

.tsv-block[data-block="note"] .tsv-block__label::before {
  background: var(--tsv-warn);
}

.tsv-block__body {
  display: grid;
  gap: 8px;
  min-width: 0;
  font-size: 15px;
  line-height: 1.55;
  color: var(--tsv-soft);
}

.tsv-block__body :is(p, ul, ol) {
  margin: 0;
}

.tsv-block__body b,
.tsv-block__body strong {
  font-weight: 500;
  color: var(--tsv-fg);
}

.tsv-block__body ul {
  display: grid;
  gap: 3px;
  padding: 0;
  list-style: none;
}

.tsv-block__body ul > li {
  position: relative;
  padding-left: 18px;
}

.tsv-block__body ul > li::before {
  content: "";
  position: absolute;
  top: 10px;
  left: 2px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--tsv-accent);
}

.tsv-block[data-block="note"] .tsv-block__body ul > li::before {
  background: var(--tsv-warn);
}

.tsv-stats,
.tsv-block__body .tsv-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 28px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tsv-block__body .tsv-stats > li {
  padding-left: 0;
}

.tsv-block__body .tsv-stats > li::before {
  display: none;
}

.tsv-stat {
  display: grid;
  gap: 2px;
}

.tsv-stat b {
  font-size: clamp(24px, 2.6vw, 28px);
  font-weight: 500;
  letter-spacing: -.02em;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--tsv-fg);
}

.tsv-stat span {
  font-size: 13px;
  line-height: 1.4;
  color: var(--tsv-muted);
}

.tsv-how {
  margin-top: 20px;
  font-family: var(--tsv-font);
  color: var(--tsv-soft);
  background: var(--tsv-surface-2);
  border: 1px solid var(--tsv-line);
  border-radius: var(--tsv-r1);
}

.tsv-how > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 15px 18px;
  font-size: 15px;
  font-weight: 500;
  color: var(--tsv-fg);
  list-style: none;
  cursor: pointer;
  border-radius: inherit;
  -webkit-tap-highlight-color: transparent;
}

.tsv-how > summary::-webkit-details-marker {
  display: none;
}

.tsv-how > summary::after {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  background: var(--tsv-muted);
  -webkit-mask: var(--tsv-i-chevron) center / contain no-repeat;
  mask: var(--tsv-i-chevron) center / contain no-repeat;
  transition: transform .3s var(--tsv-ease), background-color .2s var(--tsv-ease-io);
}

.tsv-how > summary:hover::after {
  background: var(--tsv-fg);
}

.tsv-how[open] > summary::after {
  transform: rotate(180deg);
}

.tsv-how > :not(summary) {
  margin: 0 18px;
  font-size: 15px;
  line-height: 1.65;
}

.tsv-how > :not(summary) + :not(summary) {
  margin-top: 12px;
}

.tsv-how > :last-child {
  margin-bottom: 18px;
}

.tsv-how :is(ol, ul):not(.tsv-chips) {
  padding-left: 20px;
}

.tsv-how img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 12px;
}

.tsv-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tsv-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 20px;
  font-family: var(--tsv-font);
  font-size: 15px;
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  color: var(--tsv-fg);
  background: transparent;
  border: 1px solid var(--tsv-line-2);
  border-radius: 999px;
  cursor: pointer;
  transition: background-color .2s var(--tsv-ease-io), border-color .2s var(--tsv-ease-io), transform .2s var(--tsv-ease);
}

@media (hover: hover) and (pointer: fine) {
  .tsv-btn:hover {
    background: var(--tsv-wash);
    border-color: rgba(255, 255, 255, .4);
  }
}

.tsv-btn:active {
  transform: scale(.97);
}

.tsv-btn--solid {
  color: #0e0e10;
  background: #f5f5f6;
  border-color: transparent;
}

@media (hover: hover) and (pointer: fine) {
  .tsv-btn--solid:hover {
    background: #fff;
  }
}

.tsv-btn:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
}

/* ==========================================================================
   5. Tech chips
   ========================================================================== */

.tsv-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tsv-chip {
  display: inline-flex;
  align-items: center;
  margin: 0;
  padding: 8px 14px;
  font-family: var(--tsv-mono);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: .01em;
  text-decoration: none;
  color: var(--tsv-soft);
  background: transparent;
  border: 1px solid rgba(255, 255, 255, .2);
  border-radius: 999px;
  transition: border-color .25s var(--tsv-ease-io), background-color .25s var(--tsv-ease-io), color .25s var(--tsv-ease-io);
}

a.tsv-chip:hover,
a.tsv-chip:focus-visible {
  color: var(--tsv-fg);
  background: var(--tsv-accent-soft);
  border-color: var(--tsv-accent);
}

/* ==========================================================================
   6. Lightbox
   ========================================================================== */

.tsv-lightbox {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  overflow: hidden;
  font-family: var(--tsv-font);
  color: var(--tsv-fg);
  background: rgba(3, 3, 4, 0);
  transition: background-color .25s var(--tsv-ease-io);
}

.tsv-lightbox.is-open {
  background: rgba(3, 3, 4, .975);
}

.tsv-lightbox__stage {
  position: absolute;
  inset: 72px 24px 88px;
  display: grid;
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
  overflow: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.tsv-lightbox__stage::-webkit-scrollbar {
  display: none;
  width: 0;
  height: 0;
}

.tsv-lightbox.is-zoom .tsv-lightbox__stage {
  cursor: grab;
}

.tsv-lightbox.is-panning .tsv-lightbox__stage,
.tsv-lightbox.is-panning .tsv-lightbox__img {
  cursor: grabbing;
}

.tsv-lightbox__img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  margin: auto;
  object-fit: contain;
  border-radius: 12px;
  cursor: default;
  opacity: 0;
  transition: opacity .22s var(--tsv-ease-io);
  -webkit-user-drag: none;
  user-select: none;
}

.tsv-lightbox__img.is-ready {
  opacity: 1;
}

.tsv-lightbox.can-zoom .tsv-lightbox__img {
  cursor: zoom-in;
}

.tsv-lightbox.is-zoom .tsv-lightbox__stage {
  grid-template: minmax(100%, max-content) / minmax(100%, max-content);
}

.tsv-lightbox.is-zoom .tsv-lightbox__img {
  max-width: none;
  max-height: none;
  cursor: zoom-out;
}

.tsv-lightbox__close {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 3;
}

.tsv-lightbox__prev,
.tsv-lightbox__next {
  position: absolute;
  top: 50%;
  z-index: 3;
  margin-top: -20px;
  background: rgba(14, 14, 16, .7);
}

.tsv-lightbox__prev {
  left: 16px;
}

.tsv-lightbox__next {
  right: 16px;
}

.tsv-lightbox__cap {
  position: absolute;
  right: 80px;
  bottom: 24px;
  left: 80px;
  z-index: 3;
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  text-align: center;
  text-wrap: balance;
  color: var(--tsv-soft);
}

.tsv-lightbox__count {
  position: absolute;
  top: 28px;
  left: 24px;
  z-index: 3;
  margin: 0;
  font-family: var(--tsv-mono);
  font-size: 12.5px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--tsv-muted);
}

@media (max-width: 720px) {
  .tsv-lightbox__stage {
    inset: 64px 8px 96px;
  }

  .tsv-lightbox__prev,
  .tsv-lightbox__next {
    top: auto;
    bottom: 24px;
    margin-top: 0;
  }

  .tsv-lightbox__prev {
    left: 12px;
  }

  .tsv-lightbox__next {
    right: 12px;
  }

  .tsv-lightbox__cap {
    right: 64px;
    bottom: 28px;
    left: 64px;
    font-size: 13px;
  }
}

/* ==========================================================================
   Scroll lock, set on <html> while a sheet is open (iOS safe: the body is
   pinned in place and the script puts the scroll position back on close)
   ========================================================================== */

html.tsv-lock {
  overflow: hidden !important;
  scroll-behavior: auto !important;
}

html.tsv-lock body {
  position: fixed;
  right: 0;
  left: 0;
  width: 100%;
  overflow: hidden;
}

/* ==========================================================================
   No script: the hidden sources print inline as plain panes, so the page
   still reads. (scripting: none matches only when JavaScript is off.)
   ========================================================================== */

@media (scripting: none) {
  [data-sheet-src][hidden] {
    display: grid;
    gap: clamp(22px, 3vw, 32px);
    width: min(1152px, 100% - 40px);
    margin: 24px auto;
    padding: clamp(20px, 3vw, 32px);
    font-family: var(--tsv-font);
    color: var(--tsv-fg);
    background: var(--tsv-surface);
    border: 1px solid var(--tsv-line);
    border-radius: var(--tsv-r2);
  }

  [data-sheet-src] > .tsv-article__title {
    margin: 0;
    font-size: clamp(22px, 2.4vw, 30px);
    font-weight: 500;
    letter-spacing: -.02em;
    line-height: 1.15;
  }

  .tsv-media:not(.is-ready) {
    padding-bottom: 6px;
  }

  .tsv-media:not(.is-ready) > figure {
    display: grid;
    gap: 10px;
    align-content: start;
    margin: 0;
  }

  .tsv-media:not(.is-ready) > figure :is(img, video) {
    width: 100%;
    height: auto;
    border: 1px solid var(--tsv-line);
    border-radius: var(--tsv-r1);
  }

  .tsv-media:not(.is-ready) figcaption {
    font-size: 14px;
    line-height: 1.55;
    color: var(--tsv-soft);
  }

  .tsv-card__media::before,
  .tsv-card::after {
    display: none;
  }
}

/* ==========================================================================
   Motion. Only for people who have not asked for less of it.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  /* cards rise once, blur clears in 340 ms */
  .tsv-card.is-pre {
    opacity: 0;
  }

  .tsv-card.is-in {
    animation: tsv-rise .55s var(--tsv-ease) backwards, tsv-unblur .34s ease-out backwards;
    animation-delay: calc(var(--tsv-i, 0) * 70ms), calc(var(--tsv-i, 0) * 70ms);
  }

  @keyframes tsv-rise {
    from {
      opacity: 0;
      transform: translateY(20px);
    }
  }

  @keyframes tsv-unblur {
    from {
      filter: blur(6px);
    }
  }

  /* the sheet content steps in, one block after the next */
  .tsv-sheet.is-open .tsv-sheet__content > * {
    animation: tsv-rise-s .5s var(--tsv-ease) backwards, tsv-unblur-s .34s ease-out backwards;
    animation-delay: calc(var(--tsv-i, 0) * 60ms + 140ms), calc(var(--tsv-i, 0) * 60ms + 140ms);
  }

  .tsv-sheet__content[data-dir="next"] > * {
    animation: tsv-in-next .36s var(--tsv-ease) backwards, tsv-unblur-s .3s ease-out backwards !important;
    animation-delay: calc(var(--tsv-i, 0) * 40ms), calc(var(--tsv-i, 0) * 40ms) !important;
  }

  .tsv-sheet__content[data-dir="prev"] > * {
    animation: tsv-in-prev .36s var(--tsv-ease) backwards, tsv-unblur-s .3s ease-out backwards !important;
    animation-delay: calc(var(--tsv-i, 0) * 40ms), calc(var(--tsv-i, 0) * 40ms) !important;
  }

  @keyframes tsv-rise-s {
    from {
      opacity: 0;
      transform: translateY(14px);
    }
  }

  @keyframes tsv-unblur-s {
    from {
      filter: blur(5px);
    }
  }

  @keyframes tsv-in-next {
    from {
      opacity: 0;
      transform: translateX(28px);
    }
  }

  @keyframes tsv-in-prev {
    from {
      opacity: 0;
      transform: translateX(-28px);
    }
  }

  .tsv-how[open] > :not(summary) {
    animation: tsv-fade .3s var(--tsv-ease-io) backwards;
  }

  @keyframes tsv-fade {
    from {
      opacity: 0;
    }
  }

  /* image parallax on hover, fine pointers only */
  @media (hover: hover) and (pointer: fine) {
    .tsv-card:hover .tsv-card__media img {
      transform: translate3d(calc(var(--tsv-px, 0) * -10px), calc(var(--tsv-py, 0) * -8px), 0) scale(1.08);
    }
  }
}

@media (prefers-reduced-motion: reduce) {
  :is(.tsv-card, .tsv-card__media img, .tsv-lightbox, .tsv-lightbox__img, .tsv-dot::before, .tsv-ibtn, .tsv-btn, .tsv-media__play, .tsv-how > summary::after, .tsv-card::after, .tsv-card__media::before) {
    transition-duration: .01ms !important;
  }

  /* the sheet only fades: no scale, no blur, no slide */
  .tsv-sheet {
    transition: background-color .16s linear;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .tsv-sheet.is-open {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .tsv-sheet .tsv-sheet__panel,
  .tsv-sheet.is-open .tsv-sheet__panel {
    filter: none;
    transform: none;
    transition: opacity .16s linear;
  }

  .tsv-sheet .tsv-sheet__panel {
    opacity: 0;
  }

  .tsv-sheet.is-open .tsv-sheet__panel {
    opacity: 1;
  }

  .tsv-media__track {
    scroll-behavior: auto;
  }
}
