/* ============================================
   NEGATIVE KEYWORD RECOMMENDATIONS
   (/app/google-ads/{account-id}/negative-keywords/)
   ============================================
   Self-contained: this page does not load page-app.css or
   page-google-ads.css, so anything shared with those (error alert, retry
   button, skeleton pulse keyframe) is duplicated here rather than depended
   on, matching the pattern already used by page-meta-monitor.css. */

#negkw-page {
  min-height: 60vh;
}

/* .app-breadcrumb itself is defined globally in style.css (shared,
   identical markup/classes with the Google Ads dashboard and Meta Spend
   Monitor breadcrumbs). */

/* ---- Duplicated auth-gate loading state ---- */
/* .app-loading isn't defined in style.css itself (it's a per-page component,
   duplicated across page-app.css/page-meta-monitor.css/page-gads-setup.css)
   -- needed here for the #negkw-auth-loading gate that prevents the logged-
   out flash, see CLAUDE.md. Same rule as page-app.css/page-meta-monitor.css. */

.app-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  padding-block: var(--space-12);
  text-align: center;
}

/* ---- Duplicated error alert / retry button ---- */

.negkw-state {
  margin-bottom: var(--space-6);
}

.app-error-alert {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.app-retry-btn {
  background: transparent;
  color: var(--color-danger);
  border: 1.5px solid var(--color-danger);
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  border-radius: var(--radius-md);
  white-space: nowrap;
  transition: background-color var(--transition-fast);
}

.app-retry-btn:hover {
  background: #FEE2E2;
}

/* ============================================
   PAGE HEADER
   ============================================ */

.negkw-header {
  margin-bottom: var(--space-8);
}

.negkw-header__title {
  margin-bottom: var(--space-5);
}

/* ---- Summary stats bar ---- */

.negkw-summary-bar {
  display: flex;
  gap: var(--space-4);
  flex-wrap: wrap;
  /* Was --space-2, sized to sit under the old .negkw-summary-explainer text
     line (its own --space-5 margin did the rest). That line is gone (the
     methodology explainer is now a hover popover on the waste pill itself,
     see .has-popover in style.css), so the bar carries the full gap to the
     next section itself. */
  margin-bottom: var(--space-5);
}

.negkw-stat-pill {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 9999px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  color: var(--color-text-muted);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}

.negkw-stat-pill svg {
  flex-shrink: 0;
  color: var(--color-primary);
}

.negkw-stat-danger {
  color: var(--color-danger);
  font-weight: 700;
}

/* ---- "Last Audit" pill while an audit is queued/running -- see
   lastAuditPillHTML() in page-negative-keywords.js. Same pill shell, just
   stacked (icon+label row, then a thin progress bar) instead of a single
   inline row. ---- */

.negkw-stat-pill--progress {
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  min-width: 200px;
}

.negkw-audit-progress-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.negkw-audit-progress-bar {
  width: 100%;
  height: 6px;
  background: var(--color-border);
  border-radius: 9999px;
  overflow: hidden;
}

.negkw-audit-progress-fill {
  height: 100%;
  background: var(--color-primary);
  border-radius: 9999px;
  transition: width 0.4s ease;
}

/* ---- Action bar: Run New Analysis + status filter pills ---- */

.negkw-action-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.negkw-action-bar__left {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* Deliberately not .btn/.btn--secondary anymore -- a plain text link
   reduces this control's visual weight since it's a secondary, occasional
   action, not competing with the page's real primary actions (Approve/
   Apply). Same treatment as .tile-run-analysis-link on the Google Ads
   Dashboard (page-google-ads.css) for the equivalent "has results" state. */
.negkw-run-analysis-btn {
  background: none;
  border: none;
  padding: 0;
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: var(--weight-semibold);
  color: var(--color-text-muted);
  cursor: pointer;
  transition: color var(--transition-fast);
}

.negkw-run-analysis-btn:hover {
  color: var(--color-primary);
}

.negkw-status-filters {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.negkw-status-filter {
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 9999px;
  border: 1.5px solid var(--color-border);
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.negkw-status-filter:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.negkw-status-filter--active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #FFFFFF;
}

/* .negkw-status-filter:hover above (one class + one pseudo-class) is equal
   specificity to .negkw-status-filter--active (one class) -- on an active
   pill's hover state, the hover rule's `color: var(--color-primary)` was
   winning and turning the text the same blue as the pill's own filled
   background, reading as invisible. Combining both classes here makes this
   rule unambiguously more specific regardless of source order, and darkens
   the background slightly (reusing the existing --color-primary-hover
   token already used for hover feedback on other primary-colored controls)
   so the active pill still reads as interactive on hover. */
.negkw-status-filter.negkw-status-filter--active:hover {
  background: var(--color-primary-hover);
  border-color: var(--color-primary-hover);
  color: #FFFFFF;
}

/* ============================================
   FILTER / SORT CONTROLS
   ============================================
   Sorting moved from a Sort dropdown to click-to-sort column headers (see
   .negkw-th-sortable), matching the Meta Spend Monitor table, so the
   controls bar now holds just the Advanced Filters dropdown plus a short
   hint. */

.negkw-controls-bar {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-bottom: var(--space-6);
}

.negkw-sort-hint {
  font-size: 13px;
  margin: 0;
}

.negkw-run-analysis-hint {
  font-size: 13px;
  margin: var(--space-2) 0 0;
}

/* ============================================
   SELECT-ALL-ACROSS-PAGES BANNER
   ============================================
   Shown above the results table when every pending row on the current page
   is selected, offering to extend the selection to every pending
   recommendation matching the active filters (not just the visible page). */

.negkw-selectall-banner {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  background: var(--color-primary-light);
  border: 1px solid var(--color-primary);
  border-radius: 8px;
  padding: 10px 16px;
  margin-bottom: var(--space-3);
  font-size: 13px;
  color: var(--color-dark);
}

.negkw-selectall-banner__link {
  color: var(--color-primary);
  font-weight: 600;
  text-decoration: underline;
  white-space: nowrap;
  cursor: pointer;
}

/* ============================================
   BULK ACTION TOAST
   ============================================
   Brief success confirmation after a bulk approve/dismiss completes.
   Reuses the shared .alert--success look; JS shows it for a few seconds
   then hides it again. */

.negkw-bulk-toast {
  margin-bottom: var(--space-5);
}

/* Partial-apply toast (quota_exhausted, see applyPartialResults() in
   page-negative-keywords.js): the toast container itself stays
   .alert--success (a partial apply is still a positive outcome, not a
   failure), with these two inline spans distinguishing "what happened"
   (success green, matching .alert--success's own text color) from "what's
   still pending" (info blue, matching the shared .alert--info token) within
   that one message. */
.negkw-toast-success {
  color: #166534;
  font-weight: var(--weight-semibold);
}

.negkw-toast-info {
  color: #1E40AF;
  font-weight: var(--weight-semibold);
}

/* ============================================
   ADVANCED FILTERS (SEMrush-style condition builder)
   ============================================ */

.negkw-filter-dropdown {
  position: relative;
}

.negkw-filter-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  font-size: 14px;
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 8px;
  cursor: pointer;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}

.negkw-filter-toggle:hover,
.negkw-filter-toggle[aria-expanded="true"],
.negkw-filter-toggle--active {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.negkw-filter-toggle__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  background: var(--color-primary);
  color: #FFFFFF;
  border-radius: 9999px;
  font-size: 11px;
  font-weight: 700;
}

/* [hidden] has to be re-declared here: it and .negkw-filter-toggle__count
   are both author rules, and `display: inline-flex` above would otherwise
   always beat the browser's built-in "[hidden] { display: none }" UA rule
   -- same class of bug as .negkw-bulkbar[hidden] below. Without this, the
   count badge rendered as a visible empty blue dot whenever no filters
   were applied. */
.negkw-filter-toggle__count[hidden] {
  display: none;
}

.negkw-filter-toggle__chevron {
  flex-shrink: 0;
  color: currentColor;
}

.negkw-filter-panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 30;
  width: min(680px, 92vw);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  box-shadow: 0 12px 32px rgba(10, 31, 68, 0.16);
  padding: 16px;
}

