/*
  The new design's tokens and controls, linked after app.css on every page.

  ## Why everything here is namespaced

  This sheet loads wherever app.css does, and app.css is the stylesheet of every admin view and of
  the canvas too. So nothing in it may touch a page that did not ask for it:

  - Tokens are `--ds-*` only. The design's own names (`--bg`, `--panel`, `--line`, `--ink`, `--blue`,
    `--edge`, `--hover`, `--danger`, `--accent-solid`) are all read somewhere already, by the
    shortcuts sheet, the presenter, the space details, entity displays or core's shared elements, so
    declaring one would restyle those. `--edge` in particular is what
    `tests/core/unit/sharedElementPalette.test.ts` proves atomics does *not* declare.
  - Every rule that styles an element sits under `[ds]`, an attribute a redesigned page puts on its
    own root. A page without it gets the tokens and nothing else.

  ## Why plain hex and not `light-dark()`

  `light-dark()` works here, but a token is also read by scripts: `getPropertyValue` hands back the
  raw function, and a canvas `fillStyle` refuses it. So each scheme gets its own block, keyed on
  `:root[data-theme]`, which core sets on `<html>` before first paint (not `body[theme]`, which only
  arrives with `/init.js`).

  `[data-ds-scheme]` pins a subtree to one scheme whatever the page is in: the landing's dark bands,
  and `/labs/kit`, which shows both side by side.

  ## Composite tokens

  A custom property is resolved where it is declared, then inherited as a finished value. A shadow
  written as `0 0 0 1px var(--ds-line)` on `:root` alone would carry the root's line colour into a
  dark band. So the composites are declared again on every element that can change what they are
  built from: the root, each pinned scheme, and each `[ds]` root.
*/

:root,
[data-ds-scheme='light'] {
  --ds-bg: #f5f5f7;
  --ds-panel: #ffffff;
  --ds-panel2: #fbfbfd;
  --ds-ink: #1d1d1f;
  --ds-ink2: #45454a;
  --ds-mute: #6e6e73;
  --ds-line: rgba(0, 0, 0, 0.09);
  /* Opaque, for the dashed "new" tiles and an empty switch track, where a wash would vanish. */
  --ds-line-strong: #c7c7cc;
  --ds-fill: #e8e8ed;
  --ds-chip: #ffffff;
  --ds-board: #efefec;
  --ds-board-dot: rgba(30, 30, 40, 0.14);
  /* A starter's board in miniature: the cards on it, their ruled lines, and its frames. */
  --ds-board-card: #ffffff;
  --ds-board-edge: rgba(0, 0, 0, 0.08);
  --ds-board-lead: #b9b9b4;
  --ds-board-rule: #dcdcd8;
  --ds-board-head: #3a3a3e;
  --ds-board-frame: rgba(255, 255, 255, 0.35);
  --ds-board-frame-edge: rgba(0, 0, 0, 0.12);

  --ds-accent: #2f6bff;
  --ds-accent-hover: #2459d9;
  --ds-on-accent: #ffffff;
  --ds-danger: #e2453a;

  --ds-ok: #2a7a45;
  --ds-ok-soft: #eaf5ec;
  --ds-info: #1a44c4;
  --ds-info-soft: #e8eeff;
  --ds-warn: #9a5310;
  --ds-warn-soft: #fdf0e1;

  --ds-glass: rgba(245, 245, 247, 0.82);
  --ds-popover: rgba(255, 255, 255, 0.96);
  --ds-toast: #1d1d1f;
  --ds-on-toast: #f5f5f7;
  /* The toast is inverted, so its tick takes the other scheme's green. */
  --ds-on-toast-ok: #7fd49a;
  --ds-dot-idle: #d2d2d7;

  /* The new entity look (design steps 39 to 50), read only under `[ent-look]` on a space's view. */
  --ds-ent-ink: #1d1d1f;
  --ds-ent-mute: #6e6e73;
  --ds-ent-line: rgba(0, 0, 0, 0.09);
  --ds-ent-tile: #ffffff;
  --ds-ent-tile-rule: #e8e8ed;
  --ds-ent-card: #ffffff;
  --ds-ent-bar: #fbfbfd;
  --ds-ent-light-idle: #d2d2d7;
  --ds-ent-room-floor: rgba(255, 255, 255, 0.5);
  --ds-ent-room-edge: rgba(0, 0, 0, 0.09);
  --ds-ent-chip: #ffffff;
  --ds-ent-shadow: 0 0 0 1px rgba(0, 0, 0, 0.09), 0 1px 2px rgba(0, 0, 0, 0.05), 0 14px 34px -14px rgba(0, 0, 0, 0.28);
}

