/* ============================================================================
   TNI — Website layout layer                         public/styles/site.css
   ----------------------------------------------------------------------------
   Loaded AFTER brand/tokens.css and brand/type-color.css, so the cascade is
   explicit: tokens first, role classes second, layout third.

   This file contains LAYOUT ONLY: grid, flow, spacing, sizing, states. It
   re-declares NO token value. Every colour, size, radius, duration and easing
   is consumed through var(--tni-…); typography exclusively through the role
   classes (.tni-*) and the scale tokens (--tni-font-size-*, --tni-space-*,
   --tni-measure-*, --tni-radius-*).

   Structure ported from the approved reference
   brand/website-mockups/direction-a/{index.html,mockup.css}; the mockup-only
   section blocks do not ship here.
   ========================================================================= */


/* ---------------------------------------------------------------------------
   Self-hosted Poppins (400/500/600). Brand layer ships the .ttf files under
   /brand/fonts and sets --tni-font-sans, but carries no @font-face block, so the
   faces are declared here. Locally served — no CDN, no Google Fonts; there is no
   italic and no 700.
   ------------------------------------------------------------------------ */
@font-face {
  font-family: Poppins;
  src: url("/brand/fonts/Poppins-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: Poppins;
  src: url("/brand/fonts/Poppins-Medium.ttf") format("truetype");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: Poppins;
  src: url("/brand/fonts/Poppins-SemiBold.ttf") format("truetype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}


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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  font-family: var(--tni-font-sans);
  background: var(--tni-bg);
  color: var(--tni-fg);
}

img { display: block; max-width: 100%; }

/* Jump targets clear the floating bar. */
:target { scroll-margin-block-start: var(--tni-space-4xl); }

.tn-muted { color: var(--tni-fg-muted); }

/* Inline icon container — verbatim from brand/iconography.md § 8. `currentColor`
   only inherits inside an INLINE svg, which is why icons are never <img>. */
.tn-icon      { display: inline-flex; line-height: 0; flex: 0 0 auto; }
.tn-icon svg  { display: block; width: var(--tni-icon-size, 24px); height: var(--tni-icon-size, 24px); }


/* ---------------------------------------------------------------------------
   Page shell + top raster band (Base.astro)
   .tn-page is the position:relative wrapper starting at the body top; .tn-raster
   is the business-card-back raster (the Rasterverlauf square-opacity ladder,
   one artwork in both themes, colour-inverted: /brand/motif-raster-light.svg
   olive-on-cream light / /brand/motif-alt.svg chartreuse-on-dark dark), faded out
   toward the bottom by a mask. It sits BEHIND all content at z-index 0 while
   the shell lifts every direct content child to z-index 1 (the navbar takes
   its lift from its own base rule, which the sticky rule overrides from xl
   up; the skip chip is absolute at z-index 100 anyway). The layer AND the art
   span the wrapper edge to edge — full bleed like the business-card face, no
   container cap — so the Rasterverlauf continues to the viewport edges and
   never ends at the site box. Same-origin /brand asset; no external request.
   ------------------------------------------------------------------------ */
.tn-page { position: relative; }

.tn-raster {
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: min(640px, 75vw); /* art is 4:3; below 853px the band equals its height */
  z-index: 0;
  pointer-events: none;
  background-image: url("/brand/motif-raster-light.svg");
  background-position: top center;
  background-repeat: no-repeat;
  background-size: 100% auto;
  -webkit-mask-image: linear-gradient(to bottom, black 0%, transparent 100%);
  mask-image: linear-gradient(to bottom, black 0%, transparent 100%);
  opacity: 0.7;
}
[data-tni-theme="dark"] .tn-raster { background-image: url("/brand/motif-alt.svg"); }

/* Content above the band: lift the shell's direct content children. The
   navbar's lift lives in its own base rule below (sticky from xl up). */
.tn-page > :where(main, .tn-footer) { position: relative; z-index: 1; }

/* ---------------------------------------------------------------------------
   Container, section rhythm (blueprint § 7)
   ------------------------------------------------------------------------ */
.tn-container {
  width: 100%;
  max-width: var(--tni-grid-max);
  margin-inline: auto;
  padding-inline: var(--tni-space-sm);   /* 16px base gutter */
}
/* Gutter ladder (blueprint § 7): 16px base, 24px from md, 32px from lg —
   straight off the space tokens. */
@media (min-width: 768px)  { .tn-container { padding-inline: var(--tni-space-md); } }
@media (min-width: 1024px) { .tn-container { padding-inline: var(--tni-space-lg); } }

.tn-section { padding-block: var(--tni-space-2xl); }
@media (min-width: 1024px) { .tn-section { padding-block: var(--tni-space-3xl); } }

.tn-section__head { margin-block-end: var(--tni-space-xl); max-width: var(--tni-measure-body); }
.tn-section__head > .tni-overline { display: block; margin-block-end: var(--tni-space-2xs); color: var(--tni-fg-accent); }
.tn-section__head > .tni-title-2 { margin: 0; }
.tn-section__lead { margin-block-start: var(--tni-space-sm); color: var(--tni-fg-muted); }

/* Responsive display scaling (blueprint § 7): the display/title band steps DOWN
   the canonical ladder on small screens — one step below md (768px), a second
   step below sm (640px). Only existing token steps are reused; no fluid
   interpolation, no new values. site.css loads after type-color.css, so these
   equally specific rules win by source order. */
@media (max-width: 767px) {
  .tni-display-1 { font-size: var(--tni-font-size-display-2); }
  .tni-display-2 { font-size: var(--tni-font-size-title-1); }
  .tni-title-1   { font-size: var(--tni-font-size-title-2); }
  .tni-title-2   { font-size: var(--tni-font-size-title-3); }
  .tni-title-3   { font-size: var(--tni-font-size-title-4); }
  .tni-title-4   { font-size: var(--tni-font-size-lead); }
}
@media (max-width: 639px) {
  .tni-display-1 { font-size: var(--tni-font-size-title-1); }
  .tni-display-2 { font-size: var(--tni-font-size-title-2); }
  .tni-title-1   { font-size: var(--tni-font-size-title-3); }
  .tni-title-2   { font-size: var(--tni-font-size-title-4); }
  .tni-title-3   { font-size: var(--tni-font-size-lead); }
  .tni-title-4   { font-size: var(--tni-font-size-body); }
}

/* Dark rounded panel used by the 01–04 strip, the CTA band and the footer.
   `data-tni-theme="dark"` flips the semantic layer for the subtree
   (brand/type-color.css § 6); the surface comes from the flipped --tni-bg. */
.tn-panel {
  padding: var(--tni-space-xl);
  border-radius: var(--tni-radius-md);
  box-shadow: var(--tni-elevation);
}
@media (min-width: 768px) { .tn-panel { padding: var(--tni-space-2xl); } }


/* ---------------------------------------------------------------------------
   Skip link
   ------------------------------------------------------------------------ */
.tn-skip {
  position: absolute;
  left: var(--tni-space-sm);
  top: var(--tni-space-sm);
  z-index: 100;
  transform: translateY(-200%);
  padding: var(--tni-space-xs) var(--tni-space-md);
  background: var(--tni-bg-raised);
  color: var(--tni-fg);
  border: 1px solid var(--tni-line-strong);
  border-radius: var(--tni-radius-sm);
  text-decoration: none;
}
/* :focus-visible, not :focus — the back-to-top fragment (#tn-top sits on this
   link) moves focus here after a pointer click; the chip only appears for
   keyboard users. */
.tn-skip:focus-visible { transform: translateY(0); }


/* ---------------------------------------------------------------------------
   Floating navigation bar (blueprint § 5.1)
   ------------------------------------------------------------------------ */
/* relative + z-index 1 keeps the bar above the top raster band below xl;
   from xl up the sticky rule below takes over (z-index 20). */
.tn-navbar { position: relative; z-index: 1; }
@media (min-width: 1280px) {
  .tn-navbar {
    position: sticky;
    inset-block-start: var(--tni-space-sm);
    z-index: 20;
  }
}

.tn-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--tni-space-md);
  min-height: 66px;                       /* 40px mark + free space, rationale § 5 */
  padding: var(--tni-space-xs) var(--tni-space-sm);
  background: var(--tni-bg-raised);
  border: 1px solid var(--tni-line);
  border-radius: var(--tni-radius-md);
  box-shadow: var(--tni-elevation);
}
@media (min-width: 768px) { .tn-nav { padding-inline: var(--tni-space-md); } }

