/* ================================================================
   PAGES-SHARED.CSS — Cross-page rules that don't belong to one page:
   generic page containers (.home-container, .track-container, etc.),
   exercise library / kebab menus / coaching banners (used by Admin,
   Track, and Edit), uniform page padding, and the exercise-GIF
   mobile-enlarge fix.
   Part of the RustyBlade BootCamp stylesheet, split for maintainability.
   ================================================================ */

/* ================================================================
   SECTION 17: PAGE-SPECIFIC CONTAINERS
   ================================================================ */

.edit-container,
.settings-container,
.graph-container,
.admin-container,
.track-container,
.home-container {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 4px 0 8px 0;
}

.edit-container .header-section h2,
.settings-container > h2,
.graph-container > h2,
.admin-container > h2,
.track-container > h2,
.home-container .greeting {
  margin-top: 4px;
  margin-bottom: 0;
}

.edit-container .header-section .sub-greeting,
.settings-container .sub-greeting,
.graph-container .sub-greeting,
.admin-container .sub-greeting,
.track-container .sub-greeting {
  margin-top: 2px;
  margin-bottom: 8px;
}

/* FIX (mobile admin panel): baseline clamp for any admin-user-row text
   not already covered by a more specific inline clamp on its own
   element — a defensive floor rather than a visible change for most
   text here, since the row's children already set their own sizes. */
