/* =============================================================
   WORK.CSS — Work page layout and components
   ============================================================= */

/* -------------------------------------------------------------
   Work page overrides .page to lock exactly to viewport height
   ------------------------------------------------------------- */
.page {
  height: 100dvh;
}

/* -------------------------------------------------------------
   Page content — slideshow left, work panel right
   ------------------------------------------------------------- */
.page-content {
  display: flex;
  gap: 0;
  flex: 1;
  min-height: 0;
}

/* Gap only exists when the work panel is visible */
.page[data-state="work"] .page-content {
  gap: 16px;
}

/* Animate gap in sync with the panel width */
.page.is-animating .page-content {
  transition: gap 600ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* -------------------------------------------------------------
   Work panel — animates in/out as SPA state changes
   ------------------------------------------------------------- */
/* Bleeds back through the surface's vertical padding, so the timeline is
   cut off by the card's own edge. Clipped at the padding instead, entries
   vanished into a white band short of the edge and the column read as
   ending early. The surface's overflow and radius do the cutting; the
   scroller carries the resting inset as its own padding. */
.work-panel {
  flex-shrink: 0;
  position: relative;
  width: 0;
  overflow: hidden;
  opacity: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
  margin-block: calc(-1 * var(--work-surface-pad, 14px));
}

/* Work state: panel fully visible, extends to viewport bottom.
   Half the surface, less the gap between the two — which leaves the
   slideshow the other half exactly. Past the cap the nav stops growing and
   the extra width goes to the picture instead: it is a column of text and
   there is a width beyond which it only gets harder to read. */
.page[data-state="work"] .work-panel {
  width: calc(50% - var(--work-surface-pad, 14px));
  max-width: 560px;
  opacity: 1;
  overflow: visible;
}

/* Animating: enable transitions, keep overflow hidden to prevent bleed */
.page.is-animating .work-panel {
  overflow: hidden;
  transition: width 600ms cubic-bezier(0.4, 0, 0.2, 1),
              opacity 350ms ease;
}

/* -------------------------------------------------------------
   Company colours
   -------------------------------------------------------------
   Sampled from each logo, and shared: the timeline's markers and the
   slideshow's dots both read them, so a case study is the same colour
   wherever it shows up. Defined once here rather than beside each use,
   which is how the two drifted apart the last time.
   ------------------------------------------------------------- */
:root {
  /* -solid is each -wash already composited onto white, so a mark's halo can
     be the band it sits on rather than a white ring. */
  --org-pd:             #0074F1;   /* Avionté */
  --org-pd-soft:        rgba(0, 116, 241, 0.38);
  --org-pd-wash:        rgba(0, 116, 241, 0.08);
  --org-pd-solid:       rgb(235, 244, 254);

  --org-alumni:         #062240;   /* University of Notre Dame */
  --org-alumni-soft:    rgba(6, 34, 64, 0.34);
  --org-alumni-wash:    rgba(6, 34, 64, 0.07);
  --org-alumni-solid:   rgb(238, 240, 242);

  --org-transferred:    #990000;   /* Kelley School of Business */
  --org-transferred-soft: rgba(153, 0, 0, 0.32);
  --org-transferred-wash: rgba(153, 0, 0, 0.06);
  --org-transferred-solid: rgb(249, 240, 240);
}

/* -------------------------------------------------------------
   Slideshow — left panel
   ------------------------------------------------------------- */
/* Concentric with the surface it sits in: the card's own radius less the
   padding between them, so the two curves run parallel instead of the
   inner one looking too round for the space it is inset into. Same rule
   .pin-card__media follows on the other page. */
.slideshow,
.slideshow-frame {
  --slideshow-radius: calc(var(--border-radius-xl) - var(--work-surface-pad, 14px));
}

.slideshow-frame {
  flex: 1;
  min-width: 0;
  position: relative;
  filter: drop-shadow(var(--shadow-frame-cast));
}

.slideshow {
  width: 100%;
  height: 100%;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #ffffff;
  border-radius: var(--slideshow-radius);
  overflow: hidden;
}

.slideshow__track {
  width: 100%;
  height: 100%;
  position: relative;
}

/* Slides travel rather than crossfade. An idle slide parks below the
   frame, the active one sits at rest, and the outgoing one is pushed up
   and out — so a forward step reads bottom-to-top. Only the two slides
   involved in a step are ever animating; the rest sit parked. */
.slideshow__slide {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: translateY(100%);
  transition: transform 560ms cubic-bezier(0.4, 0, 0.2, 1),
              opacity   360ms ease;
  pointer-events: none;
  will-change: transform;
}

.slideshow__slide.is-active {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
  z-index: 1;
}

.slideshow__slide.is-leaving {
  opacity: 0;
  transform: translateY(-100%);
  z-index: 0;
}

/* Stepping backwards mirrors it: the incoming slide drops in from above
   and the outgoing one exits downward. */
.slideshow__track.is-back .slideshow__slide { transform: translateY(-100%); }
.slideshow__track.is-back .slideshow__slide.is-active { transform: translateY(0); }
.slideshow__track.is-back .slideshow__slide.is-leaving { transform: translateY(100%); }

/* Restoring a slide from sessionStorage must not animate in from the edge */
.slideshow__track.no-anim .slideshow__slide { transition: none; }

@media (prefers-reduced-motion: reduce) {
  .slideshow__slide { transition: opacity 360ms ease; transform: none; }
  .slideshow__slide.is-active,
  .slideshow__slide.is-leaving { transform: none; }
}

.slideshow__slide.is-active[data-href] {
  cursor: pointer;
}

.slideshow__image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  display: block;
}

.slideshow__placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: var(--color-text-muted);
  text-align: center;
  padding: 24px;
}

.slideshow__placeholder span {
  font-family: var(--font-accent);
  font-size: var(--scale-5);
  font-weight: 600;
  color: var(--color-text-secondary);
}

.slideshow__placeholder p {
  font-family: var(--font-primary);
  font-size: var(--scale-1);
  color: var(--color-text-muted);
}

/* Dot indicators — vertical pill pinned to the left edge of .slideshow-frame,
   sitting in the notch carved out of .slideshow by the clip-path in slideshow.js */
/* ── Slide nav ─────────────────────────────────────────────────
   A vertical pill on the left edge, sitting in the bite cut from the frame
   so it reads as part of the slideshow rather than on top of it. */
.slideshow__dots {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  background: #ffffff;
  border-radius: 100px;
  padding: 10px 8px;
  /* No shadow of its own: .slideshow-frame's drop-shadow is cast from the
     pill too, so the pill and the picture it sits in always match. */
}

.slideshow__dot {
  width: 9px;
  height: 9px;
  border-radius: 9999px;
  border: none;
  background: rgba(0, 0, 0, 0.2);
  padding: 0;
  cursor: pointer;
  flex-shrink: 0;
  transition: height 280ms cubic-bezier(0.34, 1.56, 0.64, 1),
              background 200ms ease;
}

/* Each dot carries its study's company, so the pill reads as the same
   colour coding the timeline beside it uses. */
.slideshow__dot[data-org="pd"]          { --dot-accent: var(--org-pd); }
.slideshow__dot[data-org="alumni"]      { --dot-accent: var(--org-alumni); }
.slideshow__dot[data-org="transferred"] { --dot-accent: var(--org-transferred); }

.slideshow__dot.is-active {
  height: 24px;
  background: var(--dot-accent, var(--color-active));
}

@media (hover: hover) and (pointer: fine) {
  .slideshow__dot:not(.is-active):hover { background: rgba(0, 0, 0, 0.36); }
}

/* Chevron prev/next buttons inside the dot pill */
.slideshow__prev,
.slideshow__next {
  width: 20px;
  height: 20px;
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(0, 0, 0, 0.35);
  border-radius: 50%;
  flex-shrink: 0;
  transition: color 150ms ease, background 150ms ease;
}

.slideshow__prev:hover,
.slideshow__next:hover {
  color: rgba(0, 0, 0, 0.8);
  background: rgba(0, 0, 0, 0.06);
}


/* -------------------------------------------------------------
   Reveal chevron — right edge, brings the dismissed intro back
   ------------------------------------------------------------- */

/* Mirrors .idea-panel-toggle: flush with the frame's right edge, sitting
   in a notch that slideshow.js carves to match. It scales in from the
   edge rather than just fading, so it reads as emerging from the notch
   as the notch itself opens. */
.slideshow__reveal {
  position: absolute;
  right: 0;
  top: 50%;
  z-index: 20;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: none;
  background: #ffffff;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.14);
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(0, 0, 0, 0.40);
  cursor: pointer;
  padding: 0;
  opacity: 0;
  transform: translateY(-50%) translateX(10px) scale(0.75);
  pointer-events: none;
  transition: opacity 260ms ease,
              transform 420ms cubic-bezier(0.32, 0.72, 0, 1),
              color 150ms ease;
}

.slideshow__reveal.is-visible {
  opacity: 1;
  transform: translateY(-50%) translateX(0) scale(1);
  pointer-events: auto;
}

