.tb-team,
.tb-team * {
  box-sizing: border-box;
}

/* One stylesheet, three modes, identical DOM:
     .tb-team--export  fixed 1920px poster, rasterised to PNG
     .tb-team--view    saved build rendered on the page
     .tb-team--screen    the builder
   Everything below the RESPONSIVE section at the end of this file only ever
   NARROWS the layout, and only inside @container queries a 1920px container
   cannot match - so the export is defined entirely by the base rules. */
.tb-team {
  --tb-border: #d297ff;
  --tb-fill: rgba(117, 60, 161, 0.49);
  --tb-text: #fff8ff;
  --tb-text-soft: #efd9ff;
  --tb-cyan: #86ddff;
  --tb-gold: #fff36d;
  --tb-url: #9aa5ff;
  width: 1920px;
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 24px;
  overflow: hidden;
  border: 2px solid var(--tb-border);
  border-radius: 16px;
  color: var(--tb-text);
  background:
    radial-gradient(circle at 12% -8%, rgba(138, 95, 220, 0.33) 0, transparent 34%),
    radial-gradient(circle at 88% -2%, rgba(90, 69, 155, 0.24) 0, transparent 30%),
    radial-gradient(circle at 50% 120%, rgba(67, 52, 110, 0.22) 0, transparent 40%),
    linear-gradient(160deg, #090a12 0%, #07080f 44%, #0f0c1a 100%);
  font-family: "CookieRunExport", "Arial Rounded MT Bold", "Trebuchet MS", Arial, sans-serif;
  letter-spacing: 0;
  line-height: 1.2;
}

.tb-team img {
  display: block;
  max-width: 100%;
}

.tb-panel {
  width: 100%;
  border: 2px solid var(--tb-border);
  border-radius: 16px;
  background: var(--tb-fill);
  box-shadow: 0 0 48px rgba(0, 0, 0, 0.95);
}

.tb-outline {
  color: inherit;
  -webkit-text-stroke: 2px #080014;
  paint-order: stroke fill;
  text-shadow: -2px 2px 2px rgb(0 0 0), 0 0 10px rgba(0, 0, 0, 0.9);
}

.tb-header {
  height: auto;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  gap: 0;
}

.tb-header-left,
.tb-header-right {
  min-width: 0;
  padding: 16px;
}

.tb-header-left {
  /* Takes the row space the treasures do not, which makes it a definite width
     for the title card to cap against — without it the card sizes to its own
     text and the auto-fitter has no box to fit into. */
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.tb-header-right {
  flex: 0 0 auto;
}

.tb-site-badge {
  height: 88px;
  display: flex;
  align-items: center;
  gap: 16px;
}

.tb-site-icon {
  width: 88px;
  height: 88px;
  border: 3px solid rgba(255, 221, 126, 0.62);
  border-radius: 18px;
  object-fit: cover;
  box-shadow: 0 0 12px rgba(0, 0, 0, 0.68);
}

.tb-site-copy {
  min-width: 0;
  width: 360px;
}

.tb-brand-title,
.tb-brand-url {
  overflow: hidden;
  white-space: nowrap;
}

.tb-brand-title {
  height: 45px;
  color: var(--tb-gold);
  font-family: "CookieRun KR", "CookieRunExport", "Outfit", sans-serif;
  font-weight: 900;
  font-size: 42px;
  line-height: 1;
}

.tb-brand-url {
  height: 32px;
  color: var(--tb-url);
  font-size: 29px;
  line-height: 1;
}

.tb-build-title-card {
  /* Hugs its text (align-self keeps it from stretching) but never past the
     region it sits in. */
  width: auto;
  max-width: 100%;
  align-self: flex-start;
  height: auto;
  padding: 8px 18px;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  gap: 18px;
  border: 2px solid var(--tb-border);
  border-radius: 16px;
  background: var(--tb-fill);
  box-shadow: 0 0 16px rgba(0, 0, 0, 0.9);
  overflow: visible;
}

.tb-build-name {
  /* Shrinks when the row runs out of space, but only after the subtitle has
     given way, and never below a legible floor. */
  flex: 0 1 auto;
  min-width: 220px;
  height: 54px;
  /* Room for the -webkit-text-stroke ink, which paints outside the text box. */
  padding-inline: 2px;
  overflow: hidden;
  color: var(--tb-text);
  font-family: "CookieRun KR", "CookieRunExport", "Outfit", sans-serif;
  font-weight: 700;
  font-size: 45px;
  line-height: 1;
  /* Starts as one line; fitExportText switches to wrapping when a long name
     would otherwise have to shrink too far. */
  white-space: nowrap;
  overflow-wrap: anywhere;
  text-overflow: ellipsis;
}

/* Mode + context, then the creator credit, laid out inline beside the name.
   Shrinks ahead of the build name — a long creator handle ellipsizes rather
   than squeezing the team's own name out of the card. */
.tb-build-subtitle {
  flex: 0 6 auto;
  min-width: 0;
  display: flex;
  flex-direction: row;
  gap: 18px;
  color: #ffc8ff;
}

.tb-build-subtitle-line {
  flex: 0 1 auto;
  min-width: 0;
  align-self: center;
  height: 30px;
  /* Room for the -webkit-text-stroke ink, which paints outside the text box. */
  padding-inline: 2px;
  overflow: hidden;
  font-size: 25px;
  line-height: 1;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.tb-build-subtitle-credit {
  height: 24px;
  color: #f0b6f0;
  font-size: 20px;
  line-height: 1;
}

.tb-treasure-panel {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.tb-treasure-heading {
  display: none;
  height: 34px;
  color: var(--tb-cyan);
  font-size: 32px;
  line-height: 1;
  border-bottom: 3px solid rgba(239, 217, 255, 0.92);
  padding: 0 14px 6px;
}

.tb-treasure-row {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: 20px;
}

.tb-treasure-card {
  width: 140px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

.tb-treasure-art-wrap {
  width: 124px;
  height: 124px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border: 2px solid rgba(255, 220, 124, 0.66);
  border-radius: 20px;
  background: rgba(255, 210, 93, 0.12);
  box-shadow: 0 8px 12px rgba(0, 0, 0, 0.4);
}

.tb-treasure-card.is-empty .tb-treasure-art-wrap {
  border-style: dashed;
  border-color: rgba(239, 217, 255, 0.4);
  background: rgba(255, 255, 255, 0.06);
}

.tb-treasure-art {
  width: 108px;
  height: 108px;
  object-fit: contain;
  filter: drop-shadow(0 6px 5px rgba(0, 0, 0, 0.55));
}

.tb-treasure-empty-mark {
  color: rgba(239, 217, 255, 0.55);
  font-size: 44px;
}

.tb-treasure-name {
  width: 100%;
  height: 40px;
  overflow: visible;
  color: var(--tb-text);
  font-size: 19px;
  line-height: 1.05;
  text-align: center;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.55);
}

.tb-treasure-card.is-empty .tb-treasure-name {
  color: rgba(239, 217, 255, 0.55);
}

.tb-team-section {
  padding: 16px;
}

.tb-team-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
  align-items: self-start;
}

.tb-cookie-tile {
  --tb-rarity-border: linear-gradient(145deg, #a8e3ff 0%, #5e9fda 54%, #1d4167 100%);
  --tb-rarity-tint: linear-gradient(160deg, rgba(54, 94, 124, 0.55), rgba(20, 38, 52, 0.55));
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 10px 8px;
  border: 3px solid transparent;
  border-radius: 18px;
  background:
    var(--tb-rarity-tint) padding-box,
    linear-gradient(165deg, rgba(20, 6, 30, 0.92), rgba(34, 7, 46, 0.92)) padding-box,
    var(--tb-rarity-border) border-box;
  box-shadow: 0 10px 22px rgba(0, 0, 0, 0.55);
}

.tb-cookie-tile[data-cookie-rarity="common"] {
  --tb-rarity-border: linear-gradient(145deg, #f3d3b1 0%, #c49769 56%, #654427 100%);
  --tb-rarity-tint: linear-gradient(160deg, rgba(133, 103, 76, 0.5), rgba(62, 46, 33, 0.5));
}

.tb-cookie-tile[data-cookie-rarity="rare"] {
  --tb-rarity-border: linear-gradient(145deg, #a8e3ff 0%, #5e9fda 54%, #1d4167 100%);
  --tb-rarity-tint: linear-gradient(160deg, rgba(54, 94, 124, 0.5), rgba(20, 38, 52, 0.5));
}

.tb-cookie-tile[data-cookie-rarity="epic"] {
  --tb-rarity-border: linear-gradient(145deg, #ffacd0 0%, #df679d 54%, #6d294b 100%);
  --tb-rarity-tint: linear-gradient(160deg, rgba(120, 50, 79, 0.5), rgba(45, 20, 33, 0.5));
}

.tb-cookie-tile[data-cookie-rarity="super-epic"] {
  --tb-rarity-border: linear-gradient(145deg, #f6b9ff 0%, #ca73ff 54%, #592b82 100%);
  --tb-rarity-tint: linear-gradient(160deg, rgba(132, 56, 150, 0.5), rgba(40, 16, 56, 0.5));
}

.tb-cookie-tile[data-cookie-rarity="special"] {
  --tb-rarity-border: linear-gradient(145deg, #ffe79a 0%, #e0a93a 56%, #7a500d 100%);
  --tb-rarity-tint: linear-gradient(160deg, rgba(128, 87, 20, 0.5), rgba(44, 28, 5, 0.5));
}

.tb-cookie-tile[data-cookie-rarity="legendary"] {
  --tb-rarity-border: linear-gradient(145deg, #94ecff 0%, #53dcb9 52%, #17698a 100%);
  --tb-rarity-tint: linear-gradient(160deg, rgba(24, 102, 126, 0.5), rgba(12, 38, 57, 0.5));
}

.tb-cookie-tile[data-cookie-rarity="dragon"] {
  --tb-rarity-border: linear-gradient(145deg, #ffb08d 0%, #f4873f 52%, #8a3316 100%);
  --tb-rarity-tint: linear-gradient(160deg, rgba(168, 58, 24, 0.5), rgba(49, 18, 12, 0.5));
}

.tb-cookie-tile[data-cookie-rarity="ancient"] {
  --tb-rarity-border: linear-gradient(45deg, #f1d6ff 0%, #eddba5 18%, #c89231 30%, #fff0c7 40%, #b17c2f 48%, #9457de 64%, #4b2a80 100%);
  --tb-rarity-tint: linear-gradient(160deg, rgba(99, 53, 165, 0.5), rgba(34, 14, 64, 0.5));
}

.tb-cookie-tile[data-cookie-rarity="beast"] {
  --tb-rarity-border: linear-gradient(45deg, #fff8e6 0%, #f6dc9a 14%, #c7922f 32%, #fff1c7 40%, #b97b27 50%, #be3158 62%, #4f0a15 100%);
  --tb-rarity-tint: linear-gradient(160deg, rgba(138, 21, 46, 0.5), rgba(32, 3, 5, 0.5));
}

.tb-cookie-tile[data-cookie-rarity="witch"] {
  --tb-rarity-border: linear-gradient(45deg, #ff9be4 0%, #f0d99e 18%, #c79231 32%, #fff0c7 40%, #b37d2f 48%, #9b3f9f 64%, #320534 100%);
  --tb-rarity-tint: linear-gradient(160deg, rgba(92, 12, 84, 0.5), rgba(23, 2, 25, 0.5));
}

.tb-cookie-tile.is-empty {
  justify-content: center;
  border: 3px dashed rgba(239, 217, 255, 0.35);
  background: rgba(255, 255, 255, 0.04);
  box-shadow: none;
}

.tb-empty-slot-mark {
  color: rgba(239, 217, 255, 0.45);
  font-size: 76px;
  line-height: 1;
}

.tb-empty-slot-label {
  color: rgba(239, 217, 255, 0.45);
  font-size: 24px;
}

.tb-cookie-art-wrap {
  position: relative;
  width: 90%;
  height: auto;
  display: grid;
  place-items: center;
  overflow: visible;
  border-radius: 16px;
  align-self: center;
}

.tb-cookie-art {
  width: 100%;
  height: auto;
  object-fit: contain;
  border-radius: 16px;
  filter: drop-shadow(2px 6px 10px rgba(0, 0, 0, 0.72));
}

.tb-cookie-initials {
  width: 150px;
  height: 150px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  color: var(--tb-text);
  font-size: 52px;
}

.tb-cookie-meta-badges,
.tb-cookie-element-badges {
  position: absolute;
  top: -16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  z-index: 10;
}

/* Type + position on the right, elements on the left. */
.tb-cookie-meta-badges {
  right: -18px;
}

.tb-cookie-element-badges {
  left: -6px;
}

.tb-cookie-meta-icon {
  width: 46px;
  height: 46px;
  object-fit: contain;
  filter: drop-shadow(2px 4px 8px rgba(0, 0, 0, 0.78));
}

/* ---- EDIT: the name laid over the portrait, at every width ----
   The tile is a flex column in the poster and the read-only card. --edit makes
   it a single-column grid instead, purely so the name and the portrait have a
   CELL to share: two grid items in one cell overlap in DOM order, and the name
   comes second. No markup changes, and nothing else moves — a one-column grid
   with the same gap lays a stack out exactly as the flex column did.

   The narrow-container rules below re-point this at a three-column grid and
   re-cap both boxes at 220px; everything here survives that untouched, because
   what makes the overlay work is the shared cell, not the column count.

   The name is sized to MATCH THE PORTRAIT rather than aligned to the bottom of
   the cell. `align-self: end` was the obvious way and is wrong: a grid row is
   as tall as its tallest item, so in the wide tile the name landed ~100px
   BELOW the portrait, next to the beascuit card that set the row height.
   Instead the box takes the art's width and `aspect-ratio: 1` to match its
   height, then bottom-aligns its own text inside itself. That holds at any
   width without knowing a number.

   The 90% mirrors the base .tb-cookie-art-wrap width, so the band is exactly
   as wide as the portrait it sits on.

   pointer-events: none is load-bearing: the art wrap IS the change-cookie
   button, and a label lying across its bottom third would otherwise swallow
   the taps that land there. */
.tb-team--screen .tb-cookie-tile:not(.is-empty) {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
}

.tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-art-wrap,
.tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-name {
  grid-column: 1;
  grid-row: 1;
}

.tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-art-wrap {
  /* Stated, not assumed: the name matches the portrait by taking the same
     width and squaring itself, which only lines up if the portrait is square.
     Every cookie asset is, so this pins the fact rather than changing it. */
  aspect-ratio: 1;
}

.tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-name {
  align-self: center;
  justify-self: center;
  z-index: 1;
  width: 98%;
  aspect-ratio: 1;
  height: auto;
  display: grid;
  align-items: end;
  justify-items: center;
  padding: 0 4px 4px;
  font-size: 16px;
  line-height: 1.1;
  /* Nudges the NAME inside the frame, without moving the frame. Positive is
     down, negative is up; set it in any breakpoint that needs it and leave the
     rest alone.

     It has to be a transform on a wrapper rather than padding on this box,
     because the ring and the band are painted by ::after/::before at `inset:
     0` — they follow the border box, so padding would move the text but the
     usable range downward stops at the 4px there is. A translate has no such
     ceiling and cannot disturb the frame at all. */
  --tb-cookie-name-nudge: 0px;
  /* Rarity-themed, off the same two vars .tb-cookie-tile uses. They are set on
     the tile by [data-cookie-rarity] and this frame is a descendant, so they
     arrive by inheritance with nothing to wire up.

     Both are painted by pseudo-elements rather than on the frame itself, and
     the reason is that this frame is mostly TRANSPARENT — it sits over the
     portrait. The tile's technique (transparent border + gradient in the
     border-box layer) relies on opaque padding-box layers hiding the rest of
     that gradient. Here the only padding-box layer fades to nothing, so the
     border gradient showed straight through and washed the whole portrait
     gold. */
  position: relative;
  border: 0;
  border-radius: 16px;
  /* Band only across the foot of the square, not a wash over the art. */
  background: linear-gradient(
    to top,
    rgb(0 0 0 / 64%) 0%,
    rgb(9 3 17 / 40%) 13%,
    rgb(9 3 17 / 0%) 27%
  );
  pointer-events: none;
}

.tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-name > .tb-cookie-name-text {
  transform: translateY(var(--tb-cookie-name-nudge, 0px));
}

/* The rarity BORDER, as a ring. The gradient fills the box, so the middle is
   masked back out: two mask layers, one clipped to the content box, composited
   so only the difference — the 2px frame — survives. */
.tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-name::after {
  content: "";
  position: absolute;
  inset: 0;
  padding: 2px;
  border-radius: inherit;
  background: var(--tb-rarity-border);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
}

/* The rarity TINT, confined to the band.
   It cannot be another background layer on the frame: --tb-rarity-tint is a
   full-box gradient at a flat 0.5 alpha, so clipping it with background-size
   would put a hard edge across the portrait exactly where the dark band has
   already faded to nothing. Given a layer of its own it can be masked on the
   same curve as the band, and the art above it stays clean.

   z-index: -1 is what orders it: inside this frame's stacking context a
   negative child paints after the frame's own background and before its text,
   so the tint colours the band without washing over the name. */
.tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-name::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--tb-rarity-tint);
  -webkit-mask-image: linear-gradient(to top, #000 0%, #000 13%, transparent 30%);
  mask-image: linear-gradient(to top, #000 0%, #000 13%, transparent 30%);
}

/* The phone card is hidden by default in its own stylesheet
   (assets/css/dex-cookie-card.css), which is where it belongs — one owner for
   the rule. It is un-hidden in the <= 699px block below. Keeping that in mind
   matters: the card is rendered into EVERY edit-mode tile, because the
   renderer keys off mode and not width, so only CSS keeps it off the wider
   layouts. */

.tb-cookie-name {
  width: 100%;
  height: 52px;
  display: grid;
  place-items: center;
  overflow: hidden;
  color: #ffffff;
  font-family: "CookieRun KR", "CookieRunExport", "Outfit", sans-serif;
  font-weight: 700;
  font-size: 25px;
  line-height: 1.02;
  text-align: center;
  text-wrap: balance;
}

.tb-topping-grid {
  width: 100%;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto;
  gap: 8px;
  padding: 8px;
  border: 2px solid rgba(210, 151, 255, 0.4);
  border-radius: 12px;
  background: rgb(10 7 46 / 55%);
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.35);
}

.tb-topping-cell {
  width: 100%;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  overflow: hidden;
  border: 2px solid rgba(210, 151, 255, 0.68);
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.1);
  box-shadow: 0 6px 10px rgba(0, 0, 0, 0.4);
}

.tb-topping-cell img {
  width: 100%;
  height: auto;
  object-fit: contain;
  filter: drop-shadow(0 5px 4px rgba(0, 0, 0, 0.55));
}

.tb-topping-cell.is-tart {
  border-color: rgba(255, 220, 124, 0.78);
  background: rgba(255, 210, 93, 0.14);
}

.tb-topping-cell.is-empty {
  border-style: dashed;
  border-color: rgba(210, 151, 255, 0.3);
  background: rgba(255, 255, 255, 0.04);
}

/* Per-cookie beascuit card: name, art, then the 2x2 bonus effect grid — the
   tile-sized version of the cookie build export's beascuit frame. */
.tb-beascuit-card {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px;
  border: 2px solid rgba(210, 151, 255, 0.4);
  border-radius: 12px;
  background: rgb(10 7 46 / 55%);
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.35);
  align-self: center;
  min-height: 170px;
}

.tb-beascuit-name {
  height: 44px;
  display: grid;
  place-items: center;
  overflow: hidden;
  padding: 4px 8px;
  border: 2px solid rgba(255, 220, 124, 0.5);
  border-radius: 10px;
  background: rgba(255, 210, 93, 0.12);
  color: var(--tb-text);
  font-size: 17px;
  line-height: 1.05;
  text-align: center;
  overflow-wrap: anywhere;
  text-shadow: 0 0 4px rgb(0 0 0 / 95%);
}

/* ---- EDIT: the name laid over the top of the art well ----
   Same mechanism as the cookie name over its portrait: the label and the well
   are given the SAME grid cell, so they overlap in DOM order with no markup
   change. The card is a flex column by default; --edit makes it a single
   column grid so a cell exists to share.

   Absolute positioning was the obvious alternative and is wrong here. The
   well is not the card's full width — the wide tile caps it at 190px and
   centres it — so a label pinned to the card's padding box overhangs it by
   150-odd px, and there is no containing block that tracks the well.

   The width is therefore mirrored from the well rather than derived: 100%
   here, and the wide-tile rule that caps the well names this label too.

   pointer-events: none keeps the well clickable — it carries the beascuit
   cycler's arrows.

   --edit only. The poster and the read-only card keep the name in its own
   frame above the well, and the export is byte-verified against that. */
.tb-team--screen .tb-beascuit-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
}

.tb-team--screen .tb-beascuit-name--overlay,
.tb-team--screen .tb-beascuit-card > .tb-beascuit-art-wrap {
  grid-row: 1;
  grid-column: 1;
}

.tb-team--screen .tb-beascuit-name--overlay {
  /* Matches the WELL, not the cell — same reasoning as the cookie name over
     its portrait. `align-self: start` meant the head of the ROW, which is only
     the head of the well while the two are the same height. The phone layout
     lays the effects beside the well and makes the row far taller, and the
     label floated ~58px above the thing it labels. Mirroring the well's box
     (width from the shared cap rule, shape from its aspect-ratio) and centring
     both makes them coincide at any row height; the text is then held to the
     box's own head. */
  align-self: center;
  justify-self: center;
  z-index: 1;
  width: 100%;
  aspect-ratio: 1 / 0.85;
  height: auto;
  align-items: start;
  padding: 0px 8px 0;
  border: 0;
  border-radius: 10px;
  /* Band across the head of the well only. The stops had to tighten when the
     box grew to the well's full height — at 52%/100% they washed the icon. */
  background: linear-gradient(to bottom, rgb(9 3 17 / 64%) 0%, rgb(9 3 17 / 40%) 17%, rgba(9, 3, 17, 0) 34%);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.1;
  pointer-events: none;
}

.tb-beascuit-art-wrap {
  /* Definite box: the well must not change shape with the source art's aspect
     ratio, or one odd asset knocks its tile out of line with the others. */
  width: 100%;
  aspect-ratio: 1 / 0.85;
  display: grid;
  place-items: center;
  overflow: visible;
  border: 2px solid rgba(239, 217, 255, 0.34);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.01);
  box-shadow:
    0 8px 14px rgba(0, 0, 0, 0.45),
    inset 0 1px 10px rgba(255, 255, 255, 0.14);
}

.tb-team .tb-beascuit-art {
  width: auto;
  height: auto;
  max-width: 84%;
  max-height: 84%;
  object-fit: contain;
  filter: drop-shadow(0 6px 5px rgba(0, 0, 0, 0.5));
}

.tb-beascuit-empty-mark {
  color: rgba(239, 217, 255, 0.5);
  font-size: 30px;
}

.tb-beascuit-effects {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.tb-beascuit-effect {
  min-width: 0;
  height: 36px;
  display: grid;
  place-items: center;
  overflow: hidden;
  padding: 0 4px;
  border: 2px solid rgba(239, 217, 255, 0.3);
  border-radius: 10px;
  background: rgb(0 0 0 / 17%);
  color: var(--tb-text);
  font-size: 15px;
  line-height: 1.1;
  text-align: center;
  overflow-wrap: anywhere;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.5);
}

.tb-beascuit-effect.is-empty {
  border-style: dashed;
  border-color: rgba(239, 217, 255, 0.18);
  background: rgba(255, 255, 255, 0.04);
  color: rgba(239, 217, 255, 0.45);
}

/* Only ever rendered as the is-unlinked marker below. */
.tb-build-label {
  width: 100%;
  height: 40px;
  display: block;
  overflow: hidden;
  padding: 8px 10px 0;
  border: 2px solid rgba(239, 217, 255, 0.3);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.09);
  color: var(--tb-text);
  font-size: 19px;
  line-height: 1.2;
  text-align: center;
  white-space: nowrap;
  text-overflow: ellipsis;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.5);
}

.tb-build-label.is-unlinked {
  border-style: dashed;
  border-color: rgba(239, 217, 255, 0.2);
  background: rgba(255, 255, 255, 0.04);
  color: rgba(239, 217, 255, 0.55);
}

/* The row the two optional frames share.
 *
 * A flex box, and that is the point: one child fills it, two split it evenly,
 * and nothing has to ask which frames the build actually has. Every responsive
 * range below places this ONE element instead of placing each frame and then
 * correcting for the other's absence.
 *
 * Column by default, because the default tile is the poster's narrow column
 * (1241px and up) where two frames side by side would be ~95px each. The
 * ranges that have width to spare turn it into a row.
 *
 * Safe as a base rule despite base rules being the export: the poster is built
 * by build-graphic-export.js, whose tree has no .tb-detail-row at all, so this
 * selector cannot match there. */
.tb-detail-row {
  width: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.tb-detail-row > .tb-detail-frame {
  /* `1 1 0` not `1 1 auto`: an auto basis lets a long note claim more than half
     the row, and these two are meant to be equal whatever is in them. */
  flex: 1 1 0;
  min-width: 0;
}

.tb-detail-frame {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px 12px;
  border: 2px solid rgba(210, 151, 255, 0.4);
  border-radius: 12px;
  background: rgb(10 7 46 / 55%);
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.35);
}

.tb-detail-title {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  color: var(--tb-cyan);
  font-size: 22px;
  line-height: 1.1;
  letter-spacing: 0.02em;
  -webkit-text-stroke: 1px #080014;
  paint-order: stroke fill;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.62);
  border-bottom: 2px solid rgba(239, 217, 255, 0.55);
  padding-bottom: 4px;
  white-space: nowrap;
}

.tb-detail-body {
  min-width: 0;
}

.tb-detail-text {
  color: var(--tb-text);
  font-size: 17px;
  line-height: 1.3;
  white-space: pre-line;
  overflow-wrap: anywhere;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.42);
}

.tb-detail-priority-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.tb-detail-priority-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.tb-detail-priority-rank {
  flex: 0 0 auto;
  color: var(--tb-gold);
  font-size: 20px;
  line-height: 1.2;
  -webkit-text-stroke: 1px #080014;
  paint-order: stroke fill;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.65);
}

.tb-detail-priority-stat {
  min-width: 0;
  color: var(--tb-text);
  font-size: 20px;
  line-height: 1.2;
  overflow-wrap: anywhere;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.5);
}

.tb-detail-priority-text {
  margin-top: 2px;
  padding-left: 8px;
  border-left: 2px solid rgba(239, 217, 255, 0.3);
  color: var(--tb-text-soft);
  font-size: 18px;
  line-height: 1.3;
  white-space: pre-line;
  overflow-wrap: anywhere;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.42);
}

.tb-notes-section {
  padding: 20px 24px;
}

.tb-frame-title {
  display: inline-block;
  max-width: 100%;
  min-height: 40px;
  overflow: hidden;
  color: var(--tb-cyan);
  font-size: 36px;
  line-height: 1;
  -webkit-text-stroke: 1.5px #080014;
  paint-order: stroke fill;
  text-shadow: 0 3px 0 rgba(0, 0, 0, 0.62), 0 0 8px rgba(0, 0, 0, 0.72);
  border-bottom: 3px solid rgba(239, 217, 255, 0.92);
  padding-bottom: 5px;
  white-space: nowrap;
}

.tb-notes-body {
  max-height: 240px;
  margin-top: 14px;
  overflow: hidden;
  color: var(--tb-text);
  font-size: 28px;
  line-height: 1.26;
  white-space: pre-line;
  overflow-wrap: anywhere;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.42);
}

.tb-footer {
  width: 100%;
  height: 18px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--tb-text-soft);
  font-size: 26px;
  line-height: 1;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.7);
}