.negkw-filter-rows {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 12px;
}

.negkw-filter-row {
  display: grid;
  grid-template-columns: 100px 1fr 1fr 1fr 28px;
  gap: 8px;
  align-items: center;
}

.negkw-filter-select,
.negkw-filter-value {
  font-size: 13px;
  padding: 7px 10px;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background-color: var(--color-surface);
  color: var(--color-text);
  min-width: 0;
  font-family: var(--font-body);
}

.negkw-filter-select {
  cursor: pointer;
  appearance: none;
  padding-right: 24px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%235A5A72' d='M1.41 0L6 4.58 10.59 0 12 1.41l-6 6-6-6z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
}

.negkw-filter-select:focus,
.negkw-filter-value:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(26, 107, 255, 0.12);
}

.negkw-filter-row__remove {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  background: transparent;
  border: none;
  color: var(--color-text-muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  border-radius: 6px;
  transition: color var(--transition-fast), background-color var(--transition-fast);
}

.negkw-filter-row__remove:hover {
  color: var(--color-danger);
  background: #FEE2E2;
}

/* ---- Label field's value cell: a multi-select of colored pills instead
   of the plain text/number <input> every other field uses (see
   labelValueCellHTML() in page-negative-keywords.js). Carries the base
   .negkw-filter-value class too so it still participates in that class's
   grid sizing/mobile grid-area rules below without duplicating them. ---- */

.negkw-filter-value--label {
  position: relative;
  padding: 0;
  display: flex;
  align-items: center;
}

.negkw-filter-labelvalue-btn {
  width: 100%;
  height: 100%;
  min-height: 28px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
  padding: 5px 10px;
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
}

.negkw-filter-labelvalue-panel {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 40;
  width: 220px;
  max-height: 220px;
  overflow-y: auto;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(10, 31, 68, 0.16);
  padding: 6px;
}

.negkw-filter-labelvalue-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  font-size: 13px;
  color: var(--color-text);
  cursor: pointer;
  border-radius: 6px;
}

