/* Design tokens + styles for server-rendered markup (auth pages, app header).
   The editor surface itself is styled by the bundled frontend CSS.

   Scales below (space, radius, control, text, shadow) are complete ladders and
   stay complete even where a rung is currently unused. One-off tokens are not:
   if nothing references one, it is deleted rather than left as an intention.

   This file loads first on every page — including the dev harness, which borrows
   it through Vite's publicDir — so the bundled CSS never needs `var(--x, literal)`
   fallbacks. It must not grow any: a fallback is a second palette, and second
   palettes drift. See DESIGN.md. */

:root {
  /* ---- neutrals ----------------------------------------------------------
     Warm, not cool. A blue-gray next to white reads as a screenshot of a
     document; a warm one reads as paper. */
  --pasty-gray-0: #ffffff;
  --pasty-gray-50: #f6f6f4;
  --pasty-gray-100: #eeedeb;
  --pasty-gray-150: #e7e6e3;
  --pasty-gray-200: #dbdad6;
  --pasty-gray-300: #c1bfb9;
  --pasty-gray-400: #8f8d87; /* disabled text, 3.3:1 */
  --pasty-gray-600: #6b6a66; /* muted text, 5.3:1 */
  --pasty-gray-800: #33322f;
  --pasty-gray-900: #201f1d; /* body text */

  /* ---- ink (the dark ramp) -----------------------------------------------
     Authored against the light ramp, not derived from it: an inverted ramp is
     what makes a dark mode look inverted. Warm charcoal, never black, and the
     text end stops short of white. Never consumed directly — only the semantic
     layer below reads it. */
  /* Three depths, and only three. Anything that wants to recede uses ink-50,
     whether it is the field behind the page or a code well inside it — a well
     and the field are the same depth, and giving them separate near-identical
     values was five blacks pretending to be a system. */
  --pasty-ink-50: #171614; /* recessed: the field, code wells, table headers */
  --pasty-ink-100: #232220; /* the document, the header, the toolbar */
  --pasty-ink-150: #2a2926; /* raised: menus, popovers, the banner */
  --pasty-ink-300: #35332f;
  --pasty-ink-400: #45423d;
  --pasty-ink-500: #5c5852;
  --pasty-ink-600: #a3a09a; /* muted text, 6.1:1 on ink-100 */
  --pasty-ink-800: #cdc9c2;
  --pasty-ink-900: #ebe8e3; /* body text, 13.0:1 on ink-100 */

  /* ---- accent ------------------------------------------------------------
     One blue, and it means one thing: action or active state. It lightens in
     dark mode rather than darkening — #2361dd is only 2.9:1 on ink-100 — and
     so hover and pressed lighten too, which is the reverse of light mode.
     Light 5.6:1, dark 7.3:1, and both carry text on the fill. Dark runs a
     little brighter on purpose: a link that is dimmer than the prose around it
     reads as an afterthought, and the caret is one or two pixels wide. */
  --pasty-accent: light-dark(#2361dd, #8ab0f9);
  --pasty-accent-hover: light-dark(#1c51bd, #93b6f9);
  --pasty-accent-down: light-dark(#173f95, #a9c6fb);
  --pasty-accent-soft: light-dark(#eef2fc, #1e2c4a);
  --pasty-accent-active: light-dark(#dbe5f9, #26375a);
  --pasty-selection: light-dark(#cfe0fb, #2c4470);

  /* ---- danger ------------------------------------------------------------ */
  --pasty-danger: light-dark(#b42318, #f2837a);
  --pasty-danger-soft: light-dark(#fdf3f2, #2a1a18);
  --pasty-danger-border: light-dark(#f0cac5, #5a2f2a);

  /* ---- the copied chip ---------------------------------------------------
     Not an inverse any more: inverting this in dark mode puts a glaring white
     pill next to Copy Markdown. It is a raised chip in both themes. */
  --pasty-chip-surface: light-dark(var(--pasty-gray-800), var(--pasty-ink-150));
  --pasty-chip-text: light-dark(var(--pasty-gray-0), var(--pasty-ink-900));

  /* ---- interaction washes ------------------------------------------------
     Neutral, never a tint of the accent: hover is not an action. Ink on light,
     light on ink. */
  /* Dark runs hotter than a straight inversion: the same percentage of white on
     charcoal is a far smaller perceptual step than that percentage of ink on
     white, and a hover you have to look for is not a hover. */
  --pasty-hover: light-dark(rgb(32 31 29 / 5%), rgb(255 255 255 / 10%));
  --pasty-hover-strong: light-dark(rgb(32 31 29 / 9%), rgb(255 255 255 / 16%));

  /* ---- semantic layer ----------------------------------------------------
     THE RULE: components consume these, never the ramps above. A rule that
     reaches past this layer into `--pasty-gray-*` is a rule a theme cannot
     re-point, which is how a stylesheet ends up forked. */

  /* surfaces, from furthest back to furthest forward */
  --pasty-workspace: light-dark(#f2f1ee, var(--pasty-ink-50));
  --pasty-surface: light-dark(var(--pasty-gray-0), var(--pasty-ink-100));
  --pasty-surface-raised: light-dark(var(--pasty-gray-0), var(--pasty-ink-150));
  /* Deliberately the same value as the field: two names, one depth. A code
     well is not a different kind of surface from the field, it is the same
     recess seen inside the page. */
  --pasty-surface-sunken: light-dark(#f2f1ee, var(--pasty-ink-50));

  /* text, in four tiers that mean four different things:
       --pasty-text            primary document content
       --pasty-text-secondary  secondary *document* content — quotes, markers,
                               the deepest heading, a completed task
       --pasty-text-muted      muted *application* text — save status, help
       --pasty-text-disabled   a control you cannot use
     The document never reaches past the second tier. It used to: h6, list
     markers and checked tasks were all on the chrome's muted value, which put
     document content at the same contrast as the save-status line. */
  --pasty-text: light-dark(var(--pasty-gray-900), var(--pasty-ink-900));
  --pasty-text-secondary: light-dark(var(--pasty-gray-800), var(--pasty-ink-800));
  --pasty-text-muted: light-dark(var(--pasty-gray-600), var(--pasty-ink-600));
  --pasty-text-disabled: light-dark(var(--pasty-gray-400), #6f6b64);
  --pasty-icon: light-dark(var(--pasty-gray-800), var(--pasty-ink-800));

  /* lines */
  --pasty-border: light-dark(var(--pasty-gray-200), var(--pasty-ink-400));
  --pasty-border-soft: light-dark(var(--pasty-gray-150), var(--pasty-ink-300));
  --pasty-border-strong: light-dark(var(--pasty-gray-300), var(--pasty-ink-500));
  --pasty-border-strong-hover: light-dark(var(--pasty-gray-400), #6f6b64);
  --pasty-rule: light-dark(var(--pasty-gray-200), var(--pasty-ink-400));

  /* quiet fills */
  --pasty-fill-quiet: light-dark(var(--pasty-gray-100), var(--pasty-ink-150));
  --pasty-fill-quiet-strong: light-dark(var(--pasty-gray-200), var(--pasty-ink-300));

  /* accent-adjacent */
  --pasty-on-accent: light-dark(var(--pasty-gray-0), #10203f);
  /* A pale tint in light; a translucent accent in dark, so the halo reads on
     the document, on a menu panel and in a sunken code well alike. */
  /* Derived, not copied: this had already drifted a shade behind the accent
     once, which is what a hand-written tint of another token always does. */
  --pasty-focus-ring: light-dark(#eef2fc, color-mix(in srgb, var(--pasty-accent) 35%, transparent));

  /* document constructs. Inline code and code wells go *darker* than the page
     in both themes, which is what stops them reading as bright pills. */
  --pasty-quote-border: light-dark(var(--pasty-gray-200), var(--pasty-ink-400));
  --pasty-code-border: light-dark(var(--pasty-gray-150), #36332f);
  --pasty-table-border: light-dark(var(--pasty-gray-150), var(--pasty-ink-300));
  --pasty-table-header-border: light-dark(var(--pasty-gray-200), var(--pasty-ink-400));

  /* ---- radius ------------------------------------------------------------ */
  --pasty-radius-sm: 6px; /* embedded: toolbar buttons, menu rows */
  --pasty-radius-md: 8px; /* freestanding: buttons, inputs */
  --pasty-radius-lg: 12px; /* floating: menus, cards, the page */
  --pasty-radius: var(--pasty-radius-md);

  /* ---- space (4px grid) -------------------------------------------------- */
  --pasty-space-1: 4px;
  --pasty-space-2: 8px;
  --pasty-space-3: 12px;
  --pasty-space-4: 16px;
  --pasty-space-5: 20px;
  --pasty-space-6: 24px;
  --pasty-space-7: 32px;
  --pasty-space-8: 40px;

  /* ---- control heights --------------------------------------------------- */
  --pasty-control-sm: 28px; /* toolbar */
  --pasty-control-md: 32px; /* header chrome, menu rows */
  --pasty-control-lg: 40px; /* auth forms */

  /* ---- UI type ----------------------------------------------------------- */
  --pasty-text-xs: 12px;
  --pasty-text-sm: 13px;
  --pasty-text-md: 14px;
  --pasty-text-lg: 16px;
  --pasty-text-xl: 20px;

  /* ---- elevation --------------------------------------------------------- */
  --pasty-shadow-sm: 0 1px 2px light-dark(rgb(32 31 29 / 6%), transparent);
  --pasty-shadow-md: 0 2px 4px light-dark(rgb(32 31 29 / 6%), rgb(0 0 0 / 28%)),
    0 8px 24px light-dark(rgb(32 31 29 / 10%), rgb(0 0 0 / 40%));
  --pasty-shadow-lg: 0 4px 8px light-dark(rgb(32 31 29 / 8%), rgb(0 0 0 / 34%)),
    0 16px 40px light-dark(rgb(32 31 29 / 14%), rgb(0 0 0 / 48%));

  /* ---- motion ------------------------------------------------------------
     Two durations. Everything animated references one of them, so
     prefers-reduced-motion can switch the whole product off at the token. */
  --pasty-ease: cubic-bezier(0.2, 0, 0, 1);
  --pasty-t-fast: 80ms; /* state: hover, press, active */
  --pasty-t-base: 140ms; /* entrance: menus, chips, banner */

  /* ---- typefaces --------------------------------------------------------- */
  --pasty-ui-font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial,
    sans-serif;
  /* The document stack: the same family as the UI by design — it differentiates
     itself by size, leading and measure — plus an emoji tail, because agent
     output is full of them. */
  --pasty-font: system-ui, -apple-system, "Segoe UI Variable Text", "Segoe UI", Roboto,
    "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji",
    "Segoe UI Emoji", "Noto Color Emoji";
  --pasty-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Cascadia Code",
    "Roboto Mono", "Liberation Mono", monospace;

  /* ---- layout ------------------------------------------------------------ */
  /* 44 is a floor, not a preference: a 32px control plus a 2px focus ring at a
     2px offset occupies 40px, and 40 would clip every ring against the rule. */
  --pasty-header-height: 44px;
  --pasty-toolbar-height: 41px; /* 6 + 28px control + 6 + the 1px rule */
  /* One number for the header, the toolbar and the workspace, so the chrome and
     the sheet cannot drift apart. See `.app-header__inner`. */
  --pasty-rail-gutter: var(--pasty-space-5);
  /* The workspace subtracts the whole chrome band, so the page fills the window
     exactly once and never invents a scrollbar. */
  --pasty-chrome-offset: calc(var(--pasty-header-height) + var(--pasty-toolbar-height));
  --pasty-page-max-width: 940px;
  --pasty-prose-measure: 700px;

  /* System, and it costs no JavaScript: `light-dark()` above reads this, and
     this reads the OS. The attribute rules below are the manual override, and
     they are the only thing theme.ts writes. */
  color-scheme: light dark;
}

:root[data-theme="light"] {
  color-scheme: light;
}

:root[data-theme="dark"] {
  color-scheme: dark;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --pasty-t-fast: 0ms;
    --pasty-t-base: 0ms;
  }
}




/* `light-dark()` is the whole theme mechanism, and this file forbids
   `var(--x, literal)` fallbacks — so on a browser without it every themed
   token would resolve to nothing and Pasty would render as transparent
   panels and inherited text. This block makes the failure mode "light mode"
   instead, which is exactly what Pasty was before dark mode existed.
   Generated from the pairs above; frontend/tests/theme-boot.test.ts fails if
   the two ever disagree. */
@supports not (color: light-dark(#fff, #000)) {
  :root {
    color-scheme: light;
    --pasty-accent: #2361dd;
    --pasty-accent-hover: #1c51bd;
    --pasty-accent-down: #173f95;
    --pasty-accent-soft: #eef2fc;
    --pasty-accent-active: #dbe5f9;
    --pasty-selection: #cfe0fb;
    --pasty-danger: #b42318;
    --pasty-danger-soft: #fdf3f2;
    --pasty-danger-border: #f0cac5;
    --pasty-chip-surface: var(--pasty-gray-800);
    --pasty-chip-text: var(--pasty-gray-0);
    --pasty-hover: rgb(32 31 29 / 5%);
    --pasty-hover-strong: rgb(32 31 29 / 9%);
    --pasty-workspace: #f2f1ee;
    --pasty-surface: var(--pasty-gray-0);
    --pasty-surface-raised: var(--pasty-gray-0);
    --pasty-surface-sunken: #f2f1ee;
    --pasty-text: var(--pasty-gray-900);
    --pasty-text-secondary: var(--pasty-gray-800);
    --pasty-text-muted: var(--pasty-gray-600);
    --pasty-text-disabled: var(--pasty-gray-400);
    --pasty-icon: var(--pasty-gray-800);
    --pasty-border: var(--pasty-gray-200);
    --pasty-border-soft: var(--pasty-gray-150);
    --pasty-border-strong: var(--pasty-gray-300);
    --pasty-border-strong-hover: var(--pasty-gray-400);
    --pasty-rule: var(--pasty-gray-200);
    --pasty-fill-quiet: var(--pasty-gray-100);
    --pasty-fill-quiet-strong: var(--pasty-gray-200);
    --pasty-on-accent: var(--pasty-gray-0);
    --pasty-focus-ring: #eef2fc;
    --pasty-quote-border: var(--pasty-gray-200);
    --pasty-code-border: var(--pasty-gray-150);
    --pasty-table-border: var(--pasty-gray-150);
    --pasty-table-header-border: var(--pasty-gray-200);
    --pasty-shadow-sm: 0 1px 2px rgb(32 31 29 / 6%);
    --pasty-shadow-md: 0 2px 4px rgb(32 31 29 / 6%), 0 8px 24px rgb(32 31 29 / 10%);
    --pasty-shadow-lg: 0 4px 8px rgb(32 31 29 / 8%), 0 16px 40px rgb(32 31 29 / 14%);
  }
}

* {
  box-sizing: border-box;
}

/* A class that sets `display` outranks the user agent's `[hidden]` rule, so
   toggling the attribute would silently stop hiding things. */
[hidden] {
  display: none !important;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--pasty-workspace);
  color: var(--pasty-text);
  font-family: var(--pasty-ui-font);
  font-size: var(--pasty-text-md);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--pasty-accent);
}

:focus-visible {
  outline: 2px solid var(--pasty-accent);
  outline-offset: 2px;
}

/* Entrance for anything that appears in place: menus, the copied chip, the
   banner. Closing is instant — waiting for something to leave is the one kind
   of animation that always reads as slowness. */
@keyframes pasty-pop {
  from {
    opacity: 0;
    transform: translateY(2px);
  }
}

/* ---------- buttons (shared by header + auth) ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--pasty-space-2);
  height: var(--pasty-control-md);
  padding: 0 var(--pasty-space-3);
  border: 1px solid transparent;
  border-radius: var(--pasty-radius-md);
  font: inherit;
  font-size: var(--pasty-text-sm);
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  background: transparent;
  color: var(--pasty-text);
  transition:
    background-color var(--pasty-t-fast) var(--pasty-ease),
    border-color var(--pasty-t-fast) var(--pasty-ease),
    color var(--pasty-t-fast) var(--pasty-ease);
}

.btn--primary {
  background: var(--pasty-accent);
  color: var(--pasty-on-accent);
}

.btn--primary:hover {
  background: var(--pasty-accent-hover);
}

.btn--primary:active {
  background: var(--pasty-accent-down);
}

/* An accent outline on an accent fill is invisible. A white gap between the
   two rings is what makes focus readable on a filled control. */
.btn--primary:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 2px var(--pasty-surface),
    0 0 0 4px var(--pasty-accent);
}

.btn--outline {
  border-color: var(--pasty-border);
  color: var(--pasty-text);
}

.btn--outline:hover,
.btn--quiet:hover {
  background: var(--pasty-hover);
}

.btn--outline:active,
.btn--quiet:active {
  background: var(--pasty-hover-strong);
}

.btn--quiet {
  color: var(--pasty-icon);
}

.btn--quiet:hover {
  color: var(--pasty-text);
}

/* Wide enough for "Copy Markdown", so swapping to "Copied" cannot move the
   header. A confirmation that shifts the layout is worse than no confirmation. */
#copy-markdown {
  min-width: 132px;
}

.btn--block {
  width: 100%;
  height: var(--pasty-control-lg);
  font-size: var(--pasty-text-md);
}

.btn:disabled,
.btn[aria-disabled="true"] {
  color: var(--pasty-text-disabled);
  background: var(--pasty-fill-quiet);
  border-color: transparent;
  cursor: default;
}

.btn--primary:disabled {
  background: var(--pasty-fill-quiet-strong);
  color: var(--pasty-text-disabled);
}

/* ---------- menus (shared primitives) ---------- */

.menu {
  position: relative;
}

.menu > summary {
  list-style: none;
  user-select: none;
}

.menu > summary::-webkit-details-marker {
  display: none;
}

.menu[open] > summary.btn {
  background: var(--pasty-hover-strong);
  color: var(--pasty-text);
}

.menu__chevron {
  flex: 0 0 auto;
  margin-right: -2px;
  transition: transform var(--pasty-t-fast) var(--pasty-ease);
}

.menu[open] .menu__chevron {
  transform: rotate(180deg);
}

.menu__panel {
  position: absolute;
  top: calc(100% + var(--pasty-space-2));
  right: 0;
  z-index: 40;
  width: 260px;
  max-height: 60vh;
  overflow-y: auto;
  padding: var(--pasty-space-1);
  background: var(--pasty-surface-raised);
  border: 1px solid var(--pasty-border-soft);
  border-radius: var(--pasty-radius-lg);
  box-shadow: var(--pasty-shadow-md);
  animation: pasty-pop var(--pasty-t-base) var(--pasty-ease);
}

.menu__item {
  display: flex;
  align-items: center;
  gap: var(--pasty-space-2);
  width: 100%;
  min-height: var(--pasty-control-md);
  padding: var(--pasty-space-1) var(--pasty-space-2);
  border: 0;
  border-radius: var(--pasty-radius-sm);
  background: transparent;
  color: var(--pasty-text);
  font: inherit;
  font-size: var(--pasty-text-sm);
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  transition: background-color var(--pasty-t-fast) var(--pasty-ease);
}

.menu__item:hover {
  background: var(--pasty-hover);
}

.menu__item:active {
  background: var(--pasty-hover-strong);
}

.menu__item[aria-current="page"] {
  font-weight: 600;
}

.menu__item--accent {
  color: var(--pasty-accent);
  font-weight: 500;
}

.menu__header {
  margin: 0;
  padding: var(--pasty-space-2) var(--pasty-space-2) var(--pasty-space-1);
  color: var(--pasty-text-muted);
  font-size: var(--pasty-text-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A radio row: the checkmark is the state, so the row keeps its normal weight
   and the column stays aligned whether or not a row is selected. */
.menu__item--choice::before {
  content: "";
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  background-color: currentcolor;
  opacity: 0;
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m5 12.5 4.5 4.5L19 7.5" fill="none" stroke="black" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>');
  mask-repeat: no-repeat;
  mask-position: center;
}

.menu__item--choice[aria-checked="true"]::before {
  opacity: 1;
}

.menu__item--choice[aria-checked="true"] {
  color: var(--pasty-accent);
}

.menu__separator {
  height: 0;
  margin: var(--pasty-space-1) 0;
  border: 0;
  border-top: 1px solid var(--pasty-border-soft);
}

.menu__empty {
  padding: var(--pasty-space-2);
  color: var(--pasty-text-muted);
  font-size: var(--pasty-text-sm);
}

.doc-menu__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ---------- app header (editor pages) ---------- */

.editor-page {
  min-height: 100vh;
}

/* The band spans the window; its contents do not. */
.app-header {
  position: sticky;
  top: 0;
  z-index: 30;
  display: block;
  height: var(--pasty-header-height);
  padding-inline: var(--pasty-rail-gutter);
  background: var(--pasty-surface);
}

/* THE RAIL. Deliberately the same construct as `.pasty-page` — width 100%, the
   same max-width, auto inline margins, inside the same gutter — so the chrome's
   edges land on the sheet's edges at every viewport width by definition, with
   nothing to compute and nothing to drift. The toolbar strip uses it too.
   Centring was never the problem: the toolbar was already centred on the sheet
   and still read as unrelated, because only edges are legible as alignment. */
.app-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--pasty-space-4);
  width: 100%;
  max-width: var(--pasty-page-max-width);
  height: 100%;
  margin-inline: auto;
}

.app-header__left,
.app-header__right {
  display: flex;
  align-items: center;
  gap: var(--pasty-space-2);
  min-width: 0;
}

.app-header__left {
  flex: 1 1 auto;
}

.app-header__right {
  flex: 0 0 auto;
  gap: var(--pasty-space-1);
}

/* Blue means "action" now, so the wordmark isn't blue. */
.brand {
  flex: 0 0 auto;
  padding: 0 var(--pasty-space-1);
  /* Optical: sit the wordmark's glyphs on the rail, not its padding box. */
  margin-inline-start: calc(-1 * var(--pasty-space-1));
  color: var(--pasty-text);
  font-size: var(--pasty-text-lg);
  font-weight: 600;
  letter-spacing: -0.01em;
  text-decoration: none;
}

/* The title is document metadata — a filename, not a heading. Fixed basis so
   it renders at a readable width instead of collapsing to its content. */
#doc-title-slot {
  flex: 0 1 400px;
  min-width: 0;
}

.logout-form {
  margin: 0;
}

/* ---------- account menu ---------- */

.account-menu__trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--pasty-control-sm);
  height: var(--pasty-control-sm);
  margin-left: var(--pasty-space-1);
  border-radius: 50%;
  background: var(--pasty-fill-quiet);
  color: var(--pasty-text-muted);
  font-size: var(--pasty-text-sm);
  font-weight: 600;
  text-transform: uppercase;
  cursor: pointer;
  transition:
    background-color var(--pasty-t-fast) var(--pasty-ease),
    color var(--pasty-t-fast) var(--pasty-ease);
}

.account-menu__trigger:hover,
.account-menu[open] > .account-menu__trigger {
  background: var(--pasty-fill-quiet-strong);
  color: var(--pasty-text);
}

/* ---------- auth pages ---------- */

.auth-shell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--pasty-space-5);
  min-height: 100vh;
  padding: 64px var(--pasty-space-5);
}

.auth-brand {
  color: var(--pasty-text);
  font-size: var(--pasty-text-xl);
  font-weight: 600;
  letter-spacing: -0.01em;
  text-decoration: none;
}

.auth-card {
  width: 100%;
  max-width: 400px;
  padding: var(--pasty-space-7);
  background: var(--pasty-surface);
  border: 1px solid var(--pasty-border-soft);
  border-radius: var(--pasty-radius-lg);
  box-shadow: var(--pasty-shadow-sm);
}

.auth-title {
  margin: 0 0 var(--pasty-space-2);
  font-size: var(--pasty-text-xl);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.auth-intro {
  margin: 0 0 var(--pasty-space-5);
  color: var(--pasty-text-muted);
}

.auth-links {
  margin: var(--pasty-space-4) 0 0;
  font-size: var(--pasty-text-sm);
}

.auth-footnote {
  margin: 0;
  color: var(--pasty-text-muted);
  font-size: var(--pasty-text-sm);
}

.field {
  margin-bottom: var(--pasty-space-4);
}

.field label {
  display: block;
  margin-bottom: var(--pasty-space-1);
  font-size: var(--pasty-text-sm);
  font-weight: 500;
}

/* Broad enough that a form field added later inherits the system instead of
   falling back to the user agent. */
.field input,
.field select,
.field textarea {
  width: 100%;
  height: var(--pasty-control-lg);
  padding: 0 var(--pasty-space-3);
  border: 1px solid var(--pasty-border);
  border-radius: var(--pasty-radius-md);
  font: inherit;
  font-size: var(--pasty-text-md);
  background: var(--pasty-surface);
  color: var(--pasty-text);
  transition:
    border-color var(--pasty-t-fast) var(--pasty-ease),
    box-shadow var(--pasty-t-fast) var(--pasty-ease);
}

.field textarea {
  height: auto;
  padding: var(--pasty-space-2) var(--pasty-space-3);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  border-color: var(--pasty-accent);
  outline: none;
  box-shadow: 0 0 0 3px var(--pasty-focus-ring);
}

.field--invalid input {
  border-color: var(--pasty-danger);
}

.field__help {
  margin: var(--pasty-space-1) 0 0;
  color: var(--pasty-text-muted);
  font-size: var(--pasty-text-xs);
}

.field__help ul {
  margin: var(--pasty-space-1) 0 0;
  padding-left: 18px;
}

.field__error {
  margin: var(--pasty-space-1) 0 0;
  color: var(--pasty-danger);
  font-size: var(--pasty-text-xs);
}

/* ---------- CLI token page ---------- */

.token-reveal {
  margin-bottom: var(--pasty-space-4);
  padding: var(--pasty-space-3);
  background: var(--pasty-accent-soft);
  border: 1px solid var(--pasty-accent-active);
  border-radius: var(--pasty-radius-md);
}

.token-reveal__value {
  display: block;
  padding: var(--pasty-space-2) var(--pasty-space-3);
  background: var(--pasty-surface);
  border: 1px solid var(--pasty-border-soft);
  border-radius: var(--pasty-radius-sm);
  font-family: var(--pasty-mono);
  font-size: var(--pasty-text-sm);
  overflow-wrap: anywhere;
  user-select: all;
}

.token-reveal__note {
  margin: var(--pasty-space-1) 0;
  font-size: var(--pasty-text-sm);
}

.token-meta {
  margin: 0 0 var(--pasty-space-4);
  font-size: var(--pasty-text-sm);
}

.token-meta div {
  display: flex;
  justify-content: space-between;
  padding: var(--pasty-space-1) 0;
}

.token-meta dt {
  color: var(--pasty-text-muted);
}

.token-meta dd {
  margin: 0;
}

/* Every code chip on an auth page, except the token itself — which is a block
   the user is meant to select whole, and has its own treatment above. */
.auth-card code:not(.token-reveal__value) {
  padding: 1px 5px;
  border-radius: var(--pasty-radius-sm);
  background: var(--pasty-surface-sunken);
  font-family: var(--pasty-mono);
  font-size: 0.9em;
}

/* One error palette, shared with the editor's save-problem note. */
.form-errors {
  margin-bottom: var(--pasty-space-4);
  padding: var(--pasty-space-3);
  border: 1px solid var(--pasty-danger-border);
  border-radius: var(--pasty-radius-md);
  background: var(--pasty-danger-soft);
  color: var(--pasty-danger);
  font-size: var(--pasty-text-sm);
}

.form-errors p {
  margin: 0;
}

/* ---------- narrow screens ----------
   Desktop is the priority. What survives here is the loop itself: the document,
   its title, and Copy Markdown. */

/* Edge-to-edge below this point: the sheet loses its side borders, so there is
   no longer an edge to align to. Chrome keeps a small gutter because text
   touching the window edge reads as broken. */
@media (max-width: 900px) {
  :root {
    --pasty-rail-gutter: var(--pasty-space-2);
  }
}

@media (max-width: 720px) {
  /* The title takes what's left rather than reserving a fixed column. */
  #doc-title-slot {
    flex: 1 1 auto;
  }

  /* Visually hidden rather than removed: the live region still announces every
     save, it just stops competing for pixels there aren't any of. */
  #save-status-slot {
    position: absolute;
    width: 1px;
    height: 1px;
    min-width: 0;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
  }

  /* Create account is the conversion path; the anonymous banner carries a
     log-in link, and the signup page offers one too. */
  .app-header__right > .btn--quiet {
    display: none;
  }

  .auth-card {
    padding: var(--pasty-space-5);
  }
}

/* Past this point the title field is narrower than the word "Untitled", which
   reads as a broken control rather than a quiet one. The document and the loop
   around it still work; the filename waits for a wider screen. */
@media (max-width: 560px) {
  #doc-title-slot {
    display: none;
  }
}