.tb-footer-source {
  display: flex;
  align-items: center;
  gap: 24px;
}

.tb-footer-url {
  color: var(--tb-cyan);
}

.tb-footer-date {
  color: var(--tb-text-soft);
}

.is-clipped {
  overflow: hidden;
}

/* ==========================================================================
   MODES AND RESPONSIVE BEHAVIOUR

   The base rules above ARE the export: a fixed 1920px, five-across poster.
   Nothing below changes that. The container is declared on the root so every
   region can respond, and every override lives in a `max-width` container
   query that a 1920px container can never satisfy. That ordering is
   deliberate - if container context ever failed to resolve inside the
   exporter's <foreignObject>, unmatched queries simply would not apply and
   the poster would still render five-across.

   View and edit diverge on narrow screens on purpose:
     --view  keeps the five-across read and scrolls sideways, so a saved build
             looks like the poster it exports to.
     --edit  reflows to a stack, because you cannot build a team through a
             window that shows one cookie at a time.
   ========================================================================== */

.tb-team {
  container-type: inline-size;
  container-name: tb-team;
}

/* On the page the card fills its column; the poster keeps the fixed width set
   in the base rule, so a missing modifier can never break the PNG. */
.tb-team--view,
.tb-team--screen {
  width: 100%;
  max-width: 1920px;
}