.negkw-filter-labelvalue-item:hover {
  background: var(--color-bg);
}

.negkw-filter-labelvalue-item input[type="checkbox"] {
  accent-color: var(--color-primary);
}

.negkw-filter-labelvalue-empty {
  padding: 10px;
  font-size: 12px;
  color: var(--color-text-muted);
  text-align: center;
}

.negkw-filter-add {
  background: transparent;
  border: none;
  color: var(--color-primary);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  padding: 4px 0;
  margin-bottom: 12px;
}

.negkw-filter-add:hover {
  text-decoration: underline;
}

.negkw-filter-panel__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--color-border);
}

.negkw-filter-apply-btn {
  background: var(--color-dark);
  color: #FFFFFF;
  border: none;
  padding: 9px 20px;
  font-size: 14px;
  font-weight: 600;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color var(--transition-fast);
}

.negkw-filter-apply-btn:hover {
  background: #142c5c;
}

.negkw-filter-clear-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: none;
  color: var(--color-text-muted);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.negkw-filter-clear-btn:hover {
  color: var(--color-danger);
}

@media (max-width: 640px) {
  .negkw-filter-panel {
    width: 92vw;
  }

  .negkw-filter-row {
    grid-template-columns: 1fr 28px;
    grid-template-areas:
      "include remove"
      "field field"
      "operator operator"
      "value value";
    row-gap: 6px;
  }

  .negkw-filter-select--include { grid-area: include; }
  .negkw-filter-row__remove      { grid-area: remove; }
  .negkw-filter-select--field    { grid-area: field; }
  .negkw-filter-select--operator { grid-area: operator; }
  .negkw-filter-value            { grid-area: value; }
}

/* ============================================
   EMPTY / NO-MATCHES STATES
   ============================================ */

.negkw-empty-banner {
  background: var(--color-bg);
  border: 1px dashed var(--color-border);
  border-radius: 12px;
  padding: var(--space-8);
  text-align: center;
  color: var(--color-text-muted);
  font-size: 1rem;
}

/* Part 5 (2026-07-23): filtered-to-zero-rows state renders as a real table
   row (full-width message cell spanning every column, see
   emptyResultsTableHTML() in page-negative-keywords.js) instead of a bare
   <p> floating below the filter bar -- keeps the dark navy header visible
   even when nothing matches. .negkw-empty-card is the 768px-breakpoint
   mobile-card equivalent (.negkw-cards), sharing the same message/link
   classes. */
.negkw-empty-row__cell {
  padding: 0;
}

.negkw-empty-row__content {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  padding: var(--space-8) var(--space-6);
  text-align: center;
}

.negkw-empty-row__message {
  color: var(--color-text-muted);
  margin: 0 0 var(--space-3);
}

.negkw-empty-view-all-link {
  color: var(--color-primary);
  font-weight: var(--weight-semibold);
  text-decoration: none;
}

.negkw-empty-view-all-link:hover {
  text-decoration: underline;
}

