/* ===========================================================================
   LOREHUB DESIGN SYSTEM — single served stylesheet.
   Generated from the Claude Design "Lorehub Design System" project: webfonts +
   color/typography/spacing/elevation tokens + base reset + every component's
   CSS, inlined into one file so apps link exactly one stylesheet. Component CSS
   references the token custom properties, so it always tracks the live tokens.

   NOT ENTIRELY GENERATED ANY MORE: the "WEB PORTAL PRIMITIVES" section is
   hand-written. A refresh from the Claude Design project must PRESERVE it
   rather than overwrite the file wholesale. It is still component CSS — it
   styles the portal components in `../components/` — so it does belong here.

   APP-SPECIFIC CSS DOES NOT BELONG IN THIS FILE. A page layout that has no
   component behind it goes in the consuming app's own stylesheet
   (`apps/web/src/styles/web.css`, served at `/assets/web.css` and linked after
   this one), precisely because this file is regenerable and that one is not.
   ========================================================================= */

/* ===========================================================================
   WEBFONTS — self-hosted variable woff2 (was a fonts.googleapis.com @import;
   self-hosting removes the last external origins from the CSP). Files live in
   ./fonts/ (design-system) and are served by each app at /assets/fonts/ via
   `readFontAsset`. Latin + latin-ext subsets only; other scripts fall back to
   the system stacks in the --font-* tokens.
   NOTE: the family is "Hanken Grotesk" — the design draft's "Hanken Grotesque"
   was a typo Google Fonts silently dropped, so --font-sans never actually
   loaded a webfont before this. Regenerate files + rules with the css2 URL in
   the worklog (032) if weights/subsets ever change — and RENAME the files when
   you do (the /assets/fonts/ route serves them with a year-long immutable
   cache, so same-name replacements never reach returning browsers).
   ========================================================================= */