.tn-nav__brand { display: inline-flex; flex: 0 0 auto; }
.tn-nav__brand img { width: auto; height: 40px; }

/* Theme-aware groundless mark (Logo.astro, variant 'mark'): light art by
   default, reverse art inside any dark-theme subtree ([data-tni-theme="dark"]
   on <html> or on a .tn-panel). Both <img> boxes are identical, so the pure-CSS
   swap cannot shift layout. */
.tn-logo__dark { display: none; }
[data-tni-theme="dark"] .tn-logo__light { display: none; }
[data-tni-theme="dark"] .tn-logo__dark { display: block; }

.tn-nav__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--tni-space-md);
  margin: 0;
  margin-inline: auto;
  padding: 0;
  list-style: none;
}

.tn-nav__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tni-target-comfort);
  color: var(--tni-fg);
  text-decoration: none;
}
.tn-nav__link:hover {
  color: var(--tni-fg-accent);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.18em;
}
/* Current page: colour AND an underline marker, never colour alone (§ 5.1). */
.tn-nav__link[aria-current="page"] {
  color: var(--tni-fg-accent);
  box-shadow: inset 0 -2px 0 0 var(--tni-fg-accent);
}

.tn-nav__actions {
  display: flex;
  align-items: center;
  gap: var(--tni-space-sm);
  margin-inline-start: auto;
}
.tn-nav__cta { text-decoration: none; }