:root[data-theme='dark'],
[data-ds-scheme='dark'] {
  --ds-bg: #000000;
  --ds-panel: #1c1c1e;
  --ds-panel2: #232325;
  --ds-ink: #f5f5f7;
  --ds-ink2: #c7c7cc;
  --ds-mute: #a1a1a6;
  --ds-line: rgba(255, 255, 255, 0.11);
  --ds-line-strong: #48484a;
  --ds-fill: #2c2c2e;
  /* Not the design's #2c2c2e: that is the segmented track's own colour, so the selected segment
     disappeared into it. The marketplace file already corrects it to this. */
  --ds-chip: #48484a;
  --ds-board: #141416;
  --ds-board-dot: rgba(255, 255, 255, 0.08);
  --ds-board-card: #2c2c2e;
  --ds-board-edge: rgba(255, 255, 255, 0.06);
  --ds-board-lead: #6e6e73;
  --ds-board-rule: #48484a;
  --ds-board-head: #e5e5ea;
  --ds-board-frame: rgba(255, 255, 255, 0.04);
  --ds-board-frame-edge: rgba(255, 255, 255, 0.14);

  --ds-accent: #2f6bff;
  --ds-accent-hover: #2459d9;
  --ds-on-accent: #ffffff;
  --ds-danger: #e2453a;

  --ds-ok: #7fd49a;
  --ds-ok-soft: #17301f;
  --ds-info: #9db7ff;
  --ds-info-soft: #1d2a55;
  --ds-warn: #f0b979;
  --ds-warn-soft: #3a2a14;

  --ds-glass: rgba(0, 0, 0, 0.72);
  --ds-popover: rgba(44, 44, 46, 0.96);
  --ds-toast: #f5f5f7;
  --ds-on-toast: #1d1d1f;
  --ds-on-toast-ok: #2a7a45;
  --ds-dot-idle: #48484a;

  --ds-ent-ink: #f5f5f7;
  --ds-ent-mute: #a1a1a6;
  --ds-ent-line: rgba(255, 255, 255, 0.12);
  --ds-ent-tile: #2c2c2e;
  /* Not the design's own rule colour, which is the dark tile's colour too, so its lines vanished. */
  --ds-ent-tile-rule: #48484a;
  --ds-ent-card: #1c1c1e;
  --ds-ent-bar: #232325;
  --ds-ent-light-idle: #48484a;
  --ds-ent-room-floor: rgba(255, 255, 255, 0.035);
  --ds-ent-room-edge: rgba(255, 255, 255, 0.12);
  --ds-ent-chip: #1c1c1e;
  --ds-ent-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12), 0 1px 2px rgba(0, 0, 0, 0.05), 0 14px 34px -14px rgba(0, 0, 0, 0.5);
}

/* Only a pinned subtree sets its own colour scheme. The page's is core's, written on <html>. */
[data-ds-scheme='light'] {
  color-scheme: light;
}

[data-ds-scheme='dark'] {
  color-scheme: dark;
}

