/* =========================================================
   PANTRY work section
   One case, Pantry itself, on the page's own grid: the vertical page lines
   run straight through, and the horizontal lines are the section-edge
   hairline with its plus marks, one per row. Rectangles span whole cells.
   The case opens in place below the card, on the 12-column grid.
   Motion lives in scripts/work.js. Values come from tokens.css; the ones
   below only apply to this section.
   ========================================================= */

.work {
  /* Cards grow past their cell while they reveal; never let that widen the
     page on phones. */
  overflow-x: clip;
  /* Space above the label and after the section. */
  --work-pad-top: 25svh;
  --work-pad-bottom: 30svh;
  /* One grid row, as a share of one bay's width. Rows grow if a caption
     needs more. */
  --work-row-ratio: 0.7;
  /* One bay, a satellite on mobile: share of the bay it takes, hung
     from one line. */
  --work-sat-share: 62%;
  /* Reveal: image scale at the start (read by JS). */
  --work-reveal-scale: 1.15;
  /* Caption lines rise from below their mask; the mask leaves this much
     room around a line so nothing (the button border, a focus ring) is cut. */
  --work-line-slack: var(--space-8);
  /* Hover: cover to the logo animation. */
  --work-hover-duration: var(--duration);
  --work-hover-scale: 1.04;
  /* Red marker: twice the stroke of a hairline, the page plus size. */
  --work-marker-stroke: calc(var(--line-width) * 2);
  --work-stamp-duration: calc(var(--duration) * 1.5);
  --work-stamp-scale: 1.8;
  /* Reduced motion fade. */
  --work-fade: calc(var(--duration) * 2);

  /* Lettering: the PANTRY row, as a share of its frame's width, and the
     space between two letters. */
  --work-word-width: 64%;
  --work-word-gap: 0%;
  /* The logo animation (cover hover, motion pack): one loop, the step
     between two letters, and how far above its place a letter starts. */
  --work-sting-duration: calc(var(--duration) * 9);
  --work-sting-stagger: calc(var(--duration) * 0.2);
  --work-sting-drop: -140%;

  /* Case: space before each part, after its rule, and from its words to
     its visual. */
  --work-part-gap: var(--space-128);
  --work-part-pad: var(--space-48);
  --work-visual-gap: var(--space-64);
  /* Parts rise into place as they come on screen, one after another. */
  --work-rise: var(--space-32);
  --work-rise-duration: calc(var(--duration) * 2);
  --work-rise-stagger: calc(var(--duration) * 0.2);

  /* Logo: the mixed letters turn to clay, one after another. */
  --work-swap-duration: var(--hero-item-swap-duration);
  --work-swap-stagger: calc(var(--duration) * 0.2);
  --work-swap-hop: -6%;

  /* Inputs: things you like, how far each one leans. */
  --work-like-tilt: 6deg;

  /* Workflow graph (graph px, the stage scales): the canvas dot grid, a
     port, the inner padding of a node, the wire stroke, how fast an
     active wire flows, and the height of an output preview. */
  --work-graph-dot: var(--space-24);
  --work-gport: calc(var(--space-8) + var(--line-width));
  --work-gpad: var(--space-12);
  --work-gwire: calc(var(--line-width) * 1.5);
  --work-gflow: calc(var(--duration) * 1.5);
  --work-gpreview: var(--space-48);

  /* Inside a frame, text keeps the cell padding, so it lines up with the
     words under the frame. Headline and type sample sizes are shares of
     the frame's width. */
  --work-frame-pad: var(--cell-pad);
  --work-post-size: 12.5cqi;
  --work-sample-size: 24cqi;

  padding: var(--work-pad-top) 0 var(--work-pad-bottom);
  overflow-x: clip;
}

/* ---------- Grid ----------
   One column per bay, no gaps: cell edges are the page lines. The body is
   a size container, so a row can be measured from the bay width. Rows are
   set by JS (count) and close with a zero-height row for the last line. */

.work-body {
  container-type: inline-size;
  margin-top: var(--space-96);
}