/* Under lg the bar wraps instead of opening a JS sheet: a hamburger without a
   script would be a broken control, and the site ships no menu JavaScript.
   The action cluster shrinks and wraps internally so nothing overflows the
   container at 375px */
@media (max-width: 1279px) {
  .tn-nav__list { order: 3; width: 100%; margin-inline: 0; }
  .tn-nav__actions { flex: 1 1 auto; flex-wrap: wrap; justify-content: flex-end; min-width: 0; }
}

/* Phone header (<640): brand, language and theme share the first row, the
   booking CTA gets its own full-width row, then the wrapped link list. Keeps
   the zero-JS wrap nav but removes two rows of chrome. */
@media (max-width: 639px) {
  .tn-nav__actions { display: contents; }
  .tn-lang { order: 2; margin-inline-start: auto; }
  .tn-theme-toggle { order: 2; }
  .tn-nav__cta { order: 3; flex: 1 1 100%; justify-content: center; }
  .tn-nav__list { order: 4; }
}

/* At desktop the bar stays a single row: brand, links and the action cluster
   all sit on one vertical centre line. The list is the only part allowed to
   give; the mark and the actions keep their intrinsic size. */
@media (min-width: 1280px) {
  .tn-nav { flex-wrap: nowrap; }
  .tn-nav__list { flex-wrap: nowrap; min-width: 0; }
  .tn-nav__link { white-space: nowrap; }
  .tn-nav__actions { flex: 0 0 auto; }
}


/* ---------------------------------------------------------------------------
   Language switcher + theme toggle
   ------------------------------------------------------------------------ */
.tn-lang { display: flex; align-items: center; gap: var(--tni-space-2xs); }

.tn-lang__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tni-target-comfort);
  padding-inline: var(--tni-space-3xs);
  color: var(--tni-fg);
  text-decoration: none;
}
.tn-lang__link:hover {
  color: var(--tni-fg-accent);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.18em;
}
.tn-lang__link[aria-current="true"] {
  color: var(--tni-fg-accent);
  box-shadow: inset 0 -2px 0 0 var(--tni-fg-accent);
}

.tn-theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tni-target-comfort);
  height: var(--tni-target-comfort);
  padding: 0;
  background: transparent;
  color: var(--tni-fg);
  border: 1px solid var(--tni-line-strong);
  border-radius: var(--tni-radius-sm);
  cursor: pointer;
}
.tn-theme-toggle:hover { background: var(--tni-bg-sunken); }
/* Half-filled circle = contrast affordance. Drawn with currentColor, no new art. */
.tn-theme-toggle__glyph {
  width: 16px;
  height: 16px;
  border: 1px solid currentColor;
  border-radius: var(--tni-radius-full);
  background: linear-gradient(90deg, currentColor 0 50%, transparent 50% 100%);
}