/* Bricolage Grotesque — latin-ext */
@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 400 800;
  font-stretch: 100%;
  font-display: swap;
  src: url("/assets/fonts/bricolage-grotesque-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;
}
/* Bricolage Grotesque — latin */
@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 400 800;
  font-stretch: 100%;
  font-display: swap;
  src: url("/assets/fonts/bricolage-grotesque-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+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Hanken Grotesk — latin-ext */
@font-face {
  font-family: "Hanken Grotesk";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/hanken-grotesk-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;
}
/* Hanken Grotesk — latin */
@font-face {
  font-family: "Hanken Grotesk";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/hanken-grotesk-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+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* JetBrains Mono — latin-ext */
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/jetbrains-mono-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;
}
/* JetBrains Mono — latin */
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/jetbrains-mono-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+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ===========================================================================
   COLOR TOKENS — dark-first, warm "ink" neutrals, coral primary.
   ========================================================================= */
:root {
  --ink-1000: #080706;
  --ink-950: #0c0b0a;
  --ink-900: #121110;
  --ink-850: #181613;
  --ink-800: #1f1c19;
  --ink-750: #262220;
  --ink-700: #2e2a26;
  --ink-600: #3c372f;
  --ink-500: #534c43;
  --ink-400: #6e665b;
  --ink-300: #968c7e;
  --ink-200: #c0b6a7;
  --ink-100: #e8e0d3;
  --ink-50: #f8f3e9;

  --coral-700: #c13a1e;
  --coral-600: #e84a28;
  --coral-500: #fb5b33;
  --coral-400: #ff7d5c;
  --coral-300: #ffa489;
  --coral-200: #ffc7b5;
  --coral-tint: rgba(251, 91, 51, 0.14);
  --coral-tint-strong: rgba(251, 91, 51, 0.24);

  --teal-600: #2c9384;
  --teal-500: #3fb8a6;
  --teal-400: #5fd0be;
  --teal-300: #8fe3d5;
  --teal-tint: rgba(63, 184, 166, 0.14);

  --lore-500: #9b7bff;
  --lore-400: #b7a0ff;
  --lore-tint: rgba(155, 123, 255, 0.16);

  --gild-500: #e8b259;
  --gild-400: #f2c878;
  --gild-tint: rgba(232, 178, 89, 0.14);

  --green-500: #5fbe7a;
  --green-tint: rgba(95, 190, 122, 0.14);
  --amber-500: #e8a93c;
  --amber-tint: rgba(232, 169, 60, 0.14);
  /* --red-400 exists for TEXT ON A RED TINT. --red-500 on --danger-soft over
     --surface-card measures 4.04:1, under the 4.5 AA needs; --red-400 measures
     4.98:1. On an untinted surface --red-500 is fine (4.76:1). */
  --red-400: #f2705f;
  --red-500: #ed5247;
  --red-600: #d63b30;
  --red-tint: rgba(237, 82, 71, 0.14);
  --blue-500: #4da3e8;
  --blue-tint: rgba(77, 163, 232, 0.14);

  /* Semantic aliases — reference these in product code */
  --bg-app: var(--ink-950);
  --bg-base: var(--ink-900);
  --surface-sunken: var(--ink-850);
  --surface-card: var(--ink-800);
  --surface-raised: var(--ink-750);
  --surface-hover: var(--ink-700);
  --surface-overlay: #14120ff2;

  --border-subtle: var(--ink-700);
  --border-default: var(--ink-600);
  --border-strong: var(--ink-500);
  --border-accent: var(--coral-500);
  --hairline: rgba(248, 243, 233, 0.07);

  --text-primary: var(--ink-100);
  --text-secondary: var(--ink-200);
  --text-muted: var(--ink-300);
  --text-disabled: var(--ink-400);
  --text-onAccent: #1b0d06;
  --text-link: var(--coral-300);

  --accent: var(--coral-500);
  --accent-hover: var(--coral-400);
  --accent-press: var(--coral-600);
  --accent-soft: var(--coral-tint);
  --accent-2: var(--teal-500);
  --accent-2-soft: var(--teal-tint);

  --success: var(--green-500);
  --success-soft: var(--green-tint);
  --warning: var(--amber-500);
  --warning-soft: var(--amber-tint);
  --danger: var(--red-500);
  --danger-press: var(--red-600);
  --danger-soft: var(--red-tint);
  --info: var(--blue-500);
  --info-soft: var(--blue-tint);

  --focus-ring: rgba(251, 91, 51, 0.55);
  --focus-ring-w: 2px;

  color-scheme: dark;
}

/* ===========================================================================
   UE TYPE TOKENS — one colour per `UeTypeKey` from `@lorehub/uasset-diff`'s
   `classifyUeType`, for the `.uasset` semantic-diff type swatch.

   Hand-written, unlike most of this file: these are transcribed from the design
   record (`../lorehub-desktop/docs/design/uasset-diff-brief*.md`, rounds 1-6),
   not emitted by the Claude Design export.

   Derived from Unreal's own pin palette: keep UE's HUE (so a UE dev still reads
   "that's the bool one"), throw away UE's lightness/chroma (half of Epic's
   values are invisible on --ink-850), and re-land every type at oklch
   L 0.62–0.85 / C 0.015–0.22. Where two types collide after that they are
   separated by FAMILY: hue = family, chroma/lightness = member.

   That chroma range is the SPEC, not what every panel shows: five of the
   nineteen (string, transform, rotator, object/softObject, vector) fall outside
   sRGB and are gamut-clipped there, so chroma separates members reliably only
   on a wide-gamut display. Every token still measures at least 4.9:1 against
   --ink-850, so the swatch itself is legible; a consumer that DIMS one (an
   opacity on a map's key cell, say) is the thing that can push it under 3:1.

   FLAT AND SELF-CONTAINED on purpose. One property per key, nothing computed,
   no per-component tokens: container shape (array/set/map) and the hollow "soft
   reference" rule are MARKUP concerns, and anything needing a computed value
   does not survive the trip into the desktop app, whose stylesheet is a
   vendored copy of this file.

   The names are camelCase where the key is (`--ue-type-softObject`), so the set
   is exactly `UeTypeKey` and a missing or surplus token is obvious on sight.
   Note the obvious payoff does NOT materialise: a consumer cannot write
   `var(--ue-type-${key})`, because a template literal is invisible to the
   desktop's `check-css-vars.ts` guard, so the shipped consumer keys a literal
   map of nineteen `var()` references instead. The naming still earns its keep as
   a one-to-one correspondence; it just does not save the map.
   ========================================================================= */
:root {
  --ue-type-bool: oklch(0.7 0.185 24);
  --ue-type-byte: oklch(0.68 0.095 205);
  --ue-type-int: oklch(0.76 0.135 168);
  --ue-type-float: oklch(0.85 0.185 128);
  --ue-type-string: oklch(0.74 0.215 348);
  --ue-type-text: oklch(0.72 0.145 6);
  --ue-type-name: oklch(0.73 0.175 322);
  --ue-type-vector: oklch(0.84 0.15 78);
  --ue-type-rotator: oklch(0.74 0.14 266);
  --ue-type-transform: oklch(0.74 0.17 44);
  --ue-type-struct: oklch(0.66 0.125 286);
  --ue-type-object: oklch(0.75 0.145 248);
  --ue-type-class: oklch(0.72 0.17 300);
  /* softObject == object and softClass == class BY DESIGN — same thing, not
     loaded — and the swatch carries the difference by rendering hollow. The
     duplication is the statement; do not collapse these into aliases. */
  --ue-type-softObject: oklch(0.75 0.145 248);
  --ue-type-softClass: oklch(0.72 0.17 300);
  --ue-type-interface: oklch(0.8 0.09 36);
  /* Low chroma, not a moved hue: a delegate is a binding rather than a value,
     and this clears the bool/text crowd on the red arc without leaving it. */
  --ue-type-delegate: oklch(0.63 0.06 14);
  --ue-type-wildcard: oklch(0.62 0.015 60);
  --ue-type-unknown: oklch(0.74 0.045 72);
}

/* ===========================================================================
   TYPOGRAPHY TOKENS
   ========================================================================= */
:root {
  --font-display: "Bricolage Grotesque", "Hanken Grotesk", system-ui, sans-serif;
  --font-sans: "Hanken Grotesk", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", "Roboto Mono", monospace;

  --text-xs: 12px;
  --text-sm: 13px;
  --text-base: 15px;
  --text-md: 17px;
  --text-lg: 20px;
  --text-xl: 24px;
  --text-2xl: 30px;
  --text-3xl: 38px;
  --text-4xl: 48px;
  --text-5xl: 64px;
  --text-6xl: 84px;
  --text-7xl: 108px;

  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-extra: 800;

  --leading-none: 1;
  --leading-tight: 1.1;
  --leading-snug: 1.25;
  --leading-normal: 1.5;
  --leading-relaxed: 1.65;

  --tracking-tighter: -0.03em;
  --tracking-tight: -0.015em;
  --tracking-normal: 0;
  --tracking-wide: 0.02em;
  --tracking-caps: 0.08em;

  --font-heading: var(--font-display);
  --font-body: var(--font-sans);
  --font-code: var(--font-mono);
}

/* ===========================================================================
   SPACING, RADII, SIZING — 4px base grid.
   ========================================================================= */
:root {
  --space-0: 0;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 28px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-14: 56px;
  --space-16: 64px;
  --space-20: 80px;
  --space-24: 96px;
  --space-32: 128px;

  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-xl: 20px;
  --radius-2xl: 28px;
  --radius-3xl: 40px;
  --radius-pill: 999px;
  --radius-round: 50%;

  --control-sm: 30px;
  --control-md: 38px;
  --control-lg: 46px;

  --sidebar-w: 248px;
  --container: 1200px;
  --container-wide: 1440px;
  --content-measure: 68ch;

  --z-base: 0;
  --z-sticky: 100;
  --z-dropdown: 200;
  --z-overlay: 300;
  --z-modal: 400;
  --z-toast: 500;
  --z-tooltip: 600;
}

/* ===========================================================================
   ELEVATION, BORDERS, MOTION
   ========================================================================= */
:root {
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.42);
  --shadow-md: 0 6px 18px rgba(0, 0, 0, 0.46);
  --shadow-lg: 0 16px 40px rgba(0, 0, 0, 0.52);
  --shadow-xl: 0 28px 70px rgba(0, 0, 0, 0.6);

  --glow-coral: 0 0 0 1px rgba(251, 91, 51, 0.35), 0 8px 28px rgba(251, 91, 51, 0.28);
  --glow-teal: 0 0 24px rgba(63, 184, 166, 0.3);

  --edge-light: inset 0 1px 0 rgba(248, 243, 233, 0.06);
  --edge-light-strong: inset 0 1px 0 rgba(248, 243, 233, 0.1);

  --elev-card: var(--shadow-md), var(--edge-light);
  --elev-popover: var(--shadow-lg), var(--edge-light);
  --elev-modal: var(--shadow-xl), var(--edge-light-strong);

  --border-w: 1px;
  --border-w-thick: 1.5px;
  --border: 1px solid var(--border-default);
  --border-subtle-rule: 1px solid var(--border-subtle);

  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  --dur-instant: 80ms;
  --dur-fast: 140ms;
  --dur-base: 220ms;
  --dur-slow: 340ms;
  --dur-slower: 520ms;

  --transition-base: all var(--dur-base) var(--ease-out);
  --transition-fast: all var(--dur-fast) var(--ease-out);

  --blur-sm: blur(6px);
  --blur-md: blur(14px);
  --blur-lg: blur(28px);
}

