/* A random adventure's table (random_setup/new, plans/random-setup-cards.md):
   World and Hero, each a short seed and the tags placed on it, the tray of
   tags under them, and Settings beside them, which opens in place. The head,
   the Settings card and its sheet, the switches and the seal are the story
   table's (pages/story_cards.css); what is here is what only this page has.

   Sizes are in px, as story_cards.css's are. Every page loads every
   stylesheet, so each class here is this page's own. The tags and chips are
   not scoped to the page, and their colours are written out rather than read
   from its properties: a tag being dragged is a copy of it in <body>
   (lib/tag_motion.js), outside the page, and has to look the same there. */

/* A tag's height, and a chip menu row's: a thumb's on a touch screen. The
   colours are the ones the script's animations need (lib/tag_motion.js). */
.random-table {
  --tag-h: 36px;
  --row-h: 36px;
  --tag-flash: #d1c9bb;
  --tag-field: #fbf6ea;
  --tag-ink: #3a2a14;
  --tag-gilt: #8a7354;
}
@media (pointer: coarse) {
  .random-table { --tag-h: 44px; --row-h: 44px; }
}
.random-table-view[hidden],
.random-settings[hidden] { display: none; }
.random-table .story-table-lede { max-width: 56ch; }

/* ── The deck ──
   World, Hero and the tray under them; Settings, Generate and its note in
   the third column. */
.random-deck {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-areas: "world hero foot" "tray tray foot";
  grid-template-rows: auto 1fr;
  gap: 24px;
}
.random-deck-play { display: contents; }
.random-deck .seed-card--world { grid-area: world; }
.random-deck .seed-card--hero { grid-area: hero; }
.random-deck .tag-tray { grid-area: tray; }
.tag-tray-sentinel { display: none; }
.random-deck-foot {
  grid-area: foot;
  align-self: start;
  display: flex;
  flex-direction: column;
  gap: 24px;
  min-width: 0;
}
/* A button, where custom's face is a link. */
button.story-card {
  width: 100%;
  margin: 0;
  text-align: left;
  font: inherit;
  cursor: pointer;
}
/* Its name level with World's and Hero's, whose inked plates are 22px high. */
.random-deck .story-card--settings .story-card-top { min-height: 22px; align-items: center; }
.random-generate .btn { width: 100%; }
.random-deck-foot .story-start-note { margin: -12px auto 0; text-align: center; }

/* ── World and Hero ──
   The story card's face (painted with it in story_cards.css) without its
   clipping, its own stacking context or its lift: a chip's menu reaches past
   the card's edge, and on a phone it is the only thing drawn over the pinned
   tray, which a card with a z-index would be too. Stretched, as a card with
   a ratio is not by default: when a long seed and ten tags make one card
   taller than 3:4, the other grows with it and the row stays even. */
.seed-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-self: stretch;
  min-width: 0;
  width: 100%;
  aspect-ratio: 3 / 4;
  padding: 18px 18px 16px;
  color: #5a4a30;
}
.seed-card-top,
.seed-card-hints,
.seed-card-field,
.seed-card-count { position: relative; z-index: 1; }
.seed-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 22px;
}
/* The card's name, inked when it is the active card. */
.seed-card-plate {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 0 0 0 -8px;
  padding: 3px 8px;
  font-family: 'Cinzel', serif;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #3a2a14;
}
:is(.seed-card-plate-mark, .tag-target-mark, .tag-chip-menu-icon) {
  display: inline-flex;
  flex: none;
  width: 14px;
  height: 14px;
}
:is(.seed-card-plate-mark, .tag-target-mark, .tag-chip-menu-icon, .tray-tag-mark, .tray-group-fit-mark) svg {
  display: block;
  width: 100%;
  height: 100%;
}
.seed-card-plate-mark { opacity: 0.5; }

/* The active card, where a tapped tag goes: the dark edge and the inked
   plate. data-active is the one value it and "Add to" share. */
