:root {
  /* Light by default; html[data-theme='dark'] below overrides color-scheme
     and the theme tokens once the pre-paint snippet (or the nav.js toggle)
     sets data-theme="dark" on the root element. */
  color-scheme: light;
  --brand-purple: #231556;
  --brand-midnight: #0c102a;
  --brand-green: #00c94d;
  --brand-green-bright: #00ff5a;
  --brand-cyan: #00c2ad;
  --brand-orange: #ff7f49;
  --brand-sky-blue: #2f8fd0;
  --brand-gray: #63666a;
  --brand-light-gray: #f2f2f4;
  --brand-border: #7e8498;
  --brand-heading-blue: #002060;
  --danger: #d1453b;
  /* Theme tokens (task 13.1) - light values. */
  --bg: #f2f2f4;
  --surface: #ffffff;
  --surface-tray: #eceef3;
  --surface-tray-alt: #ece7f0;
  --surface-subtle: #fbfbfc;
  --text: #1b1b1f;
  --text-soft: #3a3a3f;
  --accent-strong: #231556;
  --danger-strong: #b8352c;
  --danger-hover-bg: #fbe9e6;
  --input-bg: #ffffff;
  --drag-over: #ded6ea;
  --sentiment-green-bg: #d3edda;
  --sentiment-yellow-bg: #f6e9bd;
  --sentiment-red-bg: #f6d9d3;
  --sentiment-green-dot: #1c8a3e;
  --sentiment-yellow-dot: #b87d00;
  --sentiment-red-dot: #d1453b;
  /* Task 39.4 (docs/DESIGN.md §2 rows 6/9/10): themed soft-tint pairs. */
  --info-soft-bg: #eaf3fd;
  --info-border: #c2dcf3;
  --danger-soft-border: #f3c6c2;
  /* Task 39.4 (docs/DESIGN.md §2 row 11/12): constant badge-text/focus-ring
     tokens - :root only, no dark override. Their tint backgrounds are
     constant-by-design (§8 KEEP), so a themed text colour would reproduce
     the row-6 failure mode of a themed value on an unflipped background. */
  --status-info: #1f6fa8;
  --status-teal: #1a6e63;
  --status-green-deep: #186f34;
  --status-green-win: #14722f;
  --status-warm: #9a4a12;
  --status-success: #0e7a35;
  --status-danger: #b8352c;
  --focus-ring: #2a84c2;
  /* Task 54.3 (docs/DESIGN.md §2 row 14): search-term highlight. Constant
     across themes - :root only, no dark override, like the --status-* badge
     tokens above and for the same reason. A highlighter pen does not get
     darker in the dark; a dark-tinted fill measured only 1.54:1 against the
     dark yellow-sentiment card it sits on, so the mark stopped reading as a
     mark. The constant amber is 5.0-11.3:1 against every dark surface. */
  --search-hit-bg: #ffd54a;
  --search-hit-text: #1b1b1f;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}

html[data-theme='dark'] {
  color-scheme: dark;
  --bg: #15182e;
  --surface: #1c2038;
  --surface-tray: #191d33;
  --surface-tray-alt: #1e1a33;
  --surface-subtle: #21263f;
  --text: #e7e9f2;
  --text-soft: #c3c8d6;
  --accent-strong: #b9a8ff;
  --danger-strong: #ff8078;
  --danger-hover-bg: #522b32;
  --input-bg: #12152b;
  --drag-over: #2a2550;
  --sentiment-green-bg: #1f4a31;
  --sentiment-yellow-bg: #45401f;
  --sentiment-red-bg: #522b32;
  --sentiment-green-dot: #34c568;
  --sentiment-yellow-dot: #e8b93e;
  --sentiment-red-dot: #e0685f;
  --brand-border: #6c72a0;
  --brand-gray: #9ba1ad;
  --brand-heading-blue: #b9c6ff;
  --brand-light-gray: #232842;
  --info-soft-bg: #1a2540;
  --info-border: #3d5c8f;
  --danger-soft-border: #8a5058;
}

* {
  box-sizing: border-box;
}

/* Task 39.4 (docs/DESIGN.md §2 row 12): site-wide focus ring. Previously
   only two rules in the whole sheet set a focus outline at all (the old
   sentiment-button rule, now deleted as a duplicate, and .card-menu-item:
   focus below); this replaces relying on UA defaults - nearly invisible
   against table.simple styling - with a visible, AA-contrast ring
   everywhere. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

/* Task 46.1: min-height:100vh flex column, paired with the flex:1 filler on
   `.container` / `.login-wrap` below, is the classic sticky-footer layout -
   it pushes .app-footer flush to the viewport bottom on a page shorter than
   the viewport, while a taller page's content still grows past 100vh and
   scrolls normally (docs/DESIGN.md §11). */
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

a {
  color: var(--brand-sky-blue);
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}

.app-header {
  background: var(--brand-purple);
  color: white;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  height: 56px;
  position: sticky;
  top: 0;
  z-index: 10;
}
.app-header .brand {
  font-weight: 700;
  font-size: 16px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.app-header .brand .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--brand-green-bright);
  display: inline-block;
}
.app-header nav {
  display: flex;
  gap: 18px;
  align-items: center;
}
.app-header nav a {
  color: white;
  opacity: 0.8;
  font-size: 14px;
  font-weight: 500;
}
.app-header nav a.active,
.app-header nav a:hover {
  opacity: 1;
  text-decoration: none;
  color: var(--brand-green-bright);
}
.app-header nav .nav-dropdown {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.app-header nav .nav-dropdown-toggle,
.app-header nav .nav-action-btn {
  background: transparent;
  border: none;
  color: white;
  opacity: 0.8;
  font-size: 14px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.app-header nav .nav-dropdown-toggle:hover,
.app-header nav .nav-dropdown-toggle.active,
.app-header nav .nav-action-btn:hover {
  opacity: 1;
  color: var(--brand-green-bright);
}
.app-header nav .nav-dropdown-toggle .caret {
  font-size: 10px;
  opacity: 0.8;
}
.app-header nav .nav-dropdown-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  background: var(--surface);
  border: 1px solid var(--brand-border);
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  min-width: 160px;
  padding: 4px;
  z-index: 60;
  display: flex;
  flex-direction: column;
}
/* The `display: flex` above outranks the `hidden` attribute's UA display:none,
   so without this the menu would render permanently open. Re-assert none when
   hidden (specificity beats the base rule). */
.app-header nav .nav-dropdown-menu[hidden] {
  display: none;
}
.app-header nav .nav-dropdown-menu a.nav-dropdown-item {
  display: block;
  width: 100%;
  text-align: left;
  color: var(--text);
  opacity: 1;
  font-size: 13px;
  font-weight: 500;
  padding: 8px 10px;
  border-radius: 5px;
}
.app-header nav .nav-dropdown-menu a.nav-dropdown-item:hover,
.app-header nav .nav-dropdown-menu a.nav-dropdown-item.active {
  background: var(--brand-light-gray);
  color: var(--text);
  text-decoration: none;
}
.app-header .user-box {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  opacity: 0.9;
}
.app-header .user-box button {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.4);
  color: white;
  border-radius: 6px;
  padding: 5px 10px;
  cursor: pointer;
  font-size: 12px;
}
.app-header .user-box button:hover {
  border-color: var(--brand-green-bright);
  color: var(--brand-green-bright);
}
.app-header .user-menu {
  position: relative;
}
.app-header .user-menu-toggle {
  background: transparent;
  border: none;
  color: white;
  opacity: 0.9;
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
  padding: 4px 2px;
  display: flex;
  align-items: center;
  gap: 4px;
}
.app-header .user-menu-toggle:hover {
  opacity: 1;
  color: var(--brand-green-bright);
}
.app-header .user-menu-toggle .caret {
  font-size: 10px;
  opacity: 0.8;
}
.app-header .user-menu-dropdown {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  background: var(--surface);
  border: 1px solid var(--brand-border);
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  min-width: 160px;
  padding: 4px;
  z-index: 60;
}
/* Must out-specify ".app-header .user-box button" (which paints header
   buttons white) - the menu items sit inside .user-box but on a white
   dropdown, so they need dark text and no border. */
