/* -- Reset & base -- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --bg-primary:   #faf7f2;
  --bg-secondary: #f0ebe0;
  --bg-tertiary:  #e8e0d0;
  --text-primary:   #1a1410;
  --text-secondary: #6b5a45;
  --text-tertiary:  #a89070;
  --border-light:   rgba(100, 75, 45, 0.15);
  --border-mid:     rgba(100, 75, 45, 0.30);
  --border-strong:  rgba(100, 75, 45, 0.45);
  --accent-stone:   #c8a96e;
  --accent-dark:    #3d2b1f;
  --success:  #2d7a3e;
  --danger:   #b83232;
  --info:     #185FA5;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-xl: 16px;
  --font-serif: 'Crimson Text', Georgia, serif;
  --font-display: 'Cinzel', serif;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg-primary:   #1e1810;
    --bg-secondary: #2a2016;
    --bg-tertiary:  #342a1c;
    --text-primary:   #f0e8d8;
    --text-secondary: #c0a880;
    --text-tertiary:  #806848;
    --border-light:   rgba(200, 169, 110, 0.12);
    --border-mid:     rgba(200, 169, 110, 0.25);
    --border-strong:  rgba(200, 169, 110, 0.40);
    --accent-stone:   #c8a96e;
    --accent-dark:    #f0e8d8;
    --success:  #4caf6e;
    --danger:   #e05050;
    --info:     #5aa0e0;
  }
}

html, body {
  height: 100%;
  background: var(--bg-tertiary);
  color: var(--text-primary);
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* -- Layout -- */
#app {
  max-width: 1024px;
  margin: 0 auto;
  min-height: 100vh;
  background: var(--bg-primary);
  display: flex;
  flex-direction: column;
}

header {
  text-align: center;
  /* iOS standalone mode uses a translucent status bar (see index.html's
     apple-mobile-web-app-status-bar-style), so page content starts
     underneath the status bar/notch/Dynamic Island unless padding
     explicitly accounts for it - see also viewport-fit=cover in
     index.html, required for env(safe-area-inset-*) to be non-zero. */
  padding: calc(1.5rem + env(safe-area-inset-top)) 1rem 0.5rem;
  border-bottom: 0.5px solid var(--border-light);
  background: var(--bg-primary);
  position: sticky;
  top: 0;
  z-index: 10;
}

.app-title {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: 3px;
}

.app-sub {
  font-size: 12px;
  color: var(--text-secondary);
  font-style: italic;
  letter-spacing: 1px;
  margin-bottom: 0.75rem;
}

/* -- Tabs (nav landmark, not a "card" or generic action button - its own
   exception, same family as the .tab-icon-btn icons beside it) -- */
.tabs {
  display: flex;
  border-bottom: 0.5px solid var(--border-light);
  background: var(--bg-primary);
}

.tab {
  flex: 1;
  font-family: var(--font-display);
  font-size: 10px;
  letter-spacing: 1.5px;
  padding: 10px 4px;
  cursor: pointer;
  border: none;
  background: none;
  color: var(--text-secondary);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color 0.15s;
}

.tab.active {
  color: var(--text-primary);
  border-bottom-color: var(--accent-stone);
}

.tab:hover:not(.active) { color: var(--text-primary); }

.tab-icon-btn {
  flex: 0 0 auto;
  width: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  background: none;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 14px;
  position: relative;
  transition: color 0.15s;
}

.tab-icon-btn:hover { color: var(--text-primary); }

/* Small dot shown on the backup icon once a backup-id is connected. */
.tab-icon-btn.connected::after {
  content: '';
  position: absolute;
  top: 8px;
  right: 10px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--success);
  border: 1px solid var(--bg-primary);
}

/* -- Panels -- */
.panel { display: none; padding: 1rem; }
.panel.active { display: block; }

/* -- Sections: the app's one "rounded box" component. It replaces what used
   to be several separate look-alike classes (.card, .card-alt, .modal-card,
   .game-card, .log-entry, .inventory-tile, .recipe-row) - every <section>
   is a darker-tan rounded box, and a <section> nested one level inside
   another switches back to the lighter tan, purely from nesting depth. Any
   new section this pattern is used for automatically matches everywhere
   else without needing its own class. A few existing class names remain on
   some <section>s below (.log-entry, .inventory-tile, .recipe-line,
   .explorer-row, .game-card) but only for their internal flex layout
   (direction/gap) - all color/border/radius/padding now comes from here. */
