/*
 * The `.aebm` design system — port for the CalPal MCP server's public pages.
 * ===========================================================================
 *
 * Source of truth: nutrition-mtn/web-landing `src/app/globals.css` (tokens)
 * and `src/app/aebm.css` (components), described in guides/NEW_DESIGN.md.
 * Token values and the type/geometry ramp are copied verbatim so this server's
 * pages and the marketing site render as one product.
 *
 * Four deliberate departures from the source, each forced by this environment:
 *
 * 1. Plain CSS, no Tailwind and no React. The source leans on utilities and
 *    `cn()`; these two pages are hand-authored HTML served by Express, so every
 *    rule a page needs is written out here.
 *
 * 2. Tokens live on `:root`, not behind `@layer base`. There is no Tailwind
 *    layer stack to order against, and `@layer` would only lower specificity
 *    for no gain.
 *
 * 3. Tabs key off `aria-selected`, not `[data-state='active']`. The source
 *    targets the attribute Radix emits; these pages implement the WAI-ARIA tabs
 *    pattern by hand, so `data-state` never appears and that selector would
 *    silently never match — the exact invisible failure guides/NEW_DESIGN.md
 *    §14 warns about.
 *
 * 4. `.auth-shell` measures against the full viewport. The source subtracts
 *    `--localnav-height` for the site's sticky nav; these pages have no nav.
 *
 * Everything below `PROJECT EXTENSIONS` is new work for this server — code
 * blocks, copy chips, step lists and the connection motion have no counterpart
 * upstream. They are built from the same tokens and follow the same rules, so
 * a palette change moves them too.
 *
 * SCOPING (guides/NEW_DESIGN.md §3): every component rule is `.aebm` plus a
 * DESCENDANT selector. `.aebm` goes on <body>; a component class never shares
 * an element with it, or the rule cannot match.
 *
 * LIGHT ONLY (§2.4): there is no `.dark` block and no `prefers-color-scheme`
 * query anywhere in this file. `color-scheme: light` below is the whole story.
 */

/* ========================================================= design tokens */
/*
 * Values are bare HSL channels without the `hsl()` wrapper so they compose
 * with alpha: `hsl(var(--primary) / 0.12)`. Copied from the landing site's
 * globals.css — change a colour there and here, never in a component.
 */
:root {
  color-scheme: light;

  /* Surfaces, lowest to highest elevation. */
  --background: 240 10% 97%;      /* #F5F5F7 page canvas */
  --card: 0 0% 100%;              /* panels raised off the canvas */
  --card-foreground: 224 71.4% 4.1%;
  --popover: 0 0% 100%;
  --popover-foreground: 224 71.4% 4.1%;
  --muted: 220 14% 96%;           /* wells, skeletons, inset rows */
  --muted-foreground: 220 9% 38%; /* secondary text — 5.9:1 on the muted well */
  --secondary: 220 14% 92%;       /* hover fills, chip backgrounds */
  --secondary-foreground: 224 71.4% 10%;

  /* Text hierarchy. `--foreground-subtle` is tuned to clear 4.5:1 against the
     LIGHTEST surface it can land on (--muted), not merely against white. */
  --foreground: 224 71.4% 4.1%;
  --foreground-subtle: 220 9% 45%;

  /* Brand. */
  --primary: 146 63% 25%;         /* CalPal green #176A3D */
  --primary-foreground: 0 0% 100%;
  --accent: 120 60% 34%;
  --accent-foreground: 0 0% 100%;
  --ring: 146 50% 35%;

  /* Status. `-foreground` is text on the solid fill; `-muted` is the tinted
     background behind chips, banners and alerts. */
  --success: 146 63% 30%;
  --success-foreground: 0 0% 100%;
  --success-muted: 141 70% 95%;
  --warning: 28 87% 37%;
  --warning-foreground: 0 0% 100%;
  --warning-muted: 45 95% 93%;
  --info: 221 83% 45%;
  --info-foreground: 0 0% 100%;
  --info-muted: 214 95% 95%;
  --destructive: 0 72% 45%;
  --destructive-foreground: 0 0% 100%;
  --destructive-muted: 0 90% 96%;

  /* Lines. */
  --border: 220 13% 88%;
  --border-subtle: 220 13% 93%;
  --border-strong: 220 13% 80%;
  --input: 220 13% 88%;

  /* Elevation ink — tinted toward the page hue rather than pure black, so
     shadows read as depth instead of grime. */
  --shadow-color: 224 40% 10%;

  /* Data visualisation. */
  --chart-1: 146 63% 35%;
  --chart-2: 190 70% 38%;
  --chart-3: 221 83% 50%;
  --chart-4: 38 88% 45%;
  --chart-5: 280 55% 52%;

  --rating: 43 96% 56%;

  --radius: 0.75rem;
}

/* ============================================================ the root */

/*
 * Unscoped, and deliberately so: upstream the host application has already
 * zeroed the body margin before `aebm.css` loads. These two pages have no host
 * application, and this stylesheet is linked by nothing else, so the reset
 * belongs here. Kept to the document elements only.
 */
html,
body {
  margin: 0;
  min-height: 100%;
}
html { -webkit-text-size-adjust: 100%; }

.aebm {
  /* --- Fills --- */
  --fill: hsl(var(--card));
  --fill-secondary: hsl(var(--background));
  --fill-tertiary: hsl(var(--muted));
  --fill-quaternary: hsl(var(--secondary));

  /* --- Glyphs --- */
  --glyph-gray: hsl(var(--foreground));
  --glyph-gray-secondary: hsl(var(--muted-foreground));
  --glyph-gray-tertiary: hsl(var(--foreground-subtle));
  --glyph-blue: hsl(var(--info));
  --glyph-light: hsl(var(--background));

  /* --- Brand --- */
  --aebm-green: hsl(var(--primary));
  --button-fill: hsl(var(--primary));
  --button-fill-hover: hsl(var(--primary) / 0.88);
  --button-fill-active: hsl(var(--primary) / 0.8);
  --button-label: hsl(var(--primary-foreground));

  /* --- Typography --- */
  --font-family-base: -apple-system, BlinkMacSystemFont, 'SF Pro Display',
    'SF Pro Text', 'SF Pro Icons', 'Segoe UI', Roboto, 'Helvetica Neue',
    Helvetica, Arial, sans-serif;
  /* `font-src 'self'` in the server's CSP rules out a webfont, and the system
     stack is what the landing site ships anyway. */
  --font-family-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
    'Liberation Mono', monospace;

  /* --- Chrome --- */
  --localnav-border: hsl(var(--border));

  /* --- Geometry --- */
  --bento-gap: 12px;
  --bento-radius: 28px;
  --tile-inset: 40px;
  --card-gap: 20px;

  /* --- Motion --- */
  --ease-out-soft: cubic-bezier(0.28, 0.11, 0.32, 1);
  --ease-in-out-soft: cubic-bezier(0.4, 0, 0.22, 1);

  background: var(--fill);
  color: var(--glyph-gray);
  font-family: var(--font-family-base);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-size: 17px;
  line-height: 1.47059;
  letter-spacing: -0.022em;
  font-weight: 400;
}

@media (max-width: 1068px) {
  .aebm {
    --bento-radius: 24px;
    --tile-inset: 32px;
    --card-gap: 16px;
  }
}
@media (max-width: 734px) {
  .aebm {
    --bento-radius: 22px;
    --tile-inset: 24px;
  }
}

