/* Generate page — page-specific styles. Tokens, base form controls, button
   variants, and the .rb-topnav primitive come from /shared/brand.css. */

[hidden] {
  display: none !important;
}

#app {
  max-width: 980px;
  margin: 0 auto;
  padding: 36px 24px 96px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* The chat benefits from a wider canvas while the form-heavy modes retain
   their deliberately compact reading width. generate.js keeps this data
   attribute in sync with the active tab. */
#app[data-mode="agent"] {
  max-width: 1160px;
}
#app[data-mode="agent"] #recent-runs-section {
  display: none;
}
/* The AG Guide runs two columns (the form and the output rail) and earns a
   wider canvas. */
#app[data-mode="agguide"] {
  max-width: 1220px;
}

#page-head {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 4px 14px;
}
/* .group, .group h3 and .hint come from /shared/brand.css. */
.group label {
  display: flex;
  flex-direction: column;
  gap: 7px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--fg-label);
}
/* One-line pointer shown under the tabstrip when the AG Guide has moved to
   its own host (generate.js AGGUIDE_MOVED_URL); the tab itself is removed. */
.agguide-moved {
  margin: 8px 0 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--fg-muted, var(--muted, #555));
}
.agguide-moved a {
  color: var(--accent-text, #d9531e);
  font-weight: 600;
  text-decoration: underline;
}

.hint code {
  font-family: var(--font-mono);
  background: var(--surface-alt);
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 11px;
}

textarea {
  resize: vertical;
  min-height: 140px;
  font-family: var(--font-body);
  font-size: 14px;
}

#badge-texts {
  text-transform: uppercase;
}

.copy-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
@media (max-width: 640px) {
  .copy-grid { grid-template-columns: 1fr; }
}

.copy-warning {
  padding: 8px 12px;
  border: 1px solid var(--state-warning);
  border-radius: 4px;
  background: rgba(255, 196, 0, 0.10);
  color: var(--state-warning);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
}

#image-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 12px;
}
#image-list:empty { display: none; }

#image-filter {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}
.image-filter-btn {
  padding: 4px 10px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--fg-muted);
  cursor: pointer;
}
.image-filter-btn:hover { color: var(--fg); border-color: var(--fg-muted); }
.image-filter-btn.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--rb-white);
}
#image-filter .hint { margin-left: auto; }

.thumb {
  position: relative;
  margin: 0;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.thumb img {
  width: 100%;
  height: 90px;
  object-fit: cover;
  display: block;
}
.thumb figcaption {
  font-size: 11px;
  color: var(--fg-muted);
  padding: 6px 8px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border-top: 1px solid var(--border);
}
.thumb-remove {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: 50%;
  line-height: 1;
  font-size: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--rb-black);
  color: var(--rb-white);
  border: none;
}
.thumb-remove:hover {
  background: var(--accent);
  color: var(--rb-white);
}
.thumb-hidden { display: none; }
.thumb-chip {
  position: absolute;
  top: 6px;
  left: 6px;
  padding: 2px 7px;
  border: none;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  color: var(--rb-white);
}
.thumb-chip-single { background: var(--accent); }
.thumb-chip-multi { background: var(--rb-black); }

#dimensions-controls {
  display: flex;
  gap: 8px;
}
#dimensions-controls button {
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
}

#dimensions-custom {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 12px;
  border: 1px dashed var(--border-strong);
  border-radius: 4px;
  background: var(--surface-alt);
}
#dimensions-custom .dim-custom-field {
  flex-direction: row;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--fg-muted);
}
#dimensions-custom input[type="number"] {
  width: 90px;
  padding: 6px 8px;
  font-variant-numeric: tabular-nums;
}
#dimensions-custom #custom-add {
  padding: 6px 12px;
  font-size: 12px;
}
#dimensions-custom .hint { margin-left: auto; }

#dimensions {
  border: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 8px;
}
.dim-item {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
  cursor: pointer;
  color: var(--fg);
  font-size: 13px;
  font-weight: 500;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.dim-item:hover {
  border-color: var(--fg);
}
.dim-item:has(input:checked) {
  border-color: var(--accent);
  background: rgba(232, 117, 17, 0.04);
}
.dim-item input {
  margin: 0;
  padding: 0;
  width: 16px;
  height: 16px;
  cursor: pointer;
  accent-color: var(--accent);
}
/* One-shot pulse confirming a freshly-added custom size. JS adds
   .dim-item-added then removes it on animationend, so the row self-resets. */
.dim-item-added {
  animation: dim-item-pulse 1s ease-out 1;
}
@keyframes dim-item-pulse {
  0%   { background: rgba(232, 117, 17, 0.22); }
  100% { background: rgba(232, 117, 17, 0.04); }
}
.dim-label {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.dim-tag {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
  color: var(--fg-muted);
  padding: 2px 6px;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: var(--surface-alt);
  white-space: nowrap;
}

#generate {
  padding: 14px 20px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

#status {
  min-height: 1.2em;
  color: var(--fg-muted);
  font-size: 13px;
}
#status.warn { color: var(--state-warning); }
#status.error { color: var(--state-error); }

.progress {
  width: 100%;
  height: 8px;
  background: var(--rb-black-10);
  border-radius: 999px;
  overflow: hidden;
}
.progress-fill {
  height: 100%;
  background: var(--accent);
  transition: width 0.15s ease;
}
.progress-label {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg-muted);
  margin-top: 6px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Transient note shown when an SSE stream dropped and recovered, so the
   forward jump in the bar isn't silent. Cleared on the next progress render. */
.progress-recovered {
  margin-top: 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--state-warning);
}

#results {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
#results:empty { display: none; }

.results-path {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface-alt);
}
.results-path code {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.results-path .copy-path {
  padding: 6px 12px;
  font-size: 12px;
}
.results-path .view-run {
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--rb-white);
  text-decoration: none;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 4px;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.results-path .view-run:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}

.recent-runs {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.recent-runs li {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface-alt);
}
.recent-runs .recent-meta {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.recent-runs .view-run {
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--rb-white);
  text-decoration: none;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 4px;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.recent-runs .view-run:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}

#results details {
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
}
#results details > summary {
  list-style: none;
  cursor: pointer;
  padding: 10px 12px;
  font-size: 11px;
  font-weight: 700;
  color: var(--fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  user-select: none;
}
#results details > summary::-webkit-details-marker { display: none; }
#results details > summary::before {
  content: '▸';
  display: inline-block;
  width: 14px;
  color: var(--fg-muted);
  transition: transform 0.1s ease;
}
#results details[open] > summary::before { transform: rotate(90deg); }

.results-list {
  margin: 0;
  padding: 4px 12px 12px 36px;
  list-style: disc;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg);
}
.results-list li { word-break: break-all; }

