/* ---- Compend design language (Nov 5 2026, type reworked Nov 9), the
   WHOLE site, one system. Old internet: simple text links, lots of
   BOXES. Sharp, not circular: border-radius 0 everywhere, no circles,
   no pills. Minimal color: black/white/grey + the green ✳ only. Solid,
   no opacity: no rgba(), no faded text, no glow, no mist, no
   breathing. One plain sans face (Helvetica), single narrow centered
   column where a column applies, small bold all-caps grey-green
   section labels, thin grey dashed rectangles as the placeholder
   motif, plain text links instead of pill buttons. No shadows, no
   rounded corners on content elements, no solid cards.
   TYPE SCALE — one size, weight and line-height per role, so every
   section reads the same: title 28/700/1.2, body 15/400/1.6, table
   row 14/400/1.5, meta 13/400/1.5, small 12/400/1.5, section label
   12/700/uppercase/.08em, table head 11/700/uppercase/.06em. The
   brief lead is body size too, no larger opening paragraph. Colors:
   ink #111 for text, #555 for secondary, #737373 for captions,
   --cp-mute for labels. ---- */
:root {
  --cp-ink: #111;
  --cp-mute: #6B7263;
  --cp-bar: #EDF1F4;
  --cp-dash: #9AA0A6;
  --cp-green: #2E7D32;
  --cp-rule: #d9d9d9;
  --cp-sans: Helvetica, Arial, -apple-system, "Segoe UI", sans-sans;
}
#discoverView, #campaignsView, #collectionsView, #campaignView, #callSheet,
#workOverlay, #onboard,
#boardPickBar, #moreBar {
  font-family: var(--cp-sans);
  color: var(--cp-ink);
  background: #fff;
}
#discoverView button, #discoverView input, #discoverView select,
#campaignsView button, #campaignsView input, #campaignsView textarea,
#collectionsView button, #collectionsView input,
#campaignView button, #campaignView input, #campaignView textarea,
#callSheet button, #workOverlay button, #workOverlay textarea,
#picker button, #picker input, #onboard button {
  font-family: var(--cp-sans);
}
/* section labels, site-wide on these surfaces: small bold all-caps
   letter-spaced grey-green, sitting close above their content */
#discoverView .morelabel,
#campaignView .cdsect, #callSheet .cssect,
#campaignView .cdgrid label, #campaignView .cdbrief > span {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--cp-mute);
}
#campaignView .cdsect .cdhint {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  color: #a8a8a8;
  margin-left: 6px;
}
/* section rhythm: one gap above every section, so the pages share a
   single vertical rhythm instead of each block setting its own. The
   page grids reset the first section in each column to zero. */
#campaignView .campdetail .cdsect { margin: 28px 0 12px; }

/* ---- shared chrome: the slim pale blue-grey top bar ---- */
#discoverBar {
  background: var(--cp-bar);
  border-bottom: 1px solid #c9ced3;
  padding: 8px 32px 10px;
}
/* the wordmark keeps the OLD logo treatment (light wide-tracked lowercase
   Inter) even though the rest of the chrome went sans, the ✳ before it
   is green, not gold. */
#discoverBar .wordmark {
  font-family: "Inter", -apple-system, sans-sans;
  font-size: 14px;
  font-weight: 200;
  letter-spacing: .3em;
  text-transform: lowercase;
  color: var(--cp-ink);
}
#discoverBar .wordmark::before { content: "\2733\FE0E  "; color: var(--cp-green); }
/* the network view's wordmark is already the old Inter treatment (see the
   base stylesheet), it just needs the same green ✳ in front of it. */
.ui .wordmark::before { content: "\2733\FE0E  "; color: var(--cp-green); }
/* desktop shows the full wordmark; phone shows the short "cd" (see the
   phone rules in index.html). */
.ui .wordmark .wm-short { display: none; }
#discoverBar input[type="search"] {
  border: none;
  border-bottom: 1px solid var(--cp-dash);
  border-radius: 0;
  background: transparent;
  height: 36px;
  font-size: 15px;
  font-family: var(--cp-sans);
}
#discoverBar .views button {
  background: transparent;
  border: none;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  font-weight: 400;
  color: #444;
  padding: 8px 6px;
}
#discoverBar .views button.on {
  background: transparent;
  color: var(--cp-ink);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* role tabs + filter row: text links on one scrolling row, never stacked */
#roleTabs button {
  background: transparent;
  border: none;
  border-radius: 0;
  font-family: "Inter", -apple-system, sans-sans;
  font-size: 15px;
  font-weight: 400;
  color: #555;
  padding: 6px 10px;
}
#roleTabs button.on {
  background: transparent;
  color: var(--cp-ink);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* wall chrome: plain text links */
#workMore {
  background: transparent;
  color: var(--cp-ink);
  border: none;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 15px;
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 12px 0;
}
#collBar h2 { font-family: var(--cp-sans); font-weight: 700; }
#collBar .roster { font-family: var(--cp-sans); font-size: 15px; line-height: 1.7; }
#collBar button {
  background: transparent;
  border: none;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 8px 4px;
}
#findBar, #moreBar { font-family: var(--cp-sans); font-size: 14px; }
#moreBar button {
  background: transparent;
  border: none;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 13px;
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 6px 0;
}
/* find bar: the inline style in index.html owns the green bar and the
   white pill done button. A 1px cyan dash line marches along the very
   bottom edge so it is clear the wall is being viewed through the lens
   of adding to a campaign. */
#findBar { position: relative; }
#findBar::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: repeating-linear-gradient(90deg, #00c2ff 0 10px, transparent 10px 20px);
  animation: finddash 1s linear infinite;
}
@keyframes finddash {
  from { background-position: 0 0; }
  to { background-position: 20px 0; }
}
/* board-pick bar: a plain white strip with a hairline top rule, not a pill */
#boardPickBar {
  left: 0;
  right: 0;
  bottom: 0;
  transform: none;
  width: 100%;
  max-width: none;
  background: #fff;
  color: var(--cp-ink);
  border-top: 1px solid var(--cp-rule);
  border-radius: 0;
  padding: 12px 20px;
  justify-content: center;
  font-family: var(--cp-sans);
}
#boardPickBar button {
  background: transparent;
  color: var(--cp-ink);
  border: none;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 13px;
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 6px 0;
}

/* ---- campaigns top bar: the same Compend bar as the wall (pale
   blue-grey, sans wordmark + gold ✳, plain text nav), rendered inside the
   campaigns views because the wall's bar lives in #discoverView, which is
   hidden there. Sticky within the view's own scroll container. ---- */
.cptopbar {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--cp-bar);
  border-bottom: 1px solid #c9ced3;
  padding: 8px 32px 10px;
  display: flex;
  gap: 24px;
  align-items: center;
}
/* the broad button reset above (#campaignsView button / #campaignView button
   → sans) outranks a plain .cptopbar rule, so the wordmark selector carries
   the view id to win it back to the old Inter treatment. */
#campaignsView .cptopbar .cpwordmark,
#collectionsView .cptopbar .cpwordmark,
#campaignView .cptopbar .cpwordmark {
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  /* same old logo treatment as the wall bar: light wide-tracked lowercase
     Inter, with the green ✳, not the Compend sans. */
  font-family: "Inter", -apple-system, sans-sans;
  font-size: 14px;
  font-weight: 200;
  letter-spacing: .3em;
  text-transform: lowercase;
  color: var(--cp-ink);
  white-space: nowrap;
  flex: none;
}
.cptopbar .cpwordmark::before { content: "\2733\FE0E  "; color: var(--cp-green); }
/* the short "cd" mark lives in the markup (like the wall bar's .wm-short)
   so the header never reflows: desktop shows the full wordmark, phone
   shows "cd". */
