/* castomo board — UI chrome.
 *
 * Tokens mirror packages/shared/src/palette.ts (single source of truth for colour);
 * we only mirror values here because CSS cannot import TS. Keep the two in sync.
 *
 * Layout contract: the canvas fills the viewport and every control floats ABOVE it in
 * its own stacking context with `pointer-events: none` on the wrapper, `auto` on the
 * controls — so a panel can never swallow a canvas gesture that started outside it.
 */

/* THE CASTOMO BRAND. Owner decision 2026-10-07: the board wears castomo's look so it sits
   natively inside castomo.com, the castomo dashboard and dashkit.
   The first block uses castomo-dashkit's OWN token names and the light-mode values of its
   `kit/themes/castomo.css`, so a page that embeds the board and loads a dashkit theme re-skins it
   by cascade, with no fork. The canvas mirrors the same values in @castomo/shared `BRAND`.
   The second block maps this app's historical names onto the brand — every rule below reads
   those, so the brand is changed in ONE place. */
:root {
  --font: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --paper: #F4F5F8;
  --frame: #EBEDF2;
  --paper-2: #FFFFFF;
  --ink: #0B0C10;
  --ink-2: #454A5C;
  --ink-3: #656875;
  --accent: #B8331A;
  --accent-ink: #B8331A;
  --on-accent: #FFFFFF;
  --accent-2: #f05211;
  --radius-tile: 22px;
  --radius-card: 22px;
  --radius-control: 12px;
  --radius-pill: 999px;
  --shadow: 0 1px 2px rgba(11, 12, 16, .05), 0 8px 28px -12px rgba(11, 12, 16, .16);
  --shadow-pop: 0 2px 6px rgba(11, 12, 16, .08), 0 24px 56px -12px rgba(11, 12, 16, .28);
  /* Mixed from the theme exactly as dashkit mixes them, so they follow any host theme. */
  --rule: color-mix(in oklab, var(--ink) 11%, var(--paper-2));
  --rule-strong: color-mix(in oklab, var(--ink) 22%, var(--paper-2));
  --field: color-mix(in oklab, var(--ink) 5%, var(--paper-2));
  --field-hover: color-mix(in oklab, var(--ink) 8%, var(--paper-2));
  --hover: color-mix(in oklab, var(--ink) 5%, transparent);
  --press: color-mix(in oklab, var(--ink) 9%, transparent);
  --accent-soft: color-mix(in oklab, var(--accent-ink) 13%, transparent);
  --accent-hover: color-mix(in oklab, var(--accent) 86%, var(--ink));
  --focus: var(--accent-ink);
  --ok: #0E7C3A;
  --bad: #C2261A;
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --dur-fast: 120ms;
  --dur: 180ms;

  /* This app's names, now pointing at the brand. */
  --canvas-bg: var(--paper);
  --grid-dot: rgba(11, 12, 16, 0.16);
  --chrome-bg: var(--paper-2);
  --chrome-border: var(--rule);
  --chrome-shadow: var(--shadow);
  --chrome-shadow-lg: 0 1px 2px rgba(11, 12, 16, .06), 0 12px 32px -14px rgba(11, 12, 16, .22);
  --icon: var(--ink);
  --icon-hover-bg: var(--hover);
  --icon-active-bg: var(--accent-soft);
  --text-primary: var(--ink);
  --text-secondary: var(--ink-2);
  --text-tertiary: var(--ink-3);
  --selection: var(--accent);
  --danger: var(--bad);
  --success: var(--ok);
  --radius-sm: 8px;
  --radius-md: var(--radius-control);
  --radius-lg: 16px;
  --control-size: 40px;
  /* dashkit's ring: a paper gap, then the accent — visible on any surface, light or tinted. */
  --focus-ring: 0 0 0 2px var(--paper-2), 0 0 0 4px var(--focus);
}

::selection {
  background: var(--accent-soft);
  color: var(--ink);
}

* {
  box-sizing: border-box;
}

html,
body,
#root {
  height: 100%;
  margin: 0;
  overflow: hidden;
  background: var(--canvas-bg);
  font-family: var(--font);
  color: var(--text-primary);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overscroll-behavior: none;
}

.app {
  position: fixed;
  inset: 0;
}

/* ---- canvas ---------------------------------------------------------------- */

.board-canvas {
  position: absolute;
  inset: 0;
  background: var(--canvas-bg);
  touch-action: none; /* pointer events drive the camera, never the browser */
  cursor: default;
  user-select: none;
  -webkit-user-select: none;
}

/* The canvas takes focus on pointerdown (so Tab/Enter reach the board, not the browser). The
   selection outline is its focus indicator; a ring round the whole viewport is noise. */
.board-canvas:focus {
  outline: none;
}

.board-canvas[data-tool="hand"] {
  cursor: grab;
}

.board-canvas[data-panning="1"] {
  cursor: grabbing;
}

.board-canvas[data-space="1"] {
  cursor: grab;
}

/* P2: the transform box is the only affordance with no visible hit target of its own, so
   the cursor is what tells the user a handle is there. Resize handles get the matching
   resize cursor, rotation handles get `grab` (they are dragged, not clicked), and a
   locked item gets `not-allowed` — Miro's lock affordance. */