.work-grid {
  --work-row: calc(100cqi / var(--bays) * var(--work-row-ratio));
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--bays), minmax(0, 1fr));
  gap: 0;
}

/* The project lays its parts straight onto the grid. */
.work-project {
  display: contents;
}

/* Horizontal line at the top of a row: the same hairline as a section
   edge (.has-lines), across the whole page, with the same plus marks. */
.work-rule {
  position: relative;
  grid-column: 1 / -1;
  align-self: start;
  height: 0;
  pointer-events: none;
}

.work-rule::before {
  content: "";
  position: absolute;
  z-index: -2;
  top: 0;
  left: calc(50% - 50vw);
  width: 100vw;
  height: var(--line-width);
  background: var(--color-guide);
}

/* ---------- Rectangles ----------
   Each spans whole cells. Its border sits on the lines: the right and
   bottom edges reach one line width over, onto the next line, except in
   the last column, whose line sits inside the container edge. */

.work-rect {
  position: relative;
  display: block;
  margin-right: calc(var(--line-width) * -1);
  margin-bottom: calc(var(--line-width) * -1);
  will-change: transform;
}

.work-rect.is-last-col {
  margin-right: 0;
}

/* One bay: the satellite hangs from the left or right line. */
.work-rect.is-start,
.work-rect.is-end {
  width: var(--work-sat-share);
}

.work-rect.is-start {
  justify-self: start;
}

.work-rect.is-end {
  justify-self: end;
}

.work-clip {
  position: absolute;
  inset: 0;
  overflow: hidden;
  clip-path: inset(0 0 100% 0);
}

.work-media {
  position: absolute;
  inset: 0;
  display: block;
  transform: scale(var(--work-reveal-scale));
}

.work-cover,
.work-video {
  position: absolute;
  inset: 0;
  display: block;
}

/* Cover: the clay lettering on the light ground. */
.work-cover--word {
  display: grid;
  place-items: center;
  background: var(--color-surface-subtle);
}

/* Satellite: the mark, one clay P on ink. Its edge stays visible when the
   cover beside it turns ink on hover. */
.work-mark {
  display: grid;
  place-items: center;
  background: var(--color-ink);
  box-shadow: inset 0 0 0 var(--line-width) var(--color-guide-on-ink);
}

.work-mark-img {
  width: 46%;
  height: auto;
}

/* ---------- Lettering ----------
   PANTRY in a row, every letter in an equal square box, standing on the
   box's floor. Used by the cover, the logo, the brand kit and the logo
   animation. */

.work-word {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  align-items: end;
  column-gap: var(--work-word-gap);
  width: var(--work-word-width);
}

.work-letter {
  position: relative;
  display: block;
  aspect-ratio: 1;
}

.work-letter img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
  user-select: none;
  -webkit-user-drag: none;
}

/* ---------- Lead: cover, then the logo animation on hover ---------- */

.work-lead {
  color: inherit;
  cursor: pointer;
}

@media (hover: hover) and (pointer: fine) {
  .work-lead {
    cursor: none;
  }
}

.work-video {
  clip-path: inset(0 100% 0 0);
  transform: scale(var(--work-hover-scale));
  transition:
    clip-path var(--work-hover-duration) var(--ease),
    transform var(--work-hover-duration) var(--ease);
}

.work-lead.is-playing .work-video {
  clip-path: inset(0);
  transform: none;
}

/* ---------- Logo animation ----------
   On ink: the clay letters drop onto their line one after another with
   the site's spring, hold, then clear for the next loop. A red bar counts
   the loop. Runs while it or its cover has .is-playing. */

.work-sting {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--color-ink);
  overflow: hidden;
}

.work-sting .work-letter {
  opacity: 0;
  transform: translate3d(0, var(--work-sting-drop), 0);
}

.work-lead.is-playing .work-sting .work-letter,
.work-sting.is-playing .work-letter {
  animation: work-drop var(--work-sting-duration) infinite;
  animation-delay: calc(var(--i) * var(--work-sting-stagger));
}