.cptopbar .cpwordmark .cp-short { display: none; }
.cptopbar .cpnav {
  display: flex;
  gap: 4px;
  align-items: center;
  margin-left: auto;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.cptopbar .cpnav::-webkit-scrollbar { display: none; }
.cptopbar .cpnav button {
  background: transparent;
  border: none;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  font-weight: 400;
  color: #444;
  padding: 8px 6px;
  cursor: pointer;
  white-space: nowrap;
  flex: none;
}
.cptopbar .cpnav button.on {
  color: var(--cp-ink);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}
@media (max-width: 759px) {
  .cptopbar { padding: 10px 12px 8px; gap: 8px; flex-wrap: nowrap; }
  /* phone: one row, the nav scrolls sideways instead of dropping to a
     second line, like the wall bar. The five items must all fit in
     390px at rest, so the buttons shrink a touch and the bar tightens:
     "collections" was clipping to "colle" with the sign-in after it. */
  .cptopbar .cpnav { flex: 1 1 auto; min-width: 0; margin-left: 0; overflow-x: auto; }
  .cptopbar .cpnav button, .cptopbar .authslot .authbtn { font-size: 13px; padding: 8px 4px; }
}

/* ---- campaigns grid: quiet sans entries in a narrow column ---- */
#campaignsView .cgsheet { max-width: 575px; padding: 22px 20px 90px; }
#campaignsView .cgfoot .cgnew {
  background: transparent;
  color: var(--cp-ink);
  border-radius: 0;
  font-size: 14px;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  white-space: nowrap;
  padding: 6px 0;
}
#campaignsView .cgsheet h1 {
  font-family: var(--cp-sans);
  font-size: 28px;
  font-weight: 700;
}
#campaignsView .cgsub {
  font-family: var(--cp-sans);
  font-size: 15px;
  line-height: 1.6;
  color: var(--cp-ink);
}
#campaignsView .cgexpl {
  font-family: var(--cp-sans);
  font-size: 14px;
  color: var(--cp-mute);
}
#campaignsView .cggrid { display: block; margin-top: 28px; }
#campaignsView .ccard {
  display: flex;
  gap: 18px;
  border: none;
  border-top: 1px solid #e5e2df;
  border-radius: 0;
  padding: 22px 0;
}
#campaignsView .ccard:hover { border-color: #e5e2df; }
#campaignsView .ccard.example {
  border: 1px dashed var(--cp-dash);
  border-radius: 0;
  padding: 18px;
  margin-bottom: 22px;
}
#campaignsView .ccard .cccover {
  width: 120px;
  height: 120px;
  flex: none;
  border-radius: 0;
}
#campaignsView .ccard .cccover img { border-radius: 0; }
#campaignsView .ccard .cccover.empty span { font-family: var(--cp-sans); }
#campaignsView .ccard .ccbody { padding: 0; min-width: 0; }
#campaignsView .ccard .ccex {
  display: block;
  border: none;
  background: none;
  padding: 0;
  margin-bottom: 8px;
  font-family: var(--cp-sans);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--cp-mute);
}
#campaignsView .ccard h3 {
  font-family: var(--cp-sans);
  font-size: 20px;
  font-weight: 700;
  line-height: 1.3;
}
#campaignsView .ccard .ccbrief {
  font-family: var(--cp-sans);
  font-size: 15px;
  line-height: 1.6;
  color: #444;
  /* the card is a teaser, not the brief, two lines, then cut. The full
     brief lives on the detail screen. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
#campaignsView .ccard .ccfoot { display: flex; align-items: baseline; gap: 12px; flex-wrap: nowrap; margin-top: 10px; }
#campaignsView .ccard .ccteam { margin-left: auto; display: flex; align-items: center; flex: none; }
#campaignsView .ccard .ccmeta { font-size: 13px; color: var(--cp-mute); }
#campaignsView .ccard .ccstage {
  border: none;
  padding: 0;
  font-family: var(--cp-sans);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--cp-mute);
}
#campaignsView .ccard .ccn {
  font-family: var(--cp-sans);
  color: var(--cp-mute);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#campaignsView .cgfoot {
  font-family: var(--cp-sans);
  font-size: 13px;
  color: var(--cp-mute);
}
/* the import action sits inside the footer sentence, a text link, not
   a bordered button. */
#campaignsView .cgfoot button {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 13px;
  color: var(--cp-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 0;
  cursor: pointer;
}
#campaignsView .cgform .field {
  border: none;
  border-bottom: 1px solid var(--cp-dash);
  border-radius: 0;
  background: transparent;
  padding: 8px 0;
  font-family: var(--cp-sans);
  font-size: 15px;
}
#campaignsView .cgform .btn {
  background: transparent;
  color: var(--cp-ink);
  border: none;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 8px 0;
}
@media (max-width: 759px) {
  #campaignsView .ccard .cccover { width: 96px; height: 96px; }
  #campaignsView .ccard { gap: 14px; }
}

/* ---- campaign detail: one content frame for every tab (header, tabs,
   text, grids), 1200px of content centered on wide screens. Nothing
   breaks out of it, so every tab shares the same left edge. ---- */
#campaignView .campdetail { max-width: 1264px; margin: 0 auto; padding: 22px 20px 90px; box-sizing: border-box; }
/* top bar: a deliberate two-line stack on phone, back on its own line,
   actions on the next, no phrase ever split across lines */
#campaignView .cdtop { flex-wrap: wrap; gap: 4px 16px; }
#campaignView .cdtop > span {
  display: flex;
  gap: 4px 12px;
  flex-wrap: wrap;
  align-items: baseline;
}
#campaignView .cdtop button {
  font-family: var(--cp-sans);
  font-size: 14px;
  white-space: nowrap;
  padding: 6px 0;
}
#campaignView .cdtitle {
  font-family: var(--cp-sans);
  font-size: 28px;
  font-weight: 700;
  line-height: 1.2;
}
/* the title is an h1 when reading (an input when editing), an h1
   carries default margins an input does not. */
#campaignView h1.cdtitle { margin: 0; }
/* the title input is borderless by the base rule, so in edit mode it
   read as plain text, a hairline under it says it is editable, like
   the other fields. */
#campaignView input.cdtitle { border: none; border-bottom: 1px solid #bbb; padding-bottom: 4px; }
/* the facts as one readable line, and the brief / notes as plain text,
   both wrap, so nothing clips on phone the way the old single-line
   location input and the fixed-rows textareas did. */
#campaignView .cdmeta { font-family: var(--cp-sans); font-size: 13px; line-height: 1.5; color: #555; margin: 4px 0 22px; }
#campaignView .cdtext { font-family: var(--cp-sans); font-size: 15px; line-height: 1.6; color: var(--cp-ink); margin: 8px 0 22px; white-space: pre-wrap; }
/* stage stepper: plain sans text links. Four stages, no "done", the
   campaign is in progress until it is, and no DONE label belongs on it.
   Sized to fit all four stages inside 390px, no scroll needed; the
   scroll fallback stays as a safety net only. */
#campaignView .cdstages {
  display: flex;
  flex-wrap: nowrap;
  gap: 6px;
  align-items: baseline;
  margin: 12px 0 28px;
  overflow-x: auto;
  scrollbar-width: none;
}
#campaignView .cdstages::-webkit-scrollbar { display: none; }
#campaignView .cdstages button {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 15px;
  font-weight: 400;
  color: #555;
  padding: 6px 0;
  flex: none;
}
#campaignView .cdstages button.on {
  background: transparent;
  color: var(--cp-ink);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}
#campaignView .cdstages .cdarrow { color: var(--cp-dash); flex: none; }
/* moodboard tabs: a real tab bar, not a row of text links. The bar
   breaks out to the full width like the wall below it, and the tabs
   are boxes sitting on the bar's bottom border: inactive tabs are a
   flat grey fill, the active tab is white and merges with the framed
   wall underneath. The source link and the add action sit at the
   right of the bar, so the collection reads as the board's content,
   not a stray paragraph. */
#campaignView .cdmoodtabs {
  display: flex;
  flex-wrap: nowrap;
  gap: 0;
  align-items: flex-end;
  margin: 12px 0 0;
  border-bottom: 1px solid #0d0d0d;
  overflow-x: auto;
  scrollbar-width: none;
}
#campaignView .cdmoodtabs::-webkit-scrollbar { display: none; }
#campaignView .cdmoodtabs button.cdmoodtab {
  border: 1px solid #0d0d0d;
  border-bottom: none;
  background: #f4f2ef;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  font-weight: 400;
  color: #555;
  padding: 8px 14px;
  margin-bottom: -1px;
  margin-right: 6px;
  cursor: pointer;
  white-space: nowrap;
  flex: none;
}
#campaignView .cdmoodtabs button.cdmoodtab.on {
  background: #fff;
  color: var(--cp-ink);
  font-weight: 700;
}
#campaignView .cdmoodtabs .cdmoodmeta {
  margin-left: auto;
  display: flex;
  gap: 16px;
  align-items: baseline;
  flex: none;
  padding: 0 0 8px 16px;
  font-size: 13px;
  color: var(--cp-mute);
  white-space: nowrap;
}
#campaignView .cdmoodtabs .cdmoodmeta a { color: var(--cp-ink); }
#campaignView .cdmoodtabs #cdMoodAdd {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 13px;
  color: var(--cp-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 0;
  cursor: pointer;
  white-space: nowrap;
}
/* remove one photo from a moodboard (edit mode, signed in): a small
   white square at the tile's top-right corner, like the wall save
   button, sharp corners, no pill. */
#campaignView .cdwall .cdmoodremove {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 28px;
  height: 28px;
  background: #fff;
  border: 1px solid #e5e2df;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 15px;
  color: #0d0d0d;
  cursor: pointer;
}
#campaignView .cdwall .cdmoodnuke {
  position: absolute;
  top: 10px;
  left: 10px;
  width: 28px;
  height: 28px;
  background: #fff;
  border: 1px solid #e5e2df;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 15px;
  color: #b3261e;
  cursor: pointer;
}
/* location / date / budget: simple labeled rows, stacked, not a grid.
   Inputs are bare sans lines with a bottom hairline. */
#campaignView .cdgrid { display: block; }
#campaignView .cdgrid label { display: block; margin-bottom: 18px; }
#campaignView .cdgrid input {
  display: block;
  width: 100%;
  margin-top: 6px;
  border: none;
  border-bottom: 1px solid var(--cp-dash);
  border-radius: 0;
  background: transparent;
  padding: 8px 0;
  font-family: var(--cp-sans);
  font-size: 15px;
  line-height: 1.6;
  color: var(--cp-ink);
}
/* brief + notes: borderless growing text, so edit mode reads as the
   finished copy, not a form. The text itself is the field; the quiet
   small-caps label above it is the only chrome. Focus gets a pale
   solid wash, no outline, no border. */
/* growing textareas: no internal scrollbar, no resize handle; the
   height follows the content, set by growTextArea on paint and input. */