.results-error-header {
  margin: 8px 0 0;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--state-error);
}
.results-errors { color: var(--state-error); }

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, 0.36);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.modal-card {
  max-width: 460px;
  width: 100%;
  padding: 28px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.modal-card h3 {
  margin: 0;
  font-family: var(--font-headline);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.012em;
  color: var(--fg);
}
.modal-summary {
  margin: 0;
  font-size: 15px;
  color: var(--fg);
  line-height: 1.5;
}
.modal-summary strong {
  color: var(--accent-text);
  font-weight: 700;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* §3.3 — tab strip between page-head and the first panel section: a
   segmented control. Tokens from /shared/brand.css; no new colors. */
.rb-tabstrip {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 4px;
  padding: 4px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: rgba(0, 0, 0, 0.045);
  margin-bottom: 4px;
  overflow-x: auto;
  scrollbar-width: thin;
}
/* A host that serves one mode (the standalone AG Guide) has nothing to
   switch between; the strip would be a single grey button. */
.rb-tabstrip:has(> [role="tab"]:only-child) {
  display: none;
}
.rb-tabstrip [role="tab"] {
  position: relative;
  min-width: 0;
  min-height: 56px;
  padding: 10px 14px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--fg-muted);
  cursor: pointer;
  font-weight: 600;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  line-height: 1.2;
  transition: color 0.18s var(--ease), background 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.rb-tabstrip [role="tab"]:hover {
  color: var(--fg);
  background: rgba(255, 255, 255, 0.6);
}
/* Greyed (restricted) tab — present but inert, e.g. Maintenance Agent for
   anyone who isn't its allowlisted operator. */
.rb-tabstrip [role="tab"][aria-disabled="true"],
.rb-tabstrip [role="tab"][aria-disabled="true"]:hover {
  opacity: 0.45;
  cursor: not-allowed;
  color: var(--fg-muted);
  background: transparent;
  box-shadow: none;
}
.rb-tabstrip [data-mode][aria-selected="true"],
.rb-tabstrip[data-active="light"] [data-mode="light"],
.rb-tabstrip[data-active="ultra"] [data-mode="ultra"],
.rb-tabstrip[data-active="bulk"]  [data-mode="bulk"] {
  color: var(--fg);
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 4px 12px -4px rgba(0, 0, 0, 0.14);
}
.rb-tabstrip [data-mode][aria-selected="true"]::after {
  content: '';
  position: absolute;
  left: 30%;
  right: 30%;
  bottom: 5px;
  height: 3px;
  border-radius: 999px;
  background: var(--accent);
}
.rb-tab-tag {
  color: var(--fg-muted);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.01em;
  margin-left: 0;
}
/* Keep one unambiguous tab row on narrow screens. Horizontal scroll is less
   surprising than a wrapped tablist whose active underline changes rows. */
@media (max-width: 760px) {
  .rb-tabstrip {
    grid-template-columns: repeat(6, minmax(132px, 1fr));
    scroll-snap-type: x proximity;
  }
  .rb-tabstrip [role="tab"] {
    min-height: 54px;
    padding: 8px 12px;
    scroll-snap-align: start;
  }
}
#light-panel:not([hidden]),
#ultra-panel:not([hidden]),
#bulk-panel:not([hidden]) {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.recent-runs .recent-mode {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--surface-alt);
  color: var(--fg-muted);
  border: 1px solid var(--border);
}
.recent-runs .recent-mode-ultra {
  background: var(--accent);
  color: var(--rb-white);
  border-color: var(--accent);
}

/* §3.4 — ultra panel layout. KPI strip mirrors the PDF report's hero band;
   the winners list is a flex-wrap grid of selection cards. */
.ultra-kpi-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
}
.ultra-kpi-card {
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface-alt);
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 64px;
}
.ultra-kpi-label {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fg-muted);
}
.ultra-kpi-value {
  font-family: var(--font-mono);
  font-size: 18px;
  font-weight: 700;
  color: var(--fg);
}
.ultra-pattern-callout {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 10px 12px;
  border: 1px dashed var(--border-strong);
  border-radius: 4px;
  background: var(--surface-alt);
}
.ultra-pattern-pill {
  font-size: 11px;
  font-weight: 600;
  color: var(--fg);
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--border);
}

.ultra-winners {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
}
.ultra-winner-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  cursor: default;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.ultra-winner-card:hover { border-color: var(--fg-muted); }
.ultra-winner-selected {
  border-color: var(--accent);
  background: rgba(232, 117, 17, 0.06);
}
.ultra-winner-pick {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
}
.ultra-winner-pick input {
  width: 16px;
  height: 16px;
  margin: 0;
  cursor: pointer;
  accent-color: var(--accent);
}
.ultra-winner-thumb {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 4px;
  background: var(--surface-alt);
  display: block;
}
.ultra-winner-thumb-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 600;
  color: var(--fg-muted);
  text-align: center;
  padding: 8px;
  word-break: break-word;
}
.ultra-winner-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-muted);
}
.ultra-winner-ctr {
  font-size: 14px;
  font-weight: 700;
  color: var(--accent);
  display: flex;
  flex-direction: column;
  line-height: 1.1;
}
.ultra-winner-ctr small {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
  color: var(--fg-muted);
}
.ultra-winner-spend,
.ultra-winner-imps {
  font-size: 11px;
  color: var(--fg);
}
.ultra-winner-headline {
  font-size: 12px;
  font-weight: 600;
  color: var(--fg);
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.ultra-winner-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
  font-size: 10px;
}
.ultra-winner-template,
.ultra-winner-rank,
.ultra-winner-campaign {
  padding: 2px 6px;
  border-radius: 3px;
  background: var(--surface-alt);
  color: var(--fg-muted);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border: 1px solid var(--border);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.ultra-winner-template-select {
  padding: 1px 4px;
  border-radius: 3px;
  background: var(--surface-alt);
  color: var(--fg-muted);
  font-weight: 600;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border: 1px solid var(--border);
  max-width: 100%;
}
.ultra-winner-empty,
.ultra-winner-error {
  list-style: none;
  padding: 12px;
  border: 1px dashed var(--border-strong);
  border-radius: 4px;
  background: var(--surface-alt);
  color: var(--fg-muted);
  font-size: 13px;
}
.ultra-winner-error { color: var(--state-error); }
.ultra-winner-error .ultra-pack-retry {
  margin-left: 10px;
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 600;
}
/* Elapsed-seconds caption shown alongside the loading skeleton so a long cold
   load reads as progressing, not hung. Spans the winners grid so it sits above
   the skeleton cards. */
.ultra-pack-elapsed {
  grid-column: 1 / -1;
  color: var(--fg-muted);
  font-variant-numeric: tabular-nums;
}

.ultra-skeleton {
  background: linear-gradient(90deg, var(--surface-alt) 0%, var(--surface) 50%, var(--surface-alt) 100%);
  background-size: 200% 100%;
  animation: ultra-shimmer 1.4s ease-in-out infinite;
  min-height: 64px;
  border-radius: 4px;
}
.ultra-winner-card.ultra-skeleton {
  min-height: 240px;
  border-style: dashed;
}
@keyframes ultra-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

label.ultra-inline {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: 13px;
}
label.ultra-inline input[type="number"] {
  width: 80px;
  padding: 6px 8px;
  font-variant-numeric: tabular-nums;
}

#ultra-account {
  width: 100%;
}
#ultra-refresh {
  align-self: flex-start;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
}
#ultra-dimensions {
  border: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 8px;
}
#ultra-status {
  min-height: 1.2em;
  color: var(--fg-muted);
  font-size: 13px;
}
#ultra-status.warn { color: var(--state-warning); }
#ultra-status.error { color: var(--state-error); }

#ultra-results {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
#ultra-results:empty { display: none; }
#ultra-results .results-path {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface-alt);
}
#ultra-results .results-path code {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#ultra-results .copy-path {
  padding: 6px 12px;
  font-size: 12px;
}
#ultra-results .view-run {
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--rb-white);
  text-decoration: none;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 4px;
  transition: background 0.15s ease, border-color 0.15s ease;
}
#ultra-results .view-run:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}
#ultra-results details {
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
}
#ultra-results details > summary {
  list-style: none;
  cursor: pointer;
  padding: 10px 12px;
  font-size: 11px;
  font-weight: 700;
  color: var(--fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  user-select: none;
}
#ultra-results details > summary::-webkit-details-marker { display: none; }
#ultra-results details > summary::before {
  content: '▸';
  display: inline-block;
  width: 14px;
  color: var(--fg-muted);
  transition: transform 0.1s ease;
}
#ultra-results details[open] > summary::before { transform: rotate(90deg); }
#ultra-results .results-list {
  margin: 0;
  padding: 4px 12px 12px 36px;
  list-style: disc;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg);
}
#ultra-results .results-list li { word-break: break-all; }
#ultra-results .results-error-header {
  margin: 8px 0 0;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--state-error);
}
#ultra-results .results-errors { color: var(--state-error); }