@keyframes work-drop {
  0% {
    opacity: 0;
    transform: translate3d(0, var(--work-sting-drop), 0);
    animation-timing-function: var(--hero-item-ease);
  }
  16% {
    opacity: 1;
    transform: none;
  }
  80% {
    opacity: 1;
    transform: none;
    animation-timing-function: var(--ease);
  }
  92%,
  100% {
    opacity: 0;
    transform: none;
  }
}

.work-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--work-marker-stroke);
  background: var(--color-red-signal);
  transform: scaleX(0);
  transform-origin: left center;
}

.work-lead.is-playing .work-progress,
.work-sting.is-playing .work-progress {
  animation: work-progress var(--work-sting-duration) linear infinite;
}

@keyframes work-progress {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

/* ---------- Caption ----------
   In its own cell, clear of the lines by the text cell padding. */

.work-caption {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-8);
  min-width: 0;
  padding: var(--cell-pad);
}

.work-caption .item-title {
  margin-top: var(--space-4);
}

/* .btn .btn--secondary .btn--small from components.css. */
.work-caption .btn {
  margin-top: var(--space-16);
}

/* Each line rises out of a mask. The mask is a clip with slack on every
   side, so a line is hidden only while it sits below, and once the
   caption is shown the clip is gone. */
.work-line {
  display: block;
  max-width: 100%;
  clip-path: inset(calc(var(--work-line-slack) * -1));
}

.work-caption.is-shown .work-line {
  clip-path: none;
}

.work-line-inner {
  display: block;
  transform: translate3d(0, calc(100% + var(--work-line-slack)), 0);
  will-change: transform;
}

/* ---------- Red marker ----------
   The page plus mark in signal red, a little heavier, on the cover's
   corner. It stamps the corner once the card is in. */

.work-marker {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  pointer-events: none;
  will-change: transform;
}

.work-marker-plus {
  position: relative;
  display: block;
  width: var(--plus-size);
  height: var(--plus-size);
  background:
    linear-gradient(var(--color-red-signal), var(--color-red-signal)) center / 100% var(--work-marker-stroke) no-repeat,
    linear-gradient(var(--color-red-signal), var(--color-red-signal)) center / var(--work-marker-stroke) 100% no-repeat;
}

.work-marker-plus::after {
  content: "";
  position: absolute;
  inset: 0;
  border: var(--line-width) solid var(--color-red-signal);
  opacity: 0;
}

.work-marker.is-stamped .work-marker-plus {
  animation: work-stamp-press var(--work-stamp-duration) var(--ease);
}

.work-marker.is-stamped .work-marker-plus::after {
  animation: work-stamp-ring var(--work-stamp-duration) var(--ease);
}

@keyframes work-stamp-press {
  0% { transform: scale(1); }
  30% { transform: scale(0.6); }
  100% { transform: scale(1); }
}

@keyframes work-stamp-ring {
  0% { opacity: 1; transform: scale(0.4); }
  100% { opacity: 0; transform: scale(var(--work-stamp-scale)); }
}

/* ---------- Cursor tag ---------- */

.work-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 20;
  pointer-events: none;
  will-change: transform;
}

.work-cursor-text {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  padding: var(--space-4) var(--space-8);
  background: var(--color-ink);
  color: var(--color-canvas);
  white-space: nowrap;
  opacity: 0;
  transform: translate(var(--space-12), var(--space-24));
  transition:
    opacity var(--shape-label-duration) var(--ease),
    transform var(--shape-label-duration) var(--ease);
}

.work-cursor.is-visible .work-cursor-text {
  opacity: 1;
  transform: translate(var(--space-12), var(--space-12));
}

/* The only blue on the page. */
.work-cursor-dot {
  width: calc(var(--space-4) + var(--line-width) * 2);
  height: calc(var(--space-4) + var(--line-width) * 2);
  background: var(--color-accent-signal);
}

@media (hover: none), (pointer: coarse) {
  .work-cursor {
    display: none;
  }
}