/*
 * Element resets. These are (0,1,1) and outrank any single-class utility, so
 * a subtree may only be wrapped in `.aebm` when its styling is ours — which,
 * on these two hand-authored pages, it entirely is. Every piece of text below
 * therefore carries an explicit ramp class.
 */
.aebm *,
.aebm *::before,
.aebm *::after { box-sizing: border-box; }

.aebm h1, .aebm h2, .aebm h3, .aebm h4, .aebm h5, .aebm h6,
.aebm p, .aebm figure, .aebm blockquote, .aebm dl, .aebm dd {
  margin: 0;
  font-weight: inherit;
  font-size: inherit;
  line-height: inherit;
  letter-spacing: inherit;
}
.aebm ul, .aebm ol {
  margin: 0;
  padding: 0;
  list-style: none;
}
.aebm section { padding-top: 0; padding-bottom: 0; }
.aebm svg { display: block; }
.aebm img { max-width: 100%; }
.aebm a { color: inherit; text-decoration: none; }
.aebm button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.aebm input { font: inherit; color: inherit; }
.aebm pre, .aebm code, .aebm kbd, .aebm samp {
  font-family: var(--font-family-mono);
  margin: 0;
}

/* Hidden helpers. `.hidden` is the hook the page scripts toggle; `[hidden]`
   is the platform's and must win over any `display` a component sets. */
.hidden,
[hidden] { display: none !important; }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Focus ring, tuned against the light canvas. Two rings — a light gap then
   the brand colour — so it reads on both the white card and the muted well. */
.aebm :focus-visible {
  outline: 2px solid hsl(var(--ring));
  outline-offset: 2px;
  border-radius: 8px;
}

/* ===================================================== layout primitives */

.aebm .aebm-content-width-s,
.aebm .aebm-content-width-m,
.aebm .aebm-content-width-l,
.aebm .aebm-static-width-l,
.aebm .aebm-viewport-min-xl {
  margin-left: auto;
  margin-right: auto;
  width: 100%;
}

@media (max-width: 734px) {
  .aebm .aebm-content-width-s { max-width: 87.5%; }
}
@media (min-width: 735px) and (max-width: 1068px) {
  .aebm .aebm-content-width-m { max-width: 692px; }
}
@media (min-width: 1069px) {
  .aebm .aebm-content-width-l,
  .aebm .aebm-static-width-l,
  .aebm .aebm-viewport-min-xl { max-width: 980px; }
}
@media (min-width: 1441px) {
  .aebm .aebm-viewport-min-xl { max-width: 1180px; }
}

/*
 * Spacing is a `large/medium/small` triple in one attribute, matched by
 * position: `^=` is large, `*=` medium, `$=` small. Written `.aebm [data-…]`
 * = (0,2,0), which is why they outrank the `.aebm section` reset (0,1,1) —
 * that is the whole reason spacing is attributes here rather than classes.
 *
 * THE TRIPLE PICKS THE STEP; THE BREAKPOINT PICKS THE SIZE. Each step resolves
 * to a DIFFERENT pixel value at each breakpoint, so the three numbers are not
 * three pixel values on one scale:
 *
 *   step   large (≥1069px)   medium (735–1068px)   small (≤734px)
 *   0      0                 0                     0
 *   1      20px              18px                  14px
 *   2      40px              36px                  28px
 *   3      60px              54px                  42px
 *   4      80px              72px                  56px
 *   5      100px             90px                  70px
 *   6      120px             108px                 84px
 *
 * So `6/4/5` is 120 / 72 / 70px — NOT 120 / 80 / 100. Reading the triple as one
 * scale is an easy mistake and it has shipped as a real bug upstream: `6/4/5`
 * is the gap BETWEEN two mid-page bands, and reusing it as a page top left
 * 120px of empty canvas above the title on five pages. A page top and a band
 * gap are different measurements; don't reuse one for the other.
 *
 * The interior-page top is `3/2/2` (60 / 36 / 28px). Keep new pages on it. The
 * one exception is a hero that owns a backdrop, where a larger top is filled by
 * the band rather than left blank — see the connect page's header.
 */
