/* lab.css — /lab, the breeding table.
 *
 * The table is the tank's cutout reused: the settings card's field inside the
 * rim, cream ink. Slots carry no chrome beyond an outline when they hold a
 * role, so the sprite is what the eye lands on. Type stays on the fonts'
 * grids (see site.css): Yowza at 26px multiples, Lowza at 8px multiples.
 */

.lab {
  --lab-cta-h: 72px;
  max-width: 880px;
  margin: 0 auto;
  padding: calc(var(--bar-h) + 32px) 16px calc(var(--lab-cta-h) + 64px);
}

.lab :where(p) {
  margin: 0;
}

/* The call to action stays on the bottom of the viewport however far the
 * table scrolls: what the Lab is for on the left, the download on the right.
 * It wears the top bar's treatment — the page's own paper, blurred, with a
 * hairline — so it reads as the page's other bar rather than a panel. */
.lab-cta {
  position: fixed;
  z-index: 35;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  min-height: var(--lab-cta-h);
  padding: 12px var(--tank-inset);
  border-top: 1px solid var(--line);
  background: color-mix(in srgb, var(--paper) 86%, transparent);
  backdrop-filter: saturate(1.4) blur(12px);
}

.lab-cta p {
  margin: 0;
}

.lab-cta-line {
  font-size: 24px;
  line-height: 1.4;
}

.lab-cta-actions {
  display: flex;
  gap: 8px;
}

.lab-table {
  --lab-marked: #f4b4ac;
  --lab-slot-h: 128px;
  --lab-eggs-h: 144px;
  --lab-clutch-h: 202px;
  --lab-offers-h: 216px;
  --lab-floor-spare: 70.4px;
  --lab-floor-h: calc(var(--lab-offers-h) + var(--lab-floor-spare));
  --lab-clutch-gap: 8px;
  --lab-clutch-cell: 100px;
  --lab-ring-room: 8px;
  --lab-confirm-gap: 8px;
  --lab-face-h: 100px;
  --lab-face-border: 2px;
  --lab-keep: var(--kelp-bright);
  --lab-jostle-ms: 1100ms;
  position: relative;
  border: var(--rim-w) solid var(--edge);
  border-radius: 26px;
  background: var(--tank);
  color: var(--cream);
  padding: 40px 24px 24px;
  user-select: none;
  -webkit-user-select: none;
}

.lab-label {
  color: var(--amber);
}

.lab-head {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 8px;
}

.lab-sim {
  margin-left: auto;
  font-size: 16px;
  line-height: 1.6;
  color: #ffffff;
}

/* The window opens on one line: the label or the line's name, the project's
 * shrimp, and Simulation only at the far end, the words centred on the shrimp. */
.lab-head .lab-label,
.lab-head .lab-project-name,
.lab-head .lab-project-sprite {
  display: none;
}

html[data-lab-target] .lab-head .lab-label,
html[data-lab-target] .lab-head .lab-project-name,
html[data-lab-target] .lab-head .lab-project-sprite {
  display: block;
}

.lab-project {
  display: none;
  margin-bottom: 16px;
  padding-bottom: 16px;
  border-bottom: 2px solid color-mix(in srgb, var(--cream) 15%, transparent);
}

html[data-lab-target] .lab-project {
  display: block;
}

.lab-head [hidden],
html[data-lab-target] .lab-head [hidden],
.lab-offers[hidden],
.lab-expired[hidden] {
  display: none;
}

/* Confirm and Undo stand beside the table where there is room and in the
 * corner where there is not, fixed either way so they stay in reach however far
 * down the marked shrimp are. */
.lab-side {
  position: fixed;
  z-index: 30;
  right: 16px;
  bottom: calc(var(--lab-cta-h) + 16px);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.lab-side[hidden],
.lab-side [hidden] {
  display: none;
}

@media (min-width: 1120px) {
  .lab-side {
    right: auto;
    bottom: auto;
    top: 50%;
    left: calc(50% + 440px + 16px);
    transform: translateY(-50%);
  }
}

#lab-cull[aria-pressed='true'] {
  border-color: var(--lab-marked);
  color: var(--lab-marked);
}

.lab-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
}