.board-canvas[data-cursor="ns-resize"] {
  cursor: ns-resize;
}
.board-canvas[data-cursor="ew-resize"] {
  cursor: ew-resize;
}
.board-canvas[data-cursor="nwse-resize"] {
  cursor: nwse-resize;
}
.board-canvas[data-cursor="nesw-resize"] {
  cursor: nesw-resize;
}
.board-canvas[data-cursor="grab"] {
  cursor: grab;
}
.board-canvas[data-cursor="locked"] {
  cursor: not-allowed;
}
/* A mind-map fold toggle is a canvas-drawn button; the hand says it is clickable. */
.board-canvas[data-cursor="pointer"] {
  cursor: pointer;
}

/* Every Konva layer canvas is opaque white: the backdrop must be painted even before the
   first grid frame lands, which is what makes "no white flash, no layout shift" true. */
.board-canvas canvas {
  display: block;
  background: var(--canvas-bg);
}

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

/* ---- chrome scaffolding ---------------------------------------------------- */

.chrome {
  position: absolute;
  inset: 0;
  pointer-events: none;
  display: grid;
  grid-template-rows: auto 1fr auto;
  /* One column that may shrink below its content: an auto column grew to the topbar's width and
     pushed the bottombar (zoom) off-screen with it. */
  grid-template-columns: minmax(0, 1fr);
}

.chrome > * {
  pointer-events: none;
}

.chrome button,
.chrome [role="button"],
.chrome input,
.chrome a,
.chrome [data-interactive] {
  pointer-events: auto;
}

/* ---- top bar --------------------------------------------------------------- */

.topbar {
  grid-row: 1;
  /* The bar owns the top strip: panels dock below it, and if they ever overlap, the bar stays
     clickable rather than a panel swallowing its own close button. */
  position: relative;
  z-index: 50;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px 0;
}

.topbar__side {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.topbar__center {
  display: flex;
  justify-content: center;
  flex: 1;
  min-width: 0;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  height: var(--control-size);
  padding: 0 14px 0 8px;
  background: var(--chrome-bg);
  border: 1px solid var(--chrome-border);
  border-radius: var(--radius-pill);
  box-shadow: var(--chrome-shadow);
  pointer-events: auto;
}

.brand__mark {
  display: block;
  flex: none;
  border-radius: 7px;
}

.brand__title {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 220px;
}

.brand__crumb {
  font-size: 13px;
  color: var(--text-tertiary);
  white-space: nowrap;
}

.avatar {
  width: var(--control-size);
  height: var(--control-size);
  border-radius: 50%;
  /* A paper ring separates the avatar's colour from whatever chrome it sits beside. */
  border: 2px solid var(--paper-2);
  box-shadow: var(--chrome-shadow);
  display: grid;
  place-items: center;
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  background: var(--selection);
  flex: none;
  cursor: pointer;
}

/* ---- toolbars -------------------------------------------------------------- */

.toolbar {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 4px;
  background: var(--chrome-bg);
  border: 1px solid var(--chrome-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--chrome-shadow-lg);
  pointer-events: auto;
  max-width: min(100%, 720px);
  overflow-x: auto;
  scrollbar-width: none;
}

.toolbar::-webkit-scrollbar {
  display: none;
}

.toolbar__sep {
  width: 1px;
  height: 20px;
  margin: 0 4px;
  background: var(--chrome-border);
  flex: none;
}

.tool {
  position: relative;
  width: var(--control-size);
  height: var(--control-size);
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--icon);
  cursor: pointer;
  flex: none;
  transition: background-color 100ms ease-out;
}

.tool:hover {
  background: var(--icon-hover-bg);
}

.tool[aria-pressed="true"] {
  background: var(--icon-active-bg);
  color: var(--selection);
}

.tool:focus-visible,
.chip:focus-visible,
.zoom-btn:focus-visible,
.share-btn:focus-visible,
.panel__close:focus-visible {
  outline: 2px solid var(--selection);
  outline-offset: 2px;
}

/* ---- buttons --------------------------------------------------------------- */

/* THE button. castomo buttons are pills (dashkit --radius-button: 999px) on the paper surface;
   the primary one is filled with the accent. Defined once — an older reset further down used to
   restyle `.btn` as transparent, which turned the filled Share button into floating text. */
.btn {
  height: var(--control-size);
  padding: 0 16px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--chrome-border);
  background: var(--chrome-bg);
  color: var(--text-primary);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.005em;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--chrome-shadow);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.btn:hover {
  background: var(--field);
}

.btn:active {
  background: var(--field-hover);
  transform: translateY(1px);
}

.btn:disabled {
  opacity: 0.5;
  cursor: default;
  transform: none;
}

.btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.share-btn,
.btn--primary {
  background: var(--accent);
  border-color: transparent;
  color: var(--on-accent);
}

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

.share-btn:active,
.btn--primary:active {
  background: var(--accent-hover);
}

/* Open-thread count on the Comments button: a small accent pill that survives the fold below. */
.btn__count {
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
}

/* Folding chrome buttons. Their labels pushed the topbar to 1373px at a 1200px window; below
   1440px the secondary buttons fold to round icon buttons (the label stays as the accessible
   name, visually hidden) and the "back to boards" crumb drops out. */