/* ===========================================================================
   BASE / RESET
   ========================================================================= */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* The HTML `hidden` attribute must always win. Its UA rule (`display:none`) is
   only at user-agent level, so any author `display:` (a class like
   `.lh-modal__scrim{display:flex}` or an inline `display:flex` on a `hidden`
   overlay) silently overrides it and the element renders despite `hidden`. The
   island toggles visibility via the `hidden` attribute (command palette, handoff
   modal, popover panels), so make it authoritative. Removing the attribute (JS
   `el.hidden = false`) restores the element's own `display`. */
[hidden] {
  display: none !important;
}

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

body {
  margin: 0;
  background: var(--bg-app);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  font-weight: var(--weight-regular);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: "ss01", "cv01";
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: var(--font-heading);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  margin: 0;
}

p {
  margin: 0;
}

a {
  color: var(--text-link);
  text-decoration: none;
}
a:hover {
  color: var(--coral-200);
}

code,
pre,
kbd,
samp {
  font-family: var(--font-code);
  font-size: 0.92em;
}

::selection {
  background: var(--coral-tint-strong);
  color: var(--ink-50);
}

* {
  scrollbar-width: thin;
  scrollbar-color: var(--ink-600) transparent;
}
*::-webkit-scrollbar {
  width: 11px;
  height: 11px;
}
*::-webkit-scrollbar-track {
  background: transparent;
}
*::-webkit-scrollbar-thumb {
  background: var(--ink-600);
  border-radius: var(--radius-pill);
  border: 3px solid transparent;
  background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover {
  background: var(--ink-500);
  background-clip: content-box;
}

:focus-visible {
  outline: var(--focus-ring-w) solid var(--focus-ring);
  outline-offset: 2px;
}

.lh-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ===========================================================================
   COMPONENTS
   ========================================================================= */

/* Button ------------------------------------------------------------------ */
.lh-btn {
  --_bg: var(--surface-card);
  --_fg: var(--text-primary);
  --_bd: var(--border-default);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-sans);
  font-weight: 600;
  line-height: 1;
  border-radius: var(--radius-md);
  border: 1px solid var(--_bd);
  background: var(--_bg);
  color: var(--_fg);
  cursor: pointer;
  white-space: nowrap;
  user-select: none;
  text-decoration: none;
  transition:
    background var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out),
    opacity var(--dur-fast) var(--ease-out);
}
.lh-btn:focus-visible {
  outline: var(--focus-ring-w) solid var(--focus-ring);
  outline-offset: 2px;
}
.lh-btn:active {
  transform: scale(0.975);
}
.lh-btn[disabled],
.lh-btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
}
.lh-btn--sm {
  height: var(--control-sm);
  padding: 0 12px;
  font-size: 13px;
}
.lh-btn--md {
  height: var(--control-md);
  padding: 0 16px;
  font-size: 14px;
}
.lh-btn--lg {
  height: var(--control-lg);
  padding: 0 22px;
  font-size: 15px;
}
.lh-btn--full {
  width: 100%;
}
.lh-btn--primary {
  --_bg: var(--accent);
  --_fg: var(--text-onAccent);
  --_bd: transparent;
  box-shadow: var(--edge-light-strong);
}
.lh-btn--primary:hover {
  --_bg: var(--accent-hover);
}
.lh-btn--primary:active {
  --_bg: var(--accent-press);
}
.lh-btn--secondary {
  --_bg: var(--surface-card);
  --_fg: var(--text-primary);
  --_bd: var(--border-default);
}
.lh-btn--secondary:hover {
  --_bg: var(--surface-hover);
  --_bd: var(--border-strong);
}
.lh-btn--ghost {
  --_bg: transparent;
  --_fg: var(--text-secondary);
  --_bd: transparent;
}
.lh-btn--ghost:hover {
  --_bg: var(--surface-hover);
  --_fg: var(--text-primary);
}
.lh-btn--danger {
  --_bg: var(--danger);
  --_fg: #fff;
  --_bd: transparent;
}
.lh-btn--danger:hover {
  --_bg: var(--danger-press);
}
.lh-btn--accent2 {
  --_bg: var(--accent-2-soft);
  --_fg: var(--teal-300);
  --_bd: transparent;
}
.lh-btn--accent2:hover {
  --_bg: rgba(63, 184, 166, 0.22);
}
.lh-btn__spin {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  animation: lh-spin 0.7s linear infinite;
}
@keyframes lh-spin {
  to {
    transform: rotate(360deg);
  }
}

/* IconButton -------------------------------------------------------------- */
.lh-iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition:
    background var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}