/* ---------------------------------------------------------------------------
   Hero (blueprint § 5.2)
   ------------------------------------------------------------------------ */
.tn-hero__grid { display: grid; gap: var(--tni-space-xl); align-items: center; }
@media (min-width: 1024px) {
  .tn-hero__grid { grid-template-columns: 6fr 6fr; gap: var(--tni-space-2xl); }
}

.tn-hero__text { display: flex; flex-direction: column; align-items: flex-start; gap: var(--tni-space-md); }
.tn-eyebrow { color: var(--tni-fg-accent); }
/* One canonical step above the lead's own 1.45 — the lead paragraph is set at
   the body leading so the copy breathes. */
.tn-hero__lead { margin: 0; line-height: var(--tni-leading-body); }

.tn-hero__motif { margin: 0; }
.tn-hero__motif img { width: 100%; height: auto; }

/* Theme-aware hero motif: the same pure-CSS swap as the nav logo above
   (.tn-logo__light/.tn-logo__dark) — light art by default, reverse art inside
   any dark-theme subtree. Both <img> boxes are identical, so the swap cannot
   shift layout. */
.tn-motif__dark { display: none; }
[data-tni-theme="dark"] .tn-motif__light { display: none; }
[data-tni-theme="dark"] .tn-motif__dark { display: block; }

.tn-actions { display: flex; flex-wrap: wrap; align-items: stretch; gap: var(--tni-space-sm); }
.tn-actions > * { text-decoration: none; }


/* ---------------------------------------------------------------------------
   Partner strip (blueprint § 5.3)
   Light theme: logos render UNMODIFIED in full colour on the cream plate
   (vendor guideline) — fixed core-palette tokens from tokens.css, not the
   themeable semantic ones. Dark theme: the plate flips to the dark raised
   panel and the marks go monochrome cream via filter (their SVGs carry
   inline-style fills, which CSS `fill` cannot reach) — overrides below.
   ------------------------------------------------------------------------ */
.tn-partners__heading { display: block; margin-block-end: var(--tni-space-md); color: var(--tni-fg-accent); }

.tn-partners__plate {
  /* Cream — the page-surface token — so the strip reads as a subtle inset panel
     and no raw hex is needed.
     CORRECTED 2026-10-02: this was briefly set to #ffffff on the claim that
     "Proxmox's official lockup contains white elements that need a white ground".
     That claim was wrong: in proxmox.svg the values #ffffff and #666666 occur only
     inside the Inkscape <sodipodi:namedview pagecolor/bordercolor> EDITOR METADATA
     (lines 56-57); every actual artwork fill is #e57000 or #000000. Verified by
     grepping the file. No vendor logo here requires a white background. */
  background: var(--tni-cream);
  border: 1px solid var(--tni-stone);
  border-radius: var(--tni-radius-md);
  padding: var(--tni-space-lg);
  box-shadow: var(--tni-elevation);
}
@media (min-width: 768px) { .tn-partners__plate { padding: var(--tni-space-xl); } }

/* Dark theme: the plate becomes a dark inset panel — the raised surface plus
   the standard hairline — and the vendor marks KEEP their brand colours via a
   hue-preserving inversion: invert(1) flips the black wordmarks to white while
   hue-rotate(180deg) rotates the inverted hues back toward the originals
   (orange stays orange, teal stays teal). The SVGs carry inline-style fills,
   so CSS `fill` cannot recolour them; the filter also covers the alt-text
   fallback of a broken asset. Light theme stays full colour on cream. */
[data-tni-theme="dark"] .tn-partners__plate {
  background: var(--tni-bg-raised);
  border-color: var(--tni-line);
}
[data-tni-theme="dark"] .tn-partners__logo img { filter: invert(1) hue-rotate(180deg); }

.tn-partners__list {
  display: grid;
  grid-template-columns: 1fr;
  align-items: center;
  gap: var(--tni-space-lg) var(--tni-space-xl);
  margin: 0;
  padding: 0;
  list-style: none;
}

.tn-partners__item { display: flex; align-items: center; justify-content: center; min-width: 0; }

.tn-partners__logo {
  display: block;
  color: var(--tni-charcoal);            /* text fallback if an asset is absent */
}
/* Two vendor files ship no root width/height, but every <img> here carries explicit
   width/height attributes, so a fixed height keeps the mark stable before decode and
   each width follows that mark's own aspect — no letterboxing, no layout shift. */
