/* ═══════════════════════════════════════════════════════════
   Base: fonts, reset, typography defaults, background, focus
   ═══════════════════════════════════════════════════════════ */

/* Gilroy: only the 400 and 700 cuts, exactly as in Team — a 500 or 600 elsewhere would
   render a heavier face than the design system has. */
@font-face { font-family: 'Gilroy'; src: url("/assets/Gilroy-Regular-b40dc147.woff") format('woff'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'Gilroy'; src: url("/assets/Gilroy-Bold-30f25b4c.woff") format('woff'); font-weight: 700; font-style: normal; font-display: swap; }
/* RF Dewi Expanded: headings (700) and the "Blog" of the header lockup (400). */
@font-face { font-family: 'RF Dewi Expanded'; src: url("/assets/RFDewiExpanded-Regular-17653cab.woff2") format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'RF Dewi Expanded'; src: url("/assets/RFDewiExpanded-Bold-c233d754.woff2") format('woff2'), url("/assets/RFDewiExpanded-Bold-d33c2d8e.woff") format('woff'); font-weight: 700; font-style: normal; font-display: swap; }

/* ── Reset ── */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  scroll-padding-top: calc(var(--header-height) + var(--sp-4));
  scrollbar-color: var(--surface-raised) var(--bg);
}
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
body {
  min-height: 100vh;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--lh-24);
  color: var(--text);
  background: var(--bg);
  overflow-x: clip;
}
/* `hidden` must win over any display a component sets (the header search panel is flex). */
[hidden] { display: none !important; }
a { color: inherit; text-decoration: none; }
img, svg, video { display: block; max-width: 100%; }
img { height: auto; }
ul, ol { list-style: none; }
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; }
/* The browser's own clear cross is thick, tiny and outside the design system; search
   fields that need one draw their own (an .icon-btn with the 1px cross). */
input[type="search"]::-webkit-search-cancel-button { appearance: none; }
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading);
  font-weight: 700;
  line-height: 1.2; /* a fallback: every heading class sets its own pair in px */
  letter-spacing: -0.02em;
  color: var(--text);
  overflow-wrap: break-word;
}
::selection { background: rgba(29, 226, 39, 0.3); color: var(--text); }

/* ── Line breaks without a hanging line (the design system's ADR-0018): a heading or a
   short text (a lead, a description, a caption — up to a few lines) balances its lines;
   running text does not end on a lone word. Progressive — a browser without text-wrap
   breaks as before. Chrome balances up to six lines; a clamped excerpt balances the whole
   text and shows its first lines, all of them full. ── */
h1, h2, h3, h4, h5, h6 { text-wrap: balance; }
p, li, dd, figcaption, blockquote { text-wrap: pretty; }
:is(.page-subtitle, .article__lead, .subscribe__text, .subscribe__consent, .hero__excerpt,
    .feed-row__excerpt, .card__excerpt, .empty-state__text, .footer-desc,
    .field-action__error) { text-wrap: balance; }

/* ── Focus: one accent ring for every interactive element, from the keyboard only — 2px,
   2px off the edge (the design system, question 27). Inside a parent that clips, a
   control draws it 2px inside instead (the feed row, the bottom bar). ── */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ── Background: Team's static mesh gradient ── */
body::before {
  content: "";
  position: fixed;
  inset: -25%;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(ellipse 80% 70% at 5% 95%, rgba(29, 226, 39, 0.10) 0%, transparent 65%),
    radial-gradient(ellipse 70% 80% at 92% 12%, rgba(29, 226, 39, 0.08) 0%, transparent 60%),
    radial-gradient(ellipse 55% 55% at 8% 8%, rgba(0, 210, 235, 0.06) 0%, transparent 55%),
    radial-gradient(ellipse 50% 50% at 85% 85%, rgba(0, 200, 120, 0.05) 0%, transparent 55%),
    var(--bg);
}

/* ── Layout primitives ── */
.container {
  width: 100%;
  max-width: calc(var(--container) + var(--gutter) * 2);
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.main-content {
  padding-top: var(--header-height);
  min-height: calc(100vh - 240px);
}
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ── Entrance: Team's content-rise + content-fade ── */
@keyframes content-rise { from { transform: translateY(16px); } to { transform: translateY(0); } }
@keyframes content-fade { from { opacity: 0; } to { opacity: 1; } }
/* `backwards`, not `both`: a transform kept after the animation would turn every
   section into a containing block for position: fixed descendants. */
.main-content > * { animation: content-rise var(--dur-4) var(--ease) backwards, content-fade var(--dur-4) var(--ease) backwards; }
/* A soft visit (soft_visit.js: the feed's category switch) puts new blocks into <main>,
   and they rise as on a page load — all but the one holding the sticky feed bar: rising
   and fading, it would carry the bar along (and an ancestor with opacity < 1 is a
   backdrop root — the haze under the bar would go out). Its other children rise instead. */
.main-content.is-switched > :has(.feed-bar) { animation: none; }
.main-content.is-switched > :has(.feed-bar) > :not(.feed-bar) {
  animation: content-rise var(--dur-4) var(--ease) backwards, content-fade var(--dur-4) var(--ease) backwards;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
