/* The design system: docs/design-guide.md, in one file.

   Served by the shell and by every module, so a module page cannot drift from
   the guide by carrying its own copy of it. Font URLs are rooted at /static,
   so a framed module page uses the faces the shell's page has already loaded
   instead of fetching its own copies under /embed/<id>/ (issue 177), and a
   module opened on its own is served them by its own /static (R-04: nothing
   is fetched from a network to render a page).

   Themes follow the guide's four-state rule: bare :root carries the complete
   Light palette, an unstamped root follows a dark device into Dim, and
   data-theme="dim" | "black" | "sepia" redefine only tokens. Values are the
   Lattice design system's (design guide §2). */

@font-face {
  font-family: "IBM Plex Sans";
  src: url("/static/fonts/ibm-plex-sans-latin-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Sans";
  src: url("/static/fonts/ibm-plex-sans-latin-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/static/fonts/ibm-plex-mono-latin-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/static/fonts/ibm-plex-mono-latin-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Light: sunlit cream, fern accent. The complete palette lives on bare
     :root so the unstamped default is readable. */
  --bg:            #FAF5EC;
  --bg-mid:        #F5EAD3;
  --bg-deep:       #ECD9A6;
  --bg-image:      linear-gradient(157deg, var(--bg) 0%, var(--bg-mid) 38%, #F2E3B8 78%, var(--bg-deep) 100%);
  --surface:       #FFFCF7;
  --surface-2:     #F3EADB;
  --surface-3:     #E9DCC6;
  --pane:          rgba(255, 252, 247, 0.64);
  --pane-strong:   rgba(255, 252, 247, 0.88);
  --border:        #E0D2BB;
  --border-soft:   #EBE1CF;
  --border-strong: #8C785D;
  --text:          #1C170F;
  --text-2:        #5A4A35;

  --accent:        #3D6412;
  --accent-hover:  #2C4A0B;
  --accent-soft:   #E6EED6;
  --accent-fill:   #7AA33A;
  --on-accent:     #1C170F;
  --accent-glow:   rgba(122, 163, 58, 0.14);
  --good:          #1C6A73;
  --good-soft:     #DCECEC;
  --warn:          #8A5700;
  --warn-soft:     #F5E9D2;
  --crit:          #A53318;
  --crit-soft:     #F7E1DA;

  --ink:           #1C170F;
  --ink-text:      #FAF5EC;
  --ink-muted:     #B3A58E;
  --text-muted:    var(--text-2);  /* retired third grey: an alias, never a new colour */
  --focus:         var(--accent);

  --slice-1:       #2C4A0B;
  --slice-2:       #4F7D1A;
  --slice-3:       #7AA33A;
  --slice-4:       #A9C77A;
  --slice-5:       #D4E4B8;
  --series-1:      #4F7D1A;
  --series-2:      #2D5F93;
  --series-3:      #B5532B;
  --series-4:      #9A7020;
  --series-5:      #7A4A78;
  --series-6:      #1C6A73;

  --ground:        0;
  --panel-blur:    blur(22px) saturate(140%);
  --panel-shadow:  0 1.25rem 2.5rem -1.25rem rgba(60, 40, 15, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.6);

  --font-ui:   "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* The type scale of the guide (§3), in `rem` so that every size answers to
     the reader's own browser setting. A component that hard-codes `px` opts
     the reader out of that, which is why the scale is tokens and "a one-off
     size is a bug".

     The three largest steps are fluid: they are the sizes that would either
     overflow a narrow screen or look stranded on a wide one, and `clamp`
     resolves that without a breakpoint per size. The floor of each is the
     size the guide already specifies for a phone, and the ceiling is its
     desktop figure -- so the scale still reads as the table in §3, and only
     the space between the two is interpolated. */
  /* 14px is the floor (AGENTS.md §5): --t-micro and --t-small are the same
     size and survive as names only so existing rules keep working. Body is
     16px so an input never makes a phone zoom. */
  --t-micro:       0.875rem;   /* 14 */
  --t-small:       0.875rem;   /* 14 */
  --t-body:        1rem;       /* 16 */
  --t-lead:        1.125rem;   /* 18 */
  --t-h3:          1.25rem;    /* 20 */
  --t-h2:          1.625rem;   /* 26 */
  --t-display:     clamp(1.875rem, 1.05rem + 3.6vw, 3.25rem);   /* 30 -> 52 */
  --t-metric:      clamp(1.75rem, 1.45rem + 1.3vw, 2.25rem);    /* 28 -> 36 */
  --t-metric-hero: clamp(3rem, 2.4rem + 2.5vw, 4rem);           /* 48 -> 64 */

  --lh-micro:   1.4;
  --lh-small:   1.45;
  --lh-body:    1.55;
  --lh-lead:    1.5;
  --lh-h3:      1.3;
  --lh-h2:      1.22;
  --lh-display: 1;
  --lh-metric:  1.05;

  --radius-card: 1.25rem;
  --radius-control: 0.875rem;
  --radius-pill: 999px;
  --radius-inner: 0.625rem;   /* one step inside a control */
  --chrome-height: 4.5rem;

  /* 4px base (guide §4). */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;

  --duration-fast: 120ms;
  --duration-base: 180ms;
  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);

  /* The appearance switch shows each palette as itself, whichever palette
     is active, so these are constants rather than per-theme tokens. */
  --swatch-light: #FAF5EC;
  --swatch-light-accent: #7AA33A;
  --swatch-dim: #0A1114;
  --swatch-dim-accent: #F0A04B;
  --swatch-black: #000000;
  --swatch-black-accent: #C8F031;
  --swatch-sepia: #EFE3CC;
  --swatch-sepia-accent: #2F5277;

  /* Each palette's painted wash, for the Settings swatch that offers it. */
  --wash-light: linear-gradient(157deg, #FAF5EC 0%, #F5EAD3 38%, #F2E3B8 78%, #ECD9A6 100%);
  --wash-dim:   radial-gradient(130% 100% at 18% 6%, #1A2A2F 0%, #0F1A1E 46%, #0A1114 100%);
  --wash-sepia: linear-gradient(165deg, #EFE3CC 0%, #E7D8BD 55%, #D9C5A2 100%);

  /* Elevation is carried by --border and the pane. This is the one shadow the
     guide allows, and only an overlay may use it. */
  --shadow-overlay: 0 1px 2px rgba(0,0,0,.06), 0 12px 28px -18px rgba(0,0,0,.5);
}

/* System, when the device is dark: Dim. Only an unstamped root follows the
   device; any explicit choice wins. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    /* Dim: night slate, ember accent. */
    --bg:            #0A1114;
    --bg-mid:        #0F1A1E;
    --bg-deep:       #1A2A2F;
    --bg-image:      radial-gradient(130% 100% at 18% 6%, var(--bg-deep) 0%, var(--bg-mid) 46%, var(--bg) 100%);
    --surface:       #111B1F;
    --surface-2:     #18252A;
    --surface-3:     #213137;
    --pane:          rgba(17, 27, 31, 0.58);
    --pane-strong:   rgba(17, 27, 31, 0.86);
    --border:        #2A3A40;
    --border-soft:   #1F2D32;
    --border-strong: #627D85;
    --text:          #EEF2F1;
    --text-2:        #A8B7B9;

    --accent:        #F5AE5E;
    --accent-hover:  #FFC27E;
    --accent-soft:   #3A2814;
    --accent-fill:   #F0A04B;
    --on-accent:     #0A1114;
    --accent-glow:   rgba(240, 160, 75, 0.12);
    --good:          #5FD3C6;
    --good-soft:     #10302D;
    --warn:          #F2D45C;
    --warn-soft:     #2E2A12;
    --crit:          #FF7A68;
    --crit-soft:     #3A1A16;

    --ink:           #050A0C;
    --ink-text:      #EEF2F1;
    --ink-muted:     #8A9A9C;
    --text-muted:    var(--text-2);  /* retired third grey: an alias, never a new colour */
    --focus:         var(--accent);

    --slice-1:       #FDE3C4;
    --slice-2:       #F9C68C;
    --slice-3:       #F0A04B;
    --slice-4:       #C97D33;
    --slice-5:       #9A5C24;
    --series-1:      #F0A04B;
    --series-2:      #7CB8E6;
    --series-3:      #B4A6E8;
    --series-4:      #A8C96A;
    --series-5:      #FF8FA3;
    --series-6:      #5FD3C6;

    --ground:        0.62;
    --panel-blur:    blur(28px) saturate(150%);
    --panel-shadow:  0 1.5rem 3rem -1rem rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.10);
  }
}

:root[data-theme="dim"] {
  /* Dim: night slate, ember accent. */
  --bg:            #0A1114;
  --bg-mid:        #0F1A1E;
  --bg-deep:       #1A2A2F;
  --bg-image:      radial-gradient(130% 100% at 18% 6%, var(--bg-deep) 0%, var(--bg-mid) 46%, var(--bg) 100%);
  --surface:       #111B1F;
  --surface-2:     #18252A;
  --surface-3:     #213137;
  --pane:          rgba(17, 27, 31, 0.58);
  --pane-strong:   rgba(17, 27, 31, 0.86);
  --border:        #2A3A40;
  --border-soft:   #1F2D32;
  --border-strong: #627D85;
  --text:          #EEF2F1;
  --text-2:        #A8B7B9;

  --accent:        #F5AE5E;
  --accent-hover:  #FFC27E;
  --accent-soft:   #3A2814;
  --accent-fill:   #F0A04B;
  --on-accent:     #0A1114;
  --accent-glow:   rgba(240, 160, 75, 0.12);
  --good:          #5FD3C6;
  --good-soft:     #10302D;
  --warn:          #F2D45C;
  --warn-soft:     #2E2A12;
  --crit:          #FF7A68;
  --crit-soft:     #3A1A16;

  --ink:           #050A0C;
  --ink-text:      #EEF2F1;
  --ink-muted:     #8A9A9C;
  --text-muted:    var(--text-2);  /* retired third grey: an alias, never a new colour */
  --focus:         var(--accent);

  --slice-1:       #FDE3C4;
  --slice-2:       #F9C68C;
  --slice-3:       #F0A04B;
  --slice-4:       #C97D33;
  --slice-5:       #9A5C24;
  --series-1:      #F0A04B;
  --series-2:      #7CB8E6;
  --series-3:      #B4A6E8;
  --series-4:      #A8C96A;
  --series-5:      #FF8FA3;
  --series-6:      #5FD3C6;

  --ground:        0.62;
  --panel-blur:    blur(28px) saturate(150%);
  --panel-shadow:  0 1.5rem 3rem -1rem rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.10);
}

:root[data-theme="black"] {
  /* Black: true #000 so an OLED screen switches the pixels off. No wash,
     no photograph, no blur, no drop shadow. */
  --bg:            #000000;
  --bg-mid:        #000000;
  --bg-deep:       #000000;
  --bg-image:      none;
  --surface:       #000000;
  --surface-2:     #121212;
  --surface-3:     #1C1C1C;
  --pane:          #000000;
  --pane-strong:   #0A0A0A;
  --border:        #2A2A2A;
  --border-soft:   #1A1A1A;
  --border-strong: #6E6E6E;
  --text:          #F5F5F5;
  --text-2:        #ABABAB;

  --accent:        #C8F031;
  --accent-hover:  #D9FF5C;
  --accent-soft:   #1C2408;
  --accent-fill:   #C8F031;
  --on-accent:     #000000;
  --accent-glow:   rgba(200, 240, 49, 0.10);
  --good:          #3DDBC9;
  --good-soft:     #062622;
  --warn:          #FFB62E;
  --warn-soft:     #2A1E05;
  --crit:          #FF6A45;
  --crit-soft:     #2A0F08;

  --ink:           #1C1C1C;
  --ink-text:      #F5F5F5;
  --ink-muted:     #8F8F8F;
  --text-muted:    var(--text-2);  /* retired third grey: an alias, never a new colour */
  --focus:         var(--accent);

  --slice-1:       #EEFFB8;
  --slice-2:       #DCF97A;
  --slice-3:       #C8F031;
  --slice-4:       #98B822;
  --slice-5:       #6A8216;
  --series-1:      #C8F031;
  --series-2:      #5CB8FF;
  --series-3:      #FF8FC8;
  --series-4:      #FFB62E;
  --series-5:      #3DDBC9;
  --series-6:      #B4A6E8;

  --ground:        0;
  --panel-blur:    none;
  --panel-shadow:  inset 0 1px 0 rgba(255, 255, 255, 0.06);
  --shadow-overlay: 0 0 0 1px rgba(255, 255, 255, 0.10);
}

:root[data-theme="sepia"] {
  /* Sepia: parchment, drafting-ink blue. */
  --bg:            #EFE3CC;
  --bg-mid:        #E7D8BD;
  --bg-deep:       #D9C5A2;
  --bg-image:      linear-gradient(165deg, var(--bg) 0%, var(--bg-mid) 55%, var(--bg-deep) 100%);
  --surface:       #F7EEDD;
  --surface-2:     #E9DCC3;
  --surface-3:     #DCC9A9;
  --pane:          rgba(247, 238, 221, 0.58);
  --pane-strong:   rgba(247, 238, 221, 0.90);
  --border:        #D2BF9F;
  --border-soft:   #E1D2B6;
  --border-strong: #86684A;
  --text:          #2A1C12;
  --text-2:        #5A4230;

  --accent:        #2F5277;
  --accent-hover:  #213D5B;
  --accent-soft:   #DFE3E3;
  --accent-fill:   #2F5277;
  --on-accent:     #F7EEDD;
  --accent-glow:   rgba(47, 82, 119, 0.10);
  --good:          #175A54;
  --good-soft:     #D8E6DF;
  --warn:          #6C4708;
  --warn-soft:     #EFDFC0;
  --crit:          #912A16;
  --crit-soft:     #F1D9CC;

  --ink:           #2A1C12;
  --ink-text:      #F3E9D8;
  --ink-muted:     #B0A08A;
  --text-muted:    var(--text-2);  /* retired third grey: an alias, never a new colour */
  --focus:         var(--accent);

  --slice-1:       #1D3550;
  --slice-2:       #2F5277;
  --slice-3:       #557AA0;
  --slice-4:       #8BA6C2;
  --slice-5:       #C3D2E0;
  --series-1:      #2F5277;
  --series-2:      #A3341F;
  --series-3:      #3F6B3A;
  --series-4:      #8F6419;
  --series-5:      #6E3F5C;
  --series-6:      #5B6B78;

  --ground:        0.30;
  --panel-blur:    blur(22px) saturate(130%);
  --panel-shadow:  0 1.25rem 2.5rem -1rem rgba(42, 28, 18, 0.25), inset 0 1px 0 rgba(255, 250, 240, 0.55);
}

* { box-sizing: border-box; }

html {
  height: 100%;
  overflow-x: clip;
}
@supports not (overflow-x: clip) {
  html {
    overflow-x: hidden;
  }
}

body {
  height: 100%;
  overflow-x: clip;
  margin: 0;
  padding: 0;
  background: var(--bg);
  background-image: var(--bg-image);
  background-attachment: fixed;
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
}
@supports not (overflow-x: clip) {
  body {
    overflow-x: hidden;
  }
}

/* Keyboard operability is not optional, and a control that cannot be seen
   when focused is not operable. Components may override the offset; none may
   remove the ring. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
    /* Snapping is layout, not decoration, so it stays; what goes is the
       animated glide between snap points. */
    scroll-behavior: auto !important;
  }
}