/* =========================================================
   The case, opened in place
   ========================================================= */

/* Layout classes, the grid.css pattern: span per breakpoint, plus how
   many of those columns its words may take (one bay). */
.l-work-wide {
  --d: 6;
  --t: var(--grid-columns-tablet);
  --m: var(--grid-columns-mobile);
  --work-text-cols: 3;
}

.l-work-spec,
.l-work-pack {
  --d: 3;
  --t: 4;
  --m: 2;
  --work-text-cols: 3;
}

/* Phones: color and type take the full width, so their names never
   crowd. */
.l-work-spec {
  --m: var(--grid-columns-mobile);
}

@media (max-width: 1023px) {
  .l-work-wide,
  .l-work-spec,
  .l-work-pack {
    --work-text-cols: 4;
  }
}

@media (max-width: 639px) {
  .l-work-wide,
  .l-work-spec {
    --work-text-cols: 4;
  }

  .l-work-pack {
    --work-text-cols: 2;
  }
}

/* ---------- Parts ----------
   Each part: a rule across the page, the label, one headline, one line in
   one bay, then its visual. */

.grid-12.work-part {
  row-gap: 0;
  margin-top: var(--work-part-gap);
}

.work-part-label {
  padding-top: var(--work-part-pad);
}

.work-visual {
  margin-top: var(--work-visual-gap);
}

.grid-12.work-figs {
  align-items: start;
  row-gap: var(--space-48);
}

/* Rise in, one after another along a row. */
.work-reveal {
  opacity: 0;
  transform: translate3d(0, var(--work-rise), 0);
  transition:
    opacity var(--work-rise-duration) var(--ease),
    transform var(--work-rise-duration) var(--ease);
  transition-delay: calc(var(--i, 0) * var(--work-rise-stagger));
}

.work-reveal.is-in {
  opacity: 1;
  transform: none;
}

/* ---------- Frames ----------
   Media: a frame runs from line to line, and its edges are hairlines on
   the lines, so frames side by side share one line. The right edge reaches
   one line width over, except where the frame ends the row. */

.work-fig {
  min-width: 0;
}

.work-frame {
  position: relative;
  aspect-ratio: var(--work-frame-ratio, 1);
  margin-right: calc(var(--line-width) * -1);
  overflow: hidden;
  container-type: inline-size;
  background: var(--color-surface-subtle);
  box-shadow: inset 0 0 0 var(--line-width) var(--color-guide);
}

.work-figs > :last-child .work-frame,
.work-figs--packs > :nth-child(4n) .work-frame {
  margin-right: 0;
}

@media (max-width: 1023px) {
  .work-figs--packs > :nth-child(2n) .work-frame {
    margin-right: 0;
  }
}

/* A frame's words (and the words of a wide block): one bay, clear of the
   lines. Widths are whole columns of the block's own span. */
.work-fig-text,
.work-likes > .cell {
  width: calc(100% * var(--work-text-cols) / var(--d));
}

@media (max-width: 1023px) {
  .work-fig-text,
  .work-likes > .cell {
    width: calc(100% * var(--work-text-cols) / var(--t));
  }
}

@media (max-width: 639px) {
  .work-fig-text,
  .work-likes > .cell {
    width: calc(100% * var(--work-text-cols) / var(--m));
  }
}

.work-fig-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  padding-top: var(--space-16);
}

/* Small mono note in a frame's top-left corner. */
.work-frame-caption {
  position: absolute;
  z-index: 1;
  top: var(--work-frame-pad);
  left: var(--work-frame-pad);
}

/* ---------- 1. What you give ----------
   Plain notes, set in the mono: the raw material, before any design. */

.work-input {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
}

.work-input-text {
  font-family: var(--font-mono);
  font-size: var(--text-lead-size);
  font-weight: var(--text-body-weight);
  line-height: var(--text-lead-lh);
  color: var(--color-ink);
}

/* Things you like: the five mixed letters, a loose pile. */
.work-likes-row {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  align-items: end;
  padding-inline: var(--cell-pad);
}