#campaignView textarea[data-grow] { overflow: hidden; resize: none; }
#campaignView .cdbrief { margin-top: 28px; }
#campaignView .cdbrief textarea {
  display: block;
  width: 100%;
  margin-top: 4px;
  border: none;
  border-radius: 0;
  background: transparent;
  padding: 0;
  font-family: var(--cp-sans);
  font-size: 15px;
  line-height: 1.6;
  color: var(--cp-ink);
}
#campaignView .cdbrief input {
  display: block;
  width: 100%;
  margin-top: 4px;
  border: none;
  border-radius: 0;
  background: transparent;
  padding: 0;
  font-family: var(--cp-sans);
  font-size: 15px;
  line-height: 1.6;
  color: var(--cp-ink);
}
#campaignView .cdbrief textarea:focus,
#campaignView .cdbrief input:focus { outline: none; background: #f2f0ef; }
/* the brief is the editorial lead: larger type, bounded measure. */
#campaignView .cdtext.cdlead { font-size: 15px; line-height: 1.6; max-width: 640px; }
#campaignView .cdbrief.lead textarea { font-size: 15px; line-height: 1.6; }
/* art direction: a solid editorial box, grounded, not a floating
   dashed field. The label sits above the box; the box holds the copy. */
#campaignView .wkartbox { border: 1px solid #0d0d0d; padding: 16px 20px; margin: 8px 0 22px; max-width: 900px; }
#campaignView .wkartbox .cdtext { margin: 0; }
#campaignView .wkartbox textarea { display: block; width: 100%; border: none; background: transparent; padding: 0; font-family: var(--cp-sans); font-size: 15px; line-height: 1.6; color: var(--cp-ink); resize: none; }
/* mood: the aesthetic one-liners on the Board, one line each, never
   a big text box. Read mode is plain list text; edit mode is a
   one-line input per line, same type as the brief inputs. */
#campaignView .moodlines { list-style: none; margin: 8px 0 22px; padding: 0; max-width: 900px; }
#campaignView .moodlines li { font-family: var(--cp-sans); font-size: 15px; line-height: 1.6; color: var(--cp-ink); margin: 0 0 4px; }
#campaignView .moodlines input.moodline { display: block; width: 100%; border: none; border-radius: 0; background: transparent; padding: 0; font-family: var(--cp-sans); font-size: 15px; line-height: 1.6; color: var(--cp-ink); }
#campaignView .moodlines input.moodline:focus { outline: none; background: #f2f0ef; }
/* a section label that precedes full-width content (the shoot board
   strip): it breaks out with the strip so label and content align. */
#campaignView .cdsect.wkfull {
  width: 100vw;
  max-width: none;
  margin-left: calc(-50vw + 50%);
  padding-left: 20px;
  padding-right: 20px;
  box-sizing: border-box;
}
@media (min-width: 1000px) {
  #campaignView .cdsect.wkfull { padding-left: 32px; padding-right: 32px; }
}
/* board: a row of square images. Adding is one line of links under the
   row (or under the header when empty), the old big dashed "+" box was
   a third way to add that duplicated the links. */
#campaignView .cdboard { gap: 12px; }
#campaignView .cdbimg { width: 120px; height: auto; flex: none; border-radius: 0; }
#campaignView .cdbimg img {
  display: block;
  width: 120px;
  height: 120px;
  border-radius: 0;
}
#campaignView .cdboardadd { font-family: var(--cp-sans); font-size: 13px; color: var(--cp-mute); margin: 10px 0 4px; }
#campaignView .cdboardadd button {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  color: var(--cp-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 6px 0;
  cursor: pointer;
}
#campaignView .cdbimg button {
  border: 1px solid #ddd;
  border-radius: 0;
  background: #fff;
}
/* cover: the campaign's hero image, at the top of the detail view (and
   on the card, via .cccover). A photo, so it renders as-is, sharp
   corners like everything else. */
#campaignView .cdcover { margin: 4px 0 18px; }
#campaignView .cdcover img { display: block; width: 100%; max-height: 420px; object-fit: cover; border-radius: 0; }
#campaignView .cdcoveradd { font-family: var(--cp-sans); font-size: 13px; color: var(--cp-mute); margin: 10px 0 4px; }
#campaignView .cdcoveradd button {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  color: var(--cp-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 6px 0;
  cursor: pointer;
}
/* board tile "set as cover", the same small white button as the ×. */
#campaignView .cdbimg .cdsetcover { font-size: 11px; }
/* auth: the sign-in form, Compend style. The campaign detail's
   in-place prompt uses these rules; the header panel below has its own. */