.lab-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.lab-table .btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.lab-table .btn-ghost.is-quiet {
  opacity: 0.25;
}

/* The hint, the note and an error share one line, the error over the note over
 * the hint, so a message never pushes the tank down. Half a line of air sits
 * under it. */
.lab-lines {
  display: grid;
  margin: 16px 0 0.8em;
}

.lab-lines > p {
  grid-area: 1 / 1;
  min-height: 1.6em;
}

.lab-lines:has(.lab-error:not(:empty)) .lab-hint,
.lab-lines:has(.lab-error:not(:empty)) .lab-note,
.lab-lines:has(.lab-note:not(:empty)) .lab-hint {
  visibility: hidden;
}

.lab-hint {
  color: color-mix(in srgb, var(--cream) 70%, transparent);
}

.lab-count {
  min-height: 1.6em;
}

.lab-note {
  color: color-mix(in srgb, var(--cream) 70%, transparent);
}

.lab-error {
  color: var(--amber);
}

.lab-project-name {
  min-height: 1.4em;
  font-size: 24px;
  line-height: 1.4;
}

.lab-project-sprite {
  width: 96px;
  height: 96px;
  line-height: 0;
}

/* One strip of colour, standing at one of five lengths: a fifth of the way
 * for far, the whole way for acquired. */
.lab-progress {
  height: 16px;
  border: 2px solid color-mix(in srgb, var(--cream) 25%, transparent);
  border-radius: 8px;
  overflow: hidden;
}

.lab-progress-fill {
  display: block;
  width: 0;
  height: 100%;
  background: var(--amber);
  transition: width 400ms steps(4);
}

.lab-progress[data-step='far'] .lab-progress-fill {
  width: 20%;
}

.lab-progress[data-step='getting_there'] .lab-progress-fill {
  width: 40%;
}

.lab-progress[data-step='close'] .lab-progress-fill {
  width: 60%;
}

.lab-progress[data-step='very_close'] .lab-progress-fill {
  width: 80%;
}

.lab-progress[data-step='acquired'] .lab-progress-fill {
  width: 100%;
}

.lab-offers {
  box-sizing: border-box;
  height: var(--lab-offers-h);
  margin: 0;
  padding: 16px;
  border: 2px dashed color-mix(in srgb, var(--amber) 60%, transparent);
  border-radius: 16px;
}

.lab-offers .lab-slots {
  margin: 8px 0 16px;
}

/* The clutch stands on its own above the tank, four narrow cells centred in
 * the window whatever the tank holds, so it never moves when the grid reflows.
 * A cell is as wide as the widest thing it holds, a fry's face, and the egg
 * sits in the middle of it. The fold clips only up and down, and the row keeps
 * room above it, so the focus ring is never cut.
 *
 * The window stands at one height from the first paint through breeding,
 * hatching, keeping, culling and trading. The tank carries empty floor below
 * its shrimp as tall as the largest thing that can open above it, and gives
 * back exactly what opens: the eggs' row, then Confirm under it once the last
 * egg is out, or the trade panel. */
.lab-clutch {
  height: 0;
  overflow-x: visible;
  overflow-y: clip;
  transition: height 240ms steps(6);
}

.lab-clutch.is-open {
  height: calc(var(--lab-eggs-h) + var(--lab-clutch-gap));
}

.lab-clutch.is-open.is-keeping {
  height: calc(var(--lab-clutch-h) + var(--lab-clutch-gap));
}

.lab-grid {
  padding-bottom: var(--lab-floor-h);
  transition: padding-bottom 240ms steps(6);
}

.lab-clutch.is-open ~ .lab-grid {
  padding-bottom: calc(var(--lab-floor-h) - var(--lab-eggs-h) - var(--lab-clutch-gap));
}

.lab-clutch.is-open.is-keeping ~ .lab-grid {
  padding-bottom: calc(var(--lab-floor-h) - var(--lab-clutch-h) - var(--lab-clutch-gap));
}

.lab-offers:not([hidden]) ~ .lab-grid {
  padding-bottom: calc(var(--lab-floor-h) - var(--lab-offers-h));
}

/* While a clutch is out the tank cannot be picked from, and looks it: greyed
 * back until the clutch is kept. */