section {
  background: var(--bg-secondary);
  border: 0.5px solid var(--border-light);
  border-radius: var(--radius-lg);
  padding: 1rem 1.125rem;
  margin-bottom: 0.875rem;
}

section section {
  background: var(--bg-primary);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  margin-bottom: 0;
}

/* Marks the one game a nested game-card section belongs to as "current" -
   an attribute rather than a class since it's exactly what aria-current is
   for (the current item among a set of related items). */
section[aria-current="true"] {
  border-color: var(--accent-stone);
  border-width: 1.5px;
}

.sec-title {
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 1.5px;
  color: var(--text-secondary);
  margin-bottom: 0.75rem;
  display: flex;
  align-items: center;
  gap: 5px;
}

.sec-title i { font-size: 12px; }

.field-label {
  font-family: var(--font-display);
  font-size: 10px;
  letter-spacing: 1.5px;
  color: var(--text-secondary);
  display: block;
  margin-bottom: 4px;
}

.field-group {
  display: flex;
  flex-direction: column;
}

/* -- Form controls -- */
input[type="text"],
input[type="number"],
select {
  font-family: var(--font-serif);
  font-size: 14px;
  color: var(--text-primary);
  background: var(--bg-primary);
  border: 0.5px solid var(--border-mid);
  border-radius: var(--radius-md);
  padding: 7px 10px;
  outline: none;
  transition: border-color 0.15s;
  width: 100%;
}

input[type="text"]:focus,
input[type="number"]:focus,
select:focus {
  border-color: var(--accent-stone);
  box-shadow: 0 0 0 2px rgba(200,169,110,0.18);
}

select option { background: var(--bg-primary); color: var(--text-primary); }

/* -- Buttons --
   Reset first, then look is driven by context instead of per-button
   classes: size comes from where a button sits (a modal dialog is most
   compact, a nested "item row" section next, a top-level section largest),
   and color comes from position - the first button in a group is always
   the strong dark "do this" action, everything after it is whichever tan
   shade contrasts with its own nearest <section> (so it's never picked by
   hand per component - see the section/section-section rules below).
   Delete-type buttons, the tab bar, and the modal close (X) are their own
   exceptions, styled separately further down. */
button {
  font-family: inherit;
  cursor: pointer;
  border: none;
  background: none;
  color: inherit;
  appearance: none;
}

button:not(.delete):not(.tab):not(.tab-icon-btn):not(.modal-close):not(.challenge-tag) {
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 1px;
  padding: 8px 16px;
  border-radius: var(--radius-md);
  border: 0.5px solid var(--border-mid);
  background: var(--bg-secondary);
  color: var(--text-primary);
  white-space: nowrap;
  transition: background 0.12s, opacity 0.12s;
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

button:not(.delete):not(.tab):not(.tab-icon-btn):not(.modal-close):not(.challenge-tag):hover {
  background: var(--bg-primary);
}
button:not(.delete):not(.tab):not(.tab-icon-btn):not(.modal-close):not(.challenge-tag):active {
  transform: scale(0.98);
}

button:not(.delete):not(.tab):not(.tab-icon-btn):not(.modal-close):not(.challenge-tag):first-of-type {
  background: var(--accent-dark);
  color: var(--bg-primary);
  border-color: var(--accent-dark);
}
button:not(.delete):not(.tab):not(.tab-icon-btn):not(.modal-close):not(.challenge-tag):first-of-type:hover {
  opacity: 0.88;
  background: var(--accent-dark);
}

/* Non-first button, one section deep (a top-level, dark-tan section) -
   opposite tan, i.e. light. */
section button:not(.delete):not(.tab):not(.tab-icon-btn):not(.modal-close):not(.challenge-tag):not(:first-of-type) {
  background: var(--bg-primary);
}
section button:not(.delete):not(.tab):not(.tab-icon-btn):not(.modal-close):not(.challenge-tag):not(:first-of-type):hover {
  background: var(--bg-secondary);
}

/* Non-first button, two sections deep (a nested, light-tan "item row"
   section) - opposite tan the other way, i.e. dark again. */
section section button:not(.delete):not(.tab):not(.tab-icon-btn):not(.modal-close):not(.challenge-tag):not(:first-of-type) {
  background: var(--bg-secondary);
}
section section button:not(.delete):not(.tab):not(.tab-icon-btn):not(.modal-close):not(.challenge-tag):not(:first-of-type):hover {
  background: var(--bg-primary);
}

/* Nested "item row" sections (log entries, inventory tiles, recipe/explorer
   rows, per-game cards) read as compact rows, so their buttons run smaller
   than a top-level panel's main actions. */
section section button:not(.delete):not(.tab):not(.tab-icon-btn):not(.modal-close):not(.challenge-tag) {
  font-size: 10px;
  padding: 5px 10px;
}

/* Modals are dialogs, not panels - smallest tier regardless of nesting. */
#recipeModal button:not(.modal-close),
#backupModal button:not(.modal-close),
#aboutModal button:not(.modal-close) {
  font-size: 9px;
  padding: 4px 10px;
}

