/* ==========================================================================
   PulseIQ — typography, density and live motion.
   Loaded last. Sets only what the base sheet leaves generic.

   Bahnschrift is a variable DIN: its character lives in the WIDTH axis, not
   the weight axis. At 100% width it reads like any other grotesque; drawn
   semi-condensed it becomes the lettering of a gauge face, which is the whole
   reason it was chosen. Every figure the user reads as a measurement is set
   in it, condensed, with tabular numerals.

   Sizes derive from the tokens in styles.css rather than repeating literals,
   so the whole app rescales from one place.
   ========================================================================== */

body {
  font-family: var(--sans);
  font-size: var(--t-md);
  line-height: 1.55;
  font-synthesis-weight: none;
}

/* ---------------------------------------------------------------- display */
.brand-name,
.page-title,
.card-title,
.modal-title,
.stat-value,
.big-clock,
.gauge-value .num,
.sec-title,
h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 600;
  letter-spacing: 0;
  text-wrap: balance;
}

.brand-name { font-size: var(--t-lg); font-weight: 700; }
.brand-sub  { font-size: var(--t-xs); color: var(--ink-3); margin-top: -1px; }
.page-title { font-weight: 650; letter-spacing: -.018em; }
.page-sub   { font-family: var(--sans); font-size: var(--t-sm); color: var(--ink-3); }
.card-title { font-size: var(--t-lg); font-weight: 620; }
.modal-title{ font-size: var(--t-lg); font-weight: 650; }

/* ---------------------------------------------------------------- numerals */
.stat-value, .big-clock, .num, td.num, .gauge-value .num, .kcol-count {
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

.stat-value {
  font-size: var(--t-2xl);
  font-weight: 620;
  letter-spacing: -.008em;
  line-height: 1.02;
}
.stat-value span { font-weight: 500; opacity: .55; }

.big-clock {
  font-family: var(--display);
  font-size: var(--t-3xl);
  font-weight: 600;
  letter-spacing: .004em;
  line-height: 1;
}

.mono, code, pre, .kbd, .ai-metric { font-family: var(--mono); }
code, .ai-metric { font-size: var(--t-xs); letter-spacing: -.012em; }
pre { font-size: var(--t-sm); line-height: 1.62; }
td.num, .num { font-family: var(--display); font-weight: 560; }

/* ---------------------------------------------------------------- labels */
.stat-label, .nav-divider, th, .kcol-title {
  font-family: var(--sans-sm);
  font-size: var(--t-xs);
  font-weight: 650;
  letter-spacing: .085em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.sec-title { font-size: var(--t-sm); letter-spacing: .08em; }
.label  { font-family: var(--sans-sm); font-size: var(--t-sm); font-weight: 620; letter-spacing: .008em; }
.badge  { font-family: var(--sans-sm); font-size: var(--t-xs); font-weight: 660; letter-spacing: .018em; padding: var(--s-1) var(--s-2h); }
.kbd    { font-size: var(--t-xs); padding: var(--s-1) var(--s-2); }

/* ---------------------------------------------------------------- prose */
p, .ai-card-body, .card-sub, .stat-meta, .small, .tiny { font-family: var(--sans); }
.card-sub    { font-size: var(--t-sm); color: var(--ink-3); }
.small       { font-size: var(--t-md); }
.tiny        { font-size: var(--t-sm); }
.stat-meta   { font-size: var(--t-xs); color: var(--ink-3); margin-top: var(--s-0); }
.modal-body p, .empty .small { max-width: 66ch; }

.btn { font-family: var(--sans-sm); font-size: var(--t-sm); font-weight: 620; padding: var(--s-2) var(--s-4); }
.btn-sm { font-size: var(--t-xs); padding: var(--s-1h) var(--s-3); }
input, select, textarea { font-family: var(--sans); font-size: var(--t-md); padding: var(--s-2h) var(--s-3); }
/* Single-line controls get a fixed height with ZERO block padding — vertical
   centring comes from the height, so 16px text can never clip. textarea keeps
   its padding; it is the one multi-line control. */
input:not([type="checkbox"]):not([type="radio"]), select {
  height: 36px; padding-top: 0; padding-bottom: 0;
}
.user-name { font-family: var(--display); font-weight: 620; font-size: var(--t-md); }
.user-role { font-size: var(--t-xs); }

/* ---------------------------------------------------------------- sidebar */
.nav-item     { font-size: var(--t-md); padding: var(--s-2h) var(--s-3); gap: var(--s-3); font-weight: 540; }
.nav-divider  { padding: var(--s-4h) var(--s-3) var(--s-2); }
.state-label  { font-size: var(--t-md); font-weight: 580; }
.state-time   { font-size: var(--t-sm); }
.state-chip   { padding: var(--s-3) var(--s-3h); }
.avatar       { width: 31px; height: 31px; font-size: var(--t-xs); }

/* ==========================================================================
   Density and depth
   ========================================================================== */

/* The content was capped at 1120px inside a much wider column, which left a
   dead band before the AI rail. It now fills the space it is given, with a
   ceiling that still keeps running prose near a readable measure. */
.content { padding: var(--s-5) var(--s-5) var(--s-7); }
/* styles.css said 1180, layout.css said 1080, this said 1480. This one won
   by load order rather than by decision. Now it is the only one. */
.content-inner { max-width: 1600px; margin: 0 auto; }

.card {
  padding: var(--s-4) var(--s-4h);
  border-radius: 13px;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--ink) 2.5%, transparent) 0%, transparent 48px),
    var(--surface);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--ink) 4%, transparent),
              0 1px 3px -1px color-mix(in srgb, var(--ink) 14%, transparent);
}
.card-head { margin-bottom: var(--s-3h); }
.grid { gap: var(--s-3h); }
.col  { gap: var(--s-3h); }