.negkw-empty-card {
  text-align: center;
  padding: var(--space-8) var(--space-6);
}

/* Reserves space at the bottom of the results area equal to the fixed
   bulk action bar's height plus breathing room, so the bar (position:
   fixed, see FIXED BULK ACTION BAR below) never permanently sits on top
   of the last table row or the pagination controls. Larger on narrow
   viewports where the bar wraps onto multiple rows (see the max-width:
   600px rule near the bar itself). */
#neg-kw-results {
  padding-bottom: 120px;
}

@media (max-width: 600px) {
  #neg-kw-results {
    padding-bottom: 220px;
  }
}

/* ============================================
   RESULTS CARD (single flat table, replaces the old per-campaign
   accordion -- Campaign is now just the first column, see .negkw-table)
   ============================================ */

.negkw-results-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  /* No overflow: hidden here -- this card wraps .negkw-table-wrap, and any
     ancestor with overflow other than visible breaks the table's sticky
     header (see .sherpa-table in style.css). Corner rounding is instead
     applied directly to the header cells and to .negkw-pagination below.
     Deliberately NOT negative-margined out to .container's edge -- see the
     removed rule's history below and the table-column tightening under
     RESPONSIVE TABLE WIDTH near the table styles for why. */
}

/* ============================================
   CHECKBOXES
   ============================================ */

.negkw-checkbox {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  cursor: pointer;
  accent-color: var(--color-primary);
}

/* ============================================
   RECOMMENDATION TABLE (desktop, 768px+)
   ============================================ */

/* Table itself uses the shared .sherpa-table / .sherpa-table-wrap classes
   (style.css) for width/font/sticky-header/striping/hover. This class
   only carries the responsive show/hide toggle. */
.negkw-table-wrap {
  display: none;
}

/* ============================================
   RESPONSIVE TABLE WIDTH (page-scoped, not touching .sherpa-table/
   .sherpa-table-wrap in style.css)
   ============================================
   This table has 11-12 columns, several with uppercase nowrap headers
   (.sherpa-table th's white-space: nowrap, style.css) -- summed, their
   individual minimum widths can exceed the available card width, which is
   why .negkw-results-card previously clawed back .container's own 24px-
   per-side gutter via a negative margin (removed -- see the Current Phase
   entry in CLAUDE.md dated 2026-07-28 for why that gutter-recovery
   approach was reverted: it misaligned this card's edges from every other
   element on the page -- breadcrumb, title, summary pills -- by exactly
   that reclaimed 24px on each side, which is a worse problem than the
   overflow it was solving). Instead of stealing extra width, these two
   rules shrink the table's own minimum footprint enough to fit inside the
   card's normal, container-aligned width:
   (1) th/td horizontal padding trimmed from the shared 14px to 10px --
       small enough to stay comfortable, saves up to ~8px x 12 columns.
   (2) column headers allowed to wrap onto two lines instead of forcing a
       single nowrap line -- overrides .sherpa-table th's white-space:
       nowrap for this table only. A header only actually wraps once the
       column is genuinely too narrow to fit it on one line (browsers only
       wrap when forced), so short headers (Clicks, Cost, Status) still
       render on one line at any reasonable width; only the longer ones
       (Negative Keyword, Matched Keyword) wrap at narrower viewports.
   Both are scoped under .negkw-table-wrap so Meta Spend Monitor (which
   uses the same shared .sherpa-table class but has its own, shorter
   column set and was confirmed not to have this overflow problem) is
   unaffected. Verified against representative and stress-tested (longer
   campaign names/keywords, larger dollar figures) content at 1024/1200/
   1400px viewports: comfortably fits at 1200px+ (where the original
   overflow bug was reported), and is substantially improved but still
   data-dependent at 1024px, since a 12-column data table this dense has a
   real structural minimum width that can approach a ~1024px viewport's
   available space regardless of padding/wrapping -- not yet exercised
   against live account data, same standing caveat as the rest of this
   page. */
.negkw-table-wrap .sherpa-table th,
.negkw-table-wrap .sherpa-table td {
  padding-left: 10px;
  padding-right: 10px;
}

.negkw-table-wrap .sherpa-table th {
  white-space: normal;
}

/* ---- Clickable, sortable column headers (page-specific, same idea as
   Meta Monitor's .app-meta-th-sortable). Selectors are qualified with
   .sherpa-table th so the hover/active background beats the shared
   `.sherpa-table th { background-color }` rule on specificity. ---- */

