/* The site's visual language at every width. Desktop and the narrow layout
   differ in arrangement only (desktop-layout.css, the media queries in
   index.html); surfaces, weights, cards and states are the same here.
   Loaded after both, so these rules win over the older per-component glass. */

/* Stage: solid ink, no floor glow. The film grain stays. */
:root {
  --bg-page: var(--ink-0);
  --bg-gradient: linear-gradient(var(--ink-0), var(--ink-0));
}

/* One opaque surface tone, including interaction states. Borders and text
   carry affordance; translucent fills and blur would lift each nested layer. */
.loader :is(
  .case-card, .case-card-body, .case-preview-panel,
  .composer, .user-bubble, .contact-chip, .send-button, .followup,
  .case-preview-download, .case-preview-close
),
.cite-popover {
  background: var(--ink-1);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
}

.loader :is(.case-card, .contact-chip, .send-button):is(:hover, :active, .is-active),
.loader:not(.desktop-layout) .followup:is(:hover, :active) {
  border-color: var(--line-strong);
  background: var(--ink-1);
  box-shadow: none;
}

.loader .composer:focus-within {
  border-color: rgba(var(--white-rgb), 0.3);
}

.loader :is(
  .case-card, .followup, .contact-chip, .send-button,
  .case-preview-download, .case-preview-close
):focus-visible {
  outline: 1px solid rgba(var(--paper-rgb), 0.6);
  outline-offset: 2px;
  box-shadow: none;
}

/* Composer: set into the chat panel by fill alone, with no border and no
   inner shadow. On desktop it takes the stage's darker ink; the send button
   carries the panel's surface. Narrow layouts have no panel, so the composer
   keeps the surface tone and loses the border there too. */
.loader .composer,
.loader .composer:focus-within {
  border-color: transparent;
  box-shadow: none;
}

/* Send button: one style at every width. The stage tone with a hairline:
   white with a border in light, ink with a border in dark. */
.loader .composer .send-button,
[data-theme="light"] .loader .composer .send-button {
  border: 1px solid var(--line);
  background: var(--ink-0);
}
.loader .composer .send-button:focus-visible {
  border-color: var(--line-strong);
}
@media (hover: hover) and (pointer: fine) {
  .loader .composer .send-button:hover {
    border-color: var(--line-strong);
    background: var(--ink-0);
  }
}

.loader.desktop-layout .composer {
  background: var(--ink-0);
}

/* In light the composer takes the grey surface on the white stage. */
[data-theme="light"] .loader.desktop-layout .composer {
  background: var(--ink-1);
}

/* On a phone the composer floats over the stage and the scrolling cards,
   so it takes the raised tone rather than blending into the surfaces. */
.loader:not(.desktop-layout) .composer {
  background: var(--ink-2);
}

/* A ghost hairline gives the floating pill an edge in both themes, the
   same in focus. */
.loader:not(.desktop-layout) .composer,
.loader:not(.desktop-layout) .composer:focus-within {
  border-color: var(--line);
}

/* Case cards: no border at rest (the fill sets them apart); hover, focus
   and the open case bring the --line-strong border in. No arrow, one
   caption style. */
.loader .case-card {
  border: 1px solid transparent;
}

.loader .case-card::after {
  content: none;
}

/* In light the cards match the chat panel: white, lifted by the same faint
   shadow, in every state. */
[data-theme="light"] .loader :is(.case-card, .case-card-body) {
  background: var(--ink-0);
}
[data-theme="light"] .loader .case-card {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 8px 32px rgba(0, 0, 0, 0.06);
}

/* In dark the home-grid cards sit straight on the stage, where --ink-1 all
   but vanishes: they take the selected tab's grey (--fill-strong) in every
   state, at every width. The caption shares the card's fill, not a second
   layer of it. */
:root:not([data-theme="light"]) .loader .home-work-grid .case-card,
:root:not([data-theme="light"]) .loader .home-work-grid .case-card:is(:hover, :active, .is-active) {
  background: var(--ink-card);
}
:root:not([data-theme="light"]) .loader .home-work-grid .case-card-body {
  background: transparent;
}

.loader .case-card-body {
  padding: var(--space-3);
}

.loader .case-card-title {
  color: var(--text-body);
  font-size: 15px;
  font-weight: var(--weight-regular);
  line-height: 21px;
  letter-spacing: 0;
}