.app-header .user-box button.user-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  padding: 8px 10px;
  border-radius: 5px;
  cursor: pointer;
}
.app-header .user-box button.user-menu-item:hover {
  background: var(--brand-light-gray);
  border-color: transparent;
  color: var(--text);
}
/* Task 20.1: small muted version footer, shown at the end of every page
   (the 6 nav.js pages plus the login page). Task 46.1 (PRD
   prd-footer-status-bar.md §8-A, DECIDED: sticky-within-container) reverses
   the earlier "never fixed/sticky" choice: `position: sticky; bottom: 0`
   keeps the footer pinned at the viewport bottom once a page's content
   scrolls past it, rather than scrolling out of view like a normal in-flow
   element would. It only engages once content exceeds the viewport - on a
   short page the body/.container flex layout above already puts the footer
   flush to the viewport bottom, so no scrolling (and no stickiness) is ever
   needed. The opaque background is required for the sticky case, since
   page content now scrolls underneath it. See docs/DESIGN.md §11 for the
   toast-clearance relationship this introduces. */
.app-footer {
  margin-top: 24px;
  padding: 16px 24px;
  border-top: 1px solid var(--brand-border);
  text-align: center;
  font-size: 12px;
  color: var(--brand-gray);
  position: sticky;
  bottom: 0;
  background: var(--bg);
  z-index: 5;
}

.container {
  max-width: 1180px;
  /* width must be explicit (task 48.1): body is a flex column (task 46.1),
     and a flex item with cross-axis auto margins shrink-wraps to its
     content instead of stretching - so without this the max-width tiers
     below only apply when page content happens to be that wide. Safe with
     the padding because of the global border-box rule. */
  width: 100%;
  margin: 0 auto;
  padding: 24px;
  /* Task 46.1: the flex:1 filler that makes the sticky-footer layout work -
     see the body rule above and docs/DESIGN.md §11. */
  flex: 1 0 auto;
}

.page-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 18px;
}
.page-title h1 {
  font-size: 22px;
  color: var(--brand-heading-blue);
  margin: 0;
}
.page-title .sub {
  color: var(--brand-gray);
  font-size: 12.5px;
  margin-top: 2px;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--brand-purple);
  color: white;
  border: none;
  border-radius: 6px;
  padding: 9px 16px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.btn:hover {
  background: #341f74;
}
.btn.secondary {
  background: var(--surface);
  color: var(--accent-strong);
  border: 1px solid var(--brand-border);
}
.btn.secondary:hover {
  border-color: var(--accent-strong);
  background: var(--brand-light-gray);
}
.btn.danger {
  background: var(--surface);
  color: var(--danger-strong);
  border: 1px solid var(--danger-strong);
}
.btn.danger:hover {
  background: var(--danger-hover-bg);
}
.btn.small {
  padding: 5px 10px;
  font-size: 12px;
}
.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.card {
  background: var(--surface);
  border: 1px solid var(--brand-border);
  border-radius: 10px;
  padding: 18px;
  margin-bottom: 16px;
}
/* Task 39.4 (docs/DESIGN.md §3): quiet section-heading step for the five
   collapsible-card headings and four modal-card dialog titles. No margin
   here - eight of the nine h3s carry inline margins, which win anyway. */
.card h3 {
  font-size: 15px;
  font-weight: 700;
}

input[type='text'],
input[type='email'],
input[type='password'],
input[type='date'],
input[type='number'],
select,
textarea {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--brand-border);
  border-radius: 6px;
  font-size: 13px;
  font-family: inherit;
  background: var(--input-bg);
  color: var(--text);
}
textarea {
  resize: vertical;
  min-height: 60px;
}
label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  color: var(--brand-gray);
  margin-bottom: 3px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.field {
  margin-bottom: 14px;
}
.form-row {
  display: flex;
  gap: 12px;
}
.form-row > * {
  flex: 1;
}
/* Buttons in a form-row keep their intrinsic width - only fields stretch.
   The Discovery card's "+ Add" use-case button had spanned half its row
   since the field landed; 39.4's AA-visible border made it show. */
.form-row > .btn {
  flex: 0 0 auto;
}
/* The my-team toggle is a chip, not a select - intrinsic width, like .btn
   above, so it doesn't compete with the selects for the row's free space. */