.negkw-th-sortable {
  cursor: pointer;
  user-select: none;
}

/* The Annual Waste header also carries .has-popover (see sortableTh() in
   page-negative-keywords.js), which sets its own `cursor: help`. Same
   specificity as .negkw-th-sortable's `cursor: pointer` above, so this
   explicit two-class selector guarantees the clickable/sortable pointer
   cursor wins regardless of stylesheet load order. */
.negkw-th-sortable.has-popover {
  cursor: pointer;
}

.sherpa-table th.negkw-th-sortable:hover,
.sherpa-table th.negkw-th-sorted {
  /* Slightly lighter than the navy header (--color-dark) so the hovered /
     active-sort column reads as interactive. Higher specificity than
     .has-popover:hover's light-blue highlight, so a popover-carrying
     header (Annual Waste) correctly keeps this navy hover treatment
     instead of flashing light blue against the dark header row. */
  background-color: #142c5c;
}

.negkw-sort-arrow {
  font-size: 0.85em;
}

.negkw-campaign-cell {
  color: var(--color-text-muted);
  font-size: 12px;
  font-weight: 600;
  max-width: 160px;
}

/* Labels column -- pills themselves come from the shared .label-pill-group
   (style.css); this just caps the cell's width so a row with several
   labels doesn't blow out the table layout (labelPillsHTML() already caps
   at 2 pills + a "+N" overflow badge, but names can still be long). */
.negkw-labels-cell {
  max-width: 180px;
}

.negkw-term-cell {
  font-weight: 600;
  color: var(--color-dark);
  max-width: 260px;
}

.negkw-reason {
  font-weight: 400;
  font-size: 12px;
  color: var(--color-text-muted);
  margin-top: 2px;
}

/* A <div>, never the literal <td> -- desktop wraps it inside a plain <td>
   (tableRowHTML()), mobile uses it directly in the card footer (cardHTML()).
   This used to be applied straight to the <td> itself, which silently broke
   two things at once: `display: flex` on a table cell drops it out of the
   table's own display type, so (1) vertical-align: middle from the shared
   .sherpa-table td rule stopped applying (content read top-aligned -- fixed
   at the time by redeclaring vertical-align: middle directly here), and more
   seriously (2) the cell stopped participating in the table's column-width
   algorithm at all, so this column's width could drift out of sync with its
   header -- wide Actions content (e.g. the Approve button) could then spill
   past the row's true right edge instead of being constrained to the
   column's actual width. Wrapping the flex layout in an inner div instead
   keeps the <td> itself a normal table cell (default display: table-cell),
   so it sizes in lockstep with the header and centers correctly via the
   shared rule with no override needed here. */
.negkw-actions-cell {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
}

/* ---- Status-driven row treatment (box-shadow inset, not border-left,
   since border-left on a <tr> doesn't render under border-collapse) ---- */

.negkw-row--approved {
  box-shadow: inset 3px 0 0 var(--color-primary);
}

.negkw-row--applied {
  box-shadow: inset 3px 0 0 #16A34A;
  color: var(--color-text-muted);
}

.negkw-row--dismissed {
  color: #9CA3AF;
  opacity: 0.6;
}

/* One-shot flash when a row's status just changed via an action. */
@keyframes negkw-flash {
  0%   { background-color: rgba(26, 107, 255, 0.16); }
  100% { background-color: transparent; }
}

.negkw-flash {
  animation: negkw-flash 900ms ease-out;
}

/* ============================================
   RECOMMENDATION CARDS (mobile, below 768px)
   ============================================ */

.negkw-cards {
  display: block;
}

.negkw-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  padding: 16px;
  margin: 12px;
}

.negkw-card.negkw-row--approved {
  border-left: 3px solid var(--color-primary);
}

.negkw-card.negkw-row--applied {
  border-left: 3px solid #16A34A;
  color: var(--color-text-muted);
}

.negkw-card.negkw-row--dismissed {
  color: #9CA3AF;
  opacity: 0.6;
}

.negkw-card__campaign {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
  margin-bottom: 4px;
}

/* Only rendered at all when a card's recommendation has at least one
   label (see cardHTML() in page-negative-keywords.js) -- pills themselves
   come from the shared .label-pill-group. */
.negkw-card__labels {
  margin-bottom: 8px;
}

.negkw-card__header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