/* Type: regular weight across the chrome. Sizes stay per layout; phone
   inputs keep 16px so iOS does not zoom on focus. */
.loader :is(.agent-message, .user-message, .followup, .contact-chip, .prompt-input, .send-button) {
  font-weight: var(--weight-regular);
  letter-spacing: 0;
}

.loader .home-work-label {
  color: var(--text-faint);
  font: var(--weight-strong) var(--type-label) / var(--type-label-lh) var(--font-sans);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}

/* Chips: the arrow badge goes; the icon stays as a plain glyph. */
.loader .followup-arrow {
  background: transparent;
}

/* The request bubble's tail uses the small radius. */
.loader .user-bubble {
  border-color: var(--line);
  border-bottom-right-radius: var(--radius-sm);
}

/* Light cursor (light-cursor.js): one lit point, nothing around it. Paper
   throughout; over anything clickable the point swells, still round, with a
   white glow. A soft dark shadow, not an outline, keeps it visible over bright
   case artwork. */
.light-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 2147483646;
  width: 0;
  height: 0;
  pointer-events: none;
  opacity: 0;
  will-change: transform;
  transition: opacity var(--duration-fast) var(--ease-out);
}

.light-cursor.is-visible {
  opacity: 1;
}

.light-cursor-point {
  position: absolute;
  top: -4px;
  left: -4px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--paper);
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.45);
  transition:
    transform 240ms var(--ease-out),
    background-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}

.light-cursor.is-hovering .light-cursor-point {
  background: var(--paper);
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.35), 0 0 8px rgba(var(--paper-rgb), 0.5), 0 0 22px rgba(var(--paper-rgb), 0.18);
  transform: scale(1.75);
}

.light-cursor.is-pressed .light-cursor-point {
  transform: scale(0.7);
  transition-duration: 90ms;
}

.light-cursor.is-hovering.is-pressed .light-cursor-point {
  transform: scale(1.3);
}

@media (any-pointer: fine) and (any-hover: hover) and (prefers-reduced-motion: no-preference) {
  html.has-light-cursor,
  html.has-light-cursor * {
    cursor: none !important;
  }
}


/* While one card is hovered, the others in the same grid drop to black and
   white and dim, so the hovered one keeps the only colour. */
.loader .case-preview-art {
  transition: filter var(--duration-base) var(--ease-out);
}

/* Only with a real mouse: on touch a tap leaves :hover stuck on the card,
   so the others stayed dimmed after the finger lifted. */
@media (hover: hover) and (pointer: fine) {
  .loader :is(.home-work-grid, .case-preview-rail):has(.case-card:is(:hover, :focus-visible))
    .case-card:not(:hover, :focus-visible) .case-preview-art {
    filter: grayscale(1) brightness(0.72);
  }
}

@media (prefers-reduced-motion: reduce) {
  .loader .case-preview-art { transition: none; }
}

/* Theme toggle: the icon shows the theme it switches to. In the desktop
   header it sits with the contact icons; narrow layouts get a floating one. */
.theme-toggle .theme-toggle-to-dark { display: none; }
[data-theme="light"] .theme-toggle .theme-toggle-to-light { display: none; }
[data-theme="light"] .theme-toggle .theme-toggle-to-dark { display: inline-flex; }

.theme-toggle-floating {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + 12px);
  right: 12px;
  z-index: 30;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-full);
  background: var(--ink-1);
  color: var(--text-soft);
  cursor: pointer;
}
.theme-toggle-floating .contact-chip-label { display: none; }
.theme-toggle-floating .contact-chip-icon { width: 20px; height: 20px; }
:root:not([data-theme="light"]) .theme-toggle-floating .theme-toggle-to-light,
[data-theme="light"] .theme-toggle-floating .theme-toggle-to-dark { display: inline-flex; }
.theme-toggle-floating svg { width: 20px; height: 20px; }
.theme-toggle-floating:hover { color: var(--text-strong); border-color: var(--line-strong); }
.theme-toggle-floating:focus-visible { outline: 1px solid rgba(var(--paper-rgb), 0.6); outline-offset: 2px; }
@media (min-width: 1024px) {
  .theme-toggle-floating { display: none; }
}

/* Language picker: a globe button (wherever the theme toggle sits: the
   desktop header row, or floating beside it on narrow layouts) opening the
   site's own menu, an ink popover. */
