/* group-page.css — the group page (#/room/:id) only: its front and ledger, the "here"
 * list, the time spine's marks, the visit log, and the settings-change log.
 *
 * Composition only. Every colour, size and rule is a token from tokens.css;
 * the band, band head, ranked row, table, figure, provenance and states are
 * the system's own (layout.css, data.css, states.css). Prefixes: `grp-` for
 * this page, `chg-` for js/changes.js (whose table also appears in the person
 * page's group drawer), `spine-` additions for js/gantt.js.
 */

/* ============================================================== the front
 *
 * A broadsheet front page for one group, set as a FORM GUIDE: kicker, the
 * topic as headline, a giant numeral with its seat strip beside it, the one
 * call to action, and under it all the "Before you join" ledger — eight ruled
 * cells, a question in mono caps over a one-line answer in Fraunces. */

.grp-front-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(14rem, 22rem);
  grid-template-areas:
    'back   back'
    'kicker count'
    'title  count'
    'cta    count'
    'ledger ledger';
  column-gap: var(--s-7);
  row-gap: var(--s-4);
  align-items: start;
}
/* The band's generic stacking margin does not apply inside this grid. */
.band > .grp-front-grid > * + * { margin-top: 0; }

.grp-back   { grid-area: back; margin-bottom: var(--s-2); }
.grp-kicker { grid-area: kicker; }
.grp-title  { grid-area: title; }
.grp-count  { grid-area: count; }
.grp-cta    { grid-area: cta; }
.grp-ledger { grid-area: ledger; }

.grp-kicker {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--s-1) var(--s-2);
  justify-self: start;
  padding-top: var(--s-2);
  border-top: var(--edge-strong);
  color: var(--ink-2);
}
.grp-kicker-sep { color: var(--rule); }

/* The topic IS the headline. Long topics step down a size in JS (t-display →
 * t-h1 → t-h2) so they wrap into a block rather than a column of words, and
 * `balance` evens the lines. Any script, any direction: dir="auto" + .ugc. */
.grp-title {
  max-width: 24ch;
  text-wrap: balance;
  overflow-wrap: anywhere;
  hyphens: auto;
}
.grp-title.t-h2 { max-width: 40ch; }
/* 69% of topics are blank: the language pair is the title, in the italic turn,
 * never "Untitled". */
.grp-title.is-untitled { font-style: italic; font-weight: 400; color: var(--ink-2); }

/* ---- the giant numeral and its seat strip */
.grp-count {
  display: grid;
  gap: var(--s-3);
  align-content: start;
  padding-left: var(--s-6);
  border-left: var(--edge);
}
.grp-count .fig { gap: var(--s-2); }
.grp-count .fig-value { font-size: calc(var(--t-fig-giant) * 1.1); }
.grp-count .fig-unit { font-size: var(--t-base); color: var(--ink-2); }
/* The page's ONE headline numeral takes the accent — only while it is "now".
 * A figure from a stale check stays ink, and its as-of stamp says why. */
.grp-count[data-tense='now'] .fig-value { color: var(--accent); text-shadow: var(--glow-hot); }
.grp-count-note {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--s-1) var(--s-2);
  color: var(--ink-3);
  font-size: var(--t-sm);
}
.grp-count-seats { color: var(--ink-2); font-weight: 560; }
.grp-closed { color: var(--ink-2); font-style: italic; font-weight: 420; }

/* Seats, one tick each: taken is solid ink, free is an open outline. Shape and
 * fill carry it, never hue — capacity is a group property, not a warning. */
.grp-seats {
  --seat-w: 0.625rem;
  --seat-h: 1.125rem;
  display: flex; flex-wrap: wrap;
  gap: var(--s-1);
}
.grp-seat {
  width: var(--seat-w); height: var(--seat-h);
  border: var(--bw-1) solid var(--rule);
  border-radius: var(--r-1);
}
.grp-seat[data-taken='1'] { background: var(--ink); border-color: var(--ink); }
/* Past SEAT_TICKS_MAX (front.js) a tick is too thin to read: one bar instead. */
.grp-seats.is-bar {
  height: var(--s-2);
  background: var(--surface-2);
  border-radius: var(--r-1);
  overflow: hidden;
}
.grp-seats-fill {
  display: block; height: 100%;
  background: var(--ink);
  transform: scaleX(var(--fill));
  transform-origin: left center;
}

/* ---- the call to action */
.grp-cta {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--s-3);
  padding-top: var(--s-2);
}
.grp-cta .note { flex-basis: 100%; }
.grp-front .grp-cta-btn:not([data-size]) {
  min-height: 3rem;
  padding-inline: var(--s-6);
  font-size: var(--t-base);
}