.negkw-card__title {
  flex: 1;
  font-weight: 600;
  color: var(--color-dark);
  font-size: 14px;
}

.negkw-card__matched-kw {
  font-size: 0.8125rem;
  margin: 0 0 0.25rem;
}

.negkw-card__reason {
  font-size: 12px;
  color: var(--color-text-muted);
  margin-bottom: 12px;
}

.negkw-card__metrics {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 12px;
  padding: 10px;
  background: var(--color-bg);
  border-radius: 8px;
}

.negkw-card__metric {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.negkw-card__metric-label {
  font-size: 11px;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.negkw-card__metric-value {
  font-size: 14px;
  font-weight: 700;
  color: var(--color-dark);
}

.negkw-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
}

@media (min-width: 768px) {
  .negkw-table-wrap {
    display: block;
  }

  .negkw-cards {
    display: none;
  }

  /* A margin-inline: calc(-1 * var(--container-padding)) rule used to live
     here, reclaiming .container's 24px-per-side gutter for this one card
     so the table's nowrap-header-driven minimum width had room to fit
     without spilling past the card's right edge (2026-07-28 bug report:
     the Actions column/Approve button visually spilling outside the row).
     Removed (2026-07-28 follow-up) because it traded that overflow bug for
     a different, more visible one: it made .negkw-results-card 24px wider
     than every other element on the page -- breadcrumb, title, summary
     pills -- on both sides, since none of those are similarly negative-
     margined. The table's own minimum width is now trimmed instead (see
     RESPONSIVE TABLE WIDTH above .negkw-th-sortable), so this card no
     longer needs extra width and can stay aligned with the rest of the
     page like everything else in .container. */
}

/* ============================================
   PAGINATION
   ============================================ */

.negkw-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding: 12px 20px;
  border-top: 1px solid var(--color-border);
  /* Matches .negkw-results-card's own radius now that the card no longer
     clips its children with overflow: hidden (see note above it). */
  border-bottom-left-radius: 12px;
  border-bottom-right-radius: 12px;
}

.negkw-pagination__left {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

.negkw-pagination__pagesize {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--color-text-muted);
  white-space: nowrap;
}

.negkw-pagesize-select {
  font-size: 13px;
  padding: 5px 26px 5px 10px;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background-color: var(--color-surface);
  color: var(--color-text);
  cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%235A5A72' d='M1.41 0L6 4.58 10.59 0 12 1.41l-6 6-6-6z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
}

.negkw-pagination__range {
  font-size: 13px;
  color: var(--color-text-muted);
}

.negkw-pagination__controls {
  display: flex;
  align-items: center;
  gap: 12px;
}

.negkw-pagination__page {
  font-size: 13px;
  color: var(--color-text-muted);
  white-space: nowrap;
}

/* Looks like plain text until focused -- no visible border/background at
   rest, subtle border on hover as an affordance, full focus treatment only
   once the user actually clicks in. Width is set inline per-render (see
   paginationHTML() in page-negative-keywords.js) to fit totalPages' digit
   count; the value here is just a sane fallback. */
.negkw-pagination__page-input {
  width: 3ch;
  padding: 1px 3px;
  font: inherit;
  font-size: 13px;
  color: var(--color-text-muted);
  text-align: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  transition: border-color var(--transition-fast), background-color var(--transition-fast), color var(--transition-fast);
}

.negkw-pagination__page-input:hover {
  border-color: var(--color-border);
}

.negkw-pagination__page-input:focus {
  outline: none;
  border-color: var(--color-primary);
  background: var(--color-surface);
  color: var(--color-text);
}

.negkw-pagination__btn {
  background: transparent;
  border: 1.5px solid var(--color-border);
  color: var(--color-text);
  padding: 5px 12px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--transition-fast), border-color var(--transition-fast);
}

.negkw-pagination__btn:hover:not(:disabled) {
  background: var(--color-primary-light);
  border-color: var(--color-primary);
}

.negkw-pagination__btn:disabled {
  opacity: 0.4;
  cursor: default;
}

/* ============================================
   ACTION BUTTONS
   ============================================ */

.negkw-btn-approve {
  background: transparent;
  border: 1.5px solid var(--color-primary);
  color: var(--color-primary);
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--transition-fast);
}

.negkw-btn-approve:hover {
  background: var(--color-primary-light);
}