.tn-partners__logo img {
  display: block;
  width: auto;
  height: var(--tn-partner-logo-h, 56px);
  max-width: 100%;
}

/* Below md: a single column, every mark at the container width. */
@media (max-width: 767px) {
  .tn-partners__logo { width: 100%; }
  .tn-partners__logo img { width: 100%; height: auto; }
}

/* From md up, two tiers. Proxmox gets its own featured row so its mandatory
   horizontal lockup renders at >= 440px (an 80px box gives ~480px for its 6:1
   ratio) without competing with the others; odoo, tp-link and opnsense sit
   beneath at one common optical height so they read as a set. */
@media (min-width: 768px) {
  .tn-partners__list { grid-template-columns: repeat(3, 1fr); }
  .tn-partners__logo { --tn-partner-logo-h: 56px; }
  .tn-partners__item--featured { grid-column: 1 / -1; order: -1; }
  .tn-partners__item--featured .tn-partners__logo { --tn-partner-logo-h: 80px; }
}
/* The caption is the section lead between heading and plate (type classes
   tni-body + tn-section__lead in the markup); only the gap to the plate is
   owned here. It sits on the themed page surface, so it takes semantic
   tokens. */
.tn-partners__caption { margin-block-end: var(--tni-space-xl); }


/* ---------------------------------------------------------------------------
   Cards, grids, chips (blueprint § 5.4)
   ------------------------------------------------------------------------ */
.tn-grid { display: grid; gap: var(--tni-space-xl); margin: 0; padding: 0; list-style: none; }
.tn-grid > * { min-width: 0; }