.work-like {
  display: block;
  aspect-ratio: 1;
}

.work-like img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
}

.work-like:nth-child(odd) img {
  transform: rotate(calc(var(--work-like-tilt) * -1));
}

.work-like:nth-child(even) img {
  transform: rotate(var(--work-like-tilt)) translateY(calc(var(--space-8) * -1));
}

/* ---------- 2. The identity ---------- */

.l-work-wide .work-frame {
  --work-frame-ratio: 2 / 1;
}

@media (max-width: 639px) {
  .l-work-spec .work-frame {
    margin-right: 0;
  }
}

.work-frame--logo {
  display: grid;
  place-items: center;
}

/* Each letter: its own material under the clay. .is-clay (JS, once the
   logo is in view) turns them one after another, with a small hop. */
.work-logo-word .work-letter img {
  transition: opacity var(--work-swap-duration) var(--ease);
  transition-delay: calc(var(--i) * var(--work-swap-stagger));
}

.work-logo-word .work-letter-clay,
.work-frame--logo.is-clay .work-letter-raw {
  opacity: 0;
}

.work-frame--logo.is-clay .work-letter-clay {
  opacity: 1;
}

.work-frame--logo.is-clay .work-letter {
  animation: work-hop var(--work-swap-duration) var(--hero-item-ease) both;
  animation-delay: calc(var(--i) * var(--work-swap-stagger));
}

@keyframes work-hop {
  0% { transform: none; }
  40% { transform: translate3d(0, var(--work-swap-hop), 0); }
  100% { transform: none; }
}

/* Before / After: one shows at a time. */
.work-logo-state > span {
  transition: opacity var(--work-swap-duration) var(--ease);
}

.work-logo-after {
  position: absolute;
  left: 0;
  top: 0;
  opacity: 0;
}

.work-frame--logo.is-clay .work-logo-before {
  opacity: 0;
}

.work-frame--logo.is-clay .work-logo-after {
  opacity: 1;
}

/* Color: the three swatches stacked, each in the share it gets. */
.work-frame--color {
  display: flex;
  flex-direction: column;
  background: var(--color-canvas);
}

.work-swatch {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--space-8);
  padding: var(--space-16) var(--work-frame-pad);
}

.work-swatch .label,
.work-swatch .caption {
  color: inherit;
}

.work-swatch--0 {
  flex: 6;
  background: var(--color-red-signal);
  color: var(--color-ink);
}

.work-swatch--1 {
  flex: 3;
  background: var(--color-ink);
  color: var(--color-canvas);
}

.work-swatch--2 {
  flex: 2;
  color: var(--color-text-secondary);
}

/* Type: the two faces, each with its sample. */
.work-frame--type {
  display: grid;
  grid-template-rows: 1fr 1fr;
}

.work-face {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: var(--space-4);
  padding: var(--space-16) var(--work-frame-pad);
}

.work-face + .work-face {
  box-shadow: inset 0 var(--line-width) 0 var(--color-guide);
}

.work-face-sample {
  margin-bottom: auto;
  font-size: var(--work-sample-size);
  line-height: 1;
  color: var(--color-ink);
}

.work-face--0 {
  font-family: var(--font-sans);
  font-weight: var(--text-display-weight);
  letter-spacing: var(--text-display-ls);
}

.work-face--1 {
  font-family: var(--font-mono);
  font-weight: var(--text-label-weight);
}

/* ---------- 3. The workflow ----------
   A node editor (scripts/work-graph.js): a toolbar, then the canvas. The
   frame runs line to line; toolbar and legend text keep the cell padding.
   Inside, the stage is in graph px and scaled to fit by JS. */

.work-graph-frame {
  background: var(--color-canvas);
  box-shadow: inset 0 0 0 var(--line-width) var(--color-guide);
}

.work-graph-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-16);
  padding: var(--space-12) var(--cell-pad);
}