#campaignView .cdauth { font-family: var(--cp-sans); font-size: 13px; color: var(--cp-mute); margin: 12px 0 0; }
#campaignView .cdauth button {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  color: var(--cp-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 6px 0;
  cursor: pointer;
}
#campaignView .cdauth input {
  border: none;
  border-bottom: 1px solid var(--cp-dash);
  border-radius: 0;
  background: transparent;
  padding: 8px 0;
  font-family: var(--cp-sans);
  font-size: 15px;
  display: block;
  width: 100%;
  max-width: 320px;
  box-sizing: border-box;
}
#campaignView .cdauth .autherr { color: #b3261e; font-size: 13px; }
/* sync state, a quiet note, never a banner. */
#campaignView .cdsync { font-size: 12px; color: var(--cp-mute); }
/* ---- header auth: the sign-in slot in every top bar, and the panel. ---- */
.authslot { display: flex; gap: 10px; align-items: center; flex: none; min-width: 0; }
.authslot .acc { font-size: 13px; color: #737373; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.authslot .authsync { font-size: 12px; color: #a8a8a8; white-space: nowrap; }
.authslot .authpic { width: 28px; height: 28px; border-radius: 50%; background: #999; overflow: hidden; flex: none; cursor: pointer; }
.authslot .authpic img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* initials in place of a pic (no handle pic stored, or the stored pic 404s). */
.authslot .authpic-none { display: flex; align-items: center; justify-content: center; color: #fff; font-size: 12px; font-weight: 700; }
#authAccount .authpic-none { display: flex; align-items: center; justify-content: center; color: #fff; font-size: 24px; font-weight: 700; }
#authMenu { position: fixed; z-index: 80; min-width: 160px; background: #fff; border: 1px solid #0d0d0d; border-radius: 0; padding: 4px 0; }
#authMenu .authmenu-item { display: block; width: 100%; box-sizing: border-box; background: transparent; border: none; border-radius: 0; font-family: inherit; font-size: 14px; color: #0d0d0d; text-align: left; padding: 9px 14px; cursor: pointer; }
#authMenu .authmenu-item:hover { background: #f5f5f5; }
#authMenu .authmenu-out { color: #b3261e; }
#authAccount { position: fixed; inset: 0; z-index: 70; display: none; align-items: center; justify-content: center; background: #fff; padding: 20px; }
#authAccount.open { display: flex; }
#authAccount .authsheet { background: #fff; width: min(360px, 100%); padding: 22px 22px 18px; border: 1px solid #e5e2df; border-radius: 0; text-align: center; }
#authAccount .authpic { display: block; width: 64px; height: 64px; border-radius: 50%; background: #999; overflow: hidden; margin: 0 auto 12px; }
#authAccount .authpic img { width: 100%; height: 100%; object-fit: cover; display: block; }
#authAccount .authacct-name { font-size: 15px; font-weight: 700; color: #0d0d0d; }
#authAccount .authacct-handle { font-size: 13px; color: #737373; margin-top: 2px; }
#authAccount .authacct-handle a { color: #0d0d0d; text-decoration: none; }
#authAccount .authacct-email { font-size: 13px; color: #737373; margin-top: 6px; }
#authAccount .authacct-out { display: block; margin: 18px auto 0; background: transparent; border: none; border-radius: 0; font-family: inherit; font-size: 13px; color: #b3261e; text-decoration: underline; text-underline-offset: 3px; padding: 6px 0; cursor: pointer; }
.authslot .authbtn { background: transparent; border: none; font-family: inherit; font-size: 14px; font-weight: 500; color: #0d0d0d; cursor: pointer; padding: 8px 0; white-space: nowrap; }
/* the network bar's quiet treatment, and the campaigns bar's sans one */
.ui .authslot .authbtn { font-size: 11px; font-weight: 200; letter-spacing: .18em; text-transform: lowercase; color: rgba(0,0,0,.45); padding: 4px 0; }
.ui .authslot .authbtn:hover { color: rgba(0,0,0,.85); }
.ui .authslot .acc, .ui .authslot .authsync { font-size: 11px; letter-spacing: .1em; color: rgba(0,0,0,.45); }
.cptopbar .authslot .authbtn { font-family: var(--cp-sans); font-size: 14px; font-weight: 400; color: #444; padding: 8px 6px; }
/* the sign-in lives IN the wall nav, not after it, one row, same look
   as the other nav items. */
#discoverBar .views .authslot { display: inline-flex; gap: 10px; align-items: center; flex: none; }
#discoverBar .views .authslot .authbtn { font-family: var(--cp-sans); font-size: 14px; font-weight: 400; color: #444; padding: 8px 6px; }
#discoverBar .views .authslot .acc { font-family: var(--cp-sans); font-size: 14px; color: #444; }
/* the network chrome carries the same nav as the wall: same items, same
   order, same look, the faint 11px control style does not apply here. */
.ui .ctl [data-nav], .ui .ctlM [data-nav] { font-family: var(--cp-sans); font-size: 14px; font-weight: 400; color: #444; letter-spacing: 0; text-transform: none; padding: 8px 6px; white-space: nowrap; }
.ui .ctl [data-nav].on, .ui .ctlM [data-nav].on { color: var(--cp-ink); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }
.ui .ctl .authslot .authbtn, .ui .ctlM .authslot .authbtn { font-family: var(--cp-sans); font-size: 14px; font-weight: 400; color: #444; letter-spacing: 0; text-transform: none; padding: 8px 6px; }
.ui .ctl .authslot .acc, .ui .ctlM .authslot .acc { font-family: var(--cp-sans); font-size: 14px; color: #444; letter-spacing: 0; text-transform: none; }
.ui .ctl { max-width: calc(100vw - 220px); overflow-x: auto; scrollbar-width: none; }
.ui .ctl::-webkit-scrollbar { display: none; }
#authPanel { position: fixed; inset: 0; z-index: 70; display: none; align-items: center; justify-content: center; background: #fff; padding: 20px; }
#authPanel.open { display: flex; }
#authPanel .authsheet { background: #fff; width: min(360px, 100%); padding: 22px 22px 18px; border: 1px solid #e5e2df; border-radius: 0; }
#authPanel .authtitle { font-size: 15px; font-weight: 700; color: #0d0d0d; margin-bottom: 14px; }
#authPanel .authtitle .authstar { color: var(--cp-green); }
#authPanel .authnote { font-size: 13px; color: #737373; margin-bottom: 12px; }
#authPanel .authfield { display: block; width: 100%; box-sizing: border-box; border: 1px solid #e5e2df; border-radius: 0; background: #fcfbfa; padding: 10px 12px; font-family: inherit; font-size: 16px; color: #0d0d0d; outline: none; margin-bottom: 8px; }
#authPanel .authfield:focus { border-color: #0d0d0d; }
#authPanel .authrow { display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap; margin-top: 6px; }
#authPanel .authgo { background: #0d0d0d; color: #fff; border: none; border-radius: 0; font-family: inherit; font-size: 13px; font-weight: 500; padding: 9px 16px; cursor: pointer; }
#authPanel .authlink { background: transparent; border: none; font-family: inherit; font-size: 13px; color: #737373; cursor: pointer; padding: 9px 0; }
#authPanel .authlink:hover { color: #0d0d0d; }
#authPanel .autherr { font-size: 12px; color: #b3261e; }
#authPanel .authbottom { display: flex; justify-content: space-between; align-items: baseline; margin-top: 16px; }
#authPanel .authclose { background: transparent; border: none; font-family: inherit; font-size: 13px; color: #b3261e; cursor: pointer; padding: 9px 0; }
@media (max-width: 759px) {
  .authslot .acc { max-width: 110px; }
  .authslot .authsync { display: none; }
}
#campaignView .cdimport .btn {
  background: transparent;
  color: var(--cp-ink);
  border: none;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  font-weight: 400;
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 8px 0;
}
#campaignView .cdimport input {
  flex: 1;
  min-width: 200px;
  border: none;
  border-bottom: 1px solid var(--cp-dash);
  border-radius: 0;
  background: transparent;
  padding: 8px 0;
  font-family: var(--cp-sans);
  font-size: 15px;
}
#campaignView .cdimportmsg { font-family: var(--cp-sans); font-size: 13px; }
/* taste: plain sans words, roles bold, separated by middle dots */
#campaignView .cdtaste {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  font-family: var(--cp-sans);
  font-size: 14px;
  line-height: 1.9;
}
#campaignView .cdtaste .tchip {
  border: none;
  background: transparent;
  border-radius: 0;
  padding: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  color: #444;
}
#campaignView .cdtaste .tchip.role { border: none; color: var(--cp-ink); font-weight: 700; }
#campaignView .cdtaste .tchip:not(:last-child)::after { content: " ·"; color: var(--cp-dash); }
/* team: one sheet, a group row per role, person rows with columns.
   No cards. The role label and find link live in the group row. */
#campaignView .slotrole {
  font-family: var(--cp-sans);
  font-size: 17px;
  font-weight: 700;
}
#campaignView .slotfind {
  background: transparent;
  border: none;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  font-weight: 400;
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 0;
  cursor: pointer;
}
/* the owner is one line under the team header, not a slot: face + "run
   by <name>". Tapping it opens the owner's overlay. */
#campaignView .cdowner { display: flex; align-items: center; gap: 10px; font-family: var(--cp-sans); font-size: 15px; font-weight: 700; padding: 4px 0 18px; cursor: pointer; }
#campaignView .cdowner .sface { position: relative; width: 28px; height: 28px; aspect-ratio: 1/1; border-radius: 50%; background: #f2f0ef; overflow: hidden; flex: none; }
#campaignView .cdowner .sface .ini { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; color: #555; }
#campaignView .cdowner .sface img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* add a role, in place at the end of the team, the old "roles needed"
   picker section listed every role a second time. */
#campaignView .cdaddrole { font-family: var(--cp-sans); font-size: 14px; color: var(--cp-mute); margin: 4px 0 22px; }
#campaignView .cdaddrole button { border: none; background: transparent; border-radius: 0; font-family: var(--cp-sans); font-size: 14px; color: var(--cp-ink); text-decoration: underline; text-underline-offset: 3px; padding: 6px 0; cursor: pointer; }
/* delete lives at the bottom, behind a hairline, at a whisper, not up
   top at the same weight as the working actions. */
#campaignView .cddeletewrap { margin-top: 34px; padding-top: 18px; border-top: 1px solid #e5e2df; text-align: right; }
#campaignView .cddelete { border: none; background: transparent; border-radius: 0; font-family: var(--cp-sans); font-size: 13px; color: #b3261e; text-decoration: underline; text-underline-offset: 3px; padding: 6px 0; cursor: pointer; }
/* ---- detail header: cover thumb, title and date, the switches and
   export at the right. The tabs are their own row under it. ---- */
#campaignView .wkhead {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  flex-wrap: nowrap;
  margin: 6px 0 0;
}
#campaignView .wkcover {
  flex: none;
  width: 96px;
  height: 96px;
  border: 1px solid #e5e2df;
  background: #f4f2ef;
  border-radius: 0;
  padding: 0;
  cursor: pointer;
  overflow: hidden;
}
#campaignView .wkcover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 0;
}
#campaignView .wkcoverempty {
  font-family: var(--cp-sans);
  font-size: 13px;
  color: var(--cp-mute);
}
#campaignView .wktitlemid {
  flex: 1;
  min-width: 200px;
}
#campaignView .wktitlemid .cdtitle {
  width: 100%;
}
#campaignView .wkmetaline {
  display: flex;
  gap: 8px;
  align-items: baseline;
  flex-wrap: wrap;
  font-family: var(--cp-sans);
  font-size: 14px;
  color: #333;
  margin-top: 6px;
}
#campaignView .wkstatus {
  display: inline-flex;
  gap: 10px;
  flex-wrap: wrap;
}
#campaignView .wkstatus button {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  color: #555;
  padding: 0;
  cursor: pointer;
}
#campaignView .wkstatus button.on {
  color: var(--cp-ink);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}
#campaignView .wkstatustext {
  color: var(--cp-mute);
}
#campaignView .wkmetaedit {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
#campaignView .wkmetaedit input {
  font-family: var(--cp-sans);
  font-size: 14px;
  border: none;
  border-bottom: 1px solid #bbb;
  border-radius: 0;
  padding: 2px 0;
  background: transparent;
}
#campaignView .wksaved {
  font-size: 12px;
  color: var(--cp-mute);
}
/* privacy toggle in the header meta line: plain text, owner only. */
#campaignView .wkpriv {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 13px;
  color: var(--cp-mute);
  cursor: pointer;
  padding: 0;
  margin-left: 12px;
  text-decoration: underline;
}
#campaignView .wktabs {
  display: flex;
  gap: 4px 22px;
  flex-wrap: nowrap;
  align-items: baseline;
  margin: 18px 0 26px;
  border-bottom: 1px solid #e5e2df;
  overflow-x: auto;
  scrollbar-width: none;
}
#campaignView .wktabs button {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 15px;
  font-weight: 400;
  color: #555;
  padding: 6px 0;
  cursor: pointer;
  white-space: nowrap;
  flex: none;
}
#campaignView .wktabs button.on {
  color: var(--cp-ink);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* read mode keeps the line breaks stored in the text (art direction,
   camera, brief): the deck's line structure, not one paragraph. */
#campaignView .cdpre { white-space: pre-wrap; }
/* phone: the header wraps, cover and title on the first row, the tabs
   move to a fixed bar at the bottom of the screen, like the work
   view's bottom filter bar: one row, scrolls sideways, solid
   background, top hairline. The detail already carries 90px of
   bottom padding on phone, so the footer clears the bar. */
@media (max-width: 759px) {
  #campaignView .wkhead {
    flex-wrap: wrap;
  }
  #campaignView .wktabs {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 20;
    background: #fff;
    border-top: 1px solid #e5e2df;
    padding: 8px 16px max(8px, env(safe-area-inset-bottom));
    margin-left: 0;
    flex: none;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  #campaignView .wktabs::-webkit-scrollbar { display: none; }
}
/* members at the far right of the header row: one circular pic per
   member, no label, the pics imply it. The add input stays hidden
   until the + button opens it. */