@media (max-width: 1440px) {
  .btn--fold {
    width: var(--control-size);
    padding: 0;
    justify-content: center;
    gap: 0;
    position: relative;
  }
  .btn--fold .btn__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .btn--fold .btn__count {
    position: absolute;
    top: -4px;
    right: -4px;
    background: var(--accent);
    color: var(--on-accent);
    box-shadow: 0 0 0 2px var(--paper-2);
  }
  .brand__crumb { display: none; }
}

/* ---- bottom bar ------------------------------------------------------------ */

/* Navigation lives bottom-right (behaviours.md VERIFIED); status text sits opposite. */
.bottombar {
  grid-row: 3;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  padding: 0 12px 12px;
}

.zoom {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 4px;
  background: var(--chrome-bg);
  border: 1px solid var(--chrome-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--chrome-shadow-lg);
  pointer-events: auto;
}

.zoom-btn {
  width: var(--control-size);
  height: var(--control-size);
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--icon);
  font-family: inherit;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}

.zoom-btn:hover {
  background: var(--icon-hover-bg);
}

.zoom-value {
  min-width: 58px;
  height: var(--control-size);
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text-primary);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}

.zoom-value:hover {
  background: var(--icon-hover-bg);
}

.status {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-radius: 999px;
  background: var(--chrome-bg);
  border: 1px solid var(--chrome-border);
  box-shadow: var(--chrome-shadow);
  font-size: 12px;
  color: var(--text-tertiary);
  pointer-events: auto;
  max-width: 46vw;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.status__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  background: var(--text-tertiary);
}

.status__dot[data-state="connected"] {
  background: var(--success);
}

.status__dot[data-state="connecting"] {
  background: var(--accent);
}

/* P8b: while the socket is down the state text becomes the retry control. It inherits the
   pill's typography and only earns an underline on hover, so a healthy board shows no
   affordance at all — a permanent "Reconnect" button on a connected board is noise. */
.status__retry {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.status__retry:hover {
  color: var(--text-primary);
}

.status__retry:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ---- sticky contextual toolbar (P3) ----------------------------------------- */

/* Floats above the selected note. `position: absolute` at 0,0 with a JS-written transform:
   the bar has to track the camera at 60fps and a React render per frame would put the whole
   tree in the panning hot path. */
.stickybar {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px;
  background: var(--chrome-bg);
  border: 1px solid var(--chrome-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--chrome-shadow-lg);
  pointer-events: auto;
  will-change: transform;
}

.stickybar__swatches,
.stickybar__sizes {
  display: flex;
  align-items: center;
  gap: 2px;
}

.stickybar__sep {
  width: 1px;
  align-self: stretch;
  margin: 2px 2px;
  background: var(--chrome-border);
}

/* 24px hit target, 16px swatch: the control meets the >=32px rule via its own padding. */
.swatch {
  width: 24px;
  height: 24px;
  padding: 4px;
  border: 0;
  border-radius: var(--radius-sm);
  background-clip: content-box;
  cursor: pointer;
}

.swatch:hover {
  box-shadow: 0 0 0 2px var(--icon-hover-bg);
}

.swatch[aria-pressed="true"] {
  box-shadow: 0 0 0 2px var(--selection);
}

.sizebtn {
  width: 28px;
  height: 32px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  cursor: pointer;
}

/* The real note aspect ratio: 199x228, 350x228, 350x340. */
.sizebtn__box {
  display: block;
  width: 16px;
  max-height: 20px;
  background: var(--icon-hover-bg);
  border: 1px solid var(--chrome-border);
  border-radius: 2px;
}

.sizebtn:hover {
  background: var(--icon-hover-bg);
}

.sizebtn[aria-pressed="true"] .sizebtn__box {
  border-color: var(--selection);
  background: var(--icon-active-bg);
}

.swatch:focus-visible,
.sizebtn:focus-visible,
.board-textedit:focus-visible {
  outline: 2px solid var(--selection);
  outline-offset: 2px;
}

/* ---- inline note editing (P3) ---------------------------------------------- */

/* The keystroke sink. It is transparent and one pixel wide because the GLYPHS are drawn on
   the Konva canvas, where they scale and rotate with the note; this element exists only to
   give the browser a real input to focus, so the IME candidate window, the on-screen keyboard
   and the system clipboard all work. It is parked ON the caret (see TextEditor) so the IME
   popup appears where the user is typing, and `pointer-events: none` guarantees it can never
   swallow a canvas gesture. */
.board-textedit {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: 0;
  border: 0;
  outline: none;
  resize: none;
  overflow: hidden;
  opacity: 0;
  z-index: 1;
  pointer-events: none;
  white-space: pre;
}

.board-canvas[data-editing] {
  cursor: text;
}

/* ---- panels ---------------------------------------------------------------- */

/* Visible only on keyboard focus: the escape hatch out of the role="application" canvas. */
.skip-link {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 40;
  transform: translateY(-200%);
  padding: 10px 14px;
  border-radius: var(--radius-md);
  border: 1px solid var(--chrome-border);
  background: var(--chrome-bg);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  box-shadow: var(--chrome-shadow-lg);
  cursor: pointer;
}

.skip-link:focus {
  transform: translateY(0);
}

.skip-link:focus-visible {
  outline: 2px solid var(--selection);
  outline-offset: 2px;
}

.panel {
  position: absolute;
  top: 60px;
  right: 12px;
  width: min(340px, calc(100vw - 24px));
  padding: 16px;
  border-radius: 20px;
  background: var(--chrome-bg);
  border: 1px solid var(--chrome-border);
  box-shadow: var(--chrome-shadow-lg);
  pointer-events: auto;
}

.panel__title {
  margin: 0 0 12px;
  font-size: 14px;
  font-weight: 700;
}

.panel__list {
  margin: 0;
  display: grid;
  gap: 6px;
  font-size: 13px;
  color: var(--text-secondary);
}

.panel__row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}