/* Scheme-free: the same in light and dark. */
:root {
  --ds-font: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI Variable Text', 'Segoe UI', system-ui,
    sans-serif;
  --ds-font-display: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI Variable Display', 'Segoe UI',
    system-ui, sans-serif;
  --ds-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  --ds-r-tab: 8px;
  --ds-r-search: 9px;
  --ds-r-track: 10px;
  --ds-r-menu: 12px;
  --ds-r-thumb: 14px;
  --ds-r-dialog: 16px;
  --ds-r-card: 18px;
  --ds-r-hero: 24px;
  --ds-r-pill: 999px;

  --ds-ease-pop: cubic-bezier(0.2, 0.9, 0.25, 1);
  --ds-ease-reveal: cubic-bezier(0.2, 0.7, 0.2, 1);
  --ds-ease-in-out: cubic-bezier(0.65, 0, 0.25, 1);
  --ds-fast: 150ms;
  --ds-base: 220ms;
  --ds-slow: 360ms;

  --ds-page-max: 1240px;
  --ds-gutter: 32px;
  --ds-header: 52px;

  --ds-close: #ff5f57;
  --ds-close-hover: #e0443e;
  --ds-scrim: rgba(0, 0, 0, 0.32);

  /* Other people, in the order they join. */
  --ds-p1: #2f6bff;
  --ds-p2: #e2453a;
  --ds-p3: #3f9d5b;
  --ds-p4: #9a67e6;
  --ds-p5: #e08a12;

  /*
    The new entity look's colours that are the same in both schemes. A kind badge is white type on
    its tone, the folder is blue whatever the board is, and a sticky note is paper in the dark too.
  */
  --ds-ent-accent: #2f6bff;
  --ds-ent-on-accent: #ffffff;
  --ds-ent-halo: rgba(47, 107, 255, 0.18);
  --ds-ent-handle: #ffffff;
  --ds-ent-on-badge: #ffffff;
  --ds-ent-badge-doc: #2f6bff;
  --ds-ent-badge-pdf: #e2453a;
  --ds-ent-badge-sheet: #3f9d5b;
  --ds-ent-badge-slide: #e08a12;
  --ds-ent-badge-video: #9a67e6;
  --ds-ent-badge-audio: #e0578f;
  --ds-ent-badge-zip: #8e8e93;
  --ds-ent-badge-image: #2a9d8f;
  --ds-ent-video-tile: linear-gradient(145deg, #3a3a42, #0e0e12);
  --ds-ent-folder: linear-gradient(165deg, #6fa8ff, #2f6bff);
  --ds-ent-folder-tab: #5b93ff;
  --ds-ent-folder-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 10px 22px -10px rgba(47, 107, 255, 0.6);
  --ds-ent-folder-count: rgba(255, 255, 255, 0.9);
  --ds-ent-folder-count-ink: #1f55e0;
  --ds-ent-sticky: #fbe7a1;
  --ds-ent-sticky-ink: #1d1d1f;
  --ds-ent-sticky-shadow: 0 1px 1px rgba(0, 0, 0, 0.08), 0 14px 26px -12px rgba(80, 60, 0, 0.4);
  --ds-ent-sticky-mute: rgba(29, 29, 31, 0.55);
  --ds-ent-sticky-avatar: rgba(29, 29, 31, 0.82);
  --ds-ent-photo-shadow: 0 14px 34px -14px rgba(0, 0, 0, 0.35);
  --ds-ent-light-close: #ff5f57;
}

@media (max-width: 720px) {
  :root {
    --ds-gutter: 16px;
  }
}

:root,
[data-ds-scheme],
[ds] {
  --ds-ring: color-mix(in srgb, var(--ds-accent) 45%, transparent);
  --ds-shadow-raised: 0 1px 3px rgba(0, 0, 0, 0.12);
  --ds-shadow-edge: inset 0 0 0 1px var(--ds-line);
  --ds-shadow-lift: inset 0 0 0 1px var(--ds-line), 0 14px 30px rgba(0, 0, 0, 0.1);
  --ds-shadow-pop: 0 0 0 1px var(--ds-line), 0 18px 40px rgba(0, 0, 0, 0.18);
  --ds-shadow-dialog: 0 0 0 1px var(--ds-line), 0 40px 100px rgba(0, 0, 0, 0.35);
  --ds-shadow-toast: 0 18px 40px rgba(0, 0, 0, 0.25);
}

/*
  The base a redesigned page opts into.

  app.css sets Ronzino on every element with `*:not(svg path)`, which outranks inheritance, so a
  font on the page root alone would reach nothing. `[ds] *:not(svg path)` is one attribute more
  specific and wins on every node under the root.
*/

[ds],
[ds] *:not(svg path) {
  font-family: var(--ds-font);
}

[ds] :is(h1, h2, [ds-display]):not(svg path) {
  font-family: var(--ds-font-display);
}

[ds] :is(code, kbd, samp, pre):not(svg path) {
  font-family: var(--ds-mono);
}

[ds] {
  color: var(--ds-ink);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/*
  app.css styles every bare button: ink on paper, 16px, 600, .02em tracking, a 3px corner and a
  300ms `transition: all`, plus a grey `:disabled`. A design button wants none of it, and the
  `transition: all` in particular animates layout. Under `[ds]` a button starts from nothing.
*/
/* Hidden means hidden. The controls below set `display`, which would otherwise outrank the
   browser's own rule for `[hidden]` and show an element its page had hidden. */
[ds][hidden],
[ds] [hidden] {
  display: none !important;
}

[ds] button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: none;
  transition: none;
  outline-color: currentColor;
  cursor: pointer;
}

[ds] button:disabled {
  background: none;
  cursor: not-allowed;
}

[ds] a {
  color: inherit;
  text-decoration: none;
  outline-color: currentColor;
}

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

[ds] ::selection {
  background: color-mix(in srgb, var(--ds-accent) 28%, transparent);
}

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

/* Type. One scale for every page; sizes are the design's. */

[ds] .ds-h1 {
  margin: 0;
  font-size: 40px;
  line-height: 1.1;
  font-weight: 700;
  letter-spacing: -0.03em;
}

[ds] .ds-h2 {
  margin: 0;
  font-size: 28px;
  line-height: 1.2;
  font-weight: 700;
  letter-spacing: -0.02em;
}

[ds] .ds-h3 {
  margin: 0;
  font-size: 17px;
  line-height: 1.35;
  font-weight: 600;
  letter-spacing: -0.01em;
}

[ds] .ds-body {
  margin: 0;
  font-size: 15px;
  line-height: 1.5;
}

[ds] .ds-small {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.45;
}

[ds] .ds-caption {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--ds-mute);
}

[ds] .ds-mute {
  color: var(--ds-mute);
}

/*
  Icons. The shapes live in /assets/svg/ds-*.svg and are painted through a mask, so an icon takes
  the colour of the text around it like an inline one would.
*/

[ds] .ds-i {
  display: inline-block;
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  background-color: currentColor;
  -webkit-mask: var(--ds-i) center / contain no-repeat;
  mask: var(--ds-i) center / contain no-repeat;
}

[ds] .ds-i[data-i='search'] { --ds-i: url('/assets/svg/ds-search.svg'); }
[ds] .ds-i[data-i='plus'] { --ds-i: url('/assets/svg/ds-plus.svg'); }
[ds] .ds-i[data-i='import'] { --ds-i: url('/assets/svg/ds-import.svg'); }
[ds] .ds-i[data-i='grid'] { --ds-i: url('/assets/svg/ds-grid.svg'); }
[ds] .ds-i[data-i='list'] { --ds-i: url('/assets/svg/ds-list.svg'); }
[ds] .ds-i[data-i='sort'] { --ds-i: url('/assets/svg/ds-sort.svg'); }
[ds] .ds-i[data-i='sun'] { --ds-i: url('/assets/svg/ds-sun.svg'); }
[ds] .ds-i[data-i='moon'] { --ds-i: url('/assets/svg/ds-moon.svg'); }
[ds] .ds-i[data-i='device'] { --ds-i: url('/assets/svg/ds-device.svg'); }
[ds] .ds-i[data-i='cloud'] { --ds-i: url('/assets/svg/ds-cloud.svg'); }
[ds] .ds-i[data-i='offline'] { --ds-i: url('/assets/svg/ds-offline.svg'); }
[ds] .ds-i[data-i='check'] { --ds-i: url('/assets/svg/ds-check.svg'); }
[ds] .ds-i[data-i='close'] { --ds-i: url('/assets/svg/ds-close.svg'); }
[ds] .ds-i[data-i='more'] { --ds-i: url('/assets/svg/ds-more.svg'); }
[ds] .ds-i[data-i='chevron'] { --ds-i: url('/assets/svg/ds-chevron.svg'); }
[ds] .ds-i[data-i='starter'] { --ds-i: url('/assets/svg/ds-starter.svg'); }
[ds] .ds-i[data-i='spaces'] { --ds-i: url('/assets/svg/ds-spaces.svg'); }
[ds] .ds-i[data-i='new'] { --ds-i: url('/assets/svg/ds-new.svg'); }
[ds] .ds-i[data-i='bag'] { --ds-i: url('/assets/svg/ds-bag.svg'); }
[ds] .ds-i[data-i='window'] { --ds-i: url('/assets/svg/ds-window.svg'); }
[ds] .ds-i[data-i='storage'] { --ds-i: url('/assets/svg/ds-storage.svg'); }

/*
  Buttons. A pill on the chip colour with a hairline is the everyday one; `is-primary` is ink on the
  page (the design's New space), `is-accent` the blue one (Get, Create), `is-quiet` the bare one
  that only shows a ground on hover (Sort), `is-icon` a round one with no label.
*/

/* The flex box is set here as well as by the button reset, so a link drawn as a button matches. */
[ds] .ds-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  gap: 7px;
  text-decoration: none;
  height: 36px;
  padding: 0 14px;
  border-radius: var(--ds-r-pill);
  background: var(--ds-chip);
  color: var(--ds-ink);
  box-shadow: var(--ds-shadow-edge);
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  transition:
    background-color var(--ds-fast) ease,
    opacity var(--ds-fast) ease,
    box-shadow var(--ds-fast) ease;
}