.negkw-btn-apply {
  background: #16A34A;
  border: none;
  color: #FFFFFF;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--transition-fast);
}

/* Disabled while an apply job is in flight account-wide (see
   isApplyJobInFlight() in page-negative-keywords.js) -- same
   opacity/cursor treatment as .app-connect-btn[disabled]/
   .app-disconnect-all-btn[disabled] elsewhere in this app. */
.negkw-btn-apply[disabled] {
  opacity: 0.6;
  cursor: not-allowed;
}

.negkw-btn-apply:hover {
  background: #128a3e;
}

.negkw-action-link {
  color: var(--color-text-muted);
  font-size: 13px;
  font-weight: 600;
  text-decoration: underline;
  white-space: nowrap;
}

.negkw-action-link:hover {
  color: var(--color-danger);
}

.negkw-applied-label {
  color: #16A34A;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}

/* Warning indicator next to Apply/Undo on a row whose last apply attempt
   failed (stays 'approved' -- see applyResults() in page-negative-
   keywords.js). Native title attribute carries the error message. */
.negkw-apply-error {
  color: var(--color-danger);
  cursor: help;
  font-size: 14px;
  line-height: 1;
}

/* ============================================
   STATUS BADGES
   ============================================ */

.negkw-status-badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: 9999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.negkw-status-badge--pending {
  background: #E5E7EB;
  color: #374151;
}

.negkw-status-badge--approved {
  background: #DBEAFE;
  color: #1E40AF;
}

.negkw-status-badge--applied {
  background: #D1FAE5;
  color: #065F46;
}

.negkw-status-badge--dismissed {
  background: #F3F4F6;
  color: #9CA3AF;
}

/* ============================================
   LOADING SKELETON
   ============================================ */

.negkw-skeleton-table {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  overflow: hidden;
}

.negkw-skeleton-row {
  height: 44px;
  border-top: 1px solid var(--color-border);
  background: var(--color-bg);
  animation: app-skeleton-pulse 1.4s ease-in-out infinite;
}

.negkw-skeleton-table .negkw-skeleton-row:first-child {
  border-top: none;
}

@keyframes app-skeleton-pulse {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 1; }
}

/* ============================================
   FIXED BULK ACTION BAR
   ============================================
   Pinned to the viewport bottom at all times, independent of scroll
   position or content height -- a plain `position: fixed` bar has no
   scroll-container/short-page edge cases the way `position: sticky` did
   (see Key Learnings in CLAUDE.md for the history of that approach).
   Visibility is a single toggle (bar.hidden in updateBulkBar()): shown
   whenever there's a checkbox selection or an approved-but-not-applied
   count, hidden otherwise. #neg-kw-results reserves matching
   padding-bottom so the fixed bar never permanently covers the last table
   row or pagination controls.

   The bar's own position/layout/[hidden] rules now live in the shared
   .bulk-action-bar class (style.css), reused by Meta Spend Monitor's bulk
   bar too (see PART 4 of the label system work in CLAUDE.md) -- the
   markup carries both classes (class="negkw-bulkbar bulk-action-bar").
   Everything below here (button variants) stays page-specific since
   negative keywords is the only page with more than one bulk action.

   .negkw-bulkbar__actions is the bar's only direct child (2026-07-31,
   fixed a position-jump bug -- see the markup comment in page-negative-
   keywords.php) and is given width: 100% so it fills the bar's full
   horizontal space; that in turn lets .negkw-bulkbar__clear's
   margin-left: auto push Clear Selection all the way to the bar's right
   edge, with every other action staying in one stable left-aligned,
   wrapping row regardless of which of them are currently visible. flex-
   wrap: wrap (plus no min-width/white-space:nowrap on any child below) is
   what keeps this row from forcing the bar wider than the viewport on
   narrow screens -- see the mobile override further down for how Clear
   Selection's auto margin is turned off below the 600px breakpoint so it
   drops into normal wrap flow instead of getting stranded off-screen. */

.negkw-bulkbar__actions {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  width: 100%;
}

/* Outline, not filled -- "Apply Approved" below is the filled primary
   button in this bar now, so Approve Selected steps back to match the
   outline treatment of the per-row Approve button (.negkw-btn-approve). */
.negkw-bulkbar__approve {
  background: transparent;
  border: 1.5px solid var(--color-primary);
  color: var(--color-primary);
  padding: 8px 18px;
  font-size: 14px;
  font-weight: 600;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color var(--transition-fast);
}

