/* GENERATED by packages/pi-design/tools/gen-tokens.mjs — do not edit.
 * Barrel: reset + fonts + scale + tokens + components, in dependency order.
 * Source: plaza/apps/bakery/src/design-system/tokens
 * Regenerate: npm --workspace @pi-miniapps/pi-design run gen
 */

/* ─── reset.css ─── */
/**
 * The minimum reset a Pi mini app needs. Deliberately small — this ships to
 * apps with existing stylesheets, so anything opinionated here is a regression
 * somewhere else.
 */

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

html {
  /* Draws the caret, selection highlight and form controls in the right scheme.
     Apps that lock a scheme override this. */
  color-scheme: light dark;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
}

/* The grey flash on tap in WKWebView; every Pi surface handles its own press
   state, so the UA one is always wrong. */
* {
  -webkit-tap-highlight-color: transparent;
}

/* Anything under 16px makes iOS Safari zoom the viewport on focus, and the
   viewport meta cannot fully suppress it. Controls inherit the app's face
   rather than the UA's. */
input,
textarea,
select,
button {
  font: inherit;
  color: inherit;
}
input,
textarea,
select {
  font-size: max(16px, 1em);
}

img,
svg,
video,
canvas {
  display: block;
  max-width: 100%;
}

/* A DEFAULT, not an override — which is why it is wrapped in `:where()`.
 *
 * Bare, this selector is (0,1,0). The `input, textarea { … outline: none }` an
 * app writes to suppress the UA ring is (0,0,1), so the reset won that pair
 * whatever the load order and every field that already drew its own focus
 * treatment got a SECOND ring outside it, 2px away, in accent green. Measured,
 * not reasoned: on the real Droplets page a focused field computes
 * `outline: solid 2px rgb(3,130,71) @2px` OVER its own 1px border in Chromium,
 * WebKit and WebKit-with-touch alike — and a text field matches :focus-visible
 * on a plain TAP, so this was on every user, not only keyboard ones.
 *
 * `:where()` takes the specificity to (0,0,0): an app that says nothing about
 * outline still gets Pi's ring on every focusable thing, and an app that draws
 * its own focus treatment wins with a plain element selector instead of
 * `!important`. Author origin still beats the UA sheet at any specificity, so
 * the ring continues to replace WebKit's rather than sitting beside it.
 */
:where(:focus-visible) {
  outline: 2px solid var(--color-accent-alt-default, currentColor);
  outline-offset: 2px;
}


/* ─── fonts.css ─── */
/**
 * Pi's typography, served from the mini app's own origin.
 *
 * Promoted out of apps/droplets/public/pi-type.css so every mini app draws from
 * one set of outlines instead of each re-deriving them. The five files are
 * sha256-identical to the ones the iOS app registers
 * (`DesignSystem/Sources/DesignSystem/Resources/Fonts`, listed in
 * `RegisterFonts.swift`), so a mini-app screen and the Pi screen behind it draw
 * the same glyphs.
 *
 * Same-origin on purpose: mini-app CSP is `default-src 'self'`, which covers
 * fonts, so a webfont CDN would simply be blocked — silently, since a missing
 * family falls back rather than erroring.
 *
 * urls are RELATIVE so the mount point stays a free variable, and they are
 * `./fonts/` — NOT `../fonts/` — because they resolve against the URL this
 * sheet is SERVED at, not its path on disk. mountPiDesign flattens css/ to the
 * mount root (css/pi-design.css -> <base>/pi-design.css) while keeping fonts
 * nested (<base>/fonts/<face>), so from <base>/pi-design.css the faces are at
 * ./fonts/. `../fonts/` resolves to /fonts/ at the site root, which is a 404 —
 * and a 404 font is SILENT: the page just renders in New York and SF Pro,
 * which is the exact bug this file exists to prevent. test/font-url.test.js
 * asserts the served bytes, not the source, so this cannot regress.
 *
 * Weight coverage is the trap this avoids. Pi ships DM Sans in 500 ONLY and
 * Grenette in 400/700 — no DM Sans regular, no DM Sans bold. A rule asking for
 * 600 against DM Sans gets WebKit's synthetic bold, which looks worse than the
 * SF Pro it replaces. Every weight declared here has a file behind it, and
 * `font-synthesis` refuses fake bold if one ever slips back in.
 */