.lang-toggle { cursor: pointer; }
.lang-toggle:focus-visible { outline: 1px solid rgba(var(--paper-rgb), 0.6); outline-offset: 2px; }
.lang-menu {
  position: fixed;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 168px;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--ink-card);
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 140ms ease, transform 140ms ease;
}
.lang-menu.is-open { opacity: 1; transform: none; }
/* An invisible bridge over the 8px gap to the button, so a hover-opened
   menu stays up while the pointer crosses it. */
.lang-menu::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 10px;
}
.lang-menu-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  height: 36px;
  padding: 0 10px 0 12px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-soft);
  font: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}
/* On the card surface a hovered row takes --fill and the current language
   --fill-strong, so both read in either theme. */
.lang-menu { --menu-hover: var(--fill); --menu-selected: var(--fill-strong); }
.lang-menu-item:hover,
.lang-menu-item:focus-visible { background: var(--menu-hover); color: var(--text-strong); outline: none; }
.lang-menu-item[aria-checked="true"] { background: var(--menu-selected); border-color: var(--line); color: var(--text-strong); }
.lang-menu-check { display: inline-flex; width: 16px; height: 16px; opacity: 0; }
.lang-menu-check svg { width: 16px; height: 16px; }
.lang-menu-item[aria-checked="true"] .lang-menu-check { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .lang-menu { transition: none; }
}
/* While the page reloads into another language. */
.site-shell,
.lang-offer { transition: opacity 180ms ease; }
.is-switching-lang :is(.site-shell, .lang-offer, .theme-toggle-floating, .lang-toggle-floating) {
  opacity: 0.35;
  pointer-events: none;
}
.is-switching-lang { cursor: progress; }
.lang-toggle-floating {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + 12px);
  right: 60px;
  z-index: 30;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-full);
  background: var(--ink-1);
  color: var(--text-soft);
  cursor: pointer;
}
.lang-toggle-floating .contact-chip-label { display: none; }
.lang-toggle-floating .contact-chip-icon,
.lang-toggle-floating svg { width: 20px; height: 20px; }
.lang-toggle-floating:hover { color: var(--text-strong); border-color: var(--line-strong); }
@media (min-width: 1024px) {
  .lang-toggle-floating { display: none; }
}
body:has(.loader.has-preview) :is(.lang-toggle-floating, .lang-menu) { display: none; }

/* The one-time offer of the device's language, written in that language.
   Top left, level with the floating toggles on narrow layouts; it fades in
   after the intro and leaves for good once answered either way. */
.lang-offer {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + 12px);
  left: 12px;
  z-index: 30;
  display: flex;
  align-items: center;
  max-width: calc(100vw - 124px);
  height: 40px;
  padding: 0 4px 0 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-full);
  background: var(--ink-1);
  color: var(--text-soft);
  font-size: 13px;
  line-height: 1;
  opacity: 0;
  transform: translateY(-4px);
  pointer-events: none;
  transition: opacity var(--duration-base) var(--ease-out), transform var(--duration-base) var(--ease-out);
}
.lang-offer.is-shown { opacity: 1; transform: none; pointer-events: auto; }
.lang-offer-action,
.lang-offer-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 38px;
  border: 0;
  border-radius: var(--radius-full);
  background: transparent;
  font: inherit;
  cursor: pointer;
}
.lang-offer-action {
  min-width: 0;
  overflow: hidden;
  padding: 0 6px 0 16px;
  color: var(--text-strong);
  font-weight: var(--weight-medium);
  white-space: nowrap;
  text-overflow: ellipsis;
}
.lang-offer-close { flex: none; width: 32px; color: var(--text-soft); }
.lang-offer-close svg { width: 14px; height: 14px; }
.lang-offer-close:hover { color: var(--text-strong); }
:is(.lang-offer-action, .lang-offer-close):focus-visible { outline: 1px solid rgba(var(--paper-rgb), 0.6); outline-offset: -2px; }
body:has(.loader.has-preview) .lang-offer { display: none; }
@media (prefers-reduced-motion: reduce) {
  .lang-offer { transition: none; }
}