.form-row > .chip {
  flex: 0 0 auto;
}
/* My Deals' filter row has only two stretchy controls and its AE select is
   capped inline, so the default flex:1 made the search box the sole residual
   claimant - about 1320px at the widest container tier. The cap is what fixes
   that; a grow factor here is not needed and was actively harmful once the
   Team Dashboard reached eight controls, where it starved the selects until
   "All SEs / Owners" clipped. Replacing the my-team select with an intrinsic-
   width toggle chip dropped that to seven flexible controls; "All SEs /
   Owners" now measures ~150px at 1440px with Clear filters showing, up from
   the 139px it needs. */
.form-row > .filter-search {
  max-width: 420px;
}
/* Task 39.2: plan-page header grid (docs/DESIGN.md §5). Named grid-template-
   areas, not auto-fit - every field gets an explicit, unchanging slot; only
   the area map changes per breakpoint (see the 1023px/767px overrides
   below), never per-field logic. */
.plan-header-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 16px;
  grid-template-areas:
    "customer customer customer opp opp opp stage stage owner owner sentiment sentiment"
    "license license license ae ae ae region region aha aha agentic agentic"
    "dealvalue dealvalue dealvalue . . . . . . . . ."
    "tenantid tenantid tenantid tenantid cpurl cpurl cpurl cpurl cpurl cpurl cpurl cpurl"
    "date1 date1 date1 date1 date2 date2 date2 date2 date3 date3 date3 date3";
}
/* The global .field margin-bottom (14px, below) stacked on this grid's gap
   would double up the row rhythm; inside the grid, gap is the sole spacing
   authority. */
.plan-header-grid .field { margin-bottom: 0; }
.plan-header-grid input:not([type='checkbox']),
.plan-header-grid select {
  height: 38px;
}
.field-customer { grid-area: customer; }
.field-opp { grid-area: opp; }
.field-stage { grid-area: stage; }
.field-owner { grid-area: owner; }
.field-sentiment { grid-area: sentiment; }
.field-license { grid-area: license; }
.field-ae { grid-area: ae; }
.field-region { grid-area: region; }
.field-aha { grid-area: aha; }
.field-agentic { grid-area: agentic; }
.field-dealvalue { grid-area: dealvalue; }
.field-tenantid { grid-area: tenantid; }
.field-cpurl { grid-area: cpurl; }
.field-date-start { grid-area: date1; }
.field-date-est { grid-area: date2; }
.field-date-actual { grid-area: date3; }
/* The agentic cell has no label above its control, so the grid's default
   stretch would pin its 38px box to the top of the ~55px (label + input)
   row height of its neighbours; align-self:end centres it on their input
   band instead. */
.field-agentic {
  display: flex;
  align-items: center;
  height: 38px;
  align-self: end;
}
.agentic-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  text-transform: none;
  font-weight: 400;
}
/* The checkbox must not inherit any full-width input sizing (task 39.5
   follow-up F-A: was an inline width:auto on the input). */
.agentic-toggle input {
  width: auto;
}

.error-box {
  background: var(--danger-hover-bg);
  color: var(--danger-strong);
  border: 1px solid var(--danger-soft-border);
  border-radius: 6px;
  padding: 8px 12px;
  font-size: 13px;
  margin-bottom: 12px;
}

.info-box {
  background: var(--info-soft-bg);
  color: var(--brand-heading-blue);
  border: 1px solid var(--info-border);
  border-radius: 6px;
  padding: 8px 12px;
  font-size: 13px;
  margin-bottom: 12px;
}

.badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  white-space: nowrap;
}
.badge.stage-Qualification { background: #eef0ff; color: #3a3fb0; }
.badge.stage-Discovery { background: #e7f4ff; color: var(--status-info); }
.badge.stage-Scoping { background: #e6fbf3; color: var(--status-teal); }
.badge.stage-Technical-Validation { background: #eafbe9; color: var(--status-green-deep); }
.badge.stage-Stalled { background: #fff2e3; color: var(--status-warm); }
.badge.stage-Tech-Win { background: #e9f9ec; color: var(--status-green-win); }
.badge.stage-Closed-Won { background: #d9f7e3; color: var(--status-success); }
.badge.stage-Closed-Lost { background: #fdecea; color: var(--status-danger); }

.status-pill { padding: 2px 8px; border-radius: 20px; font-size: 11px; font-weight: 600; }
.status-pill.status-Not-Started { background: var(--surface-tray); color: var(--brand-gray); }
.status-pill.status-In-Progress { background: #e7f4ff; color: var(--status-info); }
.status-pill.status-Complete { background: #d9f7e3; color: var(--status-success); }
.status-pill.status-Blocked { background: #fdecea; color: var(--status-danger); }

/* List-row deal-sentiment dot (task 33.5): filled counterpart of the pale
   --sentiment-*-bg card tints, which are too faint at dot size. Green/red
   stay in the stage-badge / --danger color families above. */
.sentiment-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: 7px;
  vertical-align: middle;
}
.sentiment-dot.sentiment-green { background: var(--sentiment-green-dot); }
.sentiment-dot.sentiment-yellow { background: var(--sentiment-yellow-dot); }
.sentiment-dot.sentiment-red { background: var(--sentiment-red-dot); }

/* Plan-header sentiment picker (task 37.5): a labelled button group of
   color dots replacing the old <select> - clicking a dot sets sentiment,
   clicking the active dot again clears it. Reuses the --sentiment-*-dot
   tokens above rather than introducing new ones. */
.sentiment-picker { display: flex; gap: 8px; align-items: center; min-height: 38px; }
.sentiment-btn {
  width: 26px; height: 26px; padding: 0; border: none; border-radius: 50%;
  cursor: pointer; opacity: 0.4;
  transition: opacity 0.15s, transform 0.15s, box-shadow 0.15s;
}
.sentiment-btn.sentiment-green  { background: var(--sentiment-green-dot); }
.sentiment-btn.sentiment-yellow { background: var(--sentiment-yellow-dot); }
.sentiment-btn.sentiment-red    { background: var(--sentiment-red-dot); }
.sentiment-btn:hover:not(:disabled):not(.active) { opacity: 0.75; transform: scale(1.1); }
.sentiment-btn.active {
  opacity: 1; transform: scale(1.08);
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent-strong);
}
.sentiment-btn:disabled { cursor: default; opacity: 0.25; }
/* Read-only viewers (managers on someone else's plan) still need the set
   sentiment readable at a glance - the :disabled dim must not win there. */
.sentiment-btn.active:disabled { opacity: 0.7; }

.plan-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
}
.plan-card {
  background: var(--surface);
  border: 1px solid var(--brand-border);
  border-radius: 10px;
  padding: 14px 16px;
  cursor: pointer;
  transition: box-shadow 0.15s, border-color 0.15s;
}
.plan-card:hover {
  border-color: var(--accent-strong);
  box-shadow: 0 2px 10px rgba(35, 21, 86, 0.12);
}
.plan-card[draggable='true'] {
  cursor: grab;
}
.plan-card.dragging {
  opacity: 0.4;
  cursor: grabbing;
}
.plan-card.sentiment-green {
  background: var(--sentiment-green-bg);
}
.plan-card.sentiment-yellow {
  background: var(--sentiment-yellow-bg);
}
.plan-card.sentiment-red {
  background: var(--sentiment-red-bg);
}
.kanban-col.drag-over {
  outline: 2px dashed var(--accent-strong);
  outline-offset: -2px;
  background: var(--drag-over);
}
.plan-card .title {
  font-weight: 700;
  font-size: 15px;
  color: var(--brand-heading-blue);
  margin-bottom: 2px;
}
.plan-card .opp {
  color: var(--brand-gray);
  font-size: 12px;
  margin-bottom: 8px;
}
.plan-card .meta-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}
.progress-bar {
  height: 6px;
  border-radius: 4px;
  background: var(--brand-light-gray);
  overflow: hidden;
  margin-bottom: 8px;
}
.progress-bar > div {
  height: 100%;
  background: var(--brand-green);
}
.plan-card .note {
  font-size: 12px;
  color: var(--text-soft);
  background: var(--brand-light-gray);
  border-radius: 6px;
  padding: 6px 8px;
  margin-top: 6px;
}
.plan-card .note .author {
  font-weight: 700;
  color: var(--accent-strong);
}
.plan-card .owner {
  font-size: 11px;
  color: var(--brand-gray);
}
.badge.agentic {
  background: var(--brand-cyan);
  color: var(--brand-purple);
}
.badge.region {
  background: var(--brand-light-gray);
  color: var(--brand-gray);
}
.plan-card .deal-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  font-size: 12px;
  color: var(--brand-heading-blue);
  margin-bottom: 8px;
}
.plan-card .deal-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
/* Task 24.3: POV start/end date line on deal cards - reuses the .deal-meta
   flex-column layout (font-size/row stacking) but muted rather than the
   heading-blue it would otherwise inherit from .deal-meta, since it's
   secondary/read-only info. */
.plan-card .deal-pov {
  color: var(--brand-gray);
}

/* Task 49.3 (PRD US-001): dense one-row-per-deal layout over the shared
   .plan-card chrome - title/opportunity/badges on one line, progress and
   note wrapping full-width beneath. */
.summary-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  padding: 8px 12px;
  margin-bottom: 6px;
}
.summary-row .title { font-size: 13.5px; margin-bottom: 0; }
.summary-row .opp { margin-bottom: 0; }
.summary-row .deal-badges { margin-left: auto; font-size: 12px; }
/* Direct children only: .deal-badges is itself a flex container holding a
   .muted stage-age span - a descendant selector would give that span a
   full-width line of its own inside the badge block. */
.summary-row > .progress-bar,
.summary-row > .muted,
.summary-row > .note { flex-basis: 100%; }
.summary-row .progress-bar { margin-bottom: 0; }
.summary-row .note { margin-top: 0; }

/* Task 49.3 (PRD Q-A option B): Cards-view compact density toggle. */
.plan-card.compact { padding: 10px 12px; }
.plan-card.compact .deal-badges { font-size: 12px; }

.stage-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
}
.stage-chip {
  background: var(--surface);
  border: 1px solid var(--brand-border);
  border-radius: 20px;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
  font-family: inherit;
}
.stage-chip .count {
  display: inline-block;
  background: var(--brand-light-gray);
  border-radius: 10px;
  padding: 0 7px;
  margin-left: 4px;
  font-weight: 700;
}
/* The active chip's white text would otherwise be inherited by the count onto
   its own --brand-light-gray fill - 1.12:1 in light theme, an invisible number
   on the selected chip. --text tracks that fill in both themes. */
.stage-chip.active .count {
  color: var(--text);
}

.kanban {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  padding-bottom: 14px;
  scrollbar-width: auto;
  scrollbar-color: var(--brand-purple) var(--brand-light-gray);
}
.kanban::-webkit-scrollbar {
  height: 12px;
}
.kanban::-webkit-scrollbar-track {
  background: var(--brand-light-gray);
  border-radius: 6px;
}
.kanban::-webkit-scrollbar-thumb {
  background: var(--brand-purple);
  border-radius: 6px;
}
.kanban > .empty-state {
  flex: 1 1 100%;
}
.kanban-col {
  flex: 1 1 200px;
  min-width: 200px;
  max-width: 320px;
  background: var(--surface-tray);
  border-radius: 10px;
  padding: 10px;
  transition: box-shadow 0.2s;
  scroll-margin-inline: 12px;
}
.outcomes-toggle-row {
  margin: 4px 0 14px;
}
.outcomes-toggle-row .btn {
  width: 100%;
  justify-content: space-between;
}
.outcomes-panel {
  margin-bottom: 16px;
}
.outcomes-panel .kanban-col {
  background: var(--surface-tray-alt);
}
.kanban-col h3 {
  font-size: 13px;
  margin: 2px 6px 10px;
  color: var(--accent-strong);
  display: flex;
  justify-content: space-between;
}
.kanban-col .count {
  color: var(--brand-gray);
  font-weight: 400;
}

.module-card.collapsed .mod-items {
  display: none;
}

/* Discovery & Qualification collapsible card (task 11.1) */
.disc-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
}
.disc-card.collapsed .disc-body {
  display: none;
}
.disc-card:not(.collapsed) .disc-body {
  margin-top: 14px;
}

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 6px;
}
.chip {
  background: var(--surface);
  border: 1px solid var(--brand-border);
  border-radius: 20px;
  padding: 6px 14px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  color: var(--text);
}
.chip:hover:not(:disabled),
.stage-chip:hover {
  border-color: var(--accent-strong);
}
.chip.active,
.stage-chip.active {
  background: var(--brand-purple);
  border-color: var(--brand-purple);
  color: white;
}
.chip:disabled {
  opacity: 0.6;
  cursor: default;
}
/* Task 19.4: per-deal custom use cases - visually distinct from the master
   catalogue chips (dashed border) since clicking one always removes it,
   rather than toggling it off/on like a standard chip. */
.chip-custom {
  background: var(--surface);
  border-style: dashed;
  border-color: var(--brand-purple);
  color: var(--brand-purple);
}
.chip-custom:hover:not(:disabled) {
  background: var(--brand-purple);
  color: white;
}

.module-group {
  margin-bottom: 20px;
}
.module-group > h2 {
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--accent-strong);
  border-bottom: 2px solid var(--brand-green-bright);
  padding-bottom: 6px;
  margin-bottom: 10px;
}

.item-row {
  border: 1px solid var(--brand-border);
  border-radius: 8px;
  padding: 10px 12px;
  margin-bottom: 8px;
  background: var(--surface);
}
.item-row.child {
  margin-left: 28px;
  background: var(--surface-subtle);
}
.item-row .item-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  cursor: pointer;
}
.item-row .item-name {
  font-weight: 600;
  font-size: 13.5px;
  flex: 1;
}
.item-row .item-name .custom-tag {
  font-size: 10px;
  color: var(--brand-cyan);
  font-weight: 700;
  margin-left: 6px;
}
.item-row .item-body {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--brand-border);
  display: none;
}
.item-row.expanded .item-body {
  display: block;
}
.item-row .desc {
  font-size: 12.5px;
  color: var(--text-soft);
  white-space: pre-wrap;
  margin-bottom: 8px;
}
.item-row .success {
  font-size: 12px;
  background: var(--surface-subtle);
  border-left: 3px solid var(--brand-orange);
  padding: 6px 8px;
  margin-bottom: 10px;
  white-space: pre-wrap;
}
.item-controls {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: flex-end;
}
.item-controls .field {
  margin-bottom: 0;
  min-width: 130px;
}

