/* ═══════════════════════════════════════════════════
   Kendr — Brand token layer
   Load this FIRST, before any other Kendr stylesheet.

   Kendr is a neutral-infrastructure brand: ink is the stage, and saffron
   marks the one thing that matters right now. Everything here exists to
   keep that rule enforceable.

   THE SAFFRON RULE
   ────────────────
   Saffron (--k-saffron) is permitted in exactly five roles:

     1. the mark's core          — in every lockup
     2. the primary CTA          — the single next action on the page
     3. the active model indicator
     4. the citation marker      — the live one, not every link
     5. the busy state           — work is happening right now

   One saffron element per viewport. If two are competing, one of them
   isn't the point — demote it to --k-warm-grey or --k-paper.

   THE CORE IS EXEMPT FROM THAT BUDGET.
   Slot 1 does not count against the other four. The core is the brand's
   fixed centre — structural, always present, identical in every lockup —
   not a signal competing for attention. Many rings, one core. So a sticky
   nav lockup and a saffron primary CTA may share a viewport; what may NOT
   share one is a CTA and an active model indicator, or a live citation and
   a busy state. Budget slots 2-5 against each other.

   Consequences baked into this system:
     · The core is saffron in EVERY lockup. Reach for .kendr-mark--mono only
       when the mark is drawn inside an illustration or a mock product
       screenshot, where it is scenery rather than the signature.
     · Citation markers are warm grey at rest and saffron on hover/current.
       Only one can be current, so the rule holds automatically.
     · The busy state OUTRANKS the active model indicator. While a run is in
       flight, the model dot yields to warm grey. See .is-busy below.
     · Saffron and critical never appear in the same component.
   ═══════════════════════════════════════════════════ */

/* ═══ The face ═══════════════════════════════════════
   Space Grotesk SemiBold, self-hosted. "No substitutes" is a brand rule,
   so the face must ship with the site rather than be hoped for on the
   client. SIL Open Font License 1.1 — see assets/brand/fonts/OFL.txt.

   font-display: block (not swap) — the wordmark is the logo, and a flash
   of it set in the system sans IS the substitute the rule forbids. A brief
   invisible period is the correct trade for a 13 KB file. */
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/assets/brand/fonts/space-grotesk-600-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/assets/brand/fonts/space-grotesk-600-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* ── Core ─────────────────────────────────────── */
  --k-ink: #151412;          /* the stage — a warm near-black, not blue-black */
  --k-saffron: #e2712a;      /* the accent. Read the rule above before using. */
  --k-paper: #faf8f4;
  --k-warm-grey: #8a8378;

  /* ── Supporting system colours ───────────────────
     So saffron never has to mean two things. */
  --k-verified: #6f8f63;     /* citation checked, run succeeded */
  --k-critical: #b5463c;     /* unsupported claim, blocked action */
  --k-raise: #3a3630;        /* cards, wells, hover states on ink */
  --k-paper-wash: #f3efe8;   /* docs, print, exported reports */

  /* ── Ink surface ramp ────────────────────────── */
  --k-ink-deep: #11100f;     /* rails, sidebars — below the stage */
  --k-ink-surface: #1a1917;  /* panels sitting on the stage */
  --k-ink-raised: #1f1d1a;   /* the layer above a panel */

  /* ── Type on ink ─────────────────────────────── */
  --k-text-strong: #f5f5f4;
  --k-text: #d6d3d1;
  --k-text-muted: #a8a29e;
  --k-text-subtle: #78716c;
  --k-text-dim: #57534e;

  /* ── Lines ───────────────────────────────────── */
  --k-border: rgba(255, 255, 255, 0.08);
  --k-border-strong: rgba(255, 255, 255, 0.14);

  /* ── Saffron at strength ─────────────────────────
     Tints for wells and hairlines. These are still saffron: a saffron-
     tinted surface counts against the one-per-viewport budget. */
  --k-saffron-strong: #f08c48; /* hover only — never a resting state */
  --k-saffron-line: rgba(226, 113, 42, 0.32);
  --k-saffron-wash: rgba(226, 113, 42, 0.09);
  --k-saffron-glow: rgba(226, 113, 42, 0.18);

  /* Verified / critical tints */
  --k-verified-line: rgba(111, 143, 99, 0.30);
  --k-verified-wash: rgba(111, 143, 99, 0.09);
  --k-critical-line: rgba(181, 70, 60, 0.32);
  --k-critical-wash: rgba(181, 70, 60, 0.10);

  /* ── Text that sits ON saffron ───────────────────
     Ink, never white. Saffron on white fails contrast; saffron on ink
     is the lockup the mark already uses. */
  --k-on-saffron: #151412;

  /* ── Motion ──────────────────────────────────── */
  --k-settle: cubic-bezier(0.2, 0.8, 0.2, 1);

  /* ── Wordmark ────────────────────────────────────
     Space Grotesk SemiBold (600). No substitutes, no synthetic bold,
     no italic. The face MUST be self-hosted — see the @font-face block
     below. The system fallbacks exist only so the page is legible if a
     font file fails to load; they are not an approved substitute. */
  --k-wordmark: "Space Grotesk", ui-sans-serif, system-ui, -apple-system,
                BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  /* Lockup geometry (see .kendr-lockup):
       mark height = 1.15 x wordmark size
       gap         = 0.30 x mark height
       the mark is optically centred on the WORDMARK'S X-HEIGHT, not its
       baseline, so --k-x-height must match the face actually in use.
       Space Grotesk: xHeight 500 / unitsPerEm 1000 (measured from the
       shipped face, not assumed). */
  --k-mark-scale: 1.15;
  --k-lockup-gap: 0.30;
  --k-x-height: 0.5;

  /* Tracking is -4% at all sizes, easing to -2% below 20px so the
     letters do not collide. Set --k-wordmark-tracking to -0.02em on any
     lockup rendered under 20px (or just use .kendr-lockup--sm). */
  --k-wordmark-tracking: -0.04em;
}