/* Belt and braces: no container query can collapse the poster's columns. */
.tb-team--export .tb-team-grid {
  grid-template-columns: repeat(5, 1fr) !important;
}

/* Watermarking is poster-only. */
.tb-team--view .tb-site-badge,
.tb-team--screen .tb-site-badge,
.tb-team--view .tb-footer,
.tb-team--screen .tb-footer {
  display: none;
}

/* Built on every render then hidden in the poster; the page wants the label. */
.tb-team--view .tb-treasure-heading,
.tb-team--screen .tb-treasure-heading {
  display: block;
  color: var(--tb-text-soft);
  font-size: 19px;
  letter-spacing: 0.04em;
  text-align: center;
}

@container tb-team (max-width: 1080px) {
  /* ---- One WIDE tile per row, in BOTH modes -------------------------
     The tall single-column tile is right when five of them sit side by side.
     Below that it stops being right: the old rule here reflowed the team to
     2 + 2 + 1, which let each tile grow back to full height and turned the
     builder into a very long scroll of very tall cards.

     So at this width the tile turns itself inside out instead. One tile per
     row, laid out as two columns (see the block below):

       cookie art  |  toppings
       beascuit    |  beascuit notes
       stat targets|  notes

     That trades height for width, which is the axis a phone or tablet has to
     spare — everything about one cookie fits on roughly one screen instead of
     three. `align-items: start` stops a short tile stretching to a tall
     neighbour's height.

     --screen, so the read-only card arranges its tiles the same way. It used
     to be --edit only, with --view keeping a horizontal rail of ~190px tiles
     on the grounds that five stacked tiles make a very long preview. That was
     the last thing the two modes disagreed about, and it did not survive the
     tile turning inside out: everything INSIDE a tile is shared, so a 190px
     rail tile was running the three-column layout written for a 1000px one —
     three columns of about 40px, with the stat-target text wrapping one
     character per line. A long preview beats an unreadable one, and the phone
     range already answers the length by collapsing four of the five tiles. */
  .tb-team--screen .tb-team-grid {
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
  }

  /* The fifth tile no longer needs centring — nothing is beside it. */
  .tb-team--screen .tb-team-grid > :nth-child(5) {
    grid-column: auto;
    justify-self: stretch;
    max-width: none;
  }

  /* ---- EDIT: the wide tile ------------------------------------------
     One tile per row, laid out as:

       art (hugs) | toppings (1fr) | stat targets (1fr)
       beascuit (half)             | notes (half)

     THREE columns, and row 2 deliberately does not use them.

     This was six equal columns — thirds on top, halves underneath — until the
     art column had to hug the portrait instead of padding it out. Those two
     wants are mutually exclusive on a shared track set: with the first pair of
     tracks `a` and the rest `b`, row 2 gives stats `2a + b` against notes
     `3b`, equal only when `a == b`. No column count fixes that; 8 or 12 lands
     on the same equation. The way out is for row 2 to stop being defined by
     the columns.

     So both row 2 frames occupy the SAME full-width cell and take half of it
     each, one aligned left and one right. Overlapping items in one cell is
     normally a bug; here it is what decouples the two rows, and it costs
     nothing because a half-width box cannot reach its twin. Row 1 is then free
     to size its columns however it likes. */
  /* The portrait's cap, as a variable because FIVE things are derived from it:
     the art track below, the topping grid's width cap, its per-cell cap, the
     empty-slot scaffold's cell cap, and the beascuit well's. Row 1 is level
     only while all of them agree, so the number lives in one place and a
     breakpoint that wants a smaller portrait sets THIS, never the track.
     (Lowering the track alone is exactly how row 1 came to be 28px out at
     1000px: the portrait shrank and the four boxes sized off 170 did not.)

     Declared on EVERY tile, deliberately — the layout properties below are the
     filled tile's alone, but the cap is not. One of those five consumers is
     the EMPTY tile's topping scaffold, and while the cap sat on
     `:not(.is-empty)` its `var()` resolved to nothing there. That does not
     degrade gracefully: an unresolvable var() is invalid at computed-value
     time and takes the whole `grid-template-columns` with it, so the
     declaration fell back to `none` and the 3x2 scaffold became six cells in
     one implicit column, centred in a full-width frame. Keep this rule and
     the `:not()` one separate; the three breakpoint overrides of this cap
     must stay un-`:not()`ed for the same reason. */
  .tb-team--screen .tb-cookie-tile {
    --tb-art-cap: 170px;
  }

  .tb-team--screen .tb-cookie-tile:not(.is-empty) {
    display: grid;
    /* The art track hugs the portrait — the portrait's own cap, restated as a
       track, so the column cannot be wider than what it holds. The 24% keeps
       it shrinking with the tile once the tile is too narrow for the cap, and
       keeps the two fr columns from being starved on the way down. */
    grid-template-columns: min(var(--tb-art-cap), 24%) minmax(0, 0.4fr) minmax(0, 0.6fr);
    align-items: start;
    justify-items: center;
    column-gap: 14px;
  }

  /* ---- ROW 1 IS THE PORTRAIT'S HEIGHT: the arithmetic ----
     The topping grid and the beascuit card are sized to come out level with
     the portrait, and both of them are in a different column, so neither can
     say "the art column's width" directly. A container unit looks like the
     answer and is not: the tile's rows are sized before the container size
     resolves, so 24cqw reads as its uncapped 170px during row sizing and the
     row comes out 170 no matter what the cells then do.

     So it is solved back from the sibling column instead, which every box in
     row 1 CAN see as its own 100%. With W the tile's content width and the
     art track at 24%:

       col = (W - 0.24W - 28) / 2  = 0.38W - 14      (28 = two 14px gaps)
       W   = (col + 14) / 0.38
       art = 0.24W = (col + 14) x 12/19

     19ths, not a rounded decimal, because 0.24 / 0.38 is exactly 12/19 and the
     two boxes have to agree to the pixel or the row picks the taller one.

     Both users below also cap at the value this yields once the art track is
     at its own 170px cap, which is where the formula stops applying. */



  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-art-wrap,
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-name {
    grid-column: 1;
    grid-row: 1;
  }

  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-topping-grid {
    grid-column: 2;
    grid-row: 1;
  }

  /* Row 1's third column, always. It used to belong to stat targets, with the
     beascuit taking it only when there was no stat frame and dropping to a half
     of row 2 when there was — four :has() combinations in all. Every one of
     them was correct in isolation and the set of them was impossible to tune,
     because moving a box to suit one combination moved it in the others too.
     The card now has one home. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card {
    grid-column: 3;
    grid-row: 1;
  }

  /* Both optional frames, as ONE item: full width of row 2, splitting it
     between however many of them exist (see .tb-detail-row). */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-detail-row {
    grid-column: 1 / -1;
    grid-row: 2;
    flex-direction: row;
    gap: 14px;
  }

  /* Full-width footers: neither belongs to a column. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-ghost-chips,
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-imported-note {
    grid-column: 1 / -1;
  }

  /* The overlay itself is defined once, unscoped by width, near the base
     .tb-cookie-name rule. All this layout changes about it is the cap: here
     the tile is full-card width, so a portrait scaled to 90% of it would be
     enormous. Both boxes take the same cap so the band still matches. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-name {
    width: min(100%, 220px);
  }

  /* The art and topping grid are 90% wide in the poster, where the tile is a
     narrow column. Here the tile is the full width of the card, so they cap
     instead of scaling — a 400px cookie portrait is not more informative than
     a 220px one, and the toppings want to stay thumb-sized rather than huge. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-art-wrap {
    width: min(100%, 220px);
  }

  /* Capped so the grid comes out the PORTRAIT'S HEIGHT rather than taller.
     The cells are square and the columns equal, so the grid's height follows
     from its width — this is arithmetic, not a guess:

       chrome  = 8px gap + 2x8px padding + 2x2px border = 28px vertically
                 16px gaps + 2x8px padding + 2x2px border = 36px horizontally
       height  = 2 x cell + 28, where cell = (width - 36) / 3
       so       width = 1.5 x (height - 28) + 36

     At the portrait's own 220px cap that comes to 324px. Written as the
     expression rather than the number so a change to the padding, the gap or
     the portrait cap carries through instead of the two silently drifting.

     It binds only where the column is wide enough to allow it — about a 900px
     tile and up. Narrower, the column itself is the limit and the grid ends up
     SHORTER than the portrait, which is the harmless direction to miss in. */
  /* The FRAME fills the column; the CELLS do not. Capping the grid's width was
     what left a gap either side of it — near 1240px the column is ~400px and
     the grid only wanted ~249px. So the box goes full width and the cap moves
     onto the tracks instead: each is the cell size that makes the grid the
     portrait's height, (170 - 28) / 2, or an equal share of the row once the
     column is too narrow for that. `justify-content: center` then centres the
     three tracks in the frame rather than letting them spread. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-topping-grid {
    width: min(100%, calc((var(--tb-art-cap) - 28px) * 1.5 + 36px));
    /* Fills the row rather than sitting at the top of it, so row 1 is three
       boxes of one height. The cells stay SQUARE and centre themselves in
       whatever height the row has — stretching the rows instead would make
       them taller than they are wide as the column narrows. The width cap
       above still makes the two meet exactly at the top of the range; below
       that the grid keeps the row's height with a little air above and below
       its cells. */
    /* Fills the row so all three of row 1 are one height, with the cells
       CENTRED inside rather than the rows stretched — stretched rows would
       grow taller than they are wide as the column narrows, and the cells are
       meant to be square. */
    align-self: stretch;
    align-content: center;
  }



  /* Stretch, not centre, for anything that is a framed box: a note frame
     hugging its text in the middle of the column reads as floating. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card,
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-detail-row,
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-ghost-chips {
    justify-self: stretch;
  }

  /* The beascuit well is a 1:0.85 box at 100% of its column. In the poster's
     narrow column that is a sensible badge; in a third of a full-width card it
     becomes a slab, and since it sets its row height everything beside it
     floats in a lake of empty. */
  /* The overlaid name is listed here so it tracks the well it sits on. It
     shares the well's grid cell, but the cell is the card's full width — only
     matching this cap keeps the band the same width as the frame under it. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) .tb-beascuit-art-wrap,
  .tb-team--screen .tb-cookie-tile:not(.is-empty) .tb-beascuit-name--overlay {
    width: min(100%, 190px);
    margin-inline: auto;
  }

  /* ---- 700-1240px: sizes that only apply once the tile is three columns ----
     The PLACEMENT for this range is in the block above, unconditional. What is
     gated here is the arithmetic that assumes three columns — below 700px the
     tile is two, and these caps would shrink the wrong things.

     This block used to hold four :has() combinations that moved the beascuit
     card and the two frames around depending on which frames existed. They are
     gone: row 1 is always art | toppings | beascuit, and the frames always
     share row 2. */
  @media (min-width: 700px) {
    /* ---- EDIT: the empty slot, echoing the filled tile ----
       One tile per row makes an empty slot the full width of the card, and the
       ghost topping scaffold inside it is a 3x2 of SQUARE cells at 100% — so at
       a 1000px tile it grew cells 320px wide and the placeholder came out about
       1000x800.

       It now uses the filled tile's own shape: a portrait-sized first column
       holding the + and its label, the scaffold beside it, and the same track
       cap the real topping grid uses. That both shrinks it and makes the empty
       state read as the layout it is about to become. */
    .tb-team--screen .tb-cookie-tile.is-empty {
      display: grid;
      grid-template-columns: min(170px, 24%) minmax(0, 1fr);
      align-items: center;
      justify-items: center;
      column-gap: 14px;
      row-gap: 4px;
    }

    .tb-team--screen .tb-cookie-tile.is-empty > .tb-empty-slot-mark {
      grid-column: 1;
      grid-row: 1;
      align-self: end;
    }

    .tb-team--screen .tb-cookie-tile.is-empty > .tb-empty-slot-label {
      grid-column: 1;
      grid-row: 2;
      align-self: start;
    }

    .tb-team--screen .tb-cookie-tile.is-empty > .tb-topping-grid.is-scaffold {
      grid-column: 2;
      grid-row: 1 / span 2;
      width: 100%;
      grid-template-columns: repeat(3, min(calc((var(--tb-art-cap) - 28px) / 2), calc((100% - 16px) / 3)));
      justify-content: center;
    }

    /* The FRAME fills its column; the CELLS do not. Capping the grid's width
       was what left a gap either side of it — near 1240px the column is ~400px
       and the grid only wanted ~249px. The box goes full width and the cap
       moves onto the TRACKS: each is the cell size that makes the grid the
       portrait's height, (170 - 28) / 2, or an equal share once the column is
       too narrow. `justify-content: center` centres them in the frame.

       The cap is the cell size that makes the 3x2 exactly the PORTRAIT'S
       height: (art - 28) / 2, since the grid is 2 cells plus 28px of gap,
       padding and border. Substituting the art formula from the block above,
       where 100% is this grid's own column:

         cell = ((col + 14) x 12/19 - 28) / 2 = (100% + 34px) x 6/19 - 14px

       34, not 14: a % in `grid-template-columns` is of the grid's CONTENT box,
       so col is 100% plus the grid's own 16px padding and 4px border.

       71px is the same thing once the art track is at its 170px cap. A cap
       frozen at that 71 was the bug: below about a 1200px tile the portrait is
       the 24% and shrinks, the grid did not, and the portrait ended up
       centred inside a row it was supposed to be setting.

       700px and up only. Below that the tile is two columns and the grid
       already fills its half, so capping the tracks there just shrank the
       cells. */
    .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-topping-grid {
      width: 100%;
      justify-self: stretch;
      grid-template-columns: repeat(
        3,
        min(
          calc((var(--tb-art-cap) - 28px) / 2),
          calc((100% + 34px) * 6 / 19 - 14px),
          calc((100% - 16px) / 3)
        )
      );
      justify-content: center;
    }

    /* The card lies on its side up in row 1: well on the left, a 2x2 of effects
       on the right. Standing upright would leave a third of the tile tall and
       half empty.

       Fixed 2x2, not auto-fit: auto-fit belongs to the phone layout, where the
       space beside the well swings between half a tile and the whole one. Here
       it is always a third of row 1, and four across would read as a strip. */
    .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card {
      grid-template-columns: minmax(0, 50%) minmax(0, 1fr);
      align-items: center;
      column-gap: 2px;
      width: 100%;
      /* The short box of the three, so it fills the row like the topping grid
         does. `align-items: center` then centres the well and the effects in
         whatever height the row has. */
      align-self: stretch;
      /* The base card carries `min-height: 170px` for the POSTER, where it is
         a narrow upright column and the floor keeps it from collapsing. Lying
         down that floor is a hard 170 the card reports no matter how narrow
         its column is, so it — not the portrait — set row 1 through the whole
         band, and the portrait sat centred in a row up to 48px taller than
         itself. Here the well's cap below holds the card up instead. */
      min-height: 0;
    }

    .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card > .tb-beascuit-effects {
      grid-column: 2;
      grid-row: 1;
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* The card has to come out the portrait's height, and it is the box that
       overshoots: at a 190px well its 1:0.85 shape plus the card's own 8px
       padding and 2px border top and bottom came to 182 against the portrait's
       170, so the card set the row.

       Solved back from the height: card = well x 0.85 + 20, so a
       portrait-height card wants a well (art - 20) / 0.85 wide. Here 100% is
       the WELL's own grid area — half the card's content box — so the art
       formula from the top of this block reads (2 x 100% + 34px) x 12/19. The
       190px cap still applies above it, and 170px caps the art the same way it
       does for the topping cells. */
    .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card > .tb-beascuit-art-wrap,
    .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card > .tb-beascuit-name--overlay {
      width: 100%;
      max-width: min(190px, calc((min(var(--tb-art-cap), (2 * 100% + 34px) * 12 / 19) - 20px) / 0.85));
    }
  }

  /* ---- both ---- */
  .tb-header {
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
  }

  .tb-header-right {
    flex: 0 0 auto;
  }

  .tb-treasure-row {
    justify-content: center;
  }
}