#campaignView .wkhead .wkmembershead {
  display: flex;
  gap: 4px;
  align-items: center;
  flex: none;
  margin-left: 16px;
  font-family: var(--cp-sans);
  font-size: 13px;
  color: var(--cp-mute);
}
#campaignView .wkhead .wkmemberadd { display: none; }
#campaignView .wkhead .wkmemberadd.open { display: inline-flex; }
#campaignView #wkMemberPlus {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 20px;
  line-height: 1;
  color: var(--cp-ink);
  padding: 0 2px;
  cursor: pointer;
}
#campaignView .wkmembers a { color: var(--cp-ink); }
#campaignView .wkmember {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  color: var(--cp-ink);
}
#campaignView .wkmemberpic {
  display: inline-flex;
  cursor: pointer;
}
#campaignView .wkmemberpic.nolink {
  cursor: default;
}
#campaignView .wkmember button {
  border: none;
  background: transparent;
  border-radius: 0;
  color: #b3261e;
  font-size: 14px;
  padding: 0 2px;
  cursor: pointer;
}
#campaignView .wkmemberadd {
  display: inline-flex;
  gap: 6px;
  align-items: baseline;
}
#campaignView .wkmemberadd input {
  font-family: var(--cp-sans);
  font-size: 13px;
  border: none;
  border-bottom: 1px solid #bbb;
  border-radius: 0;
  padding: 2px 0;
  background: transparent;
  width: 170px;
}
#campaignView .wkmemberadd button {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 13px;
  color: var(--cp-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 0;
  cursor: pointer;
}
/* footer row: export and call sheet as quiet links. */
#campaignView .wkfoot {
  margin-top: 34px;
  padding-top: 18px;
  border-top: 1px solid #e5e2df;
  font-family: var(--cp-sans);
  font-size: 13px;
  color: var(--cp-mute);
}
#campaignView .wkfoot button {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 13px;
  color: var(--cp-mute);
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 6px 0;
  cursor: pointer;
}
/* moodboard drop target, while a drag is over it. */
#campaignView .cdwall.wkdrop { outline: 2px solid #2E7D32; }
/* roster rows: one line, face, name, pipeline link, remove. The slot
   header already names the role and the action link already states the
   status, so the row repeats neither. */
/* roster rows are sheet rows now, the grid, padding and hairlines
   come from .cdrow. A row is still a tap to open the person's work. */
#campaignView .slotperson { cursor: pointer; }
#campaignView .slotperson:hover { background: transparent; }
#campaignView .slotperson .sname {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  font-family: var(--cp-sans);
  font-size: 15px;
  line-height: 1.4;
  min-width: 0;
}
#campaignView .slotperson button {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 13px;
  padding: 4px 0;
  color: #737373;
}
#campaignView .slotperson .sconfirm {
  color: var(--cp-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  white-space: nowrap;
}
#campaignView .slotperson.confirmed .sconfirm {
  background: transparent;
  color: var(--cp-green);
  border: none;
}
/* read mode: the status is plain text, not a link, no underline, no
   pointer. Green when confirmed, grey otherwise. */
#campaignView .slotperson .sstat {
  font-family: var(--cp-sans);
  font-size: 13px;
  color: #737373;
  white-space: nowrap;
}
#campaignView .slotperson.confirmed .sstat { color: var(--cp-green); }
#campaignView .slotperson .sremove { color: #999; }
/* roster contact: the email or site under the name, small and grey.
   It is a link, so it sits above the row tap (see the handler). */
#campaignView .slotperson .snamewrap { display: flex; flex-direction: column; min-width: 0; }
#campaignView .slotperson .scontact { font-family: var(--cp-sans); font-size: 12px; color: #737373; text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#campaignView .slotperson .scontact:hover { text-decoration: underline; }
/* ---- sheets: the campaign detail reads like a spreadsheet, not loose
   text blocks. One bordered grid per section, a small-caps header row
   naming the columns, hairline rows. Read mode only, edit mode keeps
   the textareas and forms. ---- */
#campaignView .cdsheet { border: 1px solid #0d0d0d; font-family: var(--cp-sans); margin: 8px 0 22px; }
#campaignView .cdsheet .cdrow { display: grid; gap: 4px 12px; padding: 9px 12px; border-bottom: 1px solid #f2f0ef; align-items: baseline; }
#campaignView .cdsheet .cdrow:last-child { border-bottom: none; }
#campaignView .cdsheet .cdrow > span, #campaignView .cdsheet .cdrow > button { font-size: 14px; line-height: 1.5; min-width: 0; overflow-wrap: anywhere; }
#campaignView .cdsheet .cdhead { border-bottom: 1px solid #0d0d0d; padding: 7px 12px; }
#campaignView .cdsheet .cdhead span { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: #737373; overflow-wrap: normal; }
#campaignView .cdsheet .cdrow .cdnum { color: #737373; font-size: 12px; }
#campaignView .cdsheet .cdrow .cdsub { display: block; font-size: 12px; color: #737373; margin-top: 2px; }
#campaignView .cdsheet .cdrow .cdamt { text-align: right; }
#campaignView .cdsheet .cdrow.total { font-weight: 700; border-top: 1px solid #0d0d0d; }
#campaignView .cdsheet.shots .cdrow .cdstat.planned { color: #737373; }
#campaignView .cdsheet.shots .cdrow .cdstat.select { color: var(--cp-green); }
#campaignView .cdsheet.selects .cdrow .cdstat.select { color: #737373; }
#campaignView .cdsheet.selects .cdrow .cdstat.done { color: var(--cp-green); }
#campaignView .cdsheet .cdrow .cdthumb { float: left; width: 48px; height: 48px; object-fit: cover; margin: 2px 10px 2px 0; }
#campaignView .cdsheet .cdrow .cdshotconcept { display: block; }
#campaignView .cdsheet .cdrow .cdempty { color: #737373; font-size: 13px; }
#campaignView .cdsheet .cdrow.cdgroup { background: #fcfbfa; border-bottom: 1px solid #0d0d0d; padding: 8px 12px; }
#campaignView .cdsheet .cdgroupact { display: flex; gap: 12px; align-items: baseline; }
#campaignView .cdsheet .cdgroupact .slotremove { border: none; background: transparent; border-radius: 0; font-family: var(--cp-sans); font-size: 14px; color: #999; padding: 0; cursor: pointer; }
/* column templates */
#campaignView .cdsheet.num .cdrow { grid-template-columns: 28px 1fr; }
#campaignView .cdsheet.costs .cdrow { grid-template-columns: 1fr 92px; }
#campaignView .cdsheet.gear .cdrow { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
#campaignView .cdsheet.run .cdrow { grid-template-columns: 76px minmax(0, 1.2fr) minmax(0, 1fr); }
#campaignView .cdsheet.run .cdrow .cdruntime { font-weight: 700; }
#campaignView .cdsheet.selects .cdrow { grid-template-columns: minmax(0, 1fr) 88px; }
#campaignView .cdsheet.cuts .cdrow { grid-template-columns: minmax(0, 1fr) 108px minmax(0, 1.2fr) 28px; }
#campaignView .cdsheet.cuts .cdrow .cdcutname { font-weight: 700; }
#campaignView .cdsheet.shots .cdrow { grid-template-columns: 26px minmax(0, 1fr) 82px 82px 62px; }
#campaignView .cdsheet.team .cdrow { grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr) 78px 84px; }
/* group rows span the sheet: role at the left, actions at the right.
   This sits after the column templates on purpose, same specificity
   would let the sheet template win and crush the label into the first
   column (Day 2 wrapped to "Day / 2"). */
#campaignView .cdsheet.team .cdrow.cdgroup, #campaignView .cdsheet.shots .cdrow.cdgroup { grid-template-columns: 1fr auto; }
#campaignView .cdsheet.team .scell.person { display: flex; gap: 10px; align-items: center; min-width: 0; }
#campaignView .cdsheet.team .scell.status { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
#campaignView .cdsheet.team .scell input { width: 100%; }
@media (max-width: 759px) {
  /* wide sheets scroll sideways on phone instead of crushing columns. */
  #campaignView .cdsheet { overflow-x: auto; }
  #campaignView .cdsheet.shots .cdrow { min-width: 470px; }
  #campaignView .cdsheet.team .cdrow { min-width: 430px; }
  #campaignView .cdsheet.cuts .cdrow { min-width: 420px; }
  #campaignView .cdsheet.run .cdrow { min-width: 400px; }
}
/* shot editor: one small form per shot, fields stacked, remove at the
   bottom in red like the campaign delete. */
#campaignView .cdshotedit { border: 1px solid #e5e2df; border-radius: 0; padding: 12px; margin-bottom: 12px; }
#campaignView .cdshotedit label { display: block; font-family: var(--cp-sans); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: #737373; margin-bottom: 10px; }
#campaignView .cdshotedit input, #campaignView .cdshotedit textarea { display: block; width: 100%; margin-top: 4px; border: none; border-bottom: 1px solid var(--cp-dash); border-radius: 0; background: transparent; padding: 6px 0; font-family: var(--cp-sans); font-size: 14px; color: var(--cp-ink); outline: none; box-sizing: border-box; }
#campaignView .cdshotedit textarea { resize: vertical; line-height: 1.5; }
#campaignView .cdshotremove { border: none; background: transparent; border-radius: 0; font-family: var(--cp-sans); font-size: 13px; color: #b3261e; text-decoration: underline; text-underline-offset: 3px; padding: 4px 0; cursor: pointer; }
#campaignView .cdaddshot { border: none; background: transparent; border-radius: 0; font-family: var(--cp-sans); font-size: 14px; color: var(--cp-ink); text-decoration: underline; text-underline-offset: 3px; padding: 6px 0; cursor: pointer; margin-bottom: 22px; }