@media (min-width: 1069px) {
  .aebm [data-padding-v^="0/"] { padding-top: 0px; padding-bottom: 0px; }
  .aebm [data-padding-v^="1/"] { padding-top: 20px; padding-bottom: 20px; }
  .aebm [data-padding-v^="2/"] { padding-top: 40px; padding-bottom: 40px; }
  .aebm [data-padding-v^="3/"] { padding-top: 60px; padding-bottom: 60px; }
  .aebm [data-padding-v^="4/"] { padding-top: 80px; padding-bottom: 80px; }
  .aebm [data-padding-v^="5/"] { padding-top: 100px; padding-bottom: 100px; }
  .aebm [data-padding-v^="6/"] { padding-top: 120px; padding-bottom: 120px; }
  .aebm [data-padding-top^="0/"] { padding-top: 0px; }
  .aebm [data-padding-top^="1/"] { padding-top: 20px; }
  .aebm [data-padding-top^="2/"] { padding-top: 40px; }
  .aebm [data-padding-top^="3/"] { padding-top: 60px; }
  .aebm [data-padding-top^="4/"] { padding-top: 80px; }
  .aebm [data-padding-top^="5/"] { padding-top: 100px; }
  .aebm [data-padding-top^="6/"] { padding-top: 120px; }
  .aebm [data-padding-bottom^="0/"] { padding-bottom: 0px; }
  .aebm [data-padding-bottom^="1/"] { padding-bottom: 20px; }
  .aebm [data-padding-bottom^="2/"] { padding-bottom: 40px; }
  .aebm [data-padding-bottom^="3/"] { padding-bottom: 60px; }
  .aebm [data-padding-bottom^="4/"] { padding-bottom: 80px; }
  .aebm [data-padding-bottom^="5/"] { padding-bottom: 100px; }
  .aebm [data-padding-bottom^="6/"] { padding-bottom: 120px; }
  .aebm [data-margin-top^="0/"] { margin-top: 0px; }
  .aebm [data-margin-top^="1/"] { margin-top: 20px; }
  .aebm [data-margin-top^="2/"] { margin-top: 40px; }
  .aebm [data-margin-top^="3/"] { margin-top: 60px; }
  .aebm [data-margin-top^="4/"] { margin-top: 80px; }
  .aebm [data-margin-top^="5/"] { margin-top: 100px; }
  .aebm [data-margin-top^="6/"] { margin-top: 120px; }
}
@media (min-width: 735px) and (max-width: 1068px) {
  .aebm [data-padding-v*="/0/"] { padding-top: 0px; padding-bottom: 0px; }
  .aebm [data-padding-v*="/1/"] { padding-top: 18px; padding-bottom: 18px; }
  .aebm [data-padding-v*="/2/"] { padding-top: 36px; padding-bottom: 36px; }
  .aebm [data-padding-v*="/3/"] { padding-top: 54px; padding-bottom: 54px; }
  .aebm [data-padding-v*="/4/"] { padding-top: 72px; padding-bottom: 72px; }
  .aebm [data-padding-v*="/5/"] { padding-top: 90px; padding-bottom: 90px; }
  .aebm [data-padding-v*="/6/"] { padding-top: 108px; padding-bottom: 108px; }
  .aebm [data-padding-top*="/0/"] { padding-top: 0px; }
  .aebm [data-padding-top*="/1/"] { padding-top: 18px; }
  .aebm [data-padding-top*="/2/"] { padding-top: 36px; }
  .aebm [data-padding-top*="/3/"] { padding-top: 54px; }
  .aebm [data-padding-top*="/4/"] { padding-top: 72px; }
  .aebm [data-padding-top*="/5/"] { padding-top: 90px; }
  .aebm [data-padding-top*="/6/"] { padding-top: 108px; }
  .aebm [data-padding-bottom*="/0/"] { padding-bottom: 0px; }
  .aebm [data-padding-bottom*="/1/"] { padding-bottom: 18px; }
  .aebm [data-padding-bottom*="/2/"] { padding-bottom: 36px; }
  .aebm [data-padding-bottom*="/3/"] { padding-bottom: 54px; }
  .aebm [data-padding-bottom*="/4/"] { padding-bottom: 72px; }
  .aebm [data-padding-bottom*="/5/"] { padding-bottom: 90px; }
  .aebm [data-padding-bottom*="/6/"] { padding-bottom: 108px; }
  .aebm [data-margin-top*="/0/"] { margin-top: 0px; }
  .aebm [data-margin-top*="/1/"] { margin-top: 18px; }
  .aebm [data-margin-top*="/2/"] { margin-top: 36px; }
  .aebm [data-margin-top*="/3/"] { margin-top: 54px; }
  .aebm [data-margin-top*="/4/"] { margin-top: 72px; }
  .aebm [data-margin-top*="/5/"] { margin-top: 90px; }
  .aebm [data-margin-top*="/6/"] { margin-top: 108px; }
}
@media (max-width: 734px) {
  .aebm [data-padding-v$="/0"] { padding-top: 0px; padding-bottom: 0px; }
  .aebm [data-padding-v$="/1"] { padding-top: 14px; padding-bottom: 14px; }
  .aebm [data-padding-v$="/2"] { padding-top: 28px; padding-bottom: 28px; }
  .aebm [data-padding-v$="/3"] { padding-top: 42px; padding-bottom: 42px; }
  .aebm [data-padding-v$="/4"] { padding-top: 56px; padding-bottom: 56px; }
  .aebm [data-padding-v$="/5"] { padding-top: 70px; padding-bottom: 70px; }
  .aebm [data-padding-v$="/6"] { padding-top: 84px; padding-bottom: 84px; }
  .aebm [data-padding-top$="/0"] { padding-top: 0px; }
  .aebm [data-padding-top$="/1"] { padding-top: 14px; }
  .aebm [data-padding-top$="/2"] { padding-top: 28px; }
  .aebm [data-padding-top$="/3"] { padding-top: 42px; }
  .aebm [data-padding-top$="/4"] { padding-top: 56px; }
  .aebm [data-padding-top$="/5"] { padding-top: 70px; }
  .aebm [data-padding-top$="/6"] { padding-top: 84px; }
  .aebm [data-padding-bottom$="/0"] { padding-bottom: 0px; }
  .aebm [data-padding-bottom$="/1"] { padding-bottom: 14px; }
  .aebm [data-padding-bottom$="/2"] { padding-bottom: 28px; }
  .aebm [data-padding-bottom$="/3"] { padding-bottom: 42px; }
  .aebm [data-padding-bottom$="/4"] { padding-bottom: 56px; }
  .aebm [data-padding-bottom$="/5"] { padding-bottom: 70px; }
  .aebm [data-padding-bottom$="/6"] { padding-bottom: 84px; }
  .aebm [data-margin-top$="/0"] { margin-top: 0px; }
  .aebm [data-margin-top$="/1"] { margin-top: 14px; }
  .aebm [data-margin-top$="/2"] { margin-top: 28px; }
  .aebm [data-margin-top$="/3"] { margin-top: 42px; }
  .aebm [data-margin-top$="/4"] { margin-top: 56px; }
  .aebm [data-margin-top$="/5"] { margin-top: 70px; }
  .aebm [data-margin-top$="/6"] { margin-top: 84px; }
}

/* ============================================================= type ramp */

.aebm .spec-header {
  font-size: 48px;
  line-height: 1.08349;
  font-weight: 600;
  letter-spacing: -0.003em;
  color: var(--glyph-gray);
}
@media (max-width: 1068px) {
  .aebm .spec-header { font-size: 40px; line-height: 1.1; letter-spacing: 0em; }
}
@media (max-width: 734px) {
  .aebm .spec-header { font-size: 32px; line-height: 1.125; letter-spacing: 0.004em; }
}

.aebm .t-headline-reduced {
  font-size: 40px;
  line-height: 1.1;
  font-weight: 600;
  letter-spacing: 0em;
  color: var(--glyph-gray);
}
@media (max-width: 1068px) {
  .aebm .t-headline-reduced { font-size: 32px; line-height: 1.125; letter-spacing: 0.004em; }
}
@media (max-width: 734px) {
  .aebm .t-headline-reduced { font-size: 28px; line-height: 1.14286; letter-spacing: 0.007em; }
}

.aebm .t-callout {
  font-size: 32px;
  line-height: 1.125;
  font-weight: 600;
  letter-spacing: 0.004em;
}
@media (max-width: 1068px) {
  .aebm .t-callout { font-size: 26px; line-height: 1.15385; letter-spacing: 0.006em; }
}
@media (max-width: 734px) {
  .aebm .t-callout { font-size: 24px; line-height: 1.16667; letter-spacing: 0.009em; }
}

.aebm .spec-sub-header {
  font-size: 21px;
  line-height: 1.19048;
  font-weight: 600;
  letter-spacing: 0.011em;
}

.aebm .spec-copy {
  font-size: 21px;
  line-height: 1.381;
  font-weight: 400;
  letter-spacing: 0.011em;
  color: var(--glyph-gray-secondary);
}
@media (max-width: 734px) {
  .aebm .spec-copy { font-size: 17px; line-height: 1.47059; letter-spacing: -0.022em; }
}

.aebm .t-eyebrow-reduced {
  display: block;
  font-size: 21px;
  line-height: 1.381;
  font-weight: 400;
  letter-spacing: 0.011em;
  color: var(--glyph-gray);
}
@media (max-width: 734px) {
  .aebm .t-eyebrow-reduced { font-size: 17px; line-height: 1.47059; letter-spacing: -0.022em; }
}

.aebm .t-intro {
  font-size: 21px;
  line-height: 1.19048;
  font-weight: 600;
  letter-spacing: 0.011em;
}

.aebm .t-body {
  font-size: 17px;
  line-height: 1.47059;
  font-weight: 400;
  letter-spacing: -0.022em;
  color: var(--glyph-gray-secondary);
}

/* The interior kit's workhorse secondary size — used for step copy, notice
   bodies and row hints, and small enough that it stays subordinate to
   `.t-body` without dropping to caption weight. */
.aebm .t-detail {
  font-size: 14px;
  line-height: 1.42859;
  font-weight: 400;
  letter-spacing: -0.016em;
  color: var(--glyph-gray-secondary);
}

.aebm .t-caption {
  font-size: 12px;
  line-height: 1.33337;
  font-weight: 400;
  letter-spacing: -0.01em;
}

.aebm .badge {
  display: inline-block;
  font-size: 19px;
  line-height: 1.21053;
  font-weight: 600;
  letter-spacing: 0.012em;
}
@media (max-width: 734px) {
  .aebm .badge { font-size: 17px; line-height: 1.23536; letter-spacing: -0.022em; }
}