.card.stat { padding: var(--s-4) var(--s-4) var(--s-4); position: relative; overflow: hidden; gap: var(--s-1h); }
.card.stat::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--line-soft); transition: background var(--t-base) var(--ease);
}
.card.stat:has(.stat-value.green)::before { background: var(--signal); }
.card.stat:has(.stat-value.amber)::before { background: var(--amber); }
.card.stat:has(.stat-value.coral)::before { background: var(--coral); }

/* Tables were cramped at 8px — rows need room to be scannable. */
th { padding: var(--s-3) var(--s-3h); }
td { padding: var(--s-3) var(--s-3h); font-size: var(--t-md); }
tbody tr:hover { background: var(--surface-2); }

/* The topbar is a utility strip now; its height lives in styles.css. */
.empty  { padding: 52px 22px; }
.empty .small { font-size: var(--t-sm); }

/* AI rail scales with everything else */
.ai-rail       { --rail-w: 300px; }
.ai-title      { font-size: var(--t-sm); font-weight: 650; }
.ai-sub        { font-size: var(--t-xs); }
.ai-card       { padding: var(--s-3h) var(--s-3h); }
.ai-card-title { font-size: var(--t-sm); font-weight: 640; line-height: 1.35; }
.ai-card-body  { font-size: var(--t-sm); line-height: 1.65; max-width: none; color: var(--ink-2); }
.ai-metric     { font-size: var(--t-xs); padding: var(--s-1h) var(--s-2); }

/* ==========================================================================
   LIVE MOTION — movement means something happened, never decoration
   ========================================================================== */

.big-clock.live { color: var(--signal); }
.big-clock.live::after {
  content: ""; display: inline-block; width: 8px; height: 8px; margin-left: var(--s-2h);
  border-radius: 50%; background: var(--signal); vertical-align: middle;
  animation: heartbeat 1s steps(1, end) infinite;
}
@keyframes heartbeat { 0%, 49% { opacity: 1; } 50%, 100% { opacity: .18; } }

.figure-changed { animation: figure-tick var(--t-base) var(--spring-out); }
@keyframes figure-tick {
  0%   { transform: translateY(-3px); opacity: .45; }
  100% { transform: none; opacity: 1; }
}