/* ============================================================== the ledger */

.grp-ledger {
  margin-top: var(--s-6);
  padding-top: var(--s-3);
  border-top: var(--edge-double);
}
.grp-ledger-title { color: var(--ink); }

/* Rules between cells without nth-child arithmetic (the spans change per
 * breakpoint): every cell draws its own top and left rule, shifted 1px out of
 * its area, and the grid clips the outer edge. */
.grp-led {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  --led-pad: var(--s-4);
  margin-top: var(--s-3);
  /* Pull the first column back by its padding so its text sits on the page
   * edge, flush with the headline, while its clipped rule stays out of view. */
  margin-inline-start: calc(-1 * var(--led-pad));
  /* Clip the outer rules AND the pulled-back strip, so every rule starts on
   * the page edge under the double rule above. */
  clip-path: inset(0 0 0 var(--led-pad));
}
.grp-led-cell {
  display: grid;
  grid-template-rows: auto 1fr;
  gap: var(--s-2);
  min-width: 0;
  margin: -1px 0 0 -1px;
  padding: var(--s-4) var(--led-pad) var(--s-5);
  border-top: var(--edge-soft);
  border-left: var(--edge-soft);
}
.grp-led-cell[data-span='wide'] { grid-column: span 2; }
.grp-led-q { color: var(--ink-3); }
.grp-led-body { display: grid; gap: var(--s-2); align-content: start; min-width: 0; }

.grp-led-a {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: var(--s-1) var(--s-2);
  font-family: var(--font-display);
  font-size: var(--t-xl);
  font-weight: 520;
  line-height: var(--lh-snug);
  letter-spacing: var(--tr-title);
  color: var(--ink);
  text-wrap: balance;
  overflow-wrap: anywhere;
}
/* The language pair inherits the answer's voice instead of its tag sizing. */
.grp-led-a .lang-pair { font: inherit; letter-spacing: inherit; }
.grp-led-icon {
  --attr-glyph: 1.1em;
  --attr-glyph-w: 1.5;
  display: inline-grid; place-items: center;
  align-self: center;
}
.grp-led-glyph { --attr-glyph: 14px; display: block; }
.grp-led-d {
  font-size: var(--t-sm);
  line-height: var(--lh-normal);
  color: var(--ink-3);
  text-wrap: pretty;
}
.grp-led-d time { color: var(--ink-2); font-variant-numeric: tabular-nums; }
.grp-led-stay { display: block; margin-top: var(--s-1); color: var(--ink-2); }
.grp-led-stay .num { font-weight: 600; color: var(--ink); }
.grp-led-a .live-dot { align-self: center; }

/* Decisive (cannot speak, cannot get in): a heavier rule and a heavier answer.
 * Weight and rule, never hue (tokens.css, --attr-*). */
.grp-led-cell.is-decisive { border-top: var(--edge-strong); }
.grp-led-cell.is-decisive .grp-led-q { color: var(--ink); }
.grp-led-cell.is-decisive .grp-led-a { font-weight: 700; }
/* Quiet: the question has no live answer (closed, too new). The italic turn,
 * as for an untitled group. */
.grp-led-cell.is-quiet .grp-led-a { font-style: italic; font-weight: 400; color: var(--ink-2); }

/* ---- the pulse: headcount over the hour before the last check */
.grp-pulse {
  --pulse-h: 2.25rem;
  position: relative;
  display: grid; gap: var(--s-1);
  max-width: var(--w-text);
}
.grp-pulse-svg { display: block; width: 100%; height: var(--pulse-h); overflow: visible; }
.grp-pulse-area { fill: var(--data-1); }
.grp-pulse-line {
  fill: none;
  stroke: var(--viz-series);
  stroke-width: var(--viz-series-w);
  stroke-linejoin: round;
}
.grp-pulse-dot {
  position: absolute; right: 0; top: 0;
  width: 0.5rem; height: 0.5rem;
  border-radius: var(--r-full);
  background: var(--ink-3);
  box-shadow: 0 0 0 2px var(--bg);
  transform: translate(50%, calc(var(--y) * var(--pulse-h) - 50%));
}
/* --live means observed AND current: the end of the line earns it only "now". */
.grp-pulse[data-tense='now'] .grp-pulse-dot { background: var(--viz-now); }
.grp-pulse-axis, .grp-hours-axis {
  display: flex; justify-content: space-between;
  font-family: var(--viz-font);
  font-size: var(--viz-tick-size);
  color: var(--ink-3);
}