/* Colour helpers — the only sanctioned way to recolour type. */
.aebm .swatch-glyph-gray-dark { color: var(--glyph-gray); }
.aebm .swatch-glyph-gray-secondary-dark { color: var(--glyph-gray-secondary); }
.aebm .swatch-glyph-gray-tertiary-light { color: var(--glyph-gray-tertiary); }
.aebm .swatch-aebm-text-light { color: var(--glyph-light); }
.aebm .swatch-aebm-highlight-primary-green { color: var(--aebm-green); }
.aebm .swatch-glyph-blue-light { color: var(--glyph-blue); }

.aebm strong, .aebm b { font-weight: 600; color: var(--glyph-gray); }

/* An inline link inside body copy. Brand green rather than the system blue:
   these pages are a CalPal surface, and green is the action colour throughout. */
.aebm .text-link {
  color: var(--aebm-green);
  font-weight: 600;
  text-decoration: none;
  border-radius: 4px;
}
.aebm .text-link:hover { text-decoration: underline; }

/* =============================================================== buttons */

.aebm .button {
  display: inline-block;
  position: relative;
  cursor: pointer;
  text-align: center;
  white-space: nowrap;
  font-size: 17px;
  line-height: 1.17648;
  font-weight: 400;
  letter-spacing: -0.022em;
  min-width: 28px;
  padding: 11px 22px;
  border-radius: 980px;
  background: var(--button-fill);
  color: var(--button-label);
  transition: background-color 100ms linear, transform 220ms var(--ease-out-soft);
}
.aebm .button:hover { background: var(--button-fill-hover); }
.aebm .button:active { background: var(--button-fill-active); transform: scale(0.98); }
.aebm .button:disabled { opacity: 0.55; cursor: not-allowed; transform: none; }

.aebm .button-elevated {
  padding: 12px 23px;
  box-shadow: 0 1px 2px hsl(var(--shadow-color) / 0.16);
}

.aebm .button-secondary {
  background: hsl(var(--secondary));
  color: hsl(var(--secondary-foreground));
}
.aebm .button-secondary:hover { background: hsl(var(--secondary) / 0.8); }
.aebm .button-secondary:active { background: hsl(var(--secondary) / 0.7); }

.aebm .button-block { display: block; width: 100%; }

.aebm .button-reduced {
  font-size: 12px;
  line-height: 1.33337;
  letter-spacing: -0.01em;
  padding: 4px 11px;
}

/* An inline-flex button that carries a glyph beside its label. */
.aebm .button-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.aebm .button-icon svg { width: 16px; height: 16px; flex: none; }

/* Both modifiers set `display`, and relying on which rule comes last would be
   an accident waiting to be tidied away. Stated once, explicitly. */
.aebm .button-icon.button-block { display: flex; width: 100%; }

/*
 * Submit-in-flight state. The spinner is a sibling of the label rather than a
 * replacement for it, so `textContent` updates from the page script never wipe
 * the glyph out of the button.
 */
.aebm .button-spinner { display: none; }
.aebm .button[aria-busy='true'] .button-spinner {
  display: block;
  width: 16px;
  height: 16px;
  flex: none;
  animation: aebm-spin 900ms linear infinite;
}
@keyframes aebm-spin { to { transform: rotate(360deg); } }

/* ============================================================== surfaces */

/*
 * The page canvas. Written against `hsl(var(--card))` upstream so it resolves
 * on a page that is not an `.aebm` root; here it is the muted canvas instead,
 * because both pages float white surfaces on top of it and a white-on-white
 * page would erase every card edge.
 */
.aebm-page {
  background: hsl(var(--background));
  min-height: 100svh;
}

.aebm .panel {
  border-radius: var(--bento-radius);
  background: var(--fill-tertiary);
  padding: var(--tile-inset);
}
.aebm .panel-plain {
  background: var(--fill);
  border: 1px solid var(--localnav-border);
}
.aebm .panel-title {
  font-size: 21px;
  line-height: 1.19048;
  font-weight: 600;
  letter-spacing: 0.011em;
  color: var(--glyph-gray);
}
.aebm .panel-subtitle {
  font-size: 14px;
  line-height: 1.42859;
  letter-spacing: -0.016em;
  color: var(--glyph-gray-secondary);
}

/*
 * Unscoped on purpose (guides/NEW_DESIGN.md §3): kept so a surface dropped
 * outside an `.aebm` subtree still reads as one of ours, with the scoped
 * refinement layered on to take the system radius.
 */
.aebm-surface {
  border-radius: 22px;
  border: 1px solid hsl(var(--border) / 0.8);
  background: hsl(var(--card));
  box-shadow: 0 1px 2px hsl(var(--shadow-color) / 0.05);
}
.aebm .aebm-surface { border-radius: var(--bento-radius); }

/* The elevation a surface takes when it is the page's primary object. */
.aebm .surface-raised {
  box-shadow:
    0 1px 2px hsl(var(--shadow-color) / 0.04),
    0 18px 44px hsl(var(--shadow-color) / 0.08);
}

.aebm .section-stack { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--card-gap); }
.aebm .divider {
  height: 1px;
  border: 0;
  margin: 0;
  background: hsl(var(--border-subtle));
}

/* =========================================================== page intro */

.aebm .page-eyebrow {
  justify-self: start; /* a grid item stretches by default */
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 11px;
  border-radius: 980px;
  background: hsl(var(--primary) / 0.12);
  color: var(--aebm-green);
  font-size: 12px;
  line-height: 1.33337;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.aebm .page-eyebrow svg { width: 13px; height: 13px; flex: none; }

.aebm .page-intro-copy {
  max-width: 34em;
  color: var(--glyph-gray-secondary);
}

/* The label above a control or a group of them. */
.aebm .section-label {
  display: block;
  font-size: 12px;
  line-height: 1.33337;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--glyph-gray-tertiary);
}

/* ================================================================ forms */

.aebm .field { display: flex; flex-direction: column; gap: 7px; }

.aebm .field-label {
  font-size: 12px;
  line-height: 1.33337;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--glyph-gray);
}

.aebm .field-control {
  width: 100%;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid var(--localnav-border);
  background: var(--fill);
  color: var(--glyph-gray);
  font-family: inherit;
  font-size: 17px;
  line-height: 1.47059;
  letter-spacing: -0.022em;
  transition: border-color 200ms linear, box-shadow 200ms linear;
}
.aebm .field-control::placeholder { color: var(--glyph-gray-tertiary); }
.aebm .field-control:hover { border-color: hsl(var(--border-strong)); }
.aebm .field-control:focus {
  outline: none;
  border-color: hsl(var(--ring));
  box-shadow: 0 0 0 4px hsl(var(--ring) / 0.18);
}
/* The focus ring above is the affordance; the global outline would double it. */
.aebm .field-control:focus-visible { outline: none; }

.aebm .form-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }

.aebm .form-status {
  font-size: 14px;
  line-height: 1.42859;
  letter-spacing: -0.016em;
  color: var(--glyph-gray-secondary);
}

/* ============================================================= feedback */