.lh-iconbtn:hover {
  background: var(--surface-hover);
  color: var(--text-primary);
}
.lh-iconbtn:active {
  transform: scale(0.94);
}
.lh-iconbtn:focus-visible {
  outline: var(--focus-ring-w) solid var(--focus-ring);
  outline-offset: 2px;
}
.lh-iconbtn[disabled],
.lh-iconbtn[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
}
.lh-iconbtn--sm {
  width: 30px;
  height: 30px;
}
.lh-iconbtn--md {
  width: 38px;
  height: 38px;
}
.lh-iconbtn--lg {
  width: 46px;
  height: 46px;
}
.lh-iconbtn--solid {
  background: var(--surface-card);
  border-color: var(--border-default);
  color: var(--text-secondary);
}
.lh-iconbtn--solid:hover {
  background: var(--surface-hover);
  border-color: var(--border-strong);
}
.lh-iconbtn--active {
  background: var(--accent-soft);
  color: var(--coral-300);
}
.lh-iconbtn--active:hover {
  background: var(--coral-tint-strong);
  color: var(--coral-200);
}

/* Alert -------------------------------------------------------------------
   A form-level message banner: the refusal that belongs to the whole submission
   rather than to one field (`.lh-field__error` owns that). Sized to sit directly
   above a form, and safe to render empty + `hidden` for client script to fill. */
.lh-alert {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: 10px var(--space-3);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.45;
}
/* An author `display` beats the UA's `[hidden] { display: none }` (author origin
   wins over UA), so `hidden` on a flex alert would render it anyway. Restore it. */
.lh-alert[hidden] {
  display: none;
}
.lh-alert--danger {
  background: var(--danger-soft);
  border-color: var(--danger);
  /* --red-400, not --danger: text sits on the tint, where --red-500 fails AA. */
  color: var(--red-400);
}
.lh-alert--success {
  background: color-mix(in srgb, var(--success) 12%, transparent);
  border-color: var(--success);
  color: var(--success);
}

/* Optional profile ------------------------------------------------------- */
.lh-profile-page {
  width: min(100%, 620px);
  margin: var(--space-8) auto 0;
}
.lh-profile-page__header {
  margin-bottom: var(--space-5);
}
.lh-profile-page__header h1,
.lh-welcome-profile h2 {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  color: var(--text-primary);
}
.lh-profile-page__header p,
.lh-welcome-profile > p {
  margin: 0;
  color: var(--text-muted);
}
.lh-profile-form {
  display: grid;
  gap: var(--space-5);
  text-align: left;
}
.lh-profile-form__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}
.lh-welcome-profile {
  text-align: left;
}
.lh-profile-form--welcome .lh-profile-form__actions {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-1);
}
.lh-welcome-step {
  width: min(100%, 540px);
  margin: var(--space-10) auto 0;
}
.lh-welcome-step__card {
  display: grid;
  gap: var(--space-6);
}
.lh-welcome-step__header {
  text-align: center;
}
.lh-welcome-step__header h1 {
  margin: 0 0 var(--space-3);
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  letter-spacing: -0.02em;
  color: var(--text-primary);
}
.lh-welcome-step__header > p:last-child {
  max-width: 430px;
  margin: 0 auto;
  color: var(--text-muted);
}
.lh-welcome-step__eyebrow {
  margin: 0 0 var(--space-2);
  color: var(--coral-400);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.lh-welcome-step__icon {
  width: 48px;
  height: 48px;
  margin: 0 auto var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--accent-soft);
  color: var(--coral-400);
  display: flex;
  align-items: center;
  justify-content: center;
}
.lh-welcome-download {
  display: grid;
  gap: var(--space-3);
  text-align: center;
}

/* Input / field ----------------------------------------------------------- */
.lh-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-family: var(--font-sans);
  text-align: left;
}
.lh-field__label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
}
/* Only present when a field passes `labelAside`; a bare label keeps its old
   markup, so this adds nothing to every other field. */
.lh-field__label-row {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
}
.lh-field__label-row .lh-field__label {
  flex: 1;
}
.lh-field__hint {
  font-size: 12px;
  color: var(--text-muted);
}
.lh-field__error {
  font-size: 12px;
  color: var(--red-500);
}
.lh-input {
  display: flex;
  align-items: center;
  gap: 8px;
  height: var(--control-md);
  padding: 0 12px;
  background: var(--surface-sunken);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  transition:
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out);
}
.lh-input:hover {
  border-color: var(--border-strong);
}
.lh-input:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.lh-input--invalid {
  border-color: var(--red-500);
}
.lh-input--invalid:focus-within {
  box-shadow: 0 0 0 3px var(--red-tint);
}
.lh-input--lg {
  height: var(--control-lg);
}
.lh-input--sm {
  height: var(--control-sm);
  font-size: 13px;
}
.lh-input--disabled {
  opacity: 0.5;
  pointer-events: none;
}
.lh-input__el {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: none;
  outline: none;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 14px;
}
.lh-input__el::placeholder {
  color: var(--text-disabled);
}
.lh-input__icon {
  display: inline-flex;
  color: var(--text-muted);
  flex: none;
}
.lh-input--mono .lh-input__el {
  font-family: var(--font-mono);
  font-size: 13px;
}

/* Select ------------------------------------------------------------------ */
.lh-select {
  position: relative;
  display: flex;
  align-items: center;
  height: var(--control-md);
  background: var(--surface-sunken);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  transition:
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}
.lh-select:hover {
  border-color: var(--border-strong);
}
.lh-select:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.lh-select__el {
  appearance: none;
  -webkit-appearance: none;
  flex: 1;
  height: 100%;
  padding: 0 36px 0 12px;
  background: transparent;
  border: none;
  outline: none;
  cursor: pointer;
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 14px;
}
.lh-select__el option {
  background: var(--surface-card);
  color: var(--text-primary);
}
.lh-select__chev {
  position: absolute;
  right: 12px;
  pointer-events: none;
  color: var(--text-muted);
  display: inline-flex;
}
.lh-select--sm {
  height: var(--control-sm);
}
.lh-select--sm .lh-select__el {
  font-size: 13px;
}

/* Checkbox ---------------------------------------------------------------- */
.lh-check {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text-secondary);
  user-select: none;
}
.lh-check input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.lh-check__box {
  width: 18px;
  height: 18px;
  border-radius: var(--radius-xs);
  flex: none;
  background: var(--surface-sunken);
  border: 1.5px solid var(--border-strong);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-onAccent);
  transition:
    background var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}