.view-toggle {
  display: inline-flex;
  border: 1px solid var(--brand-border);
  border-radius: 8px;
  overflow: hidden;
}
.view-tab-btn {
  padding: 7px 18px;
  border: none;
  background: var(--surface);
  font-size: 13px;
  font-weight: 700;
  color: var(--brand-gray);
  cursor: pointer;
  font-family: inherit;
}
.view-tab-btn + .view-tab-btn {
  border-left: 1px solid var(--brand-border);
}
.view-tab-btn.active {
  background: var(--brand-purple);
  color: white;
}

.action-item {
  border: 1px solid var(--brand-border);
  border-radius: 8px;
  padding: 8px 10px;
  margin-bottom: 8px;
  background: var(--surface);
}
.action-item.child {
  margin-left: 28px;
  background: var(--surface-subtle);
}
.action-item.parent-header {
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--brand-border);
  border-radius: 0;
  padding: 6px 2px;
}
.action-item.parent-header .action-name {
  text-transform: uppercase;
  font-size: 12px;
  letter-spacing: 0.03em;
  color: var(--brand-gray);
}
.action-row-main {
  display: flex;
  align-items: center;
  gap: 10px;
}
.action-name {
  flex: 1;
  font-weight: 600;
  font-size: 13.5px;
}
.action-meta-badge {
  display: inline-block;
  margin-left: 8px;
  font-size: 11px;
  font-weight: 500;
  color: var(--brand-gray);
  white-space: nowrap;
}
.action-meta-badge.overdue,
.overdue-flag {
  color: var(--danger-strong);
  font-weight: 700;
}
.status-icon-group {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}
.status-icon-btn {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1.5px solid var(--brand-border);
  background: var(--surface);
  font-size: 14px;
  line-height: 1;
  color: var(--brand-gray);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.1s, background 0.15s, color 0.15s, border-color 0.15s;
  font-family: inherit;
  padding: 0;
}
.status-icon-btn:hover {
  transform: scale(1.12);
  border-color: var(--accent-strong);
}
.status-icon-btn.active.icon-Not-Started {
  background: var(--surface-tray);
  color: var(--brand-gray);
  border-color: var(--brand-border);
}
.status-icon-btn.active.icon-In-Progress {
  background: var(--brand-sky-blue);
  color: white;
  border-color: var(--brand-sky-blue);
}
.status-icon-btn.active.icon-Complete {
  background: var(--status-success);
  color: white;
  border-color: var(--status-success);
}
.status-icon-btn.active.icon-Blocked {
  background: var(--danger);
  color: white;
  border-color: var(--danger);
}
.action-more-toggle {
  flex-shrink: 0;
  background: transparent;
  border: none;
  color: var(--brand-gray);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  padding: 2px 4px;
}
.action-more-toggle:hover {
  color: var(--accent-strong);
}
.action-extra {
  display: none;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--brand-border);
}
.action-item.expanded .action-extra {
  display: block;
}
.action-desc {
  font-size: 12.5px;
  color: var(--text-soft);
  white-space: pre-wrap;
  margin-bottom: 8px;
}
.action-success {
  font-size: 12px;
  background: var(--surface-subtle);
  border-left: 3px solid var(--brand-orange);
  padding: 6px 8px;
  margin-bottom: 10px;
  white-space: pre-wrap;
}

.notes-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: 340px;
  overflow-y: auto;
  margin-bottom: 12px;
}
.note-item {
  background: var(--brand-light-gray);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 13px;
}
.note-item .note-meta {
  font-size: 11px;
  color: var(--brand-gray);
  margin-bottom: 3px;
}
.note-item .note-meta b {
  color: var(--accent-strong);
}
.action-desc a,
.action-success a,
.wt-item-desc a,
.wt-item-success a,
.note-item a,
.item-row .desc a,
.item-row .success a,
.feedback-body a {
  text-decoration: underline;
  overflow-wrap: anywhere;
}
.feedback-body {
  white-space: pre-wrap;
}
/* The global `select { width: 100% }` is meant for .field/table cells; as a
   direct flex item in .item-head it would crush the title to nothing. */