.aebm .notice {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 15px 17px;
  border-radius: 16px;
  background: var(--fill-tertiary);
}
.aebm .notice-icon {
  flex: 0 0 auto;
  width: 17px;
  height: 17px;
  margin-top: 2px;
  color: var(--glyph-gray-tertiary);
}
.aebm .notice-body-wrap { min-width: 0; }
.aebm .notice-title {
  font-size: 14px;
  line-height: 1.42859;
  font-weight: 600;
  letter-spacing: -0.016em;
  color: var(--glyph-gray);
}
.aebm .notice-body {
  font-size: 14px;
  line-height: 1.42859;
  letter-spacing: -0.016em;
  color: var(--glyph-gray-secondary);
}
.aebm .notice-title + .notice-body { margin-top: 2px; }

.aebm .notice-success { background: hsl(var(--success-muted)); }
.aebm .notice-success .notice-icon,
.aebm .notice-success .notice-title { color: hsl(var(--success)); }

.aebm .notice-warning { background: hsl(var(--warning-muted)); }
.aebm .notice-warning .notice-icon,
.aebm .notice-warning .notice-title { color: hsl(var(--warning)); }

.aebm .notice-danger { background: hsl(var(--destructive-muted)); }
.aebm .notice-danger .notice-icon,
.aebm .notice-danger .notice-title { color: hsl(var(--destructive)); }

.aebm .notice-info { background: hsl(var(--info-muted)); }
.aebm .notice-info .notice-icon,
.aebm .notice-info .notice-title { color: hsl(var(--info)); }

/* A status chip. `-solid` is the filled brand variant used in the hero. */
.aebm .status-pill {
  justify-self: start; /* a grid item stretches by default */
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  border-radius: 980px;
  background: hsl(var(--primary) / 0.1);
  color: var(--aebm-green);
  font-size: 12.5px;
  line-height: 1.33337;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.aebm .status-pill svg { width: 13px; height: 13px; flex: none; }
.aebm .status-pill-neutral {
  background: var(--fill-tertiary);
  color: var(--glyph-gray-secondary);
  border: 1px solid hsl(var(--border-subtle));
}
.aebm .status-pill-success {
  background: hsl(var(--success-muted));
  color: hsl(var(--success));
}

/* ================================================================= tabs */
/*
 * Keyed off `aria-selected`, not `[data-state='active']` — see departure 3 in
 * the file header. These pages implement the WAI-ARIA tabs pattern by hand, so
 * the attribute the source targets never appears in the markup.
 */

.aebm .aebm-tabs { justify-self: start; }
.aebm .aebm-tabs [role='tablist'] {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  border-radius: 980px;
  background: var(--fill-tertiary);
  max-width: 100%;
}

.aebm .aebm-tabs [role='tab'] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 8px 18px;
  border-radius: 980px;
  font-size: 14px;
  line-height: 1.42859;
  font-weight: 400;
  letter-spacing: -0.016em;
  color: var(--glyph-gray-secondary);
  white-space: nowrap;
  box-shadow: none;
  transition: background-color 200ms linear, color 200ms linear;
}
.aebm .aebm-tabs [role='tab'] svg { width: 16px; height: 16px; flex: none; }
.aebm .aebm-tabs [role='tab']:hover { color: var(--glyph-gray); }

.aebm .aebm-tabs [role='tab'][aria-selected='true'] {
  background: var(--fill);
  color: var(--glyph-gray);
  font-weight: 600;
  box-shadow: 0 1px 3px hsl(var(--shadow-color) / 0.12);
}

/* Below the small breakpoint the control spans the row and stacks each tab's
   glyph over its label, so three clients still fit a 320px screen without the
   labels truncating. */
@media (max-width: 734px) {
  .aebm .aebm-tabs { justify-self: stretch; }
  .aebm .aebm-tabs [role='tablist'] {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    width: 100%;
  }
  .aebm .aebm-tabs [role='tab'] {
    flex-direction: column;
    gap: 5px;
    padding: 9px 6px;
    font-size: 12px;
    line-height: 1.2;
    letter-spacing: -0.01em;
    white-space: normal;
    border-radius: 18px;
    overflow-wrap: anywhere;
  }
}

/* ======================================================== settings rows */

.aebm .settings-rows > * + * { border-top: 1px solid hsl(var(--border-subtle)); }
.aebm .settings-rows { overflow: hidden; }

.aebm .settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 20px;
}
.aebm .settings-row-label { min-width: 0; }
.aebm .settings-row-title {
  font-size: 15px;
  line-height: 1.4;
  font-weight: 600;
  letter-spacing: -0.016em;
  color: var(--glyph-gray);
}
.aebm .settings-row-hint {
  font-size: 13px;
  line-height: 1.42859;
  letter-spacing: -0.016em;
  color: var(--glyph-gray-secondary);
  margin-top: 2px;
}
.aebm .settings-row-action { flex: 0 0 auto; }

@media (max-width: 734px) {
  .aebm .settings-row { flex-direction: column; align-items: flex-start; gap: 10px; }
}

/* ========================================================== auth pages */

.aebm .auth-shell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* Full viewport, not `calc(100svh - var(--localnav-height))`: these pages
     carry no site nav — see departure 4 in the file header. */
  min-height: 100svh;
  padding: 48px 22px 64px;
  background:
    radial-gradient(58% 42% at 18% 12%, hsl(var(--primary) / 0.12) 0%, transparent 70%),
    radial-gradient(52% 44% at 84% 18%, hsl(var(--info) / 0.1) 0%, transparent 72%),
    linear-gradient(180deg, hsl(var(--muted)) 0%, hsl(var(--card)) 62%);
}

.aebm .auth-inner { width: 100%; max-width: 420px; }

/* The result view carries a config snippet and a token, neither of which fits
   the 420px sign-in column without wrapping into noise. */
.aebm .auth-inner-wide { max-width: 560px; }

.aebm .auth-lockup {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
}

/* Grid rather than the lockup's flex column so the pill inside can centre on
   its own width — a flex child would stretch to the column instead. */
.aebm .auth-lockup-intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
  justify-items: center;
}

.aebm .auth-card {
  border-radius: var(--bento-radius);
  border: 1px solid var(--localnav-border);
  background: hsl(var(--card) / 0.86);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  box-shadow: 0 18px 44px hsl(var(--shadow-color) / 0.1);
  padding: 28px;
}
@media (max-width: 734px) {
  .aebm .auth-card { padding: 22px 18px; }
}

.aebm .auth-card-title {
  font-size: 28px;
  line-height: 1.14286;
  font-weight: 600;
  letter-spacing: 0.007em;
  color: var(--glyph-gray);
}

.aebm .auth-card-description {
  font-size: 14px;
  line-height: 1.42859;
  letter-spacing: -0.016em;
  color: var(--glyph-gray-secondary);
}

/* ======================================================================= */
/* ========================== PROJECT EXTENSIONS ========================= */
/* ======================================================================= */
/*
 * New work for this server. No counterpart in the upstream system, but built
 * from the same tokens, geometry and motion curves, so a palette change moves
 * them with everything else.
 */

/* ---------------------------------------------------------- brand mark */

.aebm .brand-mark {
  display: inline-flex;
  align-items: center;
  gap: 11px;
}
.aebm .brand-mark-logo {
  width: 44px;
  height: 44px;
  border-radius: 11px;
  flex: none;
  box-shadow: 0 1px 2px hsl(var(--shadow-color) / 0.12);
}
/* Block, not the span default: the name and the descriptor are two lines of a
   lockup, and inline spans would set them as one running sentence. */