.live-rail { position: relative; height: 2px; border-radius: 2px; background: var(--surface-3); overflow: hidden; }
.live-rail::after {
  content: ""; position: absolute; inset: 0; width: 38%;
  background: linear-gradient(90deg, transparent, var(--signal), transparent);
  animation: rail-sweep 2.1s var(--ease) infinite;
}
@keyframes rail-sweep { from { transform: translateX(-110%); } to { transform: translateX(360%); } }

.wave { display: flex; align-items: center; gap: var(--s-0); height: 30px; }
.wave i {
  flex: 1; min-width: 2px; border-radius: 2px;
  background: var(--signal); opacity: .55; transform-origin: center;
  transition: height .28s var(--spring), opacity .28s var(--ease);
}
.wave.idle i { background: var(--ink-3); opacity: .28; }

.syncing svg { animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.row-live { animation: row-flash 1var(--t-fast) var(--ease); }
@keyframes row-flash {
  0%   { background: color-mix(in srgb, var(--signal) 16%, transparent); }
  100% { background: transparent; }
}

.ai-rail.refreshed .ai-spark { animation: spark-hit var(--t-slow) var(--spring-out); }
@keyframes spark-hit {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.22) rotate(-8deg); }
  100% { transform: scale(1); }
}

.bar-fill { transition: width .8s var(--spring), background var(--t-base) var(--ease); position: relative; }
.bar-fill.moved::after {
  content: ""; position: absolute; right: 0; top: -2px; bottom: -2px; width: 10px;
  border-radius: 6px; background: currentColor; opacity: .5;
  animation: bar-glow var(--t-slow) var(--ease) forwards;
}
@keyframes bar-glow { to { opacity: 0; transform: scaleX(2.4); } }

.focus-live { position: relative; }
.focus-live::after {
  content: ""; position: absolute; inset: -6px; border-radius: inherit;
  border: 1.5px solid var(--indigo); opacity: 0;
  animation: focus-ring 3s var(--ease) infinite;
}
@keyframes focus-ring {
  0%   { opacity: .5; transform: scale(.97); }
  70%  { opacity: 0;  transform: scale(1.05); }
  100% { opacity: 0; }
}

.btn { position: relative; overflow: hidden; }
.btn .ripple {
  position: absolute; border-radius: 50%; transform: scale(0);
  background: currentColor; opacity: .22; pointer-events: none;
  animation: ripple .55s var(--ease) forwards;
}
@keyframes ripple { to { transform: scale(2.6); opacity: 0; } }

.chart-live { animation: chart-swap .38s var(--spring); }
@keyframes chart-swap { from { opacity: .35; transform: scale(.994); } to { opacity: 1; transform: none; } }

.ribbon i.fresh { animation: bar-arrive .9s var(--ease); }
@keyframes bar-arrive {
  0%   { background: var(--signal); opacity: 1; transform: scaleY(1.25); }
  100% { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* A heat calendar with only a few weeks of data was stretching its cells to
   ~100px each. Charts fill the width they are given, so the sparse case needs
   a ceiling rather than a percentage. */
.plot { justify-content: flex-start; }
.plot svg.chart { max-height: 240px; width: auto; max-width: 100%; }
.plot .ribbon { width: 100%; }

/* ------------------------------------------------------------ width axis
   Bahnschrift is a variable DIN and its character is in the WIDTH axis, not
   the weight axis — drawn semi-condensed it reads like the lettering on a
   gauge face, which is why it was chosen for figures in the first place.

   Aptos Display has no width axis. Setting one there does nothing at best,
   and at worst asks the browser to synthesise a condensed face, which looks
   squashed. So the axis is applied only when Bahnschrift is genuinely the
   font being used. Weight is expressed as plain font-weight above, which
   every face in the stack understands. */
@supports (font-variation-settings: "wdth" 85) {
  .num, td.num, .stat-value, .big-clock, .kcol-count, .gauge-value .num {
    font-family: "Bahnschrift", var(--display);
  }
  /* Only Bahnschrift receives the axis; the fallbacks inherit nothing. */
  @font-face { font-family: "PulseIQ Figures"; src: local("Bahnschrift"); }
  .num, td.num, .stat-value, .big-clock, .kcol-count, .gauge-value .num {
    font-variation-settings: "wdth" 88;
  }
}