.item-head .feedback-status {
  width: auto;
  flex: 0 0 auto;
}
/* Base .badge carries no color of its own (every other use adds a stage/
   region modifier), so the read-only status needs one to render as a pill. */
.badge.feedback-status {
  background: var(--surface-tray);
  color: var(--brand-gray);
}

.login-wrap {
  /* Task 46.1: previously forced its own full-viewport minimum height,
     which double-counted against the new body flex column above and
     pushed .app-footer below the fold. flex:1 0 auto fills the same
     remaining space instead (see docs/DESIGN.md §11), keeping the login
     box centered with the footer flush beneath it. */
  flex: 1 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at center, var(--surface) 0%, var(--brand-midnight) 100%);
}
.login-box {
  background: var(--surface);
  border-radius: 12px;
  padding: 32px 30px;
  width: 340px;
  /* Task 22.6: cap so a viewport narrower than 340+24px never overflows -
     harmless on desktop, where 340px is always well under 100vw. */
  max-width: calc(100vw - 24px);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
}
.login-box h1 {
  font-size: 18px;
  color: var(--accent-strong);
  margin: 0 0 4px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.login-box .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--brand-green-bright);
  display: inline-block;
}
.login-box p.tag {
  font-size: 12px;
  color: var(--brand-gray);
  margin: 0 0 20px;
}
.login-box .btn {
  width: 100%;
  justify-content: center;
  margin-top: 6px;
}

.empty-state {
  text-align: center;
  color: var(--brand-gray);
  padding: 40px 10px;
  font-size: 13px;
}

.muted {
  color: var(--brand-gray);
  font-size: 12.5px;
}

/* Task 54.3: search-term highlight. <mark>'s UA style sets BOTH background
   and color (Mark/MarkText), so both are overridden - and the text token is
   constant rather than var(--text), because the fill is constant: themed
   text on an unthemed fill is the exact failure mode docs/DESIGN.md §2 row 6
   records. Tokens only, never a literal (color-freeze). */
.search-hit {
  background: var(--search-hit-bg);
  color: var(--search-hit-text);
}

table.simple {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
table.simple th,
table.simple td {
  text-align: left;
  padding: 8px 10px;
  border-bottom: 1px solid var(--brand-border);
}
table.simple th {
  color: var(--brand-gray);
  text-transform: uppercase;
  font-size: 11px;
  letter-spacing: 0.03em;
}
table.simple th.sortable {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
table.simple th.sortable:hover {
  color: var(--accent-strong);
}
table.simple th.sortable .sort-arrow {
  margin-left: 4px;
}
table.simple td.num,
table.simple th.num {
  text-align: right;
}
table.simple tbody tr[data-id] {
  cursor: pointer;
}
table.simple tbody tr[data-id]:hover {
  background: var(--brand-light-gray);
}

.inline-edit-icon {
  cursor: pointer;
  color: var(--brand-gray);
  font-size: 12px;
}
.inline-edit-icon:hover {
  color: var(--accent-strong);
}

.toast {
  position: fixed;
  bottom: 20px;
  right: 20px;
  background: var(--brand-purple);
  color: white;
  padding: 10px 16px;
  border-radius: 8px;
  font-size: 13px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);
  z-index: 100;
  /* Task 22.6: a long message with no width cap overflows the left edge of a
     narrow phone (sits 20px from the right) - 40px total keeps a 20px gap on
     both sides. Harmless on desktop where messages are short. */
  max-width: calc(100vw - 40px);
}
.toast.error {
  background: var(--danger);
}
/* Task 46.1: on any page with the sticky .app-footer (every nav.js page
   plus login - walkthrough.html has none and keeps the base 20px), clear
   the footer's text once it's stuck to the viewport bottom. --footer-h is
   the footer's actual measured height (api.js's toast(), since 46.2's
   deal-count content can wrap onto extra lines on a narrow phone - a fixed
   pixel guess can't stay correct for content of unknown length); the 56px
   fallback only covers a toast firing before any footer has ever been
   measured, e.g. the first call before layout settles. See
   docs/DESIGN.md §11. */
body:has(.app-footer) .toast {
  bottom: calc(var(--footer-h, 56px) + 20px);
}

/* ===== Responsive revamp (Phase 22) ===== */
/* Task 22.1: foundation only - viewport meta (see public/*.html), 3
   breakpoint tiers, and the shared header's hamburger/drawer. Per-page
   component responsiveness (kanban -> list, wide tables, modals) is later
   work (22.2-22.6); this section deliberately leaves those alone. */

/* Horizontal-scroll backstop. clip (NOT hidden) preserves the sticky header:
   overflow-x:hidden on body promotes it to a scroll container and forces
   overflow-y:auto, which breaks position:sticky on .app-header. clip does not. */
html, body { max-width: 100%; }
body { overflow-x: clip; }

@media (max-width: 1023px) { .container { padding: 20px; } }
@media (max-width: 767px)  { .container { padding: 16px 14px; } }

/* Large-screen tiers (Phase 43, docs/DESIGN.md §10). Same specificity as the
   base .container rule, so these MUST stay after it in the file. The prose
   cap is scoped inside the tier: it holds reading text at today's rendered
   measure (~1080px content at the 1180px container) while grids and kanban
   use the full width - below 1440px nothing changes, structurally. */
@media (min-width: 1440px) {
  .container { max-width: 1360px; }
  .item-row .desc,
  .item-row .success,
  .action-desc,
  .action-success,
  .note-body { max-width: 1080px; }
}
/* 1720px fits five kanban columns at their 320px cap: 5x320 + 4x12 gaps
   + 48 container padding = 1696px. */
@media (min-width: 1800px) {
  .container { max-width: 1720px; }
}
/* Ultrawide tier (task 48.1): on 3440+ monitors the 1720px cap left the
   board in a narrow centered band. The two caps move together - widening
   the container without raising the column cap would leave dead space to
   the right of the fifth kanban column. 2400px fits five columns at the
   raised cap: 5x460 + 4x12 gaps + 48 container padding = 2396px. The
   1440px tier's 1080px prose measure still applies, so reading text never
   widens with the board. */
@media (min-width: 2600px) {
  .container { max-width: 2400px; }
  .kanban-col { max-width: 460px; }
}

/* base / desktop: header layout identical to today */
.app-header .nav-hamburger {
  display: none;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.4);
  color: white;
  border-radius: 6px;
  width: 40px;
  height: 40px;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  align-items: center;
  justify-content: center;
}
.app-header .nav-hamburger:hover {
  border-color: var(--brand-green-bright);
  color: var(--brand-green-bright);
}
.app-header .nav-collapse {
  display: contents;
}