.aebm .brand-mark-name {
  display: block;
  font-size: 17px;
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.022em;
  color: var(--glyph-gray);
}
.aebm .brand-mark-sub {
  display: block;
  font-size: 12px;
  line-height: 1.33337;
  letter-spacing: -0.01em;
  color: var(--glyph-gray-tertiary);
}

/* ------------------------------------------------------------ skip link */

.aebm .skip-link {
  position: absolute;
  left: -9999px;
  top: 10px;
  z-index: 20;
  padding: 9px 16px;
  border-radius: 980px;
  background: hsl(var(--card));
  border: 1px solid var(--localnav-border);
  box-shadow: 0 6px 20px hsl(var(--shadow-color) / 0.16);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.016em;
  color: var(--glyph-gray);
}
.aebm .skip-link:focus { left: 14px; }

/* ------------------------------------------------------------ hero wash */
/*
 * The backdrop recipe from guides/NEW_DESIGN.md §10: light radial highlights
 * over a diagonal base, every stop a token. No image, nothing on the critical
 * path, and a palette change moves it.
 */
.aebm .hero-wash {
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(58% 44% at 16% 26%, hsl(var(--primary) / 0.22) 0%, transparent 70%),
    radial-gradient(52% 46% at 82% 22%, hsl(var(--info) / 0.2) 0%, transparent 72%),
    radial-gradient(46% 40% at 62% 88%, hsl(var(--warning) / 0.16) 0%, transparent 74%),
    radial-gradient(90% 78% at 50% 42%, transparent 55%, hsl(var(--muted)) 100%),
    linear-gradient(160deg, hsl(var(--card)) 0%, hsl(var(--background)) 42%, hsl(var(--muted)) 100%);
  border-bottom: 1px solid hsl(var(--border-subtle));
}

/* Hero copy sits left, the connection diagram right, collapsing to one column
   below the large breakpoint where the diagram would squeeze the headline. */
.aebm .hero-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 32px;
  align-items: center;
}
@media (min-width: 1069px) {
  .aebm .hero-row {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    gap: 48px;
  }
}

.aebm .hero-copy { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; justify-items: start; }
.aebm .hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}

/* --------------------------------------------------------- copy chip */
/*
 * A value the user is meant to copy: monospace, scrollable, with the action
 * fixed at the end of the row so a long value never pushes it off screen.
 */
.aebm .copy-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 7px 7px 14px;
  border-radius: 14px;
  border: 1px solid var(--localnav-border);
  background: hsl(var(--card));
  box-shadow: 0 1px 2px hsl(var(--shadow-color) / 0.05);
}
.aebm .copy-chip code {
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  white-space: nowrap;
  font-size: 13.5px;
  letter-spacing: 0;
  color: var(--glyph-gray);
  /* A scrollable strip inside a padded row: the scrollbar would otherwise
     crowd the text on platforms that reserve space for it. */
  scrollbar-width: thin;
}
.aebm .copy-chip-muted { background: var(--fill-tertiary); box-shadow: none; }

/*
 * Below the small breakpoint the value takes its own row and wraps, instead of
 * becoming a horizontally-scrolling strip behind the button. These are values
 * the user has to read back to check they pasted the right one, and a touch
 * device makes a scrollable one-line field the worst way to do that. The ID in
 * the Claude step is 36 characters and never fits on a phone at all.
 */
@media (max-width: 734px) {
  .aebm .copy-chip { flex-wrap: wrap; gap: 10px; padding: 12px; }
  .aebm .copy-chip code {
    flex: 1 1 100%;
    overflow-x: visible;
    white-space: normal;
    overflow-wrap: anywhere;
    line-height: 1.5;
  }
  .aebm .copy-chip .copy-button { flex: 1 1 100%; }
}

/* The copy action itself — small, brand-filled, fixed width so the label
   swapping to "Copied" does not resize the row. */
.aebm .copy-button {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 84px;
  padding: 8px 13px;
  border-radius: 10px;
  background: var(--button-fill);
  color: var(--button-label);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  white-space: nowrap;
  transition: background-color 100ms linear;
}
.aebm .copy-button:hover { background: var(--button-fill-hover); }
.aebm .copy-button:active { background: var(--button-fill-active); }
.aebm .copy-button svg { width: 13px; height: 13px; flex: none; }

/* The check swaps in for the clipboard glyph only while the button reports a
   completed copy, so the label and the icon never disagree. */
.aebm .copy-button .icon-check { display: none; }
.aebm .copy-button[data-copied='true'] .icon-copy { display: none; }
.aebm .copy-button[data-copied='true'] .icon-check { display: block; }

/* ------------------------------------------------------------ code block */
/*
 * An ink surface, not a dark theme: it is built from `--foreground`, the same
 * token the body type uses, so it tracks the palette instead of pinning a
 * second one. Light-only still holds — there is no `.dark` anywhere.
 */
.aebm .codeblock {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  background: hsl(var(--foreground));
  border: 1px solid hsl(var(--foreground));
  --code-fg: hsl(var(--background) / 0.9);
  --code-punct: hsl(var(--background) / 0.55);
  --code-string: hsl(var(--rating));
}
.aebm .codeblock pre {
  padding: 16px 18px;
  padding-right: 104px;
  overflow-x: auto;
  font-size: 12.5px;
  line-height: 1.65;
  letter-spacing: 0;
  color: var(--code-punct);
  white-space: pre;
}
.aebm .codeblock .k { color: var(--code-fg); }
.aebm .codeblock .s { color: var(--code-string); }

/* The copy action floats over the snippet; `pre` reserves the room for it. */
.aebm .codeblock .copy-button {
  position: absolute;
  top: 10px;
  right: 10px;
  min-width: 0;
  padding: 6px 11px;
  background: hsl(var(--background) / 0.14);
  color: var(--code-fg);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.aebm .codeblock .copy-button:hover { background: hsl(var(--background) / 0.24); }
.aebm .codeblock .copy-button:active { background: hsl(var(--background) / 0.3); }

@media (max-width: 734px) {
  .aebm .codeblock pre { padding: 14px; padding-right: 94px; font-size: 12px; }
}

/* An inline literal inside prose — a path, an env var, a header name. */
.aebm .inline-code {
  font-family: var(--font-family-mono);
  font-size: 12.5px;
  letter-spacing: 0;
  background: var(--fill-tertiary);
  border: 1px solid hsl(var(--border-subtle));
  border-radius: 6px;
  padding: 1px 6px;
  overflow-wrap: anywhere;
  color: var(--glyph-gray);
}

/* ------------------------------------------------------------ icon button */

.aebm .icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  flex: none;
  padding: 8px 13px;
  border-radius: 10px;
  border: 1px solid var(--localnav-border);
  background: hsl(var(--card));
  color: var(--glyph-gray);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  transition: background-color 150ms linear, border-color 150ms linear;
}
.aebm .icon-button:hover {
  background: var(--fill-tertiary);
  border-color: hsl(var(--border-strong));
}
.aebm .icon-button svg { width: 15px; height: 15px; flex: none; }

/* --------------------------------------------------------------- steps */

.aebm .steps { display: grid; grid-template-columns: minmax(0, 1fr); }
.aebm .steps > li + li { border-top: 1px solid hsl(var(--border-subtle)); }

.aebm .step {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr);
  gap: 16px;
  padding: 22px 24px;
}
@media (max-width: 734px) {
  .aebm .step { padding: 20px 18px; gap: 13px; grid-template-columns: 26px minmax(0, 1fr); }
}