.tn-grid--services { grid-template-columns: 1fr; }
@media (min-width: 768px)  { .tn-grid--services { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .tn-grid--services { grid-template-columns: repeat(3, 1fr); } }
/* Cards fill the stretched grid row, so the CTA pushed down by
   `margin-block-start: auto` lands on one line across the row. */
.tn-grid--services .tn-card { block-size: 100%; }
.tn-grid--solutions .tn-card { block-size: 100%; }

.tn-grid--projects { grid-template-columns: 1fr; }
@media (min-width: 768px)  { .tn-grid--projects { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .tn-grid--projects { grid-template-columns: repeat(3, 1fr); } }

.tn-card {
  position: relative;                    /* anchor for the stretched link */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--tni-space-sm);
  padding: var(--tni-space-lg);
  background: var(--tni-bg-raised);
  border: 1px solid var(--tni-line);
  border-radius: var(--tni-radius-md);
  box-shadow: var(--tni-elevation);
}
.tn-card > * { max-width: 100%; }
.tn-card__icon { --tni-icon-size: 48px; color: var(--tni-fg); }

.tn-chip {
  display: inline-flex;
  align-items: center;
  padding: var(--tni-space-3xs) var(--tni-space-xs);
  border-radius: var(--tni-radius-full);
  background: var(--tni-bg-accent-soft);
  color: var(--tni-fg-accent);
}

.tn-card__title { margin: 0; }
.tn-card__summary { margin: 0; }
.tn-card__cta { margin-block-start: auto; padding-block-start: var(--tni-space-sm); }
.tn-card__cta::after { content: ""; position: absolute; inset: 0; border-radius: var(--tni-radius-md); }

.tn-card:hover { border-color: var(--tni-accent-graphic); }
.tn-card:hover .tn-card__title { color: var(--tni-fg-accent); }
.tn-card:has(.tn-card__cta:focus-visible) {
  outline: var(--tni-focus-ring-width) solid var(--tni-focus-ring);
  outline-offset: var(--tni-focus-ring-offset);
}

.tn-grid__foot { display: flex; flex-wrap: wrap; gap: var(--tni-space-sm); margin-block-start: var(--tni-space-xl); }
.tn-grid__foot > * { text-decoration: none; }


/* ---------------------------------------------------------------------------
   01–04 strip (blueprint § 5.5)
   ------------------------------------------------------------------------ */
.tn-diff .tn-section__head { max-width: var(--tni-measure-body); }
.tn-diff .tni-overline { color: var(--tni-fg-accent); }

.tn-diff__list {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--tni-space-xl);
  margin: 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 768px)  { .tn-diff__list { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .tn-diff__list { grid-template-columns: repeat(4, 1fr); } }

.tn-diff__item { display: flex; flex-direction: column; align-items: flex-start; gap: var(--tni-space-2xs); min-width: 0; }

.tn-diff__marker { display: flex; align-items: center; gap: var(--tni-space-xs); margin: 0 0 var(--tni-space-2xs); }
/* Decorative square of the numeral pattern (typography § 5) — graphic, never the
   only carrier of the ordering. */
.tn-diff__marker::before {
  content: "";
  flex: 0 0 auto;
  width: var(--tni-marker-square-size);
  height: var(--tni-marker-square-size);
  background: var(--tni-accent-graphic);
}
.tn-diff__number {
  color: var(--tni-fg-accent);
  line-height: 1;
  letter-spacing: var(--tni-tracking-marker);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
.tn-diff__title { margin: 0; }
.tn-diff__text { margin: 0; }
.tn-diff__proof { display: flex; flex-direction: column; align-items: flex-start; gap: var(--tni-space-2xs); }
.tn-diff__metric { color: var(--tni-fg-accent); }


/* ---------------------------------------------------------------------------
   Project grid (blueprint § 5.6)
   ------------------------------------------------------------------------ */
.tn-project {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--tni-space-sm);
  overflow: hidden;
  background: var(--tni-bg-raised);
  border: 1px solid var(--tni-line);
  border-radius: var(--tni-radius-md);
  box-shadow: var(--tni-elevation);
}
.tn-project__media {
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 10;
  margin: 0;
  padding: var(--tni-space-md);
  text-align: center;
  background: var(--tni-bg-sunken);
  border-block-end: 1px solid var(--tni-line);
}
.tn-project__body { display: flex; flex-direction: column; gap: var(--tni-space-2xs); padding: 0 var(--tni-space-lg) var(--tni-space-lg); }
.tn-project__title { margin: 0; }
.tn-project__link { color: inherit; text-decoration: none; }
.tn-project__link::after { content: ""; position: absolute; inset: 0; }
.tn-project__link:hover { color: var(--tni-fg-accent); }
.tn-project:hover { border-color: var(--tni-accent-graphic); }
.tn-project:has(.tn-project__link:focus-visible) {
  outline: var(--tni-focus-ring-width) solid var(--tni-focus-ring);
  outline-offset: var(--tni-focus-ring-offset);
}

.tn-tags { display: flex; flex-wrap: wrap; gap: var(--tni-space-2xs); margin: var(--tni-space-2xs) 0 0; padding: 0; list-style: none; }
.tn-tag {
  display: inline-flex;
  align-items: center;
  padding: 0 var(--tni-space-2xs);
  border: 1px solid var(--tni-line);
  border-radius: var(--tni-radius-full);
  color: var(--tni-fg-muted);
}


/* ---------------------------------------------------------------------------
   Founders block (blueprint § 5.8)
   ------------------------------------------------------------------------ */
.tn-founders {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--tni-space-xl);
  margin: 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 768px) { .tn-founders { grid-template-columns: repeat(2, 1fr); } }

.tn-founder { display: flex; flex-direction: column; gap: var(--tni-space-xs); min-width: 0; }
.tn-founder__portrait {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 5;
  margin: 0 0 var(--tni-space-2xs);
  padding: var(--tni-space-md);
  text-align: center;
  background: var(--tni-bg-sunken);
  border: 1px solid var(--tni-line);
  border-radius: var(--tni-radius-md);
}
.tn-founder__portrait::after {
  content: "";
  position: absolute;
  inset-block-start: var(--tni-space-xs);
  inset-inline-start: var(--tni-space-xs);
  width: var(--tni-marker-square-size);
  height: var(--tni-marker-square-size);
  background: var(--tni-accent-graphic);
}
.tn-founder__name { margin: 0; }
.tn-founder__role { color: var(--tni-fg-accent); }
.tn-founder__bio { margin: 0; }
.tn-founders__statement { margin-block-start: var(--tni-space-2xl); }


/* ---------------------------------------------------------------------------
   FAQ (blueprint § 5.10) — native <details>, no JavaScript
   ------------------------------------------------------------------------ */