@media (max-width: 767px) {
  .app-header { padding: 0 16px; }
  .app-header .nav-hamburger { display: inline-flex; }

  .app-header .nav-collapse { display: none; }
  .app-header .nav-collapse.open {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    position: fixed;
    top: 56px;
    left: 0;
    right: 0;
    background: var(--brand-purple);
    border-top: 1px solid rgba(255, 255, 255, 0.15);
    padding: 12px 16px 16px;
    z-index: 20;
    max-height: calc(100vh - 56px);
    overflow-y: auto;
  }
  .app-header .nav-collapse nav { flex-direction: column; align-items: stretch; gap: 2px; }
  .app-header .nav-collapse .user-box {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    opacity: 1;
    margin-top: 8px;
    padding-top: 12px;
    border-top: 1px solid rgba(255, 255, 255, 0.15);
  }
  .app-header nav a, .app-header .user-menu-toggle, .app-header nav .nav-action-btn { padding: 10px 4px; font-size: 15px; }

  /* Flatten the absolute popovers inline (never nest an absolute popover in
     the drawer). Style BOTH the plain and [hidden] selector so the
     flattened menus show regardless of the JS-toggled hidden state (the
     existing toggle JS stays and simply has no visible effect on phone). */
  .app-header nav .nav-dropdown { display: block; }
  .app-header nav .nav-dropdown-toggle { display: none; }
  .app-header nav .nav-dropdown-menu,
  .app-header nav .nav-dropdown-menu[hidden] {
    position: static;
    display: flex;
    flex-direction: column;
    background: transparent;
    border: none;
    box-shadow: none;
    min-width: 0;
    padding: 0;
  }
  .app-header nav .nav-dropdown-menu a.nav-dropdown-item { color: white; opacity: .8; padding: 10px 4px; font-size: 15px; }

  .app-header .user-menu { position: static; }
  .app-header .user-menu-dropdown,
  .app-header .user-menu-dropdown[hidden] {
    position: static;
    display: flex;
    flex-direction: column;
    background: transparent;
    border: none;
    box-shadow: none;
    min-width: 0;
    padding: 0;
  }
  /* Flattened onto the purple drawer, so the item needs light text like the
     admin items above - the base .user-menu-item color:var(--text) is
     near-invisible on purple in light mode. */
  .app-header .user-box button.user-menu-item { color: white; opacity: .8; padding: 10px 4px; font-size: 15px; }
}

/* Task 22.2: deal-board reflow (My Deals + Team Dashboard). The kanban keeps
   its own overflow-x:auto so an opt-in Kanban still swipes; these rules only
   stack the surrounding chrome so nothing forces the BODY to scroll sideways. */
@media (max-width: 1023px) {
  .form-row { flex-wrap: wrap; }
  .form-row > * { min-width: 160px; }
  /* Task 39.2: header grid tablet map - pairs of fields per row (§5). */
  .plan-header-grid {
    grid-template-columns: repeat(6, 1fr);
    grid-template-areas:
      "customer customer customer opp opp opp"
      "stage stage owner owner sentiment sentiment"
      "license license license ae ae ae"
      "dealvalue dealvalue dealvalue . . ."
      "region region aha aha agentic agentic"
      "tenantid tenantid cpurl cpurl cpurl cpurl"
      "date1 date1 date2 date2 date3 date3";
  }
}
@media (max-width: 767px) {
  .page-title { flex-wrap: wrap; gap: 12px; }
  .form-row { flex-direction: column; }
  .form-row > * { width: 100%; }
  /* Task 54.4: a stacked row is one control per line, so an inline
     max-width (My Deals' AE select carries one to stop flex:1 handing it
     half a wide row) would render it visibly short under a full-width
     search box. Colorless override - the cap still applies above 767px. */
  .form-row > select[style*='max-width'] { max-width: 100% !important; }
  .form-row > .filter-search { max-width: 100%; }
  .plan-grid { grid-template-columns: 1fr; }
  /* Task 39.2: header grid phone map - one field per row, reproducing the
     old .form-row column stacking exactly (§5). */
  .plan-header-grid {
    grid-template-columns: 1fr;
    grid-template-areas:
      "customer" "opp" "stage" "owner" "sentiment"
      "license" "dealvalue" "ae" "region" "aha" "agentic"
      "tenantid" "cpurl"
      "date1" "date2" "date3";
  }
}

/* Task 22.3: plan detail (public/plan.html) responsive refinements. Reuses
   the existing phone tier only (@max-width:767px) - no new breakpoint.

   The add-item modal's width used to be an inline style, which no external
   @media rule could ever beat. .modal-card carries the desktop width instead,
   so the phone override below can shrink it. */
.modal-card {
  width: 460px;
  max-width: calc(100vw - 24px);
}

