/* BGSNL Dashboard.
   Palette and shapes follow the Chronicle art bible section 10 (Koki-approved
   2026-08-08). Light only, matching what actually shipped on the live
   Chronicle - dark mode was deliberately removed there.

   Chapter colours are identity trim beside a name and logo, never the sole
   encoding: as a categorical chart palette they fail CVD separation
   (Eindhoven and Maastricht are ~identical to a deuteranope) and the
   normal-vision floor. Comparisons use one hue and labelled rows instead. */

@font-face {
  font-family: "Supreme";
  src: url("/static/fonts/Supreme-Regular.woff2") format("woff2");
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: "Supreme";
  src: url("/static/fonts/Supreme-Medium.woff2") format("woff2");
  font-weight: 500; font-display: swap;
}
@font-face {
  font-family: "Supreme";
  src: url("/static/fonts/Supreme-Bold.woff2") format("woff2");
  font-weight: 700; font-display: swap;
}

:root {
  --ground:      #FBF8F1;
  --ground-2:    #F4EFE4;
  --card:        #FFFFFF;
  --ink:         #1F1F25;
  --ink-soft:    #55525C;
  --muted:       #8A8593;
  --rule:        rgba(31, 31, 37, 0.14);
  --rule-soft:   rgba(31, 31, 37, 0.07);
  --shadow:      rgba(31, 31, 37, 0.09);

  --crimson:     #9E0D33;   /* emphasis, active state, focus */
  --crimson-dim: rgba(158, 13, 51, 0.10);
  --teal:        #017363;   /* primary actions */
  --teal-dim:    rgba(1, 115, 99, 0.10);
  --green:       #025420;   /* headings */
  --red:         #F92820;   /* links, small marks */

  --radius-pill: 999px;
  --radius:      14px;
  --radius-sm:   10px;

  --f: "Supreme", ui-sans-serif, system-ui, "Segoe UI", Helvetica, Arial, sans-serif;
  --f-data: ui-monospace, "Cascadia Mono", "Segoe UI Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--f);
  color: var(--ink);
  background-color: var(--ground);
  /* the linen weave from the art bible, very quiet */
  background-image:
    linear-gradient(var(--rule-soft) 1px, transparent 1px),
    linear-gradient(90deg, var(--rule-soft) 1px, transparent 1px);
  background-size: 13px 13px;
  font-size: 16px;
  line-height: 1.55;
  overflow-x: clip;
}

h1, h2, h3 { color: var(--green); font-weight: 700; text-wrap: balance; margin: 0; }
h1 { font-size: clamp(1.6rem, 3.4vw, 2.3rem); line-height: 1.06; letter-spacing: -0.01em; }
h2 { font-size: clamp(1.15rem, 2.2vw, 1.45rem); line-height: 1.12; }
a { color: var(--red); }

.mono {
  font-family: var(--f-data);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.13em;
  color: var(--muted);
}

.wrap { max-width: 1180px; margin: 0 auto; padding: 0 28px; }
@media (max-width: 760px) { .wrap { padding: 0 18px; } }

/* --- header --------------------------------------------------------------- */

.topbar {
  border-bottom: 1px solid var(--rule);
  background: color-mix(in srgb, var(--ground) 88%, transparent);
  backdrop-filter: blur(8px);
  position: sticky; top: 0; z-index: 20;
}
.topbar .wrap {
  display: flex; align-items: center; gap: 16px;
  min-height: 68px; flex-wrap: wrap;
  /* Vertical padding matters only once this wraps: on a phone the controls
     drop to a second row, which otherwise sits flush on the bottom rule. */
  padding-top: 10px; padding-bottom: 10px;
}
.brand { display: flex; align-items: center; gap: 12px; margin-right: auto; min-width: 0; }
/* A label and its control are one unit - as bare flex siblings they wrapped
   onto separate rows, leaving "Viewing" stranded above its own dropdown.
   Named hdr-field, not field: `.field` already belongs to the dialog forms,
   where labels are block-level and inputs full-width. */
.hdr-field { display: flex; align-items: center; gap: 8px; min-width: 0; }
.hdr-field[hidden] { display: none; }

/* The controls move as one block, so they wrap under the brand together
   instead of breaking up mid-row. */
.topbar-controls { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }

/* Selects and the pill button carried different vertical padding (0.45em vs
   0.5em), so they were never the same height and never lined up. One explicit
   height settles it; horizontal padding still differs, as it should. */