/* ═══ The wordmark ═══════════════════════════════════
   ONE RULE ABOVE ALL OTHERS: the logo is lowercase, the word is not.
   The wordmark is always "kendr". In running prose it stays "Kendr".

   Never: all-caps. Never: positive letter-spacing. Never: a capital K.
   Never: the text or mono face. Never: italic. Never: saffron — the
   word is paper on ink or ink on paper, and only the core is saffron.
   The domain is never part of the wordmark; set it on a separate line. */
.kendr-wordmark {
  font-family: var(--k-wordmark);
  font-weight: 600;
  font-style: normal;
  /* Block the browser from faking a bold or an italic if the real
     SemiBold is missing — a synthesised face is a substitute. */
  font-synthesis: none;
  -webkit-font-synthesis: none;
  letter-spacing: var(--k-wordmark-tracking);
  text-transform: lowercase;
  color: var(--k-text-strong);
}

/* On paper, the word is ink. */
.kendr-wordmark--ink { color: var(--k-ink); }

/* ═══ The lockup ═════════════════════════════════════
   Size the lockup by setting font-size on .kendr-lockup; the mark and the
   gap derive from it, so the ratio holds at every size.

   Clear space around the whole lockup equals the inner ring radius
   (25% of mark width) on all sides. */
.kendr-lockup {
  display: inline-flex;
  align-items: baseline;
  gap: calc(var(--k-mark-scale) * var(--k-lockup-gap) * 1em);
  line-height: 1;
}

.kendr-lockup > .kendr-mark {
  width: calc(var(--k-mark-scale) * 1em);
  height: calc(var(--k-mark-scale) * 1em);
  /* Baseline alignment puts the mark's bottom edge on the text baseline,
     which centres it on the baseline rather than on the x-height. Drop it
     by the difference so the core sits level with the middle of "kendr". */
  transform: translateY(calc((var(--k-mark-scale) - var(--k-x-height)) / 2 * 1em));
}

/* Below 20px the tracking eases to -2%. */
.kendr-lockup--sm { --k-wordmark-tracking: -0.02em; }

/* ═══ MOTION ═════════════════════════════════════════
   One mark, five states. Each one MEANS something — that is the whole
   value of the set, so never play one just because it looks alive.

     settle    PRIMARY. App launch, full-page loading, task complete.
               Overshoots, then locks.        2.8s  cubic-bezier(.16,1,.3,1)
     thinking  Busy / indeterminate. Replaces every generic spinner in
               the product.                   3.2s + 2.1s  linear
     routing   ONLY while Kendr is choosing a model. Playing it anywhere
               else destroys its meaning.     2.4s  linear
     reveal    Entrance: splash, site hero, first paint. Play ONCE —
               never loop it in product UI.   3.6s  cubic-bezier(.2,.8,.2,1)
     listening Idle / input. Voice capture, agent standing by.
                                              2.2s  ease-in-out

   RULES (from the motion kit README):
     · Never run two of these on screen at once.
     · Never speed past 1.5x or slow past 0.7x — the timing is the mark.
     · Saffron stays saffron. The only recolour permitted is stroke
       white <-> ink (.kendr-motion--ink).
     · Below 24px use the one-ring variant (.kendr-motion--sm); the inner
       ring turns to mush.

   PROVENANCE: the kit's SVGs carry no <style> block, so they are static
   when loaded via <img> and animate only where a host page defines the
   keyframes. k-settle and k-route-in below are verbatim from
   loading-screen/kendr-loading-screen.html. The other six (k-spin,
   k-spin-rev, k-route, k-reveal, k-ping, k-pulse) are referenced by the
   kit's SVGs but defined nowhere in it; they are authored here to the
   durations, easings and descriptions in the kit README. If the design
   source later ships its own, replace these rather than keeping both. */