.lab-grid .lab-slot {
  transition: opacity 240ms steps(4), filter 240ms steps(4);
}

.lab-clutch.is-open ~ .lab-grid .lab-slot {
  opacity: 0.45;
  filter: grayscale(0.6);
}

.lab-slots.lab-clutch-row {
  grid-template-columns: repeat(4, minmax(0, var(--lab-clutch-cell)));
  grid-template-rows: var(--lab-slot-h);
  justify-content: center;
  margin-top: 0;
  padding-top: var(--lab-ring-room);
}

.lab-clutch-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-top: var(--lab-confirm-gap);
}

/* The keep window: a bar that runs down over the window's length, restarted
 * each time it is shown. js/lab.js sets that length on the bar each round;
 * the 10000ms below is only its fallback. Whatever fry are tapped when it
 * empties are kept. */
.lab-keep-timer {
  width: min(240px, 100%);
  height: 8px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--cream) 15%, transparent);
  overflow: hidden;
}

.lab-keep-timer[hidden],
#lab-keep-done[hidden] {
  display: none;
}

.lab-keep-timer span {
  display: block;
  height: 100%;
  background: var(--lab-keep);
  transform-origin: left;
  animation: lab-keep-drain 10000ms linear forwards;
}

/* Green while there is time, amber halfway, red as it runs out. */
@keyframes lab-keep-drain {
  from {
    transform: scaleX(1);
    background: var(--lab-keep);
  }
  50% {
    background: var(--amber);
  }
  to {
    transform: scaleX(0);
    background: #e5412f;
  }
}

.lab-slots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 16px 8px;
  margin-top: 8px;
}

/* The table's grid is sized for a full tank from the first paint, so nothing
 * the tank does ever changes the window's size: six columns hold twelve in
 * two rows. */
.lab-grid {
  --lab-cols: 6;
  --lab-rows: 2;
  grid-template-columns: repeat(var(--lab-cols), minmax(0, 1fr));
  grid-template-rows: repeat(var(--lab-rows), var(--lab-slot-h));
  margin-top: 0;
}

.lab-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  min-width: 0;
}

.lab-face.lab-egg-face {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: var(--lab-face-h);
}

.lab-egg {
  display: block;
  image-rendering: pixelated;
}

.lab-slot.is-hatching .lab-egg {
  animation: lab-wobble 240ms steps(2) infinite;
}

@keyframes lab-wobble {
  50% {
    transform: rotate(8deg);
  }
}

.lab-slot.is-clutch .lab-slot-label {
  color: color-mix(in srgb, var(--cream) 50%, transparent);
}

.lab-slot.is-mutant .lab-slot-label::after {
  content: ' *';
  color: var(--amber);
}

.lab-slot.is-flash .lab-face {
  animation: lab-flash 700ms ease-in-out 2;
}

@keyframes lab-flash {
  50% {
    background: color-mix(in srgb, var(--amber) 22%, transparent);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--amber) 45%, transparent);
  }
}

.lab-face {
  display: block;
  padding: 0;
  border: var(--lab-face-border) solid transparent;
  border-radius: 8px;
  background: transparent;
  cursor: pointer;
  line-height: 0;
  touch-action: pan-y;
  -webkit-touch-callout: none;
}

.lab-face:disabled {
  cursor: default;
}

.lab-table .btn:focus-visible,
.lab-face:focus-visible,
.lab-cta .btn:focus-visible {
  outline: 3px solid var(--amber);
  outline-offset: 3px;
}

/* Focus the page sent, rather than focus the player walked to, still shows the
 * ring: the next thing to act on is always visible. */
.lab-table .btn.is-aimed,
.lab-face.is-aimed {
  outline: 3px solid var(--amber);
  outline-offset: 3px;
}

@media (hover: hover) {
  .lab-face:not(:disabled):hover {
    border-color: color-mix(in srgb, var(--cream) 30%, transparent);
  }
}

.lab-offer-wait {
  cursor: default;
  border-style: dashed;
  border-color: color-mix(in srgb, var(--cream) 25%, transparent);
  animation: lab-offer-jostle var(--lab-jostle-ms) ease-in-out infinite;
}