/* ---- call sheet: sans, small-caps labels, dashed cards ---- */
#callSheet .csheet { max-width: 575px; padding: 28px 20px 90px; }
#callSheet .cstop { flex-wrap: wrap; gap: 4px 16px; }
#callSheet .cstop button {
  font-family: var(--cp-sans);
  font-size: 14px;
  white-space: nowrap;
}
#callSheet .csheet h1 { font-family: var(--cp-sans); font-size: 30px; font-weight: 700; }
#callSheet .csmeta { font-family: var(--cp-sans); font-size: 15px; line-height: 1.7; }
#callSheet .cssect { color: var(--cp-mute); }
#callSheet .cscard {
  border: 1px dashed var(--cp-dash);
  border-radius: 0;
  padding: 16px;
}
#callSheet .cscard .csnm { font-family: var(--cp-sans); }
#callSheet .cscard .csst {
  border: none;
  padding: 0;
  font-family: var(--cp-sans);
  background: transparent;
  color: var(--cp-mute);
}
#callSheet .cscard .csst.confirmed { background: transparent; color: var(--cp-green); }
#callSheet .csboard img { border-radius: 0; }
#callSheet .csnotes { font-family: var(--cp-sans); font-size: 15px; line-height: 1.7; }
/* brief (the export): the campaign as a document. Same sans, same
   hairlines, wider than the call sheet so the shot list reads. */
#callSheet .brief { max-width: 640px; padding: 28px 20px 90px; }
#callSheet .brief h1 { font-family: var(--cp-sans); font-size: 30px; font-weight: 700; }
#callSheet .brief .bstep { font-family: var(--cp-sans); font-size: 15px; font-weight: 700; color: var(--cp-ink); margin: 34px 0 4px; padding-top: 18px; border-top: 1px solid #e5e2df; }
#callSheet .brief .btext { font-family: var(--cp-sans); font-size: 15px; line-height: 1.7; color: var(--cp-ink); margin: 8px 0 22px; white-space: pre-wrap; }
#callSheet .brief .bteam { margin: 8px 0 22px; }
#callSheet .brief .bperson { font-family: var(--cp-sans); font-size: 15px; line-height: 1.6; color: var(--cp-ink); padding: 6px 0; border-bottom: 1px solid #f2f0ef; }
#callSheet .brief .blist { font-family: var(--cp-sans); font-size: 15px; line-height: 1.7; color: var(--cp-ink); margin: 8px 0 22px; padding-left: 18px; }
#callSheet .brief .blist li { margin-bottom: 2px; }
#callSheet .brief .bcosts { font-family: var(--cp-sans); font-size: 15px; margin: 8px 0 22px; max-width: 420px; }
#callSheet .brief .bcost { display: flex; justify-content: space-between; gap: 16px; padding: 4px 0; border-bottom: 1px solid #f2f0ef; }
#callSheet .brief .bcost.total { font-weight: 700; border-bottom: none; border-top: 1px solid var(--cp-dash); margin-top: 4px; padding-top: 8px; }
#callSheet .brief .bboard { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 22px; }
#callSheet .brief .bboard img { width: 120px; height: 120px; object-fit: cover; }
#callSheet .brief .bshots { margin: 8px 0 22px; }
#callSheet .brief .bday { font-family: var(--cp-sans); font-size: 13px; font-weight: 700; color: var(--cp-mute); margin: 14px 0 6px; }
#callSheet .brief .bshot { display: flex; gap: 12px; padding: 10px 0; border-bottom: 1px solid #f2f0ef; }
#callSheet .brief .bshotnum { font-family: var(--cp-sans); font-size: 15px; font-weight: 700; flex: none; width: 20px; }
#callSheet .brief .bshotconcept { font-family: var(--cp-sans); font-size: 15px; line-height: 1.6; }
#callSheet .brief .bshotmeta { font-family: var(--cp-sans); font-size: 13px; color: #737373; margin-top: 2px; }
#callSheet .brief .bshotsample { display: block; max-width: 220px; margin-top: 8px; }
#callSheet .brief .bshotnotes { font-family: var(--cp-sans); font-size: 13px; color: #737373; margin-top: 4px; }

/* ---- person overlay: sans chrome, small-caps labels, text links ---- */
#workOverlay .sheet { border-radius: 0; font-family: var(--cp-sans); }
#workOverlay h2 { font-family: var(--cp-sans); font-weight: 400; }
#workOverlay .sub, #workOverlay .bio {
  font-family: var(--cp-sans);
  font-size: 15px;
  line-height: 1.7;
}
#workOverlay .contact a { font-family: var(--cp-sans); }
#workOverlay .incamps .campchip {
  border: none;
  background: transparent;
  border-radius: 0;
  padding: 0;
  font-family: var(--cp-sans);
  font-size: 13px;
  text-decoration: none;
}
#workOverlay .incamps .campchip:hover { text-decoration: underline; }
#workOverlay .addcamp .aclabel { font-family: var(--cp-sans); }
#workOverlay .addcamp .acroles button {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 13px;
  text-decoration: none;
  padding: 0;
}
#workOverlay .addcamp .acroles button:hover { text-decoration: underline; }
#workOverlay .addcamp .acroles button.done {
  background: transparent;
  color: var(--cp-green);
  border: none;
}

/* ---- picker / collections / onboarding: sans, no pills ---- */
#picker .sheet { border-radius: 0; font-family: var(--cp-sans); }
#picker h4 { font-family: var(--cp-sans); font-weight: 700; }
#picker .opt { font-family: var(--cp-sans); }
#picker .newrow input {
  border: none;
  border-bottom: 1px solid var(--cp-dash);
  border-radius: 0;
  background: transparent;
  font-family: var(--cp-sans);
  font-size: 14px;
}
#picker .newrow button {
  background: transparent;
  color: var(--cp-ink);
  border: none;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 13px;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 9px 0;
}
#onboard { font-family: var(--cp-sans); }
#onboard h1 { font-family: var(--cp-sans); font-weight: 700; }
#onboard p { font-family: var(--cp-sans); font-size: 18px; line-height: 1.6; }
#onboard .onpaths button {
  border: 1px dashed var(--cp-dash);
  border-radius: 0;
  background: transparent;
}
#onboard .onpaths b { font-family: var(--cp-sans); }
#onboard .onpaths span { font-family: var(--cp-sans); }
#onboard .onskip { font-family: var(--cp-sans); text-decoration: underline; }

/* ---- phone: keep the slim bar to one scrolling row; the title stays
   28px, one size everywhere, so phone and desktop read the same ---- */
@media (max-width: 759px) {
  #discoverBar { padding: 10px 16px 8px; }
  #campaignView .campdetail { padding: 16px 16px 70px; }
  #campaignView .cdstages button { font-size: 14px; }
  #campaignView .cdstages { gap: 4px; }
  #campaignsView .cgsheet { padding: 16px 16px 70px; }
  #campaignsView .cgsheet h1 { font-size: 28px; }
  #callSheet .csheet { padding: 18px 16px 70px; }
  /* board import: stack the input above the link on phone, side by side
     it squeezes the input and its placeholder truncates mid-word. The
     message row keeps its auto basis (100% would blow the column's height). */
  #campaignView .cdimport { flex-direction: column; align-items: stretch; gap: 6px; }
  #campaignView .cdimport input { flex: none; min-width: 0; width: 100%; }
  #campaignView .cdimportmsg { flex-basis: auto; }
}

/* ---- style unification (Nov 5 2026), the gaps compend.css did not
   cover yet. Same system everywhere: sharp (border-radius 0), solid
   (no rgba, no opacity, no blur, no shadow, no glow), sans, black /
   white / grey + the green ✳ only. These rules load after the base
   stylesheet, so equal-specificity overrides win. ---- */