/* .btn .btn--secondary .btn--small from components.css, kept on one line. */
.work-graph-bar .btn {
  flex: none;
  white-space: nowrap;
}

.work-graph-name {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-8) var(--space-24);
  min-width: 0;
}

/* Status: a small square, red while the job runs, ink once it is done. */
.work-graph-status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
}

.work-graph-status::before {
  content: "";
  width: var(--space-8);
  height: var(--space-8);
  box-shadow: inset 0 0 0 var(--line-width) var(--color-rule);
}

.work-graph[data-state="running"] .work-graph-status::before,
.work-graph[data-state="redo"] .work-graph-status::before {
  background: var(--color-red-signal);
  box-shadow: none;
}

.work-graph[data-state="done"] .work-graph-status::before {
  background: var(--color-ink);
  box-shadow: none;
}

/* The canvas: a dot grid. It scrolls sideways when the stage is wider. */
.work-gcanvas {
  position: relative;
  margin: 0 var(--line-width) var(--line-width);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  background:
    radial-gradient(circle, var(--color-rule) var(--line-width), transparent calc(var(--line-width) * 1.5)) 0 0 / var(--work-graph-dot) var(--work-graph-dot),
    var(--color-surface-subtle);
}

.work-gsizer {
  position: relative;
}

.work-gstage {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
}

.work-gwires {
  position: absolute;
  top: 0;
  left: 0;
  overflow: visible;
  pointer-events: none;
}

/* A node: header, slot rows, one widget. Placed by JS (transform). */
.work-gnode {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  background: var(--color-canvas);
  box-shadow: 0 0 0 var(--line-width) var(--color-rule);
  transition: box-shadow var(--shape-label-duration) var(--ease);
}

.work-gnode.is-running,
.work-gnode.is-dragging {
  box-shadow: 0 0 0 var(--work-marker-stroke) var(--color-ink);
}

.work-gnode-head {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-8);
  padding: var(--space-8) var(--work-gpad);
  background: var(--color-surface-subtle);
  cursor: grab;
  touch-action: none;
  user-select: none;
}

.work-gnode.is-dragging .work-gnode-head {
  cursor: grabbing;
}

.work-gnode-title {
  font-size: var(--text-nav-size);
  font-weight: var(--text-item-weight);
  line-height: var(--text-nav-lh);
  letter-spacing: var(--text-lead-ls);
}

/* Progress, along the bottom of the header (JS fills it). */
.work-gnode-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--work-marker-stroke);
  background: var(--color-red-signal);
  transform: scaleX(0);
  transform-origin: left center;
}

/* A person: the one red node. */
.work-gnode.is-human .work-gnode-head {
  background: var(--color-red-signal);
}

.work-gnode.is-human .work-gnode-tag {
  color: var(--color-ink);
}

.work-gnode.is-human .work-gnode-bar {
  background: var(--color-ink);
}

.work-gnode-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-8) 0 var(--work-gpad);
}

/* Slot rows: inputs on the left edge, outputs on the right. */
.work-gslot {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-8);
  min-height: var(--space-24);
  padding-inline: var(--work-gpad);
}

.work-gslot-in,
.work-gslot-out {
  display: flex;
  align-items: center;
}

.work-gslot-out {
  margin-left: auto;
}

.work-gport {
  position: absolute;
  top: calc(50% - var(--work-gport) / 2);
  width: var(--work-gport);
  height: var(--work-gport);
  border-radius: 50%;
  background: var(--color-canvas);
  box-shadow: inset 0 0 0 var(--work-gwire) var(--color-text-secondary);
}

.work-gslot-in .work-gport {
  left: calc(var(--work-gport) / -2);
}

.work-gslot-out .work-gport {
  right: calc(var(--work-gport) / -2);
}

.work-gport.is-linked {
  background: var(--color-ink);
  box-shadow: none;
}

/* Widgets. */
.work-gwidget {
  margin: var(--space-4) var(--work-gpad) 0;
}

.work-gfield,
.work-gcombo,
.work-gchip {
  font-family: var(--font-mono);
  font-size: var(--text-caption-size);
  line-height: var(--text-caption-lh);
}