@font-face {
  font-family: "Grenette Pro";
  src: url("./fonts/GrenettePro-Regular.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Grenette Pro";
  src: url("./fonts/GrenettePro-Italic.otf") format("opentype");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
/* Pi's only bold Grenette style is `body_alt_m_bold`; no heading uses it. Here
   so that emphasis inside serif copy has a real face to reach for. */
@font-face {
  font-family: "Grenette Pro";
  src: url("./fonts/GrenettePro-Bold.otf") format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
/* The file's legacy family name is "DM Sans Medium"; its typographic family is
   "DM Sans" at weight 500, which is what this declares. */
@font-face {
  font-family: "DM Sans";
  src: url("./fonts/DMSans-Medium.ttf") format("truetype");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
/* `Font.codeblock` — Pi's only monospace, and only ever for code. */
@font-face {
  font-family: "IBM Plex Mono";
  src: url("./fonts/IBMPlexMono-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  /* System faces stay behind Pi's, so a font that fails to load degrades to
     what the page would otherwise render rather than to Times. */
  --pi-font-heading: "Grenette Pro", ui-serif, Georgia, "Iowan Old Style", serif;
  --pi-font-body: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --pi-font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* plaza's typography tokens reference these names but never declare them —
     next/font declares them at the app root, and mini apps have no next/font.
     Declaring them here means type-scale.css resolves correctly if an app
     links it. --font-grenette-condensed points at the regular face because
     that is what it points at upstream; matching plaza means reproducing that.
   */
  --font-grenette: var(--pi-font-heading);
  --font-grenette-condensed: var(--pi-font-heading);
  --font-dm-sans: var(--pi-font-body);
  --font-ibm-plex-mono: var(--pi-font-mono);

  /* Tracking, as em so it holds at every step. Pi tracks 19 of its 20 styles
     negative (`Font+.swift`, `.tracking(…)` in points).
       -0.015em  heading_l/m/s   (-0.6/40, -0.48/32, -0.36/24)
       -0.02em   body_m, action_l, label_s
       -0.01em   heading_xs, body_s/xs, action_s/m, label_xs
        0        label_xxs — the one style Pi leaves alone */
  --pi-track-heading: -0.015em;
  --pi-track-tight: -0.02em;
  --pi-track-body: -0.01em;

  /* Line height. Native line box = size × the face's own line height (Grenette
     1.320, DM Sans 1.302) + the style's `lineSpacing`. lineSpacing sits BETWEEN
     lines, so it only applies once text wraps — which is why one-line labels
     get `--pi-lh-single` (the face's box, nothing added) and paragraphs get the
     tier Pi gives them. */
  --pi-lh-heading: 1.42; /* heading_xs/s/m: 18/24/32 + 1.8/2.4/3.2 */
  --pi-lh-para: 1.7; /* body_s, body_m, label_s once wrapped */
  --pi-lh-copy: 1.4; /* body_xs, action_* — Pi's tighter tier */
  --pi-lh-single: 1.3; /* one line of DM Sans or Grenette: the face's own box */

  /* Fake bold is the way this could look worse than doing nothing, so it is
     refused outright. `style` stays synthesised: DM Sans has no italic file. */
  font-synthesis: style;
  -webkit-font-synthesis: style;
}


/* ─── scale.css ─── */
/**
 * Radius, spacing and motion.
 *
 * Neither plaza's token layer nor Pi's colorsets carry these — plaza's live as
 * arbitrary Tailwind values scattered through 69 .tsx files (`rounded-[3rem]`,
 * `rounded-[0.625rem]`, `px-4`). Droplets independently grew 40 border-radius
 * declarations across 17 distinct values, which is what an absent scale looks
 * like in practice.
 *
 * The values below are read off bakery's cva maps where one exists (button and
 * chip geometry is quoted at each entry) and rounded to a 4px step elsewhere.
 * Namespaced `--pi-` so it is obvious these are ours, not plaza's.
 */

:root {
  /* Radius — `--pi-radius-pill` is button size=large's rounded-[3rem];
     `--pi-radius-md` is size=medium's rounded-[0.625rem]; `--pi-radius-chip`
     is chip small/badge's rounded-[48px]. */
  --pi-radius-xs: 4px;
  --pi-radius-sm: 8px;
  --pi-radius-md: 10px;
  --pi-radius-lg: 16px;
  --pi-radius-xl: 24px;
  --pi-radius-pill: 48px;
  --pi-radius-chip: 48px;
  --pi-radius-round: 50%;

  /* Spacing — 4px step. `--pi-space-4` (16px) is the button's constant px-4. */
  --pi-space-1: 4px;
  --pi-space-2: 8px;
  --pi-space-3: 12px;
  --pi-space-4: 16px;
  --pi-space-5: 20px;
  --pi-space-6: 24px;
  --pi-space-8: 32px;
  --pi-space-10: 40px;
  --pi-space-12: 48px;

  /* Control heights, from button's cva: h-14 (56px) large, h-10 (40px) medium. */
  --pi-control-lg: 56px;
  --pi-control-md: 40px;
  --pi-control-sm: 32px;

  /* Motion. `transition-colors` in bakery is Tailwind's default 150ms
     cubic-bezier(0.4, 0, 0.2, 1). */
  --pi-dur-fast: 100ms;
  --pi-dur: 150ms;
  --pi-dur-slow: 240ms;
  --pi-ease: cubic-bezier(0.4, 0, 0.2, 1);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --pi-dur-fast: 0ms;
    --pi-dur: 0ms;
    --pi-dur-slow: 0ms;
  }
}


/* ─── tokens.css (generated) ─── */
/* GENERATED by packages/pi-design/tools/gen-tokens.mjs — do not edit.
 * 99 semantic colours + 7 shadows, light and dark.
 * Source: plaza/apps/bakery/src/design-system/tokens
 * Regenerate: npm --workspace @pi-miniapps/pi-design run gen
 */

:root {
  --color-background: #FAF3EA;
  --color-background-alt: #F7EFE4;
  --color-contrast: #FCFAF7;
  --color-contrast-inverted: #6B6255;
  --color-base-contrast: #FCFAF7;
  --color-text-base-contrast: #FCFAF7;
  --color-text-primary: #1A4631;
  --color-text-primary-strong: #0D3C26;
  --color-text-primary-alt: #038247;
  --color-text-accent: #131212;
  --color-text-secondary: #655E55;
  --color-text-secondary-alt: #6B6255;
  --color-text-tertiary: #A69986;
  --color-text-secondary-base: #655E55;
  --color-text-primary-base: #131212;
  --color-placeholder: #BEB09D;
  --color-base-contrast-inverted: #3E3A35;
  --color-divider-stroke: #E1D3C0;
  --color-split-divider-stroke: #E1D3C0;
  --color-menu-stroke: #E9DDCD;
  --color-message-background: #F3EADE;
  --color-message-text: #131212;
  --color-text-alt-secondary: #077843;
  --color-text-alt-tertiary: #0A6E40;
  --color-input-surface: #FCFAF7;
  --color-input-border: #D9C9B4;
  --color-primary-default: #1A4631;
  --color-primary-hover: #1E3C2E;
  --color-primary-tap: #21322A;
  --color-button-accent-default: #1A4631;
  --color-button-accent-hover: #1E3C2E;
  --color-button-accent-tap: #21322A;
  --color-primary-alt-default: #FCFAF7;
  --color-primary-alt-hover: #FAF3EA;
  --color-primary-alt-tap: #F7EFE4;
  --color-secondary-default: #F5EADC;
  --color-secondary-hover: #E9DDCD;
  --color-secondary-tap: #E4D7C6;
  --color-tertiary-default: #038247;
  --color-tertiary-hover: #077843;
  --color-tertiary-tap: #0A6E40;
  --color-accent-default: #1A4631;
  --color-accent-hover: #1E3C2E;
  --color-accent-tap: #21322A;
  --color-accent-alt-default: #038247;
  --color-accent-alt-hover: #077843;
  --color-accent-alt-tap: #0A6E40;
  --color-button-accent-alt-default: #038247;
  --color-fill-default: #ECE1D2;
  --color-fill-hover: #E9DDCD;
  --color-fill-tap: #E4D7C6;
  --color-button-fill-hover: #E9DDCD;
  --color-button-fill-tap: #E4D7C6;
  --color-fill-alt-default: #FCFAF7;
  --color-fill-alt-hover: #FAF3EA;
  --color-fill-alt-tap: #F7EFE4;
  --color-on-image-default: #FCFAF7;
  --color-on-image-hover: #FAF3EA;
  --color-on-image-tap: #F7EFE4;
  --color-quarternary-default: #A69986;
  --color-quarternary-hover: #9C907E;
  --color-quarternary-tap: #938776;
  --color-error-default: #D42600;
  --color-error-hover: #C72400;
  --color-error-tap: #BB2100;
  --color-disable-stroke: #D9C9B4;
  --color-disabled-fill: #C2B39F;
  --color-button-disabled-fill: #BEB09D;
  --color-default: #FAF3EA;
  --color-default-hover: #F5EEE5;
  --color-default-tap: #F0E9E1;
  --color-edge-stroke: #FFFFFF;
  --color-tile-contrast: #FFFFFF;
  --color-tile-default: #FAF3EA;
  --color-tile-hover: #F7EFE4;
  --color-tile-tap: #F3EADE;
  --color-card-default: #FCFAF7;
  --color-card-hover: #FAF3EA;
  --color-card-tap: #F7EFE3;
  --color-card-edge-stroke: #F5EADC;
  --color-panel-stroke: #E3D4BF;
  --color-feed-feature-intro-graphic: #FAF3EA;
  --color-menu-background: #FCFAF7;
  --color-menu-bg-hover: #FAF3EA;
  --color-menu-bg-tap: #ECE1D2;
  --color-sidebar-logo: #6B6255;
  --color-modal-backlay: rgba(107,98,85,0.36);
  --color-modal-background: #FCFAF7;
  --color-modal-stroke: #E9DDCD;
  --color-top-fade1: #FAF3EA;
  --color-top-fade2: #F5EEDF;
  --color-progress-highlight: #7FC099;
  --color-progress-base: #038247;
  --color-misc-scrollbar: #C2B39F;
  --color-narration-backdrop: rgba(245,234,220,0.2);
  --color-image-overlay-strong: rgba(13,60,38,0.7);
  --color-image-overlay-mid: rgba(13,60,38,0.5);
  --color-skeleton-base: rgba(247,239,227,1);
  --color-skeleton-shimmer: rgba(159,147,120,0.15);

  --shadow-shadow-1: 0px 6px 24px -2px rgba(94, 68, 15, 0.12);
  --shadow-shadow-2: 0px -6px 24px -2px rgba(236, 227, 208, 0.65);
  --shadow-shadow-3: 0px 2px 16px -6px rgba(0, 0, 0, 0.1), 0px 12px 32px -6px #e4dbc8;
  --shadow-shadow-4: 0px 6px 24px -2px rgba(94, 68, 15, 0.12);
  --shadow-toast-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.44);
  --shadow-modal-shadow: 0px 2px 16px -6px rgba(0, 0, 0, 0.1), 0px 12px 20px -6px rgba(94, 68, 15, 0.12);
  --shadow-menu-shadow: 0px 2px 16px -6px rgba(0, 0, 0, 0.1), 0px 12px 20px -6px rgba(94, 68, 15, 0.12);
}

:root[data-theme="dark"],
.dark {
  --color-background: #131212;
  --color-background-alt: #1A1918;
  --color-contrast: #1A1918;
  --color-contrast-inverted: #F0EEEB;
  --color-base-contrast: #242322;
  --color-text-base-contrast: #1A1918;
  --color-text-primary: #D8D4CE;
  --color-text-primary-strong: #F7EFE3;
  --color-text-primary-alt: #33C782;
  --color-text-accent: #FCFAF7;
  --color-text-secondary: #B4AFA7;
  --color-text-secondary-alt: #C2B39F;
  --color-text-tertiary: #AAA6A1;
  --color-text-secondary-base: #B4AFA7;
  --color-text-primary-base: #D8D4CE;
  --color-placeholder: #AAA6A1;
  --color-base-contrast-inverted: #F0EEEB;
  --color-divider-stroke: #504A42;
  --color-split-divider-stroke: #595249;
  --color-menu-stroke: #3E3A35;
  --color-message-background: #2D2B29;
  --color-message-text: #D8D4CE;
  --color-text-alt-secondary: #5FB386;
  --color-text-alt-tertiary: #7FC099;
  --color-input-surface: #2C2A28;
  --color-input-border: #4B4844;
  --color-primary-default: #3D9C6E;
  --color-primary-hover: #1E3C2E;
  --color-primary-tap: #21322A;
  --color-button-accent-default: #289A62;
  --color-button-accent-hover: #43A774;
  --color-button-accent-tap: #5FB386;
  --color-primary-alt-default: #1B1917;
  --color-primary-alt-hover: #242322;
  --color-primary-alt-tap: #302E2B;
  --color-secondary-default: #33312E;
  --color-secondary-hover: #4B4844;
  --color-secondary-tap: #56534F;
  --color-tertiary-default: #43A774;
  --color-tertiary-hover: #5FB386;
  --color-tertiary-tap: #7FC099;
  --color-accent-default: #3D9C6E;
  --color-accent-hover: #1E3C2E;
  --color-accent-tap: #21322A;
  --color-accent-alt-default: #43A774;
  --color-accent-alt-hover: #5FB386;
  --color-accent-alt-tap: #7FC099;
  --color-button-accent-alt-default: #43A774;
  --color-fill-default: #413E3B;
  --color-fill-hover: #4B4844;
  --color-fill-tap: #56534F;
  --color-button-fill-hover: #47423B;
  --color-button-fill-tap: #504A42;
  --color-fill-alt-default: #1B1917;
  --color-fill-alt-hover: #242322;
  --color-fill-alt-tap: #302E2B;
  --color-on-image-default: #1B1917;
  --color-on-image-hover: #242322;
  --color-on-image-tap: #302E2B;
  --color-quarternary-default: #AAA6A1;
  --color-quarternary-hover: #B6B3B0;
  --color-quarternary-tap: #C2C0BD;
  --color-error-default: #DE5A3D;
  --color-error-hover: #E1674D;
  --color-error-tap: #E3745C;
  --color-disable-stroke: #5A5753;
  --color-disabled-fill: #787975;
  --color-button-disabled-fill: #AAA6A1;
  --color-default: #242322;
  --color-default-hover: #23211E;
  --color-default-tap: #282622;
  --color-edge-stroke: #47423B;
  --color-tile-contrast: #FFFFFF;
  --color-tile-default: #242322;
  --color-tile-hover: #302E2B;
  --color-tile-tap: #33312E;
  --color-card-default: #242322;
  --color-card-hover: #2D2B29;
  --color-card-tap: #33312E;
  --color-card-edge-stroke: #33312E;
  --color-panel-stroke: #4B4844;
  --color-feed-feature-intro-graphic: #FAF3EA;
  --color-menu-background: #2D2B29;
  --color-menu-bg-hover: #1A1918;
  --color-menu-bg-tap: #1A1918;
  --color-sidebar-logo: #F0EEEB;
  --color-modal-backlay: rgba(45, 43, 41, 0.65);
  --color-modal-background: #1A1918;
  --color-modal-stroke: #3E3A35;
  --color-top-fade1: #131212;
  --color-top-fade2: #131212;
  --color-progress-highlight: #7FC099;
  --color-progress-base: #33C782;
  --color-misc-scrollbar: #787975;
  --color-narration-backdrop: rgba(36,35,34,0.3);
  --color-image-overlay-strong: rgba(0,0,0,0.7);
  --color-image-overlay-mid: rgba(0,0,0,0.5);
  --color-skeleton-base: rgba(51,49,46,1);
  --color-skeleton-shimmer: rgba(200,200,200,0.1);

  --shadow-shadow-1: 0px 6px 24px -2px rgba(0, 0, 0, 0.3);
  --shadow-shadow-2: 0px -6px 24px -2px rgba(19, 18, 18, 0.65);
  --shadow-shadow-3: 0px 2px 16px -6px rgba(0, 0, 0, 0.2), 0px 12px 32px -6px rgba(53, 51, 49, 0.8);
  --shadow-shadow-4: 0px 6px 24px -2px rgba(0, 0, 0, 0.3);
  --shadow-toast-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.44);
  --shadow-modal-shadow: 0px 2px 16px -6px rgba(0, 0, 0, 0.2), 0px 12px 20px -6px rgba(0, 0, 0, 0.45);
  --shadow-menu-shadow: 0px 2px 16px -6px rgba(0, 0, 0, 0.1), 0px 12px 20px -6px rgba(0, 0, 0, 0.1);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not(.light) {
    --color-background: #131212;
    --color-background-alt: #1A1918;
    --color-contrast: #1A1918;
    --color-contrast-inverted: #F0EEEB;
    --color-base-contrast: #242322;
    --color-text-base-contrast: #1A1918;
    --color-text-primary: #D8D4CE;
    --color-text-primary-strong: #F7EFE3;
    --color-text-primary-alt: #33C782;
    --color-text-accent: #FCFAF7;
    --color-text-secondary: #B4AFA7;
    --color-text-secondary-alt: #C2B39F;
    --color-text-tertiary: #AAA6A1;
    --color-text-secondary-base: #B4AFA7;
    --color-text-primary-base: #D8D4CE;
    --color-placeholder: #AAA6A1;
    --color-base-contrast-inverted: #F0EEEB;
    --color-divider-stroke: #504A42;
    --color-split-divider-stroke: #595249;
    --color-menu-stroke: #3E3A35;
    --color-message-background: #2D2B29;
    --color-message-text: #D8D4CE;
    --color-text-alt-secondary: #5FB386;
    --color-text-alt-tertiary: #7FC099;
    --color-input-surface: #2C2A28;
    --color-input-border: #4B4844;
    --color-primary-default: #3D9C6E;
    --color-primary-hover: #1E3C2E;
    --color-primary-tap: #21322A;
    --color-button-accent-default: #289A62;
    --color-button-accent-hover: #43A774;
    --color-button-accent-tap: #5FB386;
    --color-primary-alt-default: #1B1917;
    --color-primary-alt-hover: #242322;
    --color-primary-alt-tap: #302E2B;
    --color-secondary-default: #33312E;
    --color-secondary-hover: #4B4844;
    --color-secondary-tap: #56534F;
    --color-tertiary-default: #43A774;
    --color-tertiary-hover: #5FB386;
    --color-tertiary-tap: #7FC099;
    --color-accent-default: #3D9C6E;
    --color-accent-hover: #1E3C2E;
    --color-accent-tap: #21322A;
    --color-accent-alt-default: #43A774;
    --color-accent-alt-hover: #5FB386;
    --color-accent-alt-tap: #7FC099;
    --color-button-accent-alt-default: #43A774;
    --color-fill-default: #413E3B;
    --color-fill-hover: #4B4844;
    --color-fill-tap: #56534F;
    --color-button-fill-hover: #47423B;
    --color-button-fill-tap: #504A42;
    --color-fill-alt-default: #1B1917;
    --color-fill-alt-hover: #242322;
    --color-fill-alt-tap: #302E2B;
    --color-on-image-default: #1B1917;
    --color-on-image-hover: #242322;
    --color-on-image-tap: #302E2B;
    --color-quarternary-default: #AAA6A1;
    --color-quarternary-hover: #B6B3B0;
    --color-quarternary-tap: #C2C0BD;
    --color-error-default: #DE5A3D;
    --color-error-hover: #E1674D;
    --color-error-tap: #E3745C;
    --color-disable-stroke: #5A5753;
    --color-disabled-fill: #787975;
    --color-button-disabled-fill: #AAA6A1;
    --color-default: #242322;
    --color-default-hover: #23211E;
    --color-default-tap: #282622;
    --color-edge-stroke: #47423B;
    --color-tile-contrast: #FFFFFF;
    --color-tile-default: #242322;
    --color-tile-hover: #302E2B;
    --color-tile-tap: #33312E;
    --color-card-default: #242322;
    --color-card-hover: #2D2B29;
    --color-card-tap: #33312E;
    --color-card-edge-stroke: #33312E;
    --color-panel-stroke: #4B4844;
    --color-feed-feature-intro-graphic: #FAF3EA;
    --color-menu-background: #2D2B29;
    --color-menu-bg-hover: #1A1918;
    --color-menu-bg-tap: #1A1918;
    --color-sidebar-logo: #F0EEEB;
    --color-modal-backlay: rgba(45, 43, 41, 0.65);
    --color-modal-background: #1A1918;
    --color-modal-stroke: #3E3A35;
    --color-top-fade1: #131212;
    --color-top-fade2: #131212;
    --color-progress-highlight: #7FC099;
    --color-progress-base: #33C782;
    --color-misc-scrollbar: #787975;
    --color-narration-backdrop: rgba(36,35,34,0.3);
    --color-image-overlay-strong: rgba(0,0,0,0.7);
    --color-image-overlay-mid: rgba(0,0,0,0.5);
    --color-skeleton-base: rgba(51,49,46,1);
    --color-skeleton-shimmer: rgba(200,200,200,0.1);

    --shadow-shadow-1: 0px 6px 24px -2px rgba(0, 0, 0, 0.3);
    --shadow-shadow-2: 0px -6px 24px -2px rgba(19, 18, 18, 0.65);
    --shadow-shadow-3: 0px 2px 16px -6px rgba(0, 0, 0, 0.2), 0px 12px 32px -6px rgba(53, 51, 49, 0.8);
    --shadow-shadow-4: 0px 6px 24px -2px rgba(0, 0, 0, 0.3);
    --shadow-toast-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.44);
    --shadow-modal-shadow: 0px 2px 16px -6px rgba(0, 0, 0, 0.2), 0px 12px 20px -6px rgba(0, 0, 0, 0.45);
    --shadow-menu-shadow: 0px 2px 16px -6px rgba(0, 0, 0, 0.1), 0px 12px 20px -6px rgba(0, 0, 0, 0.1);
  }
}


/* ─── components.css ─── */
/**
 * Pi components for plain HTML.
 *
 * Geometry and state colours are transcribed from bakery's own cva maps — the
 * source file and variant key is quoted above each block, so a reviewer can
 * diff this against upstream by hand. Nothing here is invented where an
 * upstream value exists.
 *
 * Variants are DATA ATTRIBUTES, not modifier classes:
 *
 *     <button class="pi-btn" data-variant="primary" data-size="large">Send</button>
 *
 * because cva's compoundVariants are precedence rules, and CSS specificity
 * already implements exactly that: `.pi-btn[data-variant="x"]` is (0,2,0) and
 * `.pi-btn[data-variant="x"][data-size="y"]` is (0,3,0), so a compound wins
 * over its parts for free. It also interpolates cleanly into the innerHTML
 * templating mini apps use.
 *
 * Everything is additive and inert until used — an app that links this file and
 * uses none of it renders exactly as before.
 *
 * NOT included: typography utilities (see type-scale.css for why), icons
 * (bakery gets them through @svgr/webpack, which cannot survive a no-build
 * port), and anything requiring React state.
 */

/* ══════════════════════════════════════════════════════════════ button
 * bakery: components/buttons/button.tsx — buttonVariants cva
 * base: inline-flex items-center justify-center whitespace-nowrap
 *       transition-colors disabled:pointer-events-none disabled:opacity-50
 */

.pi-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  gap: 6px; /* gap-1.5, all sizes */
  border: 0;
  cursor: pointer;
  text-decoration: none;
  font-family: var(--pi-font-body);
  transition: background-color var(--pi-dur) var(--pi-ease),
    color var(--pi-dur) var(--pi-ease), border-color var(--pi-dur) var(--pi-ease);
}