.lh-check__box svg {
  opacity: 0;
  transform: scale(0.6);
  transition:
    opacity var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-spring);
}
.lh-check input:checked + .lh-check__box {
  background: var(--accent);
  border-color: var(--accent);
}
.lh-check input:checked + .lh-check__box svg {
  opacity: 1;
  transform: scale(1);
}
.lh-check input:focus-visible + .lh-check__box {
  outline: var(--focus-ring-w) solid var(--focus-ring);
  outline-offset: 2px;
}
.lh-check:hover .lh-check__box {
  border-color: var(--accent);
}
.lh-check--disabled {
  opacity: 0.45;
  pointer-events: none;
}

/* Switch ------------------------------------------------------------------ */
.lh-switch {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text-secondary);
  user-select: none;
}
.lh-switch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.lh-switch__track {
  width: 38px;
  height: 22px;
  border-radius: var(--radius-pill);
  flex: none;
  position: relative;
  background: var(--ink-700);
  border: 1px solid var(--border-default);
  transition:
    background var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out);
}
.lh-switch__thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--ink-200);
  box-shadow: var(--shadow-xs);
  transition:
    transform var(--dur-base) var(--ease-spring),
    background var(--dur-base) var(--ease-out);
}
.lh-switch input:checked + .lh-switch__track {
  background: var(--accent);
  border-color: transparent;
}
.lh-switch input:checked + .lh-switch__track .lh-switch__thumb {
  transform: translateX(16px);
  background: var(--text-onAccent);
}
.lh-switch input:focus-visible + .lh-switch__track {
  outline: var(--focus-ring-w) solid var(--focus-ring);
  outline-offset: 2px;
}
.lh-switch--disabled {
  opacity: 0.45;
  pointer-events: none;
}

/* Badge ------------------------------------------------------------------- */
.lh-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 12px;
  line-height: 1;
  padding: 4px 9px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  border: 1px solid transparent;
}
.lh-badge--sm {
  font-size: 11px;
  padding: 3px 7px;
}
.lh-badge__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.lh-badge--neutral {
  background: var(--ink-750);
  color: var(--text-secondary);
  border-color: var(--border-subtle);
}
.lh-badge--coral {
  background: var(--coral-tint);
  color: var(--coral-300);
}
.lh-badge--teal {
  background: var(--teal-tint);
  color: var(--teal-400);
}
.lh-badge--success {
  background: var(--success-soft);
  color: var(--green-500);
}
.lh-badge--warning {
  background: var(--warning-soft);
  color: var(--amber-500);
}
.lh-badge--danger {
  background: var(--danger-soft);
  /* --red-400, not --red-500: 12px/600 is normal text for WCAG, and --red-500 on
     this tint measures 4.04:1 over --surface-card, under AA's 4.5. The sibling
     success/warning/info tones were measured too and all pass; only danger failed. */
  color: var(--red-400);
}
.lh-badge--info {
  background: var(--info-soft);
  color: var(--blue-500);
}
.lh-badge--lore {
  background: var(--lore-tint);
  color: var(--lore-400);
}
.lh-badge--solid {
  background: var(--accent);
  color: var(--text-onAccent);
}

/* Tag --------------------------------------------------------------------- */
.lh-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  line-height: 1;
  padding: 5px 9px;
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  border: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  white-space: nowrap;
}
.lh-tag__dot {
  width: 7px;
  height: 7px;
  border-radius: 2px;
  flex: none;
}
.lh-tag__x {
  display: inline-flex;
  cursor: pointer;
  color: var(--text-muted);
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  margin-right: -2px;
  border-radius: 3px;
  transition:
    color var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out);
}
.lh-tag__x:hover {
  color: var(--text-primary);
  background: var(--surface-hover);
}

/* Avatar ------------------------------------------------------------------ */
.lh-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  border-radius: var(--radius-round);
  overflow: hidden;
  position: relative;
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--text-onAccent);
  background: var(--accent);
  user-select: none;
}
.lh-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.lh-avatar--sq {
  border-radius: var(--radius-md);
}
.lh-avatar__status {
  position: absolute;
  right: -1px;
  bottom: -1px;
  border-radius: 50%;
  border: 2px solid var(--bg-base);
}

/* Card -------------------------------------------------------------------- */
.lh-card {
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md), var(--edge-light);
  color: var(--text-secondary);
  display: flex;
  flex-direction: column;
  transition:
    border-color var(--dur-base) var(--ease-out),
    box-shadow var(--dur-base) var(--ease-out),
    transform var(--dur-base) var(--ease-out),
    background var(--dur-base) var(--ease-out);
}
.lh-card--pad-sm {
  padding: var(--space-4);
}
.lh-card--pad-md {
  padding: var(--space-5);
}
.lh-card--pad-lg {
  padding: var(--space-6);
}
.lh-card--flat {
  box-shadow: var(--edge-light);
}
.lh-card--sunken {
  background: var(--surface-sunken);
  box-shadow: none;
}
.lh-card--interactive {
  cursor: pointer;
}
.lh-card--interactive:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-lg), var(--edge-light);
  transform: translateY(-2px);
}
.lh-card--interactive:active {
  transform: translateY(0);
}
.lh-card--accent {
  border-color: var(--coral-600);
  box-shadow: var(--glow-coral);
}
.lh-card__header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: var(--space-3);
}
.lh-card__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 17px;
  color: var(--text-primary);
  letter-spacing: var(--tracking-tight);
  margin: 0;
}
.lh-card__sub {
  font-size: 13px;
  color: var(--text-muted);
  margin: 2px 0 0;
}

/* A full-row link inside a card list (e.g. the org repos list) — the SSR-safe
   stand-in for the design's per-row hover highlight. */
.lh-list-row {
  transition: background var(--dur-fast) var(--ease-out);
}
.lh-list-row:hover {
  background: var(--surface-hover);
}

/* Screen-reader-only content (e.g. a search form's submit button that sighted
   users trigger via Enter). The standard clip-rect pattern. */
