:root {
  --ink: #1a1a1a; --paper: #f7f7f5; --panel: #eeeeea; --accent: #b9d432; --accent-dim: #eef5cc;
  --ok: #2f6b4f; --ok-bg: #e3efe7; --bad: #a13d2b; --bad-bg: #f6e4df; --line: #dcdcd6;
  /* Amber "needs attention, nothing is broken" pair -- var(--warn)/var(--warn-bg)
     were already being used (the Design Studio lock banner, the QA row) but
     had never actually been defined, so those elements silently inherited
     their colour instead of showing as warnings. */
  --warn: #8a5a1f; --warn-bg: #f6e9d2;
  --mono: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
/* Belt-and-braces against horizontal page scroll on phones: a single
   too-wide element (a nowrap badge, a fixed-width column) inside any flex
   row can otherwise push the whole document wider than the viewport, which
   reads as the page being "not contained" and side-scrolling. The real fixes
   are per-component (see .recent-job-row's mobile rules), but this stops any
   future one from silently doing the same thing. */
html { overflow-x: hidden; max-width: 100%; }
body { margin: 0; background: var(--paper); color: var(--ink); font-family: var(--sans); padding-bottom: 48px; }
header { padding: 16px 18px; border-bottom: 3px solid var(--ink); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px; }
header .titles .eyebrow { font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink); margin: 0 0 4px; }
header .titles .eyebrow a.backlink { color: var(--ink); text-decoration: none; border-bottom: 1.5px solid var(--accent); }
header .titles .eyebrow a.backlink:hover { text-decoration: underline; }
header h1 { margin: 0; font-size: 20px; font-weight: 700; letter-spacing: -0.01em; }
header a.logout { font-family: var(--mono); font-size: 11.5px; color: #8a8372; text-decoration: none; border: 1px solid var(--line); padding: 6px 10px; border-radius: 4px; }
.company-branding-logo { height: 40px; width: 40px; object-fit: contain; border: 1px solid var(--line); border-radius: 4px; background: #fff; flex-shrink: 0; }

/* ---------------------------------------------------------------------------
   Docket header (index.php only -- see Dashboard Revamp README, option 2a
   desktop / 3a mobile). Full-bleed dark strip replacing <header> + the old
   stat-grid + command-bar. Sits OUTSIDE .docket-main's max-width container on
   purpose so its dark band runs edge to edge; the grid below stays capped.
--------------------------------------------------------------------------- */
.docket-body { padding-bottom: 0; overflow-x: hidden; } /* mobile tab bar (further down) supplies its own bottom spacing instead of the default body padding; overflow-x guards against any full-bleed child (header/pipeline band) being forced wider than the viewport by its own content and dragging the whole page along with it */
.docket-header { background: #1a1a1a; color: #f7f7f5; max-width: 100vw; overflow-x: hidden; }
.docket-row1 { display: flex; align-items: stretch; border-bottom: 1px solid #333; }
.docket-identity { min-width: 230px; padding: 16px 22px; border-right: 1px solid #333; }
.docket-eyebrow { font: 400 9.5px var(--mono); letter-spacing: 0.16em; text-transform: uppercase; color: #8a8372; }
.docket-greeting { font: 700 20px var(--sans); letter-spacing: -0.01em; margin-top: 4px; }
.docket-stats { display: flex; flex: 1; }
/* On pages that don't opt into the stat cells ($showDocketStats = false),
   this empty flex child still absorbs the middle of row 1 so the actions
   stay pinned right, exactly as they are on the dashboard. */
.docket-stats-empty { border-right: 1px solid #333; }
.docket-backlink { color: #8a8372; text-decoration: none; border-bottom: 1px solid #55534c; }
.docket-backlink:hover { color: #f7f7f5; }
.docket-stat { flex: 1; padding: 16px 20px; border-right: 1px solid #333; }
/* Three of the stat cells are links to a pre-filtered board. They must not
   look like links in the usual sense -- no underline, no colour shift -- just
   respond to being hovered so it's discoverable that they do something. */
a.docket-stat { text-decoration: none; color: inherit; display: block; transition: background .14s ease; }
a.docket-stat:hover { background: #262620; }
/* Five cells rather than four now. Between the mobile breakpoint and a
   comfortable desktop width they need to give a little to avoid pushing the
   header's actions off the end. */
@media (min-width: 900px) and (max-width: 1180px) {
  .docket-stat { padding: 16px 12px; }
  .docket-stat-label { font-size: 9px; letter-spacing: 0.08em; }
  .docket-stat-value { font-size: 21px; }
}
.docket-stat-due .docket-stat-label { color: #9fb6d4; }
.docket-stat-due .docket-stat-value { color: #b9cde8; }
.docket-stat-label { font: 400 9.5px var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: #8a8372; }
.docket-stat-value { font: 700 24px var(--mono); margin-top: 3px; display: block; }
.docket-stat-value-row { display: flex; align-items: baseline; gap: 8px; margin-top: 3px; }
.docket-stat-value-row .docket-stat-value { margin-top: 0; }
.docket-stat-delta { font: 700 10px var(--sans); color: #e0a99c; }
.docket-stat-overdue { background: #2a2416; }
.docket-stat-overdue .docket-stat-label { color: #d9c07a; }
.docket-stat-overdue .docket-stat-value { color: #e8c05a; }
.docket-actions { display: flex; align-items: center; gap: 9px; padding: 0 20px; flex-shrink: 0; }
.docket-btn {
  padding: 9px 16px; border-radius: 8px; font: 700 12.5px var(--sans); cursor: pointer; white-space: nowrap;
  font-family: inherit; appearance: none; -webkit-appearance: none; box-sizing: border-box; border: none;
  transition: transform 0.08s ease;
}
.docket-btn:active { transform: scale(0.97); }
.docket-btn-primary { background: var(--accent); color: #1a1a1a; }
.docket-btn-secondary { background: transparent; border: 1.5px solid #55534c; color: #f7f7f5; }
.docket-btn-secondary:hover { background: rgba(255,255,255,0.06); }

.docket-row2 { display: flex; align-items: center; gap: 14px; padding: 11px 22px; flex-wrap: wrap; }
.docket-search { flex: 1; min-width: 220px; max-width: 560px; position: relative; }
.docket-search input {
  width: 100%; box-sizing: border-box; padding: 9px 14px 9px 32px; border: 1px solid #3a3a36; border-radius: 8px;
  background: #242422; font: 400 13px var(--sans); color: #f7f7f5;
}
.docket-search input::placeholder { color: #8a8372; }
.docket-search input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.docket-search-icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); font: 400 12px var(--mono); color: #8a8372; pointer-events: none; }
.docket-search #jobSearchResults.job-search-results-open {
  background: var(--paper); box-shadow: 0 8px 24px rgba(0,0,0,0.35);
}

.docket-chip {
  padding: 6px 12px; border-radius: 20px; border: 1px solid #3a3a36; color: #c9c6bd; cursor: pointer; white-space: nowrap;
}
.docket-chip:hover { border-color: #55534c; }
.docket-chip-active { background: #f7f7f5; color: #1a1a1a; font-weight: 700; border-color: #f7f7f5; }

.docket-right-cluster { margin-left: auto; display: flex; align-items: center; gap: 10px; font: 400 10.5px var(--mono); color: #8a8372; }
.docket-pill {
  position: relative; border: 1px solid #3a3a36; border-radius: 4px; padding: 5px 9px; color: #f7f7f5;
  text-decoration: none; cursor: pointer; background: none; font: 400 10.5px var(--mono); white-space: nowrap;
}
.docket-pill:hover { border-color: #55534c; }
.docket-actor { white-space: nowrap; }
/* Notification bell -- injected into .docket-right-cluster by common.js.
   Styled here rather than inline so it matches the dark bar; the old inline
   styles used --ink borders, which are invisible against #1a1a1a. */
.docket-bell-btn {
  background: none; border: 1px solid #3a3a36; border-radius: 4px; padding: 4px 8px;
  cursor: pointer; font-size: 14px; position: relative; line-height: 1.2; color: #f7f7f5;
}
.docket-bell-btn:hover { border-color: #55534c; }
#notifBellBadge { border: 2px solid #1a1a1a; }
/* Job Board's follow-up badge on the dark bar -- same badge/animation as
   before (.followup-btn / .followup-badge, unchanged), just needs a ring so
   it reads clearly against the dark pill instead of blending in. */
.docket-pill.followup-btn .followup-badge { border: 2px solid #1a1a1a; top: -6px; right: -6px; }

/* Pipeline band -- slim white strip between the docket header and the grid. */
.pipeline-band { background: #fff; border-bottom: 1px solid var(--line); padding: 11px 22px; display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.pipeline-band-label { font: 700 10px var(--mono); letter-spacing: 0.06em; text-transform: uppercase; color: #8a8a80; }
.pipeline-band-bar { flex: 0 0 300px; display: flex; height: 8px; border-radius: 4px; overflow: hidden; background: var(--panel); }
.pipeline-band-legend { display: flex; gap: 20px; font: 400 11.5px var(--sans); color: #5c5648; flex-wrap: wrap; }
.pipeline-band-legend-item { display: flex; align-items: center; gap: 6px; }
.pipeline-band-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }
.pipeline-band-legend-item b { font-family: var(--mono); }
.pipeline-band-revenue { margin-left: auto; font: 400 10.5px var(--mono); color: #8a8372; }
.pipeline-band-revenue b { font-size: 12px; color: #1a1a1a; font-family: var(--sans); }

/* ---------------------------------------------------------------------------
   Dashboard panels -- fixed layout (no drag/hide) replacing the old
   customizable widget grid. Needs-you-today + Proof-out sit in the wider
   left column; Pipeline + Activity in the right. Deliberately its own
   .dash-panel box style rather than reusing .widget -- .widget is shared
   with jobs.php/proof.php's sidebars and carries drag/remove affordances
   that don't apply here.
--------------------------------------------------------------------------- */
.dash-grid { display: grid; grid-template-columns: 1fr; gap: 16px; align-items: start; }
@media (min-width: 900px) {
  .dash-grid { grid-template-columns: 1.6fr 1fr; }
}
.dash-col { display: flex; flex-direction: column; gap: 16px; }

.dash-panel { background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 16px; }
.dash-panel h2 { font: 700 12px var(--mono); letter-spacing: 0.05em; text-transform: uppercase; color: #8a8a80; margin: 0; }
.dash-panel-header { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; margin-bottom: 12px; }
.dash-panel-count { font: 400 11.5px var(--sans); color: #8a8372; white-space: nowrap; }

.dash-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.dash-table th { text-align: left; font: 700 10px var(--mono); letter-spacing: 0.05em; text-transform: uppercase; color: #b3ad9c; padding: 0 10px 8px 0; border-bottom: 1px solid var(--line); }
.dash-table th.dash-col-value { text-align: right; }
.dash-table th.dash-sortable { cursor: pointer; user-select: none; }
.dash-table th.dash-sortable:hover { color: var(--ink); }
.dash-table th.dash-sortable.dash-sort-active { color: var(--ink); }
.dash-sort-arrow { display: inline-block; margin-left: 3px; font-size: 8px; width: 8px; }
.dash-table td { padding: 10px 10px 10px 0; border-bottom: 1px solid #f0efea; vertical-align: top; }
.dash-table tr:last-child td { border-bottom: none; }
.dash-table tr.dash-row-clickable { cursor: pointer; }
.dash-table tr.dash-row-clickable:hover td { background: var(--panel); }
.dash-table td.dash-col-value { text-align: right; font-family: var(--mono); white-space: nowrap; }
.dash-flag { font: 700 10px var(--sans); letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap; }
.dash-flag-overdue { color: var(--bad); }
/* "Marks" means the client asked for changes -- everywhere else in the app that
   wears the bad/red treatment (.status-changes_requested, the board's own
   changes-requested pill), but here it was rendering in the success green, so
   the one row on the dashboard that means "the client is unhappy" read as good
   news. Green now belongs to the row it was always meant for: an approval. */
.dash-flag-marks { color: var(--bad); }
.dash-flag-approved { color: var(--ok); }
.dash-flag-apply_changes { color: var(--warn); }
.dash-flag-no_reply { color: #8a5a1f; }
.dash-flag-due_today { color: #8a5a1f; }
.dash-flag-request { color: #2f5289; }
.dash-flag-to_bill { color: #5b3a8a; }
.dash-job-title { font-weight: 700; color: var(--ink); }
.dash-job-sub { color: #8a8372; font-size: 11.5px; margin-top: 2px; }
.dash-panel-empty { color: #8a8372; font-size: 12.5px; padding: 6px 0; }
.dash-panel-footer { display: flex; justify-content: space-between; align-items: center; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); font-size: 12px; color: #8a8372; }
.dash-panel-footer a { color: var(--ink); font-weight: 600; text-decoration: none; border-bottom: 2px solid var(--accent); }

.dash-pipeline-bar { display: flex; height: 10px; border-radius: 5px; overflow: hidden; background: var(--panel); margin-bottom: 14px; }
.dash-pipeline-legend { display: flex; flex-direction: column; gap: 9px; }
.dash-pipeline-legend-row { display: flex; align-items: center; gap: 8px; font-size: 12.5px; }
.dash-pipeline-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.dash-pipeline-label { flex: 1; color: var(--ink); }
.dash-pipeline-figures { font-family: var(--mono); font-size: 12px; color: #5c5648; white-space: nowrap; }
.dash-pipeline-figures b { color: var(--ink); font-family: var(--sans); }

.dash-activity-feed { display: flex; flex-direction: column; gap: 10px; }
.dash-activity-item { display: flex; gap: 10px; font-size: 12.5px; }
.dash-activity-time { font-family: var(--mono); color: #b3ad9c; flex-shrink: 0; width: 42px; }
.dash-activity-text { color: var(--ink); }

.dash-secondary-grid { display: grid; grid-template-columns: 1fr; gap: 16px; margin-top: 16px; }
@media (min-width: 900px) {
  .dash-secondary-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 899px) {
  .dash-table { font-size: 12px; }
  .dash-table th:nth-child(3), .dash-table td:nth-child(3) { display: none; } /* Company column -- tight on mobile, Job + When carry enough context */
}

/* Main content area under the header/band -- same width tiers as the rest of
   the app's <main>, just under a different class since .docket-main sits
   below full-bleed elements rather than being the very first thing on the
   page. */
.docket-main { padding: 18px; max-width: 640px; margin: 0 auto; }
@media (min-width: 900px) { .docket-main { max-width: 1100px; } }
@media (min-width: 1300px) { .docket-main { max-width: 1600px; padding: 24px 40px; } }

/* Three-column widget grid (README 2a 1.3) -- 1.55fr weight on Recent Jobs
   so it's the widest thing on the page. Below 1300px there isn't room for
   three genuinely useful columns, so it steps down to two (Notes/Tools/
   Clock/Weather drop under Recent Jobs) before finally going single-column
   under 900px, where index.php's normal mobile layout (3a) takes over via
   the media queries further down. */
/* 2-column layout (was 3) -- Recent Jobs alone on the left, everything else
   (Deadlines, Calendar, Companies Notes, Tools, Clock/Weather, Today) stacked
   on the right in index.php. The old 3-column split put one widget against
   a 4-widget stack beside a 2-widget column, which is what read as uneven --
   one wide primary column plus one consistently-ordered secondary column
   reads cleaner at every width. */
.docket-grid { display: grid; grid-template-columns: 1fr; gap: 16px; align-items: start; }
@media (min-width: 900px) {
  .docket-grid { grid-template-columns: 1.6fr 1fr; }
}
.docket-col { display: flex; flex-direction: column; gap: 16px; }

/* Recent Jobs card -- edge-to-edge rows, no card padding (padding lives on
   the header row and each job row individually instead). */
.docket-recent-jobs { padding: 0 !important; overflow: hidden; }
.docket-card-header { display: flex; justify-content: space-between; align-items: center; padding: 14px 52px 12px 16px; border-bottom: 1px solid var(--line); }
.docket-card-title { font: 700 12px var(--mono); letter-spacing: 0.05em; text-transform: uppercase; color: #8a8a80; }
.docket-card-link { font: 600 11.5px var(--sans); color: var(--ink); text-decoration: none; border-bottom: 2px solid var(--accent); }
.recent-job-row { display: flex; align-items: center; gap: 12px; padding: 11px 16px; border-bottom: 1px solid #f0efea; cursor: pointer; }
.recent-job-row:last-child { border-bottom: none; }
.recent-job-row:hover { background: var(--panel); }
.recent-job-row-followup { border-left: 4px solid #c98a1f; background: #fdf6ea; }
.recent-job-row-followup:hover { background: #f9edd9; }
.recent-job-title { flex: 1; min-width: 0; }
.recent-job-desc { font: 700 13.5px var(--sans); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.recent-job-sub { font: 400 11.5px var(--sans); color: #8a8372; margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.recent-job-number { font: 400 11px var(--mono); color: #b3ad9c; flex-shrink: 0; }
.recent-job-age { font: 400 11px var(--mono); color: #8a8372; width: 56px; text-align: right; flex-shrink: 0; }

/* Deadlines widget (README 2a column 2, above Calendar) */
.deadline-row { display: flex; justify-content: space-between; align-items: center; padding: 7px 0; border-bottom: 1px solid #f0efea; font: 400 12.5px var(--sans); cursor: pointer; }
.deadline-row:last-child { border-bottom: none; }
.deadline-row:hover { color: var(--ink); }
.deadline-row-desc { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.deadline-row-pill { font: 700 10.5px var(--sans); border-radius: 20px; padding: 2px 9px; flex-shrink: 0; margin-left: 10px; }
.deadline-pill-overdue { background: var(--bad-bg); color: var(--bad); }
.deadline-pill-soon { background: #f6e8cc; color: #8a5c15; }
.deadline-pill-future { background: var(--panel); color: #6a6a5f; }

.docket-clock-weather-row { display: flex; gap: 16px; }
.docket-clock-weather-row .widget { flex: 1; padding: 14px 16px; }

/* Needs You Today -- boxed like any other widget (.widget gives the white
   bg/border/radius/padding), living inside docket-col-1 above Recent Jobs
   instead of spanning full width above the grid. */
.needs-you-today { display: block; }
.needs-you-today-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 9px; }
.needs-you-today-title { font: 700 11px var(--mono); letter-spacing: 0.06em; text-transform: uppercase; color: #8a8a80; }
.needs-you-today-count { font: 700 10px var(--sans); background: var(--bad-bg); color: var(--bad); border-radius: 20px; padding: 3px 9px; }
#needsYouTodayList { display: flex; flex-direction: column; gap: 8px; }
.needs-you-card:hover { border-color: #b3ad9c; }

/* Mobile bottom tab bar (README 3a) -- desktop-hidden. */
.docket-tabbar { display: none; }
@media (max-width: 899px) {
  .docket-tabbar {
    display: flex; position: fixed; bottom: 0; left: 0; right: 0; z-index: 15;
    border-top: 1px solid var(--line); background: #fff; padding: 9px 8px 14px;
  }
  body.docket-body { padding-bottom: 64px; } /* room for the fixed tab bar so page content isn't hidden behind it */
}
.docket-tab {
  flex: 1; text-align: center; padding: 6px 0; font: 700 10.5px var(--sans); color: #8a8372; text-decoration: none;
  border: none; background: none; cursor: pointer; font-family: inherit;
}
.docket-tab-glyph { display: block; font: 400 15px var(--mono); margin-bottom: 3px; position: relative; }
.docket-tab-active { color: var(--ink); }
.docket-tab-underline { display: block; height: 2px; width: 22px; background: var(--accent); margin: 5px auto 0; }
.docket-tab-glyph-badge { position: relative; display: inline-block; }
.docket-tab-badge {
  position: absolute; top: -5px; right: -11px; min-width: 15px; height: 15px; border-radius: 9px;
  background: var(--bad); color: #fff; font: 700 9px/15px var(--mono); text-align: center;
}

/* ---------------------------------------------------------------------------
   Mobile compression (README 3a) -- docket header row1/row2 collapse into a
   single compact block: greeting + a horizontally-scrolling stat strip
   replaces the 4-cell row, search becomes full-width, actions become two
   equal buttons, company chips and the right cluster (Job Board pill,
   Customize, actor, logout) move into the "More" drawer instead of the
   header, since there's no room for them at this width.
--------------------------------------------------------------------------- */
@media (max-width: 899px) {
  .docket-row1 { flex-direction: column; align-items: stretch; padding: 14px 16px 12px; border-bottom: none; }
  .docket-identity { min-width: 0; padding: 0; border-right: none; display: flex; justify-content: space-between; align-items: flex-start; }
  .docket-greeting { font-size: 19px; }
  .docket-stats {
    order: 2; margin-top: 12px; gap: 8px; overflow-x: auto; -webkit-overflow-scrolling: touch;
    flex: 0 0 auto; width: 100%; max-width: 100%;
  }
  .docket-stat { flex: 0 0 auto; min-width: 82px; padding: 9px 12px; border: 1px solid #3a3a36; border-radius: 8px; }
  /* On a phone the strip scrolls, so the two figures that drive today's work
     lead it: what's already late, then what lands this week. Everything else
     keeps DOM order behind them. */
  .docket-stat-overdue { order: -2; }
  .docket-stat-due { order: -1; }
  .docket-stat-value { font-size: 19px; }
  .docket-actions { order: 3; padding: 0; margin-top: 10px; gap: 9px; }
  .docket-btn { flex: 1; height: 46px; text-align: center; }

  .docket-row2 { padding: 0 16px 14px; }
  .docket-search { max-width: none; }
  /* The right cluster's ACCOUNT actions (Job Board, Log out) still need a
     home on mobile though -- they don't just vanish -- so they move into
     .docket-mobile-menu below instead of the row. */
  .docket-right-cluster { display: none; }
  .docket-mobile-menu-trigger { display: flex; }

  .pipeline-band { padding: 12px 16px; }
  .pipeline-band-bar { flex: 1 1 auto; }

  .docket-main { padding: 16px; }

  /* Recent Jobs rows on mobile (README 3a: "4 rows, no age column, badge
     right"). The desktop row packs four rigid items -- title, job number,
     status badge (white-space:nowrap, flex-shrink:0) and a 56px age column
     -- whose combined minimum width comfortably exceeds a phone screen,
     which was forcing the whole PAGE wider than the viewport and causing
     side-scrolling. Dropping the age + job-number columns here (both are
     still visible in the job modal) leaves the title free to shrink and the
     badge to sit flush right, so the row fits any width. */
  .recent-job-age, .recent-job-number { display: none; }
  .recent-job-row { gap: 10px; padding: 12px 13px; }
  .recent-job-desc { font-size: 14px; }
}

/* Mobile-only account menu trigger (44x44, top-right of the identity row per
   the 3a prototype) -- opens a small action sheet with the items that were
   in the desktop header's right cluster (Job Board, Customize, Log out).
   Hidden on desktop; that trigger button doesn't exist in the DOM there at
   all costs-wise, it's just CSS-hidden, since it's cheap and keeps the
   markup simpler than conditionally rendering it server-side. */
.docket-mobile-menu-trigger {
  display: none; position: relative; width: 44px; height: 44px; border: 1px solid #3a3a36; border-radius: 8px;
  align-items: center; justify-content: center; font: 400 15px var(--mono); color: #f7f7f5; background: none; cursor: pointer; flex-shrink: 0;
}
.docket-mobile-menu-trigger .followup-badge { border: 2px solid #1a1a1a; }
.docket-mobile-menu {
  display: none; position: fixed; inset: 0; z-index: 40; background: rgba(0,0,0,0.4);
}
.docket-mobile-menu.open { display: block; }
.docket-mobile-menu-sheet {
  position: absolute; bottom: 0; left: 0; right: 0; background: #fff; border-radius: 14px 14px 0 0;
  padding: 10px 0 max(10px, env(safe-area-inset-bottom)); max-height: 70vh; overflow-y: auto;
}
.docket-mobile-menu-item {
  display: flex; align-items: center; gap: 10px; padding: 14px 20px; font: 600 14px var(--sans); color: var(--ink);
  text-decoration: none; cursor: pointer; background: none; border: none; width: 100%; text-align: left; box-sizing: border-box;
}
.docket-mobile-menu-item:active { background: var(--panel); }
.docket-mobile-menu-close { text-align: center; padding: 12px; font: 600 13px var(--sans); color: #8a8372; }


.statusbar { padding: 8px 18px; background: var(--ink); color: var(--paper); font-family: var(--mono); font-size: 11px; min-height: 16px; }
.statusbar.ok { background: #223324; }
.statusbar.err { background: #3d2320; }

nav.tabs { display: flex; border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 5; background: var(--paper); }
nav.tabs button { flex: 1; padding: 12px 6px; border: none; background: none; font-family: var(--mono); font-size: 11.5px;
  color: #8a8372; border-bottom: 3px solid transparent; cursor: pointer; }
nav.tabs button.active { color: var(--ink); border-bottom-color: var(--accent); font-weight: 700; }

main { padding: 18px; max-width: 640px; margin: 0 auto; }
/* The 640px cap is right for phones, but was applying to every screen size --
   on a desktop monitor that left most of the window empty. Pages that need a
   specific width (e.g. board.php's Kanban view) already override this with
   an inline style, which still wins over these media queries as expected.
   1100px (not 900px) at this tier -- .lower-grid's 4 dashboard widgets each
   have a 260px minimum column width, so 4-across needs ~1060px+ before they
   stop being squeezed; 900px was leaving them cramped/wrapping badly. */
@media (min-width: 900px) {
  main { max-width: 1100px; }
}
@media (min-width: 1300px) {
  main { max-width: 1300px; }
}
.tabpanel { display: none; }
.tabpanel.active { display: block; }
.card { background: var(--panel); border: 1px solid var(--line); border-radius: 4px; padding: 18px; margin-bottom: 16px; }
.card h2 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.08em; font-family: var(--mono); color: #8a8372; margin: 0 0 14px; }
.field { margin-bottom: 12px; }
.field-row { display: flex; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; }
.field-row .field { flex: 1; margin-bottom: 0; min-width: 150px; }
.field > label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: #8a8372; margin-bottom: 5px; font-family: var(--mono); }
.field-checkbox-label { display: flex !important; align-items: center; gap: 8px; font-size: 13px; text-transform: none !important; color: var(--ink) !important; font-family: var(--sans) !important; margin-bottom: 0 !important; }
.field input:not([type="checkbox"]):not([type="radio"]), .field select, .field textarea {
  width: 100%; padding: 10px 10px; border: 1px solid var(--line); border-radius: 4px;
  font-size: 15px; background: var(--paper); color: var(--ink); font-family: var(--sans);
}
.field textarea { font-family: var(--sans); resize: vertical; min-height: 70px; }
.field input:not([type="checkbox"]):not([type="radio"]):focus, .field select:focus, .field textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Checkboxes/radios inside a .field (e.g. company-assignment lists, the
   social-access toggle) must keep their native square size -- the generic
   .field input rule above only targets text-like inputs. */
.field input[type="checkbox"], .field input[type="radio"] {
  width: 15px; height: 15px; flex-shrink: 0; accent-color: var(--ink); margin: 0; cursor: pointer;
}
.revision-display {
  padding: 10px 10px; border: 1px solid var(--line); border-radius: 4px; font-size: 15px;
  background: #eee9dd; color: #5c5648; font-family: var(--mono); font-weight: 700;
}
button.primary {
  width: 100%; padding: 14px; border: none; border-radius: 4px; background: var(--ink); color: var(--paper);
  font-size: 14.5px; font-weight: 700; letter-spacing: 0.01em; cursor: pointer; margin-top: 4px;
}
button.primary:disabled { opacity: 0.35; cursor: not-allowed; }
button.primary:active:not(:disabled) { transform: scale(0.99); }
button.secondary {
  width: 100%; padding: 13px; border: 1px solid var(--ink); border-radius: 4px; background: none;
  color: var(--ink); font-size: 14px; font-weight: 600; cursor: pointer; margin-top: 10px;
}
button.small { padding: 6px 10px; border: 1px solid var(--line); border-radius: 4px; background: var(--paper); color: var(--ink); font-size: 12px; cursor: pointer; }
button.small.danger { border-color: var(--bad); color: var(--bad); }

/* "Take Photo" / "Choose Files" pair for image uploads -- a <label> wrapping a
   visually-hidden native <input type="file">. Two separate inputs (one with
   `capture`, one without) rather than one input doing both, because on several
   mobile browsers adding `capture` to a single input either always launches
   the camera directly (no gallery option) or, depending on OEM browser, never
   shows a camera option at all when combined with certain accept lists. Two
   explicit buttons are unambiguous on every platform. See assets/common.js /
   assets/jobs.js for how selections from both feed into the same upload. */
.file-btn-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
.file-btn {
  display: inline-flex; align-items: center; gap: 6px; padding: 10px 14px; border: 1px solid var(--ink);
  border-radius: 4px; background: none; color: var(--ink); font-size: 13px; font-weight: 600; cursor: pointer;
}
.file-btn input[type="file"] {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* Inline confirmation shown right where the person is already looking after
   creating a job -- the top status bar alone is easy to miss if they've
   scrolled down to fill out the form. */
.job-created-banner {
  margin-top: 12px; padding: 14px; border: 1px solid var(--ok); border-radius: 4px;
  background: var(--ok-bg); color: var(--ok); font-size: 13.5px;
}
.job-created-banner strong { display: block; margin-bottom: 8px; font-size: 14px; }
.job-created-banner .job-created-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.job-created-banner a, .job-created-banner button {
  padding: 8px 14px; border-radius: 4px; font-size: 12.5px; font-weight: 700;
  text-decoration: none; cursor: pointer; border: 1.5px solid var(--ok); color: var(--ok); background: none;
}
.job-created-banner a.primary-action, .job-created-banner button.primary-action {
  background: var(--ok); color: #fff;
}
/* Files the server couldn't store, reported inside the success banner -- the
   job WAS created, so this is a warning sitting within good news, not an
   error state of its own. Amber against the banner's green for exactly that
   reason. */
.job-created-skipped {
  margin: 0 0 10px; padding: 10px 12px; border-radius: 4px;
  border: 1px solid var(--warn); background: var(--warn-bg); color: var(--warn);
  font-size: 12.5px; line-height: 1.5;
}
.job-created-skipped strong { display: block; margin-bottom: 4px; font-size: 12.5px; }
.job-created-skipped ul { margin: 0 0 6px; padding-left: 18px; }
.job-created-skipped li { word-break: break-word; }

/* Confirmation shown after a ready-made proof PDF is uploaded from a job card.
   Replaces a bare hint that printed the approval link and offered nothing to do
   with it -- the link is now selectable and the send action sits beside it. */
.quick-proof-done {
  margin-top: 8px; padding: 12px; border: 1px solid var(--ok);
  border-radius: 4px; background: var(--ok-bg); color: var(--ok); font-size: 13px;
}
.quick-proof-done strong { display: block; margin-bottom: 8px; font-size: 13.5px; }
.quick-proof-done label {
  display: block; font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em;
  text-transform: uppercase; margin-bottom: 4px;
}
.quick-proof-done .quickProofLink {
  width: 100%; padding: 8px; border: 1px solid var(--line); border-radius: 4px;
  font-family: var(--mono); font-size: 11.5px; background: var(--paper); color: var(--ink);
}
.quick-proof-done-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 10px; }
/* .primary/.secondary are full-width by default in this stylesheet, which
   would stack these two on their own rows. They belong side by side. */
.quick-proof-done-actions button { margin: 0; width: auto; flex: 1 1 auto; min-width: 130px; }
.quick-proof-done-actions .secondary { background: var(--paper); color: var(--ink); }

/* ---------------------------------------------------------------------------
   Add Dimensions -- the annotation canvas and its chrome (dimensions.php).
--------------------------------------------------------------------------- */
.annot-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 10px; }
.annot-toolbar .zoom-group { display: inline-flex; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }
.annot-toolbar .zoom-group button {
  padding: 8px 12px; font: 700 14px var(--sans); line-height: 1; min-width: 40px;
  background: var(--paper); color: var(--ink); border: 0; border-right: 1px solid var(--line); cursor: pointer;
}
.annot-toolbar .zoom-group button:last-child { border-right: 0; }
.annot-toolbar .zoom-group button:hover { background: var(--panel); }
.annot-toolbar .zoom-group #zoomLevel { font: 500 11.5px var(--mono); }
.annot-scale { display: flex; align-items: center; gap: 7px; font-size: 12px; color: #8a8372; flex: 1; min-width: 170px; }
.annot-scale input[type="range"] { flex: 1; min-width: 90px; }
.annot-scale span { font-family: var(--mono); font-size: 11.5px; width: 34px; }
.annot-toolbar .secondary { width: auto; margin-top: 0; padding: 8px 13px; font-size: 12.5px; }

/* The scroll container for a zoomed-in photo. touch-action stays default so
   the browser handles pan and pinch itself -- the canvas places points on
   `click`, which a gesture never produces. */
.annot-viewport {
  margin-top: 10px; max-height: 70vh; overflow: auto;
  border-radius: 4px; background: var(--panel);
  -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
}
#pendingHint {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 8px; padding: 8px 11px; border-radius: 4px;
  background: var(--warn-bg); color: var(--warn); border: 1px solid var(--warn);
  font-size: 12.5px; font-weight: 600;
}
#pendingHint .small { margin-left: auto; }

.annot-fs-bar { display: flex; align-items: center; gap: 10px; padding: 10px 12px; background: #1a1a1a; flex-shrink: 0; }
.annot-fs-bar .secondary { width: auto; margin-top: 0; padding: 8px 12px; }
.annot-fs-bar-bottom { gap: 8px; padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
.annot-fs-tools { display: inline-flex; border: 1px solid #3a3a36; border-radius: 6px; overflow: hidden; }
.annot-fs-tool {
  padding: 8px 12px; font-size: 15px; line-height: 1; cursor: pointer;
  background: #242420; color: #ccc; border: 0; border-right: 1px solid #3a3a36;
}
.annot-fs-tool:last-child { border-right: 0; }
.annot-fs-tool.active { background: var(--accent); color: #1a1a1a; }
.annot-fs-scale { color: #ccc; font-size: 12px; display: flex; align-items: center; gap: 6px; }
.annot-fs-scale input[type="range"] { width: 100px; }
.annot-fs-scale span { width: 32px; font-family: var(--mono); font-size: 11px; }
.annot-fs-slot { flex: 1; overflow: auto; -webkit-overflow-scrolling: touch; }

/* The annotation list. .li-controls stacks its buttons at narrow widths, which
   left the edit pencil sitting on its own row above Remove -- these two belong
   side by side on one line whatever the width. */
#lineListArea .list-item { align-items: center; margin-bottom: 6px; }
#lineListArea .li-controls { display: flex; flex-direction: row; align-items: center; gap: 6px; flex-shrink: 0; }
#lineListArea .li-controls .small { margin: 0; width: auto; white-space: nowrap; }
#lineListArea [data-edit-line] { padding: 6px 10px; font-size: 13px; line-height: 1; }

/* Picked-file previews on the create-job form. Replaces a bare count, which
   couldn't show WHICH files were picked or let one be dropped. */
.job-attach-strip { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.job-attach-thumb {
  position: relative; width: 64px; height: 64px; border-radius: 4px;
  border: 1px solid var(--line); overflow: hidden; background: #fff; flex-shrink: 0;
}
.job-attach-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.job-attach-remove {
  position: absolute; top: 2px; right: 2px; width: 20px; height: 20px;
  border: 0; border-radius: 50%; cursor: pointer; padding: 0;
  background: rgba(26,26,26,0.72); color: #fff; font-size: 11px; line-height: 1;
}
.job-attach-remove:hover { background: var(--bad); }

/* Due-date presets. Small, quiet, and clearly secondary to the date input
   above them -- they write into it rather than replacing it. */
.due-presets { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.due-presets button {
  padding: 5px 10px; border-radius: 14px; cursor: pointer;
  font: 600 11.5px var(--sans); white-space: nowrap;
  border: 1px solid var(--line); background: var(--paper); color: #5c5648;
}
.due-presets button:hover { border-color: var(--ink); color: var(--ink); }
.due-presets button.active { background: var(--ink); border-color: var(--ink); color: var(--paper); }

/* Input sheet -- the app-wide replacement for window.prompt(). See
   openInputSheet() in common.js. Bottom-anchored on a phone (thumb reach,
   and it sits above the keyboard rather than fighting it), centred from
   tablet width up. */
.input-sheet-backdrop {
  position: fixed; inset: 0; z-index: 1200;
  background: rgba(26,26,26,0.44);
  display: flex; align-items: flex-end; justify-content: center;
  animation: input-sheet-fade 0.15s ease;
}
@media (min-width: 700px) { .input-sheet-backdrop { align-items: center; } }
@keyframes input-sheet-fade { from { opacity: 0; } to { opacity: 1; } }
.input-sheet {
  width: 100%; max-width: 520px; background: var(--paper);
  border-radius: 12px 12px 0 0; padding: 18px;
  box-shadow: 0 -4px 24px rgba(0,0,0,0.22);
  animation: input-sheet-rise 0.18s cubic-bezier(.2,.8,.3,1);
}
@media (min-width: 700px) { .input-sheet { border-radius: 12px; margin: 20px; } }
@keyframes input-sheet-rise { from { transform: translateY(14px); opacity: .6; } to { transform: none; opacity: 1; } }
.input-sheet h3 { margin: 0 0 4px; font-size: 16px; font-weight: 800; letter-spacing: -0.01em; }
.input-sheet .input-sheet-field {
  width: 100%; padding: 11px 12px; font-family: inherit; font-size: 16px;
  border: 1px solid var(--line); border-radius: 6px; background: #fff; color: var(--ink);
  margin-top: 10px;
}
.input-sheet textarea.input-sheet-field { min-height: 90px; resize: vertical; line-height: 1.5; }
.input-sheet .input-sheet-field:focus { outline: none; border-color: var(--ink); }
.input-sheet-actions { display: flex; gap: 8px; margin-top: 14px; }
.input-sheet-actions button { flex: 1; margin-top: 0; }

/* The job's own photos, offered on the proof builder as one-tap artwork.
   Sits directly above the dropzone so the two read as "already here" then
   "or add something new", in that order. */
.job-artwork-picker {
  margin-bottom: 12px; padding: 12px; border: 1px solid var(--line);
  border-radius: 4px; background: var(--panel);
}
.job-artwork-picker-head { display: flex; flex-direction: column; gap: 2px; margin-bottom: 10px; }
.job-artwork-picker-head strong { font-size: 13px; }
.job-artwork-thumbs { display: flex; flex-wrap: wrap; gap: 8px; }
.job-artwork-thumb {
  position: relative; padding: 0; border: 1px solid var(--line); border-radius: 4px;
  background: #fff; cursor: pointer; overflow: hidden; line-height: 0;
  width: 92px; height: 92px; flex-shrink: 0;
}
.job-artwork-thumb:hover { border-color: var(--ink); }
.job-artwork-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.job-artwork-add {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 3px 0;
  font: 700 10px var(--sans); line-height: 1.4; text-align: center;
  background: rgba(26,26,26,0.82); color: var(--paper);
}
.job-artwork-thumb.is-loading { opacity: 0.55; cursor: progress; }

/* Files on a job request -- photos as thumbnails, a PDF as a document chip
   since there's nothing to preview. Both link out to the file itself. */
.req-attachments { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.req-attachments img { max-width: 96px; max-height: 96px; border-radius: 4px; border: 1px solid var(--line); display: block; }
.req-attachment-doc {
  display: inline-flex; align-items: center; gap: 5px; padding: 8px 11px;
  border: 1px solid var(--line); border-radius: 4px; background: var(--panel);
  font-size: 12px; font-weight: 600; color: var(--ink); text-decoration: none;
  max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.req-attachment-doc:hover { border-color: var(--ink); }

/* Per-company notes/to-dos panel on companies.php */
.co-notes-panel {
  margin-top: 10px; padding: 10px; border: 1px solid var(--line); border-radius: 4px; background: var(--panel);
}
.co-notes-add { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.co-notes-input {
  width: 100%; box-sizing: border-box; font-family: var(--sans); font-size: 13px;
  padding: 8px; border: 1px solid var(--line); border-radius: 4px; resize: vertical;
}
.co-notes-add-row { display: flex; align-items: center; gap: 12px; }
.co-notes-list { display: flex; flex-direction: column; gap: 6px; }
.co-note-row {
  display: flex; align-items: flex-start; gap: 8px; padding: 8px; border-radius: 4px;
  background: var(--paper); border: 1px solid var(--line);
}
.co-note-row.co-note-urgent { border-color: var(--bad); background: var(--bad-bg); }
.co-note-row.co-note-done { opacity: 0.55; }
.co-note-row.co-note-done .co-note-text { text-decoration: line-through; }
.co-note-check { margin-top: 2px; width: auto; }
.co-note-bullet { color: #8a8372; margin-top: 1px; }
.co-note-body { flex: 1; min-width: 0; }
.co-note-text { font-size: 13px; white-space: pre-wrap; word-break: break-word; }
.co-note-meta { font-size: 10.5px; color: #8a8372; margin-top: 3px; }
.co-note-actions { display: flex; gap: 4px; flex-shrink: 0; }
.co-note-icon-btn {
  border: none; background: none; cursor: pointer; font-size: 13px; padding: 2px 5px;
  color: #8a8372; border-radius: 3px;
}
.co-note-icon-btn:hover { background: var(--line); }
.co-note-row.co-note-urgent .co-note-icon-btn[data-note-toggle-urgent] { color: var(--bad); }
.co-notes-show-done { margin-top: 8px; }

/* Proof log day navigator + filters */
.log-day-nav { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 14px 0 10px; }
.log-day-label {
  flex: 1; text-align: center; font-weight: 700; font-size: 14px; background: none; border: none;
  cursor: pointer; padding: 8px; border-radius: 4px; font-family: var(--sans); color: var(--ink);
}
.log-day-label:hover { background: var(--panel); }
.log-filters { display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
.log-filters select { flex: 0 0 auto; font-size: 12.5px; padding: 7px; }
.log-filters input[type="text"] { flex: 1; min-width: 160px; font-size: 12.5px; padding: 7px; }
.letterhead-preview { border: 1px dashed var(--line); border-radius: 4px; padding: 12px 14px; margin-top: 10px; background: var(--paper); display: flex; gap: 12px; align-items: center; }
.letterhead-preview img { width: 48px; height: 48px; object-fit: contain; border: 1px solid var(--line); border-radius: 3px; background: #fff; flex-shrink: 0; }
.letterhead-preview .lh-name { font-weight: 700; font-size: 14.5px; }
.letterhead-preview .lh-detail { font-size: 11.5px; color: #5c5648; line-height: 1.5; margin-top: 2px; }
.dropzone.drag-active { border-color: var(--accent); background: var(--accent-dim); }
.dropzone input { display: none; }
.dropzone .icon { font-size: 24px; margin-bottom: 4px; }
.dropzone .main-label { font-size: 13.5px; font-weight: 600; }
.dropzone .sub-label { font-size: 11.5px; color: #8a8372; margin-top: 2px; }
.artwork-list { margin-top: 14px; display: flex; flex-direction: column; gap: 10px; }
.artwork-item { display: flex; gap: 10px; align-items: center; border: 1px solid var(--line); border-radius: 4px; padding: 10px; background: var(--paper); }
.artwork-item img { width: 52px; height: 52px; object-fit: cover; border-radius: 3px; border: 1px solid var(--line); flex-shrink: 0; }
.artwork-item .aw-fields { flex: 1; min-width: 0; }
.artwork-item input[type="text"] { width: 100%; padding: 7px 8px; border: 1px solid var(--line); border-radius: 4px; font-size: 13px; background: #fff; margin-bottom: 4px; }
.aw-dims { display: flex; gap: 6px; margin-bottom: 4px; }
.aw-dims input[type="number"] { width: 100%; padding: 6px 7px; border: 1px solid var(--line); border-radius: 4px; font-size: 12.5px; background: #fff; }
.artwork-item .aw-meta { font-family: var(--mono); font-size: 10.5px; color: #8a8372; }
.artwork-item .aw-controls { display: flex; flex-direction: column; gap: 4px; flex-shrink: 0; }
.hint { font-size: 12px; color: #8a8372; margin-top: 8px; line-height: 1.5; }
a.download-link { display: block; text-align: center; margin-top: 12px; padding: 13px; background: var(--ink); color: white; border-radius: 4px; text-decoration: none; font-weight: 700; font-size: 14.5px; border: 2px solid var(--accent); }
iframe.pdf-preview { width: 100%; height: 420px; border: 1px solid var(--line); border-radius: 4px; margin-top: 14px; }
/* proof.php's own generated-proof preview specifically (not prooflog.php's
   monthly summary preview, which stays at the default height above) -- now
   that its column actually has room (see .page-sidebar-wide), let it use
   it, scaling with the viewport instead of a fixed 420px. */
#previewArea iframe.pdf-preview { height: 78vh; min-height: 560px; }
footer { text-align: center; font-size: 11px; color: #8a8372; padding: 20px; font-family: var(--mono); }

.list-item { display: flex; gap: 12px; align-items: center; border: 1px solid var(--line); border-radius: 4px; padding: 12px; margin-bottom: 10px; background: var(--paper); }
.list-item img.logo-thumb { width: 44px; height: 44px; object-fit: contain; border: 1px solid var(--line); border-radius: 3px; background: #fff; flex-shrink: 0; }
.list-item .li-info { flex: 1; min-width: 0; }
.list-item .li-name { font-weight: 700; font-size: 14px; }
.list-item .li-sub { font-size: 11.5px; color: #5c5648; margin-top: 2px; line-height: 1.4; }
.list-item .li-controls { display: flex; flex-direction: column; gap: 4px; flex-shrink: 0; }
.empty-state { text-align: center; padding: 24px 12px; color: #8a8372; font-size: 13px; }

.home-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; padding: 4px 0; }
.home-tile {
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: 6px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 26px 14px;
  text-decoration: none; color: var(--ink); transition: border-color 0.15s, transform 0.1s;
}
.home-tile:active { transform: scale(0.97); }
.home-tile:hover { border-color: var(--accent); }
.home-tile-icon { font-size: 34px; line-height: 1; margin-bottom: 4px; }
.home-tile-label { font-weight: 700; font-size: 15px; }
.home-tile-desc { font-size: 11.5px; color: #8a8372; line-height: 1.4; }

.log-job-number { font-family: var(--mono); font-size: 11px; color: #8a8372; font-weight: 400; }
.log-view-pdf { display: inline-block; margin-top: 6px; font-size: 12px; font-weight: 700; color: var(--ink); text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 2px; }
.log-view-pdf:hover { text-decoration: underline; }
.log-no-pdf { display: inline-block; margin-top: 6px; font-size: 11.5px; color: #8a8372; font-style: italic; }

.status-badge { display: inline-block; padding: 4px 9px; border-radius: 20px; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; white-space: nowrap; flex-shrink: 0; }
.status-in_progress { background: #f6e9d2; color: #8a5a1f; }
.status-proof { background: #dde6f2; color: #2f5289; }
.status-approved { background: var(--ok-bg); color: var(--ok); }
.status-quote { background: var(--accent-dim); color: #5c6b1a; }
.status-invoiced { background: #e5ddf2; color: #5b3a8a; }
.status-hold { background: #f0d9d2; color: #8a3a1f; }
.status-pending_invoice { background: #d2e8e6; color: #1f6b62; }
.status-pending { background: #f6e9d2; color: #8a5a1f; }
.status-changes_requested { background: var(--bad-bg); color: var(--bad); }
/* "Approved, but apply these changes first" -- green like an approval, because
   that is what it is, with the amber border carrying the "something still to
   do" part rather than a second colour fighting the first. */
.status-approved_with_changes { background: var(--ok-bg); color: var(--ok); border: 1px solid var(--warn); }

.quick-status-badge { cursor: pointer; border: none; }
.quick-status-badge:hover { filter: brightness(0.94); }
.quick-status-select { display: inline-block; padding: 3px 6px; border-radius: 20px; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; border: 1.5px solid var(--ink); background: var(--paper); color: var(--ink); flex-shrink: 0; max-width: 100%; }
.board-card-status-badge { font-size: 9px; padding: 3px 7px; }

/* Read-only mark summaries rendered by renderMarkupSummary() in common.js --
   used on the Proof Log and inside the job detail modal. The client-facing
   approval page has its own copy of these in assets/approve.css; it no longer
   shares this stylesheet at all, so everything else that lived here (the brand
   banner, .approve-*, the markup toolbar, the pdf page wrapper, the
   approve.php button overrides) has moved there and is gone from this file. */
.markup-comment-row { display: flex; align-items: flex-start; gap: 8px; font-size: 12.5px; padding: 5px 0; line-height: 1.4; }
.markup-comment-text { display: flex; align-items: flex-start; gap: 8px; flex: 1; min-width: 0; }
.markup-pin-number {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 18px; height: 18px; border-radius: 50%; background: var(--bad); color: #fff;
  font-size: 10px; font-weight: 700; margin-top: 1px;
}

.job-row { border: 1px solid var(--line); border-radius: 4px; margin-bottom: 10px; overflow: hidden; background: var(--paper); }
.job-row-summary { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 12px; cursor: pointer; }
.job-row-summary:active { background: var(--accent-dim); }
.job-row-main { flex: 1; min-width: 0; }
.job-row-desc { font-weight: 700; font-size: 13.5px; line-height: 1.4; }
.job-row-detail { padding: 14px; border-top: 1px solid var(--line); background: var(--panel); }
.job-row-detail textarea { min-height: 60px; }

.job-attachments-gallery { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; }
.job-attachment-thumb { position: relative; width: 64px; height: 64px; }
.job-attachment-thumb img { width: 100%; height: 100%; object-fit: cover; border-radius: 4px; border: 1px solid var(--line); }
.attachment-remove-btn {
  position: absolute; top: -6px; right: -6px; width: 20px; height: 20px; border-radius: 50%;
  background: var(--bad); color: white; border: 2px solid var(--paper); font-size: 11px; line-height: 1;
  cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0;
}
button.secondary.danger { border-color: var(--bad); color: var(--bad); }

.active-jobs-section { margin-top: 22px; }
.active-jobs-section h2 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.08em; font-family: var(--mono); color: #8a8372; margin: 0 0 12px; }
.active-job-card { border: 1px solid var(--line); border-radius: 4px; padding: 12px; margin-bottom: 10px; background: var(--panel); display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.active-job-card .job-row-main { flex: 1; min-width: 0; }
.active-job-card .li-sub { margin-top: 2px; }
.active-job-quick-status { flex-shrink: 0; font-size: 11.5px; padding: 6px 6px; border-radius: 4px; border: 1px solid var(--line); background: var(--paper); }

.radio-group { display: flex; gap: 8px; }
.radio-option {
  flex: 1; border: 1px solid var(--line); border-radius: 4px; padding: 10px 8px;
  display: flex; align-items: center; gap: 7px; cursor: pointer; font-size: 13px;
  background: var(--paper);
}
.radio-option input { accent-color: var(--accent); flex-shrink: 0; }
.radio-option.selected { border-color: var(--accent); background: var(--accent-dim); font-weight: 700; }

.quality-report {
  border-radius: 6px; padding: 16px; text-align: center; border: 1px solid var(--line);
}
.quality-report-dpi { font-size: 26px; font-weight: 800; font-family: var(--mono); line-height: 1.1; }
.quality-report-label { font-size: 13px; font-weight: 700; margin-top: 4px; }
.quality-excellent { background: var(--ok-bg); color: var(--ok); border-color: var(--ok); }
.quality-good { background: #dde6f2; color: #2f5289; border-color: #2f5289; }
.quality-marginal { background: #f6e9d2; color: #8a5a1f; border-color: #8a5a1f; }
.quality-poor { background: #f5d9d4; color: var(--bad); border-color: var(--bad); }

/* Job board */
.board-columns { display: flex; gap: 14px; overflow-x: auto; padding-bottom: 8px; }
.board-column { flex: 1; min-width: 240px; background: var(--panel); border: 1px solid var(--line); border-radius: 4px; padding: 10px; }
.board-column-header { font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: #8a8372; display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; padding: 0 4px; }
.board-column-count { background: var(--paper); border: 1px solid var(--line); border-radius: 10px; padding: 1px 7px; font-size: 10.5px; }
.board-column-list { min-height: 60px; display: flex; flex-direction: column; gap: 8px; }
.board-card { display: flex; gap: 8px; padding: 10px; border: 1px solid var(--line); border-radius: 4px; background: var(--paper); cursor: grab; }
.board-card:active { cursor: grabbing; }
.board-card:hover { border-color: var(--ink); }
.board-card.board-card-selected { border-color: var(--ink); border-width: 2px; padding: 9px; background: var(--accent-dim); }

/* A normal flex item (not absolutely positioned) -- reserves its own space
   in the card's flex row instead of floating on top of the title text. */
.board-card-select { display: flex; align-self: flex-start; flex-shrink: 0; margin-top: 2px; }
.board-card-checkbox { width: 17px; height: 17px; cursor: pointer; accent-color: var(--ink); margin: 0; }

.board-bulk-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 150;
  background: var(--ink); color: var(--paper);
  display: none; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 18px; box-shadow: 0 -4px 16px rgba(0,0,0,0.25);
}
.board-bulk-bar.open { display: flex; }
.board-bulk-bar-count { font-weight: 700; font-size: 13px; margin-right: 4px; white-space: nowrap; }
.board-bulk-bar-spacer { flex: 1 1 auto; min-width: 4px; }
.board-bulk-select { padding: 8px 10px; border-radius: 8px; border: 1.5px solid #55534c; background: var(--ink); color: var(--paper); font-size: 12.5px; font-family: inherit; }
.docket-btn-danger { background: var(--bad); color: var(--paper); }

/* Filter bar -- replaces the old bare <select id="boardCompanySelect">.
   Company chips reuse .docket-chip/.docket-chip-active (already defined for
   the dashboard's own header company filter) so the two controls look and
   behave identically without duplicating any CSS. */
.board-filter-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.board-filter-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.board-filter-chips-quick { margin-left: auto; }
.board-quick-filter {
  font: 600 12px var(--sans); padding: 7px 13px; border-radius: 8px; cursor: pointer; white-space: nowrap;
  border: 1px solid var(--line); color: #5c5648; background: var(--paper);
}
.board-quick-filter:hover { border-color: var(--ink); }
.board-quick-filter-active.board-quick-filter-overdue { border-color: #c98a1f; background: #fdf6ea; color: #8a5c15; }
.board-quick-filter-active.board-quick-filter-awaiting { border-color: var(--ink); background: var(--ink); color: var(--paper); }
.board-quick-filter-active.board-quick-filter-approved { border-color: var(--ok); background: var(--ok-bg); color: var(--ok); }
.board-quick-filter-active.board-quick-filter-applychanges { border-color: var(--warn); background: var(--warn-bg); color: var(--warn); }
.board-quick-filter-active.board-quick-filter-duesoon { border-color: #2f5289; background: #dde6f2; color: #2f5289; }

/* Card age badge -- top-right of the title row; amber + warning glyph when
   the job is also overdue (uses the same overdue test as the quick filter
   above, computed once per card in board.js). Overdue is carried by the ⚠
   prefix + title attribute board.js adds to the badge, not a separate class. */
.board-card-title-row { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; }
.board-card-age { font: 400 10.5px var(--mono); color: #b3ad9c; flex-shrink: 0; white-space: nowrap; }

/* Two rows under the title. Facts (status, due) sit on the first and always
   render; signals (client answer, staleness, design marker) on the second and
   only appear when there's something to say -- so a quiet job stays quiet
   instead of carrying a row of empty space. */
.board-card-facts { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin-top: 6px; }
.board-card-signals { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.board-card-signals:not(:empty) { margin-top: 5px; }

/* The due date, which the card never showed. Tone carries the urgency so the
   text doesn't have to shout it: overdue red, today amber, this week a plain
   outline, anything further out muted. */
.board-card-due {
  display: inline-flex; align-items: center; gap: 3px;
  font: 700 9.5px var(--sans); letter-spacing: 0.02em; white-space: nowrap;
  padding: 3px 7px; border-radius: 12px; border: 1px solid transparent;
}
.board-card-due-over  { background: var(--bad-bg);  color: var(--bad);  border-color: var(--bad); }
.board-card-due-today { background: var(--warn-bg); color: var(--warn); border-color: var(--warn); }
.board-card-due-soon  { background: var(--paper);   color: #5c5648;     border-color: var(--line); }
.board-card-due-far   { background: none;           color: #8a8372;     border-color: var(--line); }

/* Secondary markers -- present but never competing with a status or a due
   date. Deliberately not a .status-badge: "has design instructions" is not a
   state the job is in. */
.board-card-mini {
  display: inline-flex; align-items: center; gap: 3px;
  font: 600 9.5px var(--sans); color: #8a8372; white-space: nowrap;
  padding: 2px 6px; border-radius: 10px; background: var(--panel);
}

/* Right-click context menu on a board card -- fixed-position so it can float
   above the columns regardless of scroll, closed on outside click/Escape/scroll
   from board.js. */
.board-context-menu {
  position: fixed; z-index: 200; min-width: 190px;
  background: var(--paper); border: 1px solid var(--ink); border-radius: 6px;
  box-shadow: 0 6px 20px rgba(0,0,0,0.18); padding: 6px; font-size: 13px;
  display: none;
}
.board-context-menu.open { display: block; }
.board-context-menu-title {
  font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em;
  color: #8a8372; padding: 6px 10px 4px;
}
.board-context-menu-item {
  display: block; width: 100%; text-align: left; padding: 8px 10px; border: none; background: none;
  border-radius: 4px; cursor: pointer; font-family: var(--sans); font-size: 13px; color: var(--ink);
}
.board-context-menu-item:hover { background: var(--panel); }
.board-context-menu-item.active { font-weight: 700; }
.board-context-menu-item.active::after { content: ' ✓'; }
.board-context-menu-item.danger { color: var(--bad); }
.board-context-menu-item.danger:hover { background: var(--bad-bg); }
.board-context-menu-sep { height: 1px; background: var(--line); margin: 5px 4px; }
.board-card-logo { width: 32px; height: 32px; object-fit: contain; border: 1px solid var(--line); border-radius: 3px; background: #fff; flex-shrink: 0; }
.board-card-title { font-size: 13px; font-weight: 700; line-height: 1.3; }
.board-card-sub { font-size: 11px; color: #8a8372; margin-top: 3px; }
.sortable-ghost { opacity: 0.4; }

/* Analytics */
.analytics-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; }
.analytics-stat { background: var(--paper); border: 1px solid var(--line); border-radius: 4px; padding: 14px; text-align: center; }
.analytics-stat-value { font-size: 24px; font-weight: 700; font-family: var(--mono); }
.analytics-stat-label { font-size: 11px; color: #8a8372; text-transform: uppercase; letter-spacing: 0.05em; margin: 4px 0 8px; }

/* Dashboard (Home page) -- .customize-btn/.stat-* were superseded by the
   docket header (.docket-pill / .docket-stat-*, further up); kept removed
   here rather than left as dead weight since nothing on any page still uses
   these class names (confirmed against index.php, board.js, jobs.php). */

/* ---------------------------------------------------------------------------
   Command bar (Home page) -- search field on its own line (a real search
   tool deserves real width, not squeezed into leftover flex space next to
   buttons -- this was the root cause of the layout repeatedly breaking) plus
   a row of naturally-sized action buttons below it. Buttons size to their
   own content and sit left-aligned with a fixed gap -- never stretched to
   fill a row, never fighting flex-basis math against the search box, so
   there's no viewport width where this can wrap unpredictably.
--------------------------------------------------------------------------- */
#jobSearchResults.job-search-results-open {
  display: block; position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 20;
  background: #fff; border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.14);
  max-height: 380px; overflow-y: auto; padding: 4px 0;
}
#jobSearchResults:not(.job-search-results-open) { display: none; }
#jobSearchResults .job-row:hover { background: var(--panel); }
#jobSearchResults .empty-state, #jobSearchResults .hint { padding: 10px 14px; margin: 0; }

/* ---------------------------------------------------------------------------
   Page sidebar -- a small, fixed (non-draggable/non-hideable) set of glance
   widgets for jobs.php and proof.php, so those pages aren't purely a form
   with nothing else on screen. Deliberately NOT the homepage's drag-reorder
   system (applyWidgetOrder etc in home.js) -- that's overkill for a couple
   of fixed widgets on a secondary page. Stacks below the main content on
   narrow screens, sits alongside it on wider ones.
--------------------------------------------------------------------------- */
.page-with-sidebar { display: flex; flex-direction: column; gap: 18px; }
.page-with-sidebar > .page-main { flex: 1; min-width: 0; }
.page-with-sidebar > .page-sidebar { display: flex; flex-direction: column; gap: 14px; }
@media (min-width: 900px) {
  .page-with-sidebar { flex-direction: row; align-items: flex-start; }
  .page-with-sidebar > .page-sidebar { width: 260px; flex-shrink: 0; position: sticky; top: 18px; }
}
.sidebar-stat { background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 14px 16px; }
.sidebar-stat .label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: #8a8a80; }
.sidebar-stat .value { font-size: 26px; font-weight: 700; margin-top: 2px; }
.sidebar-stat-row { display: flex; gap: 10px; }
.sidebar-stat-row .sidebar-stat { flex: 1; }

/* Wide sidebar variant -- proof.php only (jobs.php's sidebar keeps the
   default 260px). This is where the PDF preview actually lives (see
   #previewArea below), which is the entire reason anyone's on this page --
   was pinned to a fixed 320px while the form column beside it (company/
   job/artwork -- none of which benefit from being wide; a <select> isn't
   more usable at 900px than at 500px) got whatever flexible space was left
   over. Reversed: the form is now the fixed, narrower column, and this
   grows to fill the rest. */
@media (min-width: 900px) {
  .page-main.page-main-narrow { flex: 0 1 520px; }
  .page-sidebar.page-sidebar-wide { width: auto; flex: 1 1 auto; min-width: 0; }
}

/* Carried-over marks checklist (proof.php). */
.carried-over-item {
  display: flex; align-items: flex-start; gap: 8px; font-size: 12.5px; line-height: 1.4;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 6px; background: var(--paper); cursor: pointer;
}
.carried-over-item:has(input:checked) { background: var(--panel); color: #8a8372; text-decoration: line-through; }
.carried-over-item input[type="checkbox"] { margin-top: 2px; flex-shrink: 0; width: auto; }

/* ---------------------------------------------------------------------------
   Job Board "needs follow-up" widget -- a count badge (same visual language
   as the notification bell's unread badge) and a pulse animation that only
   runs while .has-followups is present. Used both by the docket header's
   Job Board pill (.docket-pill.followup-btn, see further up) and the mobile
   tab bar's Board tab badge (.docket-tab-badge, its own separate styling).
--------------------------------------------------------------------------- */
.followup-btn { position: relative; overflow: visible; }
.followup-badge {
  display: none; position: absolute; top: -7px; right: -7px; background: var(--bad); color: #fff;
  border-radius: 10px; min-width: 18px; height: 18px; font-size: 10px; font-weight: 700;
  align-items: center; justify-content: center; padding: 0 4px; border: 2px solid var(--paper);
}
.followup-btn.has-followups { animation: followup-vibrate 2.2s ease-in-out infinite; }
.followup-btn.has-followups .followup-badge { display: flex; }
@keyframes followup-vibrate {
  0%, 100% { transform: translateX(0); }
  92% { transform: translateX(0); }
  93% { transform: translateX(-2px) rotate(-1deg); }
  94% { transform: translateX(2px) rotate(1deg); }
  95% { transform: translateX(-2px) rotate(-1deg); }
  96% { transform: translateX(2px) rotate(1deg); }
  97% { transform: translateX(-1px); }
  98% { transform: translateX(1px); }
}
/* Respect reduced-motion preferences -- the badge/count still communicates
   the same information without the shake. */
@media (prefers-reduced-motion: reduce) {
  .followup-btn.has-followups { animation: none; }
}

/* Board card / job list "needs follow-up" highlight -- visually distinct from
   the existing "changes requested" red/pink treatment (status-changes_requested)
   so the two never get confused: this is amber/left-border, that stays red. */
.job-card.needs-followup, .list-item.needs-followup, .board-card-needs-followup {
  border-left: 4px solid #c98a1f;
  background: #fdf6ea;
}
.followup-flag {
  display: inline-flex; align-items: center; gap: 4px; font-size: 10.5px; font-weight: 700;
  color: #8a5c15; background: #f6e8cc; border-radius: 20px; padding: 3px 9px; white-space: nowrap;
}

.lower-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; margin-bottom: 22px; }
.widget { background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 16px; position: relative; }

/* Widget drag-and-drop -- desktop/mouse only (see the pointer:fine media query
   below). On mobile, widgets stay in whatever order they were saved in with
   no drag affordance at all, per the "lock on mobile" requirement -- touch
   drag-reordering of a scrollable page is fiddly to get right and easy to get
   wrong, and mobile doesn't have the wasted-space problem this was solving. */
.widget-drag-handle {
  display: none; position: absolute; top: 14px; right: 40px; cursor: grab;
  color: #b3ad9c; font-size: 15px; padding: 4px; line-height: 1; user-select: none;
}
@media (pointer: fine) and (min-width: 900px) {
  .widget-drag-handle { display: block; }
}
/* SortableJS's own drag-state classes (same library board.php already uses) --
   replaces the old hand-rolled .dragging/.drag-over-before/.drag-over-after. */
.widget.sortable-ghost { opacity: 0.4; }
.widget.sortable-chosen { box-shadow: 0 0 0 2px var(--accent); }

/* Mini calendar widget */
.mini-cal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; font-weight: 700; font-size: 13.5px; }
.mini-cal-nav { display: flex; gap: 4px; }
.mini-cal-nav button { border: 1px solid var(--line); background: #fff; border-radius: 4px; width: 22px; height: 22px; cursor: pointer; font-size: 12px; line-height: 1; padding: 0; }
.mini-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; text-align: center; font-size: 11.5px; }
.mini-cal-dow { color: #8a8372; font-weight: 700; padding: 4px 0; }
.mini-cal-day { padding: 6px 0 4px; border-radius: 4px; position: relative; cursor: default; }
.mini-cal-day.mini-cal-today { background: var(--ink); color: #fff; font-weight: 700; }
.mini-cal-day.mini-cal-other-month { color: #cfc9ba; }
.mini-cal-day.mini-cal-has-jobs { cursor: pointer; }
.mini-cal-day.mini-cal-has-jobs:hover { background: var(--panel); }
.mini-cal-day.mini-cal-today.mini-cal-has-jobs:hover { background: var(--ink); }
.mini-cal-dot { display: block; width: 5px; height: 5px; border-radius: 50%; margin: 2px auto 0; }
.mini-cal-dot.mini-cal-dot-overdue { background: var(--bad); }
.mini-cal-dot.mini-cal-dot-soon { background: #c98a1f; }
.mini-cal-dot.mini-cal-dot-future { background: #8a8372; }
.mini-cal-day.mini-cal-today .mini-cal-dot { background: #fff; }

/* Timezone clock widget */
.tz-clock-time { font-family: var(--mono); font-size: 30px; font-weight: 700; letter-spacing: 0.02em; }
.tz-clock-date { font-size: 12.5px; color: #8a8372; margin-top: 2px; }
.tz-clock-select { width: 100%; margin-top: 10px; font-size: 12.5px; padding: 6px; }

/* Motivational quote widget */
.quote-text { font-size: 15px; line-height: 1.5; font-style: italic; }

/* Weather widget */
.weather-current { display: flex; align-items: center; gap: 12px; }
.weather-temp { font-size: 32px; font-weight: 700; font-family: var(--mono); }
.weather-desc { font-size: 12.5px; color: #8a8372; }
.weather-set-form { display: flex; gap: 6px; margin-top: 10px; }
.weather-set-form input { flex: 1; font-size: 12.5px; padding: 6px; }

/* Tools widget -- a small grid of icon links to the standalone tool pages */
.tools-widget-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.tools-widget-item {
  display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center;
  padding: 14px 8px; border: 1px solid var(--line); border-radius: 6px; text-decoration: none;
  color: var(--ink); font-size: 12px; font-weight: 600;
}
.tools-widget-item:hover { background: var(--panel); border-color: var(--ink); }
.tools-widget-icon { font-size: 22px; }
.widget h2 { font: 700 12px var(--mono); letter-spacing: 0.05em; text-transform: uppercase; color: #8a8a80; margin: 0 0 12px; }
/* A heading with a trailing "View all →" style link -- laid out as a flex row
   rather than a float, so the link can't make the heading taller than a plain
   one and knock that card out of vertical alignment with the other columns. */
.widget h2.widget-h2-with-link { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.widget h2.widget-h2-with-link a { font: 600 11.5px var(--sans); text-transform: none; letter-spacing: 0; color: var(--ink); text-decoration: none; border-bottom: 2px solid var(--accent); white-space: nowrap; }

.widget-remove { position: absolute; top: 10px; right: 10px; width: 22px; height: 22px; border-radius: 50%; background: var(--bad-bg); color: var(--bad); border: none; font-size: 12px; font-weight: 700; cursor: pointer; display: none; align-items: center; justify-content: center; }
body.customizing .widget-remove { display: flex; }

.empty-slot { border: 1.5px dashed var(--line); border-radius: 8px; display: none; align-items: center; justify-content: center; color: #b3b3aa; font-size: 12px; padding: 30px 16px; text-align: center; }
body.customizing .empty-slot.hidden-widget { display: flex; }

.add-back-tray { display: none; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; }
body.customizing .add-back-tray.has-items { display: flex; }
.add-back-chip { background: #fff; border: 1.5px dashed var(--ink); border-radius: 20px; padding: 6px 14px; font-size: 12px; font-weight: 700; cursor: pointer; }

/* All-pages drawer -- replaces the old inline link grid with a slide-out panel,
   triggered by a small floating icon so the home page itself stays uncluttered
   as more pages get added over time. */
.pages-drawer-trigger {
  position: fixed; bottom: 20px; right: 20px; z-index: 40;
  width: 48px; height: 48px; border-radius: 50%;
  background: var(--ink); color: var(--paper); border: none;
  font-size: 20px; cursor: pointer; box-shadow: 0 2px 10px rgba(0,0,0,0.25);
  display: flex; align-items: center; justify-content: center;
}
.pages-drawer-trigger:hover { background: #000; }
/* On index.php's mobile layout the bottom tab bar occupies this corner, and
   the tab bar's own "More" item already opens this same drawer -- so hide
   the floating trigger there rather than stacking two controls for the same
   thing on top of each other. Other pages (no tab bar) keep it. */
@media (max-width: 899px) {
  body.docket-body .pages-drawer-trigger { display: none; }
}

/* Print/Social workspace switch -- only rendered for a login with access to
   both (see injectWorkspaceSwitch() in common.js). Placed inline into the
   real header markup (docket-right-cluster, or grouped with the plain
   <header>'s logout link) rather than fixed-positioned, so it can never sit
   on top of a page's own header controls. */
.workspace-switch {
  display: inline-flex; flex-shrink: 0; padding: 3px; gap: 2px;
  background: var(--ink); border-radius: 999px;
}
.workspace-switch a {
  font: 700 10.5px var(--mono); text-transform: uppercase; letter-spacing: 0.03em;
  padding: 5px 11px; border-radius: 999px; color: var(--paper); text-decoration: none; opacity: 0.65;
  white-space: nowrap;
}
.workspace-switch a:hover { opacity: 0.9; }
.workspace-switch a.active { background: var(--paper); color: var(--ink); opacity: 1; }

.pages-drawer-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.35);
  z-index: 49; opacity: 0; pointer-events: none; transition: opacity 0.2s ease;
}
.pages-drawer-overlay.open { opacity: 1; pointer-events: auto; }

.pages-drawer {
  position: fixed; top: 0; right: 0; height: 100%; width: 280px; max-width: 85vw;
  background: var(--paper); border-left: 1px solid var(--line);
  z-index: 50; transform: translateX(100%); transition: transform 0.25s ease;
  display: flex; flex-direction: column; box-shadow: -4px 0 16px rgba(0,0,0,0.15);
}
.pages-drawer.open { transform: translateX(0); }

.pages-drawer-header {
  display: flex; justify-content: space-between; align-items: center;
  padding: 16px 18px; border-bottom: 1px solid var(--line);
}
.pages-drawer-header h2 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.05em; color: #8a8a80; margin: 0; }
.pages-drawer-close {
  background: none; border: none; font-size: 16px; cursor: pointer; color: var(--ink);
  width: 28px; height: 28px; border-radius: 4px;
}
.pages-drawer-close:hover { background: var(--panel); }

.pages-drawer-links { display: flex; flex-direction: column; padding: 10px; overflow-y: auto; }
.pages-drawer-links > a {
  font-size: 14px; font-weight: 600; color: var(--ink); text-decoration: none;
  padding: 12px 14px; border-radius: 6px;
}
.pages-drawer-links > a:hover { background: var(--accent-dim); }

.pages-drawer-home {
  display: flex; align-items: center; gap: 6px;
  border: 1px solid var(--line); margin-bottom: 8px;
}

.pages-drawer-group { margin-top: 4px; border-radius: 6px; overflow: hidden; }
.pages-drawer-group-toggle {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  background: none; border: none; cursor: pointer; text-align: left;
  font-size: 13px; font-weight: 700; color: var(--ink);
  padding: 12px 14px; border-radius: 6px;
}
.pages-drawer-group-toggle:hover { background: var(--panel); }
.pages-drawer-group-arrow { font-size: 11px; color: #8a8a80; transition: transform 0.15s ease; }
.pages-drawer-group.open .pages-drawer-group-arrow { transform: rotate(90deg); }

.pages-drawer-group-links {
  display: none; flex-direction: column; padding-left: 8px;
}
.pages-drawer-group.open .pages-drawer-group-links { display: flex; }
.pages-drawer-group-links a {
  font-size: 14px; font-weight: 600; color: var(--ink); text-decoration: none;
  padding: 10px 14px; border-radius: 6px;
}
.pages-drawer-group-links a:hover { background: var(--accent-dim); }

/* Job detail popup modal -- callable from anywhere (Board, Home, Jobs list) */
.job-modal-overlay { display: none; position: fixed; inset: 0; background: rgba(26,26,26,0.55); z-index: 1000; align-items: flex-start; justify-content: center; padding: 24px 14px; overflow-y: auto; }
.job-modal-overlay.open { display: flex; }
.job-modal-card { background: #fff; border-radius: 8px; max-width: 520px; width: 100%; padding: 22px; position: relative; margin-top: 20px; margin-bottom: 40px; }

/* Job detail modal -- two-column layout (right rail: activity + comments).
   Only the job detail modal gets this width; the customer and generic
   modals (separate shells) stay their current narrow width. */
.job-modal-overlay.job-modal-wide .job-modal-card { max-width: 920px; }
.job-modal-grid { display: block; }
.job-modal-main { min-width: 0; }
.job-modal-side { margin-top: 20px; }
@media (min-width: 860px) {
  .job-modal-grid { display: grid; grid-template-columns: 1fr 320px; gap: 28px; align-items: start; }
  .job-modal-side {
    margin-top: 0; position: sticky; top: 0; max-height: calc(100vh - 120px); overflow-y: auto;
    border-left: 1px solid var(--line); padding-left: 24px;
  }
}

/* Activity feed / comments as a dotted timeline instead of flat dividers. */
.job-timeline { position: relative; }
.job-timeline-item { position: relative; padding: 0 0 14px 18px; font-size: 12.5px; }
.job-timeline-item:last-child { padding-bottom: 0; }
.job-timeline-item::before {
  content: ''; position: absolute; left: 0; top: 4px; width: 8px; height: 8px; border-radius: 50%;
  background: var(--line); border: 2px solid var(--paper); box-shadow: 0 0 0 1px var(--line);
}
.job-timeline-item::after {
  content: ''; position: absolute; left: 3px; top: 12px; bottom: -2px; width: 1px; background: var(--line);
}
.job-timeline-item:last-child::after { display: none; }
.job-timeline-item-summary { color: var(--ink); }
.job-timeline-item-meta { font: 400 10px var(--mono); color: #8a8a80; margin-top: 2px; }
.job-timeline-item-comment::before { background: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.job-modal-close { position: absolute; top: 14px; right: 14px; width: 30px; height: 30px; border-radius: 50%; border: 1.5px solid var(--ink); background: #fff; font-size: 14px; font-weight: 700; cursor: pointer; }

.notif-item:hover { background: var(--panel); }

/* Priority job highlight -- Board cards */
.board-card-priority { border-left: 4px solid var(--bad) !important; background: var(--bad-bg); }
.priority-flag { color: var(--bad); }

/* Quick Proof button on Board cards */
.quick-proof-btn { display: inline-flex; align-items: center; gap: 3px; font-size: 9.5px; font-weight: 700; text-decoration: none; color: var(--ink); background: var(--accent-dim); border: 1px solid var(--accent); border-radius: 12px; padding: 2px 8px; }
.quick-proof-btn:hover { background: var(--accent); }
/* The two pills that report a client's actual answer on a proof. Both reuse
   .quick-proof-btn's shape and only change colour, which is the whole point --
   same object, different news. .changes-requested-btn had been referenced by
   board.js since it was written but never actually defined here, so it was
   rendering in the default lime despite the code around it describing it as
   red; the one pill that means "the client is unhappy" looked like every other
   pill on the board. */
.quick-proof-btn.changes-requested-btn { color: var(--bad); background: var(--bad-bg); border-color: var(--bad); }
.quick-proof-btn.changes-requested-btn:hover { background: var(--bad); color: var(--paper); }
.quick-proof-btn.approved-btn { color: var(--ok); background: var(--ok-bg); border-color: var(--ok); }
/* Approved, with work still to do -- green text on the approval's own ground,
   but an amber border so it reads as unfinished at a glance rather than
   blending into the plain approvals beside it. */
.quick-proof-btn.approved-changes-btn { color: var(--ok); background: var(--ok-bg); border-color: var(--warn); }
.quick-proof-btn.approved-changes-btn:hover { background: var(--warn); color: var(--paper); border-color: var(--warn); }
.quick-proof-btn.approved-btn:hover { background: var(--ok); color: var(--paper); }


/* Searchable customer/company dropdowns -- type-to-filter combobox that sits
   on top of a hidden <select>. See makeSearchableSelect() in common.js. */
.searchable-select { position: relative; width: 100%; }
.searchable-select-input {
  width: 100%; padding: 10px 10px; border: 1px solid var(--line); border-radius: 4px;
  font-size: 15px; background: var(--paper); color: var(--ink); font-family: var(--sans);
}
.searchable-select-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.searchable-select-list {
  display: none; position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 30;
  background: #fff; border: 1px solid var(--line); border-radius: 4px;
  max-height: 220px; overflow-y: auto; box-shadow: 0 6px 16px rgba(26,26,26,0.16);
}
.searchable-select-list.open { display: block; }
.searchable-select-item { padding: 9px 10px; font-size: 14.5px; cursor: pointer; border-bottom: 1px solid var(--line); }
.searchable-select-item:last-child { border-bottom: none; }
.searchable-select-item.active, .searchable-select-item:hover { background: var(--accent-dim); }
.searchable-select-item.pinned { font-weight: 700; color: var(--ok); border-top: 1px solid var(--line); }
.searchable-select-empty { padding: 9px 10px; font-size: 13px; color: #8a8372; font-style: italic; }

/* Non-blocking "similar customer already exists" suggestion under a name field */
.dup-customer-hint {
  margin-top: 6px; padding: 8px 10px; background: var(--accent-dim); border: 1px solid var(--accent);
  border-radius: 4px; font-size: 12.5px; align-items: center; flex-wrap: wrap; gap: 6px;
}
.dup-customer-hint button.small { padding: 4px 8px; font-size: 11.5px; }

/* Job detail modal -- action buttons paired two-up instead of stacking five
   full-width buttons in a row. Save changes stays the one full-width,
   high-contrast action; Archive/Delete are visually quieter since they're
   used far less often (Delete keeps its red border regardless, so it's
   never mistaken for a routine action). */
.job-modal-actions-row { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.job-modal-actions-row > a, .job-modal-actions-row > button {
  flex: 1 1 140px; margin-top: 0; text-align: center; text-decoration: none;
  padding: 12px 8px; border-radius: 4px; font-weight: 600; font-size: 13px; cursor: pointer;
  border: 1px solid var(--ink); background: none; color: var(--ink); font-family: var(--sans);
}
.job-modal-actions-row > a:active, .job-modal-actions-row > button:active { transform: scale(0.99); }
.job-modal-actions-row > button.danger { border-color: var(--bad); color: var(--bad); }
.job-modal-actions-row-muted { margin-top: 14px; }
.job-modal-actions-row-muted > a, .job-modal-actions-row-muted > button {
  padding: 9px 8px; font-size: 12px; border-color: var(--line); color: #6b6558;
}
.job-modal-actions-row-muted > button.danger { border-color: var(--bad); color: var(--bad); }

/* Toggle-style checkbox fields (Priority, "price includes tax", etc.) --
   a bordered box matching input/select styling, instead of a bare inline
   checkbox that has no visual anchor and wraps awkwardly on narrow screens. */
.field-toggle {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 4px; background: var(--paper);
  font-size: 13px; font-weight: 600; color: var(--ink); cursor: pointer; user-select: none;
}
.field-toggle input[type="checkbox"] {
  width: 18px; height: 18px; flex-shrink: 0; margin: 0; accent-color: var(--ink); cursor: pointer;
}
.field-toggle span { line-height: 1.3; }
.field-toggle:has(input:checked) { border-color: var(--ink); background: var(--accent-dim); }

/* Sitewide copyright/attribution notice, injected by common.js. Self-styled
   (not just relying on inherited footer styles) so it also looks right on
   pages with no <footer> at all, where it's appended straight to <body>. */
.hsh-copyright-notice {
  text-align: center; font-size: 10.5px; color: #a39c8a; font-family: var(--mono);
  padding: 6px 20px 16px;
}
footer .hsh-copyright-notice { border-top: 1px solid var(--line); margin-top: 8px; padding-top: 10px; }

/* Attachment gallery lightbox -- click a job's thumbnail to page through
   every image in that gallery in-page, instead of one new tab per image. */
.lightbox-overlay {
  display: none; position: fixed; inset: 0; background: rgba(15,15,15,0.92); z-index: 1100;
  align-items: center; justify-content: center; padding: 20px;
}
.lightbox-overlay.open { display: flex; }
.lightbox-img { max-width: 100%; max-height: 88vh; object-fit: contain; border-radius: 4px; }
.lightbox-close {
  position: absolute; top: 16px; right: 16px; width: 36px; height: 36px; border-radius: 50%;
  border: 1.5px solid #fff; background: rgba(255,255,255,0.08); color: #fff; font-size: 16px; font-weight: 700; cursor: pointer;
}
.lightbox-nav {
  position: absolute; top: 50%; transform: translateY(-50%); width: 44px; height: 44px; border-radius: 50%;
  border: 1.5px solid #fff; background: rgba(255,255,255,0.08); color: #fff; font-size: 22px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.lightbox-prev { left: 12px; }
.lightbox-next { right: 12px; }
.lightbox-counter {
  position: absolute; bottom: 18px; left: 50%; transform: translateX(-50%);
  color: #fff; font-size: 12px; font-family: var(--mono); background: rgba(0,0,0,0.4); padding: 4px 10px; border-radius: 10px;
}
@media (max-width: 480px) {
  .lightbox-nav { width: 38px; height: 38px; font-size: 19px; }
  .lightbox-prev { left: 6px; }
  .lightbox-next { right: 6px; }
}

/* Social content calendar -- same month-grid shape as the dashboard's
   .mini-cal-* widget, sized up for a full page and holding post chips
   instead of a single severity dot per day. */
.social-cal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; flex-wrap: wrap; gap: 10px; }
.social-cal-header h3 { margin: 0; font-size: 16px; }
.social-cal-header-controls { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.social-cal-view-toggle { display: flex; border: 1px solid var(--line); border-radius: 4px; overflow: hidden; }
.social-cal-view-toggle button {
  border: none; background: #fff; padding: 6px 12px; font: 600 12px var(--sans); color: var(--sub); cursor: pointer;
}
.social-cal-view-toggle button + button { border-left: 1px solid var(--line); }
.social-cal-view-toggle button.social-cal-view-active { background: var(--ink); color: var(--paper); }
.social-cal-nav { display: flex; gap: 6px; }
.social-cal-nav-arrow { border: 1px solid var(--line); background: #fff; border-radius: 4px; width: 28px; height: 28px; cursor: pointer; font-size: 14px; line-height: 1; padding: 0; }
.social-cal-nav-today {
  border: 1px solid var(--line); background: #fff; border-radius: 4px; height: 28px; padding: 0 12px;
  cursor: pointer; font: 600 12px var(--sans); color: var(--ink); white-space: nowrap;
}
.social-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.social-cal-dow { text-align: center; color: #8a8372; font-weight: 700; font-size: 11px; padding: 4px 0 8px; }
.social-cal-day { min-height: 84px; border: 1px solid var(--line); border-radius: 5px; padding: 5px; background: #fff; display: flex; flex-direction: column; gap: 3px; }
.social-cal-day.social-cal-other-month { background: var(--panel); border-color: var(--panel); }
.social-cal-day.social-cal-other-month .social-cal-day-num { color: #cfc9ba; }
.social-cal-day.social-cal-today { border-color: var(--ink); border-width: 2px; }
.social-cal-day-num { font-size: 11.5px; font-weight: 700; color: #8a8372; }
.social-cal-today .social-cal-day-num { color: var(--ink); }
/* Week view -- 7 columns same as month, but each cell gets much more room
   since there's no other-month dimming and there are only 7 of them. */
.social-cal-grid-week .social-cal-day { min-height: 320px; }
.social-post-chip {
  display: block; width: 100%; text-align: left; border: none; border-radius: 3px; padding: 3px 5px;
  background: var(--accent-dim); color: var(--ink); font-size: 10.5px; line-height: 1.3; cursor: pointer;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.social-post-chip:hover { background: var(--accent); }
/* One glance at the calendar should hint at approval state without opening
   each post -- a left border in the same three colors as the status badges
   (.status-pending/.status-approved/.status-changes_requested) elsewhere. */
.social-post-chip-draft { border-left: 3px solid #b3ada0; padding-left: 4px; }
.social-post-chip-pending_approval { border-left: 3px solid #8a5a1f; padding-left: 4px; }
.social-post-chip-approved { border-left: 3px solid var(--ok); padding-left: 4px; }
.social-post-chip-needs_changes { border-left: 3px solid var(--bad); padding-left: 4px; }
.social-cal-more { font-size: 10px; color: #8a8372; background: none; border: none; cursor: pointer; text-align: left; padding: 2px 5px; }
.social-post-chip[draggable="true"] { cursor: grab; }
.social-post-chip-dragging { opacity: 0.4; }
.social-cal-day-dropping { outline: 2px dashed var(--accent); outline-offset: -2px; background: var(--accent-dim); }
@media (max-width: 720px) {
  .social-cal-grid { gap: 3px; }
  .social-cal-day { min-height: 60px; padding: 3px; }
  .social-cal-dow { font-size: 9.5px; }
  .social-cal-grid-week .social-cal-day { min-height: 160px; }
}

/* Platform picker -- checkboxes styled as toggle chips rather than a bare
   list, since "which platforms" reads faster as a row of pills than a
   vertical checkbox stack. */
.platform-check-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 4px; }
.platform-check { position: relative; }
.platform-check input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.platform-check span {
  display: inline-block; padding: 7px 13px; border: 1px solid var(--line); border-radius: 20px;
  font-size: 12.5px; font-weight: 600; color: #8a8372; background: #fff;
}
.platform-check input:checked + span { background: var(--ink); border-color: var(--ink); color: #fff; }

/* Post-composer media thumbnails */
.post-asset-thumb-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0; }
.post-asset-thumb { position: relative; width: 72px; height: 72px; border-radius: 5px; overflow: hidden; border: 1px solid var(--line); }
.post-asset-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.post-asset-thumb-remove {
  position: absolute; top: 2px; right: 2px; width: 18px; height: 18px; border-radius: 50%;
  background: rgba(0,0,0,0.65); color: #fff; border: none; font-size: 11px; line-height: 1; cursor: pointer;
}
.post-asset-thumb-bg {
  position: absolute; bottom: 2px; left: 2px; min-width: 18px; height: 18px; border-radius: 9px; padding: 0 4px;
  background: rgba(0,0,0,0.65); color: #fff; border: none; font-size: 11px; line-height: 18px; cursor: pointer;
}
.post-asset-thumb-bg:disabled { opacity: 0.6; cursor: default; }
.post-asset-thumb-upscale {
  position: absolute; bottom: 2px; left: 26px; min-width: 18px; height: 18px; border-radius: 9px; padding: 0 4px;
  background: rgba(0,0,0,0.65); color: #fff; border: none; font-size: 11px; line-height: 18px; cursor: pointer;
}
.post-asset-thumb-upscale:disabled { opacity: 0.6; cursor: default; }
/* ===========================================================================
   Social workspace shell -- its own chrome (left rail desktop / bottom tab
   bar mobile), replacing the print all-pages drawer on every social_*.php
   page. See docs/design/social-workspace-brief.md for why. Reuses every
   existing token/component (--ink/--paper/--line/--accent, .card-like
   surfaces, .status-badge, .list-item) rather than inventing a new palette.
   =========================================================================== */

body.social-body { padding-bottom: 0; }

.social-shell { display: flex; min-height: 100vh; }

.social-rail {
  width: 220px; flex-shrink: 0; background: var(--ink); color: var(--paper);
  display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh;
}

.social-rail-switcher { padding: 18px 16px 14px; border-bottom: 1px solid rgba(247,247,245,0.12); }
/* Design Studio has its own client picker, scoped to every company rather
   than only digital/both -- see includes/social_header.php's doc comment. */
.social-hide-company-switcher .social-rail-switcher,
.social-hide-company-switcher .social-mobile-header { display: none; }
.social-rail-switcher-label { font: 700 9.5px var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: #a9a89f; margin-bottom: 6px; }
.social-switcher-select {
  width: 100%; box-sizing: border-box; padding: 8px 10px; border-radius: 5px; border: 1px solid rgba(247,247,245,0.2);
  background: #2a2a27; color: var(--paper); font: 600 13px var(--sans); appearance: none; -webkit-appearance: none;
}
.social-switcher-select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.social-rail-nav { flex: 1; padding: 14px 10px; overflow-y: auto; }
.social-navi {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 12px; margin-bottom: 2px;
  border-radius: 6px; color: #cfcec5; text-decoration: none; font: 600 13.5px var(--sans);
}
.social-navi:hover { background: rgba(247,247,245,0.08); color: var(--paper); }
.social-navi-active { background: var(--accent); color: #1a1a1a; }
.social-navi-badge {
  background: var(--bad); color: #fff; font: 700 10px var(--mono); border-radius: 20px; min-width: 18px;
  height: 18px; display: inline-flex; align-items: center; justify-content: center; padding: 0 5px;
}
.social-navi-active .social-navi-badge { background: #1a1a1a; color: var(--paper); }
.social-rail-section-label {
  font: 700 9.5px var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: #7d7c74;
  margin: 16px 12px 6px;
}

.social-rail-footer { padding: 14px 16px 18px; border-top: 1px solid rgba(247,247,245,0.12); }
.social-rail-identity { display: flex; align-items: center; gap: 9px; margin-bottom: 10px; }
.social-avatar {
  width: 30px; height: 30px; border-radius: 50%; background: var(--accent); color: #1a1a1a;
  font: 700 12px var(--sans); display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.social-rail-identity-text { display: flex; flex-direction: column; min-width: 0; }
.social-rail-name { font: 600 12.5px var(--sans); color: var(--paper); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.social-rail-role { font: 400 10.5px var(--mono); color: #a9a89f; }
.social-rail-switch-print { display: block; font: 600 11.5px var(--sans); color: #cfcec5; text-decoration: none; border-top: 1px solid rgba(247,247,245,0.12); padding-top: 10px; }
.social-rail-switch-print:hover { color: var(--paper); }

.social-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.social-mobile-header { display: none; }

.social-topbar { display: flex; justify-content: space-between; align-items: flex-end; gap: 10px; flex-wrap: wrap; padding: 20px 24px 16px; }
.social-topbar-eyebrow { font: 400 10.5px var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: #8a8372; margin-bottom: 4px; }
.social-topbar h1 { margin: 0; font: 700 22px var(--sans); letter-spacing: -0.01em; color: var(--ink); }
.social-topbar-extra { display: flex; gap: 8px; }

/* .social-content is a <main> element -- override the print-side's generic
   main{} rule (max-width: 640px/1100px/1300px, margin: 0 auto) instead of
   inheriting it, since that's what was shrinking every social page down to
   a centered 640px column regardless of the rail taking the rest. */
.social-content { padding: 20px 24px 32px; flex: 1; max-width: none; margin: 0; width: 100%; box-sizing: border-box; }

.social-panel { background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 18px; margin-bottom: 16px; }
.social-panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.social-panel-header h2 { margin: 0; font: 700 12px var(--mono); letter-spacing: 0.05em; text-transform: uppercase; color: #8a8a80; }

.social-stat-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 16px; }
.social-stat { background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 14px 16px; }
.social-stat-label { display: block; font: 400 9.5px var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: #8a8372; }
.social-stat-value { display: block; font: 700 22px var(--mono); margin-top: 4px; color: var(--ink); }

.social-filter-row { display: flex; gap: 8px; margin-bottom: 14px; flex-wrap: wrap; }
.social-filter-row select {
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 5px; background: var(--paper); color: var(--ink);
  font: 600 12.5px var(--sans);
}

.social-media-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 8px;
  min-height: 90px; border-radius: 8px; transition: background 0.1s, box-shadow 0.1s;
}
/* Every dropzone (the media grid, the brand kit's Logos box) accepts a drop
   at all times, whether it's empty or already full -- not just as an
   empty-state affordance. .social-dropzone-active is toggled during an
   active drag-over via JS (a dragenter/dragleave depth counter, since those
   events fire on every child element too). */
.social-dropzone-active {
  background: var(--accent-dim) !important; box-shadow: inset 0 0 0 2px var(--accent);
}
.social-media-grid > .empty-state { grid-column: 1 / -1; border: 1px dashed var(--line); border-radius: 8px; padding: 28px 12px; }
.social-media-item { aspect-ratio: 1; border-radius: 6px; overflow: hidden; border: 1px solid var(--line); cursor: pointer; background: var(--panel); }
.social-media-item img { width: 100%; height: 100%; object-fit: cover; display: block; }

.social-account-list { display: flex; flex-direction: column; gap: 10px; }
.social-account-row { border: 1px solid var(--line); border-radius: 6px; padding: 12px 14px; }
.social-account-row-main { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.social-account-name { font: 700 13.5px var(--sans); color: var(--ink); }
.social-account-row-note { font: 400 11.5px var(--sans); color: #8a8372; margin-top: 6px; }
.social-account-disconnect {
  margin-top: 8px; padding: 5px 11px; border: 1px solid var(--line); border-radius: 4px; background: #fff;
  color: var(--bad); font: 600 11.5px var(--sans); cursor: pointer;
}

/* Mobile bottom tab bar -- same pattern as .docket-tabbar on the print side. */
.social-tabbar { display: none; }
/* Base hidden state -- must live outside the max-width:899px query below,
   since the mobile menu's markup is always in the DOM (rendered by
   includes/social_footer.php on every page load) regardless of viewport.
   Scoping "display:none" itself to the mobile query left it with no
   display rule at all above 899px, so it rendered as plain unstyled inline
   links at the bottom of the page instead of staying hidden. */
.social-mobile-menu { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 50; }

@media (max-width: 899px) {
  .social-rail { display: none; }
  .social-mobile-header {
    display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--line);
    background: var(--ink);
  }
  .social-mobile-header .social-switcher-select-mobile { flex: 1; }
  .social-mobile-bell { position: relative; font-size: 18px; text-decoration: none; flex-shrink: 0; }
  .social-mobile-bell-badge {
    position: absolute; top: -4px; right: -6px; background: var(--bad); color: #fff; border-radius: 10px;
    min-width: 16px; height: 16px; font: 700 9px var(--mono); display: flex; align-items: center; justify-content: center; padding: 0 3px;
  }
  .social-topbar { padding: 16px 16px 12px; }
  .social-topbar h1 { font-size: 19px; }
  .social-content { padding: 16px 16px 90px; }

  .social-tabbar {
    display: flex; position: fixed; bottom: 0; left: 0; right: 0; z-index: 40;
    border-top: 1px solid var(--line); background: #fff; padding: 9px 8px 14px;
  }
  .social-tab {
    flex: 1; text-align: center; padding: 6px 0; font: 700 10.5px var(--sans); color: #8a8372; text-decoration: none;
    border: none; background: none; cursor: pointer; font-family: inherit;
  }
  .social-tab-glyph { display: block; font: 400 15px var(--mono); margin-bottom: 3px; position: relative; }
  .social-tab-active { color: var(--ink); }
  .social-tab-create .social-tab-glyph { font-size: 19px; }
  .social-tab-glyph-badge-wrap { position: relative; }
  .social-tab-badge {
    position: absolute; top: -3px; right: 16px; min-width: 15px; height: 15px; border-radius: 8px;
    background: var(--bad); color: #fff; font: 700 9px/15px var(--mono); text-align: center;
  }

  .social-mobile-menu.social-mobile-menu-open { display: block; }
  .social-mobile-menu-sheet { position: absolute; bottom: 0; left: 0; right: 0; background: #fff; border-radius: 12px 12px 0 0; padding: 8px 0 20px; }
  .social-mobile-menu-item {
    display: flex; align-items: center; gap: 10px; padding: 14px 20px; font: 600 14px var(--sans); color: var(--ink);
    text-decoration: none;
  }
  .social-mobile-menu-item:active { background: var(--panel); }
  .social-mobile-menu-close { text-align: center; padding: 12px; font: 600 13px var(--sans); color: #8a8372; }

  .social-stat-row { grid-template-columns: repeat(2, 1fr); }
}

/* ===========================================================================
   Library page -- media grid + hashtag sets (main column) and a brand kit
   sidebar, per design/Library.dc.html.
   =========================================================================== */

.social-library-layout { display: flex; gap: 0; align-items: flex-start; }
.social-library-main { flex: 1; min-width: 0; }
.social-library-brandkit {
  width: 300px; flex-shrink: 0; background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  padding: 18px 16px; margin-left: 20px; display: flex; flex-direction: column; gap: 18px;
}

.social-tag-chip {
  font: 600 11.5px var(--sans); padding: 5px 12px; border: 1px solid var(--line); border-radius: 20px;
  background: #fff; color: var(--sub); cursor: pointer;
}
.social-tag-chip-active { border-color: var(--ink); background: var(--panel); color: var(--ink); }

.social-media-item { position: relative; }
.social-media-item-tag {
  position: absolute; bottom: 5px; left: 5px; font: 700 8px var(--mono); background: rgba(26,26,26,0.72);
  color: #f7f7f5; border-radius: 2px; padding: 2px 5px; text-transform: uppercase; letter-spacing: 0.04em;
}
.social-media-item-tag-name { left: auto; right: 5px; background: var(--accent); color: #1a1a1a; }

.social-hashtag-set {
  position: relative; border: 1px solid var(--line); border-radius: 4px; padding: 11px 34px 11px 13px;
  background: var(--panel); margin-bottom: 9px;
}
.social-hashtag-set-name { font: 700 13px var(--sans); color: var(--ink); }
.social-hashtag-set-tags { font-size: 12px; color: #4a6b8a; margin-top: 4px; }
.social-hashtag-set-delete {
  position: absolute; top: 10px; right: 10px; width: 20px; height: 20px; border-radius: 50%; border: none;
  background: none; color: var(--mute); cursor: pointer; font-size: 12px;
}
.social-hashtag-set-delete:hover { background: rgba(0,0,0,0.08); color: var(--bad); }

.social-brandkit-section { display: flex; flex-direction: column; }
.social-brandkit-label {
  font: 700 10px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; color: var(--mute); margin-bottom: 8px;
}
.social-brandkit-logos { display: flex; gap: 8px; flex-wrap: wrap; min-height: 48px; border-radius: 6px; transition: background 0.1s, box-shadow 0.1s; }
.social-brandkit-logo {
  width: 62px; height: 48px; border: 1px solid var(--line); border-radius: 3px; background: #fff; cursor: pointer;
  overflow: hidden;
}
.social-brandkit-logo img { width: 100%; height: 100%; object-fit: contain; display: block; }
.social-brandkit-palette { display: flex; gap: 7px; flex-wrap: wrap; }
.social-swatch { flex: 1; min-width: 54px; position: relative; }
.social-swatch-color { height: 38px; border-radius: 3px; border: 1px solid var(--line); }
.social-swatch-hex { font: 400 8.5px var(--mono); color: var(--mute); margin-top: 4px; text-align: center; }
.social-swatch-remove {
  position: absolute; top: -6px; right: -6px; width: 16px; height: 16px; border-radius: 50%; border: none;
  background: var(--ink); color: #fff; font-size: 9px; line-height: 1; cursor: pointer;
}
.social-brandkit-section textarea {
  width: 100%; box-sizing: border-box; background: #fff; border: 1px solid var(--line); border-radius: 4px;
  padding: 10px; font: 400 12px var(--sans); color: var(--sub); resize: vertical;
}
.social-brandkit-text {
  background: #fff; border: 1px solid var(--line); border-radius: 4px; padding: 11px; font-size: 12px;
  line-height: 1.6; color: var(--sub);
}
.social-brandkit-text-bad { background: var(--bad-bg); color: var(--bad); border: none; }

@media (max-width: 899px) {
  .social-library-layout { flex-direction: column; }
  .social-library-brandkit { width: 100%; margin-left: 0; margin-top: 20px; }
}

/* ===========================================================================
   Content briefs -- a named batch of posts reviewed together in one round.
   =========================================================================== */

.social-brief-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }
.social-brief-card {
  display: block; background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 16px;
  text-decoration: none; color: inherit;
}
.social-brief-card:hover { border-color: var(--ink); }
.social-brief-card-name { font: 700 14.5px var(--sans); color: var(--ink); }
.social-brief-card-meta { display: flex; align-items: center; gap: 8px; margin-top: 8px; font: 400 12px var(--sans); color: #8a8372; }

.social-brief-back { display: inline-block; margin-bottom: 14px; font: 600 12.5px var(--sans); color: var(--ink); text-decoration: none; border-bottom: 2px solid var(--accent); }

.social-brief-post-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; margin-top: 16px; }
.social-brief-post-card {
  background: #fff; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; cursor: pointer; position: relative;
}
.social-brief-post-card:hover { border-color: var(--ink); }
.social-brief-post-thumb { aspect-ratio: 1; background: var(--panel); }
.social-brief-post-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.social-brief-post-noimg { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; font: 400 11px var(--mono); color: #b3ad9c; }
.social-brief-post-body { padding: 10px; }
.social-brief-post-caption { font: 400 12.5px var(--sans); color: var(--ink); line-height: 1.4; }
.social-brief-post-remove {
  position: absolute; top: 8px; right: 8px; width: 22px; height: 22px; border-radius: 50%; border: none;
  background: rgba(26,26,26,0.7); color: #fff; font-size: 11px; cursor: pointer;
}

/* Comments thread -- inside the composer/review modals, once a post has an id. */
.post-comments-field { margin-top: 4px; }
.post-comments-thread { max-height: 220px; overflow-y: auto; border: 1px solid var(--line); border-radius: 4px; padding: 8px 10px; background: var(--paper); margin-bottom: 8px; }
.post-comment { padding: 7px 0; border-bottom: 1px solid var(--line); }
.post-comment:last-child { border-bottom: none; }
.post-comment-meta { font: 400 10.5px var(--mono); color: #8a8372; display: flex; justify-content: space-between; gap: 8px; }
.post-comment-meta strong { color: var(--ink); font-family: var(--sans); font-weight: 700; }
.post-comment-body { font-size: 12.5px; color: var(--ink); margin-top: 2px; white-space: pre-wrap; }
.post-comment-internal .post-comment-meta strong { color: #4a6b8a; }
.post-comment-client .post-comment-meta strong { color: #8a5a1f; }
.post-comment-add { display: flex; gap: 8px; align-items: flex-end; }
.post-comment-add textarea { flex: 1; font-family: var(--sans); font-size: 12.5px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 4px; resize: vertical; }

/* ===========================================================================
   Monthly recap / team report -- print-to-PDF via the browser's own print
   dialog rather than a server-side PDF library (none exists in this
   codebase yet). Hides everything but the report content when printing.
   =========================================================================== */
@media print {
  .social-rail, .social-topbar, .social-tabbar, .social-mobile-header, #statusBar, .social-recap-actions .social-cal-header-controls { display: none !important; }
  .social-content { padding: 0 !important; }
  .social-shell, .social-main { display: block !important; }
}

/* Content proposal cards -- the text items inside a brief, replacing the
   earlier image-grid-of-posts layout now that a brief holds copy, not
   full posts (see includes/db.php's content_brief_items schema comment). */
.social-brief-item-card { cursor: pointer; margin-bottom: 12px; }
.social-brief-item-card:hover { border-color: var(--ink); }
.social-brief-item-header { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.social-brief-item-title { font: 700 14px var(--sans); color: var(--ink); }
.social-brief-item-body { font-size: 13px; color: var(--sub); line-height: 1.5; white-space: pre-wrap; }

/* Internal QA gate row -- inside the post composer, before Send for
   approval is even offered. See api/social_posts.php's markQaPassed. */
.social-qa-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 0 0 14px;
  padding: 9px 12px; border-radius: 4px; background: var(--warn-bg); color: var(--warn); font: 600 12.5px var(--sans);
}
.social-qa-row-passed { background: var(--ok-bg); color: var(--ok); }


/* ---------------------------------------------------------------------------
   Monthly company report (company_report.php) -- an on-screen render of the
   same statement the PDF export produces, so what staff preview is what the
   client receives. Status colours are their own small set rather than the
   app's generic --ok/--bad: these three sit side by side in one stacked bar,
   so they were picked to stay separable under colour-vision deficiency as
   well as in print. Every segment is direct-labelled underneath regardless,
   so the bar never carries meaning by colour alone.
--------------------------------------------------------------------------- */
.report-sheet { --rep-wip: #2f5fa8; --rep-review: #c47a08; --rep-approved: #1d7a4c; background: #fff; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }

.report-masthead { background: var(--ink); color: var(--paper); padding: 24px 26px 0; }
.report-mast-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 20px; flex-wrap: wrap; padding-bottom: 20px; }
.report-issuer { font: 500 10.5px var(--mono); letter-spacing: 0.18em; text-transform: uppercase; color: #8a8372; }
.report-title { font: 700 25px var(--sans); letter-spacing: -0.02em; margin: 7px 0 0; text-wrap: balance; }
.report-for { font-size: 13.5px; color: #8a8372; margin-top: 5px; }
.report-for strong { color: var(--paper); font-weight: 600; }
.report-period { text-align: right; font-family: var(--mono); flex-shrink: 0; }
.report-period .lbl { font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: #8a8372; }
.report-period .val { font-size: 18px; font-weight: 700; margin-top: 4px; }

.report-kpis { display: grid; grid-template-columns: repeat(5, 1fr); border-top: 1px solid #333330; }
.report-kpi { padding: 15px 16px 17px; border-right: 1px solid #333330; }
.report-kpi:last-child { border-right: 0; }
.report-kpi-label { font: 400 9.5px var(--mono); letter-spacing: 0.13em; text-transform: uppercase; color: #8a8372; }
.report-kpi-value { font: 700 29px var(--mono); line-height: 1.05; margin-top: 7px; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.report-kpi-value .unit { font-size: 14px; font-weight: 500; color: #8a8372; margin-left: 2px; }
.report-kpi-delta { font: 400 10.5px var(--mono); margin-top: 6px; color: #8a8372; font-variant-numeric: tabular-nums; }
.report-kpi-delta .arrow { font-weight: 700; }
.report-kpi-delta.is-up .arrow { color: var(--accent); }
.report-kpi-delta.is-down .arrow { color: #e0a99c; }

.report-body { padding: 0 26px 30px; }
.report-section { padding-top: 28px; }
.report-sec-head { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; flex-wrap: wrap; border-bottom: 2.5px solid var(--ink); padding-bottom: 7px; }
.report-sec-head h3 { margin: 0; font: 700 16px var(--sans); letter-spacing: -0.01em; }
.report-sec-head .note { font: 400 10.5px var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: #8a8372; }
.report-lede { color: #4a463e; font-size: 13.5px; margin: 12px 0 0; max-width: 64ch; }

.report-bar { display: flex; width: 100%; height: 28px; gap: 2px; background: var(--panel); border-radius: 3px; overflow: hidden; margin-top: 16px; }
/* Flex proportions, not percentage widths -- percentages plus the 2px gaps
   overflow the track and silently clip the last segment. */
.report-bar span { display: block; height: 100%; min-width: 2px; }
.report-bar .seg-wip { background: var(--rep-wip); }
.report-bar .seg-review { background: var(--rep-review); }
.report-bar .seg-approved { background: var(--rep-approved); }

.report-key { display: flex; flex-wrap: wrap; gap: 9px 24px; margin-top: 13px; }
.report-key-item { display: flex; align-items: baseline; gap: 8px; }
.report-key-swatch { width: 11px; height: 11px; border-radius: 2.5px; flex-shrink: 0; transform: translateY(1px); }
.report-key-swatch.seg-wip { background: var(--rep-wip); }
.report-key-swatch.seg-review { background: var(--rep-review); }
.report-key-swatch.seg-approved { background: var(--rep-approved); }
.report-key-count { font: 700 16px var(--mono); font-variant-numeric: tabular-nums; }
.report-key-label { font-size: 13px; color: #4a463e; }

.report-callout { margin-top: 18px; padding: 12px 15px; background: var(--panel); border-left: 3px solid var(--rep-review); border-radius: 0 4px 4px 0; font-size: 13px; color: #4a463e; }
.report-callout strong { color: var(--ink); }

.report-table-wrap { margin-top: 16px; overflow-x: auto; }
.report-table { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 640px; }
.report-table thead th { text-align: left; padding: 0 11px 7px 0; font: 500 9.5px var(--mono); letter-spacing: 0.13em; text-transform: uppercase; color: #8a8372; border-bottom: 1px solid var(--line); white-space: nowrap; }
.report-table tbody td { padding: 9px 11px 9px 0; border-bottom: 1px solid var(--line); vertical-align: baseline; }
.report-table tbody tr:last-child td { border-bottom: 0; }
.report-c-num { font: 700 13px var(--mono); white-space: nowrap; font-variant-numeric: tabular-nums; }
.report-c-date, .report-c-proofs { font-family: var(--mono); color: #4a463e; white-space: nowrap; font-variant-numeric: tabular-nums; }
.report-c-proofs, .report-table thead th.report-c-proofs { text-align: center; }
.report-c-dash { color: #8a8372; }
.report-c-desc { min-width: 180px; }
.report-c-cust { font-size: 12px; color: #8a8372; }

.report-pill { display: inline-flex; align-items: center; gap: 6px; font: 500 10.5px var(--mono); letter-spacing: 0.04em; white-space: nowrap; padding: 3px 9px 3px 7px; border-radius: 100px; border: 1px solid currentColor; }
.report-pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.report-pill-wip { color: var(--rep-wip); }
.report-pill-review { color: var(--rep-review); }
.report-pill-approved { color: var(--rep-approved); }

.report-foot { padding: 16px 26px 22px; border-top: 2.5px solid var(--ink); font-size: 12px; color: #8a8372; }

@media (max-width: 760px) {
  .report-kpis { grid-template-columns: repeat(2, 1fr); }
  .report-kpi { border-bottom: 1px solid #333330; }
  .report-kpi:nth-child(even) { border-right: 0; }
  .report-kpi:last-child { grid-column: 1 / -1; border-bottom: 0; }
  .report-masthead { padding: 20px 18px 0; }
  .report-body { padding: 0 18px 24px; }
  .report-foot { padding: 14px 18px 20px; }
  .report-period { text-align: left; }
}


/* Per-platform publish status -- inside a finalized post's locked view. */
.social-publish-row {
  display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--line);
  font: 600 13px var(--sans); color: var(--ink);
}
.social-publish-row:last-child { border-bottom: none; }
.social-publish-row a { margin-left: auto; font: 600 12px var(--sans); color: var(--ink); text-decoration: none; border-bottom: 2px solid var(--accent); }
.social-publish-row button[data-publish-platform] { margin-left: auto; }

/* ===========================================================================
   Design Studio -- an in-portal Fabric.js canvas so the graphics team builds
   the actual visual here instead of designing elsewhere and uploading a
   flattened result. See api/social_designs.php for the soft-lock
   collaboration model this UI reflects (claim/heartbeat/read-only banner).
   =========================================================================== */

/* Standalone page (design_studio.php uses a plain <header>, not Social's
   shell) -- override the print-side's generic `main { max-width: ... }` the
   same way .social-content does, since the editor needs the full width. */
.social-design-main { padding: 20px 24px 32px; max-width: none; margin: 0; width: 100%; box-sizing: border-box; }

.social-design-back-btn {
  width: 34px; height: 34px; border-radius: 8px; border: 1px solid var(--line); background: #fff; cursor: pointer;
  font-size: 16px; display: flex; align-items: center; justify-content: center; color: var(--ink); flex-shrink: 0; text-decoration: none;
}
.social-design-back-btn:hover { border-color: var(--ink); }

/* Design Studio's own control vocabulary -- one button, one chip, one field,
   all sized around a 16px inline SVG plus a label. The page used to lean on
   the print side's full-width button.primary/.secondary with per-element
   inline width/padding overrides, which is why nothing lined up; these are
   compact by default instead of being talked down to size at each call site. */
.ds-icon { display: block; flex-shrink: 0; }
.ds-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px; width: auto; margin: 0;
  padding: 9px 14px; border-radius: 8px; border: 1px solid transparent; cursor: pointer;
  font: 700 12.5px var(--sans); letter-spacing: 0.01em; white-space: nowrap; color: var(--ink);
  transition: background 0.12s ease, border-color 0.12s ease, transform 0.08s ease;
}
.ds-btn:active:not(:disabled) { transform: scale(0.98); }
.ds-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.ds-btn-ghost { background: #fff; border-color: var(--line); }
.ds-btn-ghost:hover:not(:disabled) { border-color: var(--ink); background: var(--paper); }
.ds-btn-ghost.active { background: var(--accent-dim); border-color: var(--accent); }
.ds-btn-primary { background: var(--ink); color: var(--paper); }
.ds-btn-primary:hover:not(:disabled) { background: #000; }

.ds-library-head {
  background: #fff; border: 1px solid var(--line); border-radius: 12px; padding: 16px 18px; margin-bottom: 18px;
}
.ds-library-headline { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.ds-library-title { font: 700 17px var(--sans); letter-spacing: -0.01em; margin: 0; }
.ds-library-sub { font: 400 12.5px var(--sans); color: #8a8372; line-height: 1.5; margin: 5px 0 0; max-width: 62ch; }
.ds-library-actions { display: flex; gap: 8px; flex-shrink: 0; }
.ds-library-filters {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line);
}
.ds-field { display: flex; align-items: center; gap: 8px; }
.ds-field label { font: 700 10.5px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; color: #8a8372; }
.ds-field select {
  font: 600 13px var(--sans); padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px;
  background: #fff; color: var(--ink); min-width: 190px;
}
.ds-search { position: relative; display: flex; align-items: center; flex: 1; min-width: 200px; max-width: 340px; }
.ds-search .ds-icon { position: absolute; left: 11px; color: #8a8372; pointer-events: none; }
.ds-search input {
  width: 100%; font: 400 13px var(--sans); padding: 8px 12px 8px 34px; border: 1px solid var(--line);
  border-radius: 8px; background: #fff; color: var(--ink); appearance: none; -webkit-appearance: none;
}
.ds-search input:focus { outline: none; border-color: var(--ink); }
.ds-chips { display: flex; gap: 4px; padding: 3px; background: var(--panel); border-radius: 9px; }
.ds-chip {
  border: none; background: none; cursor: pointer; padding: 6px 12px; border-radius: 7px;
  font: 700 11.5px var(--sans); color: #6f6a5e; white-space: nowrap;
}
.ds-chip:hover { color: var(--ink); }
.ds-chip.active { background: #fff; color: var(--ink); box-shadow: 0 1px 2px rgba(26,26,26,0.09); }
.ds-btn-tiny { padding: 4px 10px; font-size: 11.5px; border-radius: 6px; margin-left: 8px; }

/* ---------------------------------------------------------------------------
   Right-click menu on the canvas. Fixed-positioned and appended to <body> so
   it is never clipped by the canvas wrapper's own overflow, and so it can be
   placed straight at the pointer.
--------------------------------------------------------------------------- */
.ds-ctxmenu {
  position: fixed; z-index: 900; min-width: 232px; padding: 6px; background: #fff;
  border: 1px solid var(--line); border-radius: 12px; box-shadow: 0 12px 34px rgba(26,26,26,0.18);
}
.ds-ctxmenu-item {
  display: flex; align-items: center; gap: 11px; width: 100%; padding: 8px 10px; border: none;
  background: none; cursor: pointer; border-radius: 8px; color: var(--ink); text-align: left;
  font: 500 13px var(--sans);
}
.ds-ctxmenu-item:hover:not(:disabled) { background: var(--paper); }
.ds-ctxmenu-item:disabled { opacity: 0.35; cursor: default; }
.ds-ctxmenu-item .ds-icon { color: #5c5648; }
.ds-ctxmenu-label { flex: 1; white-space: nowrap; }
.ds-ctxmenu-key { font: 500 10.5px var(--mono); color: #8a8372; background: var(--panel); padding: 2px 6px; border-radius: 4px; }
.ds-ctxmenu-sep { height: 1px; background: var(--line); margin: 5px 8px; }

/* ---------------------------------------------------------------------------
   Colour panel -- opened from the properties panel's colour rows and from the
   canvas menu's "Background colour". Same fixed/body-level treatment as the
   context menu, for the same reason.
--------------------------------------------------------------------------- */
.ds-color-btn {
  display: flex; align-items: center; gap: 9px; width: 100%; padding: 7px 9px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 8px; background: #fff; font: 600 12px var(--mono); color: var(--ink);
}
.ds-color-btn:hover { border-color: var(--ink); }
.ds-color-btn-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The chequerboard shows through a transparent or absent fill, so "no fill"
   never looks like "white fill". */
.ds-color-chip {
  width: 22px; height: 22px; border-radius: 6px; flex-shrink: 0;
  box-shadow: inset 0 0 0 1px rgba(26,26,26,0.16);
}
.ds-color-chip.lg { width: 30px; height: 30px; border-radius: 8px; }

.ds-colorpop {
  position: fixed; z-index: 950; width: 300px; max-height: min(70vh, 620px); overflow-y: auto;
  padding: 12px; background: #fff; border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 14px 40px rgba(26,26,26,0.2);
}
.ds-colorpop-head { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.ds-colorpop-hex {
  flex: 1; min-width: 0; font: 600 12.5px var(--mono); text-transform: uppercase; padding: 7px 9px;
  border: 1px solid var(--line); border-radius: 7px; background: #fff; color: var(--ink);
}
.ds-colorpop-hex:focus { outline: none; border-color: var(--ink); }
/* The native picker is the escape hatch, not the main event: the OS dialog
   hides behind a small + button rather than being the first thing offered. */
.ds-colorpop-native {
  position: relative; width: 30px; height: 30px; flex-shrink: 0; display: flex; align-items: center;
  justify-content: center; border: 1px solid var(--line); border-radius: 7px; cursor: pointer; color: var(--ink);
}
.ds-colorpop-native:hover { border-color: var(--ink); }
.ds-colorpop-native input[type="color"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; padding: 0; border: none; }
.ds-colorpop-close {
  width: 30px; height: 30px; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
  border: none; background: none; border-radius: 7px; cursor: pointer; color: #8a8372;
}
.ds-colorpop-close:hover { background: var(--panel); color: var(--ink); }
.ds-colorpop-section { margin-bottom: 14px; }
.ds-colorpop-section:last-child { margin-bottom: 0; }
.ds-colorpop-title {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 7px;
  font: 700 10px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; color: #8a8372;
}
.ds-swatch-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; margin-bottom: 6px; }
.ds-swatch-grid:last-child { margin-bottom: 0; }
.ds-swatch {
  aspect-ratio: 1; width: 100%; border: none; border-radius: 50%; cursor: pointer; padding: 0;
  box-shadow: inset 0 0 0 1px rgba(26,26,26,0.16); transition: transform 0.08s ease;
}
.ds-swatch:hover { transform: scale(1.12); }
.ds-grad-dirs { display: flex; gap: 3px; }
.ds-grad-dir { width: 22px; height: 22px; padding: 0; border: 1px solid transparent; border-radius: 5px; background: none; cursor: pointer; display: flex; align-items: center; justify-content: center; }
.ds-grad-dir:hover { border-color: var(--line); }
.ds-grad-dir.active { border-color: var(--ink); }
.ds-grad-dir-chip { width: 14px; height: 14px; border-radius: 3px; display: block; box-shadow: inset 0 0 0 1px rgba(26,26,26,0.16); }
.ds-grad-dir-down { background: linear-gradient(180deg, #1a1a1a, #d8d8d2); }
.ds-grad-dir-right { background: linear-gradient(90deg, #1a1a1a, #d8d8d2); }
.ds-grad-dir-diagonal { background: linear-gradient(135deg, #1a1a1a, #d8d8d2); }
.ds-grad-dir-radial { background: radial-gradient(circle, #1a1a1a, #d8d8d2); }

.social-design-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(212px, 1fr)); gap: 16px; }
.social-design-card {
  position: relative; display: flex; flex-direction: column; background: #fff; border: 1px solid var(--line);
  border-radius: 10px; overflow: hidden; color: inherit;
  transition: border-color 0.12s ease, box-shadow 0.12s ease, transform 0.12s ease;
}
.social-design-card:hover { border-color: #c3c1b6; box-shadow: 0 6px 18px rgba(26,26,26,0.07); transform: translateY(-1px); }
.social-design-card-link { display: flex; flex-direction: column; flex: 1; text-decoration: none; color: inherit; }
/* Checkerboard behind the thumbnail so a design saved on a transparent or
   near-white background still reads as artwork rather than an empty card. */
.social-design-card-thumb {
  aspect-ratio: 4 / 3; display: flex; align-items: center; justify-content: center; padding: 10px;
  background-color: #f2f1ec;
  background-image: linear-gradient(45deg, #e7e6e0 25%, transparent 25%, transparent 75%, #e7e6e0 75%),
                    linear-gradient(45deg, #e7e6e0 25%, transparent 25%, transparent 75%, #e7e6e0 75%);
  background-size: 16px 16px; background-position: 0 0, 8px 8px;
  border-bottom: 1px solid var(--line); overflow: hidden;
}
/* min-height:0 matters: without it a portrait thumbnail's intrinsic height
   wins over the box's aspect-ratio and every card in the row ends up a
   different height. */
.social-design-card-thumb img {
  max-width: 100%; max-height: 100%; min-height: 0; width: auto; height: auto;
  object-fit: contain; display: block; box-shadow: 0 1px 4px rgba(26,26,26,0.14);
}
.social-design-card-thumb span { font: 400 11px var(--mono); color: #a8a396; }
.social-design-card-body { padding: 11px 13px 13px; }
.social-design-card-title { font: 700 13.5px var(--sans); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Attribution line -- who made it, who last touched it, when. The list shows
   the whole team's work for a client, so the card has to say whose it is. */
.social-design-card-byline {
  font: 400 11.5px var(--sans); color: #8a8372; margin-top: 4px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ds-card-client {
  display: inline-block; font: 700 10px var(--mono); text-transform: uppercase; letter-spacing: 0.06em;
  color: #5c5648; background: var(--panel); border-radius: 4px; padding: 2px 6px; margin-right: 6px;
}
.social-design-card-meta { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.social-design-card-meta .status-badge { display: inline-flex; align-items: center; gap: 4px; text-transform: none; letter-spacing: 0; }
/* Hover-revealed on a pointer, always visible on touch (where there's no
   hover to reveal them with) -- see the coarse-pointer rule below. */
.social-design-card-actions { position: absolute; top: 9px; right: 9px; display: flex; gap: 5px; opacity: 0; transition: opacity 0.12s ease; }
.social-design-card:hover .social-design-card-actions,
.social-design-card:focus-within .social-design-card-actions { opacity: 1; }
.social-design-card-action {
  width: 27px; height: 27px; border-radius: 7px; border: none; display: flex; align-items: center; justify-content: center;
  background: rgba(26,26,26,0.74); color: #fff; cursor: pointer; line-height: 1; backdrop-filter: blur(2px);
}
.social-design-card-action:hover { background: var(--ink); }
.social-design-card-action.danger:hover { background: var(--bad); }
.social-design-card-action.starred { background: #c98a1f; opacity: 1; }
.social-design-card:has(.starred) .social-design-card-actions { opacity: 1; }
@media (hover: none) {
  .social-design-card-actions { opacity: 1; }
}

.social-design-version-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--line); font: 400 13px var(--sans); }
.social-design-version-row:last-child { border-bottom: none; }
.social-design-version-meta { min-width: 0; }

.social-design-editor { display: flex; flex-direction: column; gap: 10px; }
.social-design-topbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.social-design-title-input {
  font: 700 17px var(--sans); color: var(--ink); border: none; border-bottom: 2px solid transparent; background: none;
  padding: 4px 2px; min-width: 160px; flex: 1;
}
.social-design-title-input:hover, .social-design-title-input:focus { border-bottom-color: var(--accent); outline: none; }
.social-design-lockbanner {
  display: inline-flex; align-items: center; gap: 6px;
  font: 600 12.5px var(--sans); color: var(--warn); background: var(--warn-bg); padding: 6px 12px; border-radius: 6px; white-space: nowrap;
}
.social-design-topbar-actions { display: flex; gap: 7px; margin-left: auto; flex-wrap: wrap; }
.social-design-topbar-actions button { width: auto; }
.social-design-template-active { background: var(--accent-dim) !important; border-color: var(--accent) !important; }

.social-design-toolbar {
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap; background: #fff; border: 1px solid var(--line);
  border-radius: 10px; padding: 6px 8px;
}
.social-design-toolbar button, .social-design-tool {
  width: 36px; height: 36px; border-radius: 8px; border: 1px solid transparent; background: none; cursor: pointer;
  padding: 0; display: flex; align-items: center; justify-content: center; color: var(--ink); transition: background 0.1s;
}
/* The one text control in a row of icons (Fit) -- kept in the same 36px
   rhythm rather than sitting taller than its neighbours. */
.social-design-tool-text { width: auto !important; padding: 0 12px !important; font: 700 12px var(--sans) !important; }
.social-design-toolbar button:hover, .social-design-tool:hover { background: var(--panel); }
.social-design-tool.active { background: var(--accent-dim); border-color: var(--accent); }
.social-design-toolbar-sep { width: 1px; height: 24px; background: var(--line); margin: 0 5px; }
.social-design-zoom-label { font: 600 11.5px var(--mono); color: #8a8372; min-width: 42px; text-align: center; }

/* Small square toggle/action buttons inside the properties panel -- bold/
   italic/underline/strike, text-align, and the multi-select align grid.
   Same visual language as .social-design-tool (the top toolbar) but sized
   down to fit several in a row within the 240px-wide panel. */
.social-design-icon-btn {
  width: 30px; height: 30px; border-radius: 6px; border: 1px solid var(--line); background: #fff; cursor: pointer;
  font: 600 13px var(--sans); display: flex; align-items: center; justify-content: center; color: var(--ink);
}
.social-design-icon-btn:hover { border-color: var(--ink); }
.social-design-icon-btn.active { background: var(--accent-dim); border-color: var(--accent); }
.social-design-icon-row { display: flex; gap: 6px; }
.social-design-align-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-bottom: 14px; }
.social-design-align-grid .social-design-icon-btn { width: 100%; }

/* Text-align bars (3 lines of varying width, justified per direction) and
   the bullet-list icon (dot + line, twice) -- drawn from plain divs rather
   than a font glyph or emoji, so they render identically everywhere instead
   of depending on which symbols a given OS/font happens to cover. */
.social-design-align-bars { display: flex; flex-direction: column; gap: 2px; width: 15px; }
.social-design-align-bars i { display: block; height: 2px; border-radius: 1px; background: currentColor; }
.social-design-align-bars i:nth-child(1) { width: 100%; }
.social-design-align-bars i:nth-child(2) { width: 65%; }
.social-design-align-bars i:nth-child(3) { width: 85%; }
.social-design-align-left i { align-self: flex-start; }
.social-design-align-center i { align-self: center; }
.social-design-align-right i { align-self: flex-end; }
.social-design-align-justify i { width: 100%; }

.social-design-bullet-icon { display: flex; flex-direction: column; gap: 3px; width: 16px; }
.social-design-bullet-icon i { display: flex; align-items: center; height: 2px; }
.social-design-bullet-icon i::before { content: ''; width: 3px; height: 3px; border-radius: 50%; background: currentColor; margin-right: 3px; flex-shrink: 0; }
.social-design-bullet-icon i::after { content: ''; flex: 1; height: 2px; border-radius: 1px; background: currentColor; }

/* Group/Ungroup toolbar icon -- two small squares, overlapping when
   "grouped" and apart when "ungrouped", same draw-it-with-divs reasoning
   as the align bars above. */
.social-design-group-icon { display: flex; align-items: center; }
.social-design-group-icon i { display: block; width: 11px; height: 11px; border: 1.6px solid currentColor; border-radius: 2px; background: #fff; }
.social-design-group-icon.grouped i:last-child { margin-left: -6px; }
.social-design-group-icon.ungrouped i:last-child { margin-left: 3px; }

/* Layers tab -- top of the stack listed first, matching every other layers
   panel. Visibility/lock toggles plus simple one-step up/down reordering
   (see social_design.js's renderLayersTab() for why not drag-and-drop). */
.social-design-layers-list { display: flex; flex-direction: column; gap: 2px; }
.social-design-layer-row { display: flex; align-items: center; gap: 4px; padding: 5px 6px; border-radius: 6px; cursor: pointer; }
.social-design-layer-row:hover { background: var(--panel); }
.social-design-layer-row.active { background: var(--accent-dim); }
.social-design-layer-icon { display: flex; align-items: center; justify-content: center; width: 18px; flex-shrink: 0; color: #8a8372; }
.ds-layer-type-letter { font: 700 13px var(--sans); line-height: 1; }
.social-design-layer-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 600 12px var(--sans); color: var(--ink); }
.social-design-layer-btn { width: 22px; height: 22px; border: none; background: none; cursor: pointer; font-size: 11px; border-radius: 4px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
.social-design-layer-btn:hover { background: #fff; }
.social-design-layer-btn:disabled { opacity: 0.3; cursor: default; }

/* Boards strip -- multiple pages inside one design, all sharing its
   width/height (see assets/social_design.js's dsBoards). */
.social-design-boards { display: flex; align-items: center; gap: 8px; overflow-x: auto; padding: 2px 2px 6px; }
.social-design-board-thumb {
  position: relative; flex-shrink: 0; width: 52px; height: 52px; border-radius: 6px; border: 2px solid var(--line);
  background: #fff; cursor: pointer; padding: 0; overflow: hidden; display: flex; align-items: center; justify-content: center;
}
.social-design-board-thumb img { width: 100%; height: 100%; object-fit: contain; }
.social-design-board-thumb.active { border-color: var(--accent); }
.social-design-board-num { font: 700 14px var(--mono); color: #8a8372; }
.social-design-board-dup, .social-design-board-delete {
  position: absolute; top: 2px; width: 17px; height: 17px; border-radius: 50%; background: rgba(0,0,0,0.68);
  color: #fff; display: flex; align-items: center; justify-content: center;
}
.social-design-board-dup { right: 21px; }
.social-design-board-delete { right: 2px; }
.social-design-board-add {
  flex-shrink: 0; width: 52px; height: 52px; border-radius: 6px; border: 1.5px dashed var(--line); background: var(--paper);
  cursor: pointer; font: 700 20px var(--sans); color: #8a8372;
}
.social-design-board-add:hover { border-color: var(--ink); color: var(--ink); }

.social-design-body { display: flex; gap: 14px; align-items: flex-start; }
.social-design-canvas-wrap {
  flex: 1; min-width: 0; background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  padding: 20px; display: flex; align-items: center; justify-content: center; overflow: auto; min-height: 420px;
  /* A fixed viewport rather than a box that grows with whatever is inside
     it. It used to take its height from the canvas, which meant there was
     no such thing as "the space available" to fit a design into (Fit could
     only ever measure width), and zooming in pushed the whole page longer
     instead of scrolling within the pane. Same viewport-relative cap the
     sidebar and properties panels already use. */
  height: calc(100vh - 280px);
  position: relative; /* anchors .social-design-pins-layer's absolute positioning */
}
.social-design-canvas-wrap canvas { box-shadow: 0 2px 14px rgba(0,0,0,0.15); }

/* Pin comments -- plain DOM markers, not Fabric objects, positioned by hand
   from Fabric's own canvas.wrapperEl.offsetLeft/offsetTop + pinX/Y*zoom (see
   social_design.js's renderCommentPins() for why: a Fabric object would risk
   leaking into saved canvasJson or an exported PNG/PDF if any one of the
   several toJSON()/toDataURL() call sites ever forgot to filter it out; a
   DOM layer can't leak into either by construction). pointer-events:none on
   the layer itself so it never blocks canvas drag/click; each marker turns
   it back on so the marker itself stays clickable. */
.social-design-pins-layer { position: absolute; inset: 0; pointer-events: none; }
.social-design-pin {
  position: absolute; width: 22px; height: 22px; margin: -22px 0 0 -3px; /* tip points at the exact spot */
  border-radius: 50% 50% 50% 4px; transform: rotate(-45deg); background: #c98a1f; border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,0.35); cursor: pointer; pointer-events: auto;
  display: flex; align-items: center; justify-content: center;
}
.social-design-pin span { transform: rotate(45deg); color: #fff; font: 700 10px var(--mono); }
.social-design-pin.resolved { background: #8a8372; opacity: 0.6; }
.social-design-pin:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.5); }
.social-design-pin-placing { cursor: crosshair !important; }
.social-design-pin-placing canvas { cursor: crosshair !important; }
.social-design-props {
  width: 240px; flex-shrink: 0; background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 4px;
  /* Was a flat 640px cap -- fine back when this sat inside Social's own
     scrollable shell, but on design_studio.php's plain page (more vertical
     room to actually use, especially for a long list like Stock photos
     results) that read as an oddly short box on anything but a small
     screen. Grows with the viewport instead, same idea as the sidebar
     panel below. */
  max-height: calc(100vh - 280px); overflow-y: auto;
}
.social-design-props .field { padding: 10px 12px; margin: 0; }
.social-design-props .field label { display: block; font: 600 11px var(--mono); text-transform: uppercase; letter-spacing: 0.06em; color: #8a8372; margin-bottom: 4px; }

/* Sidebar -- a narrow icon rail (Elements/Text/Photos/Templates/Tools) plus
   a wider flyout panel for whichever one is active, mirroring Canva's own
   app-level rail rather than a horizontal row of text tabs across the top. */
.social-design-sidebar {
  width: 300px; flex-shrink: 0; background: #fff; border: 1px solid var(--line); border-radius: 8px;
  overflow: hidden; align-self: stretch; display: flex;
}
.social-design-rail {
  width: 68px; flex-shrink: 0; display: flex; flex-direction: column; align-items: stretch;
  border-right: 1px solid var(--line); background: var(--paper); padding: 6px 0;
}
.social-design-rail-tab {
  display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 10px 2px; border: none;
  background: none; cursor: pointer; font: 600 9.5px var(--sans); color: #8a8372;
}
.social-design-rail-icon { display: flex; align-items: center; justify-content: center; height: 20px; line-height: 1; }
.social-design-rail-tab:hover { color: var(--ink); }
.social-design-rail-tab.active { color: var(--ink); background: #fff; box-shadow: inset 3px 0 0 var(--accent); }
/* Was a flat 560px cap -- see .social-design-props's comment, same fix. */
.social-design-sidebar-panel { padding: 12px; overflow-y: auto; flex: 1; min-height: 200px; max-height: calc(100vh - 280px); }

.social-design-sidebar-section-title { font: 700 11px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; color: #8a8372; margin: 14px 0 8px; }
.social-design-sidebar-section-title:first-child { margin-top: 0; }
.social-design-sidebar-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 4px; }
.social-design-sidebar-item {
  display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 14px 6px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--paper); cursor: pointer; font: 600 11px var(--sans); color: var(--ink);
}
.social-design-sidebar-item:hover { border-color: var(--ink); }
.social-design-sidebar-item.active { background: var(--accent-dim); border-color: var(--accent); }
.social-design-sidebar-item-icon { display: flex; align-items: center; justify-content: center; height: 22px; color: var(--ink); }

.social-design-sidebar-icongrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin-top: 10px; }
.social-design-icon-result { border: 1px solid var(--line); border-radius: 6px; padding: 6px; cursor: pointer; background: var(--paper); aspect-ratio: 1; display: flex; align-items: center; justify-content: center; }
.social-design-icon-result img { width: 100%; height: 100%; object-fit: contain; }
.social-design-icon-result:hover { border-color: var(--ink); }
#designIconSearch, #designStockSearch { width: 100%; box-sizing: border-box; padding: 8px 10px; border: 1px solid var(--line); border-radius: 6px; font-family: var(--sans); font-size: 12.5px; margin-top: 6px; }
#designStockResults { margin-top: 8px; }

.social-design-sidebar-textpreset {
  display: block; width: 100%; text-align: left; padding: 12px 10px; margin-bottom: 8px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--paper); cursor: pointer; color: var(--ink); font-family: var(--sans);
}
.social-design-sidebar-textpreset:hover { border-color: var(--ink); }

.social-design-sidebar-template {
  display: block; width: 100%; text-align: left; padding: 10px 12px; margin-bottom: 8px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--paper); cursor: pointer; color: var(--ink); font: 600 12.5px var(--sans);
}
.social-design-sidebar-template:hover { border-color: var(--ink); }

.social-design-sidebar-upload {
  display: block; text-align: center; padding: 10px; margin-bottom: 10px; border: 1.5px dashed var(--line);
  border-radius: 8px; cursor: pointer; font: 600 12px var(--sans); color: var(--ink);
}
.social-design-sidebar-upload:hover { border-color: var(--ink); background: var(--panel); }
.social-design-sidebar-photogrid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.social-design-sidebar-photo { position: relative; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; padding: 0; cursor: pointer; aspect-ratio: 1; background: var(--panel); }
.social-design-sidebar-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.social-design-sidebar-photo:hover { border-color: var(--ink); }
.social-design-vector-badge {
  position: absolute; bottom: 3px; right: 3px; font-size: 9px; font-weight: 700; letter-spacing: 0.02em;
  background: rgba(0,0,0,0.7); color: #fff; border-radius: 3px; padding: 1px 4px; line-height: 1.4;
}

.social-design-swatch-row { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.social-design-swatch { width: 20px; height: 20px; border-radius: 50%; border: 1px solid var(--line); cursor: pointer; padding: 0; }
.social-design-swatch:hover { transform: scale(1.15); }

/* New-design size picker -- grouped by Social/Print, each card showing the
   preset's own aspect ratio as a small coloured box rather than a realistic
   platform mockup (see assets/social_design.js's DESIGN_SIZE_PRESETS). */
.social-preset-group-title { font: 700 11px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; color: #8a8372; margin: 14px 0 8px; }
.social-preset-group-title:first-child { margin-top: 4px; }
.social-preset-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(108px, 1fr)); gap: 8px; }
.social-preset-card {
  display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 10px 6px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--paper); cursor: pointer; text-align: center;
}
.social-preset-card:hover { border-color: var(--ink); }
.social-preset-shape { display: flex; align-items: center; justify-content: center; border-radius: 4px; color: #fff; flex-shrink: 0; }
.social-preset-shape svg { width: 40%; height: 40%; }
.social-preset-label { font: 600 11px var(--sans); color: var(--ink); line-height: 1.3; }
.social-preset-dims { font: 400 10px var(--mono); color: #8a8372; }

/* Custom size row in the New design dialog -- width / height / unit on one
   line so it reads as a single size, not three unrelated fields. */
.ds-custom-size { border: 1px solid var(--line); border-radius: 10px; padding: 12px; background: var(--paper); }
.ds-custom-size-fields { display: grid; grid-template-columns: 1fr 1fr 84px 96px; gap: 10px; }
.ds-custom-size-fields .field { margin: 0; }
.ds-custom-size-fields input, .ds-custom-size-fields select {
  width: 100%; font: 600 13px var(--sans); padding: 8px 10px; border: 1px solid var(--line);
  border-radius: 7px; background: #fff; color: var(--ink);
}
.ds-custom-size-fields input:focus, .ds-custom-size-fields select:focus { outline: none; border-color: var(--ink); }
@media (max-width: 560px) {
  .ds-custom-size-fields { grid-template-columns: 1fr 1fr; }
}

.social-design-issues {
  background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 16px; margin-top: 4px;
}
.social-design-issue { padding: 10px 0; border-bottom: 1px solid var(--line); border-radius: 4px; transition: background 0.3s; }
.social-design-issue:last-child { border-bottom: none; }
.social-design-issue.resolved { opacity: 0.55; }
.social-design-issue-flash { background: var(--accent-dim); } /* briefly highlights the row a pin marker was clicked from */
#designPinModeBtn.active { background: var(--accent-dim); border-color: var(--accent); }
.social-design-issue-body { font-size: 13px; color: var(--ink); white-space: pre-wrap; }
/* A pinned issue leads with the pin mark; it sits inline with the first line
   of the note, so it needs the baseline nudge an inline <svg> doesn't get. */
.social-design-issue-body .ds-icon { display: inline-block; vertical-align: -2px; color: #8a8372; }
.social-design-issue-meta { font: 400 10.5px var(--mono); color: #8a8372; margin-top: 3px; }
.social-design-issue-composer { display: flex; gap: 8px; align-items: flex-end; margin-top: 10px; }
.social-design-issue-composer textarea { flex: 1; font-family: var(--sans); font-size: 12.5px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 4px; resize: vertical; }

@media (max-width: 899px) {
  .social-design-body { flex-direction: column; }
  .social-design-sidebar, .social-design-props { width: 100%; max-height: none; }
  .social-design-sidebar { flex-direction: column; }
  .social-design-rail { width: 100%; flex-direction: row; overflow-x: auto; border-right: none; border-bottom: 1px solid var(--line); }
  .social-design-rail-tab { flex: 1; }
  .social-design-rail-tab.active { box-shadow: inset 0 -3px 0 var(--accent); }
  .social-design-sidebar-panel { max-height: 320px; }
  /* Stacking order, which the DOM order alone got wrong on a phone: the
     canvas first, the controls for whatever you just tapped directly under
     it, and the add-content sidebar last. Selecting an object used to mean
     scrolling past a full screen of shape buttons to reach the panel that
     edits it -- about 1,300px down on a 664px-tall viewport. */
  /* flex:none so the stated height actually holds -- flex:1 in a column
     with no fixed container height lets it shrink straight back to
     min-height, which is what it did. */
  .social-design-canvas-wrap { width: 100%; box-sizing: border-box; order: 1; flex: none; height: 52vh; min-height: 280px; }
  .social-design-props { order: 2; }
  .social-design-sidebar { order: 3; }
}

/* The topbar wrapped to three rows of labelled buttons on a phone, taking a
   quarter of the screen before the design got any. Icons only below 720px --
   every one of them carries a title, and the two that say something a title
   can't (an unsaved dot, an issue count) keep showing it. */
@media (max-width: 720px) {
  .social-design-topbar-actions { flex-wrap: wrap; gap: 6px; }
  .social-design-topbar-actions .ds-btn > span:not(#designIssuesBadge) { display: none; }
  .social-design-topbar-actions .ds-btn { padding: 9px 11px; }
  /* One scrolling row rather than three wrapped ones, so the canvas keeps
     its vertical space. */
  .social-design-toolbar { flex-wrap: nowrap; overflow-x: auto; }
  .social-design-toolbar button, .social-design-tool { flex-shrink: 0; }
}

/* Touch targets. 36px squares are fine for a mouse and small for a finger --
   this is the only place in the app dense enough to need saying. */
@media (pointer: coarse) {
  .social-design-toolbar button, .social-design-tool { width: 44px; height: 44px; }
  .social-design-tool-text { width: auto !important; padding: 0 16px !important; }
  .social-design-icon-btn { width: 38px; height: 38px; }
  .social-design-layer-btn { width: 30px; height: 30px; }
  .social-design-layer-row { padding: 8px 6px; }
  .social-design-board-thumb, .social-design-board-add { width: 58px; height: 58px; }
  .ds-btn, .ds-chip { min-height: 40px; }
  .ds-num-field input { padding: 8px 6px; }
  /* The one-step-at-a-time layer reorder buttons and the crop handles are
     easier to hit with a little more room around them. */
  .social-design-icon-row { gap: 8px; }
}

/* ---------------------------------------------------------------------------
   Design Studio -- controls added with the friction pass: the unsaved
   indicator, the recovered-draft bar, numeric position/size fields, the
   shortcut sheet, version thumbnails, and the canvas's own pan/drop states.
--------------------------------------------------------------------------- */

/* Unsaved work. The editor knew it had unsaved changes all along and never
   showed it; this is the "at a glance, am I safe" dot, on the Save button
   itself so it sits where the answer matters. */
.ds-btn.ds-unsaved { position: relative; border-color: var(--warn); color: var(--warn); }
.ds-btn.ds-unsaved::after {
  content: ''; position: absolute; top: 4px; right: 4px; width: 7px; height: 7px;
  border-radius: 50%; background: var(--warn);
}

.social-design-draftbanner {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 12px; border-radius: 8px; background: var(--warn-bg); color: var(--warn);
  font: 600 12.5px var(--sans);
}
.social-design-smallhint {
  padding: 9px 12px; border-radius: 8px; background: var(--panel); color: #5c5648;
  font: 500 12.5px var(--sans);
}

/* Canvas viewport states -- space-to-pan, middle-drag panning, and a file
   being dragged over the canvas. */
.social-design-canvas-wrap.ds-pan-ready { cursor: grab; }
.social-design-canvas-wrap.ds-panning { cursor: grabbing; }
.social-design-canvas-wrap.ds-dropping { outline: 2px dashed var(--accent); outline-offset: -6px; }

/* Numeric X/Y/W/H/angle, in mm for print sizes and px for social. Five
   fields in a 240px panel, so they're laid out as a grid of small labelled
   boxes rather than the panel's usual full-width .field rows. */
.ds-num-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; padding: 0 12px 10px; }
.ds-num-field { display: flex; align-items: center; gap: 6px; }
.ds-num-field label {
  font: 700 10.5px var(--mono); text-transform: uppercase; letter-spacing: 0;
  color: #8a8372; width: 30px; flex-shrink: 0; margin: 0 !important;
}
/* The angle field, last in the grid, takes a full row -- its label is the
   long one and a half-width box clipped the value. */
.ds-num-grid > :last-child { grid-column: 1 / -1; }
.ds-num-grid > :last-child label { width: 46px; }
.ds-num-field input {
  width: 100%; min-width: 0; font: 500 12.5px var(--sans); padding: 5px 6px;
  border: 1px solid var(--line); border-radius: 6px; background: #fff; color: var(--ink);
}
.ds-num-field input:disabled { background: var(--panel); color: #8a8372; }
.ds-unit-toggle { float: right; display: inline-flex; gap: 2px; }
.ds-unit {
  border: 1px solid var(--line); background: #fff; cursor: pointer; border-radius: 5px;
  padding: 2px 7px; font: 700 10px var(--mono); line-height: 1.2; color: #8a8372;
  text-transform: none; letter-spacing: 0;
}
.ds-unit.active { background: var(--accent-dim); border-color: var(--accent); color: var(--ink); }

/* Renaming a layer in place -- double-click the label. */
.social-design-layer-rename {
  flex: 1; min-width: 0; font: 600 12px var(--sans); padding: 2px 4px;
  border: 1px solid var(--ink); border-radius: 4px; background: #fff; color: var(--ink);
}

/* Keyboard shortcuts sheet -- every one of these already worked; none of
   them was written down anywhere. */
.ds-shortcut-list { display: flex; flex-direction: column; gap: 3px; margin-bottom: 10px; }
.ds-shortcut-row { display: flex; align-items: baseline; gap: 10px; font: 400 13px var(--sans); }
.ds-shortcut-keys {
  flex-shrink: 0; width: 190px; font: 600 11.5px var(--mono); color: var(--ink);
  background: var(--panel); border-radius: 5px; padding: 3px 7px;
}

/* Version history -- a row is picked by looking at it, not by guessing which
   identical timestamp is the right one. */
.social-design-version-row { align-items: flex-start; }
.social-design-version-thumb {
  flex-shrink: 0; width: 54px; height: 54px; border: 1px solid var(--line); border-radius: 6px;
  background: #fff; overflow: hidden; display: flex; align-items: center; justify-content: center;
  margin-right: 10px; font: 400 9px var(--mono); color: #8a8372; text-align: center;
}
.social-design-version-thumb img { width: 100%; height: 100%; object-fit: contain; }

/* The saturated colours named in the export dialog's CMYK warning. */
.ds-colour-chip {
  display: inline-block; width: 13px; height: 13px; border-radius: 3px; vertical-align: -2px;
  border: 1px solid rgba(0,0,0,0.18); margin: 0 2px;
}

/* ---------------------------------------------------------------------------
   Design Studio -- zoom slider, the pages controls (strip toggle, count,
   grid) and full screen.
--------------------------------------------------------------------------- */

/* Zoom slider. Styled explicitly in both engines because a default range
   input is a different height and colour in every browser, and this one sits
   inside a 36px toolbar row next to icon buttons. */
.social-design-zoom-slider {
  -webkit-appearance: none; appearance: none; background: none;
  width: 108px; height: 36px; margin: 0 2px; cursor: pointer; flex-shrink: 0;
}
.social-design-zoom-slider::-webkit-slider-runnable-track { height: 4px; border-radius: 2px; background: var(--line); }
.social-design-zoom-slider::-moz-range-track { height: 4px; border-radius: 2px; background: var(--line); }
.social-design-zoom-slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 14px; height: 14px; margin-top: -5px;
  border-radius: 50%; background: var(--ink); border: 2px solid #fff; box-shadow: 0 0 0 1px var(--line);
}
.social-design-zoom-slider::-moz-range-thumb {
  width: 14px; height: 14px; border-radius: 50%; background: var(--ink); border: 2px solid #fff; box-shadow: 0 0 0 1px var(--line);
}
.social-design-zoom-slider:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Which page you're on, of how many -- next to the strip toggle rather than
   inside the strip, so hiding the strip doesn't hide the answer too. */
.social-design-pages-label {
  font: 600 11.5px var(--mono); color: #8a8372; white-space: nowrap; padding: 0 2px;
  font-variant-numeric: tabular-nums;
}

/* All pages at once. Its own overlay, not the shared 520px modal shell:
   judging pages against each other is the whole point, so it wants the
   width of the window. */
.ds-pages-overlay {
  position: fixed; inset: 0; z-index: 1100; background: rgba(26,26,26,0.6);
  display: flex; align-items: flex-start; justify-content: center; padding: 28px 18px; overflow-y: auto;
}
.ds-pages-panel {
  background: var(--paper); border-radius: 12px; width: 100%; max-width: 1080px;
  padding: 18px 20px 22px; box-shadow: 0 16px 48px rgba(0,0,0,0.28);
}
.ds-pages-head { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; }
.ds-pages-head h2 { font: 700 17px var(--sans); margin: 0; letter-spacing: -0.01em; }
.ds-pages-count { font: 600 11.5px var(--mono); color: #8a8372; }
.ds-pages-head .ds-btn:last-child { margin-left: auto; }
.ds-pages-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 14px; }
.ds-page-card {
  margin: 0; background: #fff; border: 1px solid var(--line); border-radius: 10px; overflow: hidden;
  cursor: pointer; transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.ds-page-card:hover { border-color: var(--ink); box-shadow: 0 3px 12px rgba(26,26,26,0.12); }
.ds-page-card.current { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-dim); }
.ds-page-thumb {
  display: flex; align-items: center; justify-content: center; background: var(--panel);
  border-bottom: 1px solid var(--line); overflow: hidden;
}
.ds-page-thumb img { width: 100%; height: 100%; object-fit: contain; display: block; }
.ds-page-placeholder { font: 700 20px var(--mono); color: #8a8372; }
.ds-page-card figcaption { display: flex; align-items: center; gap: 6px; padding: 7px 9px; }
.ds-page-num { font: 600 11.5px var(--sans); color: var(--ink); white-space: nowrap; }
.ds-page-tools { display: flex; gap: 2px; margin-left: auto; }
.ds-page-tools button {
  width: 24px; height: 24px; border: none; background: none; border-radius: 5px; cursor: pointer;
  display: flex; align-items: center; justify-content: center; color: var(--ink);
}
.ds-page-tools button:hover { background: var(--panel); }
.ds-page-tools button:disabled { opacity: 0.28; cursor: default; }

/* Full screen. The whole document goes fullscreen (see toggleFullscreen's
   own comment -- modals and popovers live on <body>), so this is what hides
   the page furniture and hands the space to the canvas. */
body.ds-fullscreen > header,
body.ds-fullscreen > .statusbar,
body.ds-fullscreen .social-design-smallhint { display: none; }
body.ds-fullscreen .social-design-main { padding: 10px 14px 14px; }
body.ds-fullscreen .social-design-canvas-wrap { height: calc(100vh - 190px); }
body.ds-fullscreen .social-design-sidebar-panel,
body.ds-fullscreen .social-design-props { max-height: calc(100vh - 190px); }

@media (pointer: coarse) {
  .social-design-zoom-slider { width: 96px; height: 44px; }
  .ds-page-tools button { width: 32px; height: 32px; }
}

/* Built-in layouts -- a preview grid rather than a list of names, since a
   layout is a shape and a name isn't. Each preview is rendered from the same
   code that applies the layout, at this design's own dimensions (see
   builtinTemplatePreview), so the card shows what you'd actually get. */
.social-design-template-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 6px; }
.social-design-template-card {
  display: flex; flex-direction: column; gap: 5px; padding: 5px; border: 1px solid var(--line);
  border-radius: 8px; background: #fff; cursor: pointer; text-align: left; color: var(--ink);
}
.social-design-template-card:hover { border-color: var(--ink); }
.social-design-template-preview {
  display: block; height: 74px; border-radius: 5px; background: var(--panel); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.social-design-template-preview img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; }
.social-design-template-name { font: 600 11px var(--sans); line-height: 1.25; }

/* Masking + vector parts. The mask row is the preset shapes; the vector
   colour list is every colour an imported SVG actually uses, so a two-colour
   logo can be recoloured by colour rather than path by path. */
.social-design-mask-row { display: flex; gap: 6px; flex-wrap: wrap; padding: 0 12px 4px; }
.social-design-vector-colours { display: flex; flex-direction: column; gap: 4px; padding: 4px 12px 6px; }
.social-design-vector-swatch {
  display: flex; align-items: center; gap: 8px; width: 100%; padding: 5px 7px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 6px; background: #fff; color: var(--ink);
  font: 500 11.5px var(--mono); text-align: left;
}
.social-design-vector-swatch:hover { border-color: var(--ink); }
.social-design-vector-swatch span {
  width: 18px; height: 18px; border-radius: 4px; flex-shrink: 0;
  border: 1px solid rgba(0,0,0,0.18);
}

/* Custom gradient editor -- the stop bar, its handles, and the controls
   under it. Lives inside the colour popover, which is 260px wide, so
   everything here is sized to that rather than to a dialog. */
.ds-grad-toggle {
  margin-left: auto; border: 1px solid var(--line); background: #fff; cursor: pointer;
  border-radius: 5px; padding: 2px 7px; font: 700 10px var(--mono); color: var(--ink); text-transform: none;
}
.ds-grad-toggle:hover { border-color: var(--ink); }
.ds-grad-bar-wrap { position: relative; margin: 4px 0 6px; height: 30px; }
.ds-grad-bar {
  position: absolute; inset: 0 0 10px 0; border-radius: 5px; cursor: copy;
  border: 1px solid var(--line);
}
.ds-grad-stop {
  position: absolute; bottom: 0; width: 13px; height: 13px; margin-left: -6.5px; padding: 0;
  border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px var(--line); cursor: grab;
}
.ds-grad-stop.active { box-shadow: 0 0 0 2px var(--ink); }
.ds-grad-hint { font: 400 10px var(--sans); color: #8a8372; margin-bottom: 6px; }
.ds-grad-row { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
.ds-grad-swatch {
  width: 26px; height: 26px; border-radius: 5px; border: 1px solid var(--line);
  flex-shrink: 0; cursor: pointer; overflow: hidden; position: relative;
}
.ds-grad-swatch input { position: absolute; inset: -4px; opacity: 0; cursor: pointer; }
.ds-grad-row input[type="number"] {
  width: 54px; font: 500 11.5px var(--sans); padding: 4px 6px; border: 1px solid var(--line);
  border-radius: 5px; background: #fff; color: var(--ink);
}
.ds-grad-row input[type="range"] { flex: 1; min-width: 0; accent-color: var(--ink); }
.ds-grad-unit { font: 600 10.5px var(--mono); color: #8a8372; min-width: 30px; }
.ds-grad-btn {
  border: 1px solid var(--line); background: #fff; cursor: pointer; border-radius: 5px;
  padding: 4px 8px; font: 600 11px var(--sans); color: var(--ink); display: flex;
  align-items: center; justify-content: center; gap: 4px;
}
.ds-grad-btn.wide { flex: 1; }
.ds-grad-btn:hover:not(:disabled) { border-color: var(--ink); }
.ds-grad-btn.active { background: var(--accent-dim); border-color: var(--accent); }
.ds-grad-btn:disabled { opacity: 0.4; cursor: default; }

/* Text styles gallery -- each button previews the treatment it inserts
   rather than naming it, so the sample sits above the name instead of
   beside it. */
.social-design-sidebar-textpreset { display: flex; flex-direction: column; gap: 3px; }
.ds-text-style-sample {
  display: block; color: var(--ink); line-height: 1.25; overflow: hidden;
  text-overflow: ellipsis; white-space: pre-line; max-height: 2.6em;
}
.ds-text-style-name {
  font: 600 10px var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: #8a8372;
}
.ds-field-note { font: 400 10px var(--mono); color: #8a8372; text-transform: none; letter-spacing: 0; margin-left: 6px; }

/* Effects tab -- shadow/glow presets, the sliders that tune them, blend
   modes, and a photo's look and adjustments. Rows are label / control /
   readout so a value is always visible while dragging. */
.ds-fx-presets { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; padding: 0 12px 8px; }
.ds-fx-preset {
  display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 7px 4px;
  border: 1px solid var(--line); border-radius: 8px; background: #fff; cursor: pointer;
  font: 600 10.5px var(--sans); color: var(--ink);
}
.ds-fx-preset:hover { border-color: var(--ink); }
.ds-fx-preset.active { background: var(--accent-dim); border-color: var(--accent); }
.ds-fx-preset-chip { width: 22px; height: 22px; border-radius: 5px; background: var(--ink); }
.ds-fx-chip-none { background: repeating-conic-gradient(#e0e0dc 0% 25%, #fff 0% 50%) 0 0 / 8px 8px; border: 1px solid var(--line); }
.ds-fx-chip-soft { box-shadow: 0 3px 6px rgba(0,0,0,0.45); }
.ds-fx-chip-hard { box-shadow: 3px 3px 0 rgba(0,0,0,0.55); }
.ds-fx-chip-long { box-shadow: 6px 6px 0 rgba(0,0,0,0.22); }
.ds-fx-chip-glow { box-shadow: 0 0 9px 2px rgba(185,212,50,0.95); }
.ds-fx-chip-halo { background: #4a4a44; box-shadow: 0 0 9px 3px rgba(255,255,255,0.95); }

.ds-fx-row { display: flex; align-items: center; gap: 8px; padding: 6px 12px; }
.ds-fx-row label {
  font: 600 10.5px var(--mono); text-transform: uppercase; letter-spacing: 0.04em;
  color: #8a8372; width: 72px; flex-shrink: 0; margin: 0 !important;
}
.ds-fx-row input[type="range"] { flex: 1; min-width: 0; accent-color: var(--ink); }
.ds-fx-row output {
  font: 500 11px var(--mono); color: var(--ink); width: 42px; text-align: right;
  font-variant-numeric: tabular-nums;
}
.ds-fx-row .ds-color-field { flex: 1; }
.ds-fx-select {
  flex: 1; min-width: 0; font: 500 12px var(--sans); padding: 5px 7px;
  border: 1px solid var(--line); border-radius: 6px; background: #fff; color: var(--ink);
}
.ds-fx-looks { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; padding: 0 12px 8px; }
.ds-fx-look {
  padding: 7px 8px; border: 1px solid var(--line); border-radius: 7px; background: #fff;
  cursor: pointer; font: 600 11px var(--sans); color: var(--ink); text-align: left;
}
.ds-fx-look:hover { border-color: var(--ink); }
.ds-fx-look.active { background: var(--accent-dim); border-color: var(--accent); }
/* colorFieldHtml() brings its own .field wrapper (label above, button below);
   inside an effects row it's just the button, sitting beside the row label. */
.ds-fx-row .field { flex: 1; min-width: 0; padding: 0; }
.ds-fx-row .field label:empty { display: none; }

/* Quick bar -- the contextual strip above the canvas that appears with a
   selection. Same 36px control rhythm as the main toolbar; scrolls sideways
   rather than wrapping, same as the toolbar does on a phone. */
.social-design-quickbar {
  display: flex; align-items: center; gap: 4px; background: #fff; border: 1px solid var(--line);
  border-radius: 10px; padding: 5px 8px; overflow-x: auto; white-space: nowrap;
}
.ds-qb-btn {
  width: 32px; height: 32px; border-radius: 7px; border: 1px solid transparent; background: none;
  cursor: pointer; padding: 0; display: inline-flex; align-items: center; justify-content: center;
  color: var(--ink); font: 600 13px var(--sans); flex-shrink: 0;
}
.ds-qb-btn:hover:not(:disabled) { background: var(--panel); }
.ds-qb-btn.active { background: var(--accent-dim); border-color: var(--accent); }
.ds-qb-btn:disabled { opacity: 0.35; cursor: default; }
.ds-qb-fx { font: 700 11.5px var(--mono); }
.ds-qb-chip {
  width: 32px; height: 32px; border-radius: 7px; border: 1px solid var(--line); background: #fff;
  cursor: pointer; padding: 4px; flex-shrink: 0;
}
.ds-qb-chip span { display: block; width: 100%; height: 100%; border-radius: 4px; border: 1px solid rgba(0,0,0,0.12); }
.ds-qb-chip:hover { border-color: var(--ink); }
.ds-qb-sep { width: 1px; height: 22px; background: var(--line); margin: 0 4px; flex-shrink: 0; }
.ds-qb-font {
  max-width: 150px; min-width: 110px; font: 500 12.5px var(--sans); padding: 6px 6px;
  border: 1px solid var(--line); border-radius: 7px; background: #fff; color: var(--ink); flex-shrink: 0;
}
.ds-qb-size { display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0; }
.ds-qb-size input {
  width: 46px; font: 600 12.5px var(--sans); padding: 6px 4px; text-align: center;
  border: 1px solid var(--line); border-radius: 7px; background: #fff; color: var(--ink);
  -moz-appearance: textfield;
}
.ds-qb-size input::-webkit-outer-spin-button, .ds-qb-size input::-webkit-inner-spin-button { -webkit-appearance: none; }
.ds-qb-opacity { width: 78px; accent-color: var(--ink); flex-shrink: 0; }
@media (pointer: coarse) {
  .ds-qb-btn, .ds-qb-chip { width: 40px; height: 40px; }
}

/* Weight picker in the quick bar -- narrower than the font select, since
   the longest entry is "Extra light". */
.ds-qb-weight {
  max-width: 104px; min-width: 84px; font: 500 12px var(--sans); padding: 6px 4px;
  border: 1px solid var(--line); border-radius: 7px; background: #fff; color: var(--ink); flex-shrink: 0;
}

/* ---------------------------------------------------------------------------
   Help Centre (help.php) + the per-page help drawer (injectHelpDrawer() in
   common.js). Both surfaces share the .help-topic block deliberately: the
   drawer is the same content in a narrower column, and giving it its own
   parallel styling is exactly how the two would drift apart.
--------------------------------------------------------------------------- */
.help-main { padding: 18px; max-width: 1180px; margin: 0 auto; }
@media (min-width: 1300px) { .help-main { padding: 24px 40px; } }

/* Search sits above the two-column layout, full width, because it applies to
   the whole page rather than to whichever section you happen to be in. */
.help-searchbar {
  position: relative; display: flex; align-items: center;
  background: #fff; border: 1.5px solid var(--line); border-radius: 8px;
  padding: 0 12px; margin-bottom: 6px;
}
.help-searchbar:focus-within { border-color: var(--ink); }
.help-search-icon { font-size: 17px; color: #8a8372; margin-right: 8px; }
.help-searchbar input {
  flex: 1; border: none; outline: none; background: transparent;
  font: 400 15px var(--sans); color: var(--ink); padding: 13px 0;
}
.help-searchbar input::-webkit-search-cancel-button { display: none; }
.help-search-clear {
  border: none; background: none; cursor: pointer; color: #8a8372;
  font-size: 13px; padding: 6px 4px;
}
.help-search-clear:hover { color: var(--ink); }
.help-search-meta { font: 400 11.5px var(--mono); color: #8a8372; margin: 0 0 14px 4px; }

.help-layout { display: grid; grid-template-columns: 210px 1fr; gap: 28px; align-items: start; }
@media (max-width: 899px) { .help-layout { grid-template-columns: 1fr; gap: 14px; } }
/* Grid items are min-width:auto by default, so a child wider than the track
   stretches the track rather than scrolling or wrapping inside it. Without
   this the rail's nowrap chip row on mobile blew the single column out to
   ~1166px and took the whole page with it. */
.help-rail, .help-content { min-width: 0; }

/* Left rail. Sticky on desktop so the map of the page stays put while you read
   it; on a phone it becomes a horizontally scrolling chip row instead, since a
   sticky sidebar there would eat the screen the content needs. */
.help-rail { position: sticky; top: 16px; }
.help-rail-nav { display: flex; flex-direction: column; gap: 2px; }
.help-rail-link {
  font: 600 13px var(--sans); color: #55534c; text-decoration: none;
  padding: 8px 11px; border-radius: 6px; border-left: 2px solid transparent;
}
.help-rail-link:hover { background: var(--panel); color: var(--ink); }
.help-rail-link.active { background: var(--accent-dim); color: var(--ink); border-left-color: var(--accent); }
@media (max-width: 899px) {
  .help-rail { position: static; margin-bottom: 4px; }
  .help-rail-nav {
    flex-direction: row; gap: 6px; overflow-x: auto; padding-bottom: 6px;
    -webkit-overflow-scrolling: touch;
  }
  .help-rail-link {
    white-space: nowrap; border: 1px solid var(--line); border-left-width: 1px;
    background: #fff; font-size: 12.5px;
  }
  .help-rail-link.active { border-color: var(--ink); }
}

.help-section { margin-bottom: 34px; scroll-margin-top: 16px; }
.help-section-title { font-size: 17px; font-weight: 700; letter-spacing: -0.01em; margin: 0 0 4px; }
.help-section-blurb { font-size: 13.5px; color: #6b6a63; margin: 0 0 14px; line-height: 1.5; }

/* ---- The loop stepper --------------------------------------------------- */
.help-tour {
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  padding: 20px; margin-bottom: 34px;
}
.help-tour .help-section-title { margin-bottom: 6px; }

.help-tour-track { display: flex; gap: 6px; margin: 16px 0 14px; overflow-x: auto; padding-bottom: 4px; }
.help-tour-dot {
  flex: 1; min-width: 118px; text-align: left; cursor: pointer;
  background: #fff; border: 1.5px solid var(--line); border-radius: 6px;
  padding: 9px 11px; font-family: inherit;
  display: flex; flex-direction: column; gap: 5px;
  transition: border-color 0.14s ease, background 0.14s ease;
}
.help-tour-dot:hover { border-color: #b4b2a8; }
.help-tour-dot.active { border-color: var(--ink); background: var(--accent-dim); }
.help-tour-num {
  font: 700 10px var(--mono); color: #8a8372;
  width: 19px; height: 19px; border-radius: 50%; border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center; background: var(--paper);
}
.help-tour-dot.active .help-tour-num { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.help-tour-dot-label { font: 700 11.5px var(--sans); color: var(--ink); line-height: 1.3; }

.help-tour-panels { background: #fff; border: 1px solid var(--line); border-radius: 6px; padding: 18px; }
/* Only hide the inactive panels once help.js has taken over -- with scripting
   off, all five stay visible and the stepper degrades to a readable list. */
.help-tour-panels.js-ready .help-tour-panel { display: none; }
.help-tour-panels.js-ready .help-tour-panel.active { display: block; }
.help-tour-panel-step { font: 400 10px var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: #8a8372; }
.help-tour-panel h3 { font-size: 16px; margin: 6px 0 8px; }
.help-tour-panel p { font-size: 14px; line-height: 1.62; color: #3d3c37; margin: 0; }
.help-tour-controls { display: none; gap: 8px; margin-top: 16px; }
.help-tour-panels.js-ready .help-tour-controls { display: flex; }
/* button.primary/.secondary are width:100% by design -- they're built to fill
   a form column. Side by side in this row that made each one demand the whole
   width, and there is no shrinking back from an explicit width, so the Next
   button ended up off the side of the page (invisibly, since html sets
   overflow-x:hidden). Size them to their text instead. The margin-top reset
   is the same story: the two classes carry different top margins, which left
   the pair sitting at different heights. */
.help-tour-controls button { flex: 0 0 auto; width: auto; margin-top: 0; }
.help-tour-controls button:disabled { opacity: 0.4; cursor: default; }

/* ---- One topic ---------------------------------------------------------- */
.help-topics { display: flex; flex-direction: column; gap: 8px; }
.help-topic {
  background: #fff; border: 1px solid var(--line); border-radius: 6px;
  overflow: hidden; scroll-margin-top: 16px;
}
.help-topic.open { border-color: #b4b2a8; }
.help-topic-flash { box-shadow: 0 0 0 2px var(--accent); }

.help-topic-head {
  width: 100%; display: flex; align-items: flex-start; gap: 11px;
  background: none; border: none; cursor: pointer; text-align: left;
  padding: 14px 15px; font-family: inherit;
}
.help-topic-head:hover { background: var(--accent-dim); }
.help-topic-icon { font-size: 16px; line-height: 1.35; flex-shrink: 0; }
.help-topic-heading { flex: 1; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.help-topic-title { font: 700 14px var(--sans); color: var(--ink); }
.help-topic-summary { font-size: 12.8px; line-height: 1.5; color: #6b6a63; }
.help-topic.open .help-topic-summary { color: #55534c; }
.help-topic-arrow { font-size: 11px; color: #8a8372; flex-shrink: 0; margin-top: 3px; transition: transform 0.15s ease; }
.help-topic.open .help-topic-arrow { transform: rotate(90deg); }

.help-topic-body { display: none; padding: 2px 15px 16px 42px; }
.help-topic.open .help-topic-body { display: block; }
@media (max-width: 599px) { .help-topic-body { padding-left: 15px; } }

.help-steps { margin: 6px 0 0; padding-left: 18px; display: flex; flex-direction: column; gap: 11px; }
.help-steps li { font-size: 13.5px; line-height: 1.55; }
.help-steps li::marker { font-family: var(--mono); font-size: 11.5px; color: #8a8372; }
.help-step-do { display: block; font-weight: 700; color: var(--ink); }
.help-step-why { display: block; color: #55534c; margin-top: 2px; }

.help-tips { margin-top: 15px; background: var(--panel); border-radius: 5px; padding: 12px 14px; }
.help-tips h4 {
  font: 400 10px var(--mono); letter-spacing: 0.12em; text-transform: uppercase;
  color: #8a8372; margin: 0 0 7px;
}
.help-tips ul { margin: 0; padding-left: 17px; display: flex; flex-direction: column; gap: 6px; }
.help-tips li { font-size: 13px; line-height: 1.55; color: #3d3c37; }

.help-topic-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 15px; }
.help-go {
  font: 700 12px var(--sans); text-decoration: none; color: var(--ink);
  border: 1.5px solid var(--ink); border-radius: 20px; padding: 6px 13px;
}
.help-go:hover { background: var(--accent); }
.help-topic-permalink {
  display: inline-block; margin-top: 13px;
  font: 400 11.5px var(--mono); color: #8a8372; text-decoration: none;
  border-bottom: 1px solid var(--line);
}
.help-topic-permalink:hover { color: var(--ink); }
.help-faq-answer { font-size: 13.5px; line-height: 1.62; color: #3d3c37; margin: 6px 0 0; }
.help-faq .help-topic-icon {
  font: 700 12px var(--mono); color: #8a8372;
  width: 20px; height: 20px; border: 1px solid var(--line); border-radius: 50%;
  display: flex; align-items: center; justify-content: center; margin-top: 1px;
}

/* ---- Glossary ----------------------------------------------------------- */
.help-glossary {
  display: flex; flex-direction: column; gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: 6px; overflow: hidden;
}
.help-glossary-row { display: flex; align-items: center; gap: 13px; background: #fff; padding: 12px 15px; }
.help-glossary-means { font-size: 13.2px; line-height: 1.5; color: #3d3c37; }
@media (max-width: 599px) { .help-glossary-row { flex-direction: column; align-items: flex-start; gap: 7px; } }

.help-footer-note {
  font-size: 12.5px; line-height: 1.6; color: #6b6a63;
  border-top: 1px solid var(--line); padding-top: 16px; margin-top: 8px;
}
.help-empty-search { margin-bottom: 24px; }

/* ---------------------------------------------------------------------------
   Per-page help drawer. Its trigger stacks above the All-pages trigger rather
   than beside it: two round buttons side by side in a corner read as a pair of
   equals, and these are not equals -- one is navigation, one is "what am I
   looking at". On the mobile dashboard layout the All-pages trigger is hidden
   behind the tab bar's More item, so this one slides down to sit above the bar.
--------------------------------------------------------------------------- */
.help-trigger {
  /* right: 22px, not 20 -- this button is 44px to the All-pages trigger's 48,
     so matching their right edges would leave their centres 2px apart. */
  position: fixed; bottom: 78px; right: 22px; z-index: 40;
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--paper); color: var(--ink); border: 2px solid var(--ink);
  font: 700 19px var(--sans); cursor: pointer; box-shadow: 0 2px 10px rgba(0,0,0,0.18);
  display: flex; align-items: center; justify-content: center;
}
.help-trigger:hover { background: var(--accent); }
@media (max-width: 899px) {
  body.docket-body .help-trigger { bottom: 76px; right: 14px; }
}

.help-drawer {
  position: fixed; top: 0; right: 0; height: 100%; width: 400px; max-width: 92vw;
  background: var(--paper); border-left: 1px solid var(--line);
  z-index: 50; transform: translateX(100%); transition: transform 0.25s ease;
  display: flex; flex-direction: column; box-shadow: -4px 0 16px rgba(0,0,0,0.15);
}
.help-drawer.open { transform: translateX(0); }

.help-drawer-search { padding: 12px 14px; border-bottom: 1px solid var(--line); }
.help-drawer-search input {
  width: 100%; border: 1.5px solid var(--line); border-radius: 6px;
  padding: 9px 11px; font: 400 13.5px var(--sans); color: var(--ink); background: #fff;
}
.help-drawer-search input:focus { outline: none; border-color: var(--ink); }
.help-drawer-search input::-webkit-search-cancel-button { display: none; }

.help-drawer-body { flex: 1; overflow-y: auto; padding: 12px 14px; }
.help-drawer-group + .help-drawer-group { margin-top: 20px; }
.help-drawer-group-label {
  font: 400 10px var(--mono); letter-spacing: 0.12em; text-transform: uppercase;
  color: #8a8372; margin-bottom: 8px;
}
.help-drawer-group .help-topic + .help-topic { margin-top: 7px; }
.help-drawer-none { font-size: 12.8px; line-height: 1.55; color: #6b6a63; }
/* The drawer column is roughly a third the width of the Help Centre's, so the
   indent that lines a topic's body up under its title there just squeezes the
   text here. */
.help-drawer .help-topic-body { padding-left: 15px; }

.help-drawer-footer {
  display: block; padding: 14px; border-top: 1px solid var(--line);
  font: 700 12.5px var(--sans); color: var(--ink); text-decoration: none; text-align: center;
  background: #fff;
}
.help-drawer-footer:hover { background: var(--accent-dim); }

/* ---------------------------------------------------------------------------
   Design Studio tooltips (assets/ds-tooltip.js). One shared bubble, moved
   under whichever control is hovered/focused; the JS parses each control's
   existing title into label + <kbd> shortcut + detail line. pointer-events
   none so the bubble can never trap the cursor it is following.
--------------------------------------------------------------------------- */
.ds-tooltip {
  position: fixed; z-index: 4000; max-width: 260px;
  background: var(--ink); color: var(--paper);
  padding: 7px 11px; border-radius: 7px;
  font: 600 12px var(--sans); line-height: 1.45;
  box-shadow: 0 4px 14px rgba(0,0,0,0.28);
  pointer-events: none; opacity: 0;
  transform: translateY(3px);
  transition: opacity 0.1s ease, transform 0.1s ease;
}
.ds-tooltip.show { opacity: 1; transform: translateY(0); }
.ds-tooltip.below { transform: translateY(-3px); }
.ds-tooltip.below.show { transform: translateY(0); }
/* Arrow -- its x position is set from JS (--ds-tip-arrow-x) against the
   TARGET's centre, so a bubble clamped at the screen edge still points at
   the control rather than at its own middle. */
.ds-tooltip::after {
  content: ''; position: absolute; width: 8px; height: 8px;
  background: var(--ink); transform: rotate(45deg);
  left: calc(var(--ds-tip-arrow-x, 50%) - 4px);
  bottom: -3px;
}
.ds-tooltip.below::after { bottom: auto; top: -3px; }
.ds-tooltip-label { display: inline; }
.ds-tooltip kbd {
  display: inline-block; margin-left: 7px; padding: 1px 5px 2px;
  background: rgba(255,255,255,0.16); border-radius: 4px;
  font: 700 10.5px var(--mono); color: var(--paper);
  vertical-align: 1px;
}
.ds-tooltip-detail {
  display: block; margin-top: 3px;
  font-weight: 400; font-size: 11.5px; color: #c9c4b6;
}