.pi-btn:disabled,
.pi-btn[aria-disabled="true"] {
  pointer-events: none;
  opacity: 0.5;
}

/* — sizes ————————————————————————————————————————————————————— */

/* size=large: h-14 w-full min-w-32 max-w-[22.0625rem] rounded-[3rem] px-4 */
.pi-btn[data-size="large"] {
  height: var(--pi-control-lg);
  width: 100%;
  min-width: 128px;
  max-width: 22.0625rem;
  padding-inline: var(--pi-space-4);
  border-radius: var(--pi-radius-pill);
  font-size: 1.125rem; /* Action-M 18px */
  line-height: var(--pi-lh-copy);
  letter-spacing: var(--pi-track-tight);
  font-weight: 500;
}

/* size=medium: h-10 w-fit min-w-24 rounded-[0.625rem] px-4 */
.pi-btn[data-size="medium"] {
  height: var(--pi-control-md);
  width: fit-content;
  min-width: 96px;
  padding-inline: var(--pi-space-4);
  border-radius: var(--pi-radius-md);
  font-size: 1rem; /* Action-S 16px */
  line-height: var(--pi-lh-copy);
  letter-spacing: var(--pi-track-body);
  font-weight: 500;
}

/* size=large-tertiary: h-14 w-fit rounded-[3rem] px-4 antialiased */
.pi-btn[data-size="large-tertiary"] {
  height: var(--pi-control-lg);
  width: fit-content;
  padding-inline: var(--pi-space-4);
  border-radius: var(--pi-radius-pill);
  font-size: 1.125rem;
  line-height: var(--pi-lh-copy);
  letter-spacing: var(--pi-track-tight);
  font-weight: 500;
  -webkit-font-smoothing: antialiased;
}