.lh-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Tabs -------------------------------------------------------------------- */
.lh-tabs {
  display: flex;
  align-items: center;
  gap: 2px;
  border-bottom: 1px solid var(--border-subtle);
}
.lh-tabs--pill {
  gap: 4px;
  border: none;
  background: var(--surface-sunken);
  padding: 4px;
  border-radius: var(--radius-md);
  display: inline-flex;
}
.lh-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 14px;
  color: var(--text-muted);
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 10px 14px;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  transition:
    color var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out);
}
.lh-tab:hover {
  color: var(--text-primary);
}
.lh-tab--active {
  color: var(--text-primary);
}
.lh-tab__underline {
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: -1px;
  height: 2px;
  background: var(--accent);
  border-radius: 2px;
}
.lh-tabs--pill .lh-tab {
  padding: 7px 14px;
  border-radius: var(--radius-sm);
}
.lh-tabs--pill .lh-tab--active {
  background: var(--surface-raised);
  color: var(--text-primary);
  box-shadow: var(--shadow-xs), var(--edge-light);
}
.lh-tab__count {
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 1px 6px;
  border-radius: var(--radius-pill);
  background: var(--ink-700);
  color: var(--text-muted);
}
.lh-tab--active .lh-tab__count {
  background: var(--accent-soft);
  color: var(--coral-300);
}

/* Tooltip ----------------------------------------------------------------- */
.lh-tip-wrap {
  position: relative;
  display: inline-flex;
}
.lh-tip {
  position: absolute;
  z-index: var(--z-tooltip);
  background: var(--ink-50);
  color: var(--ink-900);
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
  padding: 6px 9px;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  /* Shrink-to-fit against the tiny .lh-tip-wrap would wrap at the trigger's width, so the
     tip sizes to its own text; the cap keeps a sentence-length label wrapping instead of
     running wider than its dialog. */
  width: max-content;
  max-width: 280px;
  pointer-events: none;
  opacity: 0;
  transition:
    opacity var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}
.lh-tip__kbd {
  font-family: var(--font-mono);
  font-size: 11px;
  opacity: 0.6;
  margin-left: 6px;
}
.lh-tip--top {
  bottom: calc(100% + 7px);
  left: 50%;
  transform: translate(-50%, 4px);
}
.lh-tip--bottom {
  top: calc(100% + 7px);
  left: 50%;
  transform: translate(-50%, -4px);
}
.lh-tip--left {
  right: calc(100% + 7px);
  top: 50%;
  transform: translate(4px, -50%);
}
.lh-tip--right {
  left: calc(100% + 7px);
  top: 50%;
  transform: translate(-4px, -50%);
}
.lh-tip-wrap:hover .lh-tip,
.lh-tip-wrap:has(:focus-visible) .lh-tip {
  opacity: 1;
  transform: translate(-50%, 0);
}
.lh-tip-wrap:hover .lh-tip--left,
.lh-tip-wrap:has(:focus-visible) .lh-tip--left {
  transform: translate(0, -50%);
}
.lh-tip-wrap:hover .lh-tip--right,
.lh-tip-wrap:has(:focus-visible) .lh-tip--right {
  transform: translate(0, -50%);
}
/* End-aligned modifier for top/bottom tips: pin the tip's right edge to the trigger's
   right edge instead of centering. For a trigger at its container's right edge, a
   centered tip overflows — and since the tip stays in layout at opacity 0, it mints a
   phantom horizontal scrollbar inside any overflow-auto ancestor even while hidden. */
.lh-tip--top.lh-tip--end {
  left: auto;
  right: 0;
  transform: translate(0, 4px);
}
.lh-tip--bottom.lh-tip--end {
  left: auto;
  right: 0;
  transform: translate(0, -4px);
}
.lh-tip-wrap:hover .lh-tip--top.lh-tip--end,
.lh-tip-wrap:hover .lh-tip--bottom.lh-tip--end,
.lh-tip-wrap:has(:focus-visible) .lh-tip--top.lh-tip--end,
.lh-tip-wrap:has(:focus-visible) .lh-tip--bottom.lh-tip--end {
  transform: translate(0, 0);
}

/* Toast ------------------------------------------------------------------- */
.lh-toast {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  width: 360px;
  max-width: calc(100vw - 32px);
  background: var(--surface-raised);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg), var(--edge-light-strong);
  padding: 13px 14px;
  font-family: var(--font-sans);
  animation: lh-toast-in var(--dur-base) var(--ease-spring);
}
@keyframes lh-toast-in {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.lh-toast__icon {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 1px;
}
.lh-toast__body {
  flex: 1;
  min-width: 0;
}
.lh-toast__title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  margin: 0;
}
.lh-toast__msg {
  font-size: 13px;
  color: var(--text-muted);
  margin: 2px 0 0;
}
.lh-toast__close {
  flex: none;
  background: transparent;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
  padding: 2px;
  display: inline-flex;
  transition:
    color var(--dur-fast),
    background var(--dur-fast);
}
.lh-toast__close:hover {
  color: var(--text-primary);
  background: var(--surface-hover);
}
.lh-toast--success .lh-toast__icon {
  background: var(--success-soft);
  color: var(--green-500);
}
.lh-toast--danger .lh-toast__icon {
  background: var(--danger-soft);
  color: var(--red-500);
}
.lh-toast--warning .lh-toast__icon {
  background: var(--warning-soft);
  color: var(--amber-500);
}
.lh-toast--info .lh-toast__icon {
  /* Was --accent-soft/--coral-300, the brand accent rather than a semantic tone. An
     orange-red disc reads as the alert signal at a glance regardless of the glyph
     inside it. --info/--info-soft is the same blue pair already used for
     .lh-badge--info and .lh-handoff__hint; Toast's info tone should match. */
  background: var(--info-soft);
  color: var(--blue-500);
}