#installBanner button { font-size: 9px; padding: 4px 10px; }

/* -- Delete buttons (exception): every destructive action - Disconnect,
   deleting a game/challenge/log entry/inventory line - reads the same way:
   a trash-can look with a light red fill, regardless of where it sits. */
.delete {
  border: none;
  border-radius: var(--radius-md);
  background: rgba(184,50,50,0.15);
  color: var(--text-primary);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  font-family: var(--font-display);
  font-size: 10px;
  letter-spacing: 1px;
  padding: 5px 9px;
  white-space: nowrap;
}
.delete:hover { background: rgba(184,50,50,0.25); }
.delete:active { transform: scale(0.98); }

/* -- Inventory grid -- */
#invGrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  gap: 8px;
}

.inventory-tile { display: flex; flex-direction: column; gap: 7px; }

/* Fixed-height slot (SIZE.large, the biggest a material image gets) so a
   SIZE.small (85px) image sits centered in the same space a SIZE.large
   (100px) one would fill - keeping the name row below it at the same
   height across every card regardless of that card's image size. */
.inventory-image-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100px;
}

/* -- Material images (exception): width/height come from the width/height
   HTML attributes (materialSize: SIZE.large=100 or SIZE.small=85), matching
   how the same material's art renders everywhere else it's shown - see
   materialSize() in app.js. */
.inventory-img {
  object-fit: cover;
  border-radius: 5px;
  border: 0.5px solid var(--border-light);
  flex-shrink: 0;
  background: var(--bg-secondary);
}

.inventory-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.inventory-name {
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.3;
  text-align: left;
}

.qty-row { display: flex; align-items: center; justify-content: center; gap: 6px; }

input[type="number"].qty-input {
  width: 64px;
  flex-shrink: 0;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 600;
  padding: 5px 6px;
}

/* Recipe */
#recipeGrid, #combResults { display: flex; flex-direction: column; gap: 10px; }

.recipe-line, .explorer-row { transition: opacity 0.2s; }
.recipe-line.out-of-stock, .explorer-row.out-of-stock { opacity: 0.45; }

.recipe-line { display: flex; align-items: center; gap: 10px; }