[ds] .ds-btn:hover {
  background: var(--ds-fill);
}

[ds] .ds-btn.is-primary {
  padding: 0 16px;
  background: var(--ds-ink);
  color: var(--ds-bg);
  box-shadow: none;
  font-weight: 600;
}

[ds] .ds-btn.is-primary:hover {
  opacity: 0.86;
}

[ds] .ds-btn.is-accent {
  padding: 0 16px;
  background: var(--ds-accent);
  color: var(--ds-on-accent);
  box-shadow: none;
  font-weight: 600;
}

[ds] .ds-btn.is-accent:hover {
  background: var(--ds-accent-hover);
}

[ds] .ds-btn.is-danger {
  background: var(--ds-danger);
  color: #ffffff;
  box-shadow: none;
  font-weight: 600;
}

[ds] .ds-btn.is-danger:hover {
  opacity: 0.88;
}

[ds] .ds-btn.is-quiet {
  height: 30px;
  padding: 0 10px;
  border-radius: var(--ds-r-tab);
  background: transparent;
  color: var(--ds-mute);
  box-shadow: none;
  font-size: 13.5px;
  gap: 6px;
}

[ds] .ds-btn.is-quiet:hover {
  background: var(--ds-fill);
  color: var(--ds-ink);
}

[ds] .ds-btn.is-icon {
  width: 32px;
  height: 32px;
  padding: 0;
  background: transparent;
  box-shadow: none;
}

[ds] .ds-btn.is-icon:hover {
  background: var(--ds-fill);
}

[ds] .ds-btn.is-small {
  height: 32px;
  padding: 0 13px;
  font-size: 13.5px;
}

[ds] .ds-btn.is-large {
  height: 44px;
  padding: 0 20px;
  font-size: 15px;
}

[ds] .ds-btn:disabled,
[ds] .ds-btn[aria-disabled='true'] {
  opacity: 0.45;
  pointer-events: none;
}

/*
  A segmented control: a filled track, the chosen segment raised on the chip colour. Drives tabs
  (`aria-selected`), toggles (`aria-pressed`) and radios (`aria-checked`) alike, so the markup keeps
  whichever role is true of it. A count in a `<small>` sits after the label.
*/