/* Modal ------------------------------------------------------------------- */
.lh-modal__scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  background: rgba(8, 7, 6, 0.66);
  backdrop-filter: var(--blur-sm);
  -webkit-backdrop-filter: var(--blur-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  animation: lh-fade var(--dur-base) var(--ease-out);
}
@keyframes lh-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
/* A bare `<dialog class="lh-modal">` (e.g. the handoff dialog, the ⌘K palette) must stay
   hidden until opened via `showModal()`/`[open]`. The native `dialog:not([open]){display:none}`
   is a UA rule, and the author `.lh-modal{display:flex}` below would otherwise win the cascade
   (author beats UA regardless of specificity) — leaving the dialog rendered in normal flow at
   the bottom of the page. Re-establish the hidden default for non-open dialogs; `[open]` /
   `showModal()` lifts it back to `display:flex`. (Div-based `.lh-modal` inside `.lh-modal__scrim`
   is unaffected — this only matches actual `<dialog>` elements.) */
dialog.lh-modal:not([open]) {
  display: none;
}
.lh-modal {
  width: 100%;
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-2xl);
  box-shadow: var(--shadow-xl), var(--edge-light-strong);
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 48px);
  animation: lh-modal-in var(--dur-slow) var(--ease-spring);
}
@keyframes lh-modal-in {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.lh-modal--sm {
  max-width: 420px;
}
.lh-modal--md {
  max-width: 540px;
}
.lh-modal--lg {
  max-width: 720px;
}
.lh-modal__head {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 22px 24px 0;
}
.lh-modal__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 21px;
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  margin: 0;
  flex: 1;
}
.lh-modal__sub {
  font-size: 13px;
  color: var(--text-muted);
  margin: 4px 0 0;
  font-family: var(--font-sans);
}
.lh-modal__x {
  flex: none;
  background: transparent;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  padding: 4px;
  border-radius: var(--radius-sm);
  display: inline-flex;
  transition:
    color var(--dur-fast),
    background var(--dur-fast);
}
.lh-modal__x:hover {
  color: var(--text-primary);
  background: var(--surface-hover);
}
.lh-modal__body {
  padding: 18px 24px;
  overflow: auto;
  font-family: var(--font-sans);
  color: var(--text-secondary);
  font-size: 14px;
}
.lh-modal__foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding: 16px 24px 22px;
  border-top: 1px solid var(--border-subtle);
  margin-top: auto;
}

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

/* ===========================================================================
   WEB PORTAL PRIMITIVES — new components for the hosting portal (apps/web).
   Sync state, branch ahead/behind, file status/glyphs, revision timeline,
   meta rows, role badges, insight blocks, and the web→desktop deep-link bridge.
   ========================================================================= */

/* SyncIndicator ----------------------------------------------------------- */
.lh-sync {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 28px;
  padding: 0 11px;
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  border: 1px solid var(--border-subtle);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
}
.lh-sync--sm {
  height: 24px;
  padding: 0 8px;
  font-size: var(--text-xs);
}
.lh-sync__icon {
  display: inline-flex;
  width: 14px;
  height: 14px;
}
.lh-sync--uptodate .lh-sync__icon {
  color: var(--green-500);
}
.lh-sync--behind {
  color: var(--amber-500);
}
.lh-sync--ahead {
  color: var(--green-500);
}
.lh-sync--changes {
  color: var(--coral-300);
}
.lh-sync--offline {
  color: var(--text-muted);
}
.lh-sync--syncing {
  color: var(--teal-400);
}
.lh-sync--syncing .lh-sync__icon {
  animation: lh-spin 1s linear infinite;
}

/* AheadBehind ------------------------------------------------------------- */
.lh-aheadbehind {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}
.lh-aheadbehind--even {
  color: var(--text-muted);
}
.lh-aheadbehind__ahead {
  color: var(--green-500);
}
.lh-aheadbehind__behind {
  color: var(--amber-500);
}

/* StatusLetter ------------------------------------------------------------ */
.lh-status {
  display: inline-block;
  width: 14px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
}
.lh-status--M {
  color: var(--amber-500);
}
.lh-status--A {
  color: var(--green-500);
}
.lh-status--D {
  color: var(--red-500);
}
.lh-status--L {
  color: var(--coral-500);
}

/* ChangeLetter (WP-069 revision diff — 5 kinds) --------------------------- */
.lh-change {
  display: inline-block;
  width: 14px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  flex: none;
}
.lh-change--A {
  color: var(--green-500);
}
.lh-change--M {
  color: var(--amber-500);
}
.lh-change--D {
  color: var(--red-500);
}
.lh-change--R {
  color: var(--teal-400);
}
.lh-change--C {
  color: var(--lore-400);
}

/* Skeleton shimmer (WP-069 lazy-fragment loading state) ------------------- */
@keyframes lh-shimmer {
  0% {
    background-position: -320px 0;
  }
  100% {
    background-position: 320px 0;
  }
}
.lh-skel {
  display: block;
  background: linear-gradient(90deg, var(--ink-800) 0%, var(--ink-700) 50%, var(--ink-800) 100%);
  background-size: 640px 100%;
  animation: lh-shimmer 1.3s linear infinite;
  border-radius: var(--radius-xs);
}

/* FileGlyph --------------------------------------------------------------- */
.lh-glyph {
  display: inline-flex;
  color: var(--text-muted);
}
.lh-glyph--lore {
  color: var(--lore-400);
}
.lh-glyph--coral {
  color: var(--coral-400);
}
.lh-glyph--teal {
  color: var(--teal-400);
}
.lh-glyph--blue {
  color: var(--blue-500);
}
.lh-glyph--gild {
  color: var(--gild-400);
}
.lh-glyph--green {
  color: var(--green-500);
}
.lh-glyph--default {
  color: var(--text-muted);
}

/* MetaRow ----------------------------------------------------------------- */
.lh-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  font-size: var(--text-sm);
}
.lh-meta__label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
}
.lh-meta__value {
  color: var(--text-secondary);
}

/* RoleBadge reuses .lh-badge tones. */