/* ---- Theme backgrounds -------------------------------------------------
   Each palette that wears a photograph has its own choice (`bg_light`,
   `bg_dim`, `bg_sepia`), stamped on the root as data attributes. Four states
   as always: bare :root is Light, the media query is System-dark (Dim) on an
   unstamped root, and [data-theme] wins over both. `gradient` is the painted
   wash and needs no rule -- it is what the token already holds. Black has no
   photograph.

   Generated from host/store.BACKGROUNDS; test_theme_backgrounds asserts this
   block and that allowlist never drift apart. Rooted at the shell's /static
   so a module's own copy of this file, served under /embed/<id>/, paints the
   same photograph when opened on its own (issue 172). */
:root[data-theme="light"][data-bg-light="light-1"] { --bg-image: url("/static/images/light-1.jpg"); }
:root[data-theme="light"][data-bg-light="light-2"] { --bg-image: url("/static/images/light-2.jpg"); }
:root[data-theme="light"][data-bg-light="light-3"] { --bg-image: url("/static/images/light-3.jpg"); }

@media not all and (prefers-color-scheme: dark) {
  :root:not([data-theme])[data-bg-light="light-1"] { --bg-image: url("/static/images/light-1.jpg"); }
  :root:not([data-theme])[data-bg-light="light-2"] { --bg-image: url("/static/images/light-2.jpg"); }
  :root:not([data-theme])[data-bg-light="light-3"] { --bg-image: url("/static/images/light-3.jpg"); }
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme])[data-bg-dim="dim-1"] { --bg-image: url("/static/images/dim-1.jpg"); }
  :root:not([data-theme])[data-bg-dim="dim-2"] { --bg-image: url("/static/images/dim-2.jpg"); }
  :root:not([data-theme])[data-bg-dim="dim-3"] { --bg-image: url("/static/images/dim-3.jpg"); }
}