/* Colour-only on hover, matching .idea-panel-toggle — no movement, or it
   would fight the entrance transform on the same property. */
.slideshow__reveal:hover { color: rgba(0, 0, 0, 0.75); }

/* Same 1px optical nudge the idea pages give their left-pointing chevron */
.slideshow__reveal svg { position: relative; left: -1px; }

@media (prefers-reduced-motion: reduce) {
  .slideshow__reveal { transition: opacity 260ms ease; transform: translateY(-50%); }
  .slideshow__reveal.is-visible { transform: translateY(-50%); }
}

/* -------------------------------------------------------------
   Glass intro card — home state only, centered in slideshow
   ------------------------------------------------------------- */
.glass-card {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: calc(100% - 48px);
  /* Widened so six persona tabs sit with real spacing rather than
     squeezing against the close button */
  max-width: 790px;
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: var(--border-radius-xl);

  /* --persona-* are shared with .persona. The top padding is deliberately
     tighter than the sides so the bar sits close to the card's top edge
     rather than floating between two equal gaps. */
  --persona-pad: 4px;
  --persona-tab-pad: 14px;
  /* Extra squeeze on the pill alone, so the blue sits a little shorter than
     the track without changing the track's own height. Only the indicator
     reads it; the tabs keep their full hit area. */
  --persona-pill-inset: 3px;
  /* Distance from the track's own edge to the content that must line up
     with the card's text column — the first label on the left, the close
     glyph on the right. The track hangs out by this so its *contents*
     align, which makes the bar wider than the card's padding. One value
     for both ends: the close button carries a tab's padding, so the two
     ends are built identically and the overhangs match. */
  --persona-inset: calc(var(--persona-pad) + var(--persona-tab-pad));
  --card-pad-x: 40px;

  /* The top is trimmed twice: once by --persona-inset, which is the strip's
     own hang-out, and again by --card-pad-trim, because the strip no longer
     has a surface to sit the labels inside — without it the first line of
     the card reads as floating too far down. */
  --card-pad-trim: 8px;
  padding: calc(var(--card-pad-x) - var(--persona-inset) - var(--card-pad-trim))
           var(--card-pad-x) 26px;
  display: flex;
  flex-direction: column;
  gap: 0;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08),
              0 1px 2px rgba(0, 0, 0, 0.04),
              inset 0 1px 0 rgba(255, 255, 255, 0.8);
  overflow: hidden;
  pointer-events: none;
  z-index: 10;
  opacity: 1;
  transition: opacity 400ms ease;
  animation: gc-card-entrance 0.5s cubic-bezier(0.34, 1.1, 0.64, 1) 0.1s both;
}

@keyframes gc-card-entrance {
  from { opacity: 0; transform: translate(-50%, calc(-50% - 28px)); }
  to   { opacity: 1; transform: translate(-50%, -50%); }
}

.glass-card__title {
  font-family: var(--font-accent);
  font-size: var(--scale-6);
  font-weight: 700;
  color: #111;
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.glass-card__body {
  font-family: var(--font-primary);
  font-size: var(--scale-3);
  font-weight: 400;
  color: #444;
  line-height: 1.55;
  margin-top: 16px;
}

/* Glass card header — holds the persona strip, which now carries the
   close button inside it as a trailing control. */
.glass-card__header {
  display: flex;
  align-items: stretch;
  gap: 8px;
}

/* Title now follows the header row rather than sitting inside it. It used
   to sit well clear of the tabs so the strip read as attached to the card's
   top edge — but the strip has no surface of its own any more, so that gap
   just read as a hole between two lines of text. */
.glass-card__title {
  margin-top: 20px;
}

/* -------------------------------------------------------------
   Persona switcher — segmented pill in the glass card header
   ------------------------------------------------------------- */

/* Built from the card's own glass vocabulary — a translucent frosted
   track with a highlight along its top edge — rather than an opaque chip
   sitting on top of it. Light track also means the labels can be black at
   both states, which a dark track ruled out. */
/* Sits inside the card's padding like every other element, so the bar is
   inset the same on both sides. It previously hung left by
   --persona-inset to put the first label on the card's text column, but
   that left the bar visibly off-centre — 19px on the left against 41px on
   the right. Even spacing wins; the label now starts inside the track. */
.persona {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0;
  flex: 1 1 auto;
  min-width: 0;
  /* Tabs pack together from the left at their own padding. The strip
     still grows to fill the header, so the close button stays hard right;
     the leftover space simply sits after the last tab. */
  justify-content: flex-start;
  padding: var(--persona-pad);
  margin-left: calc(-1 * var(--persona-inset));
  /* No container of its own — no white, no border, no blur of its own. The
     tabs sit straight on the glass, which already supplies all three; the
     blue indicator is the only thing with a surface. */
  background: none;
  border: none;
  border-radius: 100px;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  pointer-events: auto;
}

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

/* The moving indicator. Width and position are measured from the target
   tab in persona.js, the same approach the main nav pill uses. */
.persona__pill {
  position: absolute;
  /* Inset past the track's padding so the blue is shorter than the tabs it
     sits behind — the tabs are unchanged, only the indicator shrinks. */
  top: calc(var(--persona-pad) + var(--persona-pill-inset));
  left: 0;
  height: calc(100% - (var(--persona-pad) + var(--persona-pill-inset)) * 2);
  width: 0;
  /* Same treatment as .nav__pill: brand blue with white text on it */
  background: var(--color-active);
  border-radius: 100px;
  transform: translateX(0);
  transition: transform 300ms cubic-bezier(0.32, 0.72, 0, 1),
              width     300ms cubic-bezier(0.32, 0.72, 0, 1);
  will-change: transform, width;
  z-index: 0;
  pointer-events: none;
}

.persona__tab {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  text-align: center;
  border: none;
  background: none;
  border-radius: 100px;
  padding: 9px var(--persona-tab-pad);
  font-family: var(--font-primary);
  font-size: 12.5px;
  font-weight: 800;
  letter-spacing: 0.005em;
  white-space: nowrap;
  cursor: pointer;
  color: var(--color-text-inactive);
  transition: color 200ms ease;
}

/* Colour follows the pill, not the selection — so hovering another tab
   darkens that one and dims the selected one, exactly like the nav. */
.persona__tab.has-pill {
  color: #ffffff;
}

/* X close button — sits inline at the right of the title */
/* Sits inside .persona as its last item — matched to the tabs' height so
   the track reads as one control, but deliberately not a .persona__tab,
   which keeps the sliding pill from ever landing on it. */
/* Separate from the tabs rather than inside their strip, and bare in the
   same way they are. Stretched rather than given a size, so its height is
   the track's whatever the tabs come out at. */
.glass-card__close {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  align-self: stretch;
  margin-right: calc(-1 * var(--persona-inset));
  background: none;
  border: none;
  border-radius: 100px;
  /* Matches .persona__tab so the glyph is inset from its own edge by the
     same amount the first label is from the track's. */
  padding: 0 var(--persona-tab-pad);
  cursor: pointer;
  /* Same treatment as .glass-card__cta-btn: dark at rest, lightened on
     hover — rather than faint-until-hovered, which read as the inverse. */
  color: #111;
  pointer-events: auto;
  line-height: 0;
  transition: opacity 200ms ease;
}

.glass-card__close:hover {
  opacity: 0.7;
}

/* Hairline separating the close control from the tabs it now shares a
   track with */
/* Mode selection row — fades in after body text types */
.glass-card__modes {
  margin-top: 20px;
  opacity: 0;
  transition: opacity 350ms ease;
  pointer-events: none;
}

.glass-card__modes.is-visible {
  opacity: 1;
  pointer-events: auto;
}

.glass-card__modes-label {
  font-family: var(--font-primary);
  font-size: var(--scale-3);
  font-weight: 700;
  color: #444;
  letter-spacing: 0;
  text-transform: none;
  line-height: 1.55;
  margin-bottom: 10px;
}

/* Segmented control track */
.glass-card__mode-btns {
  display: flex;
  gap: 0;
  background: rgba(0, 0, 0, 0.06);
  border-radius: 100px;
  padding: 4px;
}

/* Individual pill inside the track */
.glass-card__mode-btn {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 10px 12px 11px;
  background: transparent;
  border: none;
  border-radius: 100px;
  cursor: pointer;
  pointer-events: auto;
  text-align: center;
  transition: background 220ms ease,
              box-shadow 220ms ease,
              transform 140ms ease;
}

.glass-card__mode-btn:hover {
  background: rgba(255, 255, 255, 0.88);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1),
              inset 0 1px 0 rgba(255, 255, 255, 1);
  transform: translateY(-1px);
}

.glass-card__mode-btn:active {
  transform: translateY(0);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}

.glass-card__mode-name {
  font-family: var(--font-accent);
  font-size: var(--scale-3);
  font-weight: 700;
  color: #111;
  line-height: 1.1;
  white-space: nowrap;
}

