  .fish {
    position: relative;
    flex: none;
    overflow: hidden;
    font: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    text-align: left;
    color: var(--cream);
    background: var(--bark-d);
    border: 2px solid var(--bark-l);
    border-radius: 3px;
    padding: 10px 11px 21px;
    cursor: pointer;
    transition: border-color .12s, background .12s;
  }
  .fish:hover:not(:disabled) { background: var(--bark-l); }
  .fish.fish--mut[aria-pressed="true"] {
    box-shadow: var(--chrome-edge), inset 0 0 0 2px rgba(224,160,84,.85);
  }
  .fish:focus-visible { outline: 2px solid var(--ember); outline-offset: 2px; }
  .fish[aria-pressed="true"] { border-color: var(--ember); }
  .fish--locked { opacity: .42; cursor: not-allowed; }

  .fish__fill {
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 0%;
    background: rgba(224,160,84,.2);
    border-right: 1px solid rgba(224,160,84,.5);
    pointer-events: none;
  }
  .fish__top {
    position: relative;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
  }
  .pondtab {
    flex: none;
    height: 172px;
    display: flex;
    flex-direction: column;
    color: var(--cream);
    background: var(--bark-d);
    border: 2px solid var(--bark-l);
    border-radius: 3px;
    padding: 8px;
  }
  /* Tabs holding upgrade slots grow to fit rather than clipping them. */
  .pondtab--breed,
  .pondtab[data-pane] { height: auto; min-height: 172px; }

  .pondtab--locked { opacity: .42; }

  .pondtab__name {
    flex: none;
    font-size: 13px;
    margin-bottom: 7px;
  }
  .pondtab__lvl {
    font-size: 11px;
    color: var(--ember);
    margin-left: 6px;
    white-space: nowrap;
  }
  /* auto-fit collapses to one column when the panel is too narrow for two,
     so nothing has to be re-tuned when --panel-r changes. */
  .pondtab__slots {
    flex: 1 1 auto;
    min-height: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(155px, 1fr));
    gap: 8px;
  }
  /* Rows size to content: a two-line fish name plus its level or price is
     taller than a fixed row, and the overflow escaped the tile. */
  .pondtab__slots--breed {
    grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
    grid-auto-rows: minmax(52px, auto);
  }
  .pondslot {
    background: var(--bark-dd);
    border: 2px solid var(--bark-l);
    border-radius: 3px;
  }
  /* Mutated fish read silver. The border is brushed metal rather than a flat
     colour: two stacked backgrounds, the inner one clipped to the padding box
     and the outer gradient to the border box. An enchanted mutated fish keeps
     the silver frame and turns only the fish gold. */
  :root {
    --chrome: linear-gradient(135deg,
      #fdfdfe 0%, #aab0b8 14%, #f2f4f6 27%, #7d848c 41%,
      #e8ebee 52%, #7d848c 63%, #f2f4f6 77%, #aab0b8 88%, #fdfdfe 100%);
    --chrome-edge: 0 0 0 1px rgba(20,9,6,.55), 0 0 7px rgba(214,220,228,.28);
  }

  .fish.fish--mut,
  .pondslot.pondslot--mutated {
    border: 3px solid #cbd3dd;
    border-image: var(--chrome) 1 stretch;
    box-shadow: var(--chrome-edge);
    background: linear-gradient(180deg, rgba(203,211,221,.15), rgba(203,211,221,.04)), var(--bark-d);
  }
  .fish.fish--mut:hover:not(:disabled) {
    background: linear-gradient(180deg, rgba(203,211,221,.24), rgba(203,211,221,.10)), var(--bark-l);
  }

  /* Four-point studs on the left and right edges, echoing the banner ends. */
  .fish--mut::before, .fish--mut::after {
    content: "";
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: var(--chrome);
    clip-path: polygon(50% 0%, 61% 39%, 100% 50%, 61% 61%,
                       50% 100%, 39% 61%, 0% 50%, 39% 39%);
    pointer-events: none;
    z-index: 2;
  }
  /* The fish row clips overflow, so its studs sit just inside the frame. */
  .fish--mut { padding-left: 17px; padding-right: 17px; }
  .fish--mut::before, .fish--mut::after { width: 10px; height: 20px; }
  .fish--mut::before { left: -3px; }
  .fish--mut::after  { right: -3px; }
  .pondslot--breed {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: 3px;
    min-width: 0;
    padding-bottom: 2px;
    font: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    text-align: left;
    color: var(--cream);
    cursor: pointer;
    transition: border-color .12s, background .12s;
  }
  .pondslot--breed:hover:not(:disabled) { background: var(--bark-d); }
  .pondslot--breed:disabled { cursor: not-allowed; }
  .pondslot--gated,
  .pondslot--breed.pondslot--poor { opacity: .55; }
  .pondslot--mutated { opacity: 1; }
  .pondslot__mut {
    display: block;
    margin-top: auto;
    padding: 0 6px 3px;
    font-size: 9px;
    color: var(--silver);
  }
  .pondslot--up {
    display: flex;
    flex-direction: column;
    min-width: 0;
    font: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    text-align: left;
    color: var(--cream);
    padding: 6px 7px 6px;
    cursor: pointer;
    transition: border-color .12s, background .12s;
  }
  .pondslot--up:hover:not(:disabled) { background: var(--bark-d); }
  .pondslot--up:focus-visible { outline: 2px solid var(--ember); outline-offset: 2px; }
  .pondslot--up:disabled { cursor: not-allowed; }
  .pondslot--poor  { opacity: .62; }
  .pondslot--maxed { opacity: .72; border-color: var(--ember); }
  /* The tier badge drops to its own line rather than squeezing the name
     until it breaks mid-word. */
  .pondslot__top {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 5px;
    min-width: 0;
  }
  .pondslot__name { font-size: 12px; overflow-wrap: normal; }
  .pondslot__tier {
    margin-left: auto;
    font-size: 10px;
    color: var(--ember);
    white-space: nowrap;
  }
  .pondslot__desc {
    display: block;
    margin-top: 4px;
    font-size: 10px;
    line-height: 1.4;
    overflow-wrap: break-word;
    color: rgba(242,227,208,.62);
  }
  .pondslot__cost {
    margin-top: auto;
    padding-top: 5px;
    text-align: right;
    font-size: 10px;
    color: var(--silver);
  }
  .pondslot__fish {
    display: block;
    padding: 5px 6px;
    overflow-wrap: normal;
    font-size: 10px;
    color: rgba(242,227,208,.55);
  }

  .fish__name { font-size: 13px; }
  /* Tier sits beside the name, quieter than it. Wade's three starters all
     share tier 1, so this is not just the row number. */
  .fish__tier { margin-left: 5px; font-size: 9px; opacity: .6; }
  .fish--mut .fish__name,
  .fish--mut .fish__owned {
    color: #fbfcfd;
    text-shadow: 0 1px 2px rgba(20,9,6,.9);
  }
  .fish--mut .fish__stat {
    color: #ffd79a;
    text-shadow: 0 1px 2px rgba(20,9,6,.9);
  }
  .slot--mut .slot__n { text-shadow: 0 1px 2px #140906, 0 0 4px #140906; }
  .pondslot--mutated .pondslot__fish {
    color: #fbfcfd;
    text-shadow: 0 1px 2px rgba(20,9,6,.9);
  }
  .pondslot--mutated .pondslot__mut {
    color: #e8edf3;
    text-shadow: 0 1px 2px rgba(20,9,6,.9);
  }
  .fish__stat { font-size: 10px; color: var(--ember); white-space: nowrap; }
  .fish__owned {
    position: absolute;
    right: 10px;
    bottom: 5px;
    font-size: 10px;
    color: rgba(242,227,208,.55);
  }

  /* ── Dojo ────────────────────────────────────────────────────────────── */
  /* One row per dan rank, same shell as a pond tab but sized to its content
     since the ranks hold nothing yet. */
  /* The ten ranks sit in four named phases; the phase is a heading over its
     rows, not a row itself. */
  .dojophase {
    flex: none;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }
  .dojophase__name {
    font-size: 11px;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: rgba(242,227,208,.55);
  }
  .dojotab {
    flex: none;
    display: flex;
    flex-direction: column;
    color: var(--cream);
    background: var(--bark-d);
    border: 2px solid var(--bark-l);
    border-radius: 3px;
    padding: 8px;
  }
  .dojotab--locked { opacity: .42; }
  .dojotab__name {
    flex: none;
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: 13px;
    cursor: pointer;
  }
  .dojotab--locked .dojotab__name { cursor: not-allowed; }
  /* Caret rotates rather than swapping glyphs, so the row never reflows. */
  .dojotab__name::before {
    content: "\25B8";
    font-size: 11px;
    color: var(--ember);
    transition: transform .12s ease;
  }
  .dojotab--open .dojotab__name::before { transform: rotate(90deg); }
  .dojotab__dan {
    margin-left: auto;
    font-size: 11px;
    color: var(--ember);
    white-space: nowrap;
  }
  .dojotab__slots { display: none; }
  .dojotab--open .dojotab__slots {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 7px;
  }
  .dojodesc {
    font-size: 11px;
    line-height: 1.45;
    color: rgba(242,227,208,.72);
  }
  .dojorow {
    background: var(--bark-dd);
    border: 2px solid var(--bark-l);
    border-radius: 3px;
    padding: 7px 8px;
  }
  .dojorow__top {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    font-size: 12px;
  }
  .dojorow__tier { font-size: 10px; color: var(--ember); white-space: nowrap; }
  .dojorow__desc {
    margin-top: 3px;
    font-size: 10px;
    line-height: 1.4;
    color: rgba(242,227,208,.6);
  }
  /* The bar only reads while a tier is running; it sits flat the rest of the
     time rather than disappearing, so the row height never jumps. */
  .dojorow__track {
    height: 4px;
    margin: 6px 0;
    background: rgba(20,9,6,.55);
    border-radius: 2px;
    overflow: hidden;
  }
  .dojorow__fill {
    display: block;
    height: 100%;
    width: 0%;
    background: var(--ember);
  }
  .dojorow__btn {
    width: 100%;
    font: inherit;
    font-size: 11px;
    text-transform: inherit;
    letter-spacing: inherit;
    color: var(--cream);
    background: var(--bark-d);
    border: 2px solid var(--bark-l);
    border-radius: 3px;
    padding: 4px 6px;
    cursor: pointer;
  }
  .dojorow__btn:disabled { cursor: default; opacity: .55; }
  .dojorow__btn--busy { color: var(--ember); opacity: 1; }
  .dojorow__btn--poor { color: #c9756a; }

  /* A finished dan turns gold and gives off a few slow motes. */
  .dojotab--done {
    position: relative;
    overflow: hidden;
    border-color: #e8c46a;
    box-shadow: 0 0 10px rgba(232,196,106,.3);
  }
  /* Motes are real elements rather than a gradient layer: each one carries its
     own delay, duration, drift and rise, so they never move as a block. Built
     once per finished dan in refreshDojo. */
  .dojomotes {
    position: absolute;
    inset: 0;
    pointer-events: none;
    overflow: hidden;
  }
  .dojomote {
    position: absolute;
    bottom: -4px;
    border-radius: 50%;
    background: rgba(255,236,180,.95);
    opacity: 0;
    animation: dojoMotes var(--dur) linear var(--delay) infinite;
  }
  @keyframes dojoMotes {
    from { transform: translate(0, 0);                 opacity: 0; }
    18%  {                                             opacity: var(--peak); }
    82%  {                                             opacity: var(--peak); }
    to   { transform: translate(var(--drift), var(--rise)); opacity: 0; }
  }

  /* ── Dev speed ───────────────────────────────────────────────────────── */
