/* ─────────────────────────────────────────────────────────────────────────────
   IPS Project Management Platform — Custom Styles
   ───────────────────────────────────────────────────────────────────────────── */
/* Inter font, vendored locally so the app renders identically offline. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/static/vendor/fonts/InterVariable.woff2') format('woff2-variations'),
       url('/static/vendor/fonts/InterVariable.woff2') format('woff2');
}

:root {
  --ips-blue: #00AEEF;
  --ips-dark: #1B4F8C;
  --ips-navy: #1A3A63;
  --ips-light: #E8F4FD;
}

/* Tailwind custom colors */
.text-ips-blue { color: var(--ips-blue); }
.text-ips-dark { color: var(--ips-dark); }
.bg-ips-blue { background-color: var(--ips-blue); }
.bg-ips-dark { background-color: var(--ips-dark); }
.from-ips-blue { --tw-gradient-from: var(--ips-blue); }
.border-ips-blue { border-color: var(--ips-blue); }

/* ── Layout ────────────────────────────────────────────────────────────────── */
body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background: #F3F4F6;
}

/* ── Sidebar ───────────────────────────────────────────────────────────────── */
.sidebar {
  width: 240px;
  min-height: 100vh;
  background: var(--ips-navy);
  display: flex;
  flex-direction: column;
  position: fixed;
  left: 0;
  top: 0;
  bottom: 0;
  z-index: 40;
  transition: width 0.25s cubic-bezier(0.4,0,0.2,1);
}

.sidebar.collapsed { width: 64px; }

.sidebar-logo {
  padding: 22px 18px;
  border-bottom: 1px solid rgba(255,255,255,0.10);
  display: flex;
  align-items: center;
  justify-content: flex-start;
  overflow: hidden;
  min-height: 68px;
}
.sidebar.collapsed .sidebar-logo { padding: 16px 8px; }
.sidebar.collapsed .sidebar-logo img { display: none; }

.sidebar-nav {
  flex: 1;
  padding: 12px 8px;
  overflow-y: auto;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 8px;
  color: rgba(255,255,255,0.75);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.15s;
  margin-bottom: 2px;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
}

.nav-item:hover {
  background: rgba(255,255,255,0.15);
  color: white;
}

.nav-item.active {
  background: rgba(255,255,255,0.25);
  color: white;
  font-weight: 600;
}

.nav-item svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.sidebar.collapsed .nav-item {
  justify-content: center;
  padding: 10px;
  gap: 0;
}
.sidebar.collapsed .nav-label { display: none; }
.sidebar.collapsed .sidebar-user-info { display: none; }
.sidebar.collapsed .sidebar-user-section { justify-content: center; }

/* Collapse toggle button */
.sidebar-toggle {
  position: absolute;
  top: 26px;
  right: -12px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--ips-blue);
  border: 2px solid white;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 50;
  transition: all 0.2s;
}
.sidebar-toggle:hover {
  background: var(--ips-dark);
  color: white;
  border-color: white;
}
.sidebar-toggle svg {
  width: 14px; height: 14px;
  transition: transform 0.25s;
}
.sidebar.collapsed .sidebar-toggle svg { transform: rotate(180deg); }

/* ── Main content ──────────────────────────────────────────────────────────── */
.main-content {
  margin-left: 240px;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* The shell renders the sidebar + this column inside a flex row; as a flex
     item this column's default `min-width: auto` lets it grow to its widest
     content, so a single long unbreakable value (a long meeting-point topic,
     a wide table, …) pushed the whole page past the viewport. min-width: 0
     lets the column shrink to the viewport, so inner `truncate`/overflow-x
     containers actually clip/scroll instead of blowing out the layout. */
  min-width: 0;
  transition: margin-left 0.25s cubic-bezier(0.4,0,0.2,1);
}
.main-content.sidebar-collapsed { margin-left: 64px; }

.top-header {
  background: white;
  border-bottom: 1px solid #E5E7EB;
  /* Extra left padding so the page title clears the sidebar collapse
     button (sits at right:-12 of the sidebar with a 24-px circle, half
     overhanging into the main content area). */
  padding: 0 24px 0 36px;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: sticky;
  top: 0;
  z-index: 30;
}

.help-icon-btn {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid #E5E7EB;
  background: #fff;
  color: var(--ips-blue);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.1s;
}
.help-icon-btn:hover { background: var(--ips-light); border-color: var(--ips-blue); color: var(--ips-dark); }
.help-icon-btn.active { background: var(--ips-blue); border-color: var(--ips-blue); color: #fff; }

.content-area {
  padding: 24px;
  flex: 1;
}

/* ── Cards ─────────────────────────────────────────────────────────────────── */
.card {
  background: white;
  border-radius: 12px;
  padding: 20px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.07), 0 1px 2px rgba(0,0,0,0.05);
}

/* ── Sub-tabs ──────────────────────────────────────────────────────────────── */
.sub-tab-bar {
  background: white;
  border-bottom: 1px solid #E5E7EB;
  padding: 0 24px;
  display: flex;
  gap: 0;
}

.sub-tab {
  padding: 14px 20px;
  font-size: 14px;
  font-weight: 500;
  color: #6B7280;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: all 0.15s;
  white-space: nowrap;
}

.sub-tab:hover {
  color: var(--ips-blue);
}

.sub-tab.active {
  color: var(--ips-blue);
  border-bottom-color: var(--ips-blue);
  font-weight: 600;
}

/* ── Buttons ───────────────────────────────────────────────────────────────── */
.btn-primary {
  display: inline-flex;
  align-items: center;
  padding: 8px 16px;
  background: var(--ips-blue);
  color: white;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.15s;
  border: none;
  outline: none;
}

.btn-primary:hover { background: #0099d4; }
.btn-primary:disabled { opacity: 0.6; cursor: not-allowed; }

.btn-secondary {
  display: inline-flex;
  align-items: center;
  padding: 8px 16px;
  background: white;
  color: #374151;
  border: 1px solid #D1D5DB;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.15s;
}

.btn-secondary:hover { background: #F9FAFB; border-color: #9CA3AF; }

.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.15s;
  background: transparent;
  border: none;
}

.btn-icon:hover { background: #F3F4F6; }

/* ── Forms ─────────────────────────────────────────────────────────────────── */
.input-field {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid #D1D5DB;
  border-radius: 8px;
  font-size: 14px;
  color: #374151;
  background: white;
  transition: border-color 0.15s, box-shadow 0.15s;
  outline: none;
}

.input-field:focus {
  border-color: var(--ips-blue);
  box-shadow: 0 0 0 3px rgba(0,174,239,0.12);
}

.form-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: #6B7280;
  margin-bottom: 4px;
  text-transform: uppercase;
  letter-spacing: 0.025em;
}

/* ── Modals ────────────────────────────────────────────────────────────────── */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 20px;
  backdrop-filter: blur(2px);
}

.modal-box {
  background: white;
  border-radius: 16px;
  width: 100%;
  max-width: 540px;
  max-height: 90vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 0 20px 60px rgba(0,0,0,0.2);
}

.modal-lg  { max-width: 720px !important; }
.modal-xl  { max-width: 920px !important; }
.modal-2xl { max-width: 1100px !important; }

.modal-header {
  padding: 20px 24px;
  border-bottom: 1px solid #E5E7EB;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.modal-body {
  padding: 20px 24px;
  overflow-y: auto;
  flex: 1;
}