.glass-card__mode-desc {
  font-family: var(--font-primary);
  font-size: var(--scale-2);   /* 14.4px — pairs with mode-name at scale-3 */
  font-weight: 400;
  color: #777;
  line-height: 1.3;
}

/* Bottom row — welcome text + CTA side by side */
.glass-card__bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 16px;
}

.glass-card__welcome {
  font-family: var(--font-primary);
  font-size: var(--scale-3);
  font-weight: 700;
  color: #111;
  white-space: nowrap;
  flex-shrink: 0;
  opacity: 0;
}

.glass-card__cta {
  flex: 1;
  pointer-events: auto;
  overflow: hidden;
}

.glass-card__cta-btn {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 5px;
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  font-family: var(--font-primary);
  font-size: var(--scale-3);
  font-weight: 700;
  color: #111;
  text-decoration: none;
  cursor: pointer;
  transition: opacity 200ms ease;
  overflow: hidden;
}

.glass-card__cta-btn:hover {
  opacity: 0.7;
}

.glass-card__cta-chevron {
  flex-shrink: 0;
  /* Optical nudge so the chevron sits on the label's line. Done with top
     rather than transform, which the slide-in animation owns — this way the
     offset holds through the travel and at rest beside "Work". */
  position: relative;
  top: 1.5px;
  transform: translateX(-540px);
}

.glass-card__cta-label {
  opacity: 0;
  white-space: nowrap;
}

.glass-card__cta.is-visible .glass-card__cta-label {
  animation: gc-label-in 0.28s ease 1.2s forwards;
}

.glass-card__cta.is-visible .glass-card__cta-chevron {
  animation: gc-chevron-travel 0.9s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.3s forwards;
}

@keyframes gc-label-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes gc-chevron-travel {
  from { transform: translateX(-540px); }
  to   { transform: translateX(0); }
}

/* Featured section intro bio */
.work-section__intro {
  padding: 0 28px 14px;
  font-family: var(--font-primary);
  font-size: var(--scale-2);
  font-weight: 400;
  color: var(--color-text-secondary);
  line-height: 1.55;
  flex-shrink: 0;
}

/* Work FAB — fixed bottom-right, glass pill */
.work-fab {
  position: fixed;
  bottom: 28px;
  right: 28px;
  display: flex;
  align-items: center;
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: 100px;
  padding: 9px 14px 9px 16px;
  font-family: var(--font-primary);
  font-size: var(--scale-2);
  font-weight: 600;
  color: rgba(0, 0, 0, 0.5);
  text-decoration: none;
  cursor: pointer;
  z-index: 100;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06),
              inset 0 1px 0 rgba(255, 255, 255, 0.8);
  transition: color var(--transition-fast),
              padding var(--transition-fast),
              opacity 400ms ease;
}

.work-fab:hover {
  color: rgba(0, 0, 0, 0.85);
  padding-left: 20px;
}

.work-fab__label {
  max-width: 0;
  overflow: hidden;
  opacity: 0;
  white-space: nowrap;
  margin-right: 0;
  line-height: 1;
  display: flex;
  align-items: center;
  transform: translateY(-1px);
  transition: max-width 320ms cubic-bezier(0.4, 0, 0.2, 1),
              opacity 220ms ease,
              margin-right 320ms cubic-bezier(0.4, 0, 0.2, 1);
}

.work-fab:hover .work-fab__label {
  max-width: 50px;
  opacity: 1;
  margin-right: 5px;
}

.work-fab svg {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
}

/* Dissolve card + FAB when SPA transitions to work.
   animation:none cancels the gc-card-entrance forwards-fill so the
   opacity transition can actually take effect. */
.page[data-state="work"] .glass-card,
.page[data-state="work"] .work-fab {
  animation: none;
  opacity: 0;
  pointer-events: none;
}

/* -------------------------------------------------------------
   Work logo tooltip — glass link preview on logo hover
   ------------------------------------------------------------- */
.work-logo-tooltip {
  position: fixed;
  pointer-events: none;
  z-index: 200;
  width: max-content;
  background: rgba(255, 255, 255, 0.78);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(255, 255, 255, 0.65);
  border-radius: 14px;
  padding: 12px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08),
              0 1px 2px rgba(0, 0, 0, 0.04),
              inset 0 1px 0 rgba(255, 255, 255, 0.8);
  opacity: 0;
  transition: opacity 140ms ease;
}

.work-logo-tooltip.is-visible {
  opacity: 1;
}

.work-logo-tooltip__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

.work-logo-tooltip__name {
  font-family: var(--font-accent);
  font-size: var(--scale-3);
  font-weight: 700;
  color: #111;
  line-height: 1.2;
  white-space: nowrap;
}

.work-logo-tooltip__arrow {
  flex-shrink: 0;
  color: #999;
  margin-top: 4px;
}

.work-logo-tooltip__url {
  font-family: var(--font-primary);
  font-size: var(--scale-1);
  font-weight: 400;
  color: #777;
  white-space: nowrap;
}

/* -------------------------------------------------------------
   Slide tooltip — glass cursor tooltip for slideshow hover
   ------------------------------------------------------------- */
.slide-tooltip {
  position: fixed;
  pointer-events: none;
  z-index: 60;
  width: max-content;
  background: rgba(255, 255, 255, 0.78);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(255, 255, 255, 0.65);
  border-radius: 14px;
  padding: 12px 16px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08),
              0 1px 2px rgba(0, 0, 0, 0.04),
              inset 0 1px 0 rgba(255, 255, 255, 0.8);
  opacity: 0;
  transition: opacity 140ms ease;
}

.slide-tooltip.is-visible {
  opacity: 1;
}

.slide-tooltip__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.slide-tooltip__title {
  font-family: var(--font-accent);
  font-size: var(--scale-3);
  font-weight: 700;
  color: #111;
  line-height: 1.2;
  white-space: nowrap;
}

.slide-tooltip__logo {
  width: auto;
  height: 24px;
  object-fit: contain;
  flex-shrink: 0;
}

.slide-tooltip__meta {
  font-family: var(--font-primary);
  font-size: var(--scale-1);   /* 12px */
  font-weight: 400;
  color: #555;
  line-height: 1.45;
}

/* -------------------------------------------------------------
   Work nav — single unified container replacing individual cards
   ------------------------------------------------------------- */
/* Pinned to the panel's right edge at the width it will finish at, rather
   than filling the panel as it grows. The panel is what animates: its left
   edge sweeps left across the surface and uncovers the nav, so the column
   is drawn out from under the slideshow instead of being squeezed out of a
   box that reflows every frame of the transition. 50cqw is half the
   surface's content box — the same half the panel settles at. */
.work-nav {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(calc(50cqw - var(--work-surface-pad, 14px)), 560px);
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  overscroll-behavior: none;
  overflow: visible;
  box-sizing: border-box;
}

/* -------------------------------------------------------------
   Work deck — one case study at a time
   -------------------------------------------------------------
   The panel is one surface, edge to edge. The chapter identity is fixed
   at its top and changes only when the deck crosses into another chapter
   — never between case studies inside one — while the sections beneath
   travel bottom to top on exactly the transform, duration and curve that
   .slideshow__slide uses, so the image and the words move as one.
   ------------------------------------------------------------- */
.work-deck {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  gap: 12px;
  padding: 12px;
  position: relative;
  overflow: hidden;
}

/* Each content area is its own framed section, the way the other page frames
   an image inside its card: the chapter is one, the case study is another,
   and the panel is the surface they sit on. */
.work-deck__section {
  background: #ffffff;
  border-radius: var(--border-radius-xl);
  box-shadow: var(--shadow-card);
}

.work-deck__section--head {
  flex-shrink: 0;
  padding: 20px 26px;
}

.work-deck__section--body {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  position: relative;
}

/* ── Chapter identity ─────────────────────────────────────────── */
/* Sits on the panel's own surface rather than on a card of its own, so it
   belongs to the section below it instead of floating above it — and it
   stays put while the sections move under it. */
.work-deck__head {
  position: relative;
  height: 108px;
}

.work-chapter {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity 280ms ease,
              transform 440ms cubic-bezier(0.32, 0.72, 0, 1);
}