[ds] .ds-seg {
  display: inline-flex;
  gap: 2px;
  max-width: 100%;
  padding: 3px;
  border-radius: var(--ds-r-track);
  background: var(--ds-fill);
  /* On a phone a long set scrolls inside its track rather than pushing the page sideways. */
  overflow-x: auto;
  scrollbar-width: none;
}

[ds] .ds-seg::-webkit-scrollbar {
  display: none;
}

[ds] .ds-seg > button {
  flex: 0 0 auto;
}

[ds] .ds-seg > button {
  height: 28px;
  padding: 0 12px;
  border-radius: var(--ds-r-tab);
  color: var(--ds-ink);
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  transition:
    background-color var(--ds-fast) ease,
    box-shadow var(--ds-fast) ease,
    opacity var(--ds-fast) ease;
}

[ds] .ds-seg > button:hover {
  opacity: 0.72;
}

[ds] .ds-seg > button:is([aria-selected='true'], [aria-pressed='true'], [aria-checked='true']) {
  background: var(--ds-chip);
  box-shadow: var(--ds-shadow-raised);
  opacity: 1;
}

[ds] .ds-seg > button.is-icon {
  width: 32px;
  padding: 0;
}

[ds] :is(.ds-seg > button, .ds-chip) small {
  margin-left: 6px;
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--ds-mute);
}

/* Chips: a filter you can turn on, with an optional count. On is ink, like the design's. */

[ds] .ds-chip {
  gap: 0;
  height: 32px;
  padding: 0 13px;
  border-radius: var(--ds-r-pill);
  background: var(--ds-panel);
  color: var(--ds-ink);
  box-shadow: var(--ds-shadow-edge);
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  transition: background-color var(--ds-fast) ease;
}

[ds] .ds-chip:hover {
  background: var(--ds-fill);
}

[ds] .ds-chip:is(.is-on, [aria-pressed='true']) {
  background: var(--ds-ink);
  color: var(--ds-panel);
  box-shadow: none;
}

[ds] .ds-chip:is(.is-on, [aria-pressed='true']) small {
  color: inherit;
  opacity: 0.6;
}

/* One switch. A `<button role="switch">` holding an `<i>` for the track, then its label. */

[ds] .ds-switch {
  gap: 10px;
  min-height: 24px;
  font-size: 14px;
  font-weight: 500;
  color: var(--ds-ink);
}

[ds] .ds-switch > i {
  position: relative;
  flex: 0 0 34px;
  width: 34px;
  height: 20px;
  border-radius: var(--ds-r-pill);
  background: var(--ds-line-strong);
  transition: background-color var(--ds-fast) ease;
}

[ds] .ds-switch > i::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #ffffff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.24);
  transition: transform var(--ds-fast) var(--ds-ease-pop);
}

[ds] .ds-switch[aria-checked='true'] > i {
  background: var(--ds-accent);
}

[ds] .ds-switch[aria-checked='true'] > i::after {
  transform: translateX(14px);
}

[ds] .ds-switch:disabled {
  opacity: 0.45;
}

/* A search field: a `<label>` around an icon, the input and an optional key hint. */

[ds] .ds-search {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 32px;
  padding: 0 10px;
  border-radius: var(--ds-r-search);
  background: var(--ds-fill);
  color: var(--ds-mute);
  font-size: 13.5px;
  cursor: text;
  transition:
    background-color var(--ds-fast) ease,
    box-shadow var(--ds-fast) ease;
}

[ds] .ds-search:focus-within {
  background: var(--ds-panel);
  box-shadow: 0 0 0 3px var(--ds-ring);
}

[ds] .ds-search input {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--ds-ink);
  font: inherit;
}

[ds] .ds-search input::placeholder {
  color: var(--ds-mute);
  opacity: 1;
}

[ds] .ds-search input::-webkit-search-cancel-button {
  display: none;
}

[ds] .ds-search.is-large {
  height: 44px;
  padding: 0 14px;
  border-radius: var(--ds-r-menu);
  background: var(--ds-panel);
  box-shadow: var(--ds-shadow-edge);
  font-size: 15px;
}

[ds] .ds-search.is-large:focus-within {
  box-shadow: 0 0 0 3px var(--ds-ring);
}

[ds] kbd.ds-key,
[ds] .ds-search kbd {
  padding: 1px 6px;
  border-radius: 5px;
  border: 1px solid var(--ds-line);
  color: var(--ds-mute);
  font-family: inherit;
  font-size: 11px;
  line-height: 1.5;
}

/*
  A card: a panel with a hairline that lifts on hover. `.ds-board` is the dotted ground a space or
  a starter is drawn on, at the design's 16:10.
*/

[ds] .ds-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px;
  border-radius: var(--ds-r-card);
  background: var(--ds-panel);
  box-shadow: var(--ds-shadow-edge);
  transition: box-shadow var(--ds-base) ease;
}

[ds] .ds-card:is(a, button, .is-link):hover {
  box-shadow: var(--ds-shadow-lift);
}