@keyframes k-settle {
  0%   { transform: rotate(0deg); }
  62%  { transform: rotate(348deg); }
  80%  { transform: rotate(372deg); }   /* the overshoot */
  100% { transform: rotate(360deg); }   /* ...then it locks */
}
@keyframes k-route-in { to { stroke-dashoffset: 157; } }

/* Thinking — counter-rotating rings, no beginning and no end. */
@keyframes k-spin     { to { transform: rotate(360deg); } }
@keyframes k-spin-rev { to { transform: rotate(-360deg); } }

/* Routing — a saffron arc sweeps the outer ring once per cycle. */
@keyframes k-route { to { transform: rotate(360deg); } }

/* Reveal — core first, rings outward; the per-ring delays do the
   staggering, so the keyframe itself is one scale-and-fade in. */
@keyframes k-reveal {
  0%   { opacity: 0; transform: scale(0.62); }
  38%  { opacity: 1; transform: scale(1); }
  100% { opacity: 1; transform: scale(1); }
}

/* Listening — a ring pings outward while the core breathes. */
@keyframes k-ping {
  0%   { opacity: 0.55; transform: scale(0.52); }
  70%  { opacity: 0; transform: scale(1); }
  100% { opacity: 0; transform: scale(1); }
}
@keyframes k-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.72; transform: scale(0.86); }
}

.kendr-motion {
  display: inline-grid;
  flex: 0 0 auto;
  place-items: center;
  width: 1em;
  height: 1em;
  color: var(--k-paper);
}
.kendr-motion svg { display: block; width: 100%; height: 100%; overflow: visible; }
.kendr-motion--ink { color: var(--k-ink); }

/* Every animated part turns about the mark's centre, not the box origin. */
.kendr-motion .k-part { transform-box: fill-box; transform-origin: center; }