.work-chapter.is-current {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.work-chapter.is-past { transform: translateY(-8px); }

.work-chapter__row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.work-chapter__id {
  min-width: 0;
  display: flex;
  flex-direction: column;
  /* Air between the company and the role, so the two read as separate
     facts rather than one stacked label. */
  gap: 10px;
}

.work-chapter__org {
  font-family: var(--font-primary);
  font-size: var(--scale-1);   /* 12px */
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* The degree line that used to need a step of its own in the deck. Folding
   it into the chapter block is what lets Talent Search hand straight over to
   BLOKD instead of stopping on a header first. */
.work-chapter__note {
  font-family: var(--font-primary);
  font-size: var(--scale-1);   /* 12px */
  font-weight: 500;
  line-height: 1.4;
  color: var(--color-text-muted);
  margin-top: 8px;
}

.work-chapter__foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-top: 10px;
}

.work-chapter__count {
  font-family: var(--font-primary);
  font-size: var(--scale-1);
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.work-chapter__role {
  font-family: var(--font-accent);
  font-size: var(--scale-5);   /* 24.88px */
  font-weight: 700;
  line-height: 1.1;
  color: var(--color-text-dark);
}

.work-chapter__logo {
  width: 38px;
  height: 34px;
  flex-shrink: 0;
  object-fit: contain;
}

.work-chapter__logo--cover { object-fit: cover; object-position: center; }

.work-chapter__date {
  font-family: var(--font-primary);
  font-size: var(--scale-2);
  font-weight: 600;
  color: var(--color-text-secondary);
}

/* ── Sections ─────────────────────────────────────────────────── */
/* Mirrors .slideshow__track — fills its section, clips the travel. */
.work-deck__stage {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: var(--border-radius-xl);
}

/* Parked below, exactly as .slideshow__slide is. */
.work-card {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: 26px 28px 28px;
  color: var(--color-text-primary);
  text-decoration: none;
  opacity: 0;
  transform: translateY(100%);
  transition: transform 560ms cubic-bezier(0.4, 0, 0.2, 1),
              opacity   360ms ease;
  pointer-events: none;
  will-change: transform;
}

.work-card.is-active {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
  z-index: 1;
}

.work-card.is-leaving {
  opacity: 0;
  transform: translateY(-100%);
  z-index: 0;
}

/* Stepping backwards mirrors it, the same way the slideshow does */
.work-deck__stage.is-back .work-card            { transform: translateY(-100%); }
.work-deck__stage.is-back .work-card.is-active  { transform: translateY(0); }
.work-deck__stage.is-back .work-card.is-leaving { transform: translateY(100%); }

.work-deck__stage.no-anim .work-card { transition: none; }

/* The whole section is clickable through this, rather than the section
   being an <a> itself: an anchor inside an anchor is invalid and the
   parser closes the outer one early. */
.work-card__link {
  position: absolute;
  inset: 0;
  z-index: 2;
  cursor: pointer;
}

.work-card__link:focus-visible {
  outline: 2px solid var(--color-active);
  outline-offset: -6px;
}

.work-card__body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* The facts hold their size; the prose gives. A long Team value wrapping to
   a second line was enough to push the problem text past the bottom of the
   section, so the reading length absorbs the squeeze rather than the
   structure breaking. */
.work-card__meta,
.work-card__title,
.work-card__details,
.work-card__tags { flex-shrink: 0; }

.work-card__desc,
.work-card__problem {
  flex-shrink: 1;
  min-height: 0;
  overflow: hidden;
}

/* Company left, date hard right — the same meta row the other page uses. */
/* Its own band: what kind of work this is and where it stands, closed off
   by a rule so it reads separately from the title beneath it. */
.work-card__meta {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 14px;
  margin-bottom: 18px;
  border-bottom: 1px solid var(--color-border);
}

/* The study's own framing line. The company moved up into the chapter
   block, so this carries the product and the kind of work instead. */
.work-card__kicker {
  font-family: var(--font-primary);
  font-size: var(--scale-1);   /* 12px */
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--chapter);
  min-width: 0;
}

.work-card__when {
  font-family: var(--font-primary);
  font-size: var(--scale-2);
  font-weight: 500;
  color: var(--color-text-secondary);
  white-space: nowrap;
}

.work-card__title {
  font-family: var(--font-primary);
  font-size: var(--scale-6);   /* 29.86px */
  font-weight: 700;
  line-height: 1.15;
  color: var(--color-text-dark);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 0;
}

.work-card__featured {
  font-family: var(--font-primary);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-active);
  background: rgba(17, 160, 255, 0.10);
  border: 1px solid rgba(17, 160, 255, 0.20);
  border-radius: var(--border-radius);
  padding: 3px 8px;
  white-space: nowrap;
}

.work-card__lock,
.work-card__arrow { flex-shrink: 0; color: var(--color-text-muted); }

.work-card__desc {
  font-family: var(--font-primary);
  font-size: var(--scale-3);   /* 17.28px */
  font-weight: 500;
  line-height: 1.55;
  color: var(--color-text-secondary);
}

/* Role / team, straight from the case study's own hero. Sits above the
   body, under the section's title block, so the framing reads before the
   description rather than trailing after it. */
.work-card__details {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 40px;
  /* Set well below the title: the heading is its own thing, and these are
     the facts about it rather than part of it. */
  margin: 26px 0 0;
}

.work-card__detail {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.work-card__detail dt {
  font-family: var(--font-primary);
  font-size: var(--scale-1);   /* 12px */
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.work-card__detail dd {
  font-family: var(--font-primary);
  font-size: var(--scale-2);   /* 14.4px */
  font-weight: 600;
  color: var(--color-text-dark);
}

/* What the work was up against, in the case study's own words. */
.work-card__problem {
  margin-top: 22px;
  padding-left: 18px;
  border-left: 2px solid var(--chapter);
}

.work-card__problem-label {
  font-family: var(--font-primary);
  font-size: var(--scale-1);   /* 12px */
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin-bottom: 5px;
}

/* Same size as the introduction above it. It was a step smaller, which
   made the problem read as an aside when it carries as much as the intro. */
.work-card__problem-text {
  font-family: var(--font-primary);
  font-size: var(--scale-3);   /* 17.28px */
  font-weight: 500;
  line-height: 1.55;
  color: var(--color-text-secondary);
}

/* Directly under role and team — they describe the work, so they belong
   with the other facts rather than stranded at the bottom of the panel. */
.work-card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 16px 0 24px;
  padding-bottom: 24px;
  border-bottom: 1px solid var(--color-border);
}

.work-card__tag {
  font-family: var(--font-primary);
  font-size: var(--scale-1);   /* 12px */
  font-weight: 600;
  color: var(--color-text-secondary);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 100px;
  padding: 6px 12px;
  white-space: nowrap;
}

/* ── Chapter pips ─────────────────────────────────────────────── */
/* How many case studies this chapter holds and which one is open, stated in
   the header rather than left to be inferred from the rail on the far left. */
.work-chapter__pips {
  display: flex;
  align-items: center;
  gap: 6px;
}

.work-chapter__pip {
  width: 7px;
  height: 7px;
  padding: 0;
  border: none;
  border-radius: 100px;
  background: rgba(0, 0, 0, 0.18);
  cursor: pointer;
  transition: width 260ms cubic-bezier(0.34, 1.56, 0.64, 1),
              background 220ms ease;
}

.work-chapter__pip.is-active {
  width: 20px;
  background: var(--chapter);
}

@media (hover: hover) and (pointer: fine) {
  .work-chapter__pip:not(.is-active):hover { background: rgba(0, 0, 0, 0.34); }
}

/* ── Hint ─────────────────────────────────────────────────────── */
/* Says how to move through the deck, once, on arrival — the gesture is not
   discoverable from a static panel. Dismissed by the first use of it. */
.work-deck__hint {
  position: absolute;
  left: 50%;
  bottom: 74px;
  transform: translateX(-50%) translateY(6px);
  z-index: 5;
  padding: 7px 14px;
  border-radius: 100px;
  background: rgba(27, 27, 30, 0.92);
  color: #ffffff;
  font-family: var(--font-primary);
  font-size: var(--scale-1);
  font-weight: 600;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 300ms ease, transform 420ms cubic-bezier(0.32, 0.72, 0, 1);
}

.work-deck__hint.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ── Advance cue ──────────────────────────────────────────────── */
/* Names the next section and moves to it. Takes the chapter colour, so the
   rail on the left and this read as one control rather than two. */
.work-deck__next {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 2px 2px;
  padding: 12px 16px;
  border: 1px solid var(--color-border);
  border-radius: 100px;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
  transition: border-color 200ms ease, background 200ms ease;
}

.work-deck__next:disabled {
  opacity: 0.45;
  cursor: default;
}

@media (hover: hover) and (pointer: fine) {
  .work-deck__next:not(:disabled):hover {
    background: var(--color-surface);
    border-color: color-mix(in srgb, var(--chapter) 45%, var(--color-border));
  }
}

.work-deck__next-label {
  font-family: var(--font-primary);
  font-size: var(--scale-1);   /* 12px */
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--chapter);
  flex-shrink: 0;
}