[ds] .ds-board {
  position: relative;
  aspect-ratio: 16 / 10;
  width: 100%;
  overflow: hidden;
  border-radius: var(--ds-r-thumb);
  background-color: var(--ds-board);
  background-image: radial-gradient(var(--ds-board-dot) 1.2px, transparent 1.4px);
  background-size: 14px 14px;
  box-shadow: var(--ds-shadow-edge);
}

/* Kind pills: what a marketplace item is. */

/*
  A starter's board drawn inside a .ds-board: the SVG `starterBoardHTML` makes, fitted with its
  proportions kept. Notes take their own paper colour; everything else is a panel with ruled lines.
  The strokes keep their width however far the board is scaled down.
*/
[ds] .ds-board > .kp-b {
  position: absolute;
  inset: 8%;
  width: 84%;
  height: 84%;
  overflow: visible;
}

[ds] .ds-board .kp-b rect {
  fill: var(--ds-board-card);
  stroke: var(--ds-board-edge);
  stroke-width: 1px;
  vector-effect: non-scaling-stroke;
}

[ds] .ds-board .kp-b line {
  stroke: var(--ds-board-rule);
  stroke-width: 3px;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

[ds] .ds-board .kp-b line.is-lead {
  stroke: var(--ds-board-lead);
}

[ds] .ds-board .kp-b line.is-head {
  stroke: var(--ds-board-head);
  stroke-width: 5px;
}

[ds] .ds-board .kp-b .is-frame rect {
  fill: var(--ds-board-frame);
  stroke: var(--ds-board-frame-edge);
  stroke-width: 1.5px;
}

[ds] .ds-board .kp-b :is(.is-text, .is-axis) rect {
  fill: none;
  stroke: none;
}

[ds] .ds-board .kp-b .is-note rect {
  fill: var(--note, #fde68a);
  stroke: none;
}

[ds] .ds-board .kp-b .is-note line {
  stroke: rgba(0, 0, 0, 0.14);
}

[ds] .ds-board .kp-b .is-table line {
  stroke-width: 1px;
}

[ds] .ds-board .kp-b .is-map rect {
  fill: #e3eedc;
  stroke: none;
}

[ds] .ds-board .kp-b .is-map line {
  stroke: #ffffff;
}

[ds] .ds-board .kp-b .is-dark rect {
  fill: #1f2229;
  stroke: none;
}

[ds] .ds-board .kp-b .is-dark line {
  stroke: #3a3e48;
}

[ds] .ds-board .kp-b .is-dark line.is-lead {
  stroke: #5a5f6b;
}

[ds] .ds-board .kp-b .is-axis line {
  stroke: var(--ds-board-lead);
  stroke-width: 2px;
}

/* A starter that is not built yet: the ground, and a word saying so. */
[ds] .ds-board > .kp-soon {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 3px 9px;
  border-radius: var(--ds-r-pill);
  background: var(--ds-fill);
  color: var(--ds-mute);
  font-size: 11px;
  font-weight: 700;
}

[ds] .ds-kind {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: var(--ds-r-pill);
  background: var(--ds-fill);
  color: var(--ds-ink2);
  font-size: 12px;
  font-weight: 700;
  line-height: 1.35;
  white-space: nowrap;
}

[ds] .ds-kind:is(.is-app, .is-info) {
  background: var(--ds-info-soft);
  color: var(--ds-info);
}

[ds] .ds-kind.is-kit {
  background: var(--ds-warn-soft);
  color: var(--ds-warn);
}

[ds] .ds-kind.is-soon {
  color: var(--ds-mute);
}

[ds] .ds-kind.is-pack {
  background: var(--ds-ok-soft);
  color: var(--ds-ok);
}

/* An empty state: an icon in a tile, a line in ink, a line in grey, and at most one action. */

[ds] .ds-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 56px 16px;
  text-align: center;
  color: var(--ds-mute);
  font-size: 14px;
  line-height: 1.45;
}

[ds] .ds-empty > .ds-tile {
  margin-bottom: 6px;
}

[ds] .ds-empty > strong {
  color: var(--ds-ink);
  font-size: 17px;
  font-weight: 600;
}

[ds] .ds-empty > p {
  max-width: 34ch;
  margin: 0;
}

[ds] .ds-empty > .ds-btn {
  margin-top: 10px;
}

[ds] .ds-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--ds-fill);
  color: var(--ds-ink);
}

[ds] .ds-tile > .ds-i {
  width: 20px;
  height: 20px;
}

/*
  Avatars. Yours is the graphite gradient; everybody else takes a presence colour through `--c`.
  A stack overlaps by 4px with a ring of the page between faces, and shows at most two and a +N.
*/