.admin-user-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 4px;
  border-bottom: 1px solid var(--border);
  transition: background 0.15s;
}
.admin-user-row:hover {
  background: var(--surface-variant);
}
.admin-user-row .user-checkbox {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  accent-color: var(--accent);
}
.admin-user-info {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
  /* Lets the name/email/meta text truncate instead of forcing the row
     to grow or wrap awkwardly — same reasoning as the reference. */
  min-width: 0;
}
.admin-user-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: clamp(0.8rem, 1.4vw, 0.95rem);
  flex-shrink: 0;
  border: 2px solid var(--border);
}
.admin-user-details {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.admin-user-name {
  font-weight: 600;
  font-size: clamp(0.8rem, 1.4vw, 0.9rem);
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
}
.admin-user-name-text {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.admin-user-badge {
  font-size: clamp(0.55rem, 0.9vw, 0.65rem);
  padding: 1px 6px;
  border-radius: 8px;
  font-weight: 600;
  flex-shrink: 0;
}
.admin-user-email {
  font-size: clamp(0.7rem, 1vw, 0.8rem);
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.admin-user-meta {
  font-size: clamp(0.6rem, 0.9vw, 0.7rem);
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.admin-user-controls {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
/* FIX (feature request): on narrow screens the two selects + kebab
   button (role / training-age / actions) were eating the entire row
   width, squeezing the name/email column down to an ellipsis. Wrapping
   the controls onto their own second line — aligned under the info
   column, not under the checkbox — keeps the user's name and email
   always readable at full width. Only kicks in below 640px, so the
   normal desktop single-row layout is unchanged. */
@media (max-width: 640px) {
  /* fix (row layout): the previous rule wrapped the controls onto their
     own line because they used to be three elements wide (role select,
     training-age select, kebab) and couldn't share a line with the
     avatar block. since the selects moved into the details modal, the
     controls are just a compact kebab — small enough to sit inline at
     the row's right edge. no wrap needed, and the list stays scannable
     on narrow screens. */
  .admin-user-row {
    flex-wrap: nowrap;
  }
  .admin-user-info {
    flex: 1 1 auto;
    min-width: 0;
  }
  .admin-user-controls {
    flex: 0 0 auto;
    padding-left: 0;
  }
}
.admin-user-controls .role-select {
  padding: 4px 6px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface-variant);
  color: var(--text);
  font-size: clamp(0.55rem, 0.9vw, 0.65rem);
  font-weight: 600;
  min-height: 32px;
  max-width: clamp(60px, 15vw, 100px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}
.admin-user-controls .training-age-select {
  padding: 4px 6px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface-variant);
  color: var(--text);
  font-size: clamp(0.55rem, 0.9vw, 0.65rem);
  font-weight: 600;
  min-height: 32px;
  max-width: clamp(75px, 17vw, 110px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}
@media (max-width: 480px) {
  .admin-user-row .role-select,
  .admin-user-row .training-age-select {
    min-height: 44px !important;
  }
}
@media (max-width: 480px) {
  /* Trim the meta line on the narrowest screens — name and email stay
     visible, template/logs/last-trained detail is the least essential
     of the three when space is genuinely tight. */
  .admin-user-meta {
    display: none;
  }
  .admin-user-avatar {
    width: 30px;
    height: 30px;
  }
}
@media (max-width: 768px) {
  /* FIX (design request): reduced from the 44px touch-target minimum to
     36px — smaller, tighter visual footprint per request, while staying
     above the 24px WCAG minimum tap-target guideline (below the more
     commonly recommended 44px, a deliberate tradeoff made explicitly).
     !important is required here: both elements carry inline
     min-height/min-width styles (for their default desktop sizing),
     and inline styles always beat an external stylesheet rule
     regardless of whether its media query matches — without
     !important this rule would silently never apply at all. */
  .admin-user-row .kebab-btn {
    min-height: 36px !important;
    min-width: 36px !important;
  }
  .admin-user-row .role-select {
    min-height: 44px !important;
  }
}


/* ================================================================
   SECTIONS 21–28: EXERCISE LIBRARY, KEBAB, COACHING, ETC.
   ================================================================ */

.muscle-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2px 6px;
  max-height: 80px;
  overflow: hidden;
}
@media (max-width: 992px) {
  .muscle-grid { grid-template-columns: repeat(3, 1fr); max-height: 100px; gap: 2px 4px; }
}
@media (max-width: 600px) {
  .muscle-grid { grid-template-columns: repeat(3, 1fr); max-height: 120px; gap: 2px 4px; }
  .muscle-grid label { font-size: 0.55rem !important; }
}
@media (max-width: 400px) {
  .muscle-grid { grid-template-columns: repeat(2, 1fr); max-height: 140px; gap: 2px 4px; }
  .muscle-grid label { font-size: 0.5rem !important; }
}
#libraryTab .muscle-label {
  display: none;
}

#exerciseLibraryTable td:nth-child(3),
#exerciseLibraryTable th:nth-child(3) {
  /* FIX (feature request: muscle column readability): each muscle name
     must stay on a single line. The inner <span> from edit.js carries
     white-space:nowrap, so nothing inside the cell ever wraps mid-word
     — the cell itself just needs to be wide enough to fit the longest
     name ("hamstrings", "front delt", "adductors") plus padding, and
     the block-level spans handle the vertical stacking.
     FIX (feature request: table whitespace balance): padding widened
     from 6px 4px to 6px 12px — content no longer touches the cell
     border, so adjacent columns read as distinct without needing a
     gridline between them. The 16px reclaimed from outer gutters
     (above) pays for this. */
  width: 100px;
  min-width: 100px;
  max-width: 100px;
  white-space: nowrap;
  line-height: 1.4;
  padding: 6px 12px;
  font-size: 0.65rem;
}
#exerciseLibraryTable th:nth-child(3) {
  text-align: left;
}
.table-wrapper {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
/* FIX (feature request: table whitespace balance): the table was
   sitting inside the card's 20px left/right padding, so the first
   column (GIF) had a visible empty gutter to its left and the last
   column (Actions) had one to its right — meanwhile the cells between
   columns were packed at only 4px of horizontal padding, which is
   what made the info feel cramped. The negative margin below pulls
   the table wrapper out to the card's actual edges (20px back on each
   side, leaving 6px of visual margin) so that reclaimed space is
   available inside the table; combined with the padding change below,
   every one of those reclaimed pixels is spent between columns rather
   than sitting as dead air at the ends. */
#libraryTab .table-wrapper {
  margin-left: -14px;
  margin-right: -14px;
  width: calc(100% + 28px);
}
#exerciseLibraryTable {
  table-layout: fixed;
  width: 100%;
  /* FIX (feature request: viewable at a glance): the old min-width:
     320px forced a horizontal scrollbar on any phone whose usable
     content width fell below 320px — which is nearly all of them once
     the page padding (16px × 2) and card padding are subtracted from a
     320–360px viewport. Removed, so the table now auto-fits its
     container. With table-layout: fixed, the column widths below are
     honoured within whatever horizontal space is available, and the
     GIF column may shrink slightly; content is never clipped, and no
     cell ever forces the table wider than its parent. */
}
#exerciseLibraryTable td:nth-child(4),
#exerciseLibraryTable th:nth-child(4) {
  /* FIX (feature request: table whitespace balance): mirror of the
     first cell — extra padding on the INNER edge (left of this cell)
     so the Actions buttons sit clearly separated from the muscle
     column, but trimmed outer padding on the right so the buttons sit
     near the visual card edge rather than inside a doubled gutter. */
  width: 76px;
  padding-left: 12px;
  padding-right: 4px;
}