.work-deck__next-title {
  font-family: var(--font-primary);
  font-size: var(--scale-2);   /* 14.4px */
  font-weight: 600;
  color: var(--color-text-dark);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.work-deck__next-chev {
  flex-shrink: 0;
  color: var(--color-text-muted);
  transition: transform 260ms cubic-bezier(0.32, 0.72, 0, 1);
}

@media (hover: hover) and (pointer: fine) {
  .work-deck__next:not(:disabled):hover .work-deck__next-chev {
    transform: translateY(2px);
  }
}

/* Shorter viewports. Framing each area as its own section costs height, and
   the intro, role/team, tags and problem together need more than a short
   window leaves. Spacing tightens first; the prose clamps only below that,
   so the structure survives and only the reading length gives. */
@media (max-height: 1000px) {
  .work-deck { gap: 10px; padding: 10px; }
  .work-deck__section--head { padding: 16px 22px; }
  .work-deck__head { height: 96px; }
  .work-chapter__id { gap: 7px; }
  .work-chapter__foot { margin-top: 7px; }
  .work-card { padding: 20px 26px 22px; }
  .work-card__meta { padding-bottom: 10px; margin-bottom: 12px; }
  .work-card__title { font-size: var(--scale-5); }
  .work-card__details { margin-top: 16px; gap: 8px 32px; }
  .work-card__detail dd { font-size: var(--scale-1); }
  .work-card__tags { margin: 12px 0 14px; padding-bottom: 14px; gap: 6px; }
  .work-card__tag { padding: 5px 10px; }
  .work-card__desc,
  .work-card__problem-text { font-size: var(--scale-2); line-height: 1.5; }
  .work-card__problem { margin-top: 12px; padding-left: 14px; }
  .work-deck__next { padding: 10px 14px; }
  .work-deck__hint { bottom: 66px; }
}

/* The clamp is a tidy ending, not the fitting mechanism — the flex rules
   above already stop anything spilling. These only tighten far enough to
   avoid a line being cut mid-height, so the text runs as long as the window
   actually allows. */
@media (max-height: 1000px) {
  .work-card__desc,
  .work-card__problem-text {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .work-card__desc         { -webkit-line-clamp: 6; }
  .work-card__problem-text { -webkit-line-clamp: 5; }
}

@media (max-height: 880px) {
  .work-card__desc         { -webkit-line-clamp: 4; }
  .work-card__problem-text { -webkit-line-clamp: 4; }
}

@media (max-height: 800px) {
  .work-deck__head { height: 88px; }
  .work-chapter__note { display: none; }
  .work-card__desc         { -webkit-line-clamp: 3; }
  .work-card__problem-text { -webkit-line-clamp: 2; }
}

@media (prefers-reduced-motion: reduce) {
  .work-card { transition: opacity 360ms ease; transform: none; }
  .work-card.is-active,
  .work-card.is-leaving { transform: none; }
  .work-deck__stage.is-back .work-card,
  .work-deck__stage.is-back .work-card.is-active,
  .work-deck__stage.is-back .work-card.is-leaving { transform: none; }
  .work-chapter { transition: opacity 280ms ease; transform: none; }
  .work-chapter.is-past { transform: none; }
}

/* -------------------------------------------------------------
   Quick mode — overview card (bio + featured work list)
   ------------------------------------------------------------- */
.quick-overview {
  display: none;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  overflow: hidden;
  background: #ffffff;
  border-radius: var(--border-radius-xl);
  box-shadow: var(--shadow-card);
}

html[data-mode="quick"] .quick-overview {
  display: flex;
}

.quick-overview__scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: none;
  display: flex;
  flex-direction: column;
}

.quick-overview__scroll::-webkit-scrollbar {
  display: none;
}

.quick-overview__intro {
  margin: 12px 12px 0;
  padding: 22px 20px 20px;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  background: linear-gradient(145deg, rgba(17, 160, 255, 0.1) 0%, rgba(17, 160, 255, 0.04) 100%);
  border-radius: 20px;
  border: 1px solid rgba(17, 160, 255, 0.2);
  box-shadow: 0 2px 16px rgba(17, 160, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.7);
  position: relative;
  overflow: hidden;
}

/* Frost cursor glow — follows mouse via --frost-x / --frost-y */
.quick-overview__intro::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(
    circle 90px at var(--frost-x, 50%) var(--frost-y, 50%),
    rgba(255, 255, 255, 0.38) 0%,
    rgba(255, 255, 255, 0.1) 45%,
    transparent 70%
  );
  pointer-events: none;
  opacity: 0;
  transition: opacity 200ms ease;
  border-radius: inherit;
}

.quick-overview__intro.is-frost::before {
  opacity: 1;
}

.quick-overview__intro > * {
  position: relative;
  z-index: 1;
}

.quick-overview__name {
  font-family: var(--font-accent);
  font-size: var(--scale-5);
  font-weight: 700;
  color: var(--color-text-dark);
  line-height: 1.1;
  letter-spacing: -0.01em;
}

.quick-overview__role {
  font-family: var(--font-primary);
  font-size: var(--scale-2);
  font-weight: 600;
  color: var(--color-active);
  margin-top: 3px;
}

.quick-overview__bio {
  font-family: var(--font-primary);
  font-size: var(--scale-1);
  font-weight: 400;
  color: var(--color-text-secondary);
  line-height: 1.65;
  margin-top: 10px;
}

.quick-overview__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 12px;
}

.quick-overview__tag {
  font-family: var(--font-primary);
  font-size: var(--scale-1);   /* 12px */
  font-weight: 600;
  color: rgba(17, 160, 255, 0.85);
  background: rgba(17, 160, 255, 0.08);
  border: 1px solid rgba(17, 160, 255, 0.18);
  border-radius: 6px;
  padding: 3px 8px;
}

.quick-overview__divider {
  display: none;
}

.quick-overview__label {
  font-family: var(--font-primary);
  font-size: var(--scale-1);   /* 12px */
  font-weight: 700;
  color: rgba(0, 0, 0, 0.3);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 14px 12px 8px;
  flex-shrink: 0;
}

.quick-overview .card-items {
  padding: 0 12px 24px;
}

/* Featured-work rows inside Quick mode. These are the only remaining user
   of .work-item: the full-mode nav moved to .work-card when it became a
   deck, and these rules were briefly removed with it, which flattened the
   quick overview's list into unstyled text. Scoped so the two cannot drift
   into each other again. */
.quick-overview .card-items {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.quick-overview .work-item {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-radius: var(--border-radius-lg);
  color: var(--color-text-primary);
  text-decoration: none;
  transition: background var(--transition-fast);
  cursor: pointer;
}

.quick-overview .work-item:hover {
  background-color: var(--color-surface);
}

.quick-overview .work-item__text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.quick-overview .work-item__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.quick-overview .work-item__title {
  font-family: var(--font-primary);
  font-size: var(--scale-3);   /* 17.28px */
  font-weight: 700;
  line-height: normal;
  white-space: nowrap;
}

.quick-overview .work-item__lock,
.quick-overview .work-item__arrow {
  flex-shrink: 0;
  color: var(--color-text-muted);
}

.quick-overview .work-item__desc {
  font-family: var(--font-primary);
  font-size: var(--scale-2);   /* 14.4px */
  font-weight: 500;
  line-height: normal;
  color: var(--color-text-secondary);
}

.quick-overview .work-item__arrow {
  opacity: 0;
  transform: translateX(-16px);
  transition: opacity 250ms ease, transform 350ms cubic-bezier(0.4, 0, 0.2, 1);
}

.quick-overview .work-item:hover .work-item__arrow {
  opacity: 1;
  transform: translateX(0);
}

.quick-overview .work-item[data-protected] .work-item__arrow {
  display: none;
}

/* -------------------------------------------------------------
   Bio glass card — frosted glass profile card with 3D tilt
   ------------------------------------------------------------- */
.bio-tilt-wrap {
  perspective: 900px;
  flex-shrink: 0;
}

.bio-glass-card {
  position: relative;
  background: #ffffff;
  border-radius: var(--border-radius-xl);
  padding: 24px 32px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  box-shadow: var(--shadow-card);
  transform-style: preserve-3d;
  transition: transform 80ms ease-out;
  will-change: transform;
  overflow: hidden;
}

/* Glare highlight — follows mouse */
.bio-glass-card__glare {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(
    circle at var(--mx, 50%) var(--my, 50%),
    rgba(255, 255, 255, 0.38) 0%,
    transparent 65%
  );
  pointer-events: none;
  z-index: 1;
  opacity: 0;
  transition: opacity 200ms ease;
}

.bio-glass-card:hover .bio-glass-card__glare {
  opacity: 1;
}

.bio-glass-card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  position: relative;
  z-index: 2;
}