@container tb-team (max-width: 620px) {
  .tb-team--screen .tb-team-grid > :nth-child(5) {
    grid-column: auto;
    justify-self: stretch;
    max-width: none;
  }

  .tb-team--screen .tb-cookie-art-wrap,
  .tb-team--screen .tb-topping-grid {
    width: min(100%, 320px);
  }

  .tb-topping-cell {
    /* Never let a tap target fall below the accessible minimum. */
    min-width: 44px;
  }

  .tb-treasure-card {
    width: clamp(84px, 28cqi, 140px);
  }
}

/* ==========================================================================
   EDIT MODE

   Interactive chrome only. The layout is inherited unchanged from the base
   rules, so the builder and the poster are the same tile - the scaffold IS
   the finished card with its content missing.
   ========================================================================== */

/* ---- stat rows: an accordion once there are two ----
   Collapsed hides the target field but keeps the header, so the frame still
   reads as a list of stats — and shows the target as a one-line summary so you
   do not have to open a row to remember what is in it. */
.tb-team--edit .tb-detail-priority-row.is-collapsed > .tb-detail-priority-text {
  display: none;
}

.tb-team--edit .tb-detail-priority-summary {
  overflow: hidden;
  padding: 0 2px;
  color: rgba(255, 255, 255, 0.62);
  font-size: 12px;
  line-height: 1.25;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* The rank doubles as the toggle when the list is an accordion. */
.tb-team--edit .tb-detail-priority-row.is-collapsible .tb-detail-priority-rank {
  cursor: pointer;
  user-select: none;
}

.tb-team--edit .tb-detail-priority-row.is-collapsible .tb-detail-priority-rank::after {
  content: "▾";
  margin-left: 3px;
  font-size: 9px;
  vertical-align: middle;
}

.tb-team--edit .tb-detail-priority-row.is-collapsed .tb-detail-priority-rank::after {
  content: "▸";
}

.tb-team--edit [data-tb-action] {
  cursor: pointer;
}

.tb-team--edit [data-tb-action]:focus-visible,
.tb-popover [data-tb-value]:focus-visible {
  outline: 3px solid var(--tb-cyan);
  outline-offset: 2px;
}

/* Empty cells read as "fill me", not as broken. */
.tb-team--edit .tb-topping-cell.is-empty {
  border-style: dashed;
  border-color: rgba(210, 151, 255, 0.5);
  background: rgba(255, 255, 255, 0.05);
  transition: background 120ms ease, border-color 120ms ease;
}

.tb-team--edit .tb-topping-cell.is-empty::after {
  content: "+";
  color: rgba(239, 217, 255, 0.5);
  font-size: 28px;
  line-height: 1;
}

.tb-team--edit .tb-topping-cell.is-tart.is-empty {
  /* The tart cell keeps its gold identity even when empty - in the base sheet
     .is-empty lands later at equal specificity and washes it out. */
  border-color: rgba(255, 220, 124, 0.6);
}

.tb-team--edit .tb-topping-cell:hover,
.tb-team--edit .tb-cookie-art-wrap:hover {
  border-color: var(--tb-cyan);
  background: rgba(134, 221, 255, 0.12);
}

.tb-team--screen .tb-cookie-art-wrap {
  /* border: 2px dashed transparent; */
  transition: border-color 120ms ease, background 120ms ease;
}

/* The scaffold: shape legible, obviously not yet usable. */
.tb-team--edit .tb-cookie-tile.is-empty {
  gap: 10px;
}

.tb-topping-grid.is-scaffold {
  opacity: 0.28;
  pointer-events: none;
}

.tb-team--edit .tb-cookie-tile.is-empty:hover {
  border-color: var(--tb-cyan);
  background: rgba(134, 221, 255, 0.06);
}

/* Beascuit variant arrows, drawn in CSS - no assets. */
.tb-beascuit-step {
  position: absolute;
  top: 50%;
  width: 34px;
  height: 34px;
  margin-top: -17px;
  display: grid;
  place-items: center;
  border: 2px solid rgba(210, 151, 255, 0.7);
  border-radius: 50%;
  background: rgba(20, 6, 30, 0.75);
  cursor: pointer;
}

/* The chevron is a box wearing only a top and a right border, rotated. That
   makes its INK sit up and to the right of its own box centre, so
   `place-items: center` on the button centres the wrong thing — the box, not
   the mark. The translate below is what cancels that.

   For a content box of `s` with borders of `b`, the ink's centre of mass is
   exactly (s/4, -s/4) from the box centre — the border width falls out of the
   arithmetic entirely, which is why only the glyph size appears here.

   BOTH arrows take the SAME translate, and that is the part that reads wrong
   at a glance. The translate is applied before the rotation (transforms
   compose right to left), and the target is zero offset, so the rotation
   cannot matter: whatever angle the mark ends up at, the correction is the
   same. --prev used `translate(-2px, -2px)` — the y sign flipped, as if the
   compensation had been mirrored along with the arrow — which pushed its mark
   3.2px left and 2.8px down inside a 34px button while --next sat centred.

   Derived from the size rather than hard-coded, because the button shrinks at
   narrow widths: a fixed 2px was already only approximating the 2.25px this
   size needs, and at the 6px glyph below it was out by more than the mark. */
.tb-beascuit-step::before {
  --tb-chevron-size: 9px;
  content: "";
  width: var(--tb-chevron-size);
  height: var(--tb-chevron-size);
  border-top: 3px solid var(--tb-text);
  border-right: 3px solid var(--tb-text);
}

.tb-beascuit-step--prev {
  left: -10px;
}

.tb-beascuit-step--prev::before {
  transform: rotate(-135deg)
    translate(calc(var(--tb-chevron-size) / -4), calc(var(--tb-chevron-size) / 4));
}

.tb-beascuit-step--next {
  right: -10px;
}

.tb-beascuit-step--next::before {
  transform: rotate(45deg)
    translate(calc(var(--tb-chevron-size) / -4), calc(var(--tb-chevron-size) / 4));
}

.tb-beascuit-step:hover {
  border-color: var(--tb-cyan);
  background: rgba(134, 221, 255, 0.25);
}

.tb-team--screen .tb-beascuit-art-wrap {
  /* Anchors the cycler arrows. Scoped to --edit: making this positioned in the
     poster changes paint order against its siblings and moves pixels. */
  position: relative;
}

/* Tainted variants spend slot 0 on their elemental damage; it is not a choice. */
.tb-team--edit .tb-beascuit-effect.is-locked {
  opacity: 0.75;
  cursor: not-allowed;
}

.tb-team--edit .tb-beascuit-effect.is-empty {
  border-style: dashed;
}

/* Optional frames are offered as footnotes, not calls to action. */
.tb-ghost-chips {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
}

.tb-ghost-chip {
  padding: 3px 10px;
  border: 1px dashed rgba(239, 217, 255, 0.4);
  border-radius: 999px;
  color: rgba(239, 217, 255, 0.62);
  font-size: 13px;
  line-height: 1.5;
  cursor: pointer;
}

.tb-ghost-chip:hover {
  border-color: var(--tb-cyan);
  color: var(--tb-cyan);
}

.tb-ghost-chip--inline {
  align-self: flex-start;
  margin-top: 4px;
}

.tb-team--screen .tb-detail-title {
  /* Anchors the frame's remove control. Scoped for the same reason. */
  position: relative;
}

.tb-detail-remove,
.tb-row-remove {
  position: absolute;
  top: 50%;
  right: 0;
  width: 20px;
  height: 20px;
  margin-top: -10px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: rgba(239, 217, 255, 0.6);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}

.tb-row-remove {
  position: static;
  margin: 0;
  flex: 0 0 auto;
}

.tb-detail-remove:hover,
.tb-row-remove:hover {
  color: #ff9bb5;
  background: rgba(255, 155, 181, 0.14);
}

/* Inputs inherit the card's type so an editable frame looks like the frame it
   becomes, not like a form dropped on top of it. */
.tb-input {
  width: 100%;
  padding: 4px 6px;
  border: 1px solid rgba(210, 151, 255, 0.45);
  border-radius: 8px;
  background: rgba(10, 4, 16, 0.55);
  color: var(--tb-text);
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  resize: vertical;
}

.tb-input:focus {
  outline: none;
  border-color: var(--tb-cyan);
}

select.tb-input {
  resize: none;
}

.tb-imported-note {
  width: 100%;
  color: rgba(239, 217, 255, 0.6);
  font-size: 12px;
  text-align: center;
}

.tb-tile-menu {
  position: absolute;
  top: 6px;
  right: 8px;
  z-index: 2;
  width: 26px;
  height: 22px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  color: rgba(239, 217, 255, 0.7);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}

.tb-tile-menu:hover {
  color: var(--tb-text);
  background: rgba(255, 255, 255, 0.12);
}

.tb-team--screen .tb-cookie-tile {
  position: relative;
}

/* ---- popovers: reparented to <body> to escape the tile's overflow ---- */
.tb-popover {
  position: absolute;
  /* Above every stacking context this site creates - the highest in the route
     stylesheets is 1700 (the cookie picker shell). */
  z-index: 2000;
  /* Wide enough for three topping tiles or four tart tiles a row (see the two
     --topping/--tart body rules), and still never wider than the screen. */
  width: min(460px, calc(100vw - 24px));
  max-height: 60vh;
  overflow-y: auto;
  padding: 10px;
  border: 4px solid;
  border-color: rgba(210, 151, 255, 0.5);
  border-radius: 14px;
  background: #1b0722;
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.7);
  color: var(
  --tb-text);
  font-family:
  "CookieRun KR", "Outfit", sans-serif;
}