[ds] .ds-avatar {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  overflow: hidden;
  border-radius: 50%;
  background: var(--c, linear-gradient(145deg, #4a4f5c, #1f2229));
  color: #ffffff;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1;
  user-select: none;
}

[ds] .ds-avatar > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

[ds] .ds-avatar.is-large {
  width: 30px;
  height: 30px;
  font-size: 11.5px;
}

[ds] .ds-stack {
  display: inline-flex;
  align-items: center;
}

[ds] .ds-stack > .ds-avatar {
  width: 24px;
  height: 24px;
  font-size: 9.5px;
  box-shadow: 0 0 0 2px var(--ds-ring-ground, var(--ds-bg));
}

[ds] .ds-stack > .ds-avatar + .ds-avatar {
  margin-left: -4px;
}

[ds] .ds-stack > .ds-avatar.is-more {
  background: var(--ds-fill);
  color: var(--ds-ink);
  font-variant-numeric: tabular-nums;
}

/*
  The toast (shared/utils/toast). It carries `ds` itself, so it lands styled on any page, the canvas
  included. Inverted: dark on a light page, light on a dark one.
*/

[ds][ds-toast] {
  position: fixed;
  left: 50%;
  bottom: calc(28px + env(safe-area-inset-bottom, 0px));
  z-index: 10002;
  display: flex;
  align-items: center;
  gap: 10px;
  box-sizing: border-box;
  max-width: calc(100vw - 2 * var(--ds-gutter));
  min-height: 48px;
  padding: 8px 8px 8px 16px;
  border-radius: var(--ds-r-menu);
  background: var(--ds-toast);
  color: var(--ds-on-toast);
  box-shadow: var(--ds-shadow-toast);
  font-size: 14px;
  line-height: 1.35;
  transform: translateX(-50%);
  animation: ds-toast-in var(--ds-base) var(--ds-ease-pop) both;
}

/*
  Over a modal dialog the toast is a popover, in the top layer. A popover's own rules would centre
  it and give it a border, so they are put back to the ones above.
*/
[ds][ds-toast]:popover-open {
  top: auto;
  right: auto;
  width: auto;
  height: auto;
  margin: 0;
  border: 0;
  overflow: visible;
}

/* Inside a space, clear of the toolbar along the bottom. */
[ds][ds-toast][raised] {
  bottom: calc(7rem + env(safe-area-inset-bottom, 0px));
}

[ds][ds-toast][leaving] {
  opacity: 0;
  transform: translate(-50%, 8px);
  transition:
    opacity 180ms ease,
    transform 180ms ease;
  pointer-events: none;
}

@keyframes ds-toast-in {
  from {
    opacity: 0;
    transform: translate(-50%, 10px) scale(0.97);
  }
}

[ds][ds-toast] [ds-toast-text] {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-width: 0;
  padding: 2px 6px 2px 0;
}

[ds][ds-toast] [ds-toast-title] {
  font-weight: 600;
}

[ds][ds-toast] [ds-toast-sub] {
  margin-top: 1px;
  font-size: 12.5px;
  opacity: 0.66;
}

[ds][ds-toast] [ds-toast-mark] {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin-right: -2px;
  background: var(--ds-on-toast-ok);
  -webkit-mask: url('/assets/svg/ds-check.svg') center / contain no-repeat;
  mask: url('/assets/svg/ds-check.svg') center / contain no-repeat;
}

[ds][ds-toast][tone='error'] [ds-toast-mark] {
  width: 10px;
  height: 10px;
  margin: 0 2px;
  border-radius: 50%;
  background: var(--ds-danger);
  -webkit-mask: none;
  mask: none;
}

[ds][ds-toast] :is([ds-toast-action], [ds-toast-link], [ds-toast-dismiss]) {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  height: 32px;
  padding: 0 12px;
  border-radius: var(--ds-r-tab);
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
}

[ds][ds-toast] :is([ds-toast-action], [ds-toast-link]) {
  background: var(--ds-on-toast);
  color: var(--ds-toast);
}

[ds][ds-toast] [ds-toast-dismiss] {
  background: color-mix(in srgb, var(--ds-on-toast) 14%, transparent);
  color: inherit;
}

[ds][ds-toast] :is([ds-toast-action], [ds-toast-link], [ds-toast-dismiss]):hover {
  opacity: 0.86;
}

[ds][ds-toast] :focus-visible {
  outline-color: var(--ds-on-toast);
}

@media (max-width: 720px) {
  [ds][ds-toast] {
    left: var(--ds-gutter);
    right: var(--ds-gutter);
    max-width: none;
    transform: none;
    animation-name: ds-toast-in-phone;
  }

  [ds][ds-toast][leaving] {
    transform: translateY(8px);
  }

  [ds][ds-toast]:popover-open {
    right: var(--ds-gutter);
  }
}

@keyframes ds-toast-in-phone {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}

/*
  The title-bar dialog, for a native `<dialog class="ds-dialog">` opened with `showModal()`:

    <dialog class="ds-dialog" aria-labelledby="…">
      <div class="ds-dialog-bar">
        <button type="button" ds-dialog-close aria-label="Close"></button><i></i><i></i>
        <h2 id="…">New space</h2>
      </div>
      <div class="ds-dialog-body">…</div>
      <div class="ds-dialog-foot">…buttons…</div>
    </dialog>

  `wireDialog` (shared/utils/dialog) closes it from the scrim and the red dot. The dot is drawn
  12px, as the design has it, inside a 24px button so it can be hit. On a phone it is the screen.
*/

[ds] dialog.ds-dialog {
  display: none;
  flex-direction: column;
  box-sizing: border-box;
  width: min(760px, calc(100vw - 48px));
  max-width: none;
  max-height: calc(100dvh - 48px);
  margin: auto;
  padding: 0;
  overflow: hidden;
  border: 0;
  border-radius: var(--ds-r-dialog);
  background: var(--ds-panel);
  color: var(--ds-ink);
  box-shadow: var(--ds-shadow-dialog);
}

[ds] dialog.ds-dialog[open] {
  display: flex;
  animation: ds-dialog-in var(--ds-base) var(--ds-ease-pop) both;
}

[ds] dialog.ds-dialog.is-small {
  width: min(440px, calc(100vw - 48px));
}

[ds] dialog.ds-dialog::backdrop {
  background: var(--ds-scrim);
  animation: ds-fade-in var(--ds-base) ease both;
}

@keyframes ds-dialog-in {
  from {
    opacity: 0;
    transform: translateY(8px) scale(0.98);
  }
}

@keyframes ds-fade-in {
  from {
    opacity: 0;
  }
}

[ds] .ds-dialog-bar {
  position: relative;
  display: flex;
  flex: 0 0 44px;
  align-items: center;
  gap: 8px;
  height: 44px;
  padding: 0 14px;
  border-bottom: 1px solid var(--ds-line);
  background: var(--ds-panel2);
}

[ds] .ds-dialog-bar > i {
  flex: 0 0 12px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--ds-dot-idle);
}

[ds] .ds-dialog-bar > [ds-dialog-close] {
  flex: 0 0 24px;
  width: 24px;
  height: 24px;
  margin: 0 -6px;
  border-radius: 50%;
}

[ds] .ds-dialog-bar > [ds-dialog-close]::before {
  content: '';
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--ds-close);
}