.bio-glass-card__identity {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.bio-glass-card__name {
  font-family: var(--font-accent);
  font-size: var(--scale-6);
  font-weight: 700;
  color: var(--color-text-dark);
  line-height: 1.1;
}

.bio-glass-card__role {
  font-family: var(--font-primary);
  font-size: var(--scale-2);
  font-weight: 500;
  color: var(--color-text-secondary);
  line-height: normal;
}

.bio-glass-card__loc {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 5px;
  flex-shrink: 0;
  align-self: flex-start;
  background: rgba(0, 0, 0, 0.04);
  border: 1px solid rgba(0, 0, 0, 0.07);
  border-radius: 12px;
  padding: 10px 14px;
}

.bio-glass-card__loc-city {
  font-family: var(--font-accent);
  font-size: var(--scale-2);
  font-weight: 500;
  color: var(--color-text-secondary);
  letter-spacing: -0.01em;
  white-space: nowrap;
  line-height: 1;
}

.bio-glass-card__loc-time {
  font-family: var(--font-primary);
  font-size: var(--scale-1);   /* 12px */
  font-weight: 600;
  color: var(--color-text-dark);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  line-height: 1;
  letter-spacing: 0.01em;
}

.bio-glass-card__loc-time .loc-ampm {
  font-weight: 500;
  color: var(--color-text-muted);
  margin-left: 2px;
}

.bio-glass-card__loc-time .loc-tz {
  font-weight: 700;
  color: var(--color-active);
  margin-left: 4px;
}

.bio-glass-card__bio {
  font-family: var(--font-primary);
  font-size: var(--scale-2);
  font-weight: 500;
  color: var(--color-text-primary);
  line-height: normal;
  position: relative;
  z-index: 2;
}

.bio-glass-card__skills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  position: relative;
  z-index: 2;
}

.bio-glass-card__skill {
  font-family: var(--font-primary);
  font-size: var(--scale-1);
  font-weight: 700;
  color: var(--color-text-secondary);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius);
  padding: 4px 12px;
  letter-spacing: 0.04em;
}

/* -------------------------------------------------------------
   Machine mode — light aesthetic, text-optimized layout
   ------------------------------------------------------------- */
html[data-mode="machine"] .slideshow-frame {
  display: none;
}

html[data-mode="machine"] .page[data-state="work"] .work-panel {
  width: 100%;
  max-width: none;
}

html[data-mode="machine"] .page[data-state="work"] .page-content {
  gap: 0;
}

/* Machine view panel container */
.machine-view {
  display: none;
  flex: 1;
  min-height: 0;
  flex-direction: column;
}

html[data-mode="machine"] .machine-view {
  display: flex;
}

.machine-view__scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 0 0 48px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  scrollbar-width: none;
}

.machine-view__scroll::-webkit-scrollbar {
  display: none;
}

.machine-panel {
  display: flex;
  flex-direction: column;
}

.machine-panel__label {
  font-family: 'Courier New', 'Courier', monospace;
  font-size: 11px;
  font-weight: 400;
  color: rgba(0, 0, 0, 0.65);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding-bottom: 14px;
  margin-bottom: 14px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.18);
}

.machine-panel__box {
  border: 1px solid rgba(0, 0, 0, 0.12);
  border-radius: 4px;
  padding: 18px 20px;
  background: #ffffff;
}

.machine-content {
  font-family: 'Courier New', 'Courier', monospace;
  font-size: 13px;
  line-height: 1.85;
  color: rgba(0, 0, 0, 0.96);
  white-space: pre-wrap;
  word-break: break-word;
  margin: 0;
}

.machine-entry {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-bottom: 14px;
}

.machine-entry:last-child {
  padding-bottom: 0;
}

.machine-link {
  font-family: 'Courier New', 'Courier', monospace;
  font-size: 13px;
  font-weight: 700;
  color: var(--color-active);
  text-decoration: none;
  padding-left: 4px;
}

.machine-link:hover {
  text-decoration: underline;
}

/* -------------------------------------------------------------
   Work sections — stacked inside the nav container
   ------------------------------------------------------------- */
/* -------------------------------------------------------------
   Card header — role title, logo, date, sub-roles
   ------------------------------------------------------------- */
.card-header {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-left: 14px;
  padding-right: 6px;
}

.card-header__top {
  display: flex;
  flex-direction: column;
  padding-bottom: 4px;
}

.card-header__title-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: -2px;
}

.card-header__role {
  font-family: var(--font-accent);
  font-size: var(--scale-5);   /* 24.88px */
  font-weight: 700;
  line-height: normal;
  color: var(--color-text-dark);
}

.card-header__logo {
  width: 40px;
  height: 36px;
  flex-shrink: 0;
  object-fit: contain;
}

/* ND logo is a widescreen canvas — cover crops it to fill the square */
.card-header__logo--cover {
  object-fit: cover;
  object-position: center;
}

.card-header__date {
  font-family: var(--font-primary);
  font-size: var(--scale-2);
  font-weight: 600;
  line-height: normal;
  color: var(--color-text-secondary);
  white-space: nowrap;
}

/* Education row (no connector, full width) */
.card-header__education {
  font-family: var(--font-primary);
  font-size: var(--scale-2);   /* 14.4px */
  font-weight: 500;
  line-height: normal;
  color: var(--color-text-muted);
  margin-top: -4px;
}

/* -------------------------------------------------------------
   Other Work link — bottom of Alumni section
   ------------------------------------------------------------- */
.work-other {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  font-family: var(--font-primary);
  font-size: var(--scale-3);   /* 17.28px */
  font-weight: 600;
  color: var(--color-text-dark);
  text-decoration: none;
  transition: opacity var(--transition-fast);
}

.work-other:hover {
  opacity: 0.6;
}

.work-other svg {
  flex-shrink: 0;
}

/* -------------------------------------------------------------
   Work tab navigation — outer tabs (Featured / All Work)
   ------------------------------------------------------------- */
/* Unified white section that holds tab nav + panels */
/* A tray rather than a single white card: each case study is now its own
   block sitting on it, the way the bento cards sit on the case study pages.
   The old treatment — one white surface with each chapter's header capping
   and shadowing the one above — is what this replaces. */
/* No card of its own: the timeline runs free on the surface's white, so
   the panel reads as part of the same sheet as the slideshow rather than
   as a second box set inside it. */
.work-content-section {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: transparent;
  overflow: hidden;
}

/* In quick/machine modes the mode-specific panels take over; hide the full-mode card */
html[data-mode="quick"] .work-content-section,
html[data-mode="machine"] .work-content-section {
  display: none;
}

/* Tab nav — segmented control with padding from the white card edges */
.work-tab-nav {
  display: flex;
  gap: 4px;
  margin: 12px 12px 8px;
  padding: 4px;
  flex-shrink: 0;
  background: rgba(0, 0, 0, 0.05);
  border-radius: 100px;
}

.work-tab-btn {
  flex: 1;
  font-family: var(--font-primary);
  font-size: var(--scale-2);
  font-weight: 700;
  color: var(--color-text-muted);
  background: none;
  border: none;
  padding: 9px 12px;
  border-radius: 100px;
  cursor: pointer;
  transition: color 150ms ease, background 150ms ease, box-shadow 150ms ease;
}

.work-tab-btn:hover {
  color: var(--color-text-secondary);
}

.work-tab-btn.is-active {
  color: var(--color-text-primary);
  background: #ffffff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.10);
}