/* FIX (feature request: GIF/exercise-name spacing): the exercise-name
   cell had no explicit padding rule, so it fell back to the browser
   default (~1px), which is why the name was sitting right against the
   GIF. 16px left padding gives the name a clear gap from the image
   while keeping the column at its normal width for the text itself.
   Also pads the right edge by 12px so the name doesn't crowd the
   muscle column when it wraps onto a second line. */
#exerciseLibraryTable td:nth-child(2),
#exerciseLibraryTable th:nth-child(2) {
  padding-left: 16px;
  padding-right: 12px;
}
#exerciseLibraryTable td:first-child,
#exerciseLibraryTable th:first-child {
  /* FIX (feature request: table whitespace balance): trimmed outer
     padding on the GIF cell specifically — the negative margin on
     .table-wrapper already gave it 14px of breathing room from the
     card edge, so 4px of internal padding here lands the image a
     comfortable ~10px from the visual edge without a doubled gutter.
     Extra padding stays on the INSIDE edge (right of this cell) via
     the general td padding rule below, so the gap between GIF and
     exercise name still reads clearly. */
  min-width: 88px;
  width: 88px;
  max-width: 88px;
  padding-left: 4px;
  padding-right: 12px;
}
#exerciseLibraryTable td:first-child img {
  max-height: 100px;
  max-width: 100%;
  object-fit: contain;
  border-radius: 4px;
}
@media (max-width: 600px) {
  #exerciseLibraryTable td:nth-child(3),
  #exerciseLibraryTable th:nth-child(3) {
    /* FIX (feature request: muscle column readability): same rule as
       desktop — each muscle stays on one line. 90px at 0.55rem (~8.8px)
       fits a 10-character name with room to spare. Font drop gives the
       column back a little width on phones without breaking the
       no-wrap guarantee. */
    width: 90px;
    min-width: 90px;
    max-width: 90px;
    font-size: 0.55rem;
    /* FIX (feature request: table whitespace balance): mobile padding
       matches desktop's inner-weighted pattern at a slightly smaller
       size, since phones have less total width to spend. */
    padding: 6px 8px;
  }
  #exerciseLibraryTable td:nth-child(4),
  #exerciseLibraryTable th:nth-child(4) { width: 60px; }
  /* FIX (GIF/name gap on mobile): the cell was 80px wide with 4px + 12px
     padding, leaving a 64px content area — but the image is forced to
     80px, so it overflowed 16px to the right and covered the exercise
     name cell's left padding. You could see the padding in the CSS but
     never on screen, because the image was sitting on top of it.
     Widened the cell to 96px so the 80px image fits inside with the
     12px right padding intact — that 12px is now a real, visible gap
     between the GIF and the name, on top of the 16px the name cell
     already has, for 28px total. */
  #exerciseLibraryTable td:first-child,
  #exerciseLibraryTable th:first-child {
    min-width: 96px;
    width: 96px;
    max-width: 96px;
  }
}
/* FIX (feature request: viewable at a glance): below 480px the previous
   column widths still left the muscle-group column wide enough to
   squeeze the exercise name down to a few characters. Tighten the
   fixed columns and stack the two action buttons vertically so the
   whole row genuinely fits without any horizontal scrolling — the
   muscle-group column is now narrow enough to just show 1–2 short
   words per line, and the exercise name gets the majority of the
   remaining width. The GIF image itself stays at its existing
   mobile-enlarge size (set in pages-shared-late.css), which this rule
   deliberately does not touch. */
@media (max-width: 480px) {
  #exerciseLibraryTable td:nth-child(3),
  #exerciseLibraryTable th:nth-child(3) {
    width: 44px;
    min-width: 44px;
    max-width: 44px;
    padding: 4px 1px;
    font-size: 0.5rem;
  }
  #exerciseLibraryTable td:nth-child(4),
  #exerciseLibraryTable th:nth-child(4) {
    width: 44px;
  }
  /* Stack the edit / delete buttons vertically so they fit in 44px */
  #exerciseLibraryTable td:nth-child(4) > div {
    flex-direction: column;
    gap: 3px;
  }
  #exerciseLibraryTable td:nth-child(4) .btn {
    min-height: 26px;
    padding: 0 6px;
  }
}
.exercise-expanded {
  display: none;
}
.exercise-expanded[style*="display:block"] {
  display: block !important;
}