:root[data-theme="dim"][data-bg-dim="dim-1"] { --bg-image: url("/static/images/dim-1.jpg"); }
:root[data-theme="dim"][data-bg-dim="dim-2"] { --bg-image: url("/static/images/dim-2.jpg"); }
:root[data-theme="dim"][data-bg-dim="dim-3"] { --bg-image: url("/static/images/dim-3.jpg"); }

:root[data-theme="black"][data-bg-black="black-1"] { --bg-image: url("/static/images/black-1.jpg"); }
:root[data-theme="black"][data-bg-black="black-2"] { --bg-image: url("/static/images/black-2.jpg"); }
:root[data-theme="black"][data-bg-black="black-3"] { --bg-image: url("/static/images/black-3.jpg"); }

/* Black wearing a photograph: the panes turn to smoked glass so the light in
   the picture reads through them. At 76% `--text-2` holds 4.5:1 even over
   the brightest core of every Black photograph, before the blur softens it. Plain Black keeps
   its opaque #000 panes and no blur. */
:root[data-theme="black"][data-bg-black]:not([data-bg-black="gradient"]) {
  --pane:          rgba(0, 0, 0, 0.76);
  --pane-strong:   rgba(0, 0, 0, 0.88);
  --panel-blur:    blur(22px) saturate(140%);
}