.aebm .step-number {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: hsl(var(--primary) / 0.1);
  color: var(--aebm-green);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 734px) {
  .aebm .step-number { width: 26px; height: 26px; font-size: 12px; }
}

.aebm .step-body { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; justify-items: start; }
.aebm .step-title {
  font-size: 16px;
  line-height: 1.35;
  font-weight: 600;
  letter-spacing: -0.018em;
  color: var(--glyph-gray);
}
/* Every block inside a step stretches unless it is an inline control — grid
   items would otherwise leave a copy chip or a code block short of the column. */
.aebm .step-body > .copy-chip,
.aebm .step-body > .codeblock,
.aebm .step-body > .notice,
.aebm .step-body > p { justify-self: stretch; }

/* --------------------------------------------------------- tool tag list */

.aebm .tag-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.aebm .tag {
  font-family: var(--font-family-mono);
  font-size: 11.5px;
  line-height: 1.5;
  letter-spacing: 0;
  background: hsl(var(--card));
  color: var(--glyph-gray-secondary);
  border: 1px solid hsl(var(--border-subtle));
  padding: 3px 9px;
  border-radius: 7px;
}
/* Write tools are the ones that change data — the distinction is the point of
   the list, so it is carried by a border tint as well as the adjacent legend. */
.aebm .tag-write {
  background: hsl(var(--primary) / 0.07);
  border-color: hsl(var(--primary) / 0.22);
  color: var(--aebm-green);
}

.aebm .tag-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: center;
}
.aebm .tag-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  line-height: 1.33337;
  letter-spacing: -0.01em;
  color: var(--glyph-gray-secondary);
}
.aebm .tag-legend-swatch {
  width: 9px;
  height: 9px;
  border-radius: 3px;
  flex: none;
  background: hsl(var(--border));
}
.aebm .tag-legend-swatch-write { background: hsl(var(--primary) / 0.55); }

/* ----------------------------------------------------------- disclosure */

.aebm .disclosure summary {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  list-style: none;
  color: var(--aebm-green);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.016em;
  border-radius: 8px;
}
.aebm .disclosure summary::-webkit-details-marker { display: none; }
.aebm .disclosure summary svg {
  width: 14px;
  height: 14px;
  flex: none;
  transition: transform 200ms var(--ease-out-soft);
}
.aebm .disclosure[open] summary svg { transform: rotate(90deg); }
.aebm .disclosure summary:hover { text-decoration: underline; }

/* --------------------------------------------------------- token field */

.aebm .token-field { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }

.aebm .token-box {
  font-family: var(--font-family-mono);
  font-size: 12.5px;
  line-height: 1.55;
  letter-spacing: 0;
  background: var(--fill-tertiary);
  border: 1px solid hsl(var(--border-subtle));
  border-radius: 14px;
  padding: 12px 14px;
  max-height: 96px;
  overflow: auto;
  overflow-wrap: anywhere;
  word-break: break-all;
  color: var(--glyph-gray);
}
/* Masked, so the token is not on screen for a shoulder or a screen share until
   the user asks for it. The dots are a different colour from the real value so
   the two states are never mistaken for one another. */
.aebm .token-box[data-visible='false'] { color: var(--glyph-gray-tertiary); letter-spacing: 1px; }

.aebm .token-actions { display: flex; gap: 8px; }
.aebm .token-actions .copy-button { flex: 1 1 auto; }

/* The eye swaps for the struck-through eye only while the token is on screen. */
.aebm .icon-button .icon-eye-off { display: none; }
.aebm .icon-button[aria-pressed='true'] .icon-eye { display: none; }
.aebm .icon-button[aria-pressed='true'] .icon-eye-off { display: block; }

/* -------------------------------------------------------------- footer */

.aebm .site-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px 14px;
  text-align: center;
  color: var(--glyph-gray-tertiary);
  font-size: 12.5px;
  line-height: 1.4;
  letter-spacing: -0.01em;
}
.aebm .site-footer a { color: var(--glyph-gray-tertiary); border-radius: 6px; }
.aebm .site-footer a:hover { color: var(--glyph-gray); text-decoration: underline; }
.aebm .site-footer-sep { opacity: 0.4; }
/* The build version is a footnote to the links above, not another link in the
   row — a full-width basis drops it onto its own line at every width. */
.aebm .site-footer-note { flex: 1 0 100%; }

/* ===================================================== connection motion */
/*
 * Pure CSS over static DOM geometry — no JavaScript, no video, no animation
 * library (guides/NEW_DESIGN.md §8.3). It renders identically with scripting
 * off and stops completely under `prefers-reduced-motion`.
 *
 * `aria-hidden` on the container is required, not optional: the hero copy
 * beside it already says a client connects to CalPal, and a looping animation
 * announced on repeat is noise.
 *
 * ONE PERIOD for every element in the card — 4.8s. Mixed periods drift out of
 * phase and look broken after a minute.
 */

.aebm .bridge {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 18px;
  width: min(340px, 100%);
  margin-inline: auto;
  padding: 22px;
  border-radius: 22px;
  background: hsl(var(--card) / 0.9);
  box-shadow: 0 10px 26px hsl(var(--shadow-color) / 0.16);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.aebm .bridge-track {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
}

.aebm .bridge-node { display: grid; grid-template-columns: minmax(0, 1fr); justify-items: center; gap: 9px; width: 92px; }

.aebm .bridge-node-icon {
  position: relative;
  width: 54px;
  height: 54px;
  border-radius: 17px;
  display: grid;
  place-items: center;
  background: var(--fill-tertiary);
  border: 1px solid hsl(var(--border-subtle));
  color: var(--glyph-gray-secondary);
}
.aebm .bridge-node-icon svg { width: 24px; height: 24px; }
.aebm .bridge-node-icon img { width: 30px; height: 30px; border-radius: 8px; }

.aebm .bridge-node-label {
  font-size: 11.5px;
  line-height: 1.3;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-align: center;
  color: var(--glyph-gray-secondary);
}

/* The arrival ring, keyed to the moment the pulse lands. */
.aebm .bridge-ring {
  position: absolute;
  inset: -5px;
  border-radius: 21px;
  border: 2px solid hsl(var(--primary) / 0.5);
  opacity: 0;
  animation: bridge-ring 4.8s var(--ease-out-soft) infinite;
}

/* A repeating gradient, no asset (guides/NEW_DESIGN.md §8.5). */
.aebm .bridge-wire {
  position: relative;
  flex: none;
  width: 76px;
  height: 2px;
  background-image: linear-gradient(
    to right,
    hsl(var(--foreground) / 0.24) 0 6px,
    transparent 6px 12px
  );
  background-size: 12px 2px;
}

.aebm .bridge-pulse {
  position: absolute;
  top: 50%;
  left: 0;
  width: 9px;
  height: 9px;
  margin: -4.5px 0 0 -4.5px;
  border-radius: 50%;
  background: hsl(var(--primary));
  box-shadow: 0 0 0 4px hsl(var(--primary) / 0.16);
  opacity: 0;
  animation: bridge-travel-x 4.8s var(--ease-in-out-soft) infinite;
}

.aebm .bridge-log {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 7px;
  padding-top: 16px;
  border-top: 1px solid hsl(var(--border-subtle));
}
/*
 * The row text never animates. An earlier cut faded whole rows in and out,
 * which left the bottom half of the card empty for a third of every cycle and
 * read as a rendering fault rather than as motion. Only the check glyph moves,
 * so the card always states what it is saying and the animation is the
 * handshake landing on top of it.
 */
.aebm .bridge-log-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  line-height: 1.33337;
  letter-spacing: -0.01em;
  color: var(--glyph-gray-secondary);
}
.aebm .bridge-log-row svg {
  width: 13px;
  height: 13px;
  flex: none;
  color: hsl(var(--success));
  transform-origin: center;
  animation: bridge-check-in 4.8s var(--ease-out-soft) infinite;
  /* Per-element offset as a custom property rather than a class per delay. */
  animation-delay: var(--delay, 0ms);
}