.random-table[data-active="world"] .seed-card--world,
.random-table[data-active="hero"] .seed-card--hero {
  border-color: #3a2a14;
  box-shadow: 0 0 0 1px #3a2a14, 0 10px 24px rgba(40, 25, 10, 0.24);
}
.random-table[data-active="world"] .seed-card--world .seed-card-plate,
.random-table[data-active="hero"] .seed-card--hero .seed-card-plate { background: #3a2a14; color: #f6ecd8; }
.random-table[data-active="world"] .seed-card--world .seed-card-plate-mark,
.random-table[data-active="hero"] .seed-card--hero .seed-card-plate-mark { opacity: 1; }
@media (forced-colors: active) {
  .random-table[data-active="world"] .seed-card--world,
  .random-table[data-active="hero"] .seed-card--hero { outline: 3px solid Highlight; outline-offset: -3px; }
}
/* ", tags go here", for a screen reader, on the active card's heading only. */
.seed-card-active { display: none; }
.random-table[data-active="world"] .seed-card--world .seed-card-active,
.random-table[data-active="hero"] .seed-card--hero .seed-card-active { display: inline; }

/* The hint shares its cell with the other card's, unseen, so both are as
   tall as the longer and both seeds start level across the row: German's
   Hero hint takes three lines where World's takes two. */
.seed-card-hints { display: grid; margin-top: 8px; }
.seed-card-hint {
  grid-area: 1 / 1;
  margin: 0;
  font-family: 'Lora', Georgia, serif;
  font-size: 13px;
  line-height: 1.45;
  color: #65523a;
}
.seed-card-hint--sizer { visibility: hidden; }
/* The field grows with what is typed (autogrow_controller.js) and, off a
   phone, scrolls inside after eight lines, so World and Hero stay near the
   table's 3:4. */
.random-table .seed-card-field {
  min-height: 94px;
  max-height: calc(8 * 24px + 22px);
  margin-top: 8px;
  overflow-y: auto;
  resize: none;
  line-height: 1.5;
}
.random-table .seed-card-count { margin-top: 4px; }

/* The tags placed on the card, over its faint glyph until the first. */
.seed-card-tags {
  position: relative;
  flex: 1 0 auto;
  margin-top: 10px;
  padding-top: 12px;
  border-top: 1px solid rgba(160, 137, 94, 0.45);
}
.seed-card-glyph {
  position: absolute;
  top: calc(50% + 6px);
  left: 50%;
  height: min(104px, 78%);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  opacity: 0.12;
  color: #2a1d0e;
  pointer-events: none;
}
.seed-card-glyph svg { display: block; width: 100%; height: 100%; }
.seed-card-tags.has-tags .seed-card-glyph { display: none; }
.tag-chips {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ── A tag on a card ── */
.tag-chip-wrap { position: relative; display: flex; max-width: 100%; }
.tag-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  max-width: 100%;
  height: var(--tag-h, 36px);
  margin: 0;
  padding: 0 9px 0 11px;
  background: #fbf6ea;
  border: 1px solid #8a7354;
  font-family: 'Lora', Georgia, serif;
  font-size: 14px;
  line-height: 1;
  color: #2a1d0e;
  white-space: nowrap;
  cursor: pointer;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.tag-chip-name { overflow: hidden; text-overflow: ellipsis; }
.tag-chip-caret { font-size: 10px; color: #65523a; }
.tag-chip[aria-expanded="true"] { background: #3a2a14; border-color: #2a1d0e; color: #f1e6cf; }
.tag-chip[aria-expanded="true"] .tag-chip-caret { color: #f1e6cf; }
@media (hover: hover) {
  .tag-chip:not([aria-expanded="true"]):hover { border-color: #5a4a30; }
}
.tag-chip.is-drag-src { opacity: 0.35; border-style: dashed; }
.tag-chip.is-ring { box-shadow: 0 0 0 2px #3a2a14; }
/* Where a dragged tag would land. */
.tag-chip--placeholder { background: transparent; border: 1px dashed #5a4a30; opacity: 0.5; cursor: default; }

/* "+ Your own tag", and the field it opens into. */
.tag-own { display: flex; }
.tag-own:has(.tag-own-field:not([hidden])) { flex: 1 1 220px; min-width: 0; }
.tag-own-open {
  display: inline-flex;
  align-items: center;
  height: var(--tag-h);
  margin: 0;
  padding: 0 11px;
  background: transparent;
  border: 1px dashed rgba(58, 42, 20, 0.45);
  font-family: 'Lora', Georgia, serif;
  font-size: 14px;
  line-height: 1;
  color: #65523a;
  white-space: nowrap;
  cursor: pointer;
}
@media (hover: hover) {
  .tag-own-open:hover { border-color: #5a4a30; color: #2a1d0e; }
}
.tag-own-field { display: flex; flex: 1 1 auto; gap: 6px; min-width: 0; }
.tag-own-field[hidden],
.tag-own-open[hidden],
.tag-own[hidden],
.tag-own-note[hidden],
.tag-cap[hidden] { display: none; }
/* 16px: under that a phone zooms the page into the field. */
.random-table .tag-own-input {
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
  height: var(--tag-h);
  min-height: 0;
  padding: 0 10px;
  font-size: 16px;
}
.tag-own-add {
  flex: none;
  height: var(--tag-h);
  margin: 0;
  padding: 0 12px;
  background: #3a2a14;
  border: 1px solid #1c130a;
  font-family: 'Cinzel', serif;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #f1e6cf;
  cursor: pointer;
}
@media (hover: hover) {
  .tag-own-add:hover { background: #2a1d0e; }
}
.tag-own-note { flex-basis: 100%; }
.tag-own-note-text {
  padding: 0 2px;
  font-family: 'Lora', Georgia, serif;
  font-size: 13px;
  font-style: italic;
  color: #65523a;
}
/* "8 of 10 tags". */
.tag-cap { display: flex; align-items: center; min-height: var(--tag-h); }
.tag-cap-line { padding: 0 2px; font-family: 'Lora', Georgia, serif; font-size: 12px; color: #65523a; }

/* ── A chip's menu ──
   Opened to the left of its chip unless it would cross the card's inner
   edge, and downward unless it would pass the pinned tray or the screen's
   foot (random_table_controller.js#placeMenu). As wide as its longest row,
   up to the card's inside, which placeMenu sets: a German row ("Auf die
   Karte Hauptfigur verschieben") is wider than a phone's card, and wraps
   rather than runs off the screen. */
.tag-chip-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 6;
  width: max-content;
  min-width: 190px;
  max-width: calc(100vw - 32px);
  padding: 4px 0;
  background: #f3ead8;
  border: 1px solid #3a2a14;
  box-shadow: 0 10px 28px rgba(40, 25, 10, 0.28);
}
.tag-chip-menu.is-right { left: auto; right: 0; }
.tag-chip-menu.is-up { top: auto; bottom: calc(100% + 4px); }
.tag-chip-menu button {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: var(--row-h);
  margin: 0;
  padding: 6px 14px;
  background: none;
  border: 0;
  font-family: 'Lora', Georgia, serif;
  font-size: 15px;
  text-align: left;
  color: #2a1d0e;
  cursor: pointer;
}
.tag-chip-menu[hidden],
.tag-chip-menu button[hidden],
.tag-chip-menu-note[hidden] { display: none; }
@media (hover: hover) {
  .tag-chip-menu button:hover { background: rgba(138, 115, 84, 0.12); }
}
.tag-chip-menu-icon { align-items: center; justify-content: center; font-size: 17px; line-height: 1; color: #5a4a30; }
.tag-chip-menu-note {
  margin: 0;
  padding: 8px 14px 4px;
  font-family: 'Lora', Georgia, serif;
  font-size: 13px;
  font-style: italic;
  color: #65523a;
}

/* ── While a tag is dragged ──
   Every card it may go on has a dashed edge inside it, the one under it a
   solid edge and a wash. A card that refuses a dropped tag's own card lights
   up for a moment instead (is-hint). */
.seed-card:is(.is-drop-ok, .is-drop-over, .is-hint)::after {
  content: '';
  position: absolute;
  inset: 10px;
  z-index: 4;
  pointer-events: none;
}
.seed-card.is-drop-ok::after { border: 2px dashed #a0895e; }
.seed-card:is(.is-drop-over, .is-hint)::after { border: 2px solid #3a2a14; background: rgba(160, 137, 94, 0.14); }
html.tag-dragging,
html.tag-dragging * { -webkit-user-select: none !important; user-select: none !important; }
html.tag-dragging--copy,
html.tag-dragging--copy * { cursor: copy !important; }
html.tag-dragging--move,
html.tag-dragging--move * { cursor: grabbing !important; }
html.tag-dragging--no,
html.tag-dragging--no * { cursor: not-allowed !important; }
.tag-ghost {
  position: fixed !important;
  z-index: 1000;
  margin: 0 !important;
  pointer-events: none;
  box-shadow: 0 10px 22px rgba(40, 25, 10, 0.35);
}
.tag-ghost--lift { transform: scale(1.06) rotate(-2deg); }

/* ── The tray ── */
.tag-tray {
  min-width: 0;
  padding-top: 14px;
  border-top: 1px solid rgba(138, 115, 84, 0.6);
}
.tag-tray-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
}
.tag-tray-label {
  margin: 0;
  font-family: 'Cinzel', serif;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #3a2a14;
}
.tag-tray-help {
  margin: 6px 0 12px;
  font-family: 'Lora', Georgia, serif;
  font-size: 14px;
  line-height: 1.5;
  color: #65523a;
  text-wrap: balance;
}
/* One pair of lines shows: the active card's, for the pointer in use. Each
   sentence on its own line, so the wrap never depends on the card's name. */
.tag-tray-help-text { display: none; }
@media not all and (pointer: coarse) {
  .random-table[data-active="world"] .tag-tray-help-text[data-card="world"][data-pointer="fine"],
  .random-table[data-active="hero"] .tag-tray-help-text[data-card="hero"][data-pointer="fine"] { display: inline; }
}
@media (pointer: coarse) {
  .random-table[data-active="world"] .tag-tray-help-text[data-card="world"][data-pointer="coarse"],
  .random-table[data-active="hero"] .tag-tray-help-text[data-card="hero"][data-pointer="coarse"] { display: inline; }
}
.tag-tray-help-line { display: block; }

/* "Add to": the two radios drawn as a switch. */
.tag-target {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}
.tag-target legend {
  float: left;
  padding: 0;
  font-family: 'Cinzel', serif;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #65523a;
}
.tag-target-seg { display: inline-flex; }
.tag-target-opt {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: var(--tag-h);
  padding: 0 13px;
  background: rgba(251, 246, 234, 0.5);
  border: 1px solid #3a2a14;
  font-family: 'Cinzel', serif;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #3a2a14;
  cursor: pointer;
}
.tag-target-opt + .tag-target-opt { border-left: 0; }
/* The radio covers its segment, unseen and not clickable, so a Tab that lands
   on it scrolls the whole segment into view: Chrome scrolls only when the
   focused box is out of view, and a 1px box in the corner could be in view
   while the segment was half below the fold. The margin is the ring outside
   it (the border, the offset and the outline). */
.tag-target-opt input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  pointer-events: none;
  scroll-margin: 5px;
}
.tag-target-opt:has(input:checked) { background: #3a2a14; color: #f6ecd8; }
.tag-target-opt:has(input:focus-visible) { z-index: 1; outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.tag-target-mark { opacity: 0.5; }
.tag-target-opt:has(input:checked) .tag-target-mark { opacity: 1; }
@media (hover: hover) {
  .tag-target-opt:not(:has(input:checked)):hover { background: rgba(138, 115, 84, 0.12); }
}
@media (forced-colors: active) {
  .tag-target-opt:has(input:checked) { text-decoration: underline; text-underline-offset: 3px; }
}

/* The groups share one label column: 112px, which English and Polish fit,
   or as wide as the longest name in the page's language ("HAUPTFIGUR" and
   its two slots). Never narrower, or English's tags would break their lines
   in other places than the approved table's. Positioned, so each tag's
   offsetLeft is measured from the row (tag_tray_controller.js). */
.tray-groups {
  position: relative;
  display: grid;
  grid-template-columns: minmax(112px, max-content) minmax(0, 1fr);
  gap: 8px 6px;
}
.tray-group {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: start;
}
.tray-group[hidden],
.tray-jump[hidden] { display: none; }
.tray-jumps { display: none; }
.tray-group-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  height: var(--tag-h);
  font-family: 'Cinzel', serif;
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #65523a;
  white-space: nowrap;
}
/* "Your own", inside the first group's name: as wide as it is and no taller
   than nothing, so the column is ready for that group before it shows. */
.tray-group-name-sizer {
  display: block;
  height: 0;
  overflow: hidden;
  visibility: hidden;
}
/* Which card the group's tags go on: a World slot and a Hero slot, lined up
   down the tray. */
.tray-group-fit { display: inline-flex; flex: none; gap: 4px; padding-right: 4px; }
.tray-group-fit-mark { display: inline-flex; width: 11px; height: 11px; color: #65523a; }
.tray-group-fit-mark.is-none { visibility: hidden; }
.tray-group-tags { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }

/* A tag in the tray: the table's Theme pill grown into a token. */
.tray-tag {
  position: relative;
  display: inline-flex;
  align-items: center;
  flex: none;
  max-width: 100%;
  height: var(--tag-h, 36px);
  margin: 0;
  padding: 0 11px;
  background: #fbf6ea;
  border: 1px solid #b59a70;
  font-family: 'Lora', Georgia, serif;
  font-size: 14px;
  line-height: 1;
  color: #3a2a14;
  white-space: nowrap;
  cursor: pointer;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.tray-tag-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
@media (hover: hover) {
  .tray-tag:hover { background: #f3ead8; border-color: #8a7354; }
}
.tray-tag.is-drag-src { opacity: 0.5; }
/* Faded: it cannot go on the active card. It stays where it is and still
   works, a tap sending it to its own card. #65523a clears 4.5:1 on the
   darkest parchment only over this fill (4.83:1; 4.34:1 without it). */
.random-table[data-active="world"] .tray-tag[data-fit="hero"],
.random-table[data-active="hero"] .tray-tag[data-fit="world"] {
  background: rgba(251, 246, 234, 0.22);
  border-color: rgba(160, 137, 94, 0.5);
  color: #65523a;
}
@media (hover: hover) {
  .random-table[data-active="world"] .tray-tag[data-fit="hero"]:hover,
  .random-table[data-active="hero"] .tray-tag[data-fit="world"]:hover { background: rgba(138, 115, 84, 0.12); border-color: #8a7354; color: #3a2a14; }
}
@media (forced-colors: active) {
  .random-table[data-active="world"] .tray-tag[data-fit="hero"],
  .random-table[data-active="hero"] .tray-tag[data-fit="world"] { border-style: dashed; }
}
/* Which cards hold it: dark for the active card, faint for the other. Faint
   is 0.6, not less: on a phone the other card is often off screen, and then
   this mark is the only sign the tag is on it, so it keeps the 3:1 a graphic
   that means something needs (3.82:1 on the tag, 3.67:1 on its hover). */
.tray-tag-marks { display: inline-flex; flex: none; gap: 4px; }
.tray-tag-marks:has(.tray-tag-mark:not([hidden])) { margin-left: 6px; }
.tray-tag-mark { display: inline-flex; width: 12px; height: 12px; color: #3a2a14; }
.tray-tag-mark[hidden] { display: none; }
.random-table[data-active="world"] .tray-tag-mark--hero,
.random-table[data-active="hero"] .tray-tag-mark--world { opacity: 0.6; }
/* A faded tag's mark is always the other card's; at full strength it stays
   readable on the clear fill. */
.random-table[data-active="world"] .tray-tag[data-fit="hero"] .tray-tag-mark,
.random-table[data-active="hero"] .tray-tag[data-fit="world"] .tray-tag-mark { color: #65523a; opacity: 1; }

/* The pinned phone row's jumps to each group (hidden elsewhere). */
.tray-jump {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 30px;
  margin: 0;
  padding: 0 9px;
  background: none;
  border: 0;
  font-family: 'Cinzel', serif;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #4a3a22;
  white-space: nowrap;
  cursor: pointer;
}
/* The current group's jump has a line under its name. A jump is a thumb high
   on the phone, so the line is drawn 8px above its foot, under the name as
   on the approved table's 28px jumps, not 16px below it. */
.tray-jump[aria-current="true"] {
  --tray-jump-line: #3a2a14;
  background: linear-gradient(var(--tray-jump-line), var(--tray-jump-line)) center bottom 8px / 100% 2px no-repeat;
  color: #3a2a14;
}
/* A jump whose group cannot go on the active card fades with its tags, so
   the row of jumps doubles as the legend. A faded jump still jumps, and while
   the row is pinned the jumps are the only names the groups have, so it stays
   readable: #65523a is 5.05:1 on the pinned tray's darker stop, which is why
   the jumps that fit are darker than the table's usual small capitals
   (#4a3a22, 7.42:1). The faded current one's line is the same ink, well
   over the 3:1 a mark needs. */
.random-table[data-active="world"] .tray-jump[data-fit="hero"],
.random-table[data-active="hero"] .tray-jump[data-fit="world"] { color: #65523a; }
.random-table[data-active="world"] .tray-jump[data-fit="hero"][aria-current="true"],
.random-table[data-active="hero"] .tray-jump[data-fit="world"][aria-current="true"] { --tray-jump-line: #65523a; color: #65523a; }
/* Forced colours drop the line, a background image, and with it the only
   sign of the current jump. */
@media (forced-colors: active) {
  .tray-jump[aria-current="true"] { text-decoration: underline; text-underline-offset: 3px; }
}

/* ── Settings, opened ──
   Custom's Settings page, in place: the way back is a button here. */
.random-settings { margin: 0 auto; }
.random-settings .story-back {
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}
.random-settings-pager { display: flex; justify-content: center; margin-top: 22px; }

/* ── A tablet: World and Hero side by side, the tray under them, Settings
   and Generate below ── */
@media (max-width: 1019.98px) {
  .random-deck {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-areas: "world hero" "tray tray" "foot foot";
    grid-template-rows: auto auto auto;
    gap: 18px;
  }
  .random-deck-foot {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: auto 1fr;
    gap: 0 18px;
    align-items: start;
  }
  .random-deck .story-card--settings { grid-row: 1 / span 2; }
  .random-generate,
  .random-deck-foot .story-start-note { grid-column: 2; }
  .random-deck-foot .story-start-note { margin-top: 12px; }
}

/* ── A phone: one column. The tray is pinned at the foot of the screen, like
   a hand of cards, while World and Hero go by, then laid down in its place
   under Hero (tag_tray_controller.js); Generate then takes the foot. ── */
@media (max-width: 559.98px) {
  .random-table { --tag-h: 44px; --row-h: 44px; }
  .random-table .story-table-header { margin: 2px 0 18px; padding-bottom: 16px; }
  .random-table .story-table-lede { font-size: 14px; line-height: 1.55; }

  .random-deck,
  .random-deck-play,
  .random-deck-foot { display: block; }
  .seed-card { aspect-ratio: auto; padding: 14px; }
  .seed-card::before { inset: 5px; }
  .seed-card + .seed-card { margin-top: 12px; }
  .seed-card-hint--sizer { display: none; }
  .random-table .seed-card-field { max-height: none; overflow-y: hidden; }
  .seed-card-tags { flex: none; }
  /* A focused card control stops above the pinned bars. Only these: the
     tray's own controls sit inside that band, and a page-wide scroll padding
     made every tap on them scroll the page. A card's controls clear the
     pinned tray (149px, and the home bar under it) with room for the focus
     ring; Settings only Generate's bar, since by then the tray has landed.
     The sheet's switches clear its Done bar. Every bar grows by the home bar
     under it, so each margin does too. */
  .seed-card :is(button, textarea, input) { scroll-margin-bottom: calc(164px + env(safe-area-inset-bottom)); }
  .random-deck .story-card--settings { scroll-margin-bottom: calc(124px + env(safe-area-inset-bottom)); }
  .random-settings :is(input, select, button) { scroll-margin-bottom: calc(84px + env(safe-area-inset-bottom)); }

  /* Where the tray's place starts; the script compares it with the screen's
     foot. Its showing is also how the script knows the layout is a phone's. */
  .tag-tray-sentinel { display: block; height: 14px; }

  /* Pinned: one sideways row, with jumps to each group above it. The solid
     colour under the gradient is for forced colours, which drop the gradient
     and would leave the cards passing under the tray showing through it. */
  .tag-tray:not(.is-landed) {
    position: sticky;
    bottom: 0;
    z-index: 4;
    margin: 0 calc(-0.6rem - 6px);
    padding: 6px calc(0.6rem + 6px) calc(8px + env(safe-area-inset-bottom));
    background: #e2d3b8 linear-gradient(to bottom, #e9dcc3, #e2d3b8);
    border-top: 1px solid rgba(138, 115, 84, 0.7);
    box-shadow: 0 -8px 16px rgba(40, 25, 10, 0.08);
  }
  .tag-tray:not(.is-landed) :is(.tag-tray-label, .tag-tray-help) {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
  .tag-tray:not(.is-landed) .tag-tray-head { justify-content: flex-start; }
  /* Six jumps fit a 360px screen in English, Polish and German, the short
     ones a thumb wide; on a narrower one their row scrolls by itself, never
     the page, and fades at the edge that has more. */
  .tag-tray:not(.is-landed) .tray-jumps {
    display: flex;
    flex-wrap: nowrap;
    margin: 0 calc(-0.6rem - 6px) 2px;
    padding: 0 6px;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .tag-tray:not(.is-landed) .tray-jumps::-webkit-scrollbar { display: none; }
  .tag-tray:not(.is-landed) .tray-jumps.more-r {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
  }
  .tag-tray:not(.is-landed) .tray-jumps.more-l {
    -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 24px), transparent);
    mask-image: linear-gradient(to left, #000 calc(100% - 24px), transparent);
  }
  .tag-tray:not(.is-landed) .tray-jumps.more-l.more-r {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 24px, #000 calc(100% - 24px), transparent);
    mask-image: linear-gradient(to right, transparent, #000 24px, #000 calc(100% - 24px), transparent);
  }
  .tag-tray:not(.is-landed) .tray-jump { flex: none; min-width: 44px; min-height: 44px; padding: 0 4px; letter-spacing: 0.04em; }
  .tag-tray:not(.is-landed) .tray-groups {
    display: flex;
    flex-direction: row;
    gap: 0;
    margin: 0 calc(-0.6rem - 6px);
    padding: 0 calc(0.6rem + 6px);
    overflow-x: auto;
    scroll-padding-inline: 16px;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
  }
  .tag-tray:not(.is-landed) .tray-groups::-webkit-scrollbar { display: none; }
  .tag-tray:not(.is-landed) .tray-group { display: flex; flex: none; align-items: center; gap: 6px; }
  .tag-tray:not(.is-landed) .tray-group + .tray-group { margin-left: 12px; padding-left: 12px; border-left: 1px solid rgba(138, 115, 84, 0.5); }
  .tag-tray:not(.is-landed) .tray-group[hidden] { display: none; }
  /* The jumps name the groups while pinned. Each group keeps its card marks
     at its start, in a round slot, so they do not read as the marks inside
     a square tag that say where it is placed. */
  .tag-tray:not(.is-landed) .tray-group-label { height: auto; }
  .tag-tray:not(.is-landed) .tray-group-name { display: none; }
  .tag-tray:not(.is-landed) .tray-group-fit { gap: 3px; padding: 5px 7px; border: 1px solid rgba(160, 137, 94, 0.5); border-radius: 999px; }
  .tag-tray:not(.is-landed) .tray-group-fit-mark { width: 10px; height: 10px; }
  .tray-group-fit-mark.is-none { display: none; }
  .tag-tray:not(.is-landed) .tray-group-tags { flex-wrap: nowrap; }
  .tag-tray:not(.is-landed) .tray-tag { max-width: 240px; }

  /* Laid down under Hero: every tag in view, each group's label over its
     tags, so the tags get the full width. */
  .tag-tray.is-landed .tag-tray-help { font-size: 13.5px; }
  .tag-tray.is-landed .tray-groups { display: flex; flex-direction: column; gap: 12px; }
  .tag-tray.is-landed .tray-group { grid-template-columns: minmax(0, 1fr); gap: 5px; }
  .tag-tray.is-landed .tray-group[hidden] { display: none; }
  .tag-tray.is-landed .tray-group-label { height: auto; justify-content: flex-start; gap: 8px; line-height: 1.4; }
  .tag-tray.is-landed .tray-group-fit { padding-right: 0; }

  .random-deck-foot { margin-top: 24px; }
  /* Settings as a short card: its glyph to the right, its lines at full size
     (the story table's phone faces go compact, two to a row; this one has a
     row of its own), and no "Open", as the table has none on a phone. */
  .random-deck .story-card--settings { aspect-ratio: auto; gap: 10px; padding: 14px 14px 12px; }
  .random-deck .story-card--settings::before { inset: 5px; }
  .random-deck .story-card--settings .story-card-glyph { top: 18px; right: 22px; left: auto; width: 58px; transform: none; }
  .random-deck .story-card--settings .story-card-name { font-size: 12px; letter-spacing: 0.2em; }
  .random-deck .story-card--settings .story-card-list { gap: 5px; font-size: 13.5px; }
  .random-deck .story-card--settings .story-card-foot { display: none; }
  .random-generate {
    position: sticky;
    bottom: 0;
    z-index: 3;
    margin: 16px calc(-0.6rem - 6px) 0;
    padding: 14px calc(0.6rem + 6px) calc(12px + env(safe-area-inset-bottom));
  }
  .random-deck-foot .story-start-note { display: none; }
  /* While a card's field has the keyboard, the tray goes and Generate stops
     pinning: both would ride up on the keyboard over what is being typed. */
  .random-deck[data-typing] .tag-tray { display: none; }
  .random-deck[data-typing] .random-generate { position: static; }

  .random-settings-pager {
    position: sticky;
    bottom: 0;
    z-index: 3;
    margin: 18px calc(-0.6rem - 6px) 0;
    padding: 14px calc(0.6rem + 6px) calc(10px + env(safe-area-inset-bottom));
  }
  .random-settings-pager .btn { width: 100%; }
  /* A help bubble spans its switch's row, so it can never reach past the
     screen's edge; the tooltip never moves one back inside it. Only here:
     custom's Settings card keeps its own. */
  .random-settings .story-switches :is(.setup-toggle, .setup-choice) { position: relative; }
  .random-settings .story-switches .setup-help { position: static; }
  .random-settings .story-switches .setup-help-bubble { top: calc(100% - 4px); right: 0; left: 0; width: auto; max-width: none; transform: none; }
  .random-settings .story-switches .setup-help-bubble.is-above { top: auto; bottom: calc(100% - 4px); }
}

/* A tag that fits both cards is still a thumb wide when its name is short. */
@media (pointer: coarse) {
  .tray-tag,
  .tag-chip { min-width: 44px; justify-content: center; }
}

/* ── Motion ──
   All of it waits for a reader who has not asked for less; without it the
   refused card's light shows and goes without fading. */
@media (prefers-reduced-motion: no-preference) {
  .seed-card { transition: border-color 0.15s ease, box-shadow 0.15s ease; }
  .seed-card-plate { transition: background-color 0.15s ease, color 0.15s ease; }
  .tray-tag { transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease; }
  .seed-card.is-hint::after { animation: seed-card-hint 0.9s ease-out forwards; }
}
@keyframes seed-card-hint { 0%, 45% { opacity: 1; } 100% { opacity: 0; } }