:root[data-theme="sepia"][data-bg-sepia="sepia-1"] { --bg-image: url("/static/images/sepia-1.jpg"); }
:root[data-theme="sepia"][data-bg-sepia="sepia-2"] { --bg-image: url("/static/images/sepia-2.jpg"); }
:root[data-theme="sepia"][data-bg-sepia="sepia-3"] { --bg-image: url("/static/images/sepia-3.jpg"); }

/* A photograph is the ground now, so the drifting polyline that used to be it
   stands down -- but only where an image is actually in force, so a person who
   keeps `gradient` keeps the animation too. Black never draws it. */
:root[data-theme="light"]:not([data-bg-light="gradient"]) .ground-drift,
:root[data-theme="dim"]:not([data-bg-dim="gradient"]) .ground-drift,
:root[data-theme="sepia"]:not([data-bg-sepia="gradient"]) .ground-drift,
:root[data-theme="black"] .ground-drift { display: none; }
@media not all and (prefers-color-scheme: dark) {
  :root:not([data-theme]):not([data-bg-light="gradient"]) .ground-drift { display: none; }
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]):not([data-bg-dim="gradient"]) .ground-drift { display: none; }
}

/* Cover, centred, and fixed like the gradient it replaces. Harmless on a
   gradient, which is why it is unconditional. */