/* Tab panels */
.work-tab-panel {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.work-tab-panel[hidden] {
  display: none;
}

/* Featured panel: match the scroller's padding-top so spacing is consistent across both tabs */
.work-tab-panel[data-panel="featured"] {
  padding-top: 10px;
}

/* -------------------------------------------------------------
   Inner tabs — employer/school selector inside All Work panel
   ------------------------------------------------------------- */
.work-inner-tabs {
  display: flex;
  gap: 4px;
  padding: 8px 20px 4px;
  flex-shrink: 0;
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 4px;
}

.work-inner-tab {
  font-family: var(--font-primary);
  font-size: var(--scale-1);
  font-weight: 700;
  color: var(--color-text-muted);
  background: none;
  border: none;
  padding: 6px 10px;
  border-radius: 100px;
  cursor: pointer;
  transition: color 150ms ease, background 150ms ease;
  letter-spacing: 0.02em;
}

.work-inner-tab:hover {
  color: var(--color-text-secondary);
  background: rgba(0, 0, 0, 0.04);
}

.work-inner-tab.is-active {
  color: var(--color-active);
  background: rgba(17, 160, 255, 0.08);
}

.work-inner-panel {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 8px 0;
}

.work-inner-panel[hidden] {
  display: none;
}

/* -------------------------------------------------------------
   Work nav — one scrolling column, chapter headers pinned
   -------------------------------------------------------------
   Static rather than collapsible: the reader scrolls the whole run of work
   instead of opening and shutting it. Each chapter's header pins to the top
   while its case studies pass under it, and is pushed out by the next
   chapter's header — so the brand above always names the work below without
   being repeated on every row, and the column takes any number of chapters.
   ------------------------------------------------------------- */
.work-nav__scroller {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
  -ms-overflow-style: none;
  background: transparent;
  /* How far the column and its rail fade at each end. The foot keeps the
     full distance — that is where an entry rises out of the fade. The head
     keeps only a hint of one: a company's header pins there now, and a long
     ramp would wash the pinned header out. */
  --tl-fade: 44px;
  --tl-fade-top: 10px;
  /* The whole column fades out as it reaches the panel's edges, rather than
     being cut off at them: an entry rises out of the fade at the foot and
     dissolves into it at the head. Masked on the scroller, not the content,
     so the fade stays at the edges while the entries travel through it.
     The extra stops ease the ramp — a straight two-stop gradient reads as a
     band laid over the text, where this reads as the edge shading off. */
  --tl-mask: linear-gradient(
    to bottom,
    transparent 0,
    #000 var(--tl-fade-top),
    #000 calc(100% - var(--tl-fade)),
    rgba(0, 0, 0, 0.55) calc(100% - var(--tl-fade) * 0.64),
    rgba(0, 0, 0, 0.12) calc(100% - var(--tl-fade) * 0.32),
    transparent 100%
  );
  -webkit-mask-image: var(--tl-mask);
  mask-image: var(--tl-mask);
}

.work-nav__scroller::-webkit-scrollbar { display: none; }

/* -------------------------------------------------------------
   Work timeline
   -------------------------------------------------------------
   One free-running column on the panel's white: case studies down the
   left, a continuous rail down the right carrying a marker for each one.
   The rail, the markers and the cards are all ordinary content inside the
   scroller, so they travel together and nothing here has to be driven on
   scroll.

   Every marker lives inside the line it belongs to — a card's title row, a
   company's name row — and is centred on it with top: 50%, so a dot tracks
   its title's real box rather than a measured offset. Copy can wrap or a
   chip can grow and the pairing holds. Only the horizontal reach out to
   the rail is a number, and it is the line's own inset.

   Each company owns its colour, sampled from its logo, so a run of entries
   reads as one employer's without needing a box drawn round it. Anything
   can join a run: a card, a plain note, or another row entirely.
   ------------------------------------------------------------- */
.work-tl {
  /* Right-hand gutter the rail runs down */
  --tl-gutter: 32px;
  /* Rail centre, measured in from the gutter's outer edge */
  --tl-rail: 16px;
  /* Row's right edge → rail centre */
  --tl-reach: calc(var(--tl-gutter) - var(--tl-rail));
  --tl-line: rgba(0, 0, 0, 0.11);
  --tl-dot: 11px;
  /* How far a line's right edge sits inside the row, so its marker and
     date know how far to reach out to the rail. */
  --tl-mark-inset: 0px;
  position: relative;
  /* The washes sit on a negative z-index so the rail and its dots land on
     top of them. Without a stacking context here they would fall through
     every transparent ancestor and hide behind .work-surface's white. */
  isolation: isolate;
  /* Queried by .work-item__featured below. On .work-tl rather than on a row
     because a container on the row would make it a stacking context, and
     the row's wash would then paint over the rail instead of under it. */
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  padding: 20px var(--tl-gutter) 20px 2px;
}

.work-tl__group[data-group="pd"] {
  --tl-accent: var(--org-pd);
  --tl-accent-soft: var(--org-pd-soft);
  --tl-accent-wash: var(--org-pd-wash);
  --tl-wash-solid: var(--org-pd-solid);
}

.work-tl__group[data-group="alumni"] {
  --tl-accent: var(--org-alumni);
  --tl-accent-soft: var(--org-alumni-soft);
  --tl-accent-wash: var(--org-alumni-wash);
  --tl-wash-solid: var(--org-alumni-solid);
}

.work-tl__group[data-group="transferred"] {
  --tl-accent: var(--org-transferred);
  --tl-accent-soft: var(--org-transferred-soft);
  --tl-accent-wash: var(--org-transferred-wash);
  --tl-wash-solid: var(--org-transferred-solid);
}

/* The rail. One element for the whole column, faded at both ends so it
   starts and stops rather than running into the panel's edges. */
.work-tl::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  right: var(--tl-rail);
  transform: translateX(50%);
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) 0,
    var(--tl-line) var(--tl-fade-top),
    var(--tl-line) calc(100% - var(--tl-fade)),
    rgba(0, 0, 0, 0) 100%
  );
  pointer-events: none;
}

.work-tl__group {
  display: flex;
  flex-direction: column;
}

.work-tl__group + .work-tl__group {
  margin-top: 18px;
}

.work-tl__row {
  position: relative;
  flex-shrink: 0;
  padding-bottom: 2px;
}