.tn-faq { max-width: var(--tni-measure-body); }
.tn-faq__item { border-block-end: 1px solid var(--tni-line); }
.tn-faq__item:first-of-type { border-block-start: 1px solid var(--tni-line); }

.tn-faq__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--tni-space-md);
  min-height: var(--tni-target-comfort);
  padding-block: var(--tni-space-md);
  cursor: pointer;
  list-style: none;
}
.tn-faq__summary::-webkit-details-marker { display: none; }
.tn-faq__summary:hover .tn-faq__question { color: var(--tni-fg-accent); }

.tn-faq__marker {
  flex: 0 0 auto;
  width: var(--tni-marker-square-size);
  height: var(--tni-marker-square-size);
  background: var(--tni-fg);
  transition: transform var(--tni-dur-micro) var(--tni-ease-standard);
}
.tn-faq__item[open] .tn-faq__marker { transform: rotate(45deg); }
@media (prefers-reduced-motion: reduce) { .tn-faq__marker { transition: none; } }

.tn-faq__answer { margin: 0 0 var(--tni-space-md); }


/* ---------------------------------------------------------------------------
   CTA band (blueprint § 5.11)
   ------------------------------------------------------------------------ */
.tn-cta { display: flex; flex-direction: column; align-items: center; gap: var(--tni-space-md); text-align: center; }
.tn-cta__title { max-width: var(--tni-measure-lead); }
.tn-cta__sub { margin: 0; max-width: var(--tni-measure-lead); }
.tn-cta .tn-actions { justify-content: center; }

/* On a charcoal panel the canonical dark-accent ring (#2A2D25) is invisible, so
   the accent button takes the panel's own dark-theme ring (accent-400). */
.tni-theme[data-tni-theme="dark"] .tni-button-accent:focus-visible {
  outline-color: var(--tni-focus-ring);
}


/* ---------------------------------------------------------------------------
   Footer (blueprint § 5.12)
   ------------------------------------------------------------------------ */
.tn-footer { padding-block: var(--tni-space-2xl); }

.tn-footer__inner { display: grid; gap: var(--tni-space-xl); }
@media (min-width: 768px)  { .tn-footer__inner { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .tn-footer__inner { grid-template-columns: 3fr 2fr 2fr 3fr; } }

.tn-footer__brand { display: flex; flex-direction: column; align-items: flex-start; gap: var(--tni-space-md); min-width: 0; }
.tn-footer__mark { width: auto; height: 48px; }
.tn-footer__legalname { margin: 0; }
.tn-footer__col { display: flex; flex-direction: column; gap: var(--tni-space-2xs); min-width: 0; }
.tn-footer__coltitle { margin: 0 0 var(--tni-space-3xs); }
.tn-footer__list { display: flex; flex-direction: column; gap: var(--tni-space-2xs); margin: 0; padding: 0; list-style: none; }

/* Footer/nav lists are link blocks, so the underline appears on hover/focus only. */
.tn-footer__link { color: var(--tni-fg); text-decoration: none; }
.tn-footer__link:hover,
.tn-footer__link:focus-visible {
  color: var(--tni-fg-accent);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.18em;
}

.tn-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--tni-space-md);
  margin-block-start: var(--tni-space-xl);
  padding-block-start: var(--tni-space-md);
  border-block-start: 1px solid var(--tni-line);
}
/* Right cluster of the legal row: back-to-top + social on one baseline. */
.tn-footer__bottomlinks { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--tni-space-md); }
.tn-footer__legal { margin: 0; }


/* ---------------------------------------------------------------------------
   Root language chooser
   ------------------------------------------------------------------------ */
.tn-chooser {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--tni-space-md);
  max-width: var(--tni-measure-lead);
  margin-block: var(--tni-space-2xl);
}
.tn-chooser__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tni-space-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}
.tn-chooser__list > * { text-decoration: none; }


/* ---------------------------------------------------------------------------
   Global focus punctuation — brand/type-color.css § 7 already draws the ring;
   the site only widens the halo on the dark panels so the outline stays visible
   against a charcoal surface.
   ------------------------------------------------------------------------ */
.tni-theme[data-tni-theme="dark"] :where(a, button, summary, [tabindex]):focus-visible {
  outline-color: var(--tni-focus-ring);
  outline-offset: 2px;
}