.panel__row kbd {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  padding: 1px 5px;
  border: 1px solid var(--chrome-border);
  border-radius: 4px;
  background: var(--icon-hover-bg);
  color: var(--text-primary);
  white-space: nowrap;
}

.panel__close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
}

.panel__close:hover {
  background: var(--icon-hover-bg);
}

@media (max-width: 720px) {
  .brand__title,
  .brand__crumb {
    display: none;
  }

  .status {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 0ms !important;
    animation-duration: 0ms !important;
  }
}
/* Comments panel sits ABOVE the canvas in paint order. The canvas is `position: absolute;
   inset: 0` and its Konva stages fill it, so without an explicit z-index the panel rendered
   underneath and every control in it was unclickable — visible, enabled, and mouse-dead. */
.comments-panel {
  /* The `.chrome` wrapper is `pointer-events: none` so the canvas keeps every gesture; a panel
     that inherited that was visible, enabled and completely unclickable. Opt back in here. */
  pointer-events: auto;
  position: absolute;
  top: 64px; /* clear of the top bar: at 16px this panel covered Share and swallowed the click */
  right: 16px;
  bottom: 16px;
  width: 320px;
  z-index: 30; /* above .board-canvas (z-index: auto) and the toolbar cluster */
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  border-radius: 20px; /* castomo floating-panel radius (tile 22 less the hairline) */
  background: var(--chrome-bg);
  border: 1px solid var(--chrome-border);
  box-shadow: var(--chrome-shadow-lg);
  overflow: auto;
  color: var(--text-primary);
  font-size: 14px;
}
/* Shape / text Properties panel (ShapeStylePanel): a castomo floating panel on the right, under the
   top bar and clear of the zoom control. Same paint-order and pointer-events reasons as the
   comments panel above. Every control writes immediately, so the panel is dense but calm: small
   uppercase legends, round swatches, pill size chips, and a segmented pill for alignment. */
.stylepanel {
  pointer-events: auto;
  position: absolute;
  top: 64px;
  right: 16px;
  z-index: 30;
  width: 264px;
  max-height: calc(100% - 64px - 80px); /* top bar above, zoom control below */
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 16px;
  border: 1px solid var(--chrome-border);
  border-radius: 20px;
  background: var(--chrome-bg);
  box-shadow: var(--chrome-shadow-lg);
  color: var(--text-primary);
  font-size: 13px;
}
.stylepanel__title { margin: 0; font-size: 15px; font-weight: 650; letter-spacing: -0.005em; }
.stylepanel__group {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 14px;
  border-top: 1px solid var(--rule);
}
.stylepanel__legend {
  color: var(--text-tertiary);
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
/* 16 colours as an 8x2 grid of round chips; the pressed one gets the focus-style double ring. */
.stylepanel__swatches { display: grid; grid-template-columns: repeat(8, 1fr); gap: 6px; }
.stylepanel__swatch {
  aspect-ratio: 1;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  box-shadow: inset 0 0 0 1px rgba(11, 12, 16, 0.12);
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.stylepanel__swatch:hover:not(:disabled) { transform: scale(1.12); }
.stylepanel__swatch[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--paper-2), 0 0 0 4px var(--ink); }
.stylepanel__swatch:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* label | control | value, on one line. */
.stylepanel__row {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  color: var(--text-secondary);
}
.stylepanel__row output { min-width: 36px; color: var(--text-primary); font-variant-numeric: tabular-nums; text-align: right; }
.stylepanel__row input[type="range"] { width: 100%; margin: 0; accent-color: var(--accent); }
.stylepanel__row select {
  grid-column: 2 / 4;
  min-height: 32px;
  padding: 0 10px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-control);
  background: var(--field);
  color: var(--text-primary);
  font: inherit;
}
.stylepanel__row select:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.stylepanel__sizes { display: flex; flex-wrap: wrap; gap: 4px; }
.stylepanel__size {
  min-width: 34px;
  height: 28px;
  padding: 0 8px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--field);
  color: var(--text-secondary);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.stylepanel__size:hover:not(:disabled) { background: var(--field-hover); color: var(--text-primary); }