.topbar .hdr-field > select,
.topbar .btn {
  height: 36px;
  padding-top: 0; padding-bottom: 0;
  display: inline-flex; align-items: center;
}
.topbar .hdr-field > label {
  white-space: nowrap; flex: none;
  font-size: .62rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-soft);
}
@media (max-width: 760px) {
  /* Two rows, not three. Sign out rides the brand row - given its own row it
     sat right-aligned under two full-width selects, lining up with nothing. */
  .topbar .wrap { padding-top: 12px; padding-bottom: 14px; row-gap: 14px; }
  .topbar .wrap > #signOut { order: 2; flex: none; }
  .topbar-controls { order: 3; width: 100%; gap: 12px; }
  .topbar-controls .hdr-field { flex: 1 1 100%; }
  .topbar .hdr-field > select { flex: 1; min-width: 0; }
  /* Labels share one column width so the two selects start on the same x. */
  .topbar .hdr-field > label { width: 52px; }
}
.brand img { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; flex: none; }
.brand-text { min-width: 0; }
.brand-name {
  font-weight: 700; color: var(--green); line-height: 1.15;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* --- controls ------------------------------------------------------------- */

button, .btn {
  font-family: var(--f); font-size: 0.9rem; font-weight: 500;
  border-radius: var(--radius-pill);
  border: 1px solid var(--rule);
  background: var(--card); color: var(--ink);
  padding: 0.5em 1.1em; cursor: pointer;
  transition: background .16s, border-color .16s, color .16s, transform .16s;
  text-decoration: none; display: inline-flex; align-items: center; gap: .5em;
}
button:hover, .btn:hover { border-color: var(--teal); color: var(--teal); background: var(--teal-dim); }
button:disabled { opacity: .45; cursor: not-allowed; }
button:disabled:hover { border-color: var(--rule); color: var(--ink); background: var(--card); }

.btn-primary {
  background: var(--teal); color: #fff; border-color: var(--teal);
}
.btn-primary:hover { background: #015c4f; border-color: #015c4f; color: #fff; }

:focus-visible { outline: 2px solid var(--crimson); outline-offset: 2px; }

select, input[type="text"], input[type="date"], input[type="password"] {
  font-family: var(--f); font-size: 0.9rem;
  padding: 0.45em 0.7em;
  border: 1px solid var(--rule); border-radius: var(--radius-sm);
  background: var(--card); color: var(--ink);
}
/* The native arrow sits hard against the right border. Drawing it ourselves is
   the only way to control that gap - a select's built-in arrow ignores
   padding-right in Chrome. */
select {
  appearance: none; -webkit-appearance: none;
  padding-right: 2.1em;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%235b6357' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75em center;
}
select::-ms-expand { display: none; }
input[type="text"] { min-width: 0; }

/* --- tabs ----------------------------------------------------------------- */

.tabs { display: flex; gap: 6px; border-bottom: 1px solid var(--rule); margin: 26px 0 22px; }
.tab {
  border: none; background: none; border-radius: 0;
  padding: 0.6em 0.1em; margin-right: 22px;
  color: var(--ink-soft); font-weight: 500;
  border-bottom: 2px solid transparent;
}
.tab:hover { background: none; color: var(--crimson); border-color: transparent; }
.tab[aria-selected="true"] { color: var(--crimson); border-bottom-color: var(--crimson); }

/* --- catalogue: stacked rows, not a card grid ------------------------------ */

.toolbar {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  margin-bottom: 16px;
}
.toolbar .spacer { margin-left: auto; }

.rows {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
}
.row {
  display: grid;
  grid-template-columns: 4px minmax(0, 1fr) auto auto;
  align-items: center; gap: 16px;
  padding: 14px 18px 14px 0;
  border-bottom: 1px solid var(--rule-soft);
}
.row:last-child { border-bottom: none; }
.row:hover { background: var(--ground-2); }
.row-accent { align-self: stretch; background: var(--rule-soft); border-radius: 0 2px 2px 0; }
.row-main { min-width: 0; padding-left: 14px; }
.row-name { display: flex; align-items: center; gap: 9px; font-weight: 500; min-width: 0; }
/* the name truncates; the chip must not be eaten by the ellipsis */
.row-name .name-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row-name .chip { flex: none; }
.row-sub { font-family: var(--f-data); font-size: .72rem; color: var(--muted); }
.row-price { font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 500; }
.row-date { color: var(--ink-soft); font-size: .85rem; white-space: nowrap; }

.chip {
  display: inline-block; border-radius: var(--radius-pill);
  padding: 0.15em 0.7em; font-size: .72rem; font-weight: 500;
  border: 1px solid currentColor; white-space: nowrap;
}
.chip-event { color: var(--crimson); }
.chip-membership { color: var(--teal); }

@media (max-width: 820px) {
  .row { grid-template-columns: 4px minmax(0, 1fr) auto; row-gap: 6px; padding-right: 14px; }
  .row-date { display: none; }
}

.pager {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 16px; color: var(--ink-soft); font-size: .88rem;
}
.pager .spacer { margin-left: auto; }
.pager button { padding: 0.35em 0.85em; font-size: .85rem; }
/* Previous and Next are one control, so they wrap as a pair or not at all -
   otherwise Next drops onto a line of its own on a phone. */
.pager-nav { display: flex; gap: 8px; flex: none; }

/* --- stat tiles ----------------------------------------------------------- */

.tiles { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); }
.tile {
  background: var(--card); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: 16px 18px;
  border-left: 3px solid var(--accent, var(--rule));
}
.tile-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.tile-head img { width: 30px; height: 30px; border-radius: 50%; object-fit: cover; flex: none; }
.tile-head .name { font-weight: 700; color: var(--green); }
.metric-row { display: flex; gap: 22px; flex-wrap: wrap; }
.metric { min-width: 84px; }
.metric .value {
  font-size: 1.5rem; font-weight: 700; line-height: 1.1;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.metric .value.none { font-size: .95rem; font-weight: 500; color: var(--muted); font-style: italic; }
.metric .label {
  font-family: var(--f-data); font-size: .64rem; text-transform: uppercase;
  letter-spacing: .12em; color: var(--muted);
}
.spark { display: block; margin-top: 10px; width: 100%; height: 30px; }

/* --- panels, notices ------------------------------------------------------ */

.panel {
  background: var(--card); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: 18px; margin-bottom: 18px;
}
.notice {
  border-radius: var(--radius-sm); padding: 10px 14px; margin: 12px 0;
  font-size: .9rem; border: 1px solid;
}
.notice-warn { color: #7a4b00; border-color: rgba(122,75,0,.3); background: rgba(192,135,42,.10); }
.notice-error { color: var(--crimson); border-color: rgba(158,13,51,.3); background: var(--crimson-dim); }
.notice-info { color: var(--ink-soft); border-color: var(--rule); background: var(--ground-2); }

.empty { color: var(--muted); padding: 34px 18px; text-align: center; font-style: italic; }

table.plain { width: 100%; border-collapse: collapse; font-size: .9rem; }
table.plain th {
  text-align: left; font-family: var(--f-data); font-size: .64rem;
  text-transform: uppercase; letter-spacing: .12em; color: var(--muted);
  font-weight: 500; padding: 6px 12px 6px 0; border-bottom: 1px solid var(--rule);
}
table.plain td { padding: 8px 12px 8px 0; border-bottom: 1px solid var(--rule-soft); font-variant-numeric: tabular-nums; }
table.plain td.name { font-variant-numeric: normal; }
.scroll-x { overflow-x: auto; }

/* --- export dialog -------------------------------------------------------- */

dialog {
  border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 0; max-width: 460px; width: calc(100% - 36px);
  background: var(--card); color: var(--ink); box-shadow: 0 18px 50px var(--shadow);
}
dialog::backdrop { background: rgba(31,31,37,.35); }
.dialog-body { padding: 22px; }
.field { margin: 14px 0; }
.field label { display: block; font-family: var(--f-data); font-size: .64rem;
  text-transform: uppercase; letter-spacing: .12em; color: var(--muted); margin-bottom: 5px; }
.field input, .field select { width: 100%; }
.dialog-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 20px; }

.progress { height: 5px; background: var(--ground-2); border-radius: var(--radius-pill); overflow: hidden; margin-top: 10px; }
.progress span { display: block; height: 100%; background: var(--teal); width: 0; transition: width .3s; }

/* --- login ---------------------------------------------------------------- */

.login-shell { min-height: 100vh; display: grid; place-items: center; padding: 40px 18px; }
.login-card {
  background: var(--card); border: 1px solid var(--rule); border-radius: var(--radius);
  box-shadow: 0 22px 60px var(--shadow);
  padding: 40px; max-width: 460px; width: 100%;
}
.login-card img.crest { width: 76px; height: 76px; border-radius: 50%; }
.login-card h1 { margin: 18px 0 6px; }
.login-card p.lede { color: var(--ink-soft); margin: 0 0 26px; }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* --- per-chapter panels (social, events) ---------------------------------- */

.panel.chapter { border-left: 3px solid var(--accent, var(--rule)); }
.chapter-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.chapter-head img { width: 34px; height: 34px; border-radius: 50%; object-fit: cover; flex: none; }
.chapter-head h2 { margin: 0; }

/* Missing data must never look like a zero - the previous dashboard's worst
   habit. Italic muted text reads as absence, a 0 reads as a measurement. */
.nodata { color: var(--muted); font-style: italic; font-variant-numeric: normal; }

/* --- growth chart --------------------------------------------------------- */

.chart { width: 100%; min-width: 720px; height: auto; }
.chart .grid { stroke: var(--rule-soft); stroke-width: 1; }
.chart .axis { fill: var(--muted); font-size: 11px; font-family: var(--f-data); }
/* Direct end-labels, so a line is identified by its name and not by its colour */
.chart .lbl { fill: var(--ink-soft); font-size: 12px; font-family: var(--f); }

/* --- export dialog extras -------------------------------------------------- */

.hint { color: var(--muted); font-size: .78rem; line-height: 1.45; margin-top: 6px; }
.check { display: flex; align-items: center; gap: 8px; margin-top: 8px;
  font-size: .85rem; color: var(--ink-soft); text-transform: none;
  letter-spacing: 0; font-family: var(--f); }
.check input { width: auto; margin: 0; }
input:disabled { background: var(--ground-2); color: var(--muted); }

table.plain.summary { margin-top: 14px; max-width: 340px; }
table.plain.summary td { padding: 6px 10px; }
table.plain.summary td:last-child { text-align: right; font-variant-numeric: tabular-nums; }
table.plain.summary td.strong, table.plain.summary td.name.strong { font-weight: 700; }
table.plain.summary tr:nth-child(-n+3) td { background: rgba(192,135,42,.10); }
table.plain.summary tr:nth-child(n+4) td { background: rgba(1,115,99,.08); }

.chart-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 6px; }
.chart-head h2 { margin-right: auto; }
.seg { display: inline-flex; border: 1px solid var(--rule); border-radius: var(--radius-pill); overflow: hidden; }
.seg button { border: none; border-radius: 0; padding: 0.35em 0.9em; font-size: .82rem; background: var(--card); }
.seg button:hover { background: var(--teal-dim); color: var(--teal); }
.seg button.on { background: var(--teal); color: #fff; }
.seg button.on:hover { background: var(--teal); color: #fff; }

/* The pager and the last panel were sitting flush against the viewport edge. */
main.wrap { padding-bottom: 72px; }

/* --- social: one row per platform ----------------------------------------- */
/* Instagram has no account-level like count, so the layout carries whatever
   metrics a platform actually has rather than a fixed grid with empty cells. */

.platform {
  display: grid;
  grid-template-columns: 108px minmax(0, 1fr) auto;
  align-items: center; gap: 16px;
  padding: 11px 0;
  border-top: 1px solid var(--rule-soft);
}
.platform-name { font-weight: 500; }
.platform-link { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.platform-link a { color: var(--teal); text-decoration: none; }
.platform-link a:hover { text-decoration: underline; }
.platform-metrics { display: flex; gap: 20px; white-space: nowrap; }
.stat b { font-variant-numeric: tabular-nums; font-weight: 700; }
.stat-label {
  font-family: var(--f-data); font-size: .62rem; text-transform: uppercase;
  letter-spacing: .12em; color: var(--muted);
}

@media (max-width: 640px) {
  .platform { grid-template-columns: 1fr; gap: 4px; }
  .platform-metrics { gap: 16px; }
}

/* --- history -------------------------------------------------------------- */

/* Full bleed: the Chronicle is its own page and should read exactly as it
   does on the VPS, with only the dashboard's header and tabs above it. */
#historyFrame {
  display: block;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  /* Fallback only - JS sets the real height from the frame's measured top, so
     it stays correct when the header wraps to two rows on a phone. */
  height: calc(100vh - 138px);
  min-height: 360px;
  border: 0;
  background: var(--card);
}
/* One scrollbar, not two. The Chronicle is a full page with its own scroll;
   letting the dashboard scroll as well put two bars side by side. */
body.history-open { overflow: hidden; }
/* The measure and the 72px footer gap only get in the Chronicle's way. */
body.history-open main.wrap { max-width: none; padding-left: 0; padding-right: 0; padding-bottom: 0; }
body.history-open .tabs { max-width: 1180px; margin-left: auto; margin-right: auto; padding: 0 28px; }
body.history-open #historyNotice:not(:empty) { max-width: 1180px; margin: 0 auto 12px; padding: 0 28px; }
@media (max-width: 760px) { body.history-open .tabs { padding: 0 18px; } }