/* Deprecated theme grid 3×3 */
.theme-grid-3x3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin-top: 4px;
}
.theme-card-3x3 {
  background: var(--surface);
  border: 2px solid var(--border);
  border-radius: 12px;
  cursor: pointer;
  text-align: center;
  padding: 12px 8px;
  transition: all 0.25s ease;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.theme-card-3x3:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.theme-card-3x3.active {
  border-color: var(--accent);
}
.theme-preview-3x3 {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--border);
  transition: border 0.2s;
}
.theme-card-3x3.active .theme-preview-3x3 {
  border-color: var(--accent);
}
.theme-name-3x3 {
  font-weight: 600;
  font-size: 0.7rem;
  color: var(--text-secondary);
  text-align: center;
}
.theme-card-3x3.active .theme-name-3x3 {
  color: var(--text);
}
@media (max-width: 600px) {
  .theme-grid-3x3 { grid-template-columns: repeat(3, 1fr); gap: 8px; }
  .theme-preview-3x3 { width: 36px; height: 36px; }
  .theme-name-3x3 { font-size: 0.6rem; }
}

.mi-swap-section label {
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--text-secondary);
  display: block;
  margin-bottom: 4px;
}
.mi-swap-section select:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
.mi-swap-section .swap-actions .btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.skeleton {
  background: var(--surface-variant);
  border-radius: 8px;
  animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 1; }
}
.skeleton-card {
  height: 80px;
  width: 100%;
  margin-bottom: 8px;
}
.skeleton-text {
  height: 12px;
  width: 60%;
  margin: 4px 0;
}

