/* FlyFX admin panel. No inline styles anywhere: the CSP allows style-src 'self' only. */ :root { color-scheme: light; --bg: #f6f6f4; --surface: #fcfcfb; --surface-2: #f0efec; --border: #e2e1dc; --grid: #e9e8e4; --text: #0b0b0b; --text-2: #52514e; --text-3: #7a7974; --accent: #2a78d6; --accent-ink: #ffffff; --series-1: #2a78d6; --good: #0f7b3e; --good-bg: #e3f4ea; --warn: #8a5a00; --warn-bg: #fbf0d6; --bad: #b42323; --bad-bg: #fbe5e4; --neutral-bg: #ecebe7; --focus: #2a78d6; --radius: 8px; --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace; } @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { color-scheme: dark; --bg: #121211; --surface: #1a1a19; --surface-2: #232321; --border: #34332f; --grid: #2b2a27; --text: #f0efec; --text-2: #c3c2b7; --text-3: #9a998f; --accent: #3987e5; --series-1: #3987e5; --good: #6fd39a; --good-bg: #173523; --warn: #f0c36a; --warn-bg: #3a2c0c; --bad: #f08a88; --bad-bg: #401918; --neutral-bg: #2b2a27; --focus: #6aa8f0; } } :root[data-theme="dark"] { color-scheme: dark; --bg: #121211; --surface: #1a1a19; --surface-2: #232321; --border: #34332f; --grid: #2b2a27; --text: #f0efec; --text-2: #c3c2b7; --text-3: #9a998f; --accent: #3987e5; --series-1: #3987e5; --good: #6fd39a; --good-bg: #173523; --warn: #f0c36a; --warn-bg: #3a2c0c; --bad: #f08a88; --bad-bg: #401918; --neutral-bg: #2b2a27; --focus: #6aa8f0; } * { box-sizing: border-box; } html, body { margin: 0; } body { background: var(--bg); color: var(--text); font: 14px/1.5 var(--font); -webkit-font-smoothing: antialiased; } a { color: var(--accent); text-decoration: none; } a:hover { text-decoration: underline; } :focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; } h1, h2, h3 { margin: 0; font-weight: 600; } h1 { font-size: 20px; } h2 { font-size: 15px; } code, .mono { font-family: var(--mono); font-size: 12.5px; } .muted { color: var(--text-2); } .small { font-size: 12.5px; } .hidden { display: none !important; } /* ---------- layout ---------- */ .shell { display: grid; grid-template-columns: 220px 1fr; min-height: 100vh; } .sidebar { background: var(--surface); border-right: 1px solid var(--border); padding: 20px 12px; display: flex; flex-direction: column; gap: 4px; position: sticky; top: 0; height: 100vh; } .brand { font-weight: 700; font-size: 15px; padding: 0 10px 16px; letter-spacing: -0.01em; } .brand span { color: var(--text-3); font-weight: 500; } .nav a { display: block; padding: 7px 10px; border-radius: 6px; color: var(--text-2); font-weight: 500; } .nav a:hover { background: var(--surface-2); text-decoration: none; color: var(--text); } .nav a.active { background: var(--surface-2); color: var(--text); } .sidebar-foot { margin-top: auto; padding: 12px 10px 0; border-top: 1px solid var(--border); } .sidebar-foot .who { font-weight: 600; } .main { padding: 28px 32px 48px; min-width: 0; } .page-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 20px; flex-wrap: wrap; } /* ---------- cards, tiles ---------- */ .card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 18px 20px; } /* Vertical rhythm between stacked blocks; grid items are spaced by the grid gap instead. */ .card + .card, .grid + .card, .card + .grid, .grid + .grid { margin-top: 16px; } .grid > .card { margin-top: 0; } .card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 14px; } .grid { display: grid; gap: 16px; } .tiles { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); } .two { grid-template-columns: 2fr 1fr; } .tile .label { color: var(--text-2); font-size: 13px; } .tile .value { font-size: 28px; font-weight: 600; letter-spacing: -0.02em; margin-top: 4px; } .tile .sub { color: var(--text-3); font-size: 12.5px; margin-top: 2px; } /* ---------- tables ---------- */ .table-wrap { overflow-x: auto; margin: 0 -20px; } table { width: 100%; border-collapse: collapse; } th, td { text-align: left; padding: 9px 20px; border-bottom: 1px solid var(--grid); white-space: nowrap; } th { font-size: 12px; font-weight: 600; color: var(--text-2); text-transform: none; } td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; } tbody tr:last-child td { border-bottom: 0; } tbody tr.clickable { cursor: pointer; } tbody tr.clickable:hover td { background: var(--surface-2); } .empty { color: var(--text-2); padding: 28px 0; text-align: center; } .truncate { max-width: 340px; overflow: hidden; text-overflow: ellipsis; } .badge { display: inline-flex; align-items: center; gap: 5px; padding: 1px 8px; border-radius: 999px; font-size: 12px; font-weight: 500; background: var(--neutral-bg); color: var(--text-2); } .badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; } .badge.good { background: var(--good-bg); color: var(--good); } .badge.warn { background: var(--warn-bg); color: var(--warn); } .badge.bad { background: var(--bad-bg); color: var(--bad); } /* ---------- forms & buttons ---------- */ .toolbar { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; } input, select { font: inherit; color: var(--text); background: var(--surface); border: 1px solid var(--border); border-radius: 6px; padding: 7px 10px; min-width: 0; } input:focus, select:focus { outline: 2px solid var(--focus); outline-offset: -1px; border-color: transparent; } label.field { display: grid; gap: 5px; font-weight: 500; font-size: 13px; } label.field input, label.field select { width: 100%; font-weight: 400; } .form { display: grid; gap: 14px; } button { font: inherit; font-weight: 500; cursor: pointer; border-radius: 6px; padding: 7px 14px; border: 1px solid var(--border); background: var(--surface); color: var(--text); } button:hover { background: var(--surface-2); } button.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); } button.primary:hover { filter: brightness(1.07); } button.danger { color: var(--bad); } button.link { border: 0; background: none; padding: 0; color: var(--accent); } button:disabled { opacity: .55; cursor: default; } .error { color: var(--bad); background: var(--bad-bg); border-radius: 6px; padding: 8px 12px; font-size: 13px; } .notice { background: var(--warn-bg); color: var(--warn); border-radius: 6px; padding: 10px 12px; font-size: 13px; } .secret { font-family: var(--mono); font-size: 15px; padding: 10px 12px; border-radius: 6px; background: var(--surface-2); border: 1px dashed var(--border); user-select: all; word-break: break-all; } .pager { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 14px; color: var(--text-2); font-size: 13px; } .pager .toolbar button { padding: 5px 12px; } /* Row actions stay on one line; the table scrolls sideways on narrow screens. */ td .toolbar { flex-wrap: nowrap; gap: 6px; } td .toolbar button { padding: 4px 10px; font-size: 13px; } /* ---------- rate editor ---------- */ .rate-input { width: 140px; } .code-input { width: 90px; text-transform: uppercase; font-family: var(--mono); } .form-actions { margin-top: 14px; } /* ---------- auth screens ---------- */ .auth { min-height: 100vh; display: grid; place-items: center; padding: 16px; } .auth .card { width: 100%; max-width: 380px; padding: 28px; } .auth h1 { margin-bottom: 4px; } .auth p { margin: 0 0 18px; } /* ---------- chart ---------- */ .chart { position: relative; } .chart svg { display: block; width: 100%; height: auto; overflow: visible; } .chart .gridline { stroke: var(--grid); stroke-width: 1; shape-rendering: crispEdges; } .chart .axis-text { fill: var(--text-3); font-size: 11px; font-family: var(--font); } .chart .bar { fill: var(--series-1); } .chart .hit { fill: transparent; cursor: default; } .chart .hit:hover + .bar, .chart .bar.on { opacity: .8; } .tooltip { position: absolute; pointer-events: none; z-index: 2; background: var(--text); color: var(--bg); font-size: 12px; padding: 5px 9px; border-radius: 6px; white-space: nowrap; transform: translate(-50%, calc(-100% - 8px)); } .chart-toggle { font-size: 12.5px; } .kv { display: grid; grid-template-columns: max-content 1fr; gap: 6px 20px; margin: 0; } .kv dt { color: var(--text-2); } .kv dd { margin: 0; overflow-wrap: anywhere; } pre.json { margin: 0; font-family: var(--mono); font-size: 12px; white-space: pre-wrap; word-break: break-word; max-width: 420px; color: var(--text-2); } /* ---------- small screens ---------- */ @media (max-width: 820px) { .shell { grid-template-columns: 1fr; } .sidebar { position: static; height: auto; flex-direction: row; flex-wrap: wrap; align-items: center; padding: 10px 16px; } .brand { padding: 0 12px 0 0; } .nav { display: flex; flex-wrap: wrap; gap: 2px; } .sidebar-foot { margin: 0 0 0 auto; padding: 0; border: 0; display: flex; gap: 12px; align-items: center; } .main { padding: 20px 16px 40px; } .two { grid-template-columns: 1fr; } .table-wrap { margin: 0 -20px; } /* The chart scales down with its viewBox; enlarge the axis text in viewBox units so it still renders at about 10px on a phone. */ .chart .axis-text { font-size: 18px; } .hide-narrow { display: none; } .rate-input { width: 110px; } }