@keyframes bridge-travel-x {
  0%   { transform: translateX(0);    opacity: 0; }
  5%   { transform: translateX(0);    opacity: 1; }
  30%  { transform: translateX(76px); opacity: 1; }
  36%  { transform: translateX(76px); opacity: 0; }
  37%  { transform: translateX(0);    opacity: 0; }
  100% { transform: translateX(0);    opacity: 0; }
}

@keyframes bridge-ring {
  0%, 26%   { transform: scale(0.92); opacity: 0; }
  34%       { transform: scale(1);    opacity: 0.6; }
  56%, 100% { transform: scale(1.45); opacity: 0; }
}

/* Lands just after the pulse reaches the server node at 30%, holds for most
   of the cycle, and resets at the very end. */
@keyframes bridge-check-in {
  0%, 26%   { transform: scale(0.62); opacity: 0.22; }
  36%       { transform: scale(1.12); opacity: 1; }
  44%, 88%  { transform: scale(1);    opacity: 1; }
  97%, 100% { transform: scale(0.62); opacity: 0.22; }
}

/* Below the small breakpoint the card is narrower than the horizontal run, so
   the bridge stands up and the pulse travels down it instead. */
@media (max-width: 734px) {
  .aebm .bridge-track { flex-direction: column; gap: 12px; }
  .aebm .bridge-node { width: 100%; }
  .aebm .bridge-wire {
    width: 2px;
    height: 46px;
    background-image: linear-gradient(
      to bottom,
      hsl(var(--foreground) / 0.24) 0 6px,
      transparent 6px 12px
    );
    background-size: 2px 12px;
  }
  .aebm .bridge-pulse { animation-name: bridge-travel-y; }
}

@keyframes bridge-travel-y {
  0%   { transform: translateY(0);    opacity: 0; }
  5%   { transform: translateY(0);    opacity: 1; }
  30%  { transform: translateY(46px); opacity: 1; }
  36%  { transform: translateY(46px); opacity: 0; }
  37%  { transform: translateY(0);    opacity: 0; }
  100% { transform: translateY(0);    opacity: 0; }
}

/* ====================================================== entrance reveal */
/*
 * guides/NEW_DESIGN.md §8.2. The invariant: content is visible in the served
 * HTML and STAYS visible if JavaScript never arrives. The hidden state is
 * therefore behind `data-aebm-reveal="pending"`, an attribute the server never
 * emits — only the page script sets it, and only for elements still below the
 * fold. No script, a thrown effect, no IntersectionObserver, reduced motion
 * and printing all degrade to "content is visible".
 */
.aebm .reveal-item {
  transition:
    opacity 800ms var(--ease-out-soft),
    transform 800ms var(--ease-out-soft);
}
.aebm [data-aebm-reveal='pending'].reveal-item {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
}

/* A 90ms cascade between siblings, capped so a long list never crawls. */
.aebm [data-aebm-reveal='in'].reveal-stagger > *:nth-child(2) { transition-delay: 90ms; }
.aebm [data-aebm-reveal='in'].reveal-stagger > *:nth-child(3) { transition-delay: 180ms; }
.aebm [data-aebm-reveal='in'].reveal-stagger > *:nth-child(4) { transition-delay: 270ms; }
.aebm [data-aebm-reveal='in'].reveal-stagger > *:nth-child(n + 5) { transition-delay: 360ms; }
.aebm .reveal-stagger > * {
  transition:
    opacity 800ms var(--ease-out-soft),
    transform 800ms var(--ease-out-soft);
}
.aebm [data-aebm-reveal='pending'].reveal-stagger > * {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
}

/* ======================================================= motion stops */
/*
 * Mandatory, not optional (guides/NEW_DESIGN.md §8.4 step 5): every animation
 * above has a stop here, and each lands on its RESTING state rather than its
 * initial one.
 */
@media (prefers-reduced-motion: reduce) {
  .aebm *,
  .aebm *::before,
  .aebm *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .aebm .bridge-pulse { animation: none; opacity: 0; }
  .aebm .bridge-ring { animation: none; opacity: 0; }
  .aebm .bridge-log-row svg { animation: none; opacity: 1; transform: none; }
  .aebm .button[aria-busy='true'] .button-spinner { animation: none; }
  .aebm [data-aebm-reveal] .reveal-item,
  .aebm [data-aebm-reveal='pending'].reveal-item,
  .aebm [data-aebm-reveal='pending'].reveal-stagger > * {
    opacity: 1 !important;
    transform: none !important;
  }
}

@media print {
  .aebm [data-aebm-reveal='pending'].reveal-item,
  .aebm [data-aebm-reveal='pending'].reveal-stagger > * {
    opacity: 1 !important;
    transform: none !important;
  }
  .aebm .bridge,
  .aebm .skip-link { display: none; }
  .aebm .codeblock {
    background: hsl(var(--card));
    border-color: hsl(var(--border));
    --code-fg: hsl(var(--foreground));
    --code-punct: hsl(var(--foreground) / 0.7);
    --code-string: hsl(var(--foreground));
  }
  .aebm .codeblock .copy-button { display: none; }
}

/* ==================================================== section scaffolding */

/*
 * The internal padding of a content surface. `--tile-inset` (40px) is tuned
 * for full-bleed bento tiles; a card carrying a form or a list reads tighter.
 */
.aebm .surface-pad { padding: 28px; }
@media (max-width: 1068px) { .aebm .surface-pad { padding: 24px; } }
@media (max-width: 734px)  { .aebm .surface-pad { padding: 20px 18px; } }

.aebm .section-head { display: grid; grid-template-columns: minmax(0, 1fr); gap: 5px; margin-bottom: 16px; }
.aebm .section-head-inline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 16px;
}

.aebm .stack-sm { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
.aebm .stack-md { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
.aebm .stack-lg { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; }

/* A hairline-celled strip of key/value facts. The 1px grid gap doubles as the
   rule between cells, so no cell needs its own border to align with. */
.aebm .fact-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  border-radius: 14px;
  overflow: hidden;
  background: hsl(var(--border-subtle));
  border: 1px solid hsl(var(--border-subtle));
}
.aebm .fact {
  background: hsl(var(--card));
  padding: 12px 14px;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 3px;
  min-width: 0;
}
.aebm .fact-label {
  font-size: 11px;
  line-height: 1.3;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--glyph-gray-tertiary);
}
.aebm .fact-value {
  font-size: 13.5px;
  line-height: 1.35;
  font-weight: 600;
  letter-spacing: -0.016em;
  color: var(--glyph-gray);
}
@media (max-width: 734px) {
  .aebm .fact-grid { grid-template-columns: minmax(0, 1fr); }
}