.work-gfield {
  display: block;
  padding: var(--space-8);
  background: var(--color-surface-subtle);
  box-shadow: inset 0 0 0 var(--line-width) var(--color-guide);
  color: var(--color-ink);
}

.work-gthumbs {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--space-4);
}

.work-gthumb {
  display: block;
  aspect-ratio: 1;
  background: var(--color-surface-subtle);
}

.work-gthumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.work-gstack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* A setting: name left, value right. */
.work-gcombo {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-8);
  padding: var(--space-4) var(--space-8);
  background: var(--color-surface-subtle);
  color: var(--color-ink);
  font-variant-numeric: tabular-nums;
}

.work-gstack .work-gcombo {
  margin: 0;
}

.work-gchoice {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}

.work-gchip {
  padding: var(--space-4) var(--space-8);
  text-align: center;
  white-space: nowrap;
  color: var(--color-text-secondary);
  box-shadow: inset 0 0 0 var(--line-width) var(--color-rule);
  transition:
    background-color var(--shape-label-duration) var(--ease),
    color var(--shape-label-duration) var(--ease);
}

.work-gchip--ok.is-on {
  background: var(--color-ink);
  color: var(--color-canvas);
  box-shadow: none;
}

.work-gchip--redo.is-on {
  background: var(--color-red-signal);
  color: var(--color-ink);
  box-shadow: none;
}

/* Output preview: "Waiting" until the run reaches it, then the piece. */
.work-gpreview {
  position: relative;
  display: grid;
  place-items: center;
  height: var(--work-gpreview);
  overflow: hidden;
  background: var(--color-surface-subtle);
}

.work-gpreview-wait {
  transition: opacity var(--shape-label-duration) var(--ease);
}

.work-gpreview-art {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: scale(0.9);
  transition:
    opacity var(--work-swap-duration) var(--ease),
    transform var(--work-swap-duration) var(--hero-item-ease);
}

.work-gnode.is-ready .work-gpreview-art {
  opacity: 1;
  transform: none;
}

.work-gnode.is-ready .work-gpreview-wait {
  opacity: 0;
}

.work-gpreview--social .work-gpreview-art,
.work-gpreview--motion .work-gpreview-art {
  background: var(--color-ink);
}

.work-gpreview-word {
  --work-word-width: 72%;
}

.work-gpreview-img {
  display: block;
  width: auto;
  height: auto;
  max-width: 90%;
  max-height: 88%;
}

/* Wires: grey at rest; the active ones flow in ink, the way back in red. */
.work-gwire {
  fill: none;
  stroke: var(--color-text-secondary);
  stroke-width: var(--work-gwire);
}

.work-gwire--back {
  stroke: var(--color-red-signal);
  stroke-dasharray: var(--space-4) var(--space-4);
}

.work-gwire-flow {
  fill: none;
  stroke: var(--color-ink);
  stroke-width: calc(var(--work-gwire) * 2);
  stroke-dasharray: var(--space-4) var(--space-12);
  opacity: 0;
  transition: opacity var(--shape-label-duration) var(--ease);
}

.work-gwire-flow--back {
  stroke: var(--color-red-signal);
}

.work-gwire-flow.is-active {
  opacity: 1;
  animation: work-gflow var(--work-gflow) linear infinite;
}

@keyframes work-gflow {
  to { stroke-dashoffset: calc(var(--space-16) * -1); }
}

.work-gwire-label {
  font-family: var(--font-mono);
  font-size: var(--text-label-size);
  letter-spacing: var(--text-label-ls);
  text-transform: uppercase;
  fill: var(--color-red-text);
}

/* Legend under the frame. The swipe hint shows only while it scrolls. */
.work-graph-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-8) var(--space-24);
  padding: var(--space-16) var(--cell-pad) 0;
}

.work-graph-legend .caption {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
}

.work-graph-key {
  display: inline-block;
  width: var(--space-24);
  border-top: calc(var(--work-gwire) * 2) dashed var(--color-ink);
}