/* In an open case or CV the toolbar carries the toggle next to close. */
.case-preview-theme {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--text-soft);
  cursor: pointer;
}
.case-preview-theme span { display: inline-flex; }
.case-preview-theme svg { width: 18px; height: 18px; }
.case-preview-theme:hover { color: var(--text-strong); }
.case-preview-theme:focus-visible { outline: 1px solid rgba(var(--paper-rgb), 0.6); outline-offset: 2px; }
/* While a preview covers the screen on narrow layouts, the floating toggle
   gives way to the toolbar one. */
body:has(.loader.has-preview) .theme-toggle-floating { display: none; }

/* Three surface tones: the stage (--ink-0), the chat panel and page cards
   (--ink-1), and on top of the chat the raised tone (--ink-2): the request
   bubbles, the composer, and the cards the chat puts in the thread (case
   rail, CV and contact cards). Cards outside the chat, on the home grid,
   stay on --ink-1. */
.loader .user-bubble,
.loader .composer,
.loader.desktop-layout .composer,
[data-theme="light"] .loader.desktop-layout .composer,
.loader .thread :is(.case-card, .case-card-body, .contact-chip),
.loader .thread :is(.case-card, .contact-chip):is(:hover, :active, .is-active),
[data-theme="light"] .loader .thread :is(.case-card, .case-card-body) {
  background: var(--ink-2);
}

[data-theme="light"] .loader .thread .case-card {
  box-shadow: none;
}

/* On the raised tone the fill alone sets these apart: no outline on the
   request bubble or on the case cards in the thread. */
.loader .user-bubble,
.loader .thread .case-card,
.loader .thread .case-card:is(:hover, :active, .is-active) {
  border-color: transparent;
}

/* Phone, dark theme: with no chat panel, the cards in the thread sit on the
   second tone like the follow-up chips; bubbles and the composer keep the
   raised one. */
:root:not([data-theme="light"]) .loader:not(.desktop-layout) .thread :is(.case-card, .case-card-body, .contact-chip),
:root:not([data-theme="light"]) .loader:not(.desktop-layout) .thread :is(.case-card, .contact-chip):is(:hover, :active, .is-active) {
  background: var(--ink-1);
}

/* The desktop header's folded links: the language menu's rows, each an icon
   and its label (the theme row shows the icon of the theme it switches to). */
.showcase-more { cursor: pointer; }

/* Link pill: the one text pill in the header rows at every width (Contacts,
   CV, and the tablet's top-right pair). Text only, no icons. Doubled class so it wins over the generic chip. */
.link-pill.link-pill {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 36px;
  padding: 0 14px;
  border: 1px solid transparent;
  border-radius: var(--radius-full);
  background: var(--ink-card);
  color: var(--text-strong);
  font: inherit;
  font-size: 14px;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
/* In light the pill is white on the white stage: a hairline gives it the
   edge the cards get from their shadow. */
[data-theme="light"] .link-pill.link-pill { border-color: var(--line); }
/* Hover, focus and an open menu: the same --fill-strong lift as the globe and
   theme buttons, laid over the card surface so it stays opaque. */
.link-pill.link-pill:is(:focus-visible, [aria-expanded="true"]) { border-color: var(--line-strong); background: linear-gradient(var(--fill-strong), var(--fill-strong)), var(--ink-card); }
.link-pill.link-pill:focus-visible { outline: 1px solid rgba(var(--paper-rgb), 0.6); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .link-pill.link-pill:hover { border-color: var(--line-strong); background: linear-gradient(var(--fill-strong), var(--fill-strong)), var(--ink-card); }
}
.link-pill .showcase-chevron,
.link-pill .showcase-chevron svg { display: block; width: 14px; height: 14px; color: var(--text-soft); }
.showcase-more-menu .contact-chip {
  box-sizing: border-box;
  min-height: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  height: 36px;
  padding: 0 12px 0 10px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-soft);
  font: inherit;
  font-size: 14px;
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.showcase-more-menu .contact-chip:is(:hover, :focus-visible) { background: var(--menu-hover); color: var(--text-strong); outline: none; }
.showcase-more-menu .contact-chip-icon { width: 18px; height: 18px; }
.showcase-more-menu .contact-chip-icon svg { width: 18px; height: 18px; }
.showcase-more-menu .contact-chip-label { display: inline; }

/* Tablet widths: language and theme move to the top-left corner; Contacts and
   Download CV take the top right as text pills of the same height. */
.tablet-links { display: none; }
@media (min-width: 761px) and (max-width: 1023px) {
  .lang-toggle-floating { left: 12px; right: auto; }
  .theme-toggle-floating { left: 60px; right: auto; }
  .tablet-links {
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) + 12px);
    right: 12px;
    z-index: 30;
    display: flex;
    gap: 8px;
  }
  body:has(.loader.has-preview) .tablet-links { display: none; }
}