body {
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
}

/* Decorative full-bleed layers never capture pointer events (Ticket G). */
.is-decorative,
.ground-drift,
.chart-tooltip,
.chart-endpoint-halo,
.tile__chart .readout {
  pointer-events: none;
}

/* Interactive chrome sits above decoration; hit geometry matches paint. */
.hit-target,
.nav__link,
.chart__hit,
.chart-bar-group {
  pointer-events: auto;
}

/* Framed modules do not paint a second ground. `embedded.js` stamps
   `data-embedded`; a standalone page is unchanged. */
:root[data-embedded] body {
  /* Scrim so module headings keep contrast over a photograph (WCAG AA). */
  --embedded-ground: 72%;
  background-color: color-mix(in srgb, var(--bg) var(--embedded-ground), transparent);
  background-image: none;
}

/* A person's click out of a module frame, or across the shell, to a shell page
   (R-23h). Text links are otherwise unstyled here, so this one is named. */
a.to-shell {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ---------- Lattice components ----------
   Ported from the Lattice design system (claude.ai/artifact/Pje7ADkMvH9Bpe9PkorAuQ,
   components/bundle.css) onto these tokens, for pages that are not React:
   Button, Chip, Field, Toggle, Empty and the interactive Panel edge. Here,
   in the file every module serves, so a module page and the shell draw the
   same control the same way. */

:root { --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); }