.work-graph-key--back {
  border-top-color: var(--color-red-signal);
}

.work-graph-legend .work-graph-hint {
  display: none;
}

.work-graph.is-scrolling .work-graph-legend .work-graph-hint {
  display: inline-flex;
}

/* ---------- 4. What you get ---------- */

.work-figs--packs .work-frame {
  --work-frame-ratio: 4 / 5;
}

.work-frame--kit,
.work-frame--launch {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: var(--work-frame-pad);
}

.work-frame--kit {
  gap: var(--space-24);
  background: var(--color-canvas);
}

.work-kit-word {
  --work-word-width: 100%;
}

.work-kit-swatches {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  height: var(--space-32);
  box-shadow: inset 0 0 0 var(--line-width) var(--color-guide);
}

.work-kit-swatch.work-swatch--0 { background: var(--color-red-signal); }
.work-kit-swatch.work-swatch--1 { background: var(--color-ink); }

.work-kit-type {
  display: flex;
  align-items: baseline;
  gap: var(--space-12);
  font-size: calc(var(--work-sample-size) * 0.66);
  line-height: 1;
}

/* Post and site hero: one bold line, one object. */
.work-post-title {
  position: relative;
  z-index: 1;
  display: block;
  max-width: 9em;
  font-size: var(--work-post-size);
  font-weight: var(--text-display-weight);
  line-height: var(--text-display-lh);
  letter-spacing: var(--text-display-ls);
}

.work-accent {
  color: var(--color-red-signal);
}

.work-frame--social {
  background: var(--color-ink);
  color: var(--color-canvas);
}

.work-frame--social .work-frame-caption,
.work-frame--motion .work-frame-caption {
  color: var(--color-text-on-ink-secondary);
}

.work-frame--social .work-post-title {
  position: absolute;
  top: calc(var(--work-frame-pad) + var(--space-32));
  left: var(--work-frame-pad);
}

.work-post-img {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 72%;
  height: auto;
}

.work-frame--launch .work-post-title {
  font-size: calc(var(--work-post-size) * 0.8);
}

/* A drawing of the site's button, not a button. */
.work-launch-button {
  align-self: flex-start;
  margin-top: var(--space-12);
  padding: var(--space-4) var(--space-8);
  background: var(--color-red-signal);
  font-family: var(--font-mono);
  font-size: var(--text-caption-size);
  line-height: var(--text-caption-lh);
}

.work-launch-img {
  display: block;
  width: 100%;
  height: auto;
  margin-top: auto;
}

/* ---------- End ---------- */

.work-end-title {
  padding-top: var(--work-part-pad);
}

.work-end-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-12);
  align-items: flex-start;
}

/* ---------- Reduced motion ----------
   Same grid, nothing scrubbed: rectangles and captions fade in. The case
   shows as it is; the logo still turns to clay, as a fade. */

.work.is-reduced .work-clip,
.work.is-reduced .work-line {
  clip-path: none;
}

.work.is-reduced .work-media,
.work.is-reduced .work-line-inner {
  transform: none;
}

.work.is-reduced .work-rect,
.work.is-reduced .work-caption {
  opacity: 0;
  transition: opacity var(--work-fade) var(--ease);
}

.work.is-reduced .is-in {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .work-video,
  .work-cursor-text {
    transition: none;
  }

  .work-marker.is-stamped .work-marker-plus,
  .work-marker.is-stamped .work-marker-plus::after,
  .work-frame--logo.is-clay .work-letter {
    animation: none;
  }

  .work-reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }

  /* The logo animation holds still, every letter in place. */
  .work-sting .work-letter {
    opacity: 1;
    transform: none;
    animation: none;
  }

  .work-progress {
    display: none;
  }

  .work-gnode,
  .work-gchip,
  .work-gpreview-art,
  .work-gpreview-wait,
  .work-gwire-flow {
    transition: none;
  }

  .work-gwire-flow.is-active {
    animation: none;
  }
}