/* — variants —————————————————————————————————————————————————— */

/* variant=primary: !bg-button-accent-default text-base-contrast */
.pi-btn[data-variant="primary"] {
  background: var(--color-button-accent-default);
  color: var(--color-base-contrast);
}
.pi-btn[data-variant="primary"]:hover {
  background: var(--color-button-accent-hover);
}
.pi-btn[data-variant="primary"]:active {
  background: var(--color-button-accent-tap);
}
/* compound {variant:primary}: disabled is a FILL not an opacity-only fade —
   disabled:!bg-button-accent-hover + !opacity-30, label stays base-contrast. */
.pi-btn[data-variant="primary"]:disabled,
.pi-btn[data-variant="primary"][aria-disabled="true"] {
  background: var(--color-button-accent-hover);
  color: var(--color-base-contrast);
  opacity: 0.3;
}
/* compound {variant:primary, size:medium}: hover/active keep the 10px radius */
.pi-btn[data-variant="primary"][data-size="medium"]:hover,
.pi-btn[data-variant="primary"][data-size="medium"]:active {
  border-radius: var(--pi-radius-md);
}

/* variant=secondary: border border-divider-stroke bg-background text-text-secondary */
.pi-btn[data-variant="secondary"] {
  border: 1px solid var(--color-divider-stroke);
  background: var(--color-background);
  color: var(--color-text-secondary);
}
.pi-btn[data-variant="secondary"]:hover {
  background: var(--color-secondary-hover);
}
.pi-btn[data-variant="secondary"]:active {
  background: var(--color-secondary-tap);
}
/* compound {variant:secondary, size:medium}: bg-transparent */
.pi-btn[data-variant="secondary"][data-size="medium"] {
  background: transparent;
}