.lt-btn {
  font: 600 var(--t-body)/1 var(--font-ui);
  height: 3rem;
  padding: 0 var(--space-5);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  box-sizing: border-box;
  border-radius: var(--radius-control);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: transform var(--duration-fast) var(--ease-out),
    background-color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
  user-select: none;
}
.lt-btn:active { transform: scale(0.97); }
.lt-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.lt-btn-sm { height: 2.5rem; padding: 0 var(--space-4); font-size: var(--t-small); }
.lt-btn-primary { background: var(--accent-fill); color: var(--on-accent); }
.lt-btn-primary:hover { filter: brightness(1.06); }
.lt-btn-secondary { background: var(--surface-2); color: var(--text); border-color: var(--border-strong); }
.lt-btn-secondary:hover { background: var(--surface-3); }
.lt-btn-ghost { background: transparent; color: var(--accent); }
.lt-btn-ghost:hover { background: var(--accent-soft); color: var(--accent-hover); }
.lt-btn-danger { background: transparent; color: var(--crit); border-color: var(--crit); }
.lt-btn-danger:hover { background: var(--crit-soft); }
.lt-btn svg { width: 1.25rem; height: 1.25rem; flex: none; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.lt-btn-arrow { transition: transform var(--duration-base) var(--ease-out); }
.lt-btn:hover .lt-btn-arrow { transform: translateX(3px); }

.lt-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 1.75rem;
  box-sizing: border-box;
  padding: 0 var(--space-3) 0 var(--space-2);
  border-radius: var(--radius-pill);
  font: 400 var(--t-small)/1.2 var(--font-ui);
  background: var(--surface-2);
  color: var(--text-2);
  border: 1px solid var(--border);
  white-space: nowrap;
}
.lt-chip-good { background: var(--good-soft); color: var(--good); border-color: transparent; }
.lt-chip-warn { background: var(--warn-soft); color: var(--warn); border-color: transparent; }
.lt-chip-crit { background: var(--crit-soft); color: var(--crit); border-color: transparent; }
.lt-chip-accent { background: var(--accent-soft); color: var(--accent); border-color: transparent; }
.lt-chip-glyph { font-weight: 600; }