.combobox {
  position: relative;
}
.combobox input[type="text"] {
  width: 100%;
  padding: 7px 10px;
  font-size: 13px;
  border: 1px solid var(--border-strong);
  border-radius: 3px;
  background: var(--surface);
  color: var(--fg);
  font-family: inherit;
  box-sizing: border-box;
}
.combobox input[type="text"]:focus {
  outline: none;
  border-color: var(--fg);
}
.combobox input[type="text"]:disabled {
  background: var(--surface-alt);
  color: var(--fg-muted);
  cursor: not-allowed;
}
.combobox-list {
  position: absolute;
  top: calc(100% + 2px);
  left: 0;
  right: 0;
  margin: 0;
  padding: 4px 0;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 3px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  max-height: 320px;
  overflow-y: auto;
  z-index: 210;
}
.combobox-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px 10px;
  cursor: pointer;
  border-left: 2px solid transparent;
}
.combobox-item.active,
.combobox-item:hover {
  background: var(--surface-alt);
  border-left-color: var(--fg);
}
.combobox-name {
  font-size: 13px;
  color: var(--fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.combobox-meta {
  font-size: 11px;
  color: var(--fg-subtle);
  font-family: var(--font-mono);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.combobox-empty,
.combobox-more {
  padding: 8px 10px;
  font-size: 12px;
  color: var(--fg-muted);
  font-style: italic;
}

.ultra-campaign-label .combobox { margin-top: 4px; }
.ultra-campaign-clear {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  background: transparent; border: 0; font-size: 18px; line-height: 1;
  color: var(--fg-subtle); cursor: pointer; padding: 2px 6px; border-radius: 3px;
}
.ultra-campaign-clear:hover { background: var(--surface-alt); color: var(--fg); }

/* Bulk-Upload tab — Segment 3. Tokens reuse /shared/brand.css; no new colors.
   `.row-*` and `.warn-*` are scoped to bulk tables to avoid leaking into the
   Light/Ultra panels. */
.bulk-dropzone {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 120px;
  padding: 16px;
  border: 2px dashed var(--border-strong);
  border-radius: 8px;
  background: var(--surface);
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.bulk-dropzone:hover { border-color: var(--fg-muted); }
.bulk-dropzone.is-active {
  background: rgba(232, 117, 17, 0.06);
  border-color: var(--accent);
}
.bulk-dropzone-label {
  text-align: center;
  color: var(--fg-muted);
  font-size: 13px;
  line-height: 1.5;
}

.bulk-naming-help {
  font-size: 12px;
  color: var(--fg);
  display: inline-block;
  margin-top: 6px;
  text-decoration: underline;
}
.bulk-naming-help:hover { color: var(--accent); }
.bulk-naming-doc {
  margin-top: 8px;
  padding: 12px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 12px;
  line-height: 1.6;
  color: var(--fg);
}
.bulk-naming-doc code {
  font-family: var(--font-mono);
  font-size: 11px;
  background: var(--surface);
  padding: 1px 5px;
  border-radius: 3px;
}

.bulk-summary {
  font-size: 12px;
  font-weight: 400;
  color: var(--fg-muted);
  text-transform: none;
  letter-spacing: normal;
}

/* Scroll container for the 6-column preview table: lets Matches/Warnings
   columns scroll into view on narrow viewports instead of clipping, with a
   right-edge gradient fade hinting there's more. The fade is painted on the
   scroll box itself and stays pinned because the box is the scroll viewport. */
.bulk-table-scroll {
  position: relative;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.bulk-table-scroll::after {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 28px;
  pointer-events: none;
  background: linear-gradient(to right, rgba(255, 255, 255, 0), var(--surface));
}

.bulk-preview-table,
.bulk-results-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  table-layout: auto;
}
/* Sticky header so column labels stay visible while scrolling a long batch.
   z-index sits below .combobox-list (210) and modals so dropdowns/overlays
   still paint above it; the solid surface fill keeps rows from showing
   through as they scroll under the header. */
.bulk-table-scroll .bulk-preview-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface);
}
.bulk-preview-table th,
.bulk-results-table th {
  text-align: left;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
  color: var(--fg-muted);
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-strong);
}
.bulk-preview-table td,
.bulk-results-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
  color: var(--fg);
}
.bulk-preview-table code,
.bulk-results-table code {
  font-family: var(--font-mono);
  font-size: 11px;
  background: var(--surface-alt);
  padding: 1px 4px;
  border-radius: 3px;
  word-break: break-all;
}
/* Loading placeholders for the preview body while /api/bulk/preview is in
   flight. Reuses the Ultra shimmer keyframes (.ultra-skeleton) so the body
   reads as pending instead of blank under the header. Non-interactive. */
.bulk-skeleton-row td { vertical-align: middle; }
.bulk-skeleton-cell {
  height: 14px;
  border-radius: 3px;
}

.bulk-preview-table tr.row-blocked { opacity: 0.55; }
.bulk-preview-table .row-error,
.bulk-results-table tr.row-error td { color: var(--state-error); }
.bulk-results-table tr.row-ok td   { color: var(--fg); }
/* Duplicate guard: the ad already existed in the target ad set (retry of a
   chunk that landed despite an edge timeout) — informational, not an error. */
