/* ── Design System Tokens ────────────────────────────────────────────── */ :root { --primary: #1F4E79; --primary-dark: #163b5c; --primary-light: #dbeafe; --secondary: #0F766E; --accent: #2563EB; --success: #2E7D32; --success-bg: #F0FDF4; --success-border: #BBF7D0; --warning: #B45309; --warning-bg: #FFFBEB; --warning-border: #FDE68A; --error: #B91C1C; --error-bg: #FEF2F2; --error-border: #FECACA; --info: #2563EB; --info-bg: #EFF6FF; --info-border: #BFDBFE; --overdue: #7F1D1D; --bg: #F7F9FC; --surface: #FFFFFF; --surface-raised: #F8FAFC; --border: #D0D7E2; --border-strong: #9FB6D6; --text: #111827; --text-secondary: #4B5563; --text-muted: #6B7280; --radius-xs: 4px; --radius-sm: 6px; --radius: 8px; --radius-lg: 10px; --radius-xl: 12px; --shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.06); --shadow-sm: 0 1px 4px rgba(15, 23, 42, 0.08); --shadow: 0 4px 12px rgba(15, 23, 42, 0.10); --shadow-md: 0 8px 24px rgba(15, 23, 42, 0.12); } /* ── Reset / Base ────────────────────────────────────────────────────── */ *, *::before, *::after { box-sizing: border-box; } [x-cloak] { display: none !important; } html { scroll-behavior: smooth; } body { margin: 0; min-height: 100vh; font-family: "Public Sans", "Segoe UI", Arial, sans-serif; font-size: 14px; line-height: 22px; font-weight: 400; color: var(--text); background: var(--bg); overflow-x: hidden; } a { color: inherit; } code { font-family: "IBM Plex Mono", Consolas, "Courier New", monospace; font-size: 13px; } h1, h2, h3, h4, h5, h6 { margin: 0; font-weight: 600; color: var(--text); } h1 { font-size: 28px; line-height: 36px; } h2 { font-size: 22px; line-height: 30px; } h3 { font-size: 18px; line-height: 26px; } h4 { font-size: 16px; line-height: 24px; } /* ── Layout ──────────────────────────────────────────────────────────── */ .page-shell { min-height: 100vh; display: flex; flex-direction: column; } .container { width: min(1200px, calc(100% - 2rem)); margin: 0 auto; } /* ── Site Header ─────────────────────────────────────────────────────── */ .site-header { position: sticky; top: 0; z-index: 20; background: var(--primary); border-bottom: 1px solid var(--primary-dark); box-shadow: var(--shadow-sm); } .header-inner { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0; height: 52px; } .brand { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; } .brand-mark { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: var(--radius-sm); background: rgba(255, 255, 255, 0.18); color: #fff; font-weight: 800; font-size: 12px; letter-spacing: 0.04em; flex-shrink: 0; } .brand-copy { display: flex; flex-direction: column; line-height: 1.2; } .brand-copy strong { font-size: 14px; font-weight: 700; color: #fff; letter-spacing: 0.01em; } .brand-copy small { color: rgba(255, 255, 255, 0.6); font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; } .site-nav { display: flex; align-items: center; gap: 2px; flex-wrap: wrap; } .nav-user { padding: 0 8px; color: rgba(255, 255, 255, 0.7); font-size: 13px; font-weight: 600; } .nav-logout-form { display: contents; } .nav-link { text-decoration: none; color: rgba(255, 255, 255, 0.75); font-size: 13px; font-weight: 600; padding: 6px 12px; border-radius: var(--radius-sm); transition: background-color 120ms ease, color 120ms ease; } .nav-link:hover, .nav-link:focus-visible { color: #fff; background: rgba(255, 255, 255, 0.12); } .nav-link.is-active { color: #fff; background: rgba(255, 255, 255, 0.18); } /* ── Page Content ────────────────────────────────────────────────────── */ .page-content { flex: 1; padding: 32px 0 40px; } .content-stack { display: grid; gap: 24px; } /* ── Section Heading ─────────────────────────────────────────────────── */ .section-heading { max-width: 720px; } .section-heading h1 { margin: 4px 0 8px; font-size: 28px; line-height: 36px; } .section-heading p { margin: 0; color: var(--text-secondary); line-height: 22px; font-size: 14px; } /* ── Hero (home page) ────────────────────────────────────────────────── */ .hero { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(280px, 0.9fr); gap: 16px; align-items: stretch; } .hero-copy, .hero-panel, .feature-card, .section-panel, .alert, .empty-state { background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow-sm); } .hero-copy { padding: 32px; border-radius: var(--radius-lg); } .eyebrow { display: inline-block; margin-bottom: 16px; padding: 3px 10px; border-radius: 999px; background: var(--info-bg); border: 1px solid var(--info-border); color: var(--accent); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; } .hero h1 { font-size: clamp(24px, 4vw, 36px); line-height: 1.15; letter-spacing: -0.02em; color: var(--primary); } .hero-text { max-width: 560px; margin: 16px 0 0; font-size: 14px; line-height: 22px; color: var(--text-secondary); } .hero-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 24px; } .hero-panel { display: flex; flex-direction: column; justify-content: space-between; padding: 24px; border-radius: var(--radius-lg); } .panel-label { margin: 0 0 12px; font-size: 11px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-secondary); } .hero-panel code { display: block; padding: 12px 14px; border-radius: var(--radius); background: #0f172a; color: #e2e8f0; font-family: "IBM Plex Mono", Consolas, monospace; font-size: 12px; line-height: 20px; white-space: normal; } .route-callout { margin-top: 16px; padding: 12px 14px; border-radius: var(--radius); background: var(--surface-raised); border: 1px solid var(--border); } .route-callout span { display: block; margin-bottom: 6px; color: var(--text-secondary); font-size: 13px; } .route-callout a { color: var(--accent); font-weight: 700; text-decoration: none; } /* ── Feature Grid ────────────────────────────────────────────────────── */ .feature-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; margin-top: 16px; } .feature-card { padding: 20px; border-radius: var(--radius-lg); } .feature-card h2 { margin-top: 0; margin-bottom: 8px; font-size: 16px; line-height: 24px; } .feature-card p { margin: 0; color: var(--text-secondary); line-height: 22px; font-size: 13px; } /* ── Panels & Controls ───────────────────────────────────────────────── */ .controls-panel, .table-shell { overflow: hidden; background: var(--surface); border: 1px solid var(--border); } .controls-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; } .search-row { display: grid; grid-template-columns: minmax(0, 1fr); } .field-full { width: 100%; } .section-panel { padding: 24px; border-radius: var(--radius-lg); min-width: 0; } .panel-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 16px; } .panel-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } .panel-header h2 { margin: 0 0 4px; font-size: 18px; line-height: 26px; } .panel-header p { margin: 0; color: var(--text-secondary); line-height: 22px; font-size: 13px; } .job-type-table-stack { display: grid; gap: 16px; } .job-type-table-group { display: grid; gap: 8px; padding-top: 16px; border-top: 1px solid var(--border); } .job-type-table-group:first-child { padding-top: 0; border-top: 0; } .job-type-table-heading { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; } .job-type-table-heading h3 { margin: 0; font-size: 15px; line-height: 22px; } .job-type-table-heading span { color: var(--text-secondary); font-size: 12px; font-weight: 700; } /* ── Forms ───────────────────────────────────────────────────────────── */ .form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; } .field { display: grid; gap: 6px; font-weight: 600; font-size: 13px; } .field span { font-size: 13px; color: var(--text); } .input { width: 100%; padding: 7px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font: inherit; font-size: 14px; line-height: 20px; transition: border-color 120ms ease, box-shadow 120ms ease; } .input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12); } .field-error { color: var(--error); font-size: 12px; font-weight: 600; } .form-actions { display: flex; justify-content: flex-start; align-items: center; gap: 8px; } /* ── Buttons ─────────────────────────────────────────────────────────── */ .button { display: inline-flex; align-items: center; justify-content: center; padding: 7px 16px; border-radius: var(--radius-sm); text-decoration: none; font-family: inherit; font-size: 13px; font-weight: 600; line-height: 20px; border: 1px solid transparent; cursor: pointer; transition: background-color 120ms ease, border-color 120ms ease, box-shadow 120ms ease; } .button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } .button-primary { background: var(--primary); color: #fff; border-color: var(--primary-dark); } .button-primary:hover { background: var(--primary-dark); } .button-secondary { background: var(--surface); color: var(--text); border-color: var(--border); } .button-secondary:hover { background: var(--surface-raised); border-color: var(--border-strong); } .button-danger { background: var(--error); color: #fff; border-color: #991B1B; } .button-danger:hover, .button-danger:focus-visible { background: #991B1B; } .button-sm { padding: 4px 10px; font-size: 12px; border-radius: var(--radius-xs); border: 1px solid transparent; cursor: pointer; } /* ── Alerts & Empty States ───────────────────────────────────────────── */ .alert, .empty-state { padding: 12px 16px; border-radius: var(--radius); font-size: 14px; } .alert-success { background: var(--success-bg); border-color: var(--success-border); color: var(--success); } .alert-error { background: var(--error-bg); border-color: var(--error-border); color: var(--error); } .empty-state p { margin: 0; color: var(--text-secondary); line-height: 22px; } .empty-state p + p { margin-top: 6px; } /* ── Stats Grid ──────────────────────────────────────────────────────── */ .stats-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; } .stat-card { padding: 16px; border-radius: var(--radius); background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow-xs); } .stat-card span { display: block; color: var(--text-secondary); font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600; } .stat-card strong { display: block; margin-top: 6px; font-size: 28px; line-height: 1; color: var(--primary); } .summary-feature { margin-top: 16px; padding: 14px 16px; border-radius: var(--radius); background: var(--info-bg); border: 1px solid var(--info-border); } .summary-label { display: block; color: var(--text-secondary); font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600; } .summary-feature h3 { margin: 6px 0 4px; font-size: 16px; line-height: 24px; color: var(--primary); } .summary-feature p { margin: 0; color: var(--text-secondary); font-size: 13px; } /* ── Dashboard ───────────────────────────────────────────────────────── */ .stats-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } .dashboard-panels { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; } .dashboard-table { width: 100%; border-collapse: collapse; font-size: 13px; } .dashboard-table th { text-align: left; padding: 6px 10px; font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-secondary); border-bottom: 1px solid var(--border); } .dashboard-table td { padding: 8px 10px; border-bottom: 1px solid var(--border); color: var(--text-primary); } .dashboard-table tr:last-child td { border-bottom: none; } .dashboard-table-id { color: var(--text-secondary); font-variant-numeric: tabular-nums; width: 48px; } .dashboard-table-date { color: var(--text-secondary); white-space: nowrap; } .dashboard-table-action { text-align: right; width: 40px; } .dashboard-table-action a { color: var(--primary); font-size: 12px; } .type-breakdown { display: flex; flex-direction: column; gap: 10px; padding: 4px 0; } .type-breakdown-row { display: grid; grid-template-columns: 140px 1fr 36px; align-items: center; gap: 10px; font-size: 13px; } .type-name { color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .type-bar-wrap { height: 8px; background: var(--border); border-radius: 4px; overflow: hidden; } .type-bar { display: block; height: 100%; background: var(--primary); border-radius: 4px; min-width: 4px; transition: width 0.3s ease; } .type-count { text-align: right; font-variant-numeric: tabular-nums; color: var(--text-secondary); font-size: 12px; } @media (max-width: 860px) { .stats-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } .dashboard-panels { grid-template-columns: 1fr; } } /* ── Table Toolbar ───────────────────────────────────────────────────── */ .table-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 12px; flex-wrap: wrap; padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); } .table-pill { display: inline-flex; align-items: center; padding: 3px 10px; border-radius: 999px; background: var(--info-bg); border: 1px solid var(--info-border); color: var(--accent); font-size: 12px; font-weight: 700; letter-spacing: 0.04em; } .table-caption { color: var(--text-secondary); font-size: 12px; } /* ── Tabulator ───────────────────────────────────────────────────────── */ .tabulator-host { overflow-x: auto; width: 100%; } .directory-panel .tabulator-host { min-height: 38rem; } .tabulator-host .tabulator { border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; background: var(--surface); box-shadow: var(--shadow-sm); } .tabulator-host .tabulator-header { border-bottom: 1px solid var(--border); background: var(--surface-raised); } .tabulator-host .tabulator-header .tabulator-col { min-height: 36px; background: transparent; border-right: 1px solid var(--border); } .tabulator-host .tabulator-header .tabulator-col:last-child { border-right: 0; } .tabulator-host .tabulator-header .tabulator-col .tabulator-col-content { padding: 8px 10px; } .tabulator-host .tabulator-header .tabulator-col .tabulator-col-title { font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-secondary); } .tabulator-host .tabulator-col, .tabulator-host .tabulator-cell { border-right: 1px solid var(--border); } .tabulator-host .tabulator-row .tabulator-cell:last-child { border-right: 0; } .tabulator-host .tabulator-row { background: var(--surface); border-bottom: 1px solid var(--border); transition: background-color 100ms ease; } .tabulator-host .tabulator-row:nth-child(even) { background: var(--surface-raised); } .tabulator-host .tabulator-row:hover { background: var(--info-bg); } .tabulator-host .tabulator-row.tabulator-selected { background: var(--primary-light); } .tabulator-host .tabulator-cell { padding: 8px 10px; font-size: 13px; line-height: 20px; } .tabulator-host .tabulator-row .tabulator-cell:first-child { font-weight: 600; color: var(--text); } .tabulator-host .tabulator-footer { padding: 6px 8px; background: var(--surface-raised); border-top: 1px solid var(--border); } .tabulator-host .tabulator-footer .tabulator-paginator { font-family: inherit; font-size: 13px; } .tabulator-host .tabulator-footer .tabulator-page { margin: 0 2px; padding: 4px 8px; border: 1px solid var(--border); border-radius: var(--radius-xs); background: var(--surface); color: var(--text-secondary); font-weight: 600; font-size: 12px; } .tabulator-host .tabulator-footer .tabulator-page.active, .tabulator-host .tabulator-footer .tabulator-page:hover { background: var(--primary); border-color: var(--primary-dark); color: #fff; } .tabulator-host .tabulator-footer .tabulator-page:disabled { opacity: 0.4; } .tabulator-host .tabulator-placeholder { padding: 32px 16px; color: var(--text-secondary); font-size: 13px; font-weight: 600; } /* ── HTMX Indicators ─────────────────────────────────────────────────── */ .htmx-indicator { display: none; } .htmx-request .htmx-indicator, .htmx-request.htmx-indicator { display: inline-flex; } .inline-indicator { color: var(--text-secondary); font-size: 13px; font-weight: 600; } /* ── Site Footer ─────────────────────────────────────────────────────── */ .site-footer { margin-top: auto; border-top: 1px solid var(--border); background: var(--surface); } .footer-inner { display: flex; justify-content: space-between; gap: 16px; padding: 16px 0 24px; color: var(--text-muted); font-size: 12px; line-height: 18px; } .footer-inner p { margin: 0; } /* ── Page Toolbar ────────────────────────────────────────────────────── */ .page-toolbar { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; } .page-toolbar .section-heading { margin: 0; } .page-toolbar .section-heading h1 { margin: 0 0 4px; } /* ── Campaign Types / Import Forms ───────────────────────────────────── */ .ct-form { display: grid; gap: 24px; } .form-section { display: grid; gap: 12px; } .form-section h3 { margin: 0; font-size: 15px; line-height: 22px; } .attributes-header { display: flex; flex-direction: column; gap: 4px; } .attributes-hint { margin: 0; color: var(--text-secondary); font-size: 13px; } .attribute-list { display: grid; gap: 6px; } .attribute-row { display: flex; align-items: flex-end; gap: 8px; flex-wrap: wrap; } .attr-drag-handle { cursor: grab; padding: 0 4px; color: var(--text-muted); font-size: 16px; user-select: none; align-self: flex-end; padding-bottom: 8px; line-height: 1; } .attr-drag-handle:active { cursor: grabbing; } .attribute-row.is-dragging { opacity: 0.35; } .attribute-row.is-drag-over { outline: 2px dashed var(--accent); border-radius: var(--radius-sm); background: var(--info-bg); } .attribute-order-field { flex: 0 0 5rem; min-width: 5rem; } .attribute-order-field .input { text-align: center; } .attribute-name-field { flex: 2; min-width: 160px; } .attribute-type-field { flex: 1; min-width: 110px; } .attribute-remove { padding-bottom: 0.1rem; } .input-error { border-color: var(--error) !important; } .required-mark { color: var(--error); } .delete-zone { margin-top: 32px; padding-top: 16px; border-top: 1px solid var(--error-border); } .delete-zone h4 { margin: 0 0 4px; color: var(--error); font-size: 14px; } .delete-zone p { margin: 0 0 12px; color: var(--text-secondary); font-size: 13px; } .attr-summary { color: var(--text-secondary); font-size: 13px; } .attr-empty { color: var(--text-muted); opacity: 0.6; } /* ── Import Tabs ─────────────────────────────────────────────────────── */ .import-tabs { display: flex; gap: 2px; margin-bottom: 16px; border-bottom: 1px solid var(--border); padding-bottom: 0; } .import-tab { padding: 6px 14px; border: none; background: none; cursor: pointer; font: inherit; font-size: 13px; font-weight: 600; color: var(--text-secondary); border-bottom: 2px solid transparent; margin-bottom: -1px; border-radius: 0; transition: color 120ms, border-color 120ms; } .import-tab:hover { color: var(--accent); } .import-tab.is-active { color: var(--primary); border-bottom-color: var(--primary); } .import-grid { display: grid; grid-template-columns: minmax(260px, 1.4fr) minmax(180px, 0.8fr) minmax(180px, 0.8fr); gap: 16px; } .import-actions { margin-top: 16px; flex-wrap: wrap; } /* Campaign jobs table — horizontal scroll inside the panel */ #campaign-jobs-page-table { overflow-x: auto; width: 100%; } /* ── Responsive ──────────────────────────────────────────────────────── */ @media (max-width: 860px) { .header-inner, .footer-inner { flex-direction: column; align-items: flex-start; } .header-inner { height: auto; padding: 12px 0; } .hero, .feature-grid { grid-template-columns: 1fr; } .controls-header, .table-toolbar { flex-direction: column; align-items: flex-start; } .hero-copy, .hero-panel { padding: 24px; } .form-grid { grid-template-columns: 1fr; } .import-grid { grid-template-columns: 1fr; } .stats-grid { grid-template-columns: 1fr; } .page-content { padding-top: 24px; } } @media (max-width: 560px) { .container { width: min(100% - 1rem, 1200px); } .site-nav { width: 100%; } .nav-link { width: 100%; text-align: center; } .hero h1 { font-size: 22px; } }