@keyframes lab-offer-jostle {
  0%,
  100% {
    transform: translate(0, 0) rotate(0deg);
  }

  25% {
    transform: translate(-2px, -1px) rotate(-2deg);
  }

  50% {
    transform: translate(1px, -2px) rotate(1deg);
  }

  75% {
    transform: translate(2px, 0) rotate(2deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .lab-offer-wait {
    animation: none;
  }
}

.lab-sprite {
  display: block;
  width: 96px;
  height: 96px;
  image-rendering: pixelated;
}

.lab-slot.is-sire .lab-face,
.lab-slot.is-pick .lab-face {
  border-color: var(--amber);
}

.lab-slot.is-dam .lab-face {
  border-color: var(--kelp-bright);
}

/* After the hover rule, like the other picks, so a fry turns green under the
 * pointer that just tapped it rather than when the pointer leaves. */
.lab-slot.is-keep .lab-face {
  border-color: var(--lab-keep);
}

.lab-slot.is-keep .lab-slot-label {
  color: var(--lab-keep);
}

.lab-slot.is-marked .lab-face {
  background: color-mix(in srgb, var(--lab-marked) 35%, transparent);
  border-color: var(--lab-marked);
}

.lab-slot.is-marked .lab-slot-label {
  color: var(--lab-marked);
}

.lab-slot.is-give .lab-face {
  border-color: var(--cream);
  border-style: dashed;
}

.lab-slot-label {
  line-height: 1.6;
  color: color-mix(in srgb, var(--cream) 70%, transparent);
}

.lab-slot.is-sire .lab-slot-label {
  color: var(--amber);
}

.lab-slot.is-dam .lab-slot-label {
  color: var(--kelp-bright);
}

.lab-slot.is-fresh .lab-slot-label::after {
  content: ' new';
  color: var(--amber);
}


.lab-expired {
  margin-top: 16px;
}

/* The phone table is the visible viewport and nothing more: the top bar, the
 * window, and the call to action, with no scrolling to play. The window is a
 * grid whose one stretchy row is the empty floor above the controls, so the
 * clutch and the trade row open into that floor and the window never moves.
 * Every control sits in one row at the bottom, in thumb reach, and whatever
 * the table is doing puts its own buttons there: Breed, Cull and Trade, or
 * the clutch's Confirm, or the trade's Trade, Back and Close. */
@media (max-width: 560px) {
  .lab {
    --lab-cta-h: 64px;
    --lab-gutter: 8px;
    height: calc(100vh - var(--lab-cta-h));
    height: calc(100dvh - var(--lab-cta-h));
    padding: calc(var(--bar-h) + var(--lab-gutter)) var(--lab-gutter) var(--lab-gutter);
  }

  .lab-cta {
    flex-wrap: nowrap;
    padding: 8px var(--tank-inset);
  }

  .lab-cta-line {
    font-size: 16px;
  }

  .lab-table {
    --lab-slot-h: 68px;
    --lab-face-h: 68px;
    --lab-clutch-cell: 68px;
    --lab-eggs-h: 84px;
    --lab-offers-h: 0px;
    --lab-floor-h: 0px;
    --lab-head-sprite: 64px;
    --lab-phone-gap: 8px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto auto auto auto auto auto minmax(0, 1fr) auto;
    grid-template-areas:
      'head head'
      'project project'
      'lines count'
      'offers offers'
      'clutch clutch'
      'slots slots'
      '. .'
      'controls controls';
    height: 100%;
    padding: var(--lab-phone-gap);
    border-radius: 16px;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
  }

  .lab-head {
    grid-area: head;
    gap: var(--lab-phone-gap);
    margin-bottom: var(--lab-phone-gap);
  }

  .lab-head .lab-label,
  .lab-sim {
    flex: none;
    white-space: nowrap;
  }

  .lab-project-name {
    min-width: 0;
    min-height: 0;
    overflow: hidden;
    font-size: 16px;
    line-height: 1.6;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .lab-project-sprite,
  .lab-head .lab-sprite {
    flex: none;
    width: var(--lab-head-sprite);
    height: var(--lab-head-sprite);
  }

  html[data-lab-target] .lab-project {
    grid-area: project;
    margin: 0 0 var(--lab-phone-gap);
    padding: 0;
    border: 0;
  }

  .lab-bar {
    display: contents;
  }

  .lab-count {
    grid-area: count;
    margin-left: var(--lab-phone-gap);
  }

  .lab-lines {
    grid-area: lines;
    margin: 0 0 0.8em;
  }

  .lab-table .lab-buttons {
    grid-area: controls;
    flex-wrap: nowrap;
    margin-top: var(--lab-phone-gap);
  }

  .lab-table .lab-buttons .btn {
    justify-content: center;
    min-height: 48px;
  }

  /* No Trade confirm: tapping one of yours trades. Back and Close share the row. */
  #lab-trade-back,
  #lab-trade-close {
    flex: 1 1 0;
  }

  /* No Breed button: picking the dam breeds. The two left share the row. */
  #lab-trade,
  #lab-cull {
    flex: 1 1 0;
  }

  #lab-mute {
    display: none;
  }

  #lab-cull {
    order: -1;
  }

  #lab-trade,
  #lab-cull-confirm,
  #lab-undo {
    min-width: 104px;
  }

  .lab-offers:not([hidden]) {
    display: contents;
  }

  #lab-offers-title {
    display: none;
  }

  .lab-offers .lab-slots.lab-offer-slots {
    grid-area: offers;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-rows: var(--lab-slot-h);
    margin: 0 0 var(--lab-phone-gap);
    padding: 6px;
    border: 2px dashed color-mix(in srgb, var(--amber) 60%, transparent);
    border-radius: 16px;
  }

  .lab-table:has(.lab-offers:not([hidden])) .lab-bar .lab-buttons,
  .lab-table:has(.lab-clutch.is-keeping) .lab-bar .lab-buttons,
  .lab-table:has(.lab-offers:not([hidden])) .lab-side {
    display: none;
  }

  .lab-clutch {
    display: contents;
  }

  .lab-slots.lab-clutch-row {
    grid-area: clutch;
    grid-template-rows: var(--lab-slot-h);
    align-content: center;
    height: 0;
    padding: 0;
    overflow-x: visible;
    overflow-y: clip;
    transition: height 240ms steps(6);
  }

  .lab-clutch.is-open .lab-clutch-row {
    height: var(--lab-eggs-h);
  }

  .lab-clutch-actions {
    display: none;
  }

  .lab-clutch.is-keeping .lab-clutch-actions {
    display: flex;
    grid-area: controls;
    align-items: center;
    min-height: 48px;
    margin-top: var(--lab-phone-gap);
  }

  .lab-keep-timer {
    flex: 1 1 auto;
    width: auto;
  }

  #lab-keep-done {
    flex: none;
    min-width: 104px;
  }

  .lab-clutch-actions .btn {
    justify-content: center;
    min-height: 48px;
  }

  .lab-slots {
    gap: var(--lab-phone-gap) 4px;
  }

  .lab-grid {
    --lab-cols: 4;
    --lab-rows: 3;
    grid-area: slots;
  }

  .lab-grid .lab-slot-label,
  .lab-clutch-row .lab-slot-label {
    display: none;
  }

  .lab-sprite {
    width: 64px;
    height: 64px;
  }

  .lab-side {
    grid-area: controls;
    position: static;
    justify-self: end;
    margin-top: var(--lab-phone-gap);
  }

  .lab-side .btn {
    justify-content: center;
    min-height: 48px;
  }

  .lab-table:has(.lab-side:not([hidden])) #lab-trade {
    visibility: hidden;
  }

  .lab-expired {
    grid-area: slots;
    align-self: start;
    margin: 0;
  }
}

/* A short phone draws its shrimp at three quarters, which is a whole number
 * of device pixels on the two-times screens that short phones have. */
@media (max-width: 560px) and (max-height: 600px) {
  .lab-table {
    --lab-slot-h: 52px;
    --lab-face-h: 52px;
    --lab-clutch-cell: 52px;
    --lab-eggs-h: 68px;
    --lab-head-sprite: 48px;
  }

  .lab-sprite {
    width: 48px;
    height: 48px;
  }
}