.modal-footer {
  padding: 16px 24px;
  border-top: 1px solid #E5E7EB;
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* ── Badges ────────────────────────────────────────────────────────────────── */
.status-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.badge-blue { background: #DBEAFE; color: #1D4ED8; }
.badge-green { background: #D1FAE5; color: #065F46; }
.badge-gray { background: #F3F4F6; color: #6B7280; }
.badge-yellow { background: #FEF3C7; color: #92400E; }
.badge-red { background: #FEE2E2; color: #991B1B; }
.badge-orange { background: #FFEDD5; color: #9A3412; }
.badge-purple { background: #F3E8FF; color: #6B21A8; }

/* ── Type badges ───────────────────────────────────────────────────────────── */
.type-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 700;
  flex-shrink: 0;
}

/* Responsible initial-chips on the meeting-points Rows layout — hover
   reveals the × remove button. Kept here (not Tailwind group-hover) so
   the row's own group-hover (action buttons) doesn't trigger the chip ×. */
.row-resp-chip:hover .row-resp-chip-x { opacity: 1; }

/* Inline category pill in the meeting-points Cards layout. Looks like a
   coloured badge but is a native <select> so the user can change the
   category without leaving the card. Inline background-color is set on
   the element itself (per-row colour), so don't define a default here. */
.inline-category-select {
  display: inline-block;
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
  padding: 2px 8px;
  border-radius: 4px;
  border-width: 1px;
  border-style: solid;
  cursor: pointer;
  max-width: 160px;
  text-overflow: ellipsis;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}
.inline-category-select:focus {
  outline: 2px solid rgba(30, 58, 95, 0.35);
  outline-offset: 1px;
}
/* Native <option> elements ignore the parent's coloured background, so
   reset them to a readable dark-on-white in the dropdown menu. */
.inline-category-select option {
  background-color: #fff;
  color: #1f2937;
}

/* Sliding pane (meeting-point editor) — slide in from the right with
   a matching backdrop fade. 200 ms feels snappy but not abrupt. */
.oc-pane-slide-enter-active, .oc-pane-slide-leave-active {
  transition: transform 220ms cubic-bezier(0.32, 0.72, 0, 1);
}
.oc-pane-slide-enter-from, .oc-pane-slide-leave-to { transform: translateX(100%); }
.oc-pane-slide-enter-to,   .oc-pane-slide-leave-from { transform: translateX(0); }

.oc-pane-fade-enter-active, .oc-pane-fade-leave-active {
  transition: opacity 180ms ease;
}
.oc-pane-fade-enter-from, .oc-pane-fade-leave-to { opacity: 0; }
.oc-pane-fade-enter-to,   .oc-pane-fade-leave-from { opacity: 1; }

.type-action { background: #EDE9FE; color: #6D28D9; }
.type-decision { background: #DBEAFE; color: #1D4ED8; }
.type-info { background: #F3F4F6; color: #4B5563; }

/* ── Login page ─────────────────────────────────────────────────────────────── */
.login-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ips-dark) url('/static/assets/startup-background.png') center/cover no-repeat;
  position: relative;
  overflow: hidden;
}

.login-bg-circle {
  position: absolute;
  width: 700px;
  height: 700px;
  right: -200px;
  top: -200px;
  opacity: 0.15;
}

.login-card {
  background: white;
  border-radius: 20px;
  padding: 48px;
  width: 100%;
  max-width: 500px;
  position: relative;
  z-index: 1;
  box-shadow: 0 25px 80px rgba(0,0,0,0.3);
}

.login-animation {
  width: 100%;
  height: 280px;
  border: none;
  pointer-events: none;
  background: transparent;
  border-radius: 8px;
  margin-left: 14px;
}

/* ── Scrollbar ─────────────────────────────────────────────────────────────── */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #CBD5E1; border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: #94A3B8; }

/* Thicker scrollbar for the Planner Grid + Gantt scroll hosts. The default
   6px global bar is too thin to grab confidently when the user is panning
   a wide schedule. Bump to 14px on the affected hosts only — leaves every
   other panel's scrollbar slim. */
.planner-thick-scroll::-webkit-scrollbar { width: 18px; height: 18px; }
.planner-thick-scroll::-webkit-scrollbar-track {
  background: #CBD5E1;            /* darker than before — clearer track */
  border-radius: 9px;
  box-shadow: inset 0 0 4px rgba(0,0,0,0.10);
}
.planner-thick-scroll::-webkit-scrollbar-thumb {
  background: #475569;            /* slate-600 — high contrast against track */
  border-radius: 9px;
  border: 3px solid #CBD5E1;
  min-height: 40px;               /* never let the thumb shrink invisibly */
  min-width: 40px;
}
.planner-thick-scroll::-webkit-scrollbar-thumb:hover { background: #1E293B; }
.planner-thick-scroll::-webkit-scrollbar-corner { background: #CBD5E1; }
.planner-thick-scroll { scrollbar-width: auto; scrollbar-color: #475569 #CBD5E1; }   /* Firefox */

/* The Gantt's right pane is the authoritative horizontal scroll surface.
   Even when the timeline fits the viewport we keep the bottom scrollbar
   track visible so the user always sees the affordance and can tell at
   a glance whether there's more timeline to the right. The bottom border
   reinforces the visual edge of the panel. */
.planner-gantt-right-pane {
  border-bottom: 1px solid #94A3B8;
}

/* Hide the left pane's vertical scrollbar — the right pane is the
   authoritative scroll surface, and an extra scrollbar on the labels
   would be redundant. Wheel events on the left still scroll normally
   and the JS scroll handler syncs the panes. */
.planner-left-scroll-hidden { scrollbar-width: none; }
.planner-left-scroll-hidden::-webkit-scrollbar { width: 0; height: 0; display: none; }

/* ── Table ─────────────────────────────────────────────────────────────────── */
table { border-collapse: collapse; }

/* ── Transitions ───────────────────────────────────────────────────────────── */
.fade-enter-active, .fade-leave-active { transition: opacity 0.2s; }
.fade-enter-from, .fade-leave-to { opacity: 0; }

/* ─────────────────────────────────────────────────────────────────────────────
   Tablet & Touch Adaptations — Phase 1
   Desktop experience is unchanged. Rules below apply only on touch devices
   and/or narrow screens.
   ───────────────────────────────────────────────────────────────────────────── */

/* Touch input (finger/stylus, no hover):
   - enlarge tap targets
   - reveal action buttons that desktop hides until hover */
@media (hover: none) {
  .btn-icon { padding: 10px; }
  .opacity-0.group-hover\:opacity-100 { opacity: 1 !important; }
}

/* Narrow screens (tablet portrait + standard landscape, ≤1024px):
   - auto-collapse sidebar regardless of JS toggle state
   - cap modal widths to viewport
   - stack attachment/detail side panels below their sibling form/list */
@media (max-width: 1024px) {
  .sidebar,
  .sidebar.collapsed { width: 64px; }
  .sidebar .sidebar-logo { padding: 16px 8px; }
  .sidebar .sidebar-logo img { display: none; }
  .sidebar .nav-item { justify-content: center; padding: 10px; gap: 0; }
  .sidebar .nav-label,
  .sidebar .sidebar-user-info { display: none; }
  .sidebar .sidebar-user-section { justify-content: center; }
  .sidebar-toggle { display: none; }

  .main-content,
  .main-content.sidebar-collapsed { margin-left: 64px; }

  .modal-lg,
  .modal-xl,
  .modal-2xl { max-width: 92vw !important; }

  .content-area { padding: 16px; }
  .top-header { padding: 0 16px; }
  .sub-tab-bar { padding: 0 16px; }

  :has(> .w-\[28rem\].shrink-0.border-l) { flex-direction: column !important; }
  .w-\[28rem\].shrink-0.border-l {
    width: 100% !important;
    max-height: 40vh;
    border-left: none !important;
    border-top: 1px solid #e5e7eb !important;
  }
}

/* ── Help Center ──────────────────────────────────────────────────────────── */
.help-center { background: #fff; border-radius: 12px; box-shadow: 0 1px 2px rgba(0,0,0,0.04); border: 1px solid #e5e7eb; overflow: hidden; }
.help-shell { display: flex; flex-direction: column; min-height: calc(100vh - 110px); }
.help-topbar { background: #fff; border-bottom: 1px solid #E5E7EB; position: sticky; top: 0; z-index: 5; }
.help-tabs { padding: 8px 12px; display: flex; flex-wrap: wrap; gap: 5px; }
.help-tab { padding: 7px 13px; min-height: 36px; font-size: 13px; border-radius: 7px; border: 1px solid #E5E7EB; background: #fff; color: #4B5563; cursor: pointer; transition: color 0.12s, background 0.12s, border-color 0.12s; white-space: nowrap; font-weight: 500; }
.help-tab:hover { border-color: var(--ips-blue); color: var(--ips-blue); background: #F0F9FF; }
.help-tab.active { background: var(--ips-blue); color: #fff; border-color: var(--ips-blue); font-weight: 600; }
.help-tab.priority { background: #1B4F8C; color: #fff; border-color: #1B4F8C; font-weight: 600; }
.help-tab.priority:hover { background: var(--ips-blue); border-color: var(--ips-blue); color: #fff; }
.help-tab.priority.active { background: var(--ips-blue); border-color: var(--ips-blue); color: #fff; box-shadow: 0 0 0 2px rgba(0,174,239,0.3); }
.help-content { flex: 1; min-width: 0; overflow-y: auto; }
.help-article { max-width: 1280px; padding: 32px 36px 72px; line-height: 1.65; color: #1f2937; }
.help-article .flow-chart { width: 100%; }
.help-article .help-prose { max-width: 920px; }
.help-article h1 { font-size: 28px; font-weight: 700; color: #111827; margin: 0 0 6px; letter-spacing: -0.01em; }
.help-article h2 { font-size: 18px; font-weight: 700; color: #111827; margin: 28px 0 8px; padding-bottom: 4px; border-bottom: 1px solid #e5e7eb; }
.help-article h3 { font-size: 15px; font-weight: 700; color: var(--ips-dark); margin: 20px 0 6px; }
.help-article p { margin: 8px 0 12px; font-size: 14px; }
.help-article p.lead { font-size: 15px; color: #4b5563; margin-bottom: 18px; }
.help-article p.caption { font-size: 12px; color: #6b7280; font-style: italic; margin-top: 4px; }
.help-article ul { margin: 8px 0 14px; padding-left: 22px; font-size: 14px; }
.help-article ul li { margin: 4px 0; }
.help-article a { color: var(--ips-blue); text-decoration: underline; text-underline-offset: 2px; }
.help-article a:hover { color: var(--ips-dark); }
.help-article code { background: #F3F4F6; color: #1B4F8C; padding: 1px 6px; border-radius: 4px; font-size: 12.5px; font-family: 'Menlo', 'Consolas', monospace; }
.help-article strong { color: #111827; font-weight: 600; }
.help-article .callout { background: #F0F9FF; border: 1px solid #BAE6FD; border-left: 3px solid var(--ips-blue); border-radius: 8px; padding: 12px 16px; margin: 14px 0 18px; font-size: 13.5px; color: #0c4a6e; }
.help-article .callout p { margin: 0; font-size: 13.5px; }
.help-article .help-modulecard { background: #fff; border: 1px solid #E5E7EB; border-radius: 8px; padding: 12px 14px; transition: border-color 0.12s, box-shadow 0.12s; }
.help-article .help-modulecard:hover { border-color: var(--ips-blue); box-shadow: 0 1px 3px rgba(0,174,239,0.12); }
.help-article .help-table { width: 100%; border-collapse: collapse; margin: 10px 0 18px; font-size: 13px; }
.help-article .help-table th { text-align: left; background: #F9FAFB; color: #374151; font-weight: 600; padding: 8px 10px; border-bottom: 2px solid #E5E7EB; font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; }
.help-article .help-table td { padding: 8px 10px; border-bottom: 1px solid #F3F4F6; vertical-align: top; }
.help-article .help-table tr:hover td { background: #FAFBFC; }
.help-article .mermaid { background: #FAFBFC; border: 1px solid #E5E7EB; border-radius: 10px; padding: 18px; margin: 16px 0; text-align: center; overflow-x: auto; }
.help-article .mermaid svg { max-width: 100%; height: auto; }

/* ── Help Center: HTML flow diagrams ────────────────────────────────────── */
.help-article .flow { background: #FAFBFC; border: 1px solid #E5E7EB; border-radius: 10px; padding: 14px 16px; margin: 14px 0; display: flex; flex-direction: column; gap: 10px; overflow-x: auto; }
.help-article .flow-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: 12.5px; min-height: 32px; }
.help-article .flow-row.branch { padding: 8px 10px; border-left: 3px solid #FCA5A5; background: #FEF2F2; border-radius: 6px; margin-left: 4px; }
.help-article .flow-row.override { padding: 8px 10px; border-left: 3px solid #F59E0B; background: #FEF3C7; border-radius: 6px; margin-left: 4px; }
.help-article .flow-row.note { padding: 6px 10px; font-size: 12px; color: #4B5563; font-style: italic; }
.help-article .flow-label { font-size: 11px; font-weight: 700; color: #6B7280; text-transform: uppercase; letter-spacing: 0.05em; min-width: 84px; }
.help-article .flow-pill { display: inline-block; background: #fff; border: 1.5px solid #1B4F8C; color: #1B4F8C; padding: 5px 11px; border-radius: 16px; font-weight: 600; font-size: 12px; line-height: 1.3; white-space: nowrap; }
.help-article .flow-pill.start { background: #1B4F8C; color: #fff; border-color: #1B4F8C; }
.help-article .flow-pill.ok { border-color: #059669; color: #059669; background: #ECFDF5; }
.help-article .flow-pill.err { border-color: #DC2626; color: #DC2626; background: #FEF2F2; }
.help-article .flow-pill.alt { border-color: #D97706; color: #B45309; background: #FEF3C7; }
.help-article .flow-pill.decision { border-color: #00AEEF; color: #0369A1; background: #F0F9FF; border-style: dashed; }
.help-article .flow-arrow { color: #6B7280; font-weight: 700; font-size: 16px; padding: 0 2px; user-select: none; }
.help-article .flow-arrow.dashed { color: #D97706; }
.help-article .flow-edge { font-size: 10.5px; color: #4B5563; font-weight: 600; padding: 0 2px; font-style: italic; }

/* ── Help Center: ISO 5807 SVG flowcharts ────────────────────────────────── */
.help-article .flow-chart { background: #FAFBFC; border: 1px solid #E5E7EB; border-radius: 10px; padding: 16px; margin: 14px 0; overflow-x: auto; }
.help-article .flow-chart svg.flowchart-svg { display: block; max-width: 100%; height: auto; min-width: 480px; }
.help-article .flow-legend { display: flex; gap: 12px; flex-wrap: wrap; padding-top: 8px; margin-top: 6px; border-top: 1px solid #F3F4F6; font-size: 11px; color: #6B7280; }
.help-article .flow-legend-item { display: inline-flex; align-items: center; gap: 5px; }
.help-article .flow-legend-swatch { width: 16px; height: 10px; border-radius: 4px; border: 1.5px solid #1B4F8C; background: #fff; display: inline-block; }
.help-article .flow-legend-swatch.start { background: #1B4F8C; border-color: #1B4F8C; }
.help-article .flow-legend-swatch.end { background: #ECFDF5; border-color: #059669; }
.help-article .flow-legend-swatch.cancel { background: #FEF2F2; border-color: #DC2626; }
.help-article .flow-legend-swatch.decision { background: #F0F9FF; border-color: #0369A1; transform: rotate(45deg); width: 12px; height: 12px; border-radius: 1px; }
.help-article .flow-legend-swatch.override { background: #FEF3C7; border-color: #D97706; }

/* Related-references inline bar at the top of each module section */
.help-article .help-references { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 6px 0 18px; padding: 8px 12px; background: #F0F9FF; border: 1px solid #BAE6FD; border-radius: 8px; font-size: 12px; }
.help-article .help-ref-label { color: #075985; font-weight: 700; padding-right: 4px; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em; }
.help-article .help-ref-link { display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; background: #fff; border: 1px solid #BAE6FD; border-radius: 6px; color: var(--ips-dark); text-decoration: none !important; font-weight: 500; font-size: 12px; white-space: nowrap; transition: background 0.12s, border-color 0.12s, color 0.12s; }
.help-article .help-ref-link:hover { background: var(--ips-blue); color: #fff; border-color: var(--ips-blue); }
.help-article .help-ref-link svg { width: 12px; height: 12px; }

/* ── Planner grid ────────────────────────────────────────────────────── */
.planner-grid {
  /* Single source of truth for the title-row height so the filter row's
     sticky offset can stack below it without hard-coded pixel values. */
  --planner-th-height: 33px;
  border-collapse: separate; border-spacing: 0;
  /* Authoritative column widths — required so the resize handles work
     identically in compact and wrapped row modes (otherwise the browser
     ignores explicit widths in favour of content). */
  table-layout: fixed;
  /* Slightly tighter font than the default text-sm, so more rows + columns
     are visible without scrolling. */
  font-size: 12.5px;
  line-height: 1.35;
}
.planner-grid th, .planner-grid td {
  vertical-align: middle;
  font-size: 12.5px;
  /* Light-grey grid lines so columns and rows are visually delineated. */
  border-right: 1px solid #F1F5F9;
  border-bottom: 1px solid #F1F5F9;
}
.planner-grid th { font-size: 11px; }   /* uppercase header — tighter still */
.planner-cell-display, .planner-cell-edit { font-size: 12.5px; }
.planner-grid th {
  background: #F9FAFB;
  border-bottom-color: #E5E7EB;
  /* Freeze the column headers when the table card scrolls vertically. */
  position: sticky;
  top: 0;
  z-index: 3;
}
.planner-grid tr:last-child td { border-bottom: 0; }
.planner-grid th:last-child, .planner-grid td:last-child { border-right: 0; }
.planner-grid input.input-field, .planner-grid select.input-field {
  /* Slim cell-fitting editors. Override the global field padding. */
  padding: 2px 6px;
  height: auto;
  min-height: 0;
}
.planner-grid select.input-field { padding-right: 18px; }

/* Excel-style cell focus + uniform display.
   The data <td>s are made focusable (tabindex=0). Arrow keys, Tab and
   Enter move the focus; clicking or typing on a focused cell opens the
   inline editor. See onCellClick / onCellKeydown / focusCell in planner.js. */
.planner-grid td.planner-cell {
  position: relative;
  outline: none;
  cursor: cell;
}
.planner-grid td.planner-cell:focus,
.planner-grid td.planner-cell.is-focused {
  box-shadow: inset 0 0 0 2px #2563eb;
  z-index: 1;
}
.planner-grid td.planner-readonly { cursor: default; }
.planner-cell-display {
  display: block;
  width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-height: 1.25em;
  color: #374151;
}
.planner-cell-display.planner-empty { color: #C7CDD6; }
/* Date that is locked by a predecessor on an AUTO task — read-only and
   greyed so it visibly differs from the user-editable dates next to it. */
.planner-cell-display.planner-locked { color: #9CA3AF; }
/* Pred. cell when at least one predecessor is a SUMMARY task. The engine
   still resolves these via leaf-expansion (see _expand_summary_deps in
   _schedule_engine.py) but it usually means the user forgot to point at
   the right child — flag it red with a tooltip. */
.planner-cell-display.planner-pred-warn { color: #DC2626; font-weight: 600; }
/* Light-red wash on the whole Pred. cell when at least one predecessor is
   a summary — gives the user an at-a-glance signal alongside the red text. */
.planner-grid td:has(.planner-pred-wrap.has-summary-pred),
.planner-grid td .planner-pred-wrap.has-summary-pred {
  background: #FEF2F2;
}

/* Pred. cell action button (gear icon) — same hover-reveal pattern as
   the row actions in the Description cell, anchored to the right edge. */
.planner-pred-wrap {
  position: relative;
  display: block;
  width: 100%;
  min-height: 1.25em;
}
.planner-pred-actions {
  position: absolute;
  right: 2px;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  opacity: 0;
  transition: opacity 0.12s;
  background: rgba(255, 255, 255, 0.92);
  padding: 1px 2px;
  border-radius: 4px;
  box-shadow: -4px 0 6px -2px rgba(255, 255, 255, 0.92);
}
.planner-grid tr:hover .planner-pred-actions,
.planner-grid tr:focus-within .planner-pred-actions { opacity: 1; }
.planner-pred-wrap.has-summary-pred .planner-pred-actions { background: rgba(254, 242, 242, 0.92); box-shadow: -4px 0 6px -2px rgba(254, 242, 242, 0.92); }

/* Auto / Manual mode pill in the grid — clearly clickable and colour-coded
   so the user can scan a column and see the scheduling stance at a glance. */
.planner-mode-pill {
  display: inline-block;
  padding: 0 6px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  border-radius: 9999px;
  border: 1px solid;
  cursor: pointer;
  user-select: none;
  line-height: 1.45;
}
.planner-mode-pill.is-auto   { background: #ECFDF5; color: #065F46; border-color: #6EE7B7; }
.planner-mode-pill.is-manual { background: #FEF3C7; color: #92400E; border-color: #FCD34D; }
.planner-mode-pill.is-auto:hover   { background: #D1FAE5; }
.planner-mode-pill.is-manual:hover { background: #FDE68A; }

/* Vendor-created task description — italic + amber so the project owner
   can scan a schedule and see vendor territory at a glance. Applied to any
   task whose backend `is_vendor_created` is true (set when the resolved
   parent at create-time is anywhere inside a vendor-lock subtree, regardless
   of who actually created the row). Persists across lock/unlock cycles. */
.planner-vendor-created .planner-cell-display,
.planner-vendor-created input.planner-cell-edit {
  color: #B45309;          /* amber-700 */
  font-style: italic;
  /* Italic glyphs slant past their character box; combined with the cell's
     overflow:hidden it clips the rightmost character — most visible on
     right-aligned cells (weight, duration, progress, etc.). Tiny right
     padding gives the slant breathing room; box-sizing keeps the block
     contained within the <td>'s content area. */
  padding-right: 3px;
  box-sizing: border-box;
}
.planner-vendor-created.font-semibold .planner-cell-display { font-weight: 600; }

/* Envelope-violation indicator — a vendor-locked subtree task that escaped
   the lock root's date/weight envelope. Tints only the description cell so
   the violation is visible without screaming the whole row red. The "late"
   cell tint (below) overrides this when both apply, since a schedule slip
   is the bigger story than an envelope drift. */
.planner-desc-envelope-violation {
  background: rgba(249, 115, 22, 0.10);   /* orange-500 @ 10% — gentle wash */
}
/* Late = actual progress is behind expected linear progress between start
   and finish (matches taskStatus().key === 'late'). Description-cell red
   so the status pill in the status column is mirrored at the row anchor. */
.planner-desc-late {
  background: rgba(239, 68, 68, 0.12);    /* red-500 @ 12% — wins over violation */
}
.planner-envelope-violation-badge {
  display: inline-block;
  padding: 0 5px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  border-radius: 9999px;
  background: #DC2626;     /* red-600 */
  color: white;
  line-height: 1.45;
  cursor: help;
}

/* Scope-module: cells whose ancestor row has the budget-freeze flag
   on. The values are "documentation only" — they don't roll up to the
   project total. We grey out the text (instead of patterning the
   background) so the column stays readable but is unambiguously
   marked as non-contributing. */
.scope-cell-noncontributing,
.scope-cell-noncontributing .planner-cell-display,
.scope-cell-noncontributing .planner-cell-edit {
  color: #94A3B8;        /* slate-400 */
}

/* Scope-module — WBS row depth tints. Level 1 = dark navy with white
   text, Level 2 = light blue, Level 3 = light grey. Depth 4+ stays
   neutral (default row hover). Apply only to PARENT rows (rows with
   children). Selection (`bg-blue-50`) wins over these via the template. */
.scope-row-l1 {
  background: #1B4F8C;   /* ips-dark */
  color: #FFFFFF;
}
.scope-row-l1:hover {
  background: #163E70;
}
/* Force every cell-level text class to inherit the white from the row,
   otherwise the per-column gray/blue overrides bleed through (e.g.
   `text-gray-500` on the WBS code, `font-mono text-gray-400` on ID). */
.scope-row-l1 .planner-cell,
.scope-row-l1 .planner-cell-display,
.scope-row-l1 .planner-empty,
.scope-row-l1 td,
.scope-row-l1 .planner-grip {
  color: inherit !important;
}
.scope-row-l1 .planner-cell-display.planner-empty {
  color: rgba(255, 255, 255, 0.5) !important;
}
.scope-row-l2 {
  background: #E8F4FD;   /* ips-light */
}
.scope-row-l2:hover {
  background: #D6E9F8;
}
.scope-row-l3 {
  background: #F3F4F6;   /* gray-100 */
}
.scope-row-l3:hover {
  background: #E5E7EB;   /* gray-200 */
}

/* Scope-module: qty / unit / unit-price cells on a non-frozen parent.
   These are intentionally empty — values live on the children (rollup
   mode) or on Ini.* (parked). Solid grey wash so the user reads
   "this cell isn't yours to fill" without confusing it with the more
   loaded "non-contributing" stripe pattern above. */
.scope-cell-parent-empty {
  background-color: rgba(148, 163, 184, 0.10);   /* slate-400 @ 10% */
}

/* Scope-module: AACE class auto-derived from the rolled-up min/max
   range on a non-frozen parent. Different colour family (teal) so the
   user sees at a glance which AACE values were typed manually (gray
   pill) vs auto-computed (teal pill). */
.scope-aace-derived {
  background: #CCFBF1;        /* teal-100 */
  border: 1px solid #99F6E4;  /* teal-200 */
  color: #115E59;             /* teal-800 */
  font-style: italic;
}

/* Scope-module: every grid cell is positioned relative so the fill
   handle (bottom-right) anchors correctly. Focus outline replaces the
   browser default with a clean blue ring; the planner-grid uses the
   same look on focused cells, so the two grids feel consistent. */
.scope-cell { position: relative; outline: none; }
.scope-cell.is-focused {
  box-shadow: inset 0 0 0 2px #2563EB;   /* blue-600 ring */
}

/* Excel-style fill handle — small filled square at the bottom-right
   corner of the focused cell. Drag it down to copy the cell's value
   into rows below. */
.scope-fill-handle {
  position: absolute;
  right: -3px;
  bottom: -3px;
  width: 7px;
  height: 7px;
  background: #2563EB;        /* blue-600 */
  border: 1px solid #fff;
  cursor: crosshair;
  z-index: 5;
}
.scope-fill-handle:hover { background: #1B4F8C; }

/* Scope-module: Long-Lead-Item badge inline next to the lead-time
   value. Amber pill — matches the LLI list highlight in the
   Dashboard so the row is recognisable at a glance. */
.scope-lli-badge {
  display: inline-block;
  margin-left: 4px;
  padding: 0 5px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.05em;
  border-radius: 9999px;
  background: #FEF3C7;       /* amber-100 */
  color: #92400E;            /* amber-800 */
  border: 1px solid #FCD34D; /* amber-300 */
  vertical-align: middle;
}

/* Scope-module: 'F' inline row-action button reusing the same
   pattern as the '+' / 'C' buttons next to the description cell.
   Dark-blue when frozen, light grey when not — matches the visual
   weight of the surrounding buttons so it's unambiguously clickable. */
.planner-row-btn-frozen-off { background: #F1F5F9; color: #64748B; }
.planner-row-btn-frozen-off:hover:not(:disabled) {
  background: #E2E8F0; color: #1E293B;
}
.planner-row-btn-frozen-on  { background: #1E40AF; color: #fff; border-color: #1E40AF; }
.planner-row-btn-frozen-on:hover:not(:disabled) { background: #1E3A8A; }

/* Scope-module: parent-freeze toggle on the WBS grid. Native
   checkboxes had Vue 3 reactivity quirks (the :checked binding would
   sometimes lag behind the click, masking that the toggle had fired);
   this button is unambiguous — the icon + colour reflect state
   directly, click handler is the canonical action. */
.scope-frozen-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 22px;
  border: 1px solid #CBD5E1;
  background: #fff;
  border-radius: 4px;
  font-size: 12px;
  cursor: pointer;
  color: #94A3B8;
  transition: background 120ms, border-color 120ms, color 120ms;
}
.scope-frozen-toggle:hover:not(:disabled) {
  background: #F1F5F9;
  border-color: #94A3B8;
  color: #475569;
}
.scope-frozen-toggle:disabled { cursor: not-allowed; opacity: 0.5; }
.scope-frozen-toggle.is-frozen {
  background: #DBEAFE;       /* blue-100 */
  border-color: #3B82F6;     /* blue-500 */
  color: #1E40AF;            /* blue-900 */
}
.scope-frozen-toggle.is-frozen:hover:not(:disabled) {
  background: #BFDBFE;       /* blue-200 */
}

/* Excel-style fill marquee — single dashed-blue border that tracks
   the drag from source cell to the cell under the cursor. Viewport-
   fixed so it overlays the table regardless of scroll position;
   pointer-events disabled so the underlying mousemove still hits the
   cells. Replaced the older per-cell background tint because users
   couldn't easily see where the fill range ended. */
.scope-fill-marquee {
  position: fixed;
  border: 1.5px dashed #2563EB;            /* blue-600 */
  background: rgba(37, 99, 235, 0.06);     /* very light blue fill */
  pointer-events: none;
  z-index: 50;
  box-sizing: border-box;
}

/* Wrap mode: the user toggled rows to grow with their content. Drop the
   single-line truncation so descriptions (and any long text) wrap. */
.planner-grid.is-wrap td { vertical-align: top; }
.planner-grid.is-wrap .planner-cell-display {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  word-break: break-word;
}

/* Column-resize handle in <th>. The handle is wider than the visible line
   so it's easy to grab; the visible line itself is a 2px central strip
   that turns blue on hover so the user can clearly see what to drag. */
.planner-th { position: relative; }
.planner-col-resize {
  position: absolute;
  top: 0; right: -3px;          /* straddle the column border */
  width: 7px; height: 100%;
  cursor: col-resize;
  user-select: none;
  z-index: 2;
  display: flex;
  align-items: stretch;
  justify-content: center;
}
.planner-col-resize::before {
  content: '';
  width: 2px; height: 100%;
  background: #CBD5E1;
}
.planner-col-resize:hover::before,
.planner-col-resize:active::before { background: #2563EB; }
.planner-cell-edit {
  /* Editor that fills the cell. */
  width: 100%;
  padding: 2px 6px;
  font: inherit;
  background: #fff;
  border: 1px solid #2563eb;
  border-radius: 0;
  outline: none;
  box-sizing: border-box;
}
select.planner-cell-edit { padding-right: 18px; }

/* Slightly tighter sub-tabs for the Planner — bigger than the original
   override so they stay easy to hit, smaller than the platform default
   so the Gantt still gets more vertical space. */
.planner-subtab {
  padding: 7px 18px !important;
  font-size: 13.5px !important;
  line-height: 1.25 !important;
}

/* Compact Grid action toolbar — slimmer button height than the platform
   default btn-primary / btn-secondary so the +Add task / +Add child /
   Indent / Outdent / Delete row doesn't dominate the page. The select
   (Outline-level) and any input-field inputs share the same vertical
   sizing so everything in the row lines up. */
.planner-grid-toolbar .btn-primary,
.planner-grid-toolbar .btn-secondary,
.planner-grid-toolbar select.input-field,
.planner-grid-toolbar input.input-field {
  padding-top: 4px !important;
  padding-bottom: 4px !important;
  font-size: 12px !important;
  line-height: 1.2 !important;
  height: 28px !important;
  box-sizing: border-box !important;
}

/* Row actions inside the description cell: small + / D / C buttons that
   appear only when the row is hovered or selected, so the grid stays
   uncluttered. Absolutely positioned so they FLOAT over the right end
   of the description text instead of stealing layout width — the
   description gets the full cell width when the row isn't hovered. */
.planner-desc {
  display: flex;
  align-items: center;
  gap: 4px;
  position: relative;
  padding-right: 0;
}
.planner-row-actions {
  position: absolute;
  right: 2px;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  gap: 2px;
  opacity: 0;
  transition: opacity 0.12s;
  flex-shrink: 0;
  background: rgba(255, 255, 255, 0.92);
  padding: 1px 2px;
  border-radius: 4px;
  box-shadow: -4px 0 6px -2px rgba(255, 255, 255, 0.92);
}
.planner-grid tr:hover .planner-row-actions,
.planner-grid tr:focus-within .planner-row-actions,
.planner-grid tr.bg-blue-50 .planner-row-actions { opacity: 1; }
.planner-row-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px;
  padding: 0;
  font-size: 12px; font-weight: 700; line-height: 1;
  background: #fff;
  color: #6B7280;
  border: 1px solid #D1D5DB;
  border-radius: 4px;
  cursor: pointer;
}
.planner-row-btn:hover { background: #EFF6FF; color: #1D4ED8; border-color: #93C5FD; }
.planner-row-btn:disabled { opacity: 0.4; cursor: default; }
.planner-row-btn-dep { color: #047857; }
.planner-row-btn-dep:hover { background: #ECFDF5; color: #065F46; border-color: #6EE7B7; }
.planner-row-btn-child { color: #7C3AED; }
.planner-row-btn-child:hover { background: #F5F3FF; color: #5B21B6; border-color: #C4B5FD; }
.planner-row-btn-finish { color: #1E40AF; }
.planner-row-btn-finish:hover { background: #DBEAFE; color: #1E3A8A; border-color: #93C5FD; }
.planner-row-btn-copy { color: #B45309; font-size: 11px; }
.planner-row-btn-copy:hover { background: #FEF3C7; color: #92400E; border-color: #FCD34D; }

/* ── Status pill ───────────────────────────────────────────────────── */
.planner-status-pill {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  border: 1px solid;
  white-space: nowrap;
  line-height: 1.4;
}
.planner-status-pill.is-not-started { background: #F3F4F6; color: #4B5563; border-color: #D1D5DB; }
.planner-status-pill.is-on-schedule { background: #ECFDF5; color: #065F46; border-color: #6EE7B7; }
.planner-status-pill.is-late        { background: #FEE2E2; color: #991B1B; border-color: #FCA5A5; }
.planner-status-pill.is-finished    { background: #DBEAFE; color: #1E40AF; border-color: #93C5FD; }

/* ── Per-column filter row ────────────────────────────────────────── */
/* The label row above sits sticky at top:0; this row stacks below it
   when the table scrolls vertically. Offset comes from the
   --planner-th-height variable on .planner-grid so changes to label-row
   padding only need to be made in one place. `position: sticky` is set
   explicitly (not inherited from the generic .planner-grid th rule) so a
   subtle cascade quirk can't leave the filter row scrolling with the
   body. A px fallback on the variable guards the same way. */
.planner-grid thead tr.planner-filter-row > th {
  position: sticky;
  top: var(--planner-th-height, 33px);
  z-index: 2;
  background: #fff;
  border-bottom: 1px solid #E5E7EB;
}
.planner-filter-input {
  width: 100%;
  padding: 2px 6px;
  font-size: 11.5px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: #374151;
  background: #F9FAFB;
  border: 1px solid #E5E7EB;
  border-radius: 4px;
  outline: none;
}
.planner-filter-input:focus { background: #fff; border-color: #93C5FD; }
.planner-filter-input::placeholder { color: #9CA3AF; font-style: italic; }

/* ── Column filter dropdown (planner grid + scope WBS) ──────────────── */
.planner-colfilter-root { position: relative; width: 100%; }
.planner-colfilter-btn {
  width: 100%;
  display: inline-flex; align-items: center; justify-content: space-between;
  padding: 2px 6px;
  font-size: 11px; line-height: 1.4;
  background: #F3F4F6;
  color: #6B7280;
  border: 1px solid #E5E7EB;
  border-radius: 4px;
  cursor: pointer;
  text-align: left;
}
.planner-colfilter-btn:hover { background: #E5E7EB; border-color: #D1D5DB; color: #374151; }
.planner-colfilter-btn.is-active {
  background: #DBEAFE; color: #1E40AF; border-color: #93C5FD; font-weight: 600;
}
.planner-colfilter-btn.is-active:hover { background: #BFDBFE; border-color: #60A5FA; }
.planner-colfilter-label {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  flex: 1; min-width: 0;
}
.planner-colfilter-caret { margin-left: 4px; font-size: 10px; opacity: 0.7; }
.planner-colfilter-pop {
  position: fixed;
  z-index: 1100;
  width: 260px;
  max-height: 360px;
  background: #fff;
  border: 1px solid #D1D5DB;
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.18);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.planner-colfilter-pop-head {
  padding: 8px; border-bottom: 1px solid #E5E7EB;
}
.planner-colfilter-search {
  width: 100%; padding: 4px 8px; font-size: 12px;
  border: 1px solid #D1D5DB; border-radius: 4px;
  outline: none;
}
.planner-colfilter-search:focus { border-color: #93C5FD; }
.planner-colfilter-pop-actions {
  display: flex; align-items: center; gap: 12px;
  padding: 4px 8px; border-bottom: 1px solid #E5E7EB; font-size: 11px;
  background: #F9FAFB;
}
.planner-colfilter-link {
  color: #1D4ED8; cursor: pointer; background: none; border: none;
  padding: 0; font-size: 11px;
}
.planner-colfilter-link:hover { text-decoration: underline; }
.planner-colfilter-count { margin-left: auto; color: #6B7280; font-size: 10px; }
.planner-colfilter-pop-list {
  flex: 1; overflow-y: auto; padding: 4px 0;
}
.planner-colfilter-option {
  display: flex; align-items: center; gap: 6px;
  padding: 3px 10px; font-size: 12px; cursor: pointer;
  user-select: none;
}
.planner-colfilter-option:hover { background: #F3F4F6; }
.planner-colfilter-option input[type="checkbox"] { margin: 0; }
.planner-colfilter-option-text {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  flex: 1; min-width: 0; color: #374151;
}
.planner-colfilter-empty {
  padding: 12px; text-align: center; color: #9CA3AF; font-size: 11px; font-style: italic;
}

/* ── Touch variant — bigger tap targets for tablet use (documents grid) ── */
.planner-colfilter-root.is-touch .planner-colfilter-btn {
  min-height: 38px; padding: 6px 10px; font-size: 13px;
}
.planner-colfilter-root.is-touch .planner-colfilter-caret { font-size: 12px; }
.is-touch .planner-colfilter-pop { max-height: 440px; }
.is-touch .planner-colfilter-search { padding: 10px 12px; font-size: 15px; }
.is-touch .planner-colfilter-pop-actions { padding: 8px 12px; gap: 16px; }
.is-touch .planner-colfilter-link { padding: 6px 2px; font-size: 13px; }
.is-touch .planner-colfilter-option {
  padding: 10px 12px; font-size: 14px; min-height: 44px; gap: 10px;
}
.is-touch .planner-colfilter-option input[type="checkbox"] {
  width: 20px; height: 20px; flex: 0 0 auto;
}

/* ── Package modal tabs: stack both panels in one grid cell so the modal
   keeps the taller (Details) tab's height when switching to Package Groups.
   The inactive panel stays in layout (visibility:hidden) so it still sizes
   the shared cell, but can't be seen or clicked. ── */
.pkg-tab-stack { display: grid; }
.pkg-tab-stack > .pkg-tab-panel { grid-area: 1 / 1; min-width: 0; }
.pkg-tab-panel.pkg-tab-hidden { visibility: hidden; pointer-events: none; }

/* ── Range variant — date / number From-To bounds in the filter popover ── */
.planner-colfilter-range { padding: 10px; display: flex; flex-direction: column; gap: 8px; }
.planner-colfilter-range-row {
  display: flex; align-items: center; gap: 8px; font-size: 12px; color: #374151;
}
.planner-colfilter-range-row > span { width: 40px; color: #6B7280; flex: 0 0 auto; }
.planner-colfilter-range-row input {
  flex: 1; min-width: 0; padding: 5px 8px; font-size: 12px;
  border: 1px solid #D1D5DB; border-radius: 4px; outline: none;
}
.planner-colfilter-range-row input:focus { border-color: #93C5FD; }
.planner-colfilter-range .planner-colfilter-pop-actions {
  border-bottom: none; border-top: 1px solid #E5E7EB; margin: 2px -10px -10px;
}
.is-touch .planner-colfilter-range-row { font-size: 14px; }
.is-touch .planner-colfilter-range-row input { padding: 9px 10px; font-size: 15px; min-height: 40px; }

/* ── Documents grid: per-column filter row sits just under the header row.
   The shared .meeting-table-scroll pins every thead row at top:0; nudge the
   filter row down by the header-row height so the two don't overlap. ──────── */
.meeting-table-scroll thead tr.doc-filter-row th {
  top: 41px; background: #FFFFFF; z-index: 4;
  box-shadow: inset 0 -1px 0 #E5E7EB;
}

/* ── Weekly meeting view: overlap marker ────────────────────────────
   Inset 3px amber stripe on the left of any card that conflicts in time
   with another meeting on the same day. Inset shadow keeps the card's
   own border + bg untouched (no widening, no extra DOM). */
.meeting-card-conflict {
  box-shadow: inset 3px 0 0 #F59E0B;
}

/* ── Meeting tab tables: vertical scroll inside the card with sticky head
   ── so column headers stay visible while the user scrolls. The toolbar
   ── above the card (filters + action buttons) stays in normal flow and
   ── never scrolls off because the scroll happens inside this container. */
.meeting-table-scroll {
  /* overflow on both axes so wide tables (QC ITP / Punchlist,
     Procurement Plan) can scroll horizontally inside the same scroll
     container that handles the vertical sticky-header behaviour. Tables
     that fit horizontally just don't show a horizontal bar — the
     vertical sticky thead still works either way. */
  overflow: auto;
  /* Leaves room for: top app bar, sub-tab bar, compact toolbar, and a
     little breathing space at the bottom of the viewport. min-height
     prevents the table from collapsing to nothing on short screens. */
  max-height: calc(100vh - 260px);
  min-height: 360px;
}
.meeting-table-scroll table { width: 100%; }
.meeting-table-scroll thead th,
.meeting-table-scroll thead tr {
  position: sticky; top: 0; z-index: 5;
  /* The shadow makes the boundary obvious as rows scroll under the head. */
  box-shadow: inset 0 -1px 0 #E5E7EB;
}
/* Background is repeated on every <th> because the <tr>'s own background
   doesn't paint during sticky in some browsers — cleanest fix is to set
   the bg on each cell directly. */
.meeting-table-scroll thead th { background: #F9FAFB; }

/* ── Drag-to-reorder ──────────────────────────────────────────────── */
.planner-grip-cell { cursor: grab; user-select: none; width: 18px; }
.planner-grip-cell:active { cursor: grabbing; }
.planner-grip {
  display: inline-block;
  color: #D1D5DB;
  font-size: 12px;
  letter-spacing: -2px;
  font-weight: 700;
  line-height: 1;
  transition: color 0.12s;
}
.planner-grid tr:hover .planner-grip { color: #6B7280; }
.planner-drag-source { opacity: 0.4; }
/* Top-half drop → blue line at the TOP of the target row (insert before).
   Bottom-half drop → line at the BOTTOM (insert after). */
.planner-drag-target-before > td { box-shadow: inset 0  2px 0 0 #2563EB; }
.planner-drag-target-after  > td { box-shadow: inset 0 -2px 0 0 #2563EB; }

/* ── Project summary row pinned at the top of the grid ──────────────── */
.planner-project-row > td {
  background: var(--ips-light);
  font-weight: 700;
  color: var(--ips-dark);
  border-bottom: 2px solid var(--ips-blue);
}
.planner-project-row .planner-cell-display { color: var(--ips-dark); }
.planner-project-row .planner-empty::after { content: ''; }
.planner-project-row .planner-status-pill { font-weight: 700; }

/* ── Active state for toolbar toggle buttons (e.g. Filter on) ──────── */
.btn-secondary.is-active-toggle {
  background: #DBEAFE;
  color: #1E40AF;
  border-color: #93C5FD;
}

/* Critical leaves: subtle red text (the ⚡ icon next to the description handles
   the visual cue; we also tint the row's slack column independently). */
.planner-critical-row > td:nth-child(3) { color: #B91C1C; }   /* description col */

/* Late leaves were previously highlighted with a light-red row background.
   That clashed with the envelope-violation tint, so the row background was
   removed and replaced with a ⏰ glyph in the description (analogous to the
   ⚡ critical / 🔒 vendor-lock chips). */

/* Inline predecessor combobox */
.planner-pred-cell { position: relative; }
.planner-pred-popdown {
  position: absolute;
  left: 0; top: 100%;
  z-index: 30;
  min-width: 280px; max-width: 420px;
  max-height: 240px;
  overflow-y: auto;
  background: #fff;
  border: 1px solid #D1D5DB;
  border-top: none;
  border-radius: 0 0 6px 6px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.10);
}
.planner-pred-popdown-item {
  display: flex;
  gap: 8px;
  width: 100%;
  padding: 6px 10px;
  text-align: left;
  font-size: 12px;
  cursor: pointer;
  background: transparent;
  border: 0;
  border-bottom: 1px solid #F3F4F6;
}
.planner-pred-popdown-item:hover { background: #F0F9FF; }
.planner-pred-popdown-item:last-child { border-bottom: 0; }
.planner-pred-popdown-row {
  font-family: 'Menlo','Consolas',monospace;
  color: #4B5563;
  font-weight: 600;
  min-width: 28px;
}
.planner-pred-popdown-label { color: #374151; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }


/* ─────────────────────────────────────────────────────────────────────────
   Organization chart (2026-05-12 HTML+CSS rebuild)
   Classic CSS org-chart with pseudo-element connectors. SECONDARY
   (matrix) edges are drawn as a separate SVG overlay so polylines
   between arbitrary cards stay decoupled from the layout grid.
   ───────────────────────────────────────────────────────────────────────── */

.oc-canvas {
  position: relative;
  overflow: auto;
  padding: 32px 16px;
  background: #FAFBFC;
  border-radius: 8px;
  min-height: 280px;
}
/* Block-level flex with `width: max-content` — a block element by default
   sits at the LEFT of its parent and `width:max-content` collapses it to
   its natural content size. Result: the chart hugs the canvas's left
   edge, any leftover empty space falls on the RIGHT, and there's no
   reliance on text-align cascade quirks. */
.oc-canvas-inner {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 32px;
  width: max-content;
}
/* Tree sizes to its content so multi-root width drives canvas-inner.
   Override `.oc-tree`'s `justify-content: center` here so root cards
   anchor to the LEFT of the tree's content area, not centered (which
   would have left/right padding when the tree fills wider parents). */
.oc-canvas-inner > .oc-tree {
  flex: 0 0 auto;
  justify-content: flex-start;
}

/* ── Steering-committee box (draggable, fancier card) ─────────────────
   The critical decision-making team — distinctive indigo gradient
   header, subtle shadow, hover lift on cards. Width is intentionally
   `auto` (min-width:220px) so the box stretches to fit the longest
   Name — Function line. Sits in flex flow by default; when the user
   drags it the Vue component sets inline `position:absolute; left/top`
   so it floats wherever they parked it. */
.oc-steering {
  flex: 0 0 auto;
  background: linear-gradient(180deg, #FFFFFF 0%, #F5F3FF 100%);
  border: 1.5px solid #818CF8;
  border-radius: 12px;
  min-width: 220px;
  box-shadow: 0 4px 16px rgba(99, 102, 241, 0.14),
              0 1px 3px rgba(99, 102, 241, 0.08);
  overflow: hidden;
  z-index: 5;   /* above tree connectors when positioned absolutely */
}
.oc-steering-dragging {
  box-shadow: 0 14px 36px rgba(99, 102, 241, 0.36),
              0 4px 10px rgba(99, 102, 241, 0.20) !important;
  z-index: 10;
  user-select: none;
}
.oc-steering-title {
  background: linear-gradient(135deg, #6366F1 0%, #8B5CF6 60%, #A855F7 100%);
  color: #FFFFFF;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 9px 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
.oc-steering-handle { cursor: grab; }
.oc-steering-dragging .oc-steering-handle { cursor: grabbing; }
.oc-steering-icon {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
}
.oc-steering-grip {
  width: 12px;
  height: 12px;
  margin-left: auto;
  opacity: 0.75;
  flex: 0 0 auto;
}
.oc-steering-list {
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.oc-steering-card {
  padding: 7px 11px;
  background: #FFFFFF;
  border: 1px solid #E0E7FF;
  border-radius: 7px;
  font-size: 12px;
  color: #1E1B4B;
  cursor: pointer;
  white-space: nowrap;          /* keep "Name — Function" on one row */
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  transition: transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
}
.oc-steering-card:hover {
  border-color: #818CF8;
  box-shadow: 0 4px 10px rgba(99, 102, 241, 0.18);
  transform: translateY(-1px);
}
.oc-steering-name { font-weight: 600; color: #312E81; }
.oc-steering-fn { color: #6366F1; font-weight: 500; }
/* Tree structure — ul/li nesting with pseudo-element connectors. */
.oc-tree, .oc-tree ul {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}
/* Outer tree is itself a flex row so multiple independent root trees
   sit SIDE-BY-SIDE rather than stacking vertically. (The descendant
   `.oc-tree ul` rule below handles the child rows the same way.)
   `width: max-content` collapses the tree to the exact size of its
   children + gaps, and `justify-content: flex-start` keeps the roots
   anchored to the LEFT inside that bounding box so empty space (if
   any) falls on the right. */
.oc-tree {
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
  gap: 60px;
  text-align: center;
  width: max-content;
}
/* `gap` used to create breaks in the trunk because each child's `::before`
   (left half) and `::after` (right half) ended at its own LI bounds —
   the gap between LIs went unbridged. Use horizontal LI padding only;
   adjacent LIs touch at the boundary so the half-segments meet
   continuously across the children row. */
.oc-tree ul {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding-top: 28px;
}
.oc-tree li {
  position: relative;
  padding: 28px 14px 0 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
}
/* Top-level root has no incoming line. */
.oc-tree > li {
  padding-top: 0;
}
.oc-tree > li::before,
.oc-tree > li::after { display: none; }
/* Root card also has no incoming vertical drop above it — that line
   is for children that hang off a trunk; the root has no parent.
   !important because the standard `.oc-tree li > .oc-card-wrap::before`
   (which draws the drop) AND the `:only-child` re-enable rule both
   have higher or equal specificity vs `.oc-tree > li > .oc-card-wrap`. */
.oc-tree > li > .oc-card-wrap::before {
  display: none !important;
  content: none !important;
}

/* Horizontal trunk above each child — drawn by ::before of li.
   Left half for left-of-center, right half for right-of-center. */
.oc-tree li::before,
.oc-tree li::after {
  content: '';
  position: absolute;
  top: 0;
  width: 50%;
  height: 28px;
  border-top: 2px solid #94A3B8;
}
.oc-tree li::before { left: 0; }
.oc-tree li::after { left: 50%; }

/* Vertical drop from the trunk down to the card. */
.oc-tree li > .oc-card-wrap::before {
  content: '';
  position: absolute;
  top: -28px;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  height: 28px;
  background: #94A3B8;
}

/* Hide trunk side that has no sibling on that side (single child or
   first/last with no peer). */
.oc-tree li:only-child::before,
.oc-tree li:only-child::after { display: none; }
.oc-tree li:only-child > .oc-card-wrap::before {
  /* Connect single child directly down with a clean line. */
  display: block;
}
.oc-tree li:first-child:not(:only-child)::before { border-top-color: transparent; }
.oc-tree li:last-child:not(:only-child)::after  { border-top-color: transparent; }

/* Vertical drop from the parent card down to the trunk (the kids' ul). */
.oc-tree li > ul::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  height: 28px;
  background: #94A3B8;
}

/* Card wrapper — actual card lives inside. The wrap exists so the
   vertical drop line above can hook off it. */
.oc-card-wrap {
  position: relative;
  display: inline-block;
}

/* ── The card itself ────────────────────────────────────────────── */
.oc-card {
  position: relative;
  display: inline-flex;
  flex-direction: column;
  align-items: stretch;
  min-width: 180px;
  max-width: 240px;
  padding: 0;
  background: #FFFFFF;
  border: 1.5px solid #CBD5E1;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.06);
  text-align: left;
  cursor: pointer;
  transition: box-shadow 0.15s, transform 0.15s;
}
.oc-card:hover {
  box-shadow: 0 4px 10px rgba(15, 23, 42, 0.10);
  transform: translateY(-1px);
}
.oc-card-header {
  /* symmetric top/bottom padding so html2canvas + the browser both
     read the header as visually centered (the previous 8/6 split
     leaned the text up by 2px in the PNG export) */
  padding: 7px 10px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
/* Function = primary (top), Name = secondary (below). When a card has
   no function, .oc-card-name drops .is-secondary and keeps the
   dominant default styling. Explicit pixel line-height for html2canvas
   render parity (browser unit-less line-height renders inconsistently
   in the PDF capture path). */
.oc-card-function {
  font-weight: 700;
  font-size: 13px;
  line-height: 16px;
  color: #0F172A;
  word-break: break-word;
}
.oc-card-name {
  font-weight: 700;
  font-size: 13px;
  line-height: 16px;
  color: #0F172A;
  word-break: break-word;
}
.oc-card-name.is-secondary {
  font-weight: 500;
  font-size: 11px;
  color: #475569;
  margin-top: 2px;
  line-height: 14px;
}
.oc-card-body { padding: 6px 10px 8px 10px; }
.oc-card-pkg {
  /* `inline-block` + explicit pixel line-height is the most reliable
     pattern across browsers AND html2canvas: the text box is exactly
     the line-height tall, the badge's own height = line-height + 2 ×
     padding-top, and the text sits perfectly on the line's centre.
     Avoid unit-less line-heights here — they centre slightly off in
     the canvas-rasterised render. */
  display: inline-block;
  vertical-align: middle;
  font-size: 10px;
  font-weight: 700;
  color: #FFFFFF;
  background: #1B4F8C;
  padding: 2px 6px;
  border-radius: 3px;
  margin-right: 4px;
  margin-bottom: 2px;
  line-height: 12px;
}
.oc-card-pkg-company {
  display: block;
  font-size: 10px;
  color: #64748B;
  margin-top: 1px;
}
/* Role color accent — a 4px stripe on the left edge so the role is
   identifiable at a glance without overpowering the card surface. */
.oc-card { overflow: hidden; }
.oc-card::before {
  content: '';
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 4px;
  background: var(--oc-role-color, #6B7280);
}
.oc-card .oc-card-header { padding-left: 14px; }
.oc-card .oc-card-body { padding-left: 14px; }

/* Role color tokens — mirrors the in-app role badge palette. */
.oc-role-PROJECT_OWNER { --oc-role-color: #7C3AED; }
.oc-role-PROJECT_TEAM  { --oc-role-color: #2563EB; }
.oc-role-CLIENT        { --oc-role-color: #16A34A; }
.oc-role-VENDOR        { --oc-role-color: #DC2626; }
.oc-role-BIDDER        { --oc-role-color: #D97706; }
.oc-role-DESIGN_CENTER { --oc-role-color: #C026D3; }
.oc-role-NONE          { --oc-role-color: #6B7280; }

/* ── Coordinator herringbone ─────────────────────────────────────────
   Coordinators sit on the manager-to-trunk spine, offset to either
   side. Two-column grid:  [LEFT cards | RIGHT cards]
   The vertical spine is drawn as the grid's own `::before` running from
   top to bottom of the grid section (so it's continuous through the
   internal padding). Horizontal stubs are drawn on each .oc-card-wrap —
   never on the cell — so empty cells contribute no visible line. */
.oc-with-coords {
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
}
.oc-coord-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  row-gap: 12px;
  column-gap: 0;
  align-items: center;
  position: relative;
  padding: 14px 0;
}
/* Continuous spine through the entire grid section. Starts at top:0
   (= manager card bottom because .oc-with-coords stacks the grid
   directly under the manager) and ends at bottom:0 of the grid. The
   children's trunk drop below picks up where this line ends. */
.oc-coord-grid::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  background: #94A3B8;
  transform: translateX(-1px);
  z-index: 0;
}
.oc-coord-row { display: contents; }
.oc-coord-cell {
  display: flex;
  align-items: center;
  position: relative;
  min-height: 36px;
}
.oc-coord-left  { grid-column: 1; justify-content: flex-end; }
.oc-coord-right { grid-column: 2; justify-content: flex-start; }

/* Horizontal stub — drawn on the card-wrap so it ONLY appears when a
   coordinator card actually exists in the cell. Margin reserves the
   stub's 24px gap so the card visually sits at (card-edge + 24px) from
   the spine, and the stub bridges that gap. */
.oc-coord-left .oc-card-wrap {
  position: relative;
  margin-right: 24px;
  z-index: 1;
}
.oc-coord-left .oc-card-wrap::after {
  content: '';
  position: absolute;
  left: 100%;
  top: 50%;
  width: 24px;
  height: 2px;
  background: #94A3B8;
  transform: translateY(-1px);
}
.oc-coord-right .oc-card-wrap {
  position: relative;
  margin-left: 24px;
  z-index: 1;
}
.oc-coord-right .oc-card-wrap::before {
  content: '';
  position: absolute;
  right: 100%;
  top: 50%;
  width: 24px;
  height: 2px;
  background: #94A3B8;
  transform: translateY(-1px);
}
/* Coordinator card — same visual as a regular org card. */

/* The children's <ul> below the coord-grid still needs its own 28px
   trunk drop from the wrapper's center down to the trunk row. The
   standard `.oc-tree li > ul::before` selector doesn't match here
   because this <ul> is a child of .oc-with-coords, not of an <li>. */
.oc-with-coords > ul { position: relative; }
.oc-with-coords > ul::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  height: 28px;
  background: #94A3B8;
}

/* ── Spine layout (no coordinators allowed) ──────────────────────────
   The vertical spine drops from the manager card's bottom-CENTER and
   runs straight down. Children form a clean column to the RIGHT of
   the spine, each connected by a short horizontal stub.

   Mechanics:
   • The <ul> is centered under the parent (via the standard .oc-tree li
     align-items:center on the parent), so its center sits under the
     parent card's center.
   • Each <li> has padding-left:50%, pushing its card-wrap into the
     RIGHT half of the LI. The empty LEFT half makes the LI ~2× the
     card width, but ensures the spine — drawn at left:50% of the ul —
     lands exactly at the parent card's center.
   • All cards share the same left position, so a tall spine column
     stays neatly aligned regardless of how many children it has. */
.oc-spine-children {
  list-style: none;
  margin: 0;
  padding: 28px 0 0 0;   /* 28px top for the trunk drop from the manager */
  position: relative;
  display: flex;
  flex-direction: column;
  /* CRITICAL: percentage padding on flex items resolves to 0 for the
     INTRINSIC-WIDTH pass, so `padding-left: 50%` on the spine LIs would
     not actually expand the UL. Without an explicit min-width here, the
     UL stays as narrow as its content (a single card column), then the
     spine LI's resolved padding-left = 50% of that narrow width — which
     is too small to push the card into the right half. Result: cards
     overflow past the LI right edge and overlap with adjacent siblings.
     560px = 2 × max-card-width (240) + 2 × stub gap (28) + a 24px buffer
     so children of a max-width card never overflow their spine column. */
  min-width: 560px;
}
/* Nested spines: a spine UL inside another spine LI lives in the outer
   LI's right-half content area (= 50% of the outer UL width). For the
   inner spine to fit without overflowing into adjacent siblings, the
   outer UL has to be at least 2× the inner UL's min-width.
   • 1 level of nesting → outer ≥ 2 × 560 = 1120 → use 1200 with buffer.
   • 2 levels of nesting → outer ≥ 2 × 1200 = 2400 → use 2480 with buffer.
   Beyond 2 levels of nesting we accept some overflow — extreme depth
   produces a chart too wide to read anyway. */
.oc-spine-children:has(.oc-spine-children) {
  min-width: 1200px;
}
.oc-spine-children:has(.oc-spine-children:has(.oc-spine-children)) {
  min-width: 2480px;
}
/* The single vertical spine. left:50% places it at the parent card's
   center; bottom:20px lands the terminator at ~last card center
   (approximating half a typical card's height).
   Selector deliberately specific (`.oc-tree li > ul.oc-spine-children::before`)
   so it beats the standard `.oc-tree li > ul::before` trunk-drop rule —
   specificity (0,2,3) > (0,1,3). */
.oc-tree li > ul.oc-spine-children::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 20px;
  left: 50%;
  width: 2px;
  height: auto;
  background: #94A3B8;
  transform: translateX(-1px);
}
/* Spine child row — disables the standard horizontal trunk and pushes
   its content into the right half of the LI. */
.oc-spine-children > li {
  position: relative;
  margin: 0 0 14px 0;
  padding: 0 0 0 50%;      /* content sits in the right half */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.oc-spine-children > li:last-child { margin-bottom: 0; }
.oc-spine-children > li::before,
.oc-spine-children > li::after {
  display: none;
  content: none;
}
/* Card-wrap with 28px left margin reserves space for the horizontal
   stub. The stub itself is on the card-wrap's `::before` so it stays
   tied to the card's vertical center, not the LI's (which would
   include any sub-tree height below the card). */
.oc-spine-children > li > .oc-card-wrap {
  position: relative;
  margin-left: 28px;
}
.oc-spine-children > li > .oc-card-wrap::before {
  content: '';
  position: absolute;
  top: 50%;
  left: -29px;            /* lands on the spine (which sits at -28 inside-padding edge) */
  right: auto;
  width: 28px;
  height: 2px;
  background: #94A3B8;
  transform: translateY(-1px);
}
/* If a spine child has its OWN sub-tree, we want that sub-tree (and
   its trunk drop / nested spine line at left:50% of itself) to land
   directly under the spine child's CARD center — not under the outer
   spine line.
   • margin-left:28px anchors the UL's pre-transform left edge at the
     spine child's card-wrap left edge (the card has the same 28px
     stub-gap offset).
   • The transform shifts the UL by `+card_w/2 - UL_width/2`:
     translateX(calc(110px - 50%)) ≈ shift right by 110px (≈ half a
     card_w of 220) minus half the UL's own width, so the UL ends up
     centered under the card.
   Cards range 180–240 px wide, so a card at 240 will be ~10 px off-
   centre and a card at 180 ~20 px off — visually acceptable. */
.oc-spine-children > li > ul {
  align-self: flex-start;
  margin-left: 28px;
  transform: translateX(calc(110px - 50%));
}

/* (`.oc-export-mode` overrides removed 2026-05-12 — the chart export
   now draws to canvas natively via the Vue component's _captureCanvas
   method. The live UI is the single source of truth for layout +
   styling; the exporter reads positions from the DOM and renders
   every card/connector/badge itself.) */

/* Drag-to-reorder visual feedback. */
.oc-card[draggable="true"]:hover { cursor: grab; }
.oc-card.oc-dragging { opacity: 0.4; }
.oc-drop-indicator {
  display: inline-block;
  width: 2px;
  background: #1B4F8C;
  align-self: stretch;
  margin: 0 -2px;
  border-radius: 1px;
}

/* ── Org Canvas (parallel free-form chart) ──────────────────────────
   Three-pane shell: left sidebar (contacts), center canvas, no right
   pane (properties panel deliberately deferred to v2). Cards render
   as DOM elements on top of an SVG edge layer that shares the same
   viewport transform — both move together when the user pans/zooms. */
.org-canvas-shell {
  display: flex;
  gap: 12px;
  height: calc(100vh - 220px);
  min-height: 480px;
}
.org-canvas-sidebar {
  width: 240px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid #E5E7EB;
  border-radius: 8px;
  overflow: hidden;
}
.org-canvas-sidebar-head { padding: 8px; border-bottom: 1px solid #E5E7EB; background: #F9FAFB; }
.org-canvas-sidebar-body { flex: 1; overflow-y: auto; padding: 4px 0; }
.org-canvas-sidebar-item {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 10px;
  border-bottom: 1px solid #F3F4F6;
  font-size: 12px;
  cursor: grab;
}
.org-canvas-sidebar-item:hover { background: #F9FAFB; }
.org-canvas-sidebar-item:active { cursor: grabbing; }
.org-canvas-sb-name { font-weight: 500; color: #1F2937; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.org-canvas-sb-func { font-size: 10px; color: #9CA3AF; }
.org-canvas-sb-on   { color: #16A34A; font-weight: 700; }

.org-canvas-main {
  flex: 1;
  min-width: 0;
  display: flex; flex-direction: column;
  border: 1px solid #E5E7EB;
  border-radius: 8px;
  overflow: hidden;
  background: #fff;
}
.org-canvas-toolbar {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 10px;
  background: #F9FAFB;
  border-bottom: 1px solid #E5E7EB;
  font-size: 12px;
}
.org-canvas-toolbar .btn-secondary { padding: 2px 8px; font-size: 12px; }

.org-canvas-wrap {
  flex: 1;
  position: relative;
  overflow: hidden;
  /* Repeating dot grid so the user has spatial reference while panning.
     Single layer — major lines aren't worth the visual noise here. */
  background-color: #FAFAFA;
  background-image: radial-gradient(circle, #D1D5DB 1px, transparent 1px);
  background-size: 20px 20px;
  cursor: default;
}
/* Viewers (Team / Client / Vendor) don't drag anything, so the snap grid
   gives them no useful information — hide the dot pattern to keep the
   chart looking clean. Same `no-grid` class also hides every connector
   dot (card ports + bar manager/reportees), since viewers can't drag
   new connectors and the dots are pure clutter for them. */
.org-canvas-wrap.no-grid { background-image: none; }
.org-canvas-wrap.no-grid .oc-port,
.org-canvas-wrap.no-grid .oc-port-manager,
.org-canvas-wrap.no-grid .oc-port-reportees { display: none !important; }

.org-canvas-edges {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;     /* edges are inside; this lets card events through */
}
.org-canvas-edges .oc-edge {
  fill: none;
  stroke: #64748B;
  stroke-width: 2;
  pointer-events: stroke;   /* re-enable so the user can click an edge to select */
  cursor: pointer;
}
/* Inline stroke attribute overrides this default colour. Selected edges
   thicken without changing the user-chosen colour. */
.org-canvas-edges .oc-edge:hover { stroke-width: 3; }
.org-canvas-edges .oc-edge-selected { stroke-width: 3; filter: drop-shadow(0 0 2px rgba(37,99,235,0.45)); }
.org-canvas-edges .oc-edge-pending  { stroke: #93C5FD; stroke-dasharray: 6 4; pointer-events: none; }
/* Connector styles — "Normal" (solid, no dasharray), "Dotted" (small
   round dots), "Striped" (longer dashes). */
.org-canvas-edges .oc-edge-dotted  { stroke-dasharray: 1 5; stroke-linecap: round; }
.org-canvas-edges .oc-edge-striped { stroke-dasharray: 10 6; }
/* Connector label (SVG text + rect background, rendered at label_t along the path) */
.oc-edge-label-bg {
  fill: #fff;
  stroke: #CBD5E1;
  stroke-width: 1;
  cursor: grab;
  pointer-events: auto;
}
.oc-edge-label-bg:active { cursor: grabbing; }
.oc-edge-label {
  font-size: 11px;
  fill: #1F2937;
  user-select: none;
  pointer-events: none;
  dominant-baseline: middle;
  text-anchor: middle;
}

.org-canvas-viewport {
  position: absolute; left: 0; top: 0;
  width: 100%; height: 100%;
  /* Children use absolute positioning relative to this viewport; the
     transform on this element pans + zooms the whole layer in lockstep
     with the SVG edges. The viewport itself is event-transparent so
     clicks on empty canvas land on the SVG edge layer below — that's
     how connectors stay clickable. Cards and bars override with
     `pointer-events: auto` to keep their own interactions. */
  pointer-events: none;
}
.org-canvas-card, .org-canvas-bar { pointer-events: auto; }
.org-canvas-card {
  position: absolute;
  background: #fff;
  border: 1px solid #E5E7EB;
  border-radius: 8px;
  padding: 10px 12px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.05);
  cursor: grab;
  user-select: none;
  display: flex; flex-direction: column; gap: 2px;
  transition: box-shadow 120ms ease;
}
.org-canvas-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.10); }
.org-canvas-card:active { cursor: grabbing; }
.org-canvas-card.is-selected {
  border-color: #2563EB;
  box-shadow: 0 0 0 2px rgba(37,99,235,0.18), 0 4px 12px rgba(0,0,0,0.08);
}
/* Steering committee group card (canvas) — a titled box listing members,
   independent of the reporting tree. Draggable like any node. */
.org-canvas-steering {
  position: absolute;
  width: 220px;
  background: #fff;
  border: 1px solid #E5E7EB;
  border-radius: 10px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
  cursor: grab;
  user-select: none;
  /* No overflow:hidden — the connector port dots sit on the card edges and
     would be clipped. The header rounds its own top corners instead. */
  pointer-events: auto;
}
.org-canvas-steering:active { cursor: grabbing; }
.org-canvas-steering.is-selected {
  box-shadow: 0 0 0 2px rgba(37,99,235,0.30), 0 6px 16px rgba(0,0,0,0.10);
}
.org-canvas-steering-head {
  display: flex; align-items: center; gap: 6px;
  padding: 7px 10px;
  color: #fff;
  font-weight: 600;
  font-size: 12px;
  border-radius: 9px 9px 0 0;
}
.oc-steer-icon { width: 14px; height: 14px; flex: none; }
.org-canvas-steering-body {
  padding: 8px 10px;
  display: flex; flex-direction: column; gap: 4px;
}
.org-canvas-steering-member { font-size: 12px; color: #374151; line-height: 1.25; }
.oc-steer-name { font-weight: 500; }
.oc-steer-fn { color: #9CA3AF; }
.org-canvas-steering-empty { font-size: 11px; color: #9CA3AF; font-style: italic; }
/* Member picker in the properties panel */
.oc-steer-picker {
  max-height: 180px; overflow-y: auto;
  border: 1px solid #E5E7EB; border-radius: 6px;
}
.oc-steer-pick-row {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 8px; font-size: 12px; cursor: pointer;
}
.oc-steer-pick-row:hover { background: #F9FAFB; }
.oc-steer-pick-name { color: #374151; }
.oc-steer-pick-fn { color: #9CA3AF; margin-left: auto; font-size: 11px; }

/* Vacant placeholder — a dashed amber "open position" card. Drop a contact
   onto it to fill it (the node becomes a normal contact card in place). */
.org-canvas-card.is-vacant {
  background: #FFFBEB;
  border: 1px dashed #F59E0B;
  box-shadow: none;
}
.org-canvas-card.is-vacant.is-selected {
  border-color: #2563EB;
  box-shadow: 0 0 0 2px rgba(37,99,235,0.18);
}
.org-canvas-card-vacant {
  font-size: 11px;
  font-style: italic;
  color: #B45309;
  line-height: 1.2;
}
/* Function = primary line (top). Name = secondary line (below).
   When a card has no function, the name keeps its dominant default
   styling (the v-bind drops .is-secondary). */
.org-canvas-card-func {
  font-weight: 700;
  font-size: 13px;
  color: #111827;
  line-height: 1.25;
  overflow-wrap: anywhere;     /* long titles wrap inside the 220 px card */
}
.org-canvas-card-name {
  font-weight: 600;
  font-size: 13px;
  color: #1F2937;
  line-height: 1.2;
}
.org-canvas-card-name.is-secondary {
  font-weight: 500;
  font-size: 12px;
  color: #374151;
  margin-top: 1px;             /* hair of breathing room under the title */
}
.org-canvas-card-co {
  font-size: 10px;
  color: #9CA3AF;
}
/* Role-tinted left border, mirrors the per-role accent on the tree chart. */
.org-canvas-card.oc-role-project-owner  { border-left: 4px solid #7C3AED; }
.org-canvas-card.oc-role-project-team   { border-left: 4px solid #2563EB; }
.org-canvas-card.oc-role-client         { border-left: 4px solid #16A34A; }
.org-canvas-card.oc-role-vendor         { border-left: 4px solid #DC2626; }
.org-canvas-card.oc-role-bidder         { border-left: 4px solid #D97706; }
.org-canvas-card.oc-role-design-center  { border-left: 4px solid #C026D3; }

/* ── v2 additions ──────────────────────────────────────────────────── */
.org-canvas-stage {
  flex: 1;
  display: flex;
  min-height: 0;
}
/* Rubber-band marquee. Positioned with fixed coordinates so it sits in
   screen space (the canvas itself zooms + pans; the marquee should not).
   `pointer-events: none` so the overlay never steals mousemove/up
   from the active drag handler — the window-level listeners drive
   the resize. */
.org-canvas-marquee {
  position: fixed;
  pointer-events: none;
  border: 1px dashed #2563EB;
  background: rgba(37, 99, 235, 0.08);
  z-index: 50;
}
.org-canvas-stage .org-canvas-wrap {
  flex: 1;
  min-width: 0;
}
.org-canvas-tb-sep {
  display: inline-block;
  width: 1px;
  height: 18px;
  background: #E5E7EB;
  margin: 0 4px;
}

/* Card ports (4 per card) + bar ports (2 named per bar — manager + reportees) */
.oc-port {
  position: absolute;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: #2563EB;
  border: 2px solid #fff;
  cursor: crosshair;
  opacity: 0;
  transition: opacity 120ms ease, transform 120ms ease;
  z-index: 2;
}
.oc-port:hover { transform: scale(1.3); }
.oc-port-top    { left: 50%; top: 0;    transform: translate(-50%, -50%); }
.oc-port-right  { right: 0;  top: 50%;  transform: translate( 50%, -50%); }
.oc-port-bottom { left: 50%; bottom: 0; transform: translate(-50%,  50%); }
.oc-port-left   { left: 0;   top: 50%;  transform: translate(-50%, -50%); }
.oc-port-top:hover    { transform: translate(-50%, -50%) scale(1.3); }
.oc-port-right:hover  { transform: translate( 50%, -50%) scale(1.3); }
.oc-port-bottom:hover { transform: translate(-50%,  50%) scale(1.3); }
.oc-port-left:hover   { transform: translate(-50%, -50%) scale(1.3); }

/* Bar ports: visually differentiated. Manager = amber (single attach
   point for the chain coming from above); Reportees = blue (the fan-out
   side). Always visible (no hover requirement) so the user can read the
   bar's intent at a glance. */
.oc-port-manager,
.oc-port-reportees {
  position: absolute;
  width: 14px; height: 14px;
  border-radius: 50%;
  border: 2px solid #fff;
  cursor: crosshair;
  opacity: 1;
  z-index: 3;
  transition: transform 120ms ease;
  box-shadow: 0 0 0 1px rgba(0,0,0,0.12);
}
.oc-port-manager   { background: #F59E0B; }
.oc-port-reportees { background: #2563EB; }
.oc-port-manager:hover, .oc-port-reportees:hover { transform: translate(var(--ocp-tx, -50%), var(--ocp-ty, -50%)) scale(1.25); }

/* Position rules — horizontal bar: manager dot sits fully ABOVE the
   bar (touching its top edge), reportees dot sits fully BELOW (touching
   its bottom edge). translateY ±100% pushes each dot out so the 6 px
   bar is the visible gap between them — no overlap. */
.oc-port-manager-horizontal {
  left: 50%; top: 0;
  transform: translate(-50%, -100%);
  --ocp-tx: -50%; --ocp-ty: -100%;
}
.oc-port-reportees-horizontal {
  left: 50%; bottom: 0;
  transform: translate(-50%, 100%);
  --ocp-tx: -50%; --ocp-ty: 100%;
}
/* Vertical bar: manager dot at the top end; reportees dots on BOTH
   sides at vertical mid (so cards can attach on the left, right, or
   both). Connecting from a card projects perpendicular onto the bar,
   so each side's middle dot is a visual anchor — the actual attachment
   point slides along that side. */
.oc-port-manager-vertical {
  left: 50%; top: 0;
  transform: translate(-50%, -100%);
  --ocp-tx: -50%; --ocp-ty: -100%;
}
.oc-port-reportees-vertical-right {
  right: 0; top: 50%;
  transform: translate(100%, -50%);
  --ocp-tx: 100%; --ocp-ty: -50%;
}
.oc-port-reportees-vertical-left {
  left: 0; top: 50%;
  transform: translate(-100%, -50%);
  --ocp-tx: -100%; --ocp-ty: -50%;
}

.org-canvas-card:hover .oc-port,
.org-canvas-card.is-selected .oc-port,
.org-canvas-steering:hover .oc-port,
.org-canvas-steering.is-selected .oc-port { opacity: 1; }
/* Bar ports stay visible always (see opacity:1 above) — no hover gate. */

/* PDF-export mode: hide every connector dot (bar manager/reportees +
   card ports + frame resize handles) so the captured PNG shows only
   the chart itself. Toggled on the wrap by exportPdf() during the
   html2canvas capture; removed immediately after. */
.oc-exporting .oc-port,
.oc-exporting .oc-port-manager,
.oc-exporting .oc-port-reportees,
.oc-exporting .oc-frame-resize,
.oc-exporting .oc-waypoint,
.oc-exporting .oc-midpoint,
.oc-exporting .oc-bar-resize { display: none !important; }

/* Snap toggle in the toolbar */
.org-canvas-snap {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 6px;
  font-size: 11px;
  color: #475569;
  background: #F1F5F9;
  border-radius: 4px;
  cursor: pointer;
  user-select: none;
}
.org-canvas-snap input { margin: 0; }
.org-canvas-snap:has(input:checked) { background: #DBEAFE; color: #1E40AF; }

/* 12-colour swatch grid (edge + bar colour pickers) */
.oc-swatches {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 4px;
  margin-top: 4px;
}
.oc-swatch {
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 4px;
  border: 1px solid rgba(0,0,0,0.10);
  cursor: pointer;
  padding: 0;
  transition: transform 100ms ease;
}
.oc-swatch:hover { transform: scale(1.15); }
.oc-swatch.is-selected {
  outline: 2px solid #1E40AF;
  outline-offset: 2px;
}

/* Eye button — opens the contact form. Sits in the top-right of the
   card, visible on hover and when selected so it doesn't clutter the
   default state. */
.oc-card-eye {
  position: absolute;
  top: 6px; right: 6px;
  width: 18px; height: 18px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent;
  border: none;
  color: #94A3B8;
  cursor: pointer;
  padding: 0;
  border-radius: 3px;
  opacity: 0;
  transition: opacity 120ms ease, color 120ms ease, background-color 120ms ease;
  z-index: 2;
}
.oc-card-eye svg { width: 14px; height: 14px; }
.oc-card-eye:hover { color: #2563EB; background: #EFF6FF; }
.org-canvas-card:hover .oc-card-eye,
.org-canvas-card.is-selected .oc-card-eye { opacity: 1; }

/* Card content extensions: badge strip, package chips, notes */
.org-canvas-card-badges {
  display: flex; flex-wrap: wrap; gap: 3px;
  margin-top: 6px; padding-top: 6px;
  border-top: 1px dashed #E5E7EB;
}
.oc-badge {
  display: inline-flex; align-items: center;
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 9px;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0.2px;
  white-space: nowrap;
}
.org-canvas-card-pkgs {
  display: flex; flex-wrap: wrap; gap: 3px;
  margin-top: 4px;
}
.oc-pkg-chip {
  display: inline-block;
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 9px;
  font-weight: 700;
  color: #fff;
  background: #1B4F8C;
  letter-spacing: 0.2px;
}
.org-canvas-card-notes {
  margin-top: 6px; padding-top: 6px;
  border-top: 1px dashed #E5E7EB;
  font-size: 10.5px;
  color: #4B5563;
  line-height: 1.4;
  white-space: pre-wrap;
  word-break: break-word;
}

/* Distribution bars — thin rectangles that act as connector hubs */
.org-canvas-bar {
  position: absolute;
  background: #475569;
  border-radius: 3px;
  cursor: grab;
  z-index: 1;
}
.org-canvas-bar:active { cursor: grabbing; }
.org-canvas-bar.is-selected { background: #2563EB; box-shadow: 0 0 0 2px rgba(37,99,235,0.25); }
/* Highlighted while a vertical bar is being dragged near it — release to
   lock the bars together at a T/L junction (no connector needed). */
.org-canvas-bar.is-lock-target { box-shadow: 0 0 0 3px rgba(37,99,235,0.55), 0 0 8px 2px rgba(37,99,235,0.35); }
/* Bar-lock status block in the properties panel (vertical bars). */
.org-canvas-lock-block { margin: 10px 0; padding-top: 10px; border-top: 1px solid #F1F5F9; }
.org-canvas-lock-title { font-size: 11px; font-weight: 600; color: #374151; margin-bottom: 4px; }
.org-canvas-lock-hint { font-size: 11px; color: #9CA3AF; line-height: 1.35; margin-bottom: 8px; }
.org-canvas-lock-row { display: flex; align-items: center; gap: 8px; font-size: 12px; color: #4B5563; padding: 3px 0; }
.org-canvas-lock-row > span:first-child { flex: 1; }
.org-canvas-lock-on { color: #2563EB; font-weight: 600; }
.org-canvas-lock-off { color: #9CA3AF; }
.org-canvas-lock-btn { font-size: 11px; color: #DC2626; border: 1px solid #FCA5A5; border-radius: 4px; padding: 1px 7px; background: #fff; }
.org-canvas-lock-btn:hover { background: #FEF2F2; }
.oc-bar-horizontal { /* width set inline */ }
.oc-bar-vertical   { /* height set inline */ }
.oc-bar-resize {
  position: absolute;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: #16A34A;
  border: 2px solid #fff;
  z-index: 3;
}
/* Start = top-left for horizontal, top for vertical.
   End   = bottom-right for horizontal, bottom for vertical. */
.oc-bar-horizontal .oc-bar-resize-start { left: -6px;  top: -3px;    cursor: ew-resize; }
.oc-bar-horizontal .oc-bar-resize-end   { right: -6px; top: -3px;    cursor: ew-resize; }
.oc-bar-vertical   .oc-bar-resize-start { left: -3px;  top: -6px;    cursor: ns-resize; }
.oc-bar-vertical   .oc-bar-resize-end   { left: -3px;  bottom: -6px; cursor: ns-resize; }

/* Frame: rounded-rectangle group container. Transparent interior so
   cards sitting inside remain fully visible. Border is the frame's
   own colour. Drawn before cards/bars in the DOM so those win on
   overlap for click events. */
.org-canvas-frame {
  position: absolute;
  border: 2px solid #475569;          /* overridden inline with n.color */
  border-radius: 14px;
  background: transparent;
  cursor: grab;
  user-select: none;
  pointer-events: auto;
}
.org-canvas-frame:active { cursor: grabbing; }
.org-canvas-frame.is-selected {
  box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.22);
}
/* Line-style variants — match the connector picker so the user vocabulary
   is the same on both. "Striped" = CSS dashed (long segments), "dotted"
   = CSS dotted (small round-ish dots), "solid" = default. */
.org-canvas-frame.oc-frame-solid   { border-style: solid; }
.org-canvas-frame.oc-frame-dotted  { border-style: dotted; }
.org-canvas-frame.oc-frame-striped { border-style: dashed; }
/* Label pill sits ON the border at the (label_t)-derived perimeter point;
   translate(-50%, -50%) centres it on that point. Background is white so
   the pill visually breaks the border line. */
.oc-frame-label {
  position: absolute;
  transform: translate(-50%, -50%);
  background: #fff;
  border: 1px solid #E5E7EB;
  border-radius: 6px;
  padding: 2px 8px;
  font-size: 12px;
  font-weight: 600;
  color: #1F2937;
  white-space: nowrap;
  cursor: move;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.oc-frame-label-placeholder { font-weight: 400; font-style: italic; color: #9CA3AF; }
.oc-frame-resize {
  position: absolute;
  width: 10px; height: 10px;
  background: #2563EB;
  border: 1.5px solid #fff;
  border-radius: 2px;
  z-index: 4;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);
}
.oc-frame-resize-nw { left: 0;    top: 0;    transform: translate(-50%, -50%); cursor: nwse-resize; }
.oc-frame-resize-ne { right: 0;   top: 0;    transform: translate( 50%, -50%); cursor: nesw-resize; }
.oc-frame-resize-sw { left: 0;    bottom: 0; transform: translate(-50%,  50%); cursor: nesw-resize; }
.oc-frame-resize-se { right: 0;   bottom: 0; transform: translate( 50%,  50%); cursor: nwse-resize; }

/* Waypoint + midpoint handles drawn inside the SVG edges layer */
.oc-waypoint {
  fill: #2563EB;
  stroke: #fff;
  stroke-width: 1.5;
  cursor: grab;
  pointer-events: auto;
}
.oc-waypoint:hover { fill: #1E40AF; }
.oc-midpoint {
  fill: #93C5FD;
  stroke: #fff;
  stroke-width: 1;
  pointer-events: auto;
  opacity: 0.7;
}
.oc-midpoint:hover { fill: #2563EB; opacity: 1; }
/* Axis-specific cursor: horizontal segments shift up/down, vertical
   segments shift left/right. */
.oc-midpoint-horizontal { cursor: ns-resize; }
.oc-midpoint-vertical   { cursor: ew-resize; }

/* Dashed edge style */
.org-canvas-edges .oc-edge-dashed { stroke-dasharray: 6 4; }

/* Properties panel (right side of the canvas) */
.org-canvas-props {
  width: 240px;
  flex-shrink: 0;
  display: flex; flex-direction: column;
  background: #fff;
  border-left: 1px solid #E5E7EB;
}
.org-canvas-props-head {
  padding: 8px 12px;
  font-weight: 600;
  font-size: 12px;
  color: #6B7280;
  background: #F9FAFB;
  border-bottom: 1px solid #E5E7EB;
}
.org-canvas-props-body {
  flex: 1;
  overflow-y: auto;
  padding: 12px;
}
.org-canvas-toggle {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px;
  color: #374151;
  margin-bottom: 8px;
  cursor: pointer;
}
.org-canvas-toggle input { margin: 0; }
.org-canvas-field {
  display: block;
  margin-bottom: 10px;
  font-size: 11px;
  color: #6B7280;
}
.org-canvas-field span { display: block; margin-bottom: 3px; }
.org-canvas-danger {
  display: block;
  width: 100%;
  margin-top: 12px;
  padding: 6px 10px;
  font-size: 12px;
  font-weight: 600;
  color: #B91C1C;
  background: #FEF2F2;
  border: 1px solid #FECACA;
  border-radius: 6px;
  cursor: pointer;
}
.org-canvas-danger:hover { background: #FEE2E2; }

/* Inline-editable <select> used in the Project Organization tables
   (subservices reviewers, area/unit owners). Looks like plain text until
   hovered/focused, then reveals a bordered editable control. */
.org-inline-select {
  width: 100%;
  max-width: 200px;
  font-size: 0.875rem;
  padding: 2px 4px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  cursor: pointer;
  appearance: auto;
}
.org-inline-select:hover { border-color: #E5E7EB; background: #fff; }
.org-inline-select:focus { border-color: #00AEEF; background: #fff; outline: none; }