.kendr-motion[data-state="settle"]    .k-outer { animation: k-settle 2.8s cubic-bezier(0.16, 1, 0.3, 1) infinite; }
.kendr-motion[data-state="settle"]    .k-inner { animation: k-route-in 2.8s cubic-bezier(0.16, 1, 0.3, 1) infinite; }
.kendr-motion[data-state="thinking"]  .k-outer { animation: k-spin 3.2s linear infinite; }
.kendr-motion[data-state="thinking"]  .k-inner { animation: k-spin-rev 2.1s linear infinite; }
.kendr-motion[data-state="routing"]   .k-arc   { animation: k-route 2.4s linear infinite; }
.kendr-motion[data-state="reveal"]    .k-outer { animation: k-reveal 3.6s cubic-bezier(0.2, 0.8, 0.2, 1) both; animation-delay: 0.3s; }
.kendr-motion[data-state="reveal"]    .k-inner { animation: k-reveal 3.6s cubic-bezier(0.2, 0.8, 0.2, 1) both; animation-delay: 0.15s; }
.kendr-motion[data-state="reveal"]    .k-core  { animation: k-reveal 3.6s cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.kendr-motion[data-state="listening"] .k-ping  { animation: k-ping 2.2s ease-out infinite; }
.kendr-motion[data-state="listening"] .k-core  { animation: k-pulse 2.2s ease-in-out infinite; }

/* Settle resolves: when the work finishes, stop on the locked frame
   rather than cutting mid-rotation. */
.kendr-motion[data-state="settle"].is-resolved .k-outer,
.kendr-motion[data-state="settle"].is-resolved .k-inner {
  animation-iteration-count: 1;
  animation-fill-mode: forwards;
}

@media (prefers-reduced-motion: reduce) {
  .kendr-motion .k-part { animation: none !important; }
  /* Reveal fades in from 0, so without the animation the mark must be
     explicitly visible rather than stuck invisible. */
  .kendr-motion[data-state="reveal"] .k-part { opacity: 1; transform: none; }
  .kendr-motion[data-state="listening"] .k-ping { opacity: 0; }
}

/* ═══ The mark ═══════════════════════════════════════
   Concentric rings around a fixed core: many rings, one centre.
   Sized by font-size or an explicit width/height on .kendr-mark. */

.kendr-mark {
  display: inline-grid;
  flex: 0 0 auto;
  place-items: center;
  width: 1em;
  height: 1em;
  color: var(--k-paper);      /* rings inherit currentColor */
}

.kendr-mark svg {
  display: block;
  width: 100%;
  height: 100%;
}

.kendr-mark .kendr-mark-ring {
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
}

/* Slot 1 — the mark's core. Only where the mark is the subject. */
.kendr-mark .kendr-mark-core { fill: var(--k-saffron); }

/* Persistent chrome: the mark is present, but it is not the point. */
.kendr-mark--mono .kendr-mark-core { fill: currentColor; }

/* The Settle: rings ease into alignment once, on load. Never a loop —
   a permanently spinning mark reads as "busy", which is slot 5's job. */
@keyframes kendr-settle {
  from { transform: rotate(-24deg); opacity: 0; }
  to   { transform: rotate(0deg); opacity: 1; }
}

.kendr-mark--settle .kendr-mark-ring {
  transform-origin: 50% 50%;
  animation: kendr-settle 620ms var(--k-settle) both;
}
.kendr-mark--settle .kendr-mark-ring:nth-of-type(2) { animation-delay: 90ms; }

@media (prefers-reduced-motion: reduce) {
  .kendr-mark--settle .kendr-mark-ring { animation: none; }
}

/* ═══ Slot 2 — the primary CTA ═══════════════════════
   The single next action. One per viewport, by definition. */

.k-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--k-saffron);
  background: var(--k-saffron);
  color: var(--k-on-saffron);
  font-weight: 600;
  transition: background 150ms var(--k-settle), border-color 150ms var(--k-settle);
}

.k-cta:hover {
  border-color: var(--k-saffron-strong);
  background: var(--k-saffron-strong);
}

/* A secondary action next to the CTA must never be saffron. */
.k-cta-secondary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--k-border-strong);
  background: transparent;
  color: var(--k-text);
}
.k-cta-secondary:hover { border-color: var(--k-warm-grey); color: var(--k-text-strong); }

/* ═══ Slot 3 — the active model indicator ═══════════ */

.k-model-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  flex: 0 0 6px;
  border-radius: 50%;
  background: var(--k-saffron);
}

/* ═══ Slot 4 — the citation marker ═══════════════════
   Warm grey at rest; saffron for the live one. */

.k-cite {
  border-bottom: 1px solid var(--k-border-strong);
  color: var(--k-warm-grey);
  text-decoration: none;
  transition: color 120ms var(--k-settle), border-color 120ms var(--k-settle);
}

.k-cite:hover,
.k-cite:focus-visible,
.k-cite.is-current {
  border-color: var(--k-saffron-line);
  color: var(--k-saffron);
}

/* A checked citation is verified green, not saffron — saffron means
   "look here now", green means "this held up". */
.k-cite.is-verified { color: var(--k-verified); border-color: var(--k-verified-line); }

/* ═══ Slot 5 — the busy state ════════════════════════ */

@keyframes k-busy-pulse { 50% { opacity: 0.4; } }

.k-busy { color: var(--k-saffron); }
.k-busy > i { background: var(--k-saffron); animation: k-busy-pulse 1s ease-in-out infinite; }

/* Arbitration: while something is genuinely in flight, the busy state is
   the point and the active model indicator steps back. Put .is-busy on the
   surface that contains both. */
.is-busy .k-model-dot { background: var(--k-warm-grey); }

@media (prefers-reduced-motion: reduce) {
  .k-busy > i { animation: none; }
}

/* ═══ Status colours (not saffron) ═══════════════════ */

.k-verified { color: var(--k-verified); }
.k-critical { color: var(--k-critical); }

/* ═══ Focus ══════════════════════════════════════════
   Saffron focus rings are exempt from the one-per-viewport budget:
   focus is transient and there is only ever one focused element. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--k-saffron);
  outline-offset: 2px;
}

::selection { background: var(--k-saffron-glow); color: var(--k-text-strong); }