/* variant=ghost / primary-alt: bg-primary-alt-default text-text-secondary */
.pi-btn[data-variant="ghost"],
.pi-btn[data-variant="primary-alt"] {
  background: var(--color-primary-alt-default);
  color: var(--color-text-secondary);
}
.pi-btn[data-variant="primary-alt"] {
  border: 1px solid var(--color-divider-stroke);
}
.pi-btn[data-variant="ghost"]:hover,
.pi-btn[data-variant="primary-alt"]:hover {
  background: var(--color-primary-alt-hover);
}
.pi-btn[data-variant="ghost"]:active,
.pi-btn[data-variant="primary-alt"]:active {
  background: var(--color-primary-alt-tap);
}
/* compounds {ghost|primary-alt, medium}: bg-transparent */
.pi-btn[data-variant="ghost"][data-size="medium"],
.pi-btn[data-variant="primary-alt"][data-size="medium"] {
  background: transparent;
}

/* variant=tertiary: bg-transparent text-tertiary-default */
.pi-btn[data-variant="tertiary"] {
  background: transparent;
  color: var(--color-tertiary-default);
}
.pi-btn[data-variant="tertiary"]:hover {
  color: var(--color-tertiary-hover);
}
.pi-btn[data-variant="tertiary"]:active {
  color: var(--color-tertiary-tap);
}

/* variant=negative: bg-error-default text-base-contrast */
.pi-btn[data-variant="negative"] {
  background: var(--color-error-default);
  color: var(--color-base-contrast);
}
.pi-btn[data-variant="negative"]:hover {
  background: var(--color-error-hover);
}
.pi-btn[data-variant="negative"]:active {
  background: var(--color-error-tap);
}
/* compound {negative, large}: px-6 */
.pi-btn[data-variant="negative"][data-size="large"] {
  padding-inline: var(--pi-space-6);
}
/* compound {negative, medium}: outlined, not filled */
.pi-btn[data-variant="negative"][data-size="medium"] {
  border: 1px solid var(--color-error-default);
  background: transparent;
  color: var(--color-error-default);
}
.pi-btn[data-variant="negative"][data-size="medium"]:hover {
  border-color: var(--color-error-hover);
  background: transparent;
  color: var(--color-error-hover);
}
.pi-btn[data-variant="negative"][data-size="medium"]:active {
  border-color: var(--color-error-tap);
  background: transparent;
  color: var(--color-error-tap);
}

/* variant=on-image: for overlays on photography */
.pi-btn[data-variant="on-image"] {
  background: var(--color-on-image-default);
  color: var(--color-text-secondary);
  box-shadow: var(--shadow-shadow-1);
}
.pi-btn[data-variant="on-image"]:hover {
  background: var(--color-on-image-hover);
}
.pi-btn[data-variant="on-image"]:active {
  background: var(--color-on-image-tap);
}

/* ══════════════════════════════════════════════════════════════ icon button */

.pi-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: var(--pi-control-md);
  height: var(--pi-control-md);
  padding: 0;
  border: 0;
  border-radius: var(--pi-radius-round);
  background: var(--color-fill-default);
  color: var(--color-text-secondary);
  cursor: pointer;
  transition: background-color var(--pi-dur) var(--pi-ease);
}
.pi-icon-btn:hover {
  background: var(--color-fill-hover);
}
.pi-icon-btn:active {
  background: var(--color-fill-tap);
}
.pi-icon-btn[data-variant="bare"] {
  background: transparent;
}
.pi-icon-btn[data-size="small"] {
  width: var(--pi-control-sm);
  height: var(--pi-control-sm);
}
.pi-icon-btn:disabled {
  pointer-events: none;
  opacity: 0.5;
}

/* ══════════════════════════════════════════════════════════════ chip / badge
 * bakery: components/chips/chip.tsx — chipVariants cva
 */

.pi-chip {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  min-width: 0;
  max-width: 100%;
  border: 1px solid var(--color-divider-stroke);
  background: transparent;
  color: var(--color-text-secondary);
  font-family: var(--pi-font-body);
  transition: background-color var(--pi-dur) var(--pi-ease),
    color var(--pi-dur) var(--pi-ease);
}

/* variant=badge — Consumer Library `Badge` (Figma 183:1009):
 * column, centered, gap 6px; padding 4×8px; pill; Label/XS; text-secondary-base
 */