.bulk-results-table tr.row-exists td { color: var(--fg-muted, #777); }
.row-warn { color: var(--state-warning); }

/* Degraded bulk result: sizes that were meant to group into one Flexible ad but
   shipped as separate single-image ads (Meta rejected the grouped shape). */
.bulk-degraded {
  color: var(--state-warning);
  font-size: 11px;
  margin-top: 3px;
}

/* Staged-files controls (task 7): accumulate across picks + clear. */
.bulk-files-controls {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 6px;
}
.bulk-clear-files {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 6px;
  cursor: pointer;
}
/* Names the files that were refused at staging (not images) so a drop that
   stages fewer files than were dropped explains itself. Warning-coloured, not
   error-coloured: the rest of the batch is fine and still previews. */
.bulk-files-skipped {
  margin-top: 6px;
  padding: 6px 10px;
  border-radius: 6px;
  border: 1px solid var(--state-warning);
  background: rgba(0, 0, 0, 0.03);
  color: var(--state-warning);
  font-size: 12px;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

/* Schedule-CSV (task 5) per-ad URL match note + summary banner. */
.bulk-schedule {
  font-size: 11px;
  margin-top: 3px;
  color: var(--text-muted, #555);
}
.bulk-schedule-warn { color: var(--state-warning); }
.bulk-schedule-dates { opacity: 0.85; }
.bulk-schedule-banner {
  font-size: 12px;
  margin: 0 0 8px;
  padding: 6px 10px;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.04);
}
.bulk-schedule-warnings {
  margin: 4px 0 0;
  padding-left: 18px;
  color: var(--state-warning);
}

/* Failed-preview row (task 7 issue 3): keeps the staged files recoverable
   in place with a Retry button instead of a dead table + stale push button. */
.bulk-preview-failed {
  padding: 14px 12px;
  text-align: center;
  color: var(--state-warning);
  font-size: 13px;
}
.bulk-retry-preview {
  margin-top: 8px;
  padding: 6px 14px;
  border: 1px solid currentColor;
  border-radius: 6px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}
.bulk-retry-preview:hover { background: rgba(178, 106, 0, 0.08); }
.bulk-retry-preview:disabled { cursor: default; opacity: 0.7; }
.bulk-retry-preview:disabled:hover { background: transparent; }

/* Push paused by Meta's rate limit (Kelvin 2026-08-14): the push is not
   failed, it is waiting out Meta's block and will resume the remaining ticked
   rows on its own. Warning-coloured, inline under the Push button, with a
   Stop that hands control back to the operator. */
.bulk-push-paused {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 8px;
  padding: 8px 12px;
  border-radius: 6px;
  border: 1px solid var(--state-warning);
  background: rgba(0, 0, 0, 0.03);
  color: var(--state-warning);
  font-size: 13px;
  line-height: 1.45;
}
.bulk-push-paused-stop {
  padding: 4px 12px;
  border: 1px solid currentColor;
  border-radius: 6px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}
.bulk-push-paused-stop:hover { background: rgba(178, 106, 0, 0.08); }

.warn-chip {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 8px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: rgba(178, 106, 0, 0.12);
  color: var(--state-warning);
  margin: 1px 4px 1px 0;
  white-space: nowrap;
}
.warn-chip.warn-no-pattern,
.warn-chip.warn-no-campaign,
.warn-chip.warn-no-live-adset,
.warn-chip.warn-adset-expired,
.warn-chip.warn-no-sibling,
.warn-chip.warn-below {
  background: rgba(176, 39, 26, 0.12);
  color: var(--state-error);
}
.warn-chip.warn-review,
.warn-chip.warn-at-threshold,
.warn-chip.warn-campaign-paused,
.warn-chip.warn-sibling-borrowed {
  background: rgba(178, 106, 0, 0.16);
  color: var(--state-warning);
}

/* Per-row state chips for the Part 3 routing-fix UI. Live next to adset /
   campaign names; thinner than warn-chips so they don't compete visually
   with the row-level warning column. */
.bulk-state-chip {
  display: inline-block;
  font-size: 11px;
  padding: 1px 6px;
  margin-left: 6px;
  border-radius: 3px;
  font-weight: 600;
  vertical-align: middle;
}
.bulk-state-campaign-paused {
  background: rgba(178, 106, 0, 0.16);
  color: var(--state-warning);
  border: 1px solid var(--state-warning);
}
.bulk-state-inherit-paused {
  background: rgba(74, 99, 120, 0.12);
  color: var(--fg-muted);
  border: 1px solid var(--border-strong);
  font-weight: 500;
}
.bulk-state-adset-paused {
  background: rgba(178, 106, 0, 0.12);
  color: var(--state-warning);
  border: 1px solid var(--state-warning);
  font-weight: 500;
}
.bulk-state-expired {
  background: rgba(176, 39, 26, 0.12);
  color: var(--state-error);
  border: 1px solid var(--state-error);
}
/* Borrowed-copy chip (Kelvin task 7): an empty ad set that will clone its copy
   from a peer ad set in the same campaign. Informational amber — benign and
   operator-overridable, distinct from the red "expired" hard-reject. */
.bulk-state-borrowed {
  background: rgba(178, 106, 0, 0.12);
  color: var(--state-warning);
  border: 1px solid var(--state-warning);
  font-weight: 500;
}

/* Expired adset rows: greyed but readable. :has() ships in modern Chrome /
   Safari / Firefox; older browsers fall back to no opacity which is still
   readable thanks to the EXPIRED chip + disabled checkbox. */
.bulk-adset-pick:has(input[data-expired="1"]) { opacity: 0.6; }

.bulk-match {
  margin-bottom: 6px;
  padding: 4px 6px;
  border-left: 2px solid var(--border-strong);
}
/* Campaign blocks outside the operator's status filter: unticked + dimmed.
   Checkboxes stay operable — a manual re-tick is an explicit override. */
.bulk-match.bulk-filtered-out { opacity: 0.45; }

/* Campaign-status scope radios above the preview table (task 8). */
.bulk-status-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 6px 0 10px;
  font-size: 13px;
}
.bulk-status-filter-label { font-weight: 600; }
.bulk-status-filter label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.bulk-status-filter-hint { flex-basis: 100%; }
/* Bulk tick / untick for every campaign the filter is showing (Kelvin 7/23). */
.bulk-tick-all {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
}
.bulk-tick-all-btn {
  font: inherit;
  font-size: 12px;
  padding: 3px 10px;
  border: 1px solid var(--border, #c9c9c9);
  border-radius: 4px;
  background: transparent;
  color: inherit;
  cursor: pointer;
}
.bulk-tick-all-btn:hover:not(:disabled) { background: rgba(127, 127, 127, 0.12); }
.bulk-tick-all-btn:disabled { opacity: 0.45; cursor: default; }
.bulk-match-header {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
}
.bulk-adset-pick {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: 20px;
  font: inherit;
  font-weight: 400;
}
.bulk-adset-tick:disabled,
.bulk-campaign-tick:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
/* Locked adset rows: dim + a faint diagonal hatch so the disabled state reads
   at a glance (not just a slightly-faded checkbox). The hatch is drawn behind
   the row content with a low-alpha border-strong tint; not-allowed cursor
   reinforces it on hover. */
.bulk-adset-pick:has(.bulk-adset-tick:disabled),
.bulk-adset-pick:has(.bulk-adset-tick[aria-disabled="true"]) {
  cursor: not-allowed;
  color: var(--fg-muted);
  background-image: repeating-linear-gradient(
    -45deg,
    transparent 0,
    transparent 5px,
    rgba(74, 99, 120, 0.10) 5px,
    rgba(74, 99, 120, 0.10) 7px
  );
  border-radius: 3px;
}

/* R3 confirm strip: yellow band above the campaign blocks on at-threshold
   rows. Disabled adset ticks read at 0.55 alpha so the operator sees the
   gate even without hovering. */
.bulk-row-confirm {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px;
  margin-bottom: 4px;
  background: rgba(178, 106, 0, 0.10);
  border: 1px solid var(--state-warning);
  border-radius: 3px;
  font-weight: 600;
  color: var(--state-warning);
}
.warn-ok {
  font-size: 11px;
  color: var(--state-success);
  font-weight: 600;
}

.sibling-excerpt { max-width: 280px; word-break: break-word; }
.sibling-excerpt small { color: var(--fg-muted); }
.adset-list { max-width: 240px; word-break: break-word; }
.adset-fanout {
  color: var(--fg-muted);
  font-size: 11px;
  margin-top: 2px;
}
.bulk-campaign-name { white-space: normal; word-break: break-word; }

#bulk-push { margin-top: 12px; align-self: flex-start; }

/* Bulk "Ad copy (optional)" repeaters. Copied from meta.css's .copy-* rules
   (the /generate surface loads only shared/brand.css + generate.css, not
   meta.css). Vanilla CSS, same CSS vars as the rest of the bulk tab. */
.bulk-copy-details > .hint { display: block; margin: 6px 0 10px; }
.bulk-copy-details > div { margin-bottom: 12px; }
.copy-repeater {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.copy-repeater > label { font-weight: 600; }
.copy-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.copy-row {
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.copy-row > input[type="text"],
.copy-row > textarea {
  flex: 1;
  padding: 7px 10px;
  font-size: 13px;
  border: 1px solid var(--border-strong);
  border-radius: 3px;
  background: var(--surface);
  color: var(--fg);
  font-family: inherit;
  box-sizing: border-box;
  width: auto;
}
.copy-row > textarea {
  min-height: 44px;
  resize: vertical;
}
.copy-remove {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  color: var(--fg-muted);
  padding: 0 8px;
  height: 28px;
  border-radius: 3px;
  cursor: pointer;
  font-size: 12px;
  line-height: 1;
  font-family: inherit;
  flex: 0 0 auto;
}
.copy-remove:hover {
  background: var(--surface-alt);
  color: var(--fg);
}
.copy-counter {
  margin-top: 4px;
}
.copy-add {
  align-self: flex-start;
  margin-top: 6px;
  padding: 4px 10px;
  font-size: 12px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  color: var(--fg);
  border-radius: 3px;
  cursor: pointer;
  font-family: inherit;
}
.copy-add:hover { background: var(--surface-alt); }
.copy-add:disabled { opacity: 0.5; cursor: not-allowed; }

/* AG Guide tab: a two-column workspace. The form runs down the left; the
   right rail is sticky and holds the output dock (a frosted card that stays
   pinned while the rail scrolls) and the saved-work panel. */
.ag-workspace {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 400px);
  gap: 20px;
  align-items: start;
}
.ag-controls {
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
}
.ag-field-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px 18px;
}
.ag-field-grid label {
  min-width: 0;
}
.ag-field-wide {
  grid-column: 1 / -1;
}
.ag-field-grid textarea {
  min-height: 84px;
  font-family: inherit;
}
/* Asana project picker: search input + button on one row. */
.ag-asana-picker {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
  align-items: center;
}
.ag-finalize-result {
  margin-top: 8px;
}
.ag-tm-library-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  align-items: end;
}
.ag-tm-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: flex-end;
}
.ag-tm-actions .rb-btn {
  white-space: nowrap;
}
.ag-tm-headshot-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 84px;
  gap: 14px;
  align-items: end;
}
.ag-tm-headshot-preview {
  width: 84px;
  height: 84px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--field-bg);
  overflow: hidden;
}
.ag-tm-headshot-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Hero image for the auction web page: revealed only when the operator answers
   Yes to the hero question, and pushed to Asana rather than printed. */