/* ── Rail furniture ───────────────────────────────────────────── */
/* Marker — centred on the rail, level with the line that holds it */
.work-tl__mark {
  position: absolute;
  top: 50%;
  right: calc(-1 * (var(--tl-mark-inset) + var(--tl-reach)));
  transform: translate(50%, -50%);
  width: var(--tl-dot);
  height: var(--tl-dot);
  border-radius: 50%;
  background: var(--tl-accent);
  /* A ring of whatever is behind the mark, so the rail is held off it and
     each stop reads as its own element — without a white stroke appearing
     the moment a hovered entry puts a tint there. --tl-halo becomes the
     band's own colour on hover, below. */
  box-shadow: 0 0 0 3px var(--tl-halo, #ffffff);
  transition: transform 260ms cubic-bezier(0.34, 1.4, 0.64, 1),
              box-shadow 200ms ease;
  pointer-events: none;
}

/* The company marker opens a run, so it is a bar rather than a dot: it runs
   the height of the name block beside it — the role above, the company and
   its dates below — and stands for the whole header the way a dot stands
   for a single entry. */
.work-tl__mark--org {
  top: 0;
  bottom: 0;
  height: auto;
  /* --tl-dot from the base rule: the bar is a dot stretched down the block,
     so it has to be exactly as wide as the dots it shares the rail with. */
  border-radius: 100px;
  transform: translateX(50%);
  background: var(--tl-accent);
}

/* ── Company ──────────────────────────────────────────────────── */
.work-tl__org {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: var(--tl-org-pad-top) 12px 12px;
}

/* The rail runs down into the header's marker and stops there. The backing
   hides the line across the rest of the header, so below it the line reads
   as coming back out from underneath — the run above stays strung through
   to the run below, while the header never appears to feed into its own
   work. Painted after the backing at the same depth, so it lands on it. */
.work-tl__head::after {
  content: '';
  position: absolute;
  z-index: -1;
  top: calc(-1 * var(--tl-stick-top));
  height: calc(var(--tl-stick-top) + var(--tl-org-pad-top));
  right: calc(-1 * var(--tl-reach));
  transform: translateX(50%);
  width: 2px;
  border-radius: 2px;
  background: var(--tl-line);
}

.work-tl__logo-link {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

/* Sized to stand a little taller than the role and company stacked beside
   it, so the mark anchors the pair rather than sitting between them. */
.work-tl__logo {
  width: 52px;
  height: 50px;
  object-fit: contain;
  display: block;
}

.work-tl__logo--cover { object-fit: cover; border-radius: 4px; }

/* Holds the marker, so it is the positioning context and carries the reach
   out to the rail — the company block's own right-hand padding. */
.work-tl__org-text {
  --tl-mark-inset: 12px;
  position: relative;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

/* The role is the heading — what the work was — and carries the marker, so
   the dot sits level with it. Where it was and when share the line beneath
   in one weight and size, as a single subtitle rather than two ranks. */
.work-tl__org-role {
  display: block;
  font-family: var(--font-accent);
  font-size: var(--scale-4);   /* 20.74px */
  font-weight: 700;
  line-height: 1.15;
  color: var(--color-text-dark);
  min-width: 0;
}

.work-tl__org-line {
  display: flex;
  align-items: baseline;
  gap: 10px;
  min-width: 0;
  font-family: var(--font-primary);
  font-size: var(--scale-2);   /* 14.4px */
  font-weight: 600;
  line-height: 1.3;
  color: var(--color-text-secondary);
}

.work-tl__org-name {
  min-width: 0;
}

.work-tl__org-dates {
  margin-left: auto;
  white-space: nowrap;
  flex-shrink: 0;
}

/* ── Supporting line ──────────────────────────────────────────── */
/* No marker: it belongs to the company above it rather than being a stop
   of its own, so it just runs on under the header. */
.work-tl__note {
  display: flex;
  flex-direction: column;
  font-family: var(--font-primary);
  font-size: var(--scale-2);   /* 14.4px */
  font-weight: 500;
  line-height: 1.5;
  color: var(--color-text-secondary);
  padding: 0 12px;
  margin: 0;
}

/* One fact per line — a major and its minors are two statements, not a
   single run-on split by a middot. */
.work-tl__note-line {
  display: block;
}

/* Hover band
   -------------------------------------------------------------
   An entry's highlight is painted by the row, not by the entry: the row is
   the only thing wide enough to reach the rail. It runs out past the line
   and sits behind everything on a negative z-index, so the line and the dot
   are *inside* the highlight rather than beside it, and the whole nav reads
   as one band under the pointer.

   Both ends run flush with the panel, which puts the same 14px of white
   beside the band that .work-surface's padding puts beside the slideshow —
   the band, the picture and the card edge all share one gutter. */
.work-tl__row {
  position: relative;
}

.work-tl__row::before {
  content: '';
  position: absolute;
  z-index: -1;
  top: 0;
  bottom: 0;
  /* back out through .work-tl's own padding on both sides */
  left: -2px;
  right: calc(-1 * var(--tl-gutter));
  border-radius: 14px;
  background: transparent;
  transition: background 200ms ease;
  pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {
  .work-tl__row:has(.work-item:hover)::before {
    background: var(--tl-accent-wash);
  }
}

/* ── Company header ──────────────────────────────────────────── */
/* Pinned while its own run is on screen, then pushed off by the next
   company's header — sticky bounded by the group, which is exactly the
   behaviour wanted and needs no script. The z-index lifts it over the
   entries passing underneath; being positioned with a z-index also makes it
   a stacking context, which is what lets its backing sit at -1 and still
   cover those entries. */
.work-tl__head {
  /* Pinned a little below the panel's edge rather than hard against it —
     flush, it read as pressed into the top. The backing reaches back up
     through this offset, so nothing shows in the gap above it. */
  --tl-stick-top: 14px;
  /* .work-tl__org's own top padding — how far the marker sits below the
     header's top edge, and so where the rail has to stop. */
  --tl-org-pad-top: 14px;
  position: sticky;
  top: var(--tl-stick-top);
  z-index: 2;
  padding-bottom: 18px;
  margin-bottom: 16px;
}

/* The backing. Opaque, or entries would read through the pinned header, and
   carried out past the rail the same way the hover band is, so a dot cannot
   slide out from under it in the gutter. Its bottom corners carry the same
   radius the hover band uses, so a header and a hovered entry are the same
   shape sitting on the same column. */
.work-tl__head::before {
  content: '';
  position: absolute;
  z-index: -1;
  top: calc(-1 * var(--tl-stick-top));
  bottom: 0;
  left: -2px;
  right: calc(2px - var(--tl-gutter));
  background: #ffffff;
  border-radius: 0 0 14px 14px;
}

/* Cast onto the work below instead of a rule drawn between them: the header
   is a surface the entries pass under, so the separation is its shadow. As
   with the rule it replaced, only a header with work beneath it casts — a
   company with none has nothing to separate from. */
.work-tl__group:has(.work-tl__row) .work-tl__head::before {
  /* Spread pulled in further than the blur reaches, so the cast stays under
     the header instead of wrapping its right edge and running down beside
     the rail: at -9px inset against an 8px blur the sides fall short of the
     backing's own edges, leaving only the downward throw visible. */
  box-shadow: 0 7px 8px -9px rgba(0, 0, 0, 0.42);
}

/* ── Case study ───────────────────────────────────────────────── */
/* No box. Each entry is held by the rail, its own spacing and the weight
   of its title, and shares the one text edge the company header and its
   note use — so the column reads as a single piece of writing rather than
   a stack of tiles. The surface only appears under the pointer, in the
   company's own colour. */
.work-tl .work-item {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 12px 12px 14px;
  border-radius: 14px;
  background: transparent;
  color: var(--color-text-primary);
  text-decoration: none;
  transition: background 200ms ease;
}

@media (hover: hover) and (pointer: fine) {
  /* No lift on hover: the marker rides inside the entry, so moving it
     would take its dot off the rail. The wash is painted by the row, which
     is the only thing wide enough to reach the rail.  */

  /* The card's dot answers the hover, so the pairing is unmistakable, and
     its halo becomes the band it now sits on rather than staying white. */
  .work-tl__row:has(.work-item:hover) {
    --tl-halo: var(--tl-wash-solid);
  }

  .work-tl .work-item:hover .work-tl__mark {
    transform: translate(50%, -50%) scale(1.3);
  }

  .work-tl .work-item:hover .work-item__when { color: var(--tl-accent); }
}

/* Holds the marker and the date, so both sit level with the title */
.work-item__head {
  /* the entry's own right-hand padding — the same edge the header uses */
  --tl-mark-inset: 12px;
  position: relative;
  display: flex;
  align-items: center;
  gap: 9px;
  min-height: 24px;
}

.work-item__title {
  font-family: var(--font-primary);
  font-size: var(--scale-3);   /* 17.28px */
  font-weight: 700;
  line-height: 1.2;
  color: var(--color-text-dark);
  min-width: 0;
}

/* Recommended entries are flagged by the title taking the company's colour
   rather than by a chip beside it — nothing is added to the row, and the
   signal survives a narrow column, which the chip did not.

   The word itself stays, read out but not drawn: colour alone carries no
   meaning to a screen reader, and it is also what marks the entry for the
   rule below, so the flag lives in one place. */
.work-item__featured {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.work-tl .work-item:has(.work-item__featured) .work-item__title {
  color: var(--tl-accent);
}

.work-item__lock { flex-shrink: 0; color: var(--color-text-muted); }

/* The slide this entry would show in the slideshow, carried inside the
   entry itself. Hidden here and shown on mobile, where the slideshow is
   not on screen to be handed anything — display:none keeps the lazy
   images from being fetched at all on desktop. */
.work-item__shot { display: none; }

/* Last in the title row, so the card's own date is level with its title —
   and with the marker, which hangs off the same row. */
.work-item__when {
  margin-left: auto;
  padding-left: 8px;
  font-family: var(--font-primary);
  /* Matches the company's own dates in the header above it, so the two
     read as the same field at two levels rather than two fields. */
  font-size: var(--scale-2);   /* 14.4px */
  font-weight: 600;
  color: var(--color-text-muted);
  white-space: nowrap;
  flex-shrink: 0;
}

.work-item__desc {
  font-family: var(--font-primary);
  font-size: var(--scale-2);   /* 14.4px */
  font-weight: 500;
  line-height: 1.45;
  color: var(--color-text-secondary);
}

.work-item__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}

.work-item__tag {
  font-family: var(--font-primary);
  font-size: 11px;
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-surface);
  border-radius: var(--border-radius);
  padding: 3px 8px;
  white-space: nowrap;
}

/* Trailing room is .work-tl's own bottom padding, matched to its top, and
   not a spacer after it. The rail is drawn across .work-tl, so anything
   added outside it only lengthens the gap at the foot — which is why the
   line used to stop far short there while reaching the head. Equal padding
   means the line ends the same distance from both edges of the panel. */

/* -------------------------------------------------------------
   Work surface — one card holding the slideshow and the nav
   -------------------------------------------------------------
   On home the slideshow fills it; moving to work, the slideshow gives up
   width and the nav appears beside it on the same surface, so the panel is
   revealed from within the section rather than arriving as a second card.
   ------------------------------------------------------------- */
.work-surface {
  --work-surface-pad: 14px;
  /* A container, so the nav inside can be sized against this surface rather
     than against the panel it sits in — the panel's width is the thing being
     animated, and the nav has to stay still while it moves. */
  container-type: inline-size;
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  gap: 0;
  background: #ffffff;
  border-radius: var(--border-radius-xl);
  box-shadow: var(--shadow-card);
  padding: var(--work-surface-pad);
  overflow: hidden;
}

.page[data-state="work"] .work-surface { gap: 14px; }

.page.is-animating .work-surface { transition: gap 600ms cubic-bezier(0.4, 0, 0.2, 1); }

/* The frame carries the clip-path, so the bites show the surface behind.
   Its drop-shadow is cast from everything it holds — the clipped picture and
   the dots pill sitting in the notch — so the two cannot be given different
   edges by accident. The clip is what makes this work: the shadow follows
   the real shape, bites included, which a box-shadow could not. */
.slideshow-frame {
  flex: 1;
  min-width: 0;
  position: relative;
  filter: drop-shadow(var(--shadow-frame-cast));
  /* Deliberately no background of its own: an opaque frame would be the
     silhouette the filter casts from, tracing a plain rounded rectangle and
     swallowing both the notch and the pill. The surface behind is already
     white, so the frame has nothing to cover. */
}

.slideshow {
  width: 100%;
  height: 100%;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* White, so a slide that does not fill the frame reads as the mockup's
     own background rather than as a grey box behind it. */
  background-color: #ffffff;
  border-radius: var(--slideshow-radius);
  overflow: hidden;
}


/* ── Reveal chevron ───────────────────────────────────────────── */
/* Sits in the bite on the right edge once the intro card is dismissed */
.slideshow__reveal {
  position: absolute;
  right: 0;
  top: 50%;
  z-index: 20;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: none;
  background: #ffffff;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.14);
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(0, 0, 0, 0.40);
  cursor: pointer;
  padding: 0;
  opacity: 0;
  transform: translateY(-50%) translateX(10px) scale(0.75);
  pointer-events: none;
  transition: opacity 260ms ease,
              transform 420ms cubic-bezier(0.32, 0.72, 0, 1),
              color 150ms ease;
}

.slideshow__reveal.is-visible {
  opacity: 1;
  transform: translateY(-50%) translateX(0) scale(1);
  pointer-events: auto;
}

.slideshow__reveal:hover { color: rgba(0, 0, 0, 0.75); }
.slideshow__reveal svg { position: relative; left: -1px; }

.page[data-state="work"] .slideshow__reveal { display: none; }

@media (prefers-reduced-motion: reduce) {
  .slideshow__reveal { transition: opacity 260ms ease; transform: translateY(-50%); }
  .slideshow__reveal.is-visible { transform: translateY(-50%); }
}