@media (max-width: 767px) {
  /* Design/Action tab bar: shrink the button padding so both tabs fit next
     to the (already-wrapping, via 22.2) page title. */
  .view-tab-btn {
    padding: 6px 10px;
  }

  /* Action rows: let a long item name + the four status icons + the "..."
     toggle wrap onto their own line instead of overflowing sideways. The
     item name takes the full first line so the icons/"..." wrap together
     onto a second line rather than trailing off individually. */
  .action-row-main {
    flex-wrap: wrap;
  }
  .action-name {
    flex: 1 1 100%;
  }
  .status-icon-btn {
    width: 40px;
    height: 40px;
    font-size: 16px;
  }
  .sentiment-btn {
    width: 40px;
    height: 40px;
  }

  /* Action "..." extra editor: assignee / due date / status note stack to a
     single column instead of squeezing into a 130px-min-width row. */
  .item-controls {
    flex-direction: column;
  }
  .item-controls .field {
    min-width: 0;
    width: 100%;
  }

  /* License tier column: the license-count input and deal-value line live
     in a plain (non-.field) wrapper - keep them from forcing the stacked
     column wider than the viewport. */
  #planLicenseOtherWrap,
  #planLicenseOtherWrap input,
  #planDealValue {
    max-width: 100%;
  }

  /* Agentic AI checkbox + label: keep the checkbox and its text on one line
     rather than the text wrapping under the checkbox at narrow widths. */
  .agentic-toggle {
    white-space: nowrap;
  }

  /* Add-item modal: fit within a 375px viewport, centered, and scroll if the
     form content is taller than the space below its top:80px offset.
     No max-width here (task 22.6) - the base .modal-card { max-width:
     calc(100vw - 24px) } above is the universal viewport cap; re-adding
     460px here (equal specificity, later in source) used to beat it on
     phone and re-overflow every modal-card that wants to stay narrower
     than 460 desktop-wide (e.g. modal-card-narrow's 380px). */
  .modal-card {
    width: calc(100vw - 24px);
    max-height: calc(100vh - 100px);
    overflow-y: auto;
  }

  /* Design/Action child rows: the 28px indent eats too much of a 375px row. */
  .item-row.child,
  .action-item.child {
    margin-left: 14px;
  }
}

/* Task 22.4: admin + roster tables (team.html, regions.html, data.html).
   Reuses the existing @767px phone tier only - no new breakpoint. */

/* Wide tables (team.html's roster + Orphaned Deals) scroll inside their own
   container instead of forcing the page body to scroll sideways - same
   overflow-x: auto pattern .kanban already uses above. */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Narrower modals (team.html's Add Person, nav.js's My Profile) reuse
   .modal-card's fixed positioning/shadow but must stay 380px on desktop,
   not grow to the 460px default above. */
.modal-card.modal-card-narrow {
  width: 380px;
  /* Repeat the viewport cap on this higher-specificity selector too - belt and
     braces so a 380px modal-card variant always fits a narrow phone even if
     the base .modal-card cap (task 22.3, now the sole viewport-cap authority
     on phone as of task 22.6) is ever touched again in isolation. */
  max-width: calc(100vw - 24px);
}

@media (max-width: 767px) {
  /* regions.html: the add-region row (text input + button) is a plain flex
     row, not a .form-row - stack it to a single full-width column instead of
     squeezing side by side at 375px. */
  .control-row {
    flex-direction: column;
  }
  .control-row > * {
    width: 100%;
  }
}

/* Task 22.6: remaining pages + shared components (New Deal modal, Change
   Password modal, login box, toast already handled above/inline where they
   live - this block covers the Module Library header). Reuses the existing
   @767px phone tier only - no new breakpoint. */
@media (max-width: 767px) {
  /* Module Library: the module card header's own action-button row (up/down/
     +Add Item/Remove Module) is a plain, unstyled div - at 375px the four
     buttons need to wrap and shrink instead of squeezing along one line.
     Scoped to .mod-head-actions specifically so this never touches the
     unrelated .item-row .item-head (the item edit header, already flex). */
  .mod-head-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 6px;
  }
  .mod-head-actions .btn.small {
    padding: 4px 8px;
  }
}

/* Task 32.1: deal card context menu (public/js/dealCards.js attachCardMenu/
   openMenu). One shared node per page, position:fixed and JS-positioned via
   clampMenuPosition - left/top/display are set inline, not here. */
.card-menu {
  position: fixed;
  z-index: 120;
  min-width: 180px;
  padding: 4px;
  background: var(--surface);
  border: 1px solid var(--brand-border);
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  display: none;
}
.card-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  border-radius: 6px;
  padding: 8px 10px;
  font: inherit;
  color: var(--text);
  cursor: pointer;
}
.card-menu-item:hover {
  background: var(--surface-tray);
}
.card-menu-item:focus {
  background: var(--surface-tray);
  outline: 2px solid var(--focus-ring);
  outline-offset: -2px;
}
.card-menu-divider {
  border-top: 1px solid var(--brand-border);
  margin: 4px 0;
}

/* Task 46.2 (PRD prd-footer-status-bar.md FR-2..FR-5): footer deal-count
   content, appended by nav.js's setFooterCounts() next to the version text
   on dashboard.html/manager.html only (FR-5 - the other five nav.js pages
   keep a version-only footer, since they never call setFooterCounts).
   Plain inline content inside .app-footer's own text-align:center flow, so
   a long count list wraps onto a second line on a narrow phone instead of
   overflowing horizontally - no fixed width or nowrap on the whole block.
   The leading separator is a :not(:empty)::before so an all-zero result
   (the span left childless by setFooterCounts) renders nothing extra, not
   a stray dash. */
.app-footer-counts:not(:empty)::before {
  content: ' — ';
  opacity: 0.7;
}
/* review finding, task 46.2: nowrap is scoped to each "N label" PAIR, not
   the surrounding group - a bare text node let the line break mid-pair
   (e.g. "12" / "none" split across lines) at narrow widths. The line still
   wraps freely between pairs, at the ' · '/' | ' text nodes nav.js appends
   as separate siblings. */
.app-footer-count-pair {
  white-space: nowrap;
}
.app-footer-count-sep {
  opacity: 0.7;
}

/* Task 46.3 (PRD prd-footer-status-bar.md FR-6/FR-7, US-004): the "N active
   in the last hour" stat, appended by nav.js's setFooterActivity() as a
   sibling of #appFooterCounts on manager.html only. Same :not(:empty)
   ::before idiom as .app-footer-counts above - reserved for exactly this
   next sibling group by that rule's own comment - so an absent/hidden stat
   (the span left childless by setFooterActivity) renders nothing extra. */
.app-footer-activity:not(:empty)::before {
  content: ' — ';
  opacity: 0.7;
}

/* Task 57.2 (PRD prd-release-notes.md FR-4): the footer version links to the
   release notes. color:inherit keeps the muted var(--brand-gray) the rest of
   .app-footer already uses - the global `a` colour (--brand-sky-blue) would
   put a new 12px colour pair on --bg that docs/DESIGN.md §2 has no row and
   test/contrast.test.js has no pin for. The underline is the affordance. */
.app-footer a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}