.negkw-bulkbar__approve:hover {
  background: var(--color-primary-light);
}

/* "Apply Approved (X)" -- account-wide, independent of checkbox selection.
   Primary blue and filled, distinct from the outline Approve/Dismiss
   Selected buttons which only act on checked rows. */
.negkw-bulkbar__apply {
  background: var(--color-primary);
  color: #FFFFFF;
  border: none;
  padding: 8px 18px;
  font-size: 14px;
  font-weight: 600;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color var(--transition-fast);
}

/* Disabled while an apply job is in flight account-wide -- see the
   matching .negkw-btn-apply[disabled] comment above. */
.negkw-bulkbar__apply[disabled] {
  opacity: 0.6;
  cursor: not-allowed;
}

.negkw-bulkbar__apply:hover {
  background: var(--color-primary-hover);
}

.negkw-bulkbar__dismiss {
  background: transparent;
  border: 1.5px solid var(--color-border);
  color: var(--color-text-muted);
  padding: 8px 18px;
  font-size: 14px;
  font-weight: 600;
  border-radius: 8px;
  cursor: pointer;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}

.negkw-bulkbar__dismiss:hover {
  border-color: var(--color-danger);
  color: var(--color-danger);
}

/* "Undo Approval" -- shown instead of Approve/Dismiss Selected when the
   Approved status filter is active (see updateBulkBar() in page-negative-
   keywords.js). Deliberately not the primary-blue outline .negkw-bulkbar__
   approve uses above -- reusing that would visually read as another
   "approve" action. Neutral gray outline instead (same token pairing as
   .negkw-pagination__btn elsewhere on this page), highlighting to primary
   only on hover so it still reads as an affirmative action, just distinct
   from Approve. */
.negkw-bulkbar__undo {
  background: transparent;
  border: 1.5px solid var(--color-border);
  color: var(--color-text);
  padding: 8px 18px;
  font-size: 14px;
  font-weight: 600;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color var(--transition-fast), border-color var(--transition-fast);
}

.negkw-bulkbar__undo:hover {
  background: var(--color-primary-light);
  border-color: var(--color-primary);
}

/* margin-left: auto is what pushes this to the bar's right edge (the only
   right-aligned element in the bar) -- deliberately not justify-content:
   space-between on a container, since that's what caused the old
   position-jump bug when Apply Approved appeared/disappeared. Turned off
   at the 600px breakpoint below so Clear Selection wraps in place on
   mobile instead of getting pushed toward an edge that may be off-screen. */
.negkw-bulkbar__clear {
  font-size: 13px;
  color: var(--color-text-muted);
  text-decoration: underline;
  margin-left: auto;
}

/* ============================================
   RESPONSIVE: small-screen header/controls stacking
   ============================================ */

@media (max-width: 600px) {
  .negkw-action-bar {
    flex-direction: column;
    align-items: stretch;
  }

  .negkw-controls-bar {
    flex-direction: column;
    align-items: stretch;
  }

  /* .bulk-action-bar (style.css) already stacks the bar itself at this
     breakpoint -- this just adjusts the page-specific button group inside
     it once stacked. Clear Selection's margin-left: auto (which pushes it
     to the bar's right edge at wider widths) is cancelled here so it
     drops into the same wrapping row as every other button instead of
     being pulled toward an edge that can run off a narrow viewport. */
  .negkw-bulkbar__clear {
    margin-left: 0;
  }
}

/* ============================================
   APPLY TO GOOGLE ADS MODAL
   ============================================
   Same shape as the account-deactivation confirmation modal on /app/
   (.app-modal-overlay/.app-modal in page-app.css), duplicated here with a
   negkw- prefix rather than depended on, matching this page's existing
   self-contained-per-page CSS convention (see file header). */

.negkw-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.negkw-modal-overlay[hidden] {
  display: none;
}

.negkw-modal {
  background: var(--color-surface);
  width: 100%;
  max-width: 480px;
  padding: 32px;
  border-radius: 12px;
}

.negkw-modal__title {
  margin-bottom: 16px;
}

.negkw-modal__body {
  line-height: 1.6;
  margin-bottom: 24px;
  color: var(--color-text);
}

.negkw-modal__actions {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
}

.negkw-modal__progress {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 12px 0;
  text-align: center;
}

.negkw-modal__progress-text {
  font-weight: 600;
  color: var(--color-dark);
  margin: 0;
}