.pi-chip[data-variant="badge"] {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: var(--pi-space-1) var(--pi-space-2);
  border-radius: var(--pi-radius-chip);
  background: var(--color-default);
  color: var(--color-text-secondary-base);
  font-size: 0.75rem; /* Label-XS 12px */
  line-height: var(--pi-lh-single);
  letter-spacing: var(--pi-track-body);
  font-weight: 500;
}
.pi-chip[data-variant="badge"]:hover {
  background: var(--color-button-fill-hover);
}
.pi-chip[data-variant="badge"]:active {
  background: var(--color-button-fill-tap);
}

/* variant=small — pill with border, px-12 py-8 */
.pi-chip[data-variant="small"] {
  padding: var(--pi-space-2) var(--pi-space-3);
  border-radius: var(--pi-radius-chip);
  font-size: 0.875rem;
  line-height: var(--pi-lh-single);
  letter-spacing: var(--pi-track-body);
}
.pi-chip[data-variant="small"]:active,
.pi-chip[data-variant="small"][data-state="active"] {
  background: var(--color-secondary-tap);
  color: var(--color-text-primary);
}

/* variant=large — h-56 rounded-10 px-24, used for selectors */
.pi-chip[data-variant="large"] {
  height: var(--pi-control-lg);
  width: 100%;
  max-width: 22.0625rem;
  padding: 0 var(--pi-space-6);
  border-radius: var(--pi-radius-md);
  background: var(--color-background);
}
.pi-chip[data-variant="large"][data-state="selected"] {
  justify-content: space-between;
  padding-right: 18px;
  background: var(--color-secondary-tap);
  color: var(--color-text-primary-base);
}

.pi-chip:disabled,
.pi-chip[data-state="disabled"] {
  cursor: not-allowed;
  border-color: transparent;
  background: var(--color-background);
  color: var(--color-disable-stroke);
}

/* ══════════════════════════════════════════════════════════════ card / tile */

.pi-card {
  display: block;
  background: var(--color-card-default);
  border-radius: var(--pi-radius-lg);
  overflow: hidden;
}
.pi-card[data-interactive] {
  cursor: pointer;
  transition: background-color var(--pi-dur) var(--pi-ease);
}
.pi-card[data-interactive]:hover {
  background: var(--color-card-hover);
}
.pi-card[data-interactive]:active {
  background: var(--color-card-tap);
}

/* ImageTile — Consumer Library, Figma 2860:28385 (horizontal) / 10083:27804
 * (vertical). PI-8941 item 5 lightens the default/hover/tap states, which is
 * why these use `default` rather than `card-default`.
 */
.pi-tile {
  display: flex;
  gap: var(--pi-space-4);
  padding: 10px; /* Figma: image inset 10px from the tile edge */
  border-radius: var(--pi-radius-lg);
  background: var(--color-default);
  cursor: pointer;
  transition: background-color var(--pi-dur) var(--pi-ease);
}
.pi-tile:hover {
  background: var(--color-default-hover);
}
.pi-tile:active {
  background: var(--color-default-tap);
}
.pi-tile[data-orientation="vertical"] {
  flex-direction: column;
  width: 158px;
}
.pi-tile__media {
  flex: 0 0 auto;
  width: 138px;
  height: 130px;
  border-radius: var(--pi-radius-md);
  object-fit: cover;
  background: var(--color-fill-default);
}
.pi-tile__body {
  display: flex;
  flex-direction: column;
  gap: var(--pi-space-2);
  min-width: 0;
  flex: 1 1 auto;
}
.pi-tile__chips {
  display: flex;
  gap: var(--pi-space-2);
  flex-wrap: wrap;
}
.pi-tile__title {
  font-family: var(--pi-font-body);
  font-size: 1rem;
  font-weight: 500;
  line-height: var(--pi-lh-single);
  letter-spacing: var(--pi-track-body);
  color: var(--color-text-primary-base);
  margin: 0;
}
.pi-tile__desc {
  font-family: var(--pi-font-body);
  font-size: 0.875rem;
  line-height: var(--pi-lh-copy);
  letter-spacing: var(--pi-track-body);
  color: var(--color-text-secondary);
  margin: 0;
}

/* ══════════════════════════════════════════════════════════════ avatar
 * PI-8941 item 6. Figma 10033:18312 (library) and the Droplets rows.
 *
 * "the 5 colors derived from the accent tokens" is FIVE PER-USER THEMES, not
 * five rungs of one ramp — `#accented/tone-*` resolves through an "Accent
 * tokens" collection that carries 5 modes (forest, ocean, nebula, glow,
 * bloom), which is exactly what PI-6964 "update token library to support
 * themes" is adding. Two avatars in one row share the token `#accented/tone-2`
 * and still render different colours because each node pins a different mode.
 *
 * Avatars bind tone-2 = accent-400 in their theme. Values read off Figma.
 * These are literals because plaza's token code has no theme axis yet; when
 * PI-6964 lands they become generated.
 */

:root {
  /* tone-2 (accent-400) per theme — what an avatar actually paints. */
  --pi-tone-forest: #3d9c6e;
  --pi-tone-ocean: #6c92bd;
  --pi-tone-nebula: #af77c4;
  --pi-tone-glow: #bb7b56;
  --pi-tone-bloom: #c5708b;

  /* tone-1 (accent-300) per theme — the library default, lighter. */
  --pi-tone-forest-1: #5fb386;
  --pi-tone-ocean-1: #96aec9;
  --pi-tone-nebula-1: #c9a2d1;
  --pi-tone-glow-1: #d0a287;
  --pi-tone-bloom-1: #d597a7;
}

.pi-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  position: relative;
  width: 28px;
  height: 28px;
  border-radius: var(--pi-radius-round);
  border: 2px solid var(--color-background);
  background: var(--pi-tone-forest);
  color: var(--color-base-contrast);
  font-family: var(--pi-font-body);
  /* Label/XXS — 10px, the one Pi style with no negative tracking. */
  font-size: 0.625rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0;
  text-transform: uppercase;
  user-select: none;
  overflow: hidden;
}
.pi-avatar[data-theme-tone="ocean"] { background: var(--pi-tone-ocean); }
.pi-avatar[data-theme-tone="nebula"] { background: var(--pi-tone-nebula); }
.pi-avatar[data-theme-tone="glow"] { background: var(--pi-tone-glow); }
.pi-avatar[data-theme-tone="bloom"] { background: var(--pi-tone-bloom); }

/* Pending invite: nobody has accepted, so there is no identity to colour —
   a flat disabled fill with NO letter.
   Literal, not var(--color-disabled-fill): Figma's #button/disabled-fill is
   #BEB09D and plaza's code has #C2B39F for the same name. Matching Figma is
   the brief, so the drift is pinned here rather than papered over. */
.pi-avatar[data-state="pending"] {
  background: #beb09d;
  color: transparent;
}
/* Draft: never sent. Reads as a hollow ring — page-background fill with a
   divider-stroke border. */
.pi-avatar[data-state="draft"] {
  background: var(--color-background);
  border-color: var(--color-divider-stroke);
  color: transparent;
}

.pi-avatar[data-size="lg"] {
  width: 36px;
  height: 36px;
  font-size: 0.875rem;
}
.pi-avatar > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Cluster: 40×40 box, A pinned top-left and B bottom-right at a (12,12)
   offset so the two discs overlap diagonally, clipped by the box. */