/* RevisionRow — timeline rail + selectable card --------------------------- */
.lh-revrow {
  display: flex;
  gap: 14px;
  --_rail: var(--coral-500);
}
.lh-revrow--coral {
  --_rail: var(--coral-500);
}
.lh-revrow--teal {
  --_rail: var(--teal-500);
}
.lh-revrow--lore {
  --_rail: var(--lore-500);
}
.lh-revrow--gild {
  --_rail: var(--gild-500);
}
.lh-revrow__rail {
  width: 16px;
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.lh-revrow__line {
  width: 2px;
  background: var(--_rail);
}
.lh-revrow__line--top {
  height: 14px;
}
.lh-revrow__line--bot {
  flex: 1;
}
.lh-revrow--first .lh-revrow__line--top {
  background: transparent;
}
.lh-revrow--last .lh-revrow__line--bot {
  background: transparent;
}
.lh-revrow__node {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex: none;
  background: var(--bg-app);
  border: 2.5px solid var(--_rail);
}
.lh-revrow--selected .lh-revrow__node {
  background: var(--_rail);
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--_rail) 22%, transparent);
}
.lh-revrow__card {
  display: block;
  flex: 1;
  min-width: 0;
  margin: 0 0 2px;
  padding: 12px 14px;
  border-radius: var(--radius-lg);
  border: 1px solid transparent;
  color: inherit;
  text-decoration: none;
  transition:
    background var(--dur-fast, 140ms) var(--ease-out),
    border-color var(--dur-fast, 140ms) var(--ease-out);
}
.lh-revrow__card:hover {
  background: var(--surface-hover);
}
.lh-revrow--selected .lh-revrow__card {
  background: var(--surface-card);
  border-color: var(--border-default);
  box-shadow: var(--shadow-sm), var(--edge-light);
}
.lh-revrow__head {
  display: flex;
  align-items: center;
  gap: 10px;
}
.lh-revrow__msg {
  flex: 1;
  min-width: 0;
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lh-revrow__meta {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 7px;
  flex-wrap: wrap;
  font-size: var(--text-xs);
  color: var(--text-muted);
}
.lh-revrow__sig {
  font-family: var(--font-mono);
  color: var(--coral-300);
}

/* Insight blocks ---------------------------------------------------------- */
.lh-insight-hist__bars {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  height: 140px;
  padding: 8px 0;
}
.lh-insight-hist__bar {
  flex: 1;
  min-height: 2px;
  background: var(--ink-700);
  border-radius: 4px 4px 0 0;
  transition: height var(--dur-base, 220ms) var(--ease-out);
}
.lh-insight-hist__bar--peak {
  background: linear-gradient(var(--coral-400), var(--coral-500));
}
.lh-insight-hist__peak {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-disabled);
  text-align: right;
}
.lh-insight-comp__track {
  display: flex;
  height: 10px;
  border-radius: var(--radius-pill);
  overflow: hidden;
  margin-bottom: 16px;
}
.lh-insight-comp__fill {
  height: 100%;
}
.lh-insight-comp__seg {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 0;
}
.lh-insight-comp__swatch {
  width: 9px;
  height: 9px;
  border-radius: 2px;
  flex: none;
}
.lh-insight-comp__label {
  flex: 1;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.lh-insight-comp__size {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
}
.lh-insight-comp__pct {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-primary);
  width: 36px;
  text-align: right;
}
.lh-insight-contrib__row {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 7px 0;
}
.lh-insight-contrib__name {
  width: 110px;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}
.lh-insight-contrib__track {
  flex: 1;
  height: 7px;
  border-radius: var(--radius-pill);
  background: var(--ink-700);
  overflow: hidden;
}
.lh-insight-contrib__fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--teal-500), var(--teal-400));
}
.lh-insight-contrib__value {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
  width: 64px;
  text-align: right;
}
.lh-insight-largest__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
}
.lh-insight-largest__path {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  direction: rtl;
  text-align: left;
}
.lh-insight-largest__size {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* DeeplinkButton — web→desktop bridge ------------------------------------- */
.lh-deeplink {
  position: relative;
  display: inline-flex;
}
.lh-deeplink--split .lh-deeplink__primary {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.lh-deeplink__more {
  position: relative;
}
.lh-deeplink__toggle {
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 7px;
  cursor: pointer;
  list-style: none;
  background: var(--surface-raised);
  color: var(--text-secondary);
  border: 1px solid var(--border-default);
  border-left: none;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
}
.lh-deeplink__toggle::-webkit-details-marker {
  display: none;
}
.lh-deeplink__menu {
  position: absolute;
  top: 44px;
  right: 0;
  z-index: var(--z-dropdown);
  width: 250px;
  padding: 6px;
  background: var(--surface-raised);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg), var(--edge-light);
}
.lh-deeplink__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--text-secondary);
  text-decoration: none;
}
.lh-deeplink__item:hover {
  background: var(--surface-hover);
}

/* HandoffModal — reuses .lh-modal__scrim ---------------------------------- */
.lh-handoff {
  padding: 26px;
  text-align: center;
}
.lh-handoff__icon {
  position: relative;
  width: 56px;
  height: 56px;
  margin: 0 auto 16px;
  border-radius: var(--radius-lg);
  background: var(--accent-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--coral-400);
}
.lh-handoff__spinner {
  position: absolute;
  inset: -6px;
  border-radius: var(--radius-lg);
  border: 2px solid var(--coral-tint-strong);
  border-top-color: var(--coral-500);
  animation: lh-spin 0.8s linear infinite;
}
.lh-handoff__title {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-size: var(--text-lg);
  color: var(--text-primary);
  margin: 0 0 6px;
  letter-spacing: var(--tracking-tight);
}
.lh-handoff__lede {
  margin: 0 0 18px;
  font-size: var(--text-sm);
  color: var(--text-muted);
  line-height: var(--leading-normal);
}
.lh-handoff__uri {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  border: 1px solid var(--border-subtle);
  margin-bottom: 18px;
  color: var(--text-disabled);
}
.lh-handoff__uri-text {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--coral-300);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: left;
}
.lh-handoff__hint {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 13px;
  border-radius: var(--radius-md);
  background: var(--info-soft);
  border: 1px solid color-mix(in oklab, var(--blue-500) 26%, transparent);
  margin-bottom: 18px;
  text-align: left;
  font-size: var(--text-xs);
  color: var(--text-secondary);
}
.lh-handoff__hint i {
  color: var(--blue-500);
  flex: none;
}
.lh-handoff__foot {
  display: flex;
  justify-content: center;
  gap: 10px;
}