/* The blur an open picker sits on, created by the editor for the three value
   pickers and torn down with them. backdrop-filter blurs what is behind its
   OWN element, so this full-viewport layer is the mechanism rather than a
   tint over one.

   1999 is deliberate: directly under the popover's 2000 and above everything
   else the site stacks, including the guide builder's team-build modal, which
   sits at 1900 precisely so it cannot bury these popovers — inside that modal
   the modal IS the page behind the picker, so it should blur with the rest.

   It IS the click-catcher, which is the point: an outside click closes the
   popover and does nothing else. Without it the click closed the popover AND
   landed on whatever was underneath, and the miss that actually happened was
   dismissing a topping picker onto the cookie portrait — which opened the
   cookie modal BEHIND the topping popover and left both on screen. The cost
   is a second tap to reach the next control, and it buys a dismissal that
   cannot misfire. (It was pointer-events: none when it was only a blur.) */
.tb-popover-scrim {
  position: fixed;
  inset: 0;
  z-index: 1999;
  background: rgba(12, 3, 18, 0.35);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  animation: tb-popover-scrim-in 120ms ease-out;
}

/* Opacity only — nothing moves, so this is safe under reduced motion. */
@keyframes tb-popover-scrim-in {
  from {
    opacity: 0;
  }
}

.tb-popover-title {
  margin-bottom: 8px;
  color: var(--tb-cyan);
  font-size: 15px;
}

.tb-popover-body {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* The icon pickers lay out as a grid rather than wrapped flex, because a
   fixed `flex-basis: 50%` is what locked them to two columns no matter how
   wide the popover got. auto-fill + a minimum tile width lets the column
   count follow the available width instead, so these also collapse sensibly
   on a narrow phone rather than overflowing.

   The two minimums differ because the tiles do: a topping tile carries the
   icon AND a ×5 button beside it, a tart tile is just the icon. They are sized
   off the icon sizes further down — bump one and check the other. */
.tb-popover-body--topping {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 136px), 1fr));
}

.tb-popover-body--tart {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 100px), 1fr));
}

/* Bonus effects are text plus a ×N button. Two columns at the wide popover:
   the labels run to "DMG Resist Bypass", and squeezing three across would
   truncate the one thing that identifies the option. */
.tb-popover-body--effect {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 165px), 1fr));
}

/* The footer actions span the grid instead of becoming another cell. */
.tb-popover-body--topping .tb-popover-actions,
.tb-popover-body--tart .tb-popover-actions,
.tb-popover-body--effect .tb-popover-actions {
  grid-column: 1 / -1;
}

.tb-popover-option {
  /* flex: 1 1 calc(50% - 6px); */
  min-width: 0;
  width: fit-content;
  display: flex;
  align-items: center;
  gap: 8px;
  background: #0000006e;
  padding: 6px 8px;
  border: 1px solid #764f91;
  border-radius: 10px;
  font-size: 13px;
  cursor: pointer;
}

.tb-popover-option img {
  width: 76px;
  height: 76px;
  flex: 0 0 auto;
  object-fit: contain;
}

.tb-popover-option span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tb-popover-option:hover {
  background: rgba(134, 221, 255, 0.14);
}

.tb-popover-option.is-selected {
  border-color: var(--tb-cyan);
  background: rgba(134, 221, 255, 0.2);
}

/* ---- icon-first options (topping + tart pickers) ----
   The name is a tooltip and an aria-label rather than a visible column, which
   frees the width for an icon big enough to recognise at a glance.

   Toppings spend that freed width on a per-option "Use ×5"; tarts have nothing
   to put there — one tart per slot means no ×5 to offer — so they are icon and
   nothing else, and the tile itself stays the click target. That is the whole
   difference between `--icon` and `--icon --split`. */
.tb-popover-option--icon {
  gap: 6px;
  padding: 4px 6px;
  justify-content: center;
  justify-self: center;
  width: auto;
}

.tb-popover-option--icon img {
  width: 56px;
  height: 56px;
}

/* Tarts run bigger than toppings AND keep a name, because they are the hard
   ones to tell apart: every tart is the same star biscuit with a different
   small corner gem, whereas the toppings are ten distinct pictures. The name
   sits under the icon rather than beside it, so it costs a little height per
   tile instead of the width the bigger icon just bought. */
.tb-popover-body--tart .tb-popover-option {
  flex-direction: column;
  gap: 4px;
  padding: 6px 4px;
}

.tb-popover-body--tart .tb-popover-option--icon img {
  width: 76px;
  height: 76px;
}

/* Wraps to a second line rather than ellipsising — at this width "Searing
   Raspberry" would otherwise be cut to "Searing Raspber…", which reads like a
   different tart. Two lines is the ceiling; nothing in the set needs three.

   Written as `.tb-popover-option .tb-popover-name` on purpose: the generic
   `.tb-popover-option span` rule above sets `white-space: nowrap`, and an
   element+class selector outranks a bare class — so a lone `.tb-popover-name`
   loses that one property and the label silently goes back to one clipped
   line. */