.code-chip {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 1px;
  color: var(--text-primary);
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

/* Sized to match the surrounding text height, per-color shape (see
   COLOR_SHAPE in app.js) standing in for the colored box it replaced. */
.code-shape {
  width: 0.9em;
  height: 0.9em;
  flex-shrink: 0;
  margin-top: -2px;
}

.result-badge {
  font-size: 12px;
  font-style: italic;
  display: flex;
  align-items: center;
  gap: 4px;
}

.result-badge i { font-size: 11px; }
.result-known  { color: var(--success); }
.result-nothing { color: var(--danger); }
.result-unknown { color: var(--text-tertiary); }
.result-untried { color: var(--text-tertiary); }

/* Two tile images joined edge-to-edge, each rotated to the orientation
   that makes the touching colors match (see getRecipeCombinationsForPair). */
.tile-pair {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  flex-shrink: 0;
}

.tile-img {
  object-fit: cover;
  border: 0.5px solid var(--border-light);
  background: var(--bg-secondary);
}

/* A compact explorer row: one tile-pair image, plus one outcome (or two,
   for a pair with a reverse-read counterpart, see renderExplorer) shown
   beside it rather than as a tall stacked card. */
.explorer-row {
  display: flex;
  align-items: center;
  gap: 14px;
}

.explorer-outcomes {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  min-width: 0;
}

.explorer-outcome {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* -- Log -- */
.log-entry { display: flex; flex-direction: column; gap: 6px; }

.log-entry-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.log-code {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 600;
  min-width: 62px;
  letter-spacing: 1px;
  display: flex;
  align-items: center;
  gap: 3px;
}

.log-item {
  flex: 1;
  font-size: 13px;
  color: var(--text-primary);
  min-width: 80px;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.log-time { font-size: 11px; color: var(--text-tertiary); white-space: nowrap; }

/* -- Material images (exception): the two materials that produced a code
   (see materialDuoHtml), shown as a side-by-side icon pair on a Recipe
   row. -- */
.material-duo {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

/* Clips a material image down to just its center card, cropping away the
   decorative wood-grain frame and colored edge-matching shapes (see
   materialDuoHtml) - the image is zoomed to 200% and centered so the
   visible 50%-of-width/height center region fills the container
   edge-to-edge. */
.material-duo-crop {
  position: relative;
  overflow: hidden;
  border-radius: 3px;
  border: 0.5px solid var(--border-light);
  background: var(--bg-secondary);
  flex-shrink: 0;
}

/* transform (translate to center, plus the tile's rotation) is set inline
   per-image by materialDuoHtml(), since the rotation is data-dependent. */
.material-duo-crop img {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 200%;
  height: 200%;
  object-fit: cover;
}

/* One compact line per known code (see renderRecipe): code, then a
   fixed-width materials slot (empty when the materials aren't known), then
   the result - the fixed width keeps every row's result lined up in the
   same spot regardless of whether that row has materials to show. */
.recipe-line-materials {
  width: 160px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
}

.recipe-line-result { flex: 1; min-width: 0; }

/* -- Utility rows -- */
.form-row {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  flex-wrap: wrap;
}

.filter-row {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 0.75rem;
  flex-wrap: wrap;
}

.filter-row i { color: var(--text-tertiary); font-size: 14px; flex-shrink: 0; }
.filter-row input { flex: 1; min-width: 120px; }

.hint {
  font-size: 11px;
  color: var(--text-tertiary);
  font-style: italic;
  margin-top: 6px;
}

/* -- Checkbox label -- */
.check-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-display);
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--text-secondary);
  cursor: pointer;
}


#logResultPreview:not(:empty) { margin-top: 4px; }

/* -- Empty state -- */
.empty-state {
  text-align: center;
  padding: 2rem 1rem;
  color: var(--text-tertiary);
  font-style: italic;
  font-size: 14px;
}

/* -- Toast -- */
#toast {
  position: fixed;
  bottom: calc(24px + env(safe-area-inset-bottom));
  left: 50%;
  transform: translateX(-50%);
  background: var(--accent-dark);
  color: var(--bg-primary);
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 1px;
  padding: 10px 20px;
  border-radius: var(--radius-md);
  opacity: 0;
  transition: opacity 0.25s;
  pointer-events: none;
  z-index: 999;
  white-space: nowrap;
}

#toast.show { opacity: 1; }

/* -- Modals (recipe/backup/about): identified by id rather than a shared
   class, since there are exactly three of them and each is already
   uniquely id'd for JS anyway. Each wraps one top-level <section> for its
   content, so it already gets the standard dark-tan rounded-box look. -- */
#recipeModal, #backupModal, #aboutModal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 20px;
}

#recipeModal[hidden], #backupModal[hidden], #aboutModal[hidden] { display: none; }

#recipeModal section, #backupModal section, #aboutModal section {
  position: relative;
  padding: 24px 20px 20px;
  max-width: 380px;
  width: 100%;
  max-height: 80vh;
  overflow-y: auto;
}

/* -- Modal close (X) (exception) -- */
.modal-close {
  position: absolute;
  top: 8px;
  right: 8px;
  background: none;
  border: none;
  color: var(--text-tertiary);
  font-size: 15px;
  cursor: pointer;
  padding: 8px;
}

.modal-close:hover { color: var(--text-primary); }

.modal-title { padding-right: 22px; margin-bottom: 4px; }

/* -- Backup modal -- */
.backup-disclaimer {
  font-size: 12px;
  color: var(--text-secondary);
  line-height: 1.5;
  margin: 8px 0 14px;
}

.backup-disclaimer a { color: var(--accent-stone); }
.backup-disclaimer a:hover { color: var(--text-primary); }

.backup-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0;
}