.kebab-wrapper {
  position: relative;
  display: inline-block;
}
.kebab-btn {
  font-size: 1.1rem;
  line-height: 1;
  padding: 0 6px;
  min-height: 28px;
  min-width: 28px;
  border-radius: 6px;
  border: none;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
  font-family: var(--font);
}
.kebab-btn:hover {
  background: var(--surface-variant);
}
.kebab-dropdown {
  display: none;
  position: fixed;
  width: auto;
  min-width: auto;
  max-width: 220px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow-lg);
  z-index: 9999;
  padding: 4px 0;
  animation: dropdownFade 0.15s ease;
  white-space: nowrap;
}
.kebab-dropdown.open {
  display: block;
}
@keyframes dropdownFade {
  from { opacity: 0; transform: translateY(-4px) scale(0.97); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
.kebab-item {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: 6px 12px;
  background: transparent;
  border: none;
  color: var(--text);
  font-size: clamp(0.55rem, 1vw, 0.7rem);
  cursor: pointer;
  text-align: left;
  font-family: var(--font);
  transition: background 0.15s, color 0.15s;
}
.kebab-item:hover {
  background: var(--surface-variant);
}
.kebab-item.delete-template-btn {
  color: var(--red);
}
.kebab-item.delete-template-btn:hover {
  background: var(--red-soft);
  color: var(--red);
}
.kebab-item.use-template-btn {
  color: var(--green);
}
.kebab-item.use-template-btn:hover {
  background: var(--green-soft);
  color: var(--green);
}
.kebab-item.duplicate-template-btn {
  color: var(--amber);
}
.kebab-item.duplicate-template-btn:hover {
  background: var(--amber-soft);
  color: var(--amber);
}
.kebab-item.edit-template-btn:hover {
  background: var(--accent-soft);
  color: var(--accent-text);
}
.kebab-item.view-history-btn:hover {
  background: var(--surface-variant);
  color: var(--text);
}
.kebab-item.delete-user-btn,
.kebab-item.unassign-template-btn {
  color: var(--red);
}
.kebab-item.delete-user-btn:hover,
.kebab-item.unassign-template-btn:hover {
  background: var(--red-soft);
  color: var(--red);
}
.kebab-item.view-user-logs-btn:hover {
  background: var(--accent-soft);
  color: var(--accent-text);
}
@media (max-width: 480px) {
  .kebab-dropdown { max-width: 180px; }
  .kebab-item { padding: 8px 10px; font-size: clamp(0.5rem, 1.2vw, 0.6rem); }
  .kebab-btn { min-height: 32px; min-width: 32px; font-size: 1.2rem; }
}

.coach-banner {
  animation: coachFadeSlide 0.3s ease;
}
@keyframes coachFadeSlide {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: translateY(0); }
}
.coach-banner .coach-dismiss {
  background: none;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 16px;
  padding: 2px 6px;
  flex-shrink: 0;
  transition: all 0.2s;
  border-radius: 4px;
  line-height: 1;
}
.coach-banner .coach-dismiss:hover {
  color: var(--text);
  background: var(--surface-variant);
}
.coach-banner .coach-show-ai {
  background: none;
  border: none;
  color: var(--accent-text);
  font-size: 11px;
  cursor: pointer;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 4px;
  transition: background 0.2s, color 0.2s;
  font-family: var(--font);
}
.coach-banner .coach-show-ai:hover {
  background: var(--accent-soft);
  color: var(--accent-hover);
}
.coach-banner .coach-show-coach {
  background: none;
  border: none;
  color: var(--accent-text);
  font-size: 11px;
  cursor: pointer;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 4px;
  transition: background 0.2s, color 0.2s;
  font-family: var(--font);
}
.coach-banner .coach-show-coach:hover {
  background: var(--accent-soft);
  color: var(--accent-hover);
}
.ai-suggestion {
  background: var(--surface-variant);
  border-radius: 8px;
  padding: 8px 12px;
  margin-bottom: 8px;
  animation: coachFadeSlide 0.3s ease;
}
.ai-suggestion-icon {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.ai-suggestion-icon i,
.ai-suggestion-icon svg {
  width: 12px !important;
  height: 12px !important;
}
.ai-suggestion .suggestion-text {
  flex: 1;
}
.ai-suggestion .coaching-dismiss {
  background: none;
  border: none;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: 1.2rem;
  padding: 0 4px;
  flex-shrink: 0;
  transition: all 0.2s;
}
.ai-suggestion .coaching-dismiss:hover {
  color: var(--text);
}
.pill-icon {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
}
.pill-icon-complete {
  color: var(--green, #4caf50);
}
.pill-icon-partial {
  color: var(--text-secondary);
}

/* ================================================================
   ONBOARDING — days-per-week slider thumb (feature request: UI
   redesign). appearance:none is required here for the custom thumb
   rules below to take effect at all — without it, browsers ignore
   ::-webkit-slider-thumb/::-moz-range-thumb entirely and fall back to
   their native default appearance.
   ================================================================ */
.training-age-option {
  text-align: left;
  padding: 12px 14px;
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  align-items: flex-start;
  background: var(--surface);
  border: 2px solid var(--border);
  cursor: pointer;
  font-family: var(--font);
  transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}
.training-age-option:hover {
  border-color: var(--accent);
}
.training-age-option.selected {
  border-color: var(--accent);
  background: var(--accent-soft);
  box-shadow: 0 0 0 1px var(--accent), 0 4px 14px rgba(198, 40, 40, 0.18);
}
.training-age-title {
  font-weight: 700;
  color: var(--text);
}
.training-age-desc {
  font-size: 11px;
  color: var(--text-muted);
}
.onboarding-step-label {
  flex: 1;
  text-align: center;
  font-size: 10px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  transition: color 0.25s ease;
}
.onboarding-step-label.active {
  color: var(--gold);
}
/* FIX (Track input font size + placeholder contrast): 16px is the
   minimum iOS Safari won't zoom when a field is focused — mandatory
   on touch devices. On desktop, 16px reads as visually oversized
   next to 14px body text and pulls the eye to the input fields
   instead of the logged sets above them. Media query drops it to
   14px only where the pointer is precise (mouse/trackpad). Touch
   devices keep 16px and behave exactly as before.
   Placeholder contrast: the default --text-muted is legible for body
   copy at 14-16px, but at input placeholder weight it reads as
   barely-there on dark backgrounds. --text-secondary is the next
   step up and was the intended value here — using it directly. */
@media (pointer: fine) {
  .weight-input,
  .reps-input,
  .rir-input,
  .stack-combined-input,
  .type-select,
  .unit-select {
    font-size: 14px !important;
  }
}
.weight-input::placeholder,
.reps-input::placeholder,
.rir-input::placeholder,
.stack-combined-input::placeholder {
  color: var(--text-secondary);
  opacity: 1; /* Firefox defaults placeholder opacity to 0.54; reset it */
}