.pi-avatar-cluster {
  position: relative;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  overflow: hidden;
}
.pi-avatar-cluster > .pi-avatar {
  position: absolute;
}
.pi-avatar-cluster > .pi-avatar:first-child {
  top: 0;
  left: 0;
}
.pi-avatar-cluster > .pi-avatar:nth-child(2) {
  bottom: 0;
  right: 0;
}

/* ══════════════════════════════════════════════════════════════ chat card
 * PI-8941 item 8. Figma: Consumer library 10086:27966, and every row on the
 * Droplets Activities screens (Pi.next "Activity page states", 6103:89729).
 *
 * One skeleton for every state. Row height is exactly 75px: 16px padding +
 * a 43px content band (20px title + 8px gap + 15px subtitle) + 16px padding.
 * Rows stack with NO gap — the bottom divider does the separating.
 *
 * Three mutually-exclusive trailing configurations, set with data-trailing:
 *   badge-chevron · chevron · kebab
 */

.pi-chatcard {
  display: flex;
  align-items: center;
  gap: var(--pi-space-4);
  width: 100%;
  padding: var(--pi-space-4) 0;
  border: 0;
  border-bottom: 1px solid var(--color-divider-stroke);
  background: transparent;
  text-align: left;
  overflow: hidden;
  cursor: pointer;
  font-family: var(--pi-font-body);
  transition: background-color var(--pi-dur) var(--pi-ease);
}
/* No hover/pressed state exists in Figma — every variant in the file is
   state=Default. This is the smallest honest affordance rather than an
   invented one. */
.pi-chatcard:active {
  background: var(--color-card-tap);
}

.pi-chatcard__body {
  display: flex;
  flex-direction: column;
  gap: var(--pi-space-1);
  min-width: 0;
  flex: 1 0 0;
}
.pi-chatcard__text {
  display: flex;
  flex-direction: column;
  gap: var(--pi-space-2);
  min-width: 0;
}

/* Headings/All breakpoints/XS — Grenette Pro 18/110%, ls -1% */
.pi-chatcard__title {
  font-family: var(--pi-font-heading);
  font-size: 1.125rem;
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -0.01em;
  font-feature-settings: "liga" 0;
  color: var(--color-text-primary-base);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin: 0;
}

/* Body/All breakpoints/XS — DM Sans Medium 14/110%, ls -1% */
.pi-chatcard__subtitle {
  font-family: var(--pi-font-body);
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--color-text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin: 0;
}

.pi-chatcard__trailing {
  display: flex;
  align-items: center;
  gap: var(--pi-space-2);
  flex-shrink: 0;
}

/* — badge —————————————————————————————————————————————————————
 * Label/XS, 12/1.4, ls -1%. Height lands at 25px from the 4px padding.
 * The library's own default is the LIGHT bordered pill; the Droplets rows
 * override it to the two solid fills below.
 */
.pi-chatcard__badge {
  display: inline-flex;
  align-items: center;
  padding: var(--pi-space-1) var(--pi-space-2);
  border-radius: var(--pi-radius-chip);
  border: 1px solid var(--color-divider-stroke);
  background: var(--color-tile-default);
  color: var(--color-text-secondary);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
}
/* "Your turn" — it is this user's move. Stays until they respond. */
.pi-chatcard__badge[data-kind="turn"] {
  border-color: transparent;
  background: var(--color-base-contrast-inverted);
  color: var(--color-contrast);
}
/* "New" — answers from other people, not yet seen. Clears on viewing. */
.pi-chatcard__badge[data-kind="new"] {
  border-color: transparent;
  background: var(--color-accent-alt-default);
  color: var(--color-contrast);
}

/* — chevron / kebab ———————————————————————————————————————————— */

.pi-chatcard__chevron {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  color: var(--color-text-secondary);
}
.pi-chatcard__kebab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  padding: 6px;
  border: 0;
  border-radius: var(--pi-radius-md);
  /* Transparent on purpose — an affordance, not a filled button. */
  background: transparent;
  color: var(--color-text-secondary);
  cursor: pointer;
}
.pi-chatcard__kebab:active {
  background: var(--color-fill-hover);
}

/* ══════════════════════════════════════════════════════════════ message
 * PI-8941 item 1 adds #message/background-accent + #message/text-contrast for
 * the current user's own message in a group chat. Those two semantic names do
 * not exist in plaza's token code yet (they land with PI-6964), so they are
 * declared here with the values read directly off the Figma components, and
 * fall through to the generated token the moment plaza publishes them.
 */