/* ---- the crowd: regulars solid, newcomers open, unsure hatched */
.grp-crowd { display: flex; gap: 2px; height: var(--s-2); max-width: var(--w-text); }
.grp-crowd-seg { flex-basis: 0; border-radius: var(--r-1); }
.grp-crowd-seg[data-k='regular'] { background: var(--ink); }
.grp-crowd-seg[data-k='new'] { border: var(--bw-1) solid var(--ink-2); }
.grp-crowd-seg[data-k='unsure'] {
  background: repeating-linear-gradient(135deg, var(--viz-hatch) 0 1px, transparent 1px 4px);
}

/* ---- usual hours: arrivals by hour of the reader's day */
.grp-hours { display: grid; gap: var(--s-1); max-width: var(--w-text); }
/* Labels at 0, 6, 12 and 18h: four equal columns, each label on its left
 * edge, so 18h sits at 75% and not at the far end. */
.grp-hours .grp-hours-axis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grp-hours-bars {
  display: grid;
  grid-template-columns: repeat(24, minmax(0, 1fr));
  gap: 2px;
  height: 2.5rem;
  border-bottom: var(--edge);
}
.grp-hours-bar { display: flex; align-items: flex-end; }
.grp-hours-fill {
  display: block; width: 100%; height: 100%;
  background: var(--data-2);
  transform: scaleY(max(var(--h), 0.04));
  transform-origin: bottom;
}
.grp-hours-bar.is-peak .grp-hours-fill { background: var(--data-5); }
.grp-hours-bar.is-now { outline: var(--bw-1) dashed var(--ink-3); outline-offset: 1px; }

/* ---- arrival choreography. Seats fill left to right, the pulse and the hours
 * rise once. Off entirely under reduced motion: the base rule shortens
 * durations but not delays, so a staggered tick would sit invisible. */
@media (prefers-reduced-motion: no-preference) {
  .grp-seat { animation: grp-seat-in var(--dur-4) var(--ease-out) both; animation-delay: calc(var(--i) * 18ms + 120ms); }
  .grp-seats-fill { animation: grp-fill-in var(--dur-4) var(--ease-out) both 120ms; }
  .grp-pulse-svg, .grp-hours-bars { animation: grp-rise var(--dur-4) var(--ease-out) both 200ms; }
  .grp-led-cell { animation: grp-rise var(--dur-3) var(--ease-out) both; }
  .grp-led-cell:nth-child(n + 5) { animation-delay: 60ms; }
}
@keyframes grp-seat-in { from { opacity: 0; transform: scaleY(0.2); } }
@keyframes grp-fill-in { from { transform: scaleX(0); } }
@keyframes grp-rise { from { opacity: 0; transform: translateY(6px); } }
@media (prefers-reduced-motion: reduce) {
  .grp-seat, .grp-seats-fill, .grp-pulse-svg, .grp-hours-bars, .grp-led-cell { animation: none !important; }
}

/* ---- the phone dock: the CTA, kept in reach once the front scrolls away */
.grp-dock { display: none; }

@media (min-width: 60rem) {
  /* Four across: the settings on the first row, the readings on the second. */
  .grp-led { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .grp-led-cell[data-span='wide'] { grid-column: auto; }
}

@media (max-width: 56rem) {
  .grp-front-grid {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: 'back' 'kicker' 'title' 'count' 'cta' 'ledger';
  }
  .grp-count {
    padding-left: 0;
    border-left: 0;
    padding-block: var(--s-3);
    border-block: var(--edge-soft);
  }
  .grp-count .fig-value { font-size: var(--t-fig-giant); }
}

@media (max-width: 44.9375rem) {
  .grp-led { --led-pad: var(--s-3); }
  .grp-led-cell { padding-block: var(--s-3) var(--s-4); }
  .grp-led-cell:not([data-span='wide']) .grp-led-a { font-size: var(--t-lg); }
  .grp-cta { flex-direction: column; align-items: stretch; }
  .grp-front .grp-cta-btn:not([data-size]) { width: 100%; }

  .grp-dock {
    position: fixed; z-index: 30;
    inset: auto 0 0 0;
    display: flex; align-items: center; gap: var(--s-3);
    padding: var(--s-2) var(--s-gutter) calc(var(--s-2) + env(safe-area-inset-bottom, 0px));
    background-color: var(--surface);
    border-top: var(--edge-strong);
    box-shadow: var(--shadow-lift), inset 0 1px 0 var(--halo);
    transform: translateY(110%);
    visibility: hidden;
    transition: transform var(--dur-3) var(--ease-out), visibility 0s linear var(--dur-3);
  }
  .grp-dock[data-shown='1'] {
    transform: none;
    visibility: visible;
    transition: transform var(--dur-3) var(--ease-out);
  }
  .grp-dock-title {
    flex: 1; min-width: 0;
    font-family: var(--font-display);
    font-size: var(--t-base);
    font-weight: 560;
  }
  .grp-dock .btn { flex: none; min-height: 44px; }
  /* Room at the foot of the page so the dock never sits over the last line. */
  .canvas:has(.grp-dock) { padding-bottom: 4.5rem; }
}

/* ============================================================== who is here */

.grp-here { border-top: var(--edge); }
.grp-here-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--s-4);
  align-items: start;
  padding-block: var(--s-3);
  border-bottom: var(--edge-soft);
}
.grp-here-who { min-width: 0; }
.grp-here-name {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--s-2);
  min-width: 0;
}
.grp-here-name .entity { min-height: 44px; max-width: 100%; }
.grp-here-name .entity-name { font-weight: 600; }
.grp-here-row .claim { padding-left: calc(36px + var(--s-2)); margin-top: 0; }
.grp-here-fig { align-items: flex-end; padding-top: var(--s-2); }
.grp-here-fig .fig-unit { text-align: right; }