/* page + network background: flat white, no mist gradient, no fog veils */
body { background: #fff; }
.fog { display: none; }
#loading { background: #fff; }
#loading .dot { width: 10px; height: 10px; border-radius: 0; background: #333; animation: none; }

/* ---- network chrome: sans, solid, sharp ---- */
.ui { font-family: var(--cp-sans); }
.ui input[type="search"] { border-bottom: 1px solid #999; color: #333; }
.ui input[type="search"]::placeholder { color: #808080; }
.ui input[type="search"]:focus { border-bottom-color: #333; }
.ui button, .ui select { color: #555; }
.ui button:hover, .ui select:hover { color: #0d0d0d; }
.ui .count { color: #737373; }
.ui .types { color: #555; }
.ui .types:hover { color: #0d0d0d; }
.ui .wordmark { color: #555; }
#legend { background: #fff; backdrop-filter: none; border: 1px solid #999; color: #555; font-family: "Inter", -apple-system, sans-sans; }
#legend .sw { width: 8px; height: 8px; border-radius: 0; opacity: 1; }
#legend .row .n { color: #999; }
#panel { background: #fff; backdrop-filter: none; border-left: 1px solid #999; font-family: var(--cp-sans); }
#panel .avatar { border-radius: 50%; aspect-ratio: 1/1; object-fit: cover; opacity: 1; }
#panel .handle, #panel .handle a { color: #555; }
#panel .bio { color: #333; }
#panel .meta, #panel .meta a { color: #555; }
#panel h3 { color: #737373; border-top: 1px solid #999; }
#panel .addBtn { border-radius: 0; }
.connitem { border-bottom: 1px solid #e5e2df; }
.connitem:hover { background: #f2f0ef; }
.connitem img { border-radius: 50%; aspect-ratio: 1/1; object-fit: cover; opacity: 1; }
.connitem .hd { color: #555; }
.connitem .bb { color: #555; }
.tag { color: #555; border: 1px solid #999; }
#closePanel { color: #555; }
#closePanelBottom { background: #fff; backdrop-filter: none; border-top: 1px solid #999; color: #555; }

/* ---- wall: sharp square tiles, solid save button, square role labels ---- */
.workitem img { border-radius: 0; }
.workitem .save { background: #fff; border: 1px solid #e5e2df; border-radius: 0; opacity: 1; box-shadow: none; }
.workitem .rolelabels span { background: #0d0d0d; border-radius: 0; }
.workitem .credits .face { border-radius: 50%; aspect-ratio: 1/1; object-fit: cover; }

/* search is off for now (owner, Nov 5): the inputs stay in the DOM and the
   search logic in app.js stays wired, so restoring it is just deleting
   this rule. display:none takes them out of layout and tab order. */
#discoverBar #dq, .ui #q { display: none !important; }

/* ---- overlays / pickers: solid scrims, circular faces, square thumbs ---- */
#workOverlay { background: #fff; }

/* ---- campaign + call-sheet faces: circles, solid initials ---- */
/* the card roster shows everybody, one line, right aligned. Faces
   are 20px and overlap by half, so 12 fit in one row on a 390px
   phone alongside the footer text, and the row never wraps. */
.ccard .ccface { position: relative; width: 20px; height: 20px; border-radius: 50%; aspect-ratio: 1/1; background: #f2f0ef; overflow: hidden; flex: none; }
.ccard .ccface .ini { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 8px; font-weight: 700; color: #555; }
.ccard .ccface img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ccard .ccface + .ccface { margin-left: -10px; }
/* ---- campaign + call-sheet faces: circles, solid initials. The size,
   overflow, and cover-fit live here too (same values as the inline
   rules), so the circle holds in the one canonical stylesheet even if
   the inline block is ever trimmed. ---- */
.slotperson .sface { position: relative; width: 36px; height: 36px; border-radius: 50%; aspect-ratio: 1/1; background: #f2f0ef; overflow: hidden; flex: none; }
.slotperson .sface .ini { color: #555; }
.slotperson .sface img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.csheet .cscard .csface { position: relative; width: 56px; height: 56px; border-radius: 50%; aspect-ratio: 1/1; background: #f2f0ef; overflow: hidden; margin-bottom: 10px; }
.csheet .cscard .csface .ini { color: #555; }
.csheet .cscard .csface img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* ---- person overlay: a profile-pic fallback is never a big photo.
   The source is 150px (some are circular crops baked in), blowing it
   up to the full pane is a giant blurry face. It shows at its native
   150px, centered, with a caption saying what it is. ---- */
#workOverlay .pane.picfb { flex-direction: column; justify-content: center; align-items: center; }
#workOverlay .pane.picfb img.big { flex: none; border-radius: 50%; aspect-ratio: 1/1; width: 150px; height: 150px; min-height: 0; max-height: 150px; object-fit: cover; cursor: default; }
#workOverlay .pane .picfbcap { display: none; font-family: var(--cp-sans); font-size: 13px; color: var(--cp-mute); text-align: center; }
#workOverlay .pane.picfb .picfbcap { display: block; }

/* ---- thumb-zone close (phone, Nov 5 2026), every dismiss control
   becomes a solid black square at the bottom-right, fixed so it never
   scrolls away. The thing you tap to get out of a view sits where your
   right thumb rests, not at the top of the screen. Desktop is untouched:
   everything here lives inside the 759px media query. The labels are
   hidden visually only (font-size 0 + a "×" from ::after), the button's
   real text stays in the DOM, so screen readers still announce it.
   The person overlay is EXCLUDED (Rubin cut, Nov 6): its close is one
   small plain ×, bottom-right, and its save is a word in the actions
   row, never black squares. ---- */
@media (max-width: 759px) {
  /* the person panel's top close is gone on phone, the bottom close is
     the only one now. */
  #panel #closePanel { display: none; }
  /* the top rows are actions-only now (no back buttons), so they stay
     right-aligned instead of sliding left. */
  #campaignView .cdtop, #callSheet .cstop { justify-content: flex-end; }
  /* one shared thumb-zone close. Double-ID selectors so these win over
     the base + compend rules that style the same buttons in place. */
  #panel #closePanelBottom,
  #callSheet #csBack,
  #onboard #onSkip {
    position: fixed;
    /* the overlay back button carries top/left from the base rule, both
       must be cleared or they beat bottom/right on a fixed element. */
    top: auto;
    left: auto;
    bottom: 16px;
    right: 16px;
    z-index: 60;
    width: 48px;
    height: 48px;
    min-width: 48px;
    min-height: 48px;
    margin: 0;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #0d0d0d;
    color: #fff;
    border: none;
    border-radius: 0;
    font-size: 0;
    line-height: 1;
    letter-spacing: 0;
    text-transform: none;
    text-decoration: none;
    cursor: pointer;
  }
  #panel #closePanelBottom::after,
  #callSheet #csBack::after,
  #onboard #onSkip::after {
    content: "×";
    font-family: var(--cp-sans);
    font-size: 28px;
    line-height: 1;
    color: #fff;
  }
  /* the fixed close leaves the flow, so the scrolling panels need bottom
     padding to keep their last content clear of it. The campaign sheets
     already carry 70px of bottom padding on phone. */
  #panel { padding-bottom: 80px; }
}

/* ---- compact "cd" header + bottom filter bar (phone, Nov 5 2026) ----
   The full "creative directory" wordmark is gone on phone, the header is
   one compact row: "✳ cd" on the left, the nav next to it. The short form
   lives in the markup (.wm-short) so the header never reflows: desktop
   shows the full wordmark, phone shows "cd". The filter controls (role
   tabs + location + forme-leads + saved row) move to a fixed bar at the
   bottom of the screen in work, thumb-reachable; placeFilterBar() in
   app.js moves the nodes (not clones) so their wiring survives. ---- */
/* the short mark is hidden on desktop; the full wordmark shows there. */
#discoverBar .wordmark .wm-short { display: none; }
@media (max-width: 759px) {
  /* compact header: one row, "✳ cd" + nav. The full wordmark never
     shows on phone, no second line, no scroll trick, so the header
     cannot jump or reflow as you scroll. */
  #discoverBar { padding: 8px 16px 6px; }
  #discoverBar .bar { gap: 12px; }
  #discoverBar .wordmark { flex: none; }
  #discoverBar .wordmark .wm-full { display: none; }
  #discoverBar .wordmark .wm-short { display: inline; letter-spacing: .1em; }
  /* the nav takes the rest of the row and scrolls sideways if it ever
     outgrows it, instead of wrapping or clipping. */
  #discoverBar .views { flex: 1 1 auto; min-width: 0; overflow-x: auto; scrollbar-width: none; }
  #discoverBar .views::-webkit-scrollbar { display: none; }
  #discoverBar .views button { padding: 8px 4px; font-size: 13px; }

  /* ---- bottom filter bar: fixed at the very bottom of the screen in
     work, above the wall content, below every overlay/panel (z 20 vs
     overlay 35, picker 40, onboard 60) so it sits behind them when one
     is open and never covers a close button. ---- */
  #filterBar {
    position: fixed;
    bottom: 0; left: 0; right: 0;
    z-index: 20;
    background: #fff;
    border-top: 1px solid #e5e2df;
    padding-bottom: max(8px, env(safe-area-inset-bottom));
  }
  #filterBar #roleTabs { padding: 8px 16px 10px; }
  /* the wall's scroll container gets bottom clearance so its last row
     and the show-more button scroll clear of the bar (tabs only now). */
  #discoverView { padding-bottom: 90px; }

  /* ---- thumb-zone text clearance: the overlay close × sits fixed at
     the bottom-right on phone, and the wofoot bottom padding (64px)
     already clears it. These containers end before the campaigns
     close button's x-range instead, so their text wraps clear. ---- */
  #campaignsView .cgfoot { padding-right: 64px; }
  #campaignView .cdmeta { padding-right: 64px; }
  #campaignView .slotperson { padding-right: 64px; }
  /* the sheets get a little more bottom room so their last content
     clears the button when scrolled to the end. */
  #campaignsView .cgsheet, #campaignView .campdetail { padding-bottom: 90px; }

  /* campaigns top bar: the same compact "cd" header as the work view on
     phone, one row, "✳ cd" on the left, the nav scrolling beside it, the
     full wordmark gone. (Overrides the older phone rule below that dropped
     the nav to its own line.) Desktop keeps the full wordmark. */
  .cptopbar { flex-wrap: nowrap; padding: 8px 16px 6px; }
  .cptopbar .cpwordmark .cp-full { display: none; }
  .cptopbar .cpwordmark .cp-short { display: inline; letter-spacing: .1em; }
  .cptopbar .cpnav { flex: 1 1 auto; margin-left: auto; overflow-x: auto; }
  /* campaigns grid: a little tighter on phone so the footer lands fully
     in view at rest with one or two campaigns, even in a wide font, the
     one-row header above already saves ~30px, this saves ~25px more. */
  #campaignsView .cgsheet { padding-top: 12px; }
  #campaignsView .cgsheet h1 { margin: 12px 0 8px; }
  #campaignsView .cgsub { margin: 0; }
  #campaignsView .cggrid { margin-top: 20px; }
}

/* ---- production (Nov 5): voting, responsibilities, cut list, run
   sheet, post page, visual shot view. Same system: sans, sharp,
   black/white/grey, green only for a confirmed/voted state. ---- */
#campaignView .cdshot { cursor: pointer; }
#campaignView .slotperson .cdvotes { font-family: var(--cp-sans); font-size: 12px; color: #737373; }
#campaignView .slotperson .cdvote { display: block; border: none; background: transparent; border-radius: 0; font-family: var(--cp-sans); font-size: 12px; color: var(--cp-ink); text-decoration: underline; text-underline-offset: 3px; padding: 2px 0; cursor: pointer; text-align: left; }
#campaignView .slotperson .cdresp, #campaignView .slotperson .cdcall { display: block; width: 100%; border: none; border-bottom: 1px solid var(--cp-dash); border-radius: 0; background: transparent; padding: 4px 0; font-family: var(--cp-sans); font-size: 12px; color: var(--cp-ink); outline: none; box-sizing: border-box; }
#campaignView .cdcutremove { border: none; background: transparent; color: #b3261e; font-size: 15px; padding: 0 4px; cursor: pointer; margin-left: auto; }
#campaignView .cdcutadd { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 22px; }
#campaignView .cdcutadd input { border: none; border-bottom: 1px solid var(--cp-dash); border-radius: 0; background: transparent; padding: 6px 0; font-family: var(--cp-sans); font-size: 14px; color: var(--cp-ink); outline: none; }
#campaignView .cdcutadd button { border: none; background: transparent; border-radius: 0; font-family: var(--cp-sans); font-size: 14px; color: var(--cp-ink); text-decoration: underline; text-underline-offset: 3px; padding: 6px 0; cursor: pointer; }
/* cut role links: the role for the next cut, picked from text links. */
#campaignView .cdcutroles {
  font-family: var(--cp-sans);
  font-size: 14px;
  color: #555;
  margin: 0 0 22px;
}
#campaignView .cdcutrole {
  border: none;
  background: transparent;
  border-radius: 0;
  font-family: var(--cp-sans);
  font-size: 14px;
  color: #555;
  padding: 0;
  cursor: pointer;
}
#campaignView .cdcutrole.on {
  color: var(--cp-ink);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}
#campaignView .cdrun { margin: 8px 0 22px; }
#campaignView .cdrunrow, #callSheet .cdrunrow { display: flex; flex-wrap: wrap; gap: 4px 12px; padding: 6px 0; border-bottom: 1px solid #f2f0ef; font-family: var(--cp-sans); font-size: 14px; }
#campaignView .cdruntime, #callSheet .cdruntime { font-weight: 700; flex: none; width: 72px; }
#campaignView .cdrunitem, #callSheet .cdrunitem { flex: 1 1 160px; }
#campaignView .cdrunnote, #callSheet .cdrunnote { color: #737373; font-size: 13px; }
#callSheet .csresp, #callSheet .cscall { font-family: var(--cp-sans); font-size: 13px; color: #555; }
#campaignView .cdowner .scall { font-family: var(--cp-sans); font-size: 12px; color: #737373; }
/* collection cover: a 2x2 grid of work, sharp squares, never a face. */
.collCover { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
.collCover img { width: 100%; height: 100%; border-radius: 0; object-fit: cover; display: block; }

/* ---- collections grid: a full page of collection cards, like campaigns.
   One card per collection: the 2x2 work cover, name, count. Tap a card
   to open its wall. ---- */
#collectionsView .colsheet { max-width: 960px; margin: 0 auto; padding: 22px 32px 90px; }
#collectionsView .colsheet h1 { font-family: var(--cp-sans); font-size: 26px; font-weight: 700; margin: 10px 0 6px; }
#collectionsView .colnew { display: flex; gap: 12px; align-items: baseline; max-width: 420px; margin: 14px 0 24px; }
#collectionsView .colnew input { flex: 1; min-width: 0; border: none; border-bottom: 1px solid var(--cp-dash); border-radius: 0; background: transparent; font-family: var(--cp-sans); font-size: 14px; padding: 9px 0; color: var(--cp-ink); }
#collectionsView .colnew button { background: transparent; color: var(--cp-ink); border: none; border-radius: 0; font-family: var(--cp-sans); font-size: 14px; font-weight: 700; text-decoration: underline; text-underline-offset: 3px; padding: 6px 0; cursor: pointer; white-space: nowrap; }
#collectionsView .colgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
#collectionsView .colcard { border: 1px solid #e5e2df; border-radius: 0; background: #fff; cursor: pointer; overflow: hidden; }
#collectionsView .colcard:hover { border-color: #0d0d0d; }
#collectionsView .colcard .collCover { width: 100%; aspect-ratio: 1 / 1; }
#collectionsView .colcard .cdot { display: block; width: 100%; aspect-ratio: 1 / 1; }
#collectionsView .colcard .colbody { display: flex; align-items: flex-start; gap: 8px; padding: 10px 12px 12px; }
#collectionsView .colcard .nm { font-family: var(--cp-sans); font-size: 15px; font-weight: 700; line-height: 1.3; }
#collectionsView .colcard .ct { font-family: var(--cp-sans); font-size: 12px; color: var(--cp-mute); margin-top: 2px; }
#collectionsView .colcard .del { margin-left: auto; background: transparent; border: none; font-family: var(--cp-sans); font-size: 16px; color: #808080; cursor: pointer; padding: 0 2px; flex: none; }
@media (max-width: 759px) {
  #collectionsView .colsheet { padding: 16px 16px 70px; }
  #collectionsView .colsheet h1 { font-size: 22px; }
  #collectionsView .colgrid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
}
/* quiet credit line under a board photo: who made it, linked. */
.workcredit { font-family: var(--cp-sans); font-size: 12px; color: #737373; margin-top: 4px; }
.workcredit a { color: inherit; }
#campaignView .cdbcredit { display: block; font-family: var(--cp-sans); font-size: 11px; color: #737373; margin-top: 2px; }
#campaignView .cdbcredit a { color: inherit; }

/* the moodboard is a collection from the same source as the wall, so it
   renders as the wall: true masonry, two across in the narrow detail
   column, same tile spacing as the phone wall. */
#campaignView .cdwall { column-count: 2; column-gap: 16px; }
/* the moodboard wall sits inside the content frame, padded inside its border. */
#campaignView .cdwall, #campaignView .cdboard { padding: 16px 16px 0; box-sizing: border-box; }
/* the moodboard wall is a framed board: the tab bar above is its top
   edge, so the wall carries the other three sides and the active tab
   connects straight into it. */
#campaignView .cdwall { border: 1px solid #0d0d0d; border-top: none; }
/* phone: the tab bar is too narrow for the tab plus the source link
   plus the add button, so the meta drops to its own row below the
   tabs and the wall regains its top border, keeping the frame whole. */
@media (max-width: 759px) {
  #campaignView .cdmoodtabs { flex-wrap: wrap; }
  #campaignView .cdmoodtabs .cdmoodmeta { margin-left: 0; width: 100%; padding: 8px 0; }
  #campaignView .cdwall { border-top: 1px solid #0d0d0d; }
}
@media (min-width: 1000px) { #campaignView .cdwall { column-count: 3; } }
@media (min-width: 1400px) { #campaignView .cdwall { column-count: 4; } }

/* ---- desktop workspace: 1000px and up, the detail uses the full
   width in two and three column grids, not one narrow column. Phone
   stays single column. ---- */
@media (min-width: 1000px) {
  #campaignView .campdetail { padding: 28px 32px 90px; }
  /* text fields and body text stop at a readable measure, left aligned
     on the frame like everything else. */
  #campaignView .cdbrief textarea, #campaignView .cdtext { max-width: 72ch; }
  #campaignView .cdbrief input { max-width: 420px; }
  /* page grids: two columns for brief, shoot, styling. */
  #campaignView .wkbriefgrid,
  #campaignView .wkshootgrid,
  #campaignView .wkstylegrid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 48px; align-items: start; margin-top: 24px; }
  #campaignView .wkbriefcol > :first-child,
  #campaignView .wkshootcol > :first-child,
  #campaignView .wkstylecol > :first-child { margin-top: 0; }
  /* roomier sheets on desktop. */
  #campaignView .cdsheet .cdrow { padding: 10px 14px; }
  #campaignView .cdsheet .cdhead { padding: 8px 14px; }
}
/* brief images: full column width, each at its own height. The
   aspect-ratio reserves the box from the start, so the brief reads
   as grey skeleton blocks while the images load instead of jumping
   when each one arrives. */
#campaignView .wkbriefimg { width: 100%; height: auto; display: block; margin: 0 0 12px; aspect-ratio: 1.4; background: #e5e2df; }
@media (min-width: 1000px) and (max-width: 1399px) {
  #campaignView .wkstylecol .wblooks { grid-template-columns: minmax(0, 1fr); }
}