.stylepanel__size[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-ink); }
.stylepanel__size:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* Alignment: one segmented pill per axis, spanning the control and value columns. */
.stylepanel__segs {
  grid-column: 2 / 4;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
  padding: 3px;
  border-radius: var(--radius-pill);
  background: var(--field);
}
.stylepanel__seg {
  display: grid;
  place-items: center;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.stylepanel__seg:hover:not(:disabled) { color: var(--text-primary); }
.stylepanel__seg[aria-pressed="true"] {
  background: var(--paper-2);
  color: var(--text-primary);
  box-shadow: 0 1px 2px rgba(11, 12, 16, 0.08), 0 2px 8px -2px rgba(11, 12, 16, 0.10);
}
.stylepanel__seg:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.stylepanel button:disabled { cursor: not-allowed; opacity: 0.5; }
.stylepanel__foot { margin: 0; color: var(--text-tertiary); font-size: 12px; }
/* Phones: a bottom sheet above the zoom control instead of a column over the top bar and toolbar.
   Kept next to the base rule on purpose: an earlier media block loses to it on source order. */
@media (max-width: 720px) {
  .stylepanel {
    top: auto;
    left: 12px;
    right: 12px;
    bottom: 76px;
    width: auto;
    max-height: 46vh;
  }
}

.comments-panel__head { display: flex; align-items: center; justify-content: space-between; }
.comments-panel__head h2 { margin: 0; font-size: 16px; font-weight: 600; }
.comments-panel__close { border: 0; background: transparent; font-size: 18px; cursor: pointer; color: var(--text-secondary); }
.comments-panel__filters { display: flex; gap: 6px; }
.comments-panel__filters button[aria-pressed="true"] { background: var(--icon-active-bg); color: var(--accent-ink); }
.comments-panel__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.comment-thread__open { display: block; width: 100%; text-align: left; background: transparent; border: 0; cursor: pointer; }
.comment-thread__body { display: block; color: var(--text-secondary); }
.comment-composer { width: 100%; font: inherit; padding: 6px; border-radius: 8px; border: 1px solid var(--chrome-border); }
.comments-panel__new { display: flex; flex-direction: column; gap: 6px; }

/* Members panel: same surface language as the comments panel, docked right below it. */
.members-panel {
  pointer-events: auto; /* .chrome is pointer-events:none; opt back in */
  position: absolute;
  top: 64px; /* clear of the top bar, same reason as the comments panel */
  right: 352px; /* clears the comments panel when both are open */
  width: 320px;
  max-height: 70vh;
  overflow: auto;
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  border-radius: 20px;
  background: var(--chrome-bg);
  border: 1px solid var(--chrome-border);
  box-shadow: var(--chrome-shadow-lg);
  color: var(--text-primary);
  font-size: 14px;
}
.members-panel__head { display: flex; align-items: center; justify-content: space-between; }
.members-panel__head h2 { margin: 0; font-size: 16px; font-weight: 600; }
.members-panel__label { color: var(--text-secondary); font-size: 13px; }
.members-panel__add { display: flex; gap: 6px; }
.members-panel__input { flex: 1; min-width: 0; font: inherit; padding: 6px 8px; border: 1px solid var(--chrome-border); border-radius: 8px; }
.members-panel__role { font: inherit; padding: 6px; border: 1px solid var(--chrome-border); border-radius: 8px; }
.members-panel__error { margin: 0; color: var(--bad); font-size: 13px; }
.members-panel__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.members-panel__list li { display: flex; align-items: center; gap: 8px; }
.members-panel__avatar { width: 24px; height: 24px; border-radius: 100%; color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 600; }
.members-panel__who { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.members-panel__name { font-weight: 500; }
.members-panel__email { color: var(--text-secondary); font-size: 12px; overflow: hidden; text-overflow: ellipsis; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ------------------------------------------------------------------ type + form reset
   Measured against live Miro: Noto Sans at 14/16/18px in weights 400/500/600, radii 8/16/100%.
   Before this reset, every <button>/<select>/<input> fell back to the UA default —
   `13.33px Arial` — which the token probe caught as a completely foreign type scale. Form
   controls do NOT inherit font by default; this is the whole fix. */

.app,
.board-shell {
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-primary);
}

button,
input,
select,
textarea,
optgroup {
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  color: inherit;
}

/* Quiet buttons inside panels: 40px hit area, no surface until hovered. The chrome's `.btn` is
   its own component above and is deliberately NOT listed here. */
.members-panel button:not(.btn),
.comments-panel button:not(.btn),
.icon-btn {
  min-height: 40px;
  padding: 0 12px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  background: transparent;
  cursor: pointer;
  font-weight: 500;
  transition: background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.members-panel button:not(.btn):hover,
.comments-panel button:not(.btn):hover,
.icon-btn:hover {
  background: var(--hover);
}
.members-panel :is(button, input, select):focus-visible,
.comments-panel :is(button, textarea):focus-visible,
.icon-btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* Headings use the measured weight steps rather than browser defaults. */
.topbar h1,
.members-panel__head h2,
.comments-panel__head h2 {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.members-panel__name,
.comment-thread__author {
  font-weight: 500;
}
.members-panel__email,
.members-panel__label,
.comment-thread__body {
  font-size: 13px;
  color: var(--text-secondary);
}

/* Inputs and selects read as fields, not as native chrome. */
/* dashkit fields: a faint ink tint instead of a drawn box, an edge only when focused. */
.members-panel__input,
.members-panel__role,
.comment-composer,
.boards-view__search {
  min-height: 40px;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  background: var(--field);
  color: var(--ink);
  padding: 0 12px;
  transition: background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
:is(.members-panel__input, .members-panel__role, .comment-composer, .boards-view__search):hover {
  background: var(--field-hover);
}
:is(.members-panel__input, .comment-composer, .boards-view__search)::placeholder {
  color: var(--ink-3);
}
.comment-composer {
  min-height: 0;
  padding: 8px 10px;
  resize: vertical;
}
.comment-composer:focus-visible,
.members-panel :is(input, select):focus-visible {
  outline: none;
  border-color: var(--focus);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Avatar / pill shapes are fully round (measured 100% radius). */
/* Board title: the measured 18px/600 step, so the scale is a superset of Miro's rather than a
   subset — a board editor should not be missing a type step that exists in the product. */
.board-title,
.topbar h1 {
  font-size: 18px;
  font-weight: 600;
}

.avatar,
.members-panel__avatar {
  border-radius: 100%;
  font-weight: 600;
  display: grid;
  place-items: center;
  color: #ffffff;
}

/* ------------------------------------------------------------------ boards view
   The front door, in castomo's tile language: 22px tiles on paper, the soft two-layer shadow,
   a lift on hover, pill controls. It covers the canvas, so the board chrome is hidden while it
   shows (App sets data-front-door) and this view carries its own header. */
.chrome[data-front-door] > .topbar,
.chrome[data-front-door] > .bottombar {
  display: none;
}

.boards-view {
  position: absolute;
  inset: 0;
  z-index: 60;
  pointer-events: auto; /* `.chrome > *` is pointer-events:none; this view must scroll and click */
  overflow: auto;
  padding: 40px 32px 72px;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-size: 14px;
}
.boards-view__inner { max-width: 1180px; margin: 0 auto; }

.boards-view__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 32px;
}
.boards-view__brand { display: flex; align-items: center; gap: 12px; min-width: 0; }
.boards-view__brand svg { flex: none; border-radius: 8px; box-shadow: var(--shadow); }
.boards-view__head h1 { margin: 0; font-size: 22px; font-weight: 650; letter-spacing: -0.02em; }
.boards-view__actions { display: flex; align-items: center; gap: 10px; }

.boards-view__error {
  margin: 0 0 20px;
  padding: 10px 14px;
  border-radius: var(--radius-control);
  background: color-mix(in oklab, var(--bad) 8%, var(--paper-2));
  color: var(--bad);
  font-size: 13px;
  font-weight: 500;
}

.boards-view__search { width: 100%; max-width: 420px; font: inherit; }
.boards-view__search:focus-visible {
  outline: none;
  border-color: var(--focus);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Segmented pill: the filters were bare text, and the pressed one an ellipse (radius 100%). */
.boards-view__filters {
  display: flex;
  width: max-content;
  max-width: 100%;
  gap: 2px;
  margin: 16px 0 24px;
  padding: 4px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper-2);
  box-shadow: var(--shadow);
}
.boards-view__filters button {
  min-height: 32px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.boards-view__filters button:hover { background: var(--hover); color: var(--ink); }
.boards-view__filters button[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-ink); }
.boards-view__filters button:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.boards-view__grid,
.boards-view__templates {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 20px;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}

/* A tile: 22px outer radius, and every inset surface uses 22 − 10 (the padding) = 12, so the
   corners stay concentric instead of a sharp rectangle sitting in a round one. */
.board-card,
.template-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  height: 100%;
  padding: 10px 10px 16px;
  text-align: left;
  border: 1px solid color-mix(in oklab, var(--ink) 6%, transparent);
  border-radius: var(--radius-tile);
  background: var(--paper-2);
  box-shadow: var(--shadow);
  color: var(--ink);
  font: inherit;
  cursor: pointer;
  transition:
    box-shadow var(--dur) var(--ease-out),
    transform var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out);
}
.board-card:hover,
.template-card:hover:not(:disabled) {
  box-shadow: var(--shadow-pop);
  transform: translateY(-2px);
  border-color: color-mix(in oklab, var(--ink) 9%, transparent);
}
.board-card:active,
.template-card:active:not(:disabled) { transform: translateY(0); box-shadow: var(--shadow); }
.board-card:focus-visible,
.template-card:focus-visible { outline: none; box-shadow: var(--shadow), var(--focus-ring); }
.template-card:disabled { cursor: progress; opacity: 0.6; }

/* Text sits on the tile's padding plus 6px, aligned with the inset preview's rounded corner. */
.board-card__title,
.template-card__title,
.board-card__meta,
.template-card__category,
.board-card__role,
.template-card__cta { padding: 0 6px; }
.board-card__title,
.template-card__title {
  margin-top: 8px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.board-card__meta,
.template-card__category { color: var(--ink-3); font-size: 13px; }
.board-card__role { color: var(--ink-3); font-size: 12px; }
.template-card__cta {
  margin-top: auto;
  padding-top: 8px;
  color: var(--accent-ink);
  font-size: 13px;
  font-weight: 600;
}

.boards-view__subhead { margin: 48px 0 16px; font-size: 17px; font-weight: 650; letter-spacing: -0.015em; }
.boards-view__empty {
  margin: 0;
  padding: 28px;
  border: 1px dashed var(--rule-strong);
  border-radius: var(--radius-tile);
  color: var(--ink-3);
  text-align: center;
}

/* Inset previews: dotted paper, the same dot the canvas draws, so a tile reads as a board. */
.board-card__thumb,
.template-card__preview {
  display: block;
  position: relative;
  width: 100%;
  height: 132px;
  border-radius: 12px;
  background-color: var(--paper);
  background-image: radial-gradient(circle, rgba(11, 12, 16, 0.12) 1px, transparent 1.4px);
  background-size: 14px 14px;
  background-position: 7px 7px;
  overflow: hidden;
}
.board-card__thumb { object-fit: cover; }
.board-card__thumb--empty,
.template-card__preview--empty { background-color: var(--frame); }

.template-card__stage { position: absolute; inset: 18px 22px; }
.template-card__box {
  position: absolute;
  border-radius: 3px;
  background: color-mix(in oklab, var(--ink) 14%, var(--paper-2));
  box-shadow: 0 1px 1.5px rgba(11, 12, 16, 0.08);
}
.template-card__box--sticky_note { background: #FFF2A8; border-radius: 2px; }
.template-card__box--shape { background: var(--paper-2); box-shadow: inset 0 0 0 1px var(--rule-strong); }
.template-card__box--frame {
  background: color-mix(in oklab, var(--paper-2) 70%, transparent);
  box-shadow: inset 0 0 0 1px var(--rule);
  border-radius: 4px;
}
.template-card__box--text { background: var(--ink-3); height: 3px !important; border-radius: 2px; box-shadow: none; }
.template-card__box--connector { background: var(--ink-2); height: 1.5px !important; box-shadow: none; }
.template-card__box--mindmap_node { background: var(--paper-2); border-radius: 999px; box-shadow: inset 0 0 0 1px var(--accent); }

/* A control you can see should be a control you can hit. The offline retry pill rendered 17px tall
   and had no accessible name of its own (it borrowed its text from the status line). */
.status__retry {
  min-height: 32px;
  padding: 0 12px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--chrome-border);
  background: var(--chrome-bg);
  color: var(--text-primary);
  font: inherit;
  cursor: pointer;
}
.status__retry:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.comment-thread__reactions { display: flex; gap: 4px; margin: 6px 0; }
.comment-thread__reactions button {
  display: inline-flex; align-items: center; gap: 3px;
  min-width: 32px; min-height: 28px; padding: 0 8px;
  border: 1px solid var(--chrome-border); border-radius: var(--radius-pill);
  background: var(--chrome-bg); cursor: pointer; font-size: 13px; line-height: 1;
}
.comment-thread__reactions button.is-mine { border-color: var(--accent); background: var(--icon-active-bg); }
.comment-thread__reactions button:disabled { opacity: 0.5; cursor: default; }
.comment-thread__count { font-size: 11px; color: var(--text-secondary); }

.members-panel__invites { border-top: 1px solid var(--chrome-border); padding-top: 8px; }
.members-panel__invites h3 { margin: 0 0 6px; font-size: 13px; font-weight: 500; color: var(--text-secondary); }
.members-panel__invites ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.members-panel__invites li { display: flex; align-items: center; gap: 8px; justify-content: space-between; font-size: 13px; }

/* ------------------------------------------------------------------ narrow screens
   The toolbar overflowed a 390px viewport by ~45px: every tool wrapped into a second row that
   covered the canvas, and the top bar had nowhere to put its buttons. Miro's answer is the obvious
   one - the tool strip scrolls horizontally and stays one row. */
@media (max-width: 900px) {
  .toolbar {
    max-width: calc(100vw - 24px);
    overflow-x: auto;
    overflow-y: hidden;
    flex-wrap: nowrap;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .toolbar::-webkit-scrollbar { display: none; }

  /* The toolbar was centred inside a column that itself started off-screen, so a fitting toolbar
     still hung 30px past the right edge. On a phone the strip gets its own full-width row. */
  .topbar { padding: 8px 8px 0; gap: 8px; flex-wrap: wrap; }
  /* flex-basis 100%, not just width: the desktop rule gives this column a zero basis, so on a top
     bar with fewer buttons (a sandbox board has no Share) it fitted the first line and shrank to
     nothing instead of wrapping. */
  .topbar__center { order: 3; flex: 0 0 100%; width: 100%; min-width: 0; display: flex; }
  .topbar__side { order: 1; }
  .toolbar { margin: 0 auto; }
  .topbar__side .btn { height: 36px; font-size: 13px; }
  .topbar__side .btn--fold { width: 36px; }

  .members-panel, .comments-panel {
    top: 56px;
    left: 8px;
    right: 8px;
    width: auto;
    max-height: 52vh;
  }

  .boards-view { padding: 20px 16px 48px; }
  .boards-view__head { margin-bottom: 20px; }
  .boards-view__brand svg { width: 28px; height: 28px; }
  .boards-view__head h1 { font-size: 19px; }
  .boards-view__subhead { margin-top: 36px; }
  .board-card__thumb, .template-card__preview { height: 104px; }
  .template-card__stage { inset: 14px 16px; }
  .boards-view__grid, .boards-view__templates { grid-template-columns: repeat(auto-fill, minmax(156px, 1fr)); gap: 12px; }
}

/* Touch gestures belong to the canvas, not to the browser's page handling: without this a one-finger
   drag scrolls the page and a two-finger pinch zooms the viewport instead of the board. */
.board-canvas, .konvajs-content canvas {
  touch-action: none;
}

/* Refusals are brief and dark: castomo's ink plate, pill-shaped, lifted like a popover. */
.refusal-toast {
  position: absolute;
  left: 50%;
  top: 72px;
  transform: translateX(-50%);
  z-index: 40;
  pointer-events: none;
  margin: 0;
  padding: 10px 18px;
  border-radius: var(--radius-pill);
  background: var(--ink);
  color: var(--paper-2);
  font-size: 13px;
  font-weight: 500;
  box-shadow: var(--shadow-pop);
}

/* The sign-in card: a castomo tile with the castomo mark, one sentence on what the account is, and
   two buttons that both leave for the castomo account service (no password form on boards). */
.auth-panel {
  display: grid;
  gap: 12px;
  max-width: 420px;
  margin: 0 0 8px;
  padding: 22px;
  border: 1px solid color-mix(in oklab, var(--ink) 6%, transparent);
  border-radius: var(--radius-tile);
  background: var(--paper-2);
  box-shadow: var(--shadow);
}
.auth-panel__head { display: flex; align-items: center; gap: 12px; }
.auth-panel__title { margin: 0; font-size: 17px; font-weight: 650; letter-spacing: -0.01em; line-height: 1.25; }
.auth-panel__body { margin: 0; color: var(--ink-2); font-size: 14px; line-height: 1.5; }
.auth-panel__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 2px; }
.auth-panel .btn { justify-content: center; }
.auth-panel__error { margin: 0; color: var(--bad); font-size: 13px; font-weight: 500; }

/* /auth/callback and sandbox start-up errors: the same card, alone and centred on castomo paper. */
.callback-view {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 16px;
  background: var(--paper);
}
.callback-view .auth-panel { width: min(420px, 100%); margin: 0; }

/* The account chip in the front door header: avatar initial + name; a small menu below it. */
.account-menu { position: relative; }
.account-menu__chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 14px 0 4px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper-2);
  box-shadow: var(--shadow);
  cursor: pointer;
  list-style: none;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}
.account-menu__chip::-webkit-details-marker { display: none; }
.account-menu__chip:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.account-menu__avatar {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-pill);
  background: var(--ink);
  color: var(--paper-2);
  font-size: 13px;
  font-weight: 700;
}
.account-menu__name { max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.account-menu__pop {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  z-index: 70;
  display: grid;
  min-width: 240px;
  padding: 8px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
  background: var(--paper-2);
  box-shadow: var(--shadow-pop);
}
.account-menu__email { margin: 4px 10px 8px; color: var(--ink-3); font-size: 12px; overflow-wrap: anywhere; }
.account-menu__item {
  display: block;
  padding: 10px;
  border: 0;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.account-menu__item:hover { background: var(--hover); }
.account-menu__item:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* The sandbox's keep bar: an ink plate centred at the bottom, between the status pill and the zoom
   control. It is the one thing the sandbox asks of the visitor, so it is the darkest object on the
   page; once kept it says so and offers the way into boards. */
.sandbox-bar {
  pointer-events: auto;
  position: fixed;
  left: 50%;
  bottom: 16px;
  transform: translateX(-50%);
  z-index: 65;
  display: flex;
  align-items: center;
  gap: 14px;
  width: max-content;
  max-width: min(760px, calc(100vw - 32px));
  padding: 8px 8px 8px 18px;
  border-radius: var(--radius-pill);
  background: var(--ink);
  color: var(--paper-2);
  box-shadow: var(--shadow-pop);
}
.sandbox-bar__note { flex: 1 1 auto; min-width: 0; margin: 0; font-size: 13px; line-height: 1.35; color: color-mix(in oklab, var(--paper-2) 82%, transparent); }
.sandbox-bar[data-state="kept"] .sandbox-bar__note { color: var(--paper-2); font-weight: 600; }
.sandbox-bar__actions { display: flex; gap: 6px; flex: none; }
.sandbox-bar .btn:not(.btn--primary) { background: color-mix(in oklab, var(--paper-2) 12%, transparent); color: var(--paper-2); border-color: transparent; }
.sandbox-bar .btn:not(.btn--primary):hover { background: color-mix(in oklab, var(--paper-2) 20%, transparent); }
@media (max-width: 720px) {
  .sandbox-bar {
    left: 12px;
    right: 12px;
    bottom: 72px;
    transform: none;
    width: auto;
    max-width: none;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    padding: 12px;
    border-radius: 20px;
  }
  .sandbox-bar__actions .btn { flex: 1; justify-content: center; }
}

/* Language switcher: a small segmented pill, on the board topbar and in the front door's header. */
.lang-switch {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-pill);
  background: var(--paper-2);
  box-shadow: var(--shadow);
  pointer-events: auto;
}
.lang-switch button {
  min-height: 32px;
  min-width: 40px;
  padding: 0 10px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 0.02em;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.lang-switch button:hover { background: var(--hover); color: var(--ink); }
.lang-switch button[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-ink); }
.lang-switch button:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* A sandbox board (SandboxView) belongs to nobody until it is kept: nothing to share yet. */
:root[data-sandbox] .share-btn { display: none; }

/* An embedded board (EmbedView) lives inside another castomo product, which has its own brand,
   navigation and language. `min` (the default) keeps the tools, comments and zoom, and drops what
   belongs to boards-the-site: the brand and "back to boards", Share, the language switch.
   `none` is a bare canvas — a preview or showcase. `full` changes nothing. */
:root[data-embed="min"] .topbar__side:first-child,
:root[data-embed="min"] .share-btn,
:root[data-embed="min"] .lang-switch { display: none; }
:root[data-embed="none"] .chrome { display: none; }