@media (max-width: 29.9375rem) {
  .grp-here-row .claim { padding-left: 0; }
}

/* ======================================================== the time spine
 *
 * viz.css owns the axis voice; these are the marks. Bars are data ink, a
 * visit still open at the last check is the accent (the one mark the page's
 * sentence is about), a truncated bar fades via a gradient whose colour is
 * set here, never in JS. */

.spine { display: grid; gap: var(--s-3); margin-top: var(--s-2); }
/* Drawn at the measured width; below the minimum it scrolls, never squashes. */
.spine-scroll > .spine-svg { width: auto; max-width: none; }
.spine-bar:not(.is-cut) { fill: var(--data-4); }
.spine-bar.is-open { fill: var(--viz-emph); }
.spine-fade-stop { stop-color: var(--data-4); }
.spine-lane-label { font-family: var(--font-text); }
.spine-legend .legend-key[data-swatch='emph'] .legend-swatch { background: var(--viz-emph); }

/* ---- the visit log: the spine's accessible twin, one click away */
.grp-visit-log {
  margin-top: var(--s-5);
  border-top: var(--edge-soft);
}
.grp-visit-log-summary {
  display: flex; align-items: center; gap: var(--s-2);
  min-height: 44px;
  color: var(--accent);
  font-weight: 600;
  font-size: var(--t-sm);
  cursor: pointer;
  list-style: none;
}
.grp-visit-log-summary::-webkit-details-marker { display: none; }
.grp-visit-log-summary::before {
  content: '';
  width: 0.45em; height: 0.45em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--dur-2) var(--ease-both);
}
.grp-visit-log[open] > .grp-visit-log-summary::before { transform: rotate(45deg); }
.grp-visit-log > .table-wrap { margin-top: var(--s-2); }

/* ============================================================== regulars */

.grp-reg-name { color: var(--ink); }
.grp-reg-name:hover { color: var(--accent); }
.grp-regulars .ranked-title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }

/* ============================================================ the record */

.grp-record .col-aside > .kicker { margin-bottom: var(--s-2); }
.grp-record-facts .meta-row { grid-template-columns: minmax(6.5rem, 8rem) minmax(0, 1fr); }
.grp-code {
  font-size: var(--t-xs);
  letter-spacing: 0;
  overflow-wrap: anywhere;
}
.grp-ext { color: var(--accent); }
.grp-ext:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---- js/changes.js: the log (this page) and the table (the group drawer) */
.chg-log { border-top: var(--edge); }
.chg-log-item {
  display: grid;
  grid-template-columns: minmax(7rem, 9rem) minmax(0, 1fr);
  column-gap: var(--s-4);
  align-items: baseline;
  padding-block: var(--s-3);
  border-bottom: var(--edge-soft);
}
.chg-log-when {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-xs);
  color: var(--ink-3);
}
.chg-log-what { display: grid; gap: var(--s-1); min-width: 0; }
.chg-field { font-size: var(--t-sm); font-weight: 600; color: var(--ink); }
.chg-log-pair, .chg-to {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: var(--s-1) var(--s-2);
  min-width: 0;
}
.chg-value { color: var(--ink-3); }
.chg-value.is-new { color: var(--ink); }
.chg-arrow { color: var(--ink-3); }

@media (max-width: 29.9375rem) {
  .chg-log-item { grid-template-columns: minmax(0, 1fr); row-gap: var(--s-1); }
}