.ag-hero-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 104px;
  gap: 14px;
  align-items: end;
}
.ag-hero-row[hidden] {
  display: none;
}
.ag-hero-preview {
  width: 104px;
  height: 78px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--field-bg);
  overflow: hidden;
}
.ag-hero-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Live regions keep their line even when empty: a region that is
   display:none until its first message is not announced, and the reserved
   line keeps the buttons around it from shifting. */
#ag-tm-status,
#ag-asana-status,
#ag-ckpt-status,
#ag-finalize-status {
  min-height: 1.2em;
  color: var(--fg-muted);
  font-size: 13px;
  line-height: 1.5;
}
#ag-tm-status.error,
#ag-asana-status.error,
#ag-ckpt-status.error,
#ag-finalize-status.error {
  color: var(--state-error);
}
.ag-viewing-preview {
  display: block;
  margin-top: 2px;
  font-size: 12.5px;
  font-weight: 400;
  color: var(--fg-muted);
  min-height: 1.1em;
}
.ag-viewing-preview.error {
  color: var(--state-error);
}
.ag-section-hint {
  margin: -6px 0 4px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--fg-muted);
  max-width: 72ch;
}
.ag-autofill-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 2px;
}
.ag-autofill-row .ag-section-hint {
  margin: 0;
}
/* Search fields carry a magnifier; states re-declare the image because the
   shared hover/focus rules paint background-color only. */
#ag-tm-search,
#ag-ckpt-search,
#ag-asana-project-q {
  padding-left: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none' stroke='%23808080' stroke-width='1.8' stroke-linecap='round'%3E%3Ccircle cx='7' cy='7' r='4.5'/%3E%3Cpath d='M10.5 10.5L14 14'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: 14px 50%;
  background-size: 16px 16px;
}
.ag-tm-combo {
  position: relative;
}
.ag-tm-results {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 6px);
  z-index: 20;
  margin: 0;
  padding: 6px;
  list-style: none;
  max-height: 260px;
  overflow-y: auto;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .ag-tm-results { background: var(--surface); }
}
.ag-tm-results li {
  padding: 8px 12px;
  border-radius: 9px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  color: var(--fg);
  line-height: 1.35;
}
.ag-tm-results li.active,
.ag-tm-results li:hover {
  background: rgba(0, 0, 0, 0.055);
}
.ag-tm-results li.none {
  color: var(--fg-muted);
  font-weight: 400;
  cursor: default;
}
.ag-tm-result-meta {
  display: block;
  font-size: 12px;
  font-weight: 400;
  color: var(--fg-muted);
}
.ag-consigners {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 2px;
}
.ag-consigner-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
  gap: 12px;
  align-items: end;
  padding: 16px;
  border-radius: 16px;
  background: rgba(0, 0, 0, 0.025);
  border: 1px solid var(--hairline);
}
.ag-consigner-row .ag-consigner-name-field {
  grid-column: 1 / -1;
}
.ag-consigner-remove {
  align-self: end;
  white-space: nowrap;
  background: transparent;
  border-color: transparent;
  color: var(--fg-muted);
}
.ag-consigner-remove:hover:not(:disabled) {
  background: rgba(176, 39, 26, 0.08);
  border-color: transparent;
  color: var(--state-error);
}
.ag-tm2 {
  margin-top: 4px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
#ag-tm2-fields {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px;
  border-radius: 16px;
  background: rgba(0, 0, 0, 0.025);
  border: 1px solid var(--hairline);
}
#ag-tm2-fields[hidden] {
  display: none;
}
#ag-tm2-fields .ag-section-hint { margin: 0; }
#ag-tm2-remove { align-self: flex-start; }
#ag-tm2-add,
#ag-consigner-add { align-self: flex-start; }

/* Photos: a toolbar (order as a segmented control, auto-brighten as a
   switch), the help line, the bulk drop zone, then the boxes. */