:root {
  --color-message-background-accent: var(--color-accent-alt-default, #038247);
  --color-message-text-contrast: var(--color-neutral-25, #fcfaf7);
}

.pi-msg {
  max-width: 85%;
  padding: var(--pi-space-3) var(--pi-space-4);
  border-radius: var(--pi-radius-lg);
  background: var(--color-message-background);
  color: var(--color-message-text);
  font-family: var(--pi-font-heading);
  font-size: 1.125rem;
  line-height: 1.45;
  letter-spacing: var(--pi-track-body);
}
/* data-author="self" — the group-chat variant PI-8941 introduces. */
.pi-msg[data-author="self"] {
  margin-left: auto;
  background: var(--color-message-background-accent);
  color: var(--color-message-text-contrast);
}
.pi-msg__author {
  display: block;
  margin-bottom: var(--pi-space-1);
  font-family: var(--pi-font-body);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: var(--pi-lh-single);
  color: var(--color-text-secondary);
}

/* ══════════════════════════════════════════════════════════════ field */

.pi-field {
  width: 100%;
  min-height: var(--pi-control-lg);
  padding: var(--pi-space-3) var(--pi-space-4);
  border: 1px solid var(--color-input-border);
  border-radius: var(--pi-radius-md);
  background: var(--color-input-surface);
  color: var(--color-text-primary-base);
  font-family: var(--pi-font-body);
}
.pi-field::placeholder {
  color: var(--color-placeholder);
}
.pi-field:focus {
  outline: 2px solid var(--color-accent-alt-default);
  outline-offset: -1px;
}

/* ══════════════════════════════════════════════════════════════ menu
 * Figma 6103:86776 (220×88, two items) and 6583:14181 (220×52, one item).
 */

.pi-menu {
  min-width: 220px;
  padding: var(--pi-space-1) 0;
  border: 1px solid var(--color-menu-stroke);
  border-radius: var(--pi-radius-md);
  background: var(--color-card-default);
  box-shadow: var(--shadow-menu-shadow);
  overflow: hidden;
}
.pi-menu__item {
  display: flex;
  align-items: center;
  gap: var(--pi-space-3);
  width: 100%;
  height: 44px;
  padding: 0 var(--pi-space-4);
  border: 0;
  background: transparent;
  color: var(--color-text-primary-base);
  font-family: var(--pi-font-body);
  font-size: 0.9375rem;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
}
.pi-menu__item:hover {
  background: var(--color-fill-hover);
}
.pi-menu__item:active {
  background: var(--color-fill-tap);
}
.pi-menu__item[data-variant="destructive"] {
  color: var(--color-error-default);
}

/* ══════════════════════════════════════════════════════════════ dialog
 * Figma 6589:31651 (compact, no body), 6053:56078 "Leave this group?" and
 * 6691:117564 "End {Activity_name}?" (default), 6121:111283 / 6121:111291
 * (the rename pair, title + input). One skeleton, three widths: the five
 * Droplets modals differ only in which slots they fill and how wide they are.
 *
 * The container values are pixel-probed off those nodes and every one of them
 * already has a token: 24px uniform padding is `--pi-space-6`, the 16px gap
 * between every section is `--pi-space-4`, the 1px stroke is `#modal/stroke`,
 * and the two stacked drop shadows are `--shadow-modal-shadow` verbatim.
 *
 * NO CLOSE BUTTON, and none is coming: all five modals carry a 32×32 icon
 * button in the title frame and it is HIDDEN in all five, at an x that in
 * 6589:31651 overflows its own title frame. Dismissal is the scrim and Cancel.
 *
 * NO DIALOG BUTTON CLASSES either — every button in all five is already
 * expressible in `.pi-btn`, and reproducing them here would be a second place
 * for the button rules to drift from bakery's cva. Cancel is
 * `data-variant="tertiary" data-size="medium"` (transparent, label
 * `--color-tertiary-default` #038247, which is the measured ghost label; the
 * size supplies the measured h=40 / radius 10 / min-width 96 / px-16). The
 * destructive confirm is `data-variant="negative" data-size="medium"`, whose
 * compound above is already outlined-not-filled — i.e. the file encodes the
 * design's rule that a destructive confirm is never a fill. The non-destructive
 * primary (Save, OK) is `data-variant="primary" data-size="medium"`.
 * `data-variant="ghost"` is the wrong Cancel: its label is `--color-text-
 * secondary`, not the green the design draws.
 */

:root {
  /* Derived by circular fit at four independent arc points on the rendered
     card, exact. It is not a rung of the scale — sm 8 / md 10 / lg 16 / xl 24
     have no 20 between them — so it is named for the thing that uses it, the
     way `--color-message-background-accent` below is. */
  --pi-radius-dialog: 20px;
}

/* The backdrop and the centring box are one node: a second wrapper would only
   exist to be positioned identically. `--color-modal-backlay` is the token
   named for exactly this; the Figma nodes are isolated component specs with no
   overlay layer, so the value comes from the design system, not from taste. */
.pi-dialog-scrim {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  padding: var(--pi-space-6);
  background: var(--color-modal-backlay);
}

/* `.pi-dialog-scrim[data-state="closing"]` is reserved and deliberately carries
   no rules — exit animation is the app's, but the attribute it hangs off is the
   DS's, so two apps cannot invent two different names for the same moment. */

.pi-dialog {
  display: flex;
  flex-direction: column;
  gap: var(--pi-space-4);
  padding: var(--pi-space-6);
  /* `--color-background` (#FAF3EA), not `--color-modal-background` (#FCFAF7):
     the probe returns (250,243,234) and the nodes bind `#base/background`, so
     the token whose NAME fits is not the token the design uses. */
  background: var(--color-background);
  border: 1px solid var(--color-modal-stroke);
  border-radius: var(--pi-radius-dialog);
  box-shadow: var(--shadow-modal-shadow);
  max-width: 100%;
  /* A long title or a long body on a short viewport would otherwise overflow
     the grid area and put the confirm button somewhere unreachable. */
  max-height: 100%;
  overflow-y: auto;
}

/* Widths are an enumerated set rather than three numbers discovered one at a
   time. Vertical rhythm is not set anywhere: padding + gap reproduce the
   measured 24/25/16/66/16/40/24 = 211 for free. */
.pi-dialog[data-width="compact"] {
  width: 248px; /* 6589:31651 — title + actions, no body. */
}
.pi-dialog[data-width="default"] {
  width: 300px; /* 6053:56078, 6691:117564 — title + body + actions. */
}
.pi-dialog[data-width="input"] {
  width: 345px; /* 6121:111283, 6121:111291 — title + field + actions. */
}

/* Body/M — 18/1.4, ls -2%. `--color-text-primary-base` is #131212, the measured
   `#base/text-primary`; `--color-text-primary` is #1A4631, the green. */
.pi-dialog__title {
  margin: 0;
  font-family: var(--pi-font-body);
  font-size: 1.125rem;
  font-weight: 500;
  line-height: var(--pi-lh-copy);
  letter-spacing: var(--pi-track-tight);
  color: var(--color-text-primary-base);
  text-align: left;
}

/* Body/S — 16/1.4, ls -1%. */
.pi-dialog__body {
  margin: 0;
  font-family: var(--pi-font-body);
  font-size: 1rem;
  font-weight: 500;
  line-height: var(--pi-lh-copy);
  letter-spacing: var(--pi-track-body);
  color: var(--color-text-secondary);
}

/* Wraps a `.pi-field` and its error line as ONE section, so the 8px between a
   field and its message stays distinct from the 16px between sections. */
.pi-dialog__field {
  display: flex;
  flex-direction: column;
  gap: var(--pi-space-2);
}

/* Label/S — 14/1.4, ls -2%. The leading warning triangle is the app's inline
   SVG: the gap reserves room for a glyph this file does not ship (see header). */
.pi-dialog__error {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-family: var(--pi-font-body);
  font-size: 0.875rem;
  font-weight: 500;
  line-height: var(--pi-lh-copy);
  letter-spacing: var(--pi-track-tight);
  color: var(--color-error-default);
}

/* Cancel LEFT, confirm RIGHT, always — that order is constant across all five
   nodes. The ALIGNMENT is not: the confirmation modals (6053:56078 Leave,
   6691:117564 End activity) draw the row centred — 6691:117564 is a 300-wide
   card with 24 padding, so its content box is 252 and its 224-wide Actions frame
   sits at x=38, an equal 14px inset either side — while both rename modals
   (6121:111283, 6121:111291) draw it flush right.
   This was previously justified here as "the right-aligned nodes are the newer
   ones". That is not true: node ids rise monotonically within a file, and the
   right-aligned rename modals (6121:*) are OLDER than the centred End modal
   (6691:*). Nothing about age settles it, so nothing here pretends to — the DS
   ships both readings and each caller names the node it is building. The default
   stays flush-right so the rename family, the one with more instances, needs no
   attribute; the two confirmations pass data-align="center". */
.pi-dialog__actions {
  display: flex;
  gap: var(--pi-space-2);
  justify-content: flex-end;
}
.pi-dialog__actions[data-align="center"] {
  justify-content: center;
}

/* ══════════════════════════════════════════════════════════════ divider */

.pi-divider {
  height: 1px;
  border: 0;
  margin: 0;
  background: var(--color-divider-stroke);
}

/* ══════════════════════════════════════════════════════════════ empty state */

.pi-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--pi-space-3);
  padding: var(--pi-space-12) var(--pi-space-6);
  text-align: center;
}
.pi-empty__title {
  font-family: var(--pi-font-heading);
  font-size: 1.5rem;
  line-height: var(--pi-lh-heading);
  letter-spacing: var(--pi-track-heading);
  color: var(--color-text-primary);
  margin: 0;
}
.pi-empty__body {
  font-family: var(--pi-font-body);
  font-size: 1rem;
  line-height: var(--pi-lh-para);
  letter-spacing: var(--pi-track-body);
  color: var(--color-text-secondary);
  margin: 0;
  max-width: 30ch;
}

/* ══════════════════════════════════════════════════════════════ visually-hidden */

.pi-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;
}