.tb-popover-option .tb-popover-name {
  width: 100%;
  color: var(--tb-text-soft);
  font-size: 9px;
  line-height: 1.2;
  text-align: center;
  white-space: normal;
  overflow-wrap: break-word;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

/* Split tiles have TWO click targets inside them, so the whole-tile hover is
   cancelled and hover moves onto whichever half the pointer is over. Without
   that, hovering ×5 lights up the icon too and the tile reads as one button
   when it is two. */
.tb-popover-option--split {
  justify-content: flex-start;
  cursor: default;
}

.tb-popover-option--split:hover {
  background: none;
}

.tb-popover-pick {
  flex: 0 0 auto;
  display: flex;
  padding: 3px;
  border-radius: 10px;
  cursor: pointer;
}

.tb-popover-pick:hover {
  background: rgba(134, 221, 255, 0.2);
}

/* The text half of a bonus-effect option. Takes the slack so the ×N button
   keeps a fixed width down the column rather than jittering with label
   length. */
.tb-popover-pick--text {
  flex: 1 1 auto;
  min-width: 0;
  align-items: center;
  padding: 3px 5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* In a topping tile the icon is fixed and the button takes the slack, so every
   ×5 lines up down the column. In an effect tile it is the other way round —
   the text takes the slack (see --text above) and the button holds a fixed
   width, or a short label like ATK would leave a stretched ×4 next to it. */
.tb-popover-fill {
  /* flex: 1 1 auto; */
  min-width: 2.6em;
  padding: 6px 8px;
  border: 1px solid rgba(210, 151, 255, 0.5);
  border-radius: 9px;
  font-size: 12px;
  line-height: 1.1;
  text-align: center;
  white-space: nowrap;
  cursor: pointer;
}

.tb-popover-body--effect .tb-popover-fill {
  flex: 0 0 auto;
}

.tb-popover-fill:hover {
  border-color: var(--tb-cyan);
  background: rgba(134, 221, 255, 0.16);
}

.tb-popover-actions {
  width: 100%;
  display: flex;
  gap: 8px;
  margin-top: 6px;
  padding-top: 8px;
  border-top: 1px solid rgba(210, 151, 255, 0.3);
}

.tb-popover-action {
  flex: 1 1 auto;
  padding: 6px 8px;
  border: 1px solid rgba(210, 151, 255, 0.5);
  border-radius: 10px;
  font-size: 13px;
  text-align: center;
  cursor: pointer;
}

.tb-popover-action:hover {
  border-color: var(--tb-cyan);
  background: rgba(134, 221, 255, 0.16);
}

/* The poster shrinks frame titles to fit with its JS fitter, which does not
   run on the page - so "STAT TARGETS & PRIORITY" was clipped in a page-width
   tile. Size it down and let it wrap instead. Scoped away from --export so
   the poster keeps its measured 22px. */
.tb-team--view .tb-detail-title,
.tb-team--screen .tb-detail-title {
  display: block;
  overflow: visible;
  white-space: normal;
  font-size: 14px;
  text-wrap: balance;
}

/* ==========================================================================
   PAGE TYPE + SPACING SCALE

   Every size above was measured for a 1920px poster that is normally viewed
   scaled down. On the page the card renders roughly 1:1 in a narrower column,
   so those sizes read oversized - the header especially. This section brings
   the page rendering down to a comfortable scale.

   Deliberately limited: the cookie tile's own content (art, name, topping
   grid, beascuit card) is already right and is left alone. Only the header,
   the treasure panel, the detail frames and the team-notes panel move.

   Scoped away from --export, which keeps its measured values.
   ========================================================================== */

/* ---- header ---- */
.tb-team--view .tb-header-left,
.tb-team--screen .tb-header-left,
.tb-team--view .tb-header-right,
.tb-team--screen .tb-header-right {
  padding: 8px;
}

.tb-team--view .tb-build-title-card,
.tb-team--screen .tb-build-title-card {
  padding: 4px 8px;
  gap: 8px;
  align-items: center;
}

.tb-team--view .tb-build-name,
.tb-team--screen .tb-build-name {
  min-width: 0;
  height: auto;
  font-size: 26px;
  line-height: 1.15;
}

.tb-team--view .tb-build-subtitle-line,
.tb-team--screen .tb-build-subtitle-line {
  height: auto;
  font-size: 15px;
}

.tb-team--view .tb-build-subtitle-credit,
.tb-team--screen .tb-build-subtitle-credit {
  height: auto;
  font-size: 13px;
}

.tb-team--view .tb-build-subtitle,
.tb-team--screen .tb-build-subtitle {
  gap: 12px;
}

/* ---- treasures ---- */
.tb-team--view .tb-treasure-row,
.tb-team--screen .tb-treasure-row {
  gap: 2px;
}

.tb-team--view .tb-treasure-card,
.tb-team--screen .tb-treasure-card {
  /* Wide enough for two lines of a long treasure name without breaking
     mid-word. */
  width: 96px;
  gap: 6px;
}

.tb-team--view .tb-treasure-art-wrap,
.tb-team--screen .tb-treasure-art-wrap {
  width: 72px;
  height: 72px;
  border-radius: 14px;
}

.tb-team--view .tb-treasure-art,
.tb-team--screen .tb-treasure-art {
  width: 60px;
  height: 60px;
}

.tb-team--view .tb-treasure-empty-mark,
.tb-team--screen .tb-treasure-empty-mark {
  font-size: 26px;
}

.tb-team--view .tb-treasure-name,
.tb-team--screen .tb-treasure-name {
  height: 30px;
  font-size: 12px;
  line-height: 1.2;
}

.tb-team--view .tb-treasure-panel,
.tb-team--screen .tb-treasure-panel {
  gap: 6px;
}

/* ---- detail frames: the description text is the main offender ---- */
.tb-team--view .tb-detail-text,
.tb-team--screen .tb-detail-text,
.tb-team--view .tb-detail-body,
.tb-team--screen .tb-detail-body {
  font-size: 12px;
  line-height: 1.35;
}

.tb-team--view .tb-detail-priority-text,
.tb-team--screen .tb-detail-priority-text {
  padding-left: 6px;
  font-size: 12px;
  line-height: 1.35;
}

.tb-team--view .tb-detail-priority-rank,
.tb-team--screen .tb-detail-priority-rank,
.tb-team--view .tb-detail-priority-stat,
.tb-team--screen .tb-detail-priority-stat {
  font-size: 14px;
}

.tb-team--view .tb-detail-priority-list,
.tb-team--screen .tb-detail-priority-list,
.tb-team--view .tb-detail-priority-row,
.tb-team--screen .tb-detail-priority-row {
  gap: 6px;
}

/* Keep the frame's remove control off the title text. */
.tb-team--screen .tb-detail-title {
  padding-right: 22px;
}

/* ---- team notes panel ---- */
.tb-team--view .tb-frame-title,
.tb-team--screen .tb-frame-title {
  min-height: 26px;
  font-size: 18px;
}

.tb-team--view .tb-notes-body,
.tb-team--screen .tb-notes-body {
  font-size: 15px;
  line-height: 1.35;
}


/* ==========================================================================
   HEADER TREATMENT (page only)
   ========================================================================== */

/* Character art anchored to the left of the header, behind the title card.
   overflow:hidden keeps it inside the panel's rounded corners. */
.tb-team--view .tb-header,
.tb-team--screen .tb-header {
  position: relative;
  overflow: hidden;
  align-items: stretch;
  /* Tall enough to show the character whole at a readable size, which also
     gives the bottom-aligned title card something to overlap. */
  min-height: 200px;
  background-image: url("/assets/team-builds-header-bg.png");
  background-repeat: no-repeat;
  background-position: left bottom;
  background-size: auto 100%;
  flex-direction: row;
}

/* Bottom-left: the header stretches its columns, so the title card drops to
   the bottom of its own column while align-self keeps it hard left. */
.tb-team--view .tb-header-left,
.tb-team--screen .tb-header-left {
  justify-content: flex-end;
}

/* Keeps the title card and treasures above the character art. */
.tb-team--view .tb-build-title-card,
.tb-team--screen .tb-build-title-card,
.tb-team--view .tb-header-right,
.tb-team--screen .tb-header-right {
  position: relative;
  z-index: 1;
}

/* TREASURES heading. The element already carries .tb-outline, so the stroke
   and shadow come from there; this is colour, face and size. */
.tb-team--view .tb-treasure-heading,
.tb-team--screen .tb-treasure-heading {
  color: #ffffff;
  font-family: "CookieRun KR", "CookieRunExport", "Outfit", sans-serif;
  font-weight: 700;
  font-size: 24px;
  height: auto;
  line-height: 1.15;
}


/* ==========================================================================
   MOBILE BAND-AID (temporary)

   Tightens the on-page card for phones after the team-builder rebuild.
   Deliberately blunt: it drops chrome (header art, the title column, per-item
   labels) and reclaims the padding they cost, rather than reflowing anything.
   Intended to be replaced by a proper narrow-width pass, so it is kept as one
   removable block at the end of the file rather than folded into the sections
   above.

   Two constraints shaped it:

   1. Every rule is scoped to --view/--edit. Several of these targets are
      styled by bare selectors in the base rules, and a bare override here
      would reach the 1920px --export poster whenever a phone is the device
      rasterising the PNG - `.tb-team-section { padding: 8px }` alone would
      move it. Scoping by mode is what keeps the export defined by the base
      rules, exactly as the note at the top of this file requires.

   2. It is @media, not @container, because a container query resolves against
      an ANCESTOR container. `.tb-team` IS the container, so a rule for it
      inside `@container tb-team (…)` can never match its own root and the
      padding override would silently do nothing. Descendants could have used
      @container, but splitting the block across two mechanisms would let the
      root and its children switch over at different widths.

   699px is the canonical site mobile boundary (see the route stylesheets).
   ========================================================================== */

@media (max-width: 699px) {
  /* ---- card shell ---- */
  .tb-team--view,
  .tb-team--screen {
    padding: 4px;
  }

  .tb-team--view .tb-team-section,
  .tb-team--screen .tb-team-section {
    padding: 8px;
  }

  /* ---- header: title column and character art both go ---- */
  .tb-team--view .tb-header-left,
  .tb-team--screen .tb-header-left {
    display: flex;
    justify-self: end;
  }

  /* The saved-build preview used to strip this header down to bare treasure
     wells here — no character art, no TREASURES heading, no treasure names, a
     1rem build name and no min-height. That was written for a version of this
     range where --view also hid .tb-header-left, so the panel would otherwise
     have been mostly empty above a 72px row. The column is shown in both trees
     now (see the rule above), so those overrides only made the preview
     disagree with the builder about the same header.

     They are gone rather than paired: every other header rule in this file is
     written for both trees, and --view has no reason to differ. If the phone
     header needs to shed weight, shed it on --screen so the builder and the
     preview shed it together. */

  .tb-team--view .tb-build-subtitle,
  .tb-team--screen .tb-build-subtitle {
    display: block;
  }

  /* Empty slots keep their dashed "add one" look - that rule is more specific
     (.tb-treasure-card.is-empty .tb-treasure-art-wrap) and still wins. */
  .tb-team--view .tb-treasure-art-wrap,
  .tb-team--edit .tb-treasure-art-wrap {
    background: rgb(148 5 168 / 86%);
  }

  /* ---- cookie tile: art and toppings carry it, labels drop ---- */
  .tb-team--view .tb-cookie-tile,
  .tb-team--screen .tb-cookie-tile {
    gap: 6px;
  }

  /* The --edit half has to match the wide-tile overlay selector's specificity
     (0,4,0 with the :not()) or it loses on specificity, not source order, and
     the name paints over the portrait on a phone. Media-query nesting gives no
     weight of its own. */
  .tb-team--view .tb-cookie-name,
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-name,
  .tb-team--screen .tb-cookie-name {
    display: none;
  }

  /* No wide-tile row-span override is needed here any more. It existed because
     the topping grid and beascuit spanned the art AND name rows, and hiding
     the name just above left column 1 a row short. The name now shares the
     art's cell instead of taking a row, so there is nothing to compensate
     for. */

  /* Same 90% as the base rule; restated to undo the `min(100%, 320px)` cap the
     narrow-container edit rule applies. */
  .tb-team--view .tb-cookie-art-wrap,
  .tb-team--screen .tb-cookie-art-wrap {
    width: 90%;
  }

  .tb-team--view .tb-topping-grid,
  .tb-team--screen .tb-topping-grid {
    width: 96%;
  }

  /* --edit is exempt now: the name is overlaid on the well rather than
     stacked above it, so it costs no height and there is nothing to reclaim
     by dropping it. --view still stacks it, so it still goes. */
  .tb-team--view .tb-beascuit-name,
  .tb-team--screen .tb-beascuit-name:not(.tb-beascuit-name--overlay) {
    display: none;
  }

  .tb-team--view .tb-imported-note,
  .tb-team--screen .tb-imported-note {
    display: none;
  }

  /* ---- EDIT: the phone tile ------------------------------------------
     The square portrait and its overlaid name give way to the Cookie-Dex
     "Comfy" cookie card (see assets/css/dex-cookie-card.css), which is short,
     wide and full-bleed — the one shape that reads at 300-something px:

       cookie card (full width)
       toppings  | stat targets
       beascuit  | notes

     The portrait is not restyled into the card; it is hidden and a separate
     card element takes its place, rendered in EDIT MODE ONLY. That keeps the
     poster's tree free of it entirely rather than merely styled around it.

     Every rule below restates a wide-tile property rather than relying on
     source order: the container query at <= 1080px also matches at these
     widths, and media-query nesting carries no specificity of its own, so
     these selectors have to match its (0,5,0) shape to win. */
  /* 40/60, the same bias row 1 of the wide tile has: the beascuit card holds a
     well, a name and four effect chips beside it, the topping grid holds six
     square cells that are happy to shrink. Written as fr so the two tracks
     still absorb the gap between them — 40%/60% would add up to the whole
     tile and push the pair 6px wide. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) {
    grid-template-columns: minmax(0, 0.4fr) minmax(0, 0.6fr);
    column-gap: 6px;
  }

  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-dexcard {
    display: block;
    grid-column: 1 / -1;
    grid-row: 1;
    width: 100%;
    justify-self: stretch;
  }

  /* The card replaces both, so neither may keep a cell. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-art-wrap {
    display: none;
  }

  /* Companion to --tb-cookie-name-nudge, for this range. That dial moves the
     name plate overlaid on the square portrait, and the portrait is hidden
     here — the name you see below 700px belongs to the Dex card and is a
     different element on a different stylesheet, so the other dial has nothing
     to move. Positive is down, negative is up; set it on the card.

     A transform again, and for the same reason: the frame is laid out by the
     card's own stack, and JS measures the name to compute
     --cookie-name-fit-scale. A transform changes neither. Three classes so it
     outranks dex-cookie-card.css's own `.tb-dexcard .cookie-name`, which loads
     after this file. */
  .tb-team--view .tb-dexcard,
  .tb-team--screen .tb-dexcard {
    --tb-dexcard-name-nudge: 0px;
  }

  .tb-team--view .tb-dexcard .cookie-name,
  .tb-team--screen .tb-dexcard .cookie-name {
    transform: translateY(var(--tb-dexcard-name-nudge, 0px));
  }

  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-topping-grid {
    grid-column: 1;
    grid-row: 2;
    width: 100%;
    /* Stretch, not start: the two frames in this row are meant to come out the
       same height, and either one can be the taller. The beascuit card already
       stretched; this is the other half of that, for the widths where the
       card's bonus effects stack into four rows and IT is the tall one. Left
       at `start` the topping frame just ended early and the row looked broken
       under the Dex card. The cells stay their own size — the extra height
       lands in the frame around them. */
    align-self: stretch;
  }

  /* Beside the toppings, always — the same shape as the wide tile one row
     down. The column used to belong to stat targets, with the beascuit card
     taking it only when there was no stat frame; that was the phone half of
     the :has() scheme and it is gone with the rest of it. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card {
    grid-column: 2;
    grid-row: 2;
    width: auto;
    justify-self: stretch;
    /* The pair fills the row, the way row 1 of the wide tile does. The base
       card is `align-self: center` for the poster's column; left alone here it
       floated 9px below the topping grid beside it at the top of this range,
       where the grid is the taller of the two. */
    align-self: stretch;
    /* And the stretch has to be allowed to work. The base card carries
       `min-height: 170px` for the POSTER, where it is a narrow upright column
       and the floor stops it collapsing. Lying down — which is what this range
       does to it — that floor is a hard 170 the card reports however short its
       content is, so the card set the row height by itself and stood up to
       50px taller than the topping grid beside it. The wide layout drops the
       floor for exactly this reason; this range had been missing that half.
       The well's own aspect ratio holds the card up instead. */
    min-height: 0;
  }

  /* Both optional frames as ONE item, sharing row 3 between however many of
     them the build has (see .tb-detail-row). */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-detail-row {
    grid-column: 1 / -1;
    grid-row: 3;
    flex-direction: row;
    /* The tile's own column-gap, so the seam between the two frames lines up
       with the one between the toppings and the beascuit card above them. */
    gap: 6px;
  }

  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-ghost-chips {
    grid-column: 1 / -1;
    grid-row: 4;
  }

  /* ---- the beascuit card turns on its side ----
     The card is a column everywhere else: well on top, bonus effects under it.
     In half a phone tile that stacks two tall boxes in a narrow strip. Laid
     across instead, the well and the effects share the height.

     Only the effects need placing: the well and its overlaid name are already
     pinned to row 1 / column 1 by the --edit rule that gives them a cell to
     share, and that placement is exactly what this wants. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card {
    grid-template-columns: minmax(0, 44%) minmax(0, 1fr);
    align-items: center;
    column-gap: 8px;
  }

  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card > .tb-beascuit-effects {
    grid-column: 2;
    grid-row: 1;
  }

  /* Laying the card across shrinks the well to a fraction of half a tile — 57px
     at a 430px phone — and a fixed 14px label covers the icon it names. Scaled
     with the page instead, capped at the size it already had so the top of this
     range is unchanged. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) .tb-beascuit-name--overlay {
    padding: 3px 4px 0;
  }

  /* Effects fit as many columns as the space beside the well allows, which
     varies a lot here: the card is half a tile at 430px and the full tile at
     390px, so a viewport threshold would be guessing at the wrong number. A
     60px floor is what keeps "Bonus Effect" off one-letter-per-line — at 430px
     two columns measured 28px each, which is exactly that failure.

     This lands on two columns at the top of the range and again once the card
     goes full width, and one in between, with no breakpoint to maintain.

     min(60px, 100%) rather than a bare 60px: a minmax floor is a HARD minimum,
     so where the column is narrower than the floor the track overflows its
     card instead of shrinking. Just above this range's own 390px step the
     column is ~54px, which overflowed by 6. */
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card > .tb-beascuit-effects {
    grid-template-columns: repeat(auto-fit, minmax(min(60px, 100%), 1fr));
  }

  /* ---- 515px: both boxes in row 2 change shape ----
     The row keeps its 40/60 split and its two items; what changes is what is
     inside them. The topping grid turns 3x2 into 2x3 and the beascuit card
     stands back up, well on top and effects under it.

     ONE breakpoint for both, deliberately. They are the same fact about the
     row — 40% and 60% of a tile this narrow are no longer wide enough for a
     three-across grid or for a well with chips beside it — and splitting them
     left a window where the upright card was ~253px tall next to a 3x2 grid
     needing ~105, with the difference showing as empty frame.

     The toppings half is the hard constraint of the two, so it sets the
     number. .tb-topping-cell carries a 44px min-width (the tap-target floor),
     and a min-width is a HARD minimum: once three cells plus the gaps stop
     fitting the track, the grid does not shrink, it OVERFLOWS — the third
     column spills out of its own frame and under the beascuit card. Three
     cells need 144px, which the 40% track crosses at 477px, measured. 515
     clears that with room to spare, which it needs: the arithmetic moves with
     the scrollbar and with the reader's text size.

     Retune the 40/60 and this number moves with it. */
  @media (max-width: 515px) {
    .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-topping-grid {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card {
      grid-template-columns: minmax(0, 1fr);
      align-items: stretch;
      align-content: stretch;
    }

    .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card > .tb-beascuit-effects {
      grid-column: 1;
      grid-row: 2;
      /* Back to a fixed 2x2: auto-fit is for the sideways layout, where the
         space beside the well varies. Under the well it is the card's full
         width at every size in this range. */
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  /* ---- 390px and below: two across, in pairs ----
     The cookie card keeps the full width; below it the pieces pair up:

       cookie card
       toppings  | beascuit
       stat targets
       notes
       + chips

     Both boxes already have the shapes they want — the 515px block above gave
     them those. What this range adds is even halves and a frame per row. */

  @media (max-width: 390px) {
    /* Even halves again, not the 40/60 of the wider phone range. This range
       reshapes both boxes — the topping grid goes 2x3 and the beascuit card
       stands back up — so neither of them is the wide one any more, and 40% of
       a ~298px tile leaves the topping cells under the 44px tap minimum. */
    .tb-team--screen .tb-cookie-tile:not(.is-empty) {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-topping-grid {
      grid-column: 1;
      grid-row: 2;
    }

    .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card {
      grid-column: 2;
      grid-row: 2;
    }

    /* Both frames take the whole tile, one per row — back to the base column
       direction, undoing the row the wider phone range sets. They are the two
       pieces here that hold typing rather than icons, and a half-tile column
       at ~123px gives a notes textarea about four words a line. */
    .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-detail-row {
      flex-direction: column;
      gap: 6px;
    }

    /* The 2x3 topping grid and the upright beascuit card are not restated
       here: the 515px block above sets both, for the reasons this range used
       to state itself. */

    /* ---- VIEW: collapsible ----
       The tiles already stack — that is the shared --screen rule up in the
       1080px block. What is specific down here is that four of the five start
       COLLAPSED, or a five-cookie preview becomes a five-screen scroll. The
       builder does not collapse, because you are editing all five.

       Collapsed: the cookie card is all that is left, and it is the toggle.
       Hiding the siblings rather than the tile keeps the card clickable. */
    .tb-team--view .tb-cookie-tile.is-collapsed > *:not(.tb-dexcard) {
      display: none;
    }

    /* ...and the tile's own frame goes with them. A collapsed tile is not a
       card with one thing in it — it IS the cookie card, which already carries
       its own rarity-themed border. Leaving the tile's frame on drew a second,
       thicker border around each one and stacked five double-framed rows.

       The whole frame has to go, not just the border: the background is
       painted in padding-box and border-box layers, so a border alone would
       still leave a rarity wash behind the card. */
    .tb-team--view .tb-cookie-tile.is-collapsed {
      padding: 0;
      border: 0;
      border-radius: 0;
      background: none;
      box-shadow: none;
      min-width: 0;
    }

    /* Tight stack. The 16px that separates five tiles laid side by side reads
       as loose once they are a vertical list of collapsed bars. */
    .tb-team--view .tb-team-grid {
      gap: 6px;
    }

    /* The card is a button here, so it should look like one. */
    .tb-team--view .tb-cookie-tile > .tb-dexcard {
      cursor: pointer;
    }

  }
}

@media (max-width: 1410px) {
  .tb-beascuit-effect {
    font-size: 12px;
  }
}



@media (max-width: 1290px) {
  .tb-team--screen .tb-beascuit-name--overlay {
    font-size: 12px;
  }
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-name {
    font-size: 14px;
  }
  .tb-cookie-meta-icon {
    width: 38px;
    height: 38px;
  }
  .tb-team--view .tb-build-name, .tb-team--screen .tb-build-name {
    font-size: 22px;
  }
}

@media (max-width: 1000px) {
  .tb-team--screen .tb-cookie-tile:not(.is-empty) {
    display: grid;
    align-items: start;
    justify-items: center;
    column-gap: 10px;
  }

  /* The art track hugs the portrait — the portrait's own cap, restated as a
     track, so the column cannot be wider than what it holds. The 24% keeps it
     shrinking with the tile once the tile is too narrow for the cap, and keeps
     the two fr columns from being starved on the way down.

     FLOORED AT 700px, and it has to be: below that the portrait gives way to
     the full-width Dex card and the row underneath is just toppings |
     beascuit, which the phone block sets up as two even columns. This block
     sits AFTER the phone block in the file, so an unfloored three-track
     template wins on source order and puts the empty art column back — the
     toppings and the beascuit end up sharing two thirds of the tile with dead
     space at the end of it. Same for the copy in the 850px block below. */
  @media (min-width: 700px) {
    /* Every tile, like the 170px base — the empty tile's scaffold reads this
       cap too, and must shrink with the portrait rather than being left
       sized off a number the filled tiles no longer use. */
    .tb-team--screen .tb-cookie-tile {
      --tb-art-cap: 140px;
    }
  }
  .tb-team--view .tb-header, .tb-team--screen .tb-header {
    padding: 1rem;
  }
  .tb-cookie-meta-icon {
    width: 30px;
    height: 30px;
  }
  .tb-cookie-meta-badges, .tb-cookie-element-badges {
    top: -10px;
  }
  .tb-cookie-meta-badges {
    right: -10px;
  }
  .tb-cookie-element-badges {
    left: -10px;
  }
  .tb-team--view .tb-build-name, .tb-team--screen .tb-build-name {
    font-size: 20px;
  }
  .tb-beascuit-step {
    width: 28px;
    height: 28px;
  }
  .tb-beascuit-effect {
    font-size: 10px;
  }
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-detail-row {
    gap: 10px;
  }
}

@media (max-width: 850px) {
  /* Floored for the reason spelled out in the 1000px block above; every tile
     for the reason spelled out beside the 170px base. */
  @media (min-width: 700px) {
    .tb-team--screen .tb-cookie-tile {
      --tb-art-cap: 130px;
    }
  }
  .tb-topping-cell {
    min-width: 44px;
    border-radius: 10px
  }
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-topping-grid {
    gap: 4px;
    padding: 4px;
  }
  .tb-beascuit-card {
    padding: 4px;
  }
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card {
    column-gap: 4px;
  }
  .tb-team--screen .tb-cookie-tile:not(.is-empty) {
    padding: 6px;
    gap: 6px;
    column-gap: 6px;
  }
  .tb-beascuit-effects {
    gap: 2px;
  }
  .tb-beascuit-effect {
    font-size: 10px;
    padding: 0px 2px;
  }
  .tb-beascuit-step::before {
    --tb-chevron-size: 6px;
    width: var(--tb-chevron-size);
    height: var(--tb-chevron-size);
  }
  .tb-team--view .tb-build-name, .tb-team--screen .tb-build-name {
    font-size: 18px;
  }
  .tb-team--view .tb-treasure-card, .tb-team--screen .tb-treasure-card {
    width: 76px;
    gap: 6px;
  }
  .tb-team--view .tb-treasure-art-wrap, .tb-team--screen .tb-treasure-art-wrap {
    width: 62px;
    height: 62px;
    border-radius: 14px;
  }
  .tb-team--view .tb-treasure-art, .tb-team--screen .tb-treasure-art {
    width: 52px;
    height: 52px;
  }
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-beascuit-card {
    align-content: center;
  }
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-detail-row {
    gap: 6px;
  }
  .tb-beascuit-step {
    top: 100%;
  }
  .tb-beascuit-step--next {
    right: -1px;
  }
  .tb-beascuit-step--prev {
    left: -1px;
  }
  .tb-team--screen .tb-beascuit-name--overlay {
    font-size: 10px
  }
  .tb-team--screen .tb-cookie-tile:not(.is-empty) > .tb-cookie-name {
    --tb-cookie-name-nudge: 16px;
  }
}

@media (max-width: 699px) {
  .tb-team--view .tb-treasure-card,
  .tb-team--screen .tb-treasure-card {
    width: 60px;
    gap: 6px;
  }
  .tb-team--view .tb-treasure-art-wrap,
  .tb-team--screen .tb-treasure-art-wrap {
    width: 52px;
    height: 52px;
    border-radius: 14px;
  }
  .tb-team--view .tb-treasure-art,
  .tb-team--screen .tb-treasure-art {
    width: 48px;
    height: 48px;
  }
  .tb-beascuit-effect {
    font-size: 10px;
  }
  .tb-team--view .tb-treasure-row, .tb-team--screen .tb-treasure-row {
    gap: 6px;
  }
  .tb-team--view .tb-treasure-name, .tb-team--screen .tb-treasure-name {
    font-size: 8px;
  }
  .tb-treasure-heading {
    padding-bottom: 2px;
  }
  .tb-treasure-panel {
    justify-content: end;
  }
  .tb-team--view .tb-dexcard,
  .tb-team--screen .tb-dexcard {
    --cookie-card-aspect-ratio: 1193 / 200;
  }
}

@media (max-width: 450px) {
  .tb-team--screen .tb-cookie-tile:not(.is-empty) {
    grid-template-columns: minmax(0, 0.5fr) minmax(0, 0.5fr);
    column-gap: 6px;
  }
}



@media (max-width: 390px) {
  .tb-team--view .tb-treasure-heading,
  .tb-team--edit .tb-treasure-heading {
    font-size: 1rem;
    align-self: end;
    text-align: right;
    padding: 0 4px 2px;
  }
  .tb-team--view .tb-treasure-art-wrap,
  .tb-team--edit .tb-treasure-art-wrap {
    width: 54px;
    height: 54px;
    border-radius: 10px;
  }
  .tb-team--view .tb-treasure-art,
  .tb-team--edit .tb-treasure-art {
    width: 50px;
    height: 50px;
  }
  .tb-team--view .tb-treasure-card,
  .tb-team--edit .tb-treasure-card {
    width: 56px;
    gap: 6px;
  }
  .tb-team--view .tb-treasure-name,
  .tb-team--edit .tb-treasure-name {
    display: none;
    /*
    height: auto;
    font-size: 10px;
    line-height: 1.2;
    max-width: 64px;
    overflow: visible;
    */
  }
  .tb-team--view .tb-treasure-panel,
  .tb-team--edit .tb-treasure-panel {
    gap: 4px;
  }
  .tb-treasure-panel {
    justify-content: start;
  }
  .tb-team--view .tb-header,
  .tb-team--edit .tb-header {
    position: relative;
    overflow: hidden;
    align-items: start;
    
    /* Tall enough to show the character whole at a readable size, which also
       gives the bottom-aligned title card something to overlap. */
    min-height: 40px;
    background-image: url("/assets/team-builds-header-bg.png");
    background-repeat: no-repeat;
    background-position: left 50%;
    background-size: auto 70%;
    flex-direction: column;
    padding: 0.25rem;
  }
  /* The header stacks here, so the treasure panel is a column item and its
     horizontal position is align-self, not justify-content. --screen, NOT
     --edit: this was an --edit-only rule, so the builder pinned its treasures
     to the right edge while every saved-build preview — the builder's own
     collection, arena, guild boss, the event pages — left them hugging the
     left with the whole right half of the header empty beside them. Same
     header, two answers. --screen is carried by both trees, which is what
     keeps them from drifting apart again. */
  .tb-team--screen .tb-header-right {
    align-self: flex-end;
  }
  .tb-team--view .tb-header-left,
  .tb-team--edit .tb-header-left {
    display: block;
    align-self: flex-end;
    padding: 2px 8px;
  }
  .tb-team--view .tb-build-name,
  .tb-team--edit .tb-build-name {
    min-width: 0;
    height: auto;
    font-size: 16px;
    line-height: 1.15;
  }
  .tb-cookie-tile {
    padding: 8px 6px;
  }
  .tb-beascuit-card {
    padding: 2px;
    border: 2px solid rgb(210 151 255 / 40%);
    height: 100%;
  }
  .tb-beascuit-effects {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2px;
  }
  .tb-beascuit-step {
    position: absolute;
    top: 90%;
    width: 24px;
    height: 24px;
    margin-top: -17px;
    display: grid;
    place-items: center;
    border: 2px solid rgba(210, 151, 255, 0.7);
    border-radius: 50%;
    background: rgba(20, 6, 30, 0.75);
    cursor: pointer;
  }
  /* Only the size: the centring correction is derived from it. */
  .tb-beascuit-step::before {
    --tb-chevron-size: 6px;
  }
  /* The popover rules that used to sit here now live in the phone block below
     — see the note there for why 390px was the wrong ceiling for them. */
  .tb-team--view .tb-build-subtitle-line, .tb-team--screen .tb-build-subtitle-line {
    font-size: 12px;
  }
  .btn-glow {
    padding: 0.4rem 0.8rem
  }
}

/* ==========================================================================
   PICKER POPOVERS ON A PHONE
   ==========================================================================
   These rules used to live in the max-width: 390px block above, which almost
   no phone matches in portrait — the real range is 393px (iPhone Pro) through
   430px (Pro Max), so the "mobile" popover reached a 360px handset and nothing
   else. Everyone on a modern phone got the desktop tile sizes inside a
   phone-width window, which is what left the tart grid at three columns of
   110px tracks holding 86px tiles.

   The numbers below are ONE SET, derived in this order: the popover is
   min(360px, 100vw - 24px) wide, so the width to divide up is 320px at a
   360px viewport and ~353px at 393px; an icon size fixes the tile width; the
   grid minimum is that tile plus a little slack. They are picked so the column
   count is the SAME across the whole 360-450px range — three toppings, four
   tarts, two bonus effects — rather than reflowing per handset. Change an icon
   size and the grid minimum has to be re-derived with it, or the tiles start
   floating in the middle of much wider tracks again (or overflow them). */
@media (max-width: 450px) {
  .tb-popover {
    width: min(360px, calc(100vw - 24px));
    padding: 4px;
  }

  /* The window title goes. "Select Topping" over a grid of toppings, opened
     from the topping slot the reader just tapped, is the least load-bearing
     line in the popover, and dropping it buys back a row of tiles inside the
     60vh cap. The same holds for "Bonus Effect" over the beascuit effect list.
     NOT the slot menu: its three lines are commands rather than a set of
     values, and "Slot options" is what says they apply to the slot rather than
     the team. Clipped rather than display:none, so the line still reaches a
     screen reader — which does not have the "I just tapped this" context that
     makes it redundant on screen. */
  .tb-popover--topping .tb-popover-title,
  .tb-popover--tart .tb-popover-title,
  .tb-popover--effect .tb-popover-title {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* Topping tile: 44 icon + 4 gap + ~43 button + 6 padding + 2 border ≈ 99.
     Every tile takes its whole track instead of sitting fit-content in the
     middle of it: the leftover few px per column read as gaps between the
     options when they sit outside the tile and as padding when they sit
     inside, and a full-width tile is the bigger touch target of the two. It
     also stops the tart tiles being sized by their labels, which had "Juicy
     Apple Jelly" visibly wider than "Fresh Kiwi" in the same row. */
  .tb-popover-option--icon {
    gap: 4px;
    padding: 2px 4px 2px 2px;
    width: 100%;
    justify-self: stretch;
  }
  .tb-popover-option--icon img {
    width: 44px;
    height: 44px;
  }
  /* ×5 is the secondary half of the tile; the desktop padding is what pushed
     a topping past a third of the popover. */
  .tb-popover-fill {
    min-width: 2.4em;
    padding: 6px;
  }
  .tb-popover-body--topping {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 100px), 1fr));
  }

  /* Tart tile: 64 icon + 4 padding + 2 border = 70, in a 72px minimum. Tarts
     keep the bigger icon and the name for the reason the base rules give —
     they are one biscuit with a small corner gem, not ten pictures — so they
     buy their fourth column from the tile padding and the column gap rather
     than by shrinking to topping size. */
  .tb-popover-body--tart .tb-popover-option {
    gap: 2px;
    padding: 4px 2px;
  }
  .tb-popover-body--tart .tb-popover-option--icon img {
    width: 64px;
    height: 64px;
  }
  .tb-popover-body--tart {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 72px), 1fr));
    column-gap: 4px;
  }

  /* Bonus effects are text, so they are sized by the longest label rather than
     by an icon: 165px is what the desktop grid needs to keep "DMG Resist
     Bypass" on one line, and 2 x 165 does not fit a 360px phone — that popover
     was ONE column of eleven ragged fit-content pills with the right half of
     the window empty. 148px holds two columns from 360px up (and cannot reach
     three, which would need 115px or less at 393px and really would truncate
     the label). The long labels pay for it by wrapping to a second line
     instead of ellipsising — the base rules ellipsise, and a "DMG Resist
     Bypa…" is exactly the one thing that identifies the option going missing.
     Wrapped or not, both pills in a row are the same height: the option is a
     stretched grid item. */
  .tb-popover-body--effect {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 148px), 1fr));
    column-gap: 4px;
  }
  .tb-popover-body--effect .tb-popover-option {
    width: 100%;
    gap: 4px;
    padding: 3px 5px;
  }
  .tb-popover-body--effect .tb-popover-pick--text {
    padding: 3px 4px;
    overflow: visible;
    white-space: normal;
    overflow-wrap: break-word;
    line-height: 1.15;
  }
}