.ag-photo-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px 16px;
}
.ag-order-radios {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  background: rgba(0, 0, 0, 0.05);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-pill);
}
label.ag-order-radio {
  position: relative;
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 0;
  padding: 7px 14px;
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: 600;
  color: var(--fg-muted);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.18s var(--ease), color 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.ag-order-radio:hover { color: var(--fg); }
.ag-order-radio input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  border: 0;
  opacity: 0;
  cursor: pointer;
}
.ag-order-radio:has(input:checked) {
  background: var(--surface);
  color: var(--fg);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08), 0 3px 10px -3px rgba(0, 0, 0, 0.16);
}
.ag-order-radio:has(input:focus-visible) {
  box-shadow: 0 0 0 3px var(--focus-ring);
}
label.ag-auto-brighten {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 10px;
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--fg);
  cursor: pointer;
}
.ag-order {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.ag-order-help {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--fg-muted);
  max-width: 78ch;
}
.ag-order-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.ag-order-actions:not(:has(button:not([hidden]))) { display: none; }
.ag-order-reset {
  padding: 7px 12px;
  font-size: 12.5px;
  border-radius: var(--radius-pill);
}
label.ag-bulk {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 14px;
  margin: 0;
  padding: 16px 18px;
  border: 1.5px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  background: rgba(0, 0, 0, 0.015);
  color: var(--fg-muted);
  font-size: 13px;
  font-weight: 400;
  line-height: 1.5;
  cursor: pointer;
  transition: border-color 0.18s var(--ease), background 0.18s var(--ease);
}
.ag-bulk:hover { border-color: var(--rb-black-60); background: rgba(0, 0, 0, 0.03); }
.ag-bulk.ag-drop {
  border-color: var(--accent, #E87511);
  background: var(--accent-soft);
}
.ag-bulk-icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--fg);
  color: var(--rb-white);
  font-size: 17px;
  line-height: 1;
}
.ag-bulk-text strong { color: var(--fg); font-weight: 600; }
.ag-slots {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.ag-page-slots {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.ag-page-slots-title {
  font-size: 11px;
  font-weight: 600;
  color: var(--fg-subtle);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.ag-slot-row {
  display: grid;
  gap: 5px;
}
.ag-slot-row-1 { grid-template-columns: minmax(0, 1fr); }
.ag-slot-row-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ag-slot-row-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ag-slot-row-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* Adjustable boxes (2026-09-04): a sized row's columns are its printed box
   widths (set inline by applyRowGeometry, with a 10px gutter column between
   boxes), and the rows of a page are separated by a gutter element. Both
   gutters are drag handles; the line shows on hover, while dragging, and on
   keyboard focus. */
.ag-slot-row-sized { gap: 0; }
.ag-page-slots-sized { gap: 0; }
.ag-page-slots-sized .ag-page-slots-title { margin-bottom: 6px; }
.ag-slot-gutter,
.ag-row-gutter {
  position: relative;
  touch-action: none;
  user-select: none;
  outline: none;
}
.ag-slot-gutter { cursor: col-resize; }
.ag-row-gutter { height: 10px; cursor: row-resize; }
.ag-slot-gutter::after,
.ag-row-gutter::after {
  content: '';
  position: absolute;
  border-radius: 2px;
  background: var(--accent, #E87511);
  opacity: 0;
  transition: opacity 0.15s ease;
}
.ag-slot-gutter::after { top: 6px; bottom: 6px; left: 50%; width: 4px; margin-left: -2px; }
.ag-row-gutter::after { left: 6px; right: 6px; top: 50%; height: 4px; margin-top: -2px; }
.ag-slot-gutter:hover::after,
.ag-row-gutter:hover::after,
.ag-slot-gutter:focus-visible::after,
.ag-row-gutter:focus-visible::after { opacity: 0.55; }
.ag-slot-gutter.ag-gutter-active::after,
.ag-row-gutter.ag-gutter-active::after { opacity: 1; }
/* The corner handle of a sized box: drag it in any direction (sideways for
   width, up or down for the row's height). Two diagonal grip lines, brighter
   on hover and while dragging. */
.ag-slot-resize {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 22px;
  height: 22px;
  cursor: nwse-resize;
  touch-action: none;
  user-select: none;
  z-index: 3;
  opacity: 0.75;
  background: linear-gradient(135deg, transparent 0 52%, #fff 52% 60%, transparent 60% 70%, #fff 70% 78%, transparent 78%);
  filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.8));
  transition: opacity 0.15s ease;
}
.ag-slot-resize:hover,
.ag-slot-resize.ag-gutter-active {
  opacity: 1;
  background: linear-gradient(135deg, transparent 0 52%, var(--accent, #E87511) 52% 60%, transparent 60% 70%, var(--accent, #E87511) 70% 78%, transparent 78%);
}
/* Size − / + row under the zoom pill: the box's printed size and two steps. */
.ag-slot-size {
  order: 3;
  display: flex;
  align-items: stretch;
  width: 100%;
  box-sizing: border-box;
  background: rgba(0, 0, 0, 0.9);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.ag-slot-size-btn {
  border: 0;
  padding: 0 6px;
  height: 18px;
  background: transparent;
  color: white;
  line-height: 18px;
  font-size: 11px;
  border-radius: 0;
  cursor: pointer;
}
button.ag-slot-size-btn:hover { background: rgba(255, 255, 255, 0.18); color: white; border-color: transparent; }
/* Removable boxes (2026-09-04): ⊟ at the right of the Size row takes the box
   out of its row (greyed on a row's only box); ⊞ at the right edge of a row
   short of its template's boxes puts one back. */
.ag-slot-box-remove {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border-left: 1px solid rgba(255, 255, 255, 0.12);
  font-size: 12px;
  white-space: nowrap;
}
.ag-slot-box-remove-text { font-size: 9px; letter-spacing: 0.02em; }
/* A narrow box keeps the icon and the tooltip only. */
.ag-slot-narrow .ag-slot-box-remove-text { display: none; }
.ag-slot-box-remove-off,
button.ag-slot-box-remove-off:hover {
  opacity: 0.3;
  cursor: default;
  background: transparent;
  color: white;
}
.ag-slot-empty-tools {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 4px 6px;
  max-width: 100%;
}
.ag-slot-empty-tools .ag-slot-empty-size { white-space: nowrap; }
.ag-slot-empty-tools .ag-slot-box-remove {
  height: 16px;
  line-height: 16px;
  padding: 0 5px;
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: 4px;
  color: white;
}
.ag-slot-empty-tools button.ag-slot-box-remove:hover { background: rgba(255, 255, 255, 0.2); color: white; border-color: rgba(255, 255, 255, 0.45); }
/* The ⊞ that puts a box back sits in a slim column at the row's right edge;
   the stack toggle (on the gutters, below) shares its look. */
.ag-row-tools {
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-self: center;
  justify-self: end;
}
.ag-row-add,
.ag-row-stack {
  width: 20px;
  height: 22px;
  padding: 0;
  border: 1px dashed var(--border-strong);
  border-radius: 6px;
  background: transparent;
  color: var(--fg-muted);
  font-size: 14px;
  line-height: 20px;
  cursor: pointer;
}
button.ag-row-add:hover,
button.ag-row-add:focus-visible,
button.ag-row-stack:hover,
button.ag-row-stack:focus-visible {
  border-color: var(--accent, #E87511);
  color: var(--accent, #E87511);
  background: transparent;
}
/* One column across the row (a lone box, a two-box row stacked): the grip
   only moves the row's height. */
.ag-slot-row-onecol .ag-slot-resize { cursor: ns-resize; }
/* Stacked boxes (2026-09-08, any row 2026-09-09): a row with a stacked pair
   has three grid rows (box, gutter, box); the pair's boxes take the top and
   bottom of their column with the stack gutter (a row handle) between, and
   everything else spans all three (set inline by renderSlots). The stack
   toggle sits on the line it works on, at its start so the line's middle is
   still the drag handle: ▤ at the top of the gutter between two photos that
   stand alone, ▥ at the left end of the gutter inside a pair. */
.ag-slot-gutter > .ag-row-stack,
.ag-stack-gutter > .ag-row-stack,
.ag-slot-gutter > button.ag-row-stack:hover,
.ag-stack-gutter > button.ag-row-stack:hover {
  position: absolute;
  z-index: 1;
  background: var(--surface, #fff);
}
.ag-slot-gutter > .ag-row-stack { top: 2px; left: 50%; transform: translateX(-50%); }
.ag-stack-gutter > .ag-row-stack { left: 2px; top: 50%; transform: translateY(-50%); }
.ag-row-stack-on {
  border-style: solid;
  border-color: var(--accent, #E87511);
  color: var(--accent, #E87511);
}
.ag-slots-held {
  margin: 0;
  font-size: 12.5px;
  color: var(--fg-muted);
}
.ag-slot-size-val {
  flex: 1;
  align-self: center;
  color: rgba(255, 255, 255, 0.85);
  font-size: 9px;
  line-height: 18px;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* A box: an empty one is a dark, dashed target ("+ Add"); a filled one is a
   dark frame around the photo, its overlay controls on top. */
.ag-slot {
  position: relative;
  min-height: 82px;
  border: 1px dashed rgba(255, 255, 255, 0.3);
  border-radius: 10px;
  background: linear-gradient(180deg, #2C2C2C 0%, #1B1B1B 100%);
  overflow: hidden;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transition: border-color 0.18s var(--ease), background 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.ag-slot:hover {
  border-color: rgba(255, 255, 255, 0.7);
}
.ag-slot-empty:hover {
  background: linear-gradient(180deg, #343434 0%, #222 100%);
}
.ag-slot[draggable="true"] { cursor: grab; }
.ag-slot.ag-dragging { opacity: .5; }
.ag-slot.ag-slot-drop-target { outline: 2px dashed var(--accent, #E87511); outline-offset: 2px; }
.ag-slot img {
  width: 100%;
  height: 100%;
  min-height: 82px;
  object-fit: cover;
  display: block;
  /* Live framing preview: the box is the printed image shape (see
     .ag-slot-row-sized) and the thumbnail is scaled by the zoom in force
     about the crop's focus point, which also positions the cover crop, so
     what shows is the window the page cuts: at 50% 50% the centred crop,
     elsewhere the photo moved inside its box (the arrows on the zoom row) or
     the vertical position the detector chose for a small box. Scaling a
     cover-fitted image about the same fraction it is positioned by shows
     the window at that fraction of the whole room (cover plus zoom), which
     is the renderer's left = focusX * (srcW - winW). */
  transform: scale(var(--ag-zoom, 1));
  transform-origin: calc(var(--ag-focus-x, 0.5) * 100%) calc(var(--ag-focus-y, 0.5) * 100%);
  object-position: calc(var(--ag-focus-x, 0.5) * 100%) calc(var(--ag-focus-y, 0.5) * 100%);
  transition: transform 0.15s ease;
}
/* Rows with server preview geometry: a filled box stacks a print-shaped photo
   frame, the zoom pill row, and the name field, so the whole crop is visible
   and the controls never cover it (the four-column frames are too short for
   overlays). Empty boxes keep the plain add target. */
.ag-slot-row-sized .ag-slot-sized {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  min-height: 0;
  background: #111;
}
.ag-slot-photo {
  position: relative;
  width: 100%;
  aspect-ratio: var(--ag-slot-aspect, 2 / 1);
  overflow: hidden;
  background: #1B1B1B;
  order: 1;
}
.ag-slot-photo img {
  min-height: 0;
}
.ag-slot-row-sized .ag-slot-sized .ag-slot-zoom {
  position: static;
  order: 2;
  width: 100%;
  box-sizing: border-box;
  border-radius: 0;
  background: rgba(0, 0, 0, 0.9);
  justify-content: flex-start;
  /* The pan arrows sit at the right of the row and drop under the pill in a
     box too narrow for both. */
  flex-wrap: wrap;
}
/* Move the photo inside its box (2026-09-04): ◀ ▲ ▼ ▶ and ⌖ on the zoom row.
   A greyed arrow means no room that way (or the edge is reached); ⌖ lights
   in the accent while the photo is moved by hand, like the manual zoom. */
.ag-slot-pan {
  display: inline-flex;
  align-items: stretch;
  margin-left: auto;
}
.ag-slot-pan-btn {
  border: 0;
  padding: 0;
  width: 17px;
  height: 18px;
  background: transparent;
  color: white;
  font-size: 9px;
  line-height: 18px;
  text-align: center;
  border-radius: 0;
  cursor: pointer;
}
.ag-slot-pan-centre { font-size: 13px; }
button.ag-slot-pan-btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.18); color: white; border-color: transparent; }
.ag-slot-pan-btn:disabled { opacity: 0.3; cursor: default; }
.ag-slot-pan-on,
.ag-slot-pan-on:disabled { background: var(--accent, #E87511); opacity: 1; }
.ag-slot-row-sized .ag-slot-sized .ag-slot-caption {
  position: static;
  order: 4;
  border-top: 0;
}
/* Narrow frames (the four-across boxes at ~110px, or a box the operator
   squeezed under 150pt of print; the page sets .ag-slot-narrow from the
   printed width): smaller corner controls so the photo stays visible. */
.ag-slot-narrow .ag-slot-remove,
.ag-slot-narrow .ag-slot-replace,
.ag-slot-narrow .ag-slot-secondary,
.ag-slot-narrow .ag-slot-feature {
  width: 17px;
  height: 17px;
  top: 4px;
  font-size: 11px;
}
.ag-slot-narrow .ag-slot-remove { right: 4px; }
.ag-slot-narrow .ag-slot-replace { right: 24px; }
.ag-slot-narrow .ag-slot-secondary { right: 44px; }
.ag-slot-narrow .ag-slot-feature { right: 64px; }
.ag-slot-narrow .ag-slot-label { top: 4px; left: 4px; padding: 1px 4px; font-size: 9px; }
.ag-slot-label {
  position: absolute;
  top: 5px;
  left: 5px;
  padding: 2px 6px;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.75);
  color: white;
  font-size: 10px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  z-index: 2;
}
.ag-slot-label-muted {
  font-weight: 700;
  opacity: 0.75;
}
.ag-slot-remove {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 0;
  padding: 0;
  background: rgba(0, 0, 0, 0.78);
  color: white;
  line-height: 1;
  z-index: 3;
  cursor: pointer;
}
.ag-slot-empty { background: linear-gradient(180deg, #2C2C2C 0%, #1B1B1B 100%); }
/* An empty box in a sized row takes the printed shape (in a row with photos
   it stretches to the row like any grid cell) and shows its printed size. */
.ag-slot-row-sized .ag-slot-sized-empty {
  flex-direction: column;
  gap: 4px;
  min-height: 0;
  aspect-ratio: var(--ag-slot-aspect, 2 / 1);
}
.ag-slot-empty-size {
  color: rgba(255, 255, 255, 0.7);
  font-size: 9px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.ag-slot-add {
  color: var(--rb-white);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 4px 11px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.14);
  pointer-events: none;
}
.ag-slot-filled { cursor: default; border-style: solid; border-color: rgba(0, 0, 0, 0.35); }
.ag-slot-filled[draggable="true"] { cursor: grab; }
.ag-slot-filled.ag-dragging { cursor: grabbing; }
/* The equipment-name field sits on the photo's dark bar; it is a text input,
   so every shared field rule is undone here by name. */
input.ag-slot-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  box-sizing: border-box;
  padding: 1px 6px;
  line-height: 1.15;
  border: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 0;
  box-shadow: none;
  background: rgba(0, 0, 0, 0.72);
  color: #fff;
  font-size: 10px;
  font-family: inherit;
  z-index: 3;
  transition: none;
}
input.ag-slot-caption:hover { background: rgba(0, 0, 0, 0.78); }
input.ag-slot-caption::placeholder { color: rgba(255, 255, 255, 0.6); }
input.ag-slot-caption:focus {
  outline: 2px solid var(--accent, #E87511);
  outline-offset: -2px;
  background: rgba(0, 0, 0, 0.86);
  border-color: rgba(255, 255, 255, 0.18);
  box-shadow: none;
}
/* Selecting the equipment name must stay readable. The field paints white text on
   a dark bar; with no ::selection rule the browser falls back to its default
   selected-text colour (dark glyphs), which reads as near-black on the dark bar
   (Venice 2026-07-08 "highlighting equipment name is black and hard to read").
   Force white text on the brand accent so the selection is high-contrast. */
.ag-slot-caption::selection {
  color: #fff;
  background-color: var(--accent, #E87511);
}
.ag-slot-caption::-moz-selection {
  color: #fff;
  background-color: var(--accent, #E87511);
}
.ag-slot-replace {
  position: absolute;
  top: 5px;
  right: 31px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 0;
  padding: 0;
  background: rgba(0, 0, 0, 0.78);
  color: white;
  line-height: 1;
  font-size: 12px;
  z-index: 3;
  cursor: pointer;
}
/* Secondary-consigner mark (AG Guide Phase II): a per-photo asterisk toggle in
   the same circular-button rail as replace/remove. Toggled on = brand accent,
   matching the asterisk the renderer prints on the item and beside the
   secondary consigner line. */
.ag-slot-secondary {
  position: absolute;
  top: 5px;
  right: 57px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 0;
  padding: 0;
  background: rgba(0, 0, 0, 0.78);
  color: white;
  line-height: 1;
  font-size: 14px;
  font-weight: 700;
  z-index: 3;
  cursor: pointer;
}
.ag-slot-secondary-on { background: var(--accent, #E87511); }
/* Featured pair (2026-09-03): a per-photo star in the same rail. Starred photos
   (two at most) lead the grid and print large in the top row; the frame gets
   an accent inset so the pair reads at a glance. */
.ag-slot-feature {
  position: absolute;
  top: 5px;
  right: 83px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 0;
  padding: 0;
  background: rgba(0, 0, 0, 0.78);
  color: white;
  line-height: 1;
  font-size: 13px;
  z-index: 3;
  cursor: pointer;
}
.ag-slot-feature-on { background: var(--accent, #E87511); }
.ag-slot-featured .ag-slot-photo { box-shadow: inset 0 0 0 2px var(--accent, #E87511); }
button.ag-slot-remove:hover,
button.ag-slot-replace:hover,
button.ag-slot-secondary:hover,
button.ag-slot-feature:hover {
  background: rgba(0, 0, 0, 0.92);
  color: white;
  border-color: transparent;
}
button.ag-slot-secondary-on:hover { background: var(--accent-hover); }
button.ag-slot-feature-on:hover { background: var(--accent-hover); }
/* Manual per-photo zoom (Anna 2026-09-01): a − Auto/% + pill sitting just above
   the caption bar. The readout doubles as the reset-to-Auto button and flips to
   the brand accent while a manual factor is in force, mirroring the secondary
   toggle's on-state language. */
.ag-slot-zoom {
  position: absolute;
  left: 5px;
  bottom: 26px;
  display: flex;
  align-items: stretch;
  border-radius: 9px;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.78);
  z-index: 3;
}
.ag-slot-zoom-btn,
.ag-slot-zoom-val {
  border: 0;
  padding: 0 6px;
  height: 18px;
  background: transparent;
  color: white;
  line-height: 18px;
  font-size: 11px;
  border-radius: 0;
  cursor: pointer;
}
.ag-slot-zoom-val {
  font-size: 9px;
  font-weight: 700;
  min-width: 30px;
  text-align: center;
  padding: 0 2px;
  font-variant-numeric: tabular-nums;
}
button.ag-slot-zoom-btn:hover,
button.ag-slot-zoom-val:hover { background: rgba(255, 255, 255, 0.18); color: white; border-color: transparent; }
.ag-slot-zoom-manual .ag-slot-zoom-val,
.ag-slot-zoom-manual button.ag-slot-zoom-val:hover { background: var(--accent, #E87511); color: white; }
/* Auto readout: the factor the automatic framing will print at (from the
   server's look at the photo), shown beside the pill while Auto is in force. */
.ag-slot-zoom-auto {
  align-self: center;
  padding: 0 6px 0 2px;
  color: rgba(255, 255, 255, 0.85);
  font-size: 9px;
  line-height: 18px;
  white-space: nowrap;
}
.ag-slot-zoom-auto[hidden] { display: none; }
/* Right-hand rail: Output + Save progress live here (Erica 2026-07-10 asked for
   the save button on the right, always in reach) and stick together while the
   long left column scrolls. The rail scrolls internally once a preview is
   open, and the output dock stays pinned at its top: the frosted card the
   saved-work panel slides under. */
.ag-side {
  position: sticky;
  top: calc(var(--nav-h) + 16px);
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
  max-height: calc(100vh - var(--nav-h) - 32px);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  padding: 4px 10px 28px;
  margin: -4px -10px 0;
}
.ag-output {
  position: sticky;
  top: 0;
  z-index: 3;
  gap: 10px;
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border-color: rgba(0, 0, 0, 0.09);
  box-shadow: var(--shadow-md);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .ag-output { background: var(--surface); }
}
/* With a PDF preview or an Asana link open the card is tall; pinned, it
   would cover the saved-work panel scrolling under it, so it scrolls with
   the rail like any other card until the result is cleared. */
.ag-output:has(#ag-result:not([hidden])),
.ag-output:has(#ag-finalize-result:not([hidden])) {
  position: static;
}
.ag-output h3 { margin-bottom: 4px; }
#ag-render {
  padding: 13px 20px;
  font-size: 15px;
  font-weight: 700;
  border-radius: 13px;
}
#ag-finalize {
  padding: 12px 20px;
  font-size: 14.5px;
  border-radius: 13px;
}
/* Keep the checkpoint history compact inside the sticky rail; the list scrolls
   internally instead of pushing the panel off-screen. */
.ag-side .ag-ckpt-list {
  max-height: 240px;
  overflow-y: auto;
}
#ag-status {
  min-height: 1.2em;
  color: var(--fg-muted);
  font-size: 13px;
  line-height: 1.5;
}
#ag-status.error {
  color: var(--state-error);
}
.ag-warnings {
  margin: 0;
  padding: 10px 14px 10px 30px;
  border: 1px solid rgba(232, 117, 17, 0.35);
  border-radius: 12px;
  background: var(--state-warning-bg);
  color: var(--state-warning);
  font-size: 12.5px;
  line-height: 1.5;
}
.ag-result {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 6px;
  border-top: 1px solid var(--hairline);
}
.ag-result .rb-btn {
  align-self: flex-start;
}
.ag-preview-zoom {
  max-width: 180px;
}
.ag-preview-zoom select { padding: 7px 36px 7px 12px; line-height: 20px; font-size: 13px; }
#ag-preview {
  width: 100%;
  height: 640px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--field-bg);
}
@media (max-width: 960px) {
  .ag-workspace {
    grid-template-columns: 1fr;
  }
  .ag-side {
    position: static;
    max-height: none;
    overflow: visible;
    margin: 0;
    padding: 0;
  }
  .ag-output { position: static; }
}
@media (max-width: 640px) {
  .ag-field-grid {
    grid-template-columns: 1fr;
  }
  .ag-tm-library-row,
  .ag-tm-headshot-row,
  .ag-hero-row {
    grid-template-columns: 1fr;
  }
  .ag-consigner-row {
    grid-template-columns: 1fr;
  }
  .ag-slot-row-4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .ag-photo-toolbar > * { min-width: 0; max-width: 100%; }
  .ag-order-radios { width: 100%; }
  label.ag-order-radio {
    flex: 1 1 0;
    min-width: 0;
    justify-content: center;
    text-align: center;
    padding: 7px 8px;
    font-size: 12px;
    line-height: 1.25;
    white-space: normal;
  }
  label.ag-bulk { padding: 14px; }
}

/* AG Guide build checkpoints (save progress & rollback) */
.ag-checkpoints .ag-ckpt-bar {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 8px;
}
.ag-checkpoints .ag-ckpt-bar label { grid-column: 1 / -1; }
.ag-checkpoints .ag-ckpt-bar select { width: 100%; }
.ag-checkpoints .ag-ckpt-save {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 6px;
}
.ag-checkpoints .ag-ckpt-save input { width: 100%; }
.ag-checkpoints .ag-ckpt-save .rb-btn { width: 100%; padding: 11px 16px; border-radius: 12px; }
.ag-checkpoints .ag-ckpt-search { margin-bottom: 8px; }
.ag-ckpt-search-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 7px;
}
.ag-ckpt-search-head label {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--fg-label);
}
.ag-ckpt-search-head .rb-btn {
  min-height: 30px;
  padding: 4px 11px;
  font-size: 12.5px;
  border-radius: var(--radius-pill);
}
.ag-checkpoints .ag-ckpt-search input { width: 100%; }
.ag-ckpt-search-help,
.ag-ckpt-search-summary {
  display: block;
  margin-top: 6px;
  color: var(--fg-muted);
  font-size: 12.5px;
  line-height: 1.5;
}
.ag-ckpt-search-summary:not(:empty) { color: var(--fg); font-weight: 600; }
.ag-ckpt-search-summary[data-state="error"] { color: var(--state-error); }
.ag-ckpt-search-results {
  list-style: none;
  max-height: 240px;
  margin: 8px 0 0;
  padding: 4px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}
.ag-ckpt-search-results li + li { border-top: 1px solid var(--hairline); }
.ag-ckpt-search-result {
  display: flex;
  width: 100%;
  flex-direction: column;
  gap: 2px;
  padding: 9px 12px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--fg);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.ag-ckpt-search-result:hover { background: rgba(0, 0, 0, 0.045); border-color: transparent; }
.ag-ckpt-search-result:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.ag-ckpt-search-result-title { font-weight: 600; overflow-wrap: anywhere; }
.ag-ckpt-search-result-meta { color: var(--fg-muted); font-size: 12px; font-weight: 400; overflow-wrap: anywhere; }
.ag-ckpt-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ag-ckpt-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 12px;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  background: var(--surface-alt);
}
.ag-ckpt-list li.none {
  color: var(--fg-muted);
  border-style: dashed;
  border-color: var(--border-strong);
  background: transparent;
  justify-content: flex-start;
  font-size: 13px;
  line-height: 1.5;
}
.ag-ckpt-list li.ag-ckpt-search-target {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--focus-ring);
}
.ag-ckpt-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ag-ckpt-title { color: var(--fg); font-weight: 600; font-size: 13.5px; overflow-wrap: anywhere; }
.ag-ckpt-meta { color: var(--fg-muted); font-size: 12px; }
.ag-ckpt-restore { flex: 0 0 auto; padding: 6px 12px; font-size: 13px; border-radius: var(--radius-pill); }

/* Upload progress for Generate / Finalize (Erica 2026-09-02: a 30 MB photo
   upload was the step that failed, silently). A thin accent bar under the
   status line fills as the bytes go up and carries a "12 of 31 MB" label. */
.ag-upload-progress {
  position: relative;
  margin: 4px 0 2px;
  padding-top: 6px; /* the track */
}
.ag-upload-progress::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 6px;
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.08);
}
.ag-upload-progress-bar {
  position: absolute;
  top: 0;
  left: 0;
  height: 6px;
  width: 0;
  border-radius: 3px;
  background: var(--accent, #E87511);
  transition: width 0.12s linear;
}
.ag-upload-progress-label {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  color: var(--fg-muted, #666);
  font-variant-numeric: tabular-nums;
}
.ag-upload-progress.ag-upload-progress-done .ag-upload-progress-bar { background: var(--state-success); }
.ag-upload-progress.ag-upload-progress-error .ag-upload-progress-bar { background: var(--state-error); }