/* The label lives in the field and lifts on focus or when filled; an error
   rewrites it ("Height — must be a number"), in the field, not below it. */
.lt-field { position: relative; display: block; max-width: 24rem; }
.lt-field-input {
  width: 100%;
  height: 3.75rem;
  box-sizing: border-box;
  padding: 1.5rem 3rem 0.5rem var(--space-4);
  font: 400 var(--t-body)/1.5 var(--font-ui);
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-control);
  outline: none;
  transition: border-color var(--duration-fast) var(--ease-out),
    background-color var(--duration-fast) var(--ease-out);
  -webkit-appearance: none;
  appearance: none;
}
.lt-field-input:hover { background: var(--surface-3); }
.lt-field-input:focus { border-color: var(--accent); background: var(--surface); box-shadow: 0 0 0 3px var(--accent-glow); }
.lt-field-label {
  position: absolute;
  left: var(--space-4);
  top: 1.125rem;
  font: 400 var(--t-body)/1.5rem var(--font-ui);
  color: var(--text-2);
  pointer-events: none;
  transform-origin: left top;
  transition: transform var(--duration-base) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.lt-field-input:focus + .lt-field-label,
.lt-field-input:not(:placeholder-shown) + .lt-field-label,
.lt-field-select + .lt-field-label { transform: translateY(-0.6875rem) scale(0.875); }
.lt-field-input:focus + .lt-field-label { color: var(--accent); }
.lt-field[data-state="invalid"] .lt-field-input { border-color: var(--crit); }
.lt-field[data-state="invalid"] .lt-field-label { color: var(--crit); }

.lt-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 3rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text);
  font: 400 var(--t-body)/1.3 var(--font-ui);
  cursor: pointer;
  text-align: left;
  border-radius: var(--radius-control);
}
.lt-toggle:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.lt-toggle-track {
  position: relative;
  flex: none;
  width: 3.25rem;
  height: 2rem;
  box-sizing: border-box;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  transition: background-color var(--duration-base) var(--ease-out), border-color var(--duration-base) var(--ease-out);
}
.lt-toggle-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: var(--radius-pill);
  background: var(--text-2);
  transition: transform var(--duration-base) var(--ease-spring), background-color var(--duration-base) var(--ease-out);
}
.lt-toggle[aria-checked="true"] .lt-toggle-track { background: var(--accent-fill); border-color: var(--accent-fill); }
.lt-toggle[aria-checked="true"] .lt-toggle-thumb { transform: translateX(1.25rem); background: var(--on-accent); }

.lt-empty {
  display: grid;
  justify-items: start;
  gap: var(--space-3);
  padding: var(--space-5);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-card);
}
.lt-empty-dash { font: 500 var(--t-metric)/1 var(--font-mono); color: var(--text-2); }
.lt-empty-title { font: 600 var(--t-h3)/1.3 var(--font-ui); margin: 0; }

/* Panel: a frosted pane with a 1px edge; an interactive one lights its edge. */
.lt-panel-interactive { cursor: pointer; transition: border-color var(--duration-fast) var(--ease-out), transform var(--duration-fast) var(--ease-out); }
.lt-panel-interactive:hover { border-color: var(--accent); }
.lt-panel-interactive:active { transform: scale(0.99); }

@media (prefers-reduced-motion: reduce) {
  .lt-btn, .lt-btn-arrow, .lt-field-input, .lt-field-label, .lt-toggle-track, .lt-toggle-thumb, .lt-panel-interactive { transition: none; }
  .lt-btn:active, .lt-panel-interactive:active { transform: none; }
}