/* Contacts bottom sheet (tablet Contacts pill): an ink sheet rising from the
   bottom edge, square at the bottom, one row per link. */
.contact-sheet-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(var(--ink-0-rgb), 0.6);
  opacity: 0;
  transition: opacity 200ms ease;
}
.contact-sheet-backdrop.is-open { opacity: 1; }
.contact-sheet {
  position: fixed;
  left: 50%;
  bottom: 0;
  z-index: 51;
  width: min(480px, 100%);
  padding: 10px 12px calc(env(safe-area-inset-bottom, 0px) + 16px);
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  background: var(--ink-card);
  outline: none;
  transform: translate(-50%, 100%);
  transition: transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.contact-sheet.is-open { transform: translate(-50%, 0); }
.contact-sheet-backdrop[hidden],
.contact-sheet[hidden] { display: none; }
.contact-sheet-grip {
  display: block;
  width: 36px;
  height: 4px;
  margin: 0 auto 14px;
  border-radius: var(--radius-full);
  background: var(--line-strong);
}
.contact-sheet-title {
  margin: 0 0 8px;
  padding: 0 12px;
  color: var(--text-faint);
  font-size: 13px;
}
.contact-sheet-list { display: flex; flex-direction: column; gap: 2px; }
.contact-sheet-row {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 52px;
  padding: 0 12px;
  border-radius: var(--radius-sm);
  color: var(--text-body);
  font-size: 16px;
  text-decoration: none;
}
.contact-sheet-row:is(:hover, :focus-visible) { background: var(--fill); color: var(--text-strong); outline: none; }
.contact-sheet-icon,
.contact-sheet-icon svg { display: block; width: 20px; height: 20px; color: var(--text-soft); }
@media (prefers-reduced-motion: reduce) {
  .contact-sheet, .contact-sheet-backdrop { transition: none; }
}

/* Desktop case and CV viewer: like the chat, no panel. The document sits on
   the stage right of the chat's divider; the toolbar keeps its hairline. */
.loader.desktop-layout .case-preview-panel {
  border-color: transparent;
  background: transparent;
}

/* Sphere tags over a card's cover, top right. The one glass surface in the
   system: they are the only chrome that sits on imagery, so they are dark
   frosted glass that blurs and slightly saturates the cover beneath, with a
   hairline of light along the top edge. Same in both themes, since the
   cover, not the stage, is what shows through. Inert; they float over the
   art and never take height from it. */
.case-tags {
  position: absolute;
  top: 10px;
  right: 10px;
  left: 10px;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 4px;
  pointer-events: none;
}
.tag-pill {
  --glass: rgba(14, 14, 16, 0.42);
  box-sizing: border-box;
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 10px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--radius-full);
  background: var(--glass);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  backdrop-filter: blur(14px) saturate(160%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    0 1px 2px rgba(0, 0, 0, 0.18);
  color: #f2f2ee;
  font-size: 12px;
  font-weight: var(--weight-medium);
  line-height: 1;
  white-space: nowrap;
}

/* The AI tag: the one place colour is allowed. A 1px conic ring of orange,
   pink, violet and blue turns slowly in place of the glass edge. No green,
   no yellow. */
@property --ai-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}
.tag-pill.is-ai {
  --ai-ring: conic-gradient(from var(--ai-angle),
    #ff8a3d, #ff4d8d, #a259ff, #3d8bff, #a259ff, #ff4d8d, #ff8a3d);
  isolation: isolate;
  border-color: transparent;
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.tag-pill.is-ai::before {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: -1;
  border-radius: inherit;
  background: var(--ai-ring);
  animation: ai-turn 6s linear infinite;
}
/* The glass, inside the ring. */
.tag-pill.is-ai::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--glass);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  backdrop-filter: blur(14px) saturate(160%);
}
/* The label stays white like every tag: on dark glass over bright covers a
   coloured label lost its contrast. The colour lives in the ring. */
@keyframes ai-turn {
  to { --ai-angle: 360deg; }
}
@media (prefers-reduced-motion: reduce) {
  .tag-pill.is-ai::before { animation: none; }
}
