/*
  AgencyLadder — base layer
  Font loading contract, reset, global tabular-nums, body background, keyframes.
  DESIGN-SYSTEM.md §1 (theme), §3 (typography), §6 (motion).

  Load order in the page <head>:
    <link ... Google Fonts ...>
    <link rel="stylesheet" href="/css/tokens.css">
    <link rel="stylesheet" href="/css/base.css">
    <link rel="stylesheet" href="/css/components.css">
*/

/* -----------------------------------------------------------------------
   Font loading — Inter 400/500/600/700/800 + JetBrains Mono 400/500/600/700.
   No italics, no variable axes, nothing self-hosted (§3 "Loading"). This is
   authored here as a documented contract; ship the equivalent <link> tags
   in every page <head> ahead of this stylesheet:

   <link rel="preconnect" href="https://fonts.googleapis.com">
   <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
   <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">

   Deliberately NOT a CSS @import here: @import serialises behind this
   stylesheet's own download and ignores the <link rel="preconnect"> pair
   above, so it would quietly defeat the fast-load contract it's supposed
   to enforce. The <link> tags are the loading mechanism; this file just
   assumes the stacks below are already available.
   ----------------------------------------------------------------------- */

/* -----------------------------------------------------------------------
   Reset
   ----------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body,
h1,
h2,
h3,
h4,
p,
figure,
blockquote,
dl,
dd,
ul,
ol {
  margin: 0;
}

ul,
ol {
  padding: 0;
  list-style: none;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

img,
picture,
svg,
canvas {
  display: block;
  max-width: 100%;
}

button,
input,
textarea,
select {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
}

button {
  cursor: pointer;
}

button:disabled {
  cursor: default;
}

a {
  color: inherit;
  text-decoration: none;
}

/* -----------------------------------------------------------------------
   The global numeric rule (§3) — every number on the board is Mono and
   tabular. This is applied globally rather than only where digits are
   known to render, because the board polls every few seconds and any
   surface can gain a number later; a global rule can't be forgotten.
   Non-negotiable: without it, live-updating figures jitter.
   ----------------------------------------------------------------------- */
html {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* -----------------------------------------------------------------------
   Body — dark only, no prefers-color-scheme, no toggle (§1)
   ----------------------------------------------------------------------- */
body {
  background: var(--page);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
  /* No horizontal scroll surface — layout is flex-wrap + min-width floors,
     never a breakpoint, so nothing should ever force overflow-x (§4). */
  overflow-x: hidden;
}

/* -----------------------------------------------------------------------
   6. Motion — keyframe registry
   ----------------------------------------------------------------------- */

/* pls — 2s ease-in-out infinite, live dots */
@keyframes pls {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .35; transform: scale(.82); }
}

/* rise — 300ms entry for modals and toasts */
@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* tick — 1000ms clock pulse (agoLabel-style live timestamps) */
@keyframes tick {
  0%, 100% { opacity: .5; }
  50%      { opacity: 1; }
}

/* swp — skeleton shimmer sweep */
@keyframes swp {
  from { background-position: -160% 0; }
  to   { background-position: 260% 0; }
}

/* fall — slow drifting confetti, Top Shoutout panel only (§6). Documented in the motion
   registry but missing from this file until ODO-7/8 needed it for the shoutout card. */
@keyframes fall {
  0%   { transform: translateY(0) rotate(0deg); opacity: .5; }
  100% { transform: translateY(340px) rotate(140deg); opacity: 0; }
}

/* ── [hidden] MUST ACTUALLY HIDE ───────────────────────────────────────────────────────────────
   The browser's own `[hidden] { display: none }` is a USER-AGENT rule, so any author rule that
   sets `display` on the same element beats it on cascade origin alone, regardless of specificity.
   Every component in this codebase that is a flex or grid container and gets toggled with the
   `hidden` attribute therefore stays visible while claiming to be hidden.

   It has bitten twice already and both were reported as "why is this here":
     - .consent-details (display:flex) rendered the whole cookie panel on first paint, making the
       "small corner card" 404px tall, 48% of a phone viewport.
     - .board-empty-strip stayed on screen after being hidden for signed-in readers, leaving an
       empty outlined button with no label sitting under the board.

   `!important` is deliberate and is the one place in this stylesheet it is justified: `hidden` is
   a statement about whether the element EXISTS for the reader, and nothing about a component's own
   layout should be able to override that. A component that needs to be visible simply must not
   carry the attribute. */
[hidden] {
  display: none !important;
}