#backupModalBody code {
  font-family: var(--font-display);
  font-size: 12px;
  background: var(--bg-tertiary);
  border: 0.5px solid var(--border-light);
  border-radius: 4px;
  padding: 2px 6px;
  letter-spacing: 0.5px;
}

/* -- Install banner -- */
#installBanner {
  display: none;
  background: var(--bg-secondary);
  border-top: 0.5px solid var(--border-light);
  padding: 10px 16px;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--text-secondary);
}

#installBanner.visible { display: flex; }
#installBanner strong { color: var(--text-primary); font-family: var(--font-display); font-size: 11px; letter-spacing: 1px; }

/* -- Active game badge -- */
.active-game-badge {
  font-size: 10px;
  letter-spacing: 0.5px;
  color: var(--text-secondary);
  font-style: italic;
  padding-top: 8px;
  padding-bottom: 8px;
}

.active-game-badge.none { color: var(--text-tertiary); }

/* -- Recipe rows (grouped, read-only view of discovered codes) -- */
.recipe-outcome-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.recipe-flavor {
  font-size: 12px;
  color: var(--text-secondary);
  font-style: italic;
  margin-top: 6px;
}

.recipe-meta {
  font-size: 11px;
  color: var(--text-tertiary);
  margin-top: 6px;
}

/* -- Challenge tag (exception - a status badge, not an action button, so it
   sits out of the generic button cascade above like .active-pill does) -- */
.challenge-tag {
  font-family: var(--font-serif);
  font-size: 11px;
  letter-spacing: 0;
  color: var(--text-secondary);
  background: var(--bg-tertiary);
  border: 0.5px solid var(--border-light);
  border-radius: var(--radius-md);
  padding: 4px 9px;
  cursor: pointer;
}

.tag-editor {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}

.tag-editor select,
.tag-editor input { width: auto; font-size: 12px; padding: 5px 8px; }

/* -- Challenges (games/campaigns) -- */
#sessionList {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.game-card { display: block; }

.game-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: 6px;
}

input.game-name-input {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  border: 0.5px solid transparent;
  background: transparent;
  padding: 2px 4px;
  flex: 1;
  min-width: 100px;
  width: auto;
}

input.game-name-input:hover,
input.game-name-input:focus {
  border-color: var(--border-mid);
  background: var(--bg-primary);
  box-shadow: none;
}

/* -- Active/status pill (exception) -- */
.active-pill {
  font-family: var(--font-display);
  font-size: 9px;
  letter-spacing: 0.5px;
  padding: 1px 8px;
  border-radius: var(--radius-md);
  background: var(--accent-stone);
  color: var(--accent-dark);
}

.game-used-label {
  font-size: 11px;
  color: var(--text-tertiary);
  font-style: italic;
  margin-top: 4px;
}

/* Nested Game > Epoch > Challenge list. <ul>/<ol> only ever appear in this
   one context in the whole app, so they're styled directly by tag rather
   than by a class. */
ul {
  list-style: disc;
  margin: 6px 0 0;
  padding-left: 18px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.epoch-bullet-label {
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 0.5px;
  color: var(--text-secondary);
}

/* display:flex on the <li>s below suppresses the browser's native ::marker,
   so the "1." style numbering (making it obvious e.g. epoch 1's first
   challenge was C101) is drawn by hand via a counter instead. */
ol {
  counter-reset: challenge-num;
  list-style: none;
  margin: 4px 0 0;
  padding-left: 0;
}

ol li {
  counter-increment: challenge-num;
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 12px;
  color: var(--text-primary);
  padding: 1px 0;
}

ol li::before {
  content: counter(challenge-num) ".";
  flex-shrink: 0;
  width: 16px;
  color: var(--text-tertiary);
}

/* The label is always the first of an entry's two <span>s, the date the
   second - relied on instead of a class for each. */
ol li span:nth-of-type(1) { flex: 1; }
ol li span:nth-of-type(2) {
  font-size: 10px;
  color: var(--text-tertiary);
  white-space: nowrap;
}

/* The add-challenge row is always rendered last in its <ol> (see
   renderChallenge), so it's targeted by position rather than a class. */
ol li:last-child { align-items: center; }

.add-challenge-form {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}

.add-challenge-form select { width: auto; min-width: 100px; font-size: 12px; }

/* -- Responsive -- */
@media (max-width: 440px) {
  #invGrid { grid-template-columns: repeat(2, 1fr); }
  .app-title { font-size: 18px; }
}