[ds] .ds-dialog-bar > [ds-dialog-close]:hover::before {
  background: var(--ds-close-hover);
}

[ds] .ds-dialog-bar > :is(h2, h3, [ds-dialog-title]) {
  position: absolute;
  left: 76px;
  right: 76px;
  margin: 0;
  overflow: hidden;
  color: var(--ds-mute);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0;
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
  pointer-events: none;
}

[ds] .ds-dialog-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 22px 24px;
  overflow: auto;
}

[ds] .ds-dialog-foot {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
  padding: 14px 24px;
  border-top: 1px solid var(--ds-line);
  background: var(--ds-panel2);
}

@media (max-width: 720px) {
  [ds] dialog.ds-dialog,
  [ds] dialog.ds-dialog.is-small {
    width: 100vw;
    height: 100dvh;
    max-height: none;
    border-radius: 0;
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  [ds] dialog.ds-dialog[open] {
    animation-name: ds-dialog-in-phone;
  }
}

@keyframes ds-dialog-in-phone {
  from {
    transform: translateY(24px);
    opacity: 0;
  }
}

/*
  Keep it: On this device or Synced, for anything that makes a space. Drawn by
  `helpers.atomics.keepIt` (shared/utils/keepIt), on its own or as `<atomics-keep-it>`.

    <div class="ds-keep-it">
      <span class="ds-keep-it-label">Keep it</span>
      <div class="ds-seg ds-keep-it-modes" role="radiogroup">…two [mode] radios…</div>
      <p class="ds-keep-it-note">What the chosen mode means.</p>
      <p class="ds-keep-it-why">Why Synced is off, and the way out.</p>
    </div>

  The segmented control stretches to two equal halves, as the design draws it. An option that is
  off keeps its words and loses its colour, so it still reads as a choice that exists.
*/

[ds] .ds-keep-it {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

[ds] .ds-keep-it-label {
  color: var(--ds-mute);
  font-size: 12.5px;
  font-weight: 600;
}

[ds] .ds-seg.ds-keep-it-modes {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

[ds] .ds-seg.ds-keep-it-modes > button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  height: 30px;
}

[ds] .ds-seg.ds-keep-it-modes > button .ds-i {
  width: 15px;
  height: 15px;
}

[ds] .ds-seg.ds-keep-it-modes > button[disabled] {
  color: var(--ds-mute);
  cursor: not-allowed;
}

[ds] .ds-seg.ds-keep-it-modes > button[disabled]:hover {
  opacity: 1;
}

[ds] .ds-keep-it :is(.ds-keep-it-note, .ds-keep-it-why) {
  margin: 0;
  color: var(--ds-mute);
  font-size: 13px;
  line-height: 1.5;
  text-wrap: pretty;
}

[ds] .ds-keep-it .ds-keep-it-why {
  color: var(--ds-ink);
}

[ds] .ds-keep-it .ds-keep-it-why :is(a, button) {
  padding: 0;
  color: var(--ds-accent);
  font: inherit;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

[ds] .ds-keep-it .ds-keep-it-why :is(a, button):hover {
  text-decoration: underline;
}
