/* base.css: the prototype's own global styles, plus Relay's local webfonts.
 *
 * The prototype pulled Hanken Grotesk and JetBrains Mono off Google Fonts.
 * Relay ships both as variable woff2 under /fonts and the board has to work
 * with no network, so the @font-face blocks below are Relay's, lifted from
 * tokens.css unchanged. Everything after them is the prototype's <helmet>
 * verbatim: the scrollbars, the keyframes and the reduced-motion block.
 */

@font-face {
  font-family: "Hanken Grotesk";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/hanken-grotesk-latin.woff2?v=1") format("woff2");
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Hanken Grotesk";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/hanken-grotesk-latin-ext.woff2?v=1") format("woff2");
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/fonts/jetbrains-mono-latin.woff2?v=1") format("woff2");
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/fonts/jetbrains-mono-latin-ext.woff2?v=1") format("woff2");
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ⚠️⚠️ WITHOUT THIS EVERY NATIVE CONTROL PAINTS LIGHT. `color-scheme` was
     absent from the whole of web/, so anything the BROWSER draws rather than
     the stylesheet came out in the light palette on a black app: scrollbars
     on elements that opted into the standard scrollbar, select menus, number
     spinners, date pickers. The rack's scrollbar was the visible one
     because it is the only rule setting `scrollbar-width` without a
     `scrollbar-color`, but it was never the only element affected. One
     declaration, and the class of bug closes rather than the instance. */
:root {
  color-scheme: dark;
  /* #714 THE OVERLAY LAYERS, BY NAME, IN ONE ORDER. Reported 2026-08-12: a
     tooltip drew BEHIND the open Group dropdown. The template had fifteen
     bare z-index numbers and no rule for how they related, so the tooltip
     (300) lost to any row menu (900) and the update toast (200) to both.
     Bottom to top: a dialog's scrim (the dialogs keep their own 60 to 200),
     then anything opened from a control (dropdowns, row and context menus,
     the filter menu), then the tooltip, which must explain whatever it sits
     on, then the toast, which must be read whatever is open. Use the names;
     a new bare number is how the old fault comes back. */
  --z-popover: 900;
  --z-tooltip: 1000;
  --z-toast: 1100;
}
html,
body {
  margin: 0;
  background: #0a0a0a;
}
body {
  overflow: auto;
}
/* #716 Selected text wears the accent at half strength, not the operating
   system's blue, everywhere text can be selected: rows, panels, chat, code,
   inputs, dialogs. ⚠️ BACKGROUND ONLY. Setting no `color` keeps each surface's
   own text colour, which is the one thing guaranteed readable on that surface,
   and it survives the light theme's page wide invert the same way the text
   does. One rule for the whole app, never per component. */
::selection {
  background-color: rgba(255, 138, 0, 0.5);
}
button {
  white-space: nowrap;
  flex: none;
}
a {
  color: var(--brand-text, #ffb45c);
  text-decoration: none;
}
a:hover {
  color: var(--brand-ink, #ff8a00);
}
::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
::-webkit-scrollbar-thumb {
  background: #242424;
  border-radius: 99px;
  border: 3px solid #0a0a0a;
}
::-webkit-scrollbar-track {
  background: transparent;
}
@keyframes om-pageA {
  from {
    opacity: 0;
    transform: translateY(7px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes om-pageB {
  from {
    opacity: 0;
    transform: translateY(7px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes om-pop {
  from {
    opacity: 0;
    transform: translateY(-5px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes om-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes om-reveal {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes om-railin {
  from {
    opacity: 0;
    transform: translateX(26px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes om-modal {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
button,
[role="switch"] {
  transition:
    background-color 0.16s ease,
    border-color 0.16s ease,
    color 0.16s ease,
    box-shadow 0.16s ease,
    transform 0.11s cubic-bezier(0.22, 0.61, 0.36, 1);
}
button:active,
[role="switch"]:active {
  transform: scale(0.965);
}
/* ⭐⭐ #2429 #2430 THE REDESIGNED WORKSPACE CARD (.wsc) replaced .wscard: the
   list view Hero card and the grid view tile, one shared block in relay.html.
   The whole card opens the board, so hover has to SAY so: it lifts, the border
   warms, the cover zooms a little and an "Open board" label takes the role
   badge's place. Reduce motion keeps the colour cues and drops the movement.
   The press is #2054's, kept: a paint only scale, gentler than a button's
   because a large card scaling hard reads as a jump. */
.wsc {
  position: relative;
  background: #101010;
  border: 1px solid #1e1e1e;
  border-radius: 16px;
  overflow: hidden;
  cursor: pointer;
  transition:
    border-color 0.18s ease,
    box-shadow 0.18s ease,
    transform 0.18s ease;
}
.wsc:hover,
.wsc:focus-visible {
  border-color: rgba(255, 138, 0, 0.34);
  box-shadow:
    0 14px 40px rgba(0, 0, 0, 0.35),
    0 0 0 1px rgba(255, 138, 0, 0.34);
  transform: translateY(-2px);
  outline: none;
}
.wsc:active {
  transform: translateY(0) scale(0.996);
}
.wsc-cover {
  position: relative;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}
/* The cover zooms on its own layer so the text over it does not move. */
.wsc-cover::before {
  content: "";
  position: absolute;
  inset: 0;
  background: inherit;
  transition: transform 0.4s ease;
}
.wsc-cover::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0, 0, 0, 0) 30%, rgba(0, 0, 0, 0.72) 100%);
  pointer-events: none;
}
.wsc-tile .wsc-cover::after {
  background: linear-gradient(
    180deg,
    rgba(0, 0, 0, 0.25) 0%,
    rgba(0, 0, 0, 0) 45%,
    rgba(0, 0, 0, 0.35) 100%
  );
}
.wsc:hover .wsc-cover::before,
.wsc:focus-visible .wsc-cover::before {
  transform: scale(1.04);
}
.wsc-over {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 13px;
  width: 100%;
  min-width: 0;
  padding: 16px 18px;
  color: #fff;
}
.wsc-mark {
  width: 50px;
  height: 50px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 13px;
  background: rgba(12, 12, 12, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.2);
  overflow: hidden;
}
/* #2432 an uploaded logo fills its tile, cropped rather than squashed. */
.wsc-logo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.wsc-name {
  display: block;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.wsc-over .wsc-name {
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.5);
}
.wsc-sub {
  display: block;
  font-family: "JetBrains Mono", monospace;
  font-size: 10.5px;
  color: #818181;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.wsc-over .wsc-sub {
  color: rgba(255, 255, 255, 0.75);
}
.wsc-right {
  position: relative;
  margin-left: auto;
  display: flex;
  align-items: center;
  flex: none;
}
.wsc-role {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 3px 8px;
  border: 1px solid;
  border-radius: 999px;
  background: rgba(10, 10, 10, 0.55);
  white-space: nowrap;
  transition: opacity 0.15s ease;
}
.wsc-role-tl {
  position: absolute;
  left: 12px;
  top: 12px;
  z-index: 1;
}
.wsc-go {
  position: absolute;
  right: 0;
  top: 50%;
  margin-top: -14px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 11px;
  border-radius: 999px;
  background: #ff8a00;
  color: #140a00;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  opacity: 0;
  transform: translateX(-6px);
  transition:
    opacity 0.18s ease,
    transform 0.18s ease;
  pointer-events: none;
}
.wsc-go-br {
  top: auto;
  bottom: 12px;
  right: 12px;
  margin-top: 0;
  z-index: 1;
}
.wsc:hover .wsc-go,
.wsc:focus-visible .wsc-go {
  opacity: 1;
  transform: translateX(0);
}
.wsc-hero:hover .wsc-role,
.wsc-hero:focus-visible .wsc-role {
  opacity: 0;
}
.wsc-body {
  display: flex;
  align-items: center;
  gap: 10px 18px;
  flex-wrap: wrap;
  padding: 12px 14px 12px 18px;
  transition: background 0.18s ease;
}
.wsc:hover .wsc-body,
.wsc:hover .wsc-foot {
  background: #141414;
}
.wsc-nums {
  display: flex;
  gap: 6px 18px;
  flex-wrap: wrap;
  font-size: 11px;
  color: #949494;
}
.wsc-nums b {
  font-family: "JetBrains Mono", monospace;
  font-weight: 500;
  font-size: 12.5px;
  margin-right: 5px;
}
.wsc-end {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 2px;
  flex-wrap: wrap;
}
.wsc-toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 28px;
  padding: 0 9px;
  font: inherit;
  font-size: 11px;
  color: #adadad;
  background: transparent;
  border: 0;
  border-radius: 7px;
  cursor: pointer;
  white-space: nowrap;
}
.wsc-toggle:hover {
  background: #1c1c1c;
  color: #f2f2f2;
}
.wsc-ic {
  width: 30px;
  height: 30px;
  display: inline-grid;
  place-items: center;
  padding: 0;
  color: #949494;
  background: transparent;
  border: 0;
  border-radius: 8px;
  cursor: pointer;
}
.wsc-ic:hover {
  background: #1c1c1c;
  color: #f2f2f2;
}
.wsc-exp {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 10px;
  padding: 14px 18px;
  border-top: 1px solid #1a1a1a;
  cursor: default;
}
.wsc-exp-tile {
  grid-template-columns: minmax(0, 1fr);
  padding: 0 16px 14px;
  border-top: 0;
}
.wsc-kpi {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 11px 12px;
  background: #151515;
  border: 1px solid #202020;
  border-radius: 10px;
  min-width: 0;
}
.wsc-kpi-k {
  font-size: 8.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #818181;
  font-weight: 700;
}
.wsc-kpi-v {
  font-family: "JetBrains Mono", monospace;
  font-size: 17px;
  line-height: 1;
  color: #ececec;
}
.wsc-kpi-s {
  font-size: 11px;
  color: #949494;
}
.wsc-week {
  grid-column: 1 / -1;
}
.wsc-week-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px 18px;
  margin-top: 4px;
}
.wsc-exp-tile .wsc-week-row {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.wsc-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
/* The grid: 2, 3 or 4 tiles a row by window width (the home page has no
   sidebar, so the window is the page), one on a phone. */
.wsc-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
  align-items: start;
}
@media (min-width: 680px) {
  .wsc-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (min-width: 1024px) {
  .wsc-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
@media (min-width: 1400px) {
  .wsc-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}
.wsc-tile {
  display: flex;
  flex-direction: column;
}
.wsc-id {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 0 16px;
  margin-top: -40px;
}
.wsc-mark-tile {
  width: 54px;
  height: 54px;
  border-radius: 15px;
  border: 3px solid #101010;
  background: #151515;
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.45);
}
/* The name starts below the cover, never on it, so it reads on any cover. */
.wsc-idtext {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-top: 46px;
}
.wsc-idtext .wsc-name {
  font-size: 15px;
}
.wsc-tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  padding: 14px 16px 12px;
}
.wsc-t {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  padding: 8px 10px;
  background: #151515;
  border: 1px solid #1e1e1e;
  border-radius: 9px;
}
.wsc-t b {
  font-family: "JetBrains Mono", monospace;
  font-weight: 500;
  font-size: 13.5px;
  line-height: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.wsc-t span {
  font-size: 8.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #818181;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.wsc-foot {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: auto;
  padding: 8px 10px 8px 12px;
  border-top: 1px solid #1a1a1a;
  transition: background 0.18s ease;
}
.wsc-add {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: 100%;
  padding: 16px;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: #949494;
  background: transparent;
  border: 1px dashed #2a2a2a;
  border-radius: 14px;
  cursor: pointer;
}
.wsc-add:hover {
  color: #f2f2f2;
  border-color: rgba(255, 138, 0, 0.34);
  background: rgba(255, 138, 0, 0.06);
}
.wsc-add-tile {
  flex-direction: column;
  min-height: 268px;
  height: 100%;
  border-radius: 16px;
}
@media (max-width: 640px) {
  .wsc-cover {
    height: 132px !important;
  }
  .wsc-tile .wsc-cover {
    height: 112px !important;
  }
  .wsc-end {
    margin-left: 0;
    width: 100%;
  }
}
html[data-reduce-motion] .wsc,
html[data-reduce-motion] .wsc:hover,
html[data-reduce-motion] .wsc:active,
html[data-reduce-motion] .wsc-cover::before,
html[data-reduce-motion] .wsc-go {
  transform: none !important;
  transition: none !important;
}
/* #2432 the look's controls on a cover: Change cover for the owner, shown on
   hover or keyboard focus; who chose the look for everybody else. */
.wsc-cover-btn,
.wsc-setby {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  border-radius: 999px;
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  color: #ececec;
  background: rgba(10, 10, 10, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.18);
  backdrop-filter: blur(6px);
}
.wsc-cover-btn {
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease;
}
.wsc-cover-btn:hover {
  background: rgba(10, 10, 10, 0.82);
}
.wsc:hover .wsc-cover-btn,
.wsc:focus-within .wsc-cover-btn,
.wsc-cover-btn:focus-visible {
  opacity: 1;
}
/* A tile has no room for the sentence: the lock alone, the sentence its tooltip. */
.wsc-tile .wsc-setby {
  padding: 5px;
}
.wsc-tile .wsc-setby-t {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
/* The Customize dialog's parts. */
.look-sec {
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.look-hd {
  display: flex;
  align-items: center;
  gap: 8px;
}
.look-eyebrow {
  margin-right: auto;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #949494;
}
.look-sub {
  font-size: 11px;
  font-weight: 600;
  color: #adadad;
}
.look-note {
  font-size: 11px;
  line-height: 1.45;
  color: #949494;
}
.look-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  color: #d4d4d4;
  background: #171717;
  border: 1px solid #2a2a2a;
  border-radius: 8px;
  padding: 6px 10px;
  cursor: pointer;
}
.look-btn:hover {
  color: #f2f2f2;
  border-color: #3a3a3a;
}
.look-btn svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}
.look-save {
  color: #1a0d00;
  background: #ff8a00;
  border-color: #ff8a00;
}
.look-save:hover {
  color: #1a0d00;
  background: #ffa033;
  border-color: #ffa033;
}
.look-covers {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
  gap: 8px;
}
.look-cover {
  position: relative;
  height: 52px;
  padding: 0;
  border-radius: 9px;
  border: 2px solid transparent;
  cursor: pointer;
}
.look-cover span {
  position: absolute;
  left: 6px;
  bottom: 4px;
  font-size: 9.5px;
  font-weight: 600;
  color: #fff;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8);
}
.look-search {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 11px;
  color: #818181;
  background: #0b0b0b;
  border: 1px solid #262626;
  border-radius: 8px;
}
.look-search svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}
.look-search input {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 12.5px;
  color: #e2e2e2;
  background: transparent;
  border: 0;
  outline: none;
  padding: 8px 0;
}
.look-count {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  white-space: nowrap;
}
.look-icons {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(38px, 1fr));
  gap: 6px;
  max-height: 184px;
  overflow-y: auto;
  padding: 2px;
}
.look-icons button {
  height: 38px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid #222222;
  border-radius: 8px;
  cursor: pointer;
}
.look-icons button:hover {
  border-color: #3a3a3a;
}
/* #2436 the workspace list's states: skeletons shaped like the view, the
   failure alert, the two kinds of empty, and the Workspaces search. */
.wsc-skelcard {
  cursor: default;
  display: flex;
  flex-direction: column;
}
.wsc-skelcard:hover {
  transform: none;
}
.wsc-skel {
  display: block;
  border-radius: 6px;
  background: linear-gradient(90deg, #161616 0%, #1f1f1f 50%, #161616 100%) 0 0 / 200% 100%;
  animation: wsc-shimmer 1.4s ease-in-out infinite;
}
@keyframes wsc-shimmer {
  from {
    background-position: 100% 0;
  }
  to {
    background-position: -100% 0;
  }
}
@media (prefers-reduced-motion: reduce) {
  .wsc-skel {
    animation: none;
  }
}
.wsc-alert {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  font-size: 12.5px;
  line-height: 1.45;
  color: #ffd2a1;
  background: rgba(255, 138, 0, 0.07);
  border: 1px solid rgba(255, 138, 0, 0.3);
  border-radius: 10px;
}
.wsc-alert svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}
.wsc-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 28px 20px;
  text-align: center;
  color: #949494;
  background: #101010;
  border: 1px dashed #262626;
  border-radius: 14px;
}
.wsc-empty svg {
  fill: none;
  stroke: #ffb45c;
  stroke-width: 2;
}
.wsc-empty b {
  font-size: 13.5px;
  color: #ececec;
}
.wsc-empty p {
  margin: 0 0 4px;
  max-width: 440px;
  font-size: 12px;
  line-height: 1.55;
}
.wsc-search {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  width: 210px;
  max-width: 46vw;
  padding: 0 10px;
  color: #818181;
  background: #0b0b0b;
  border: 1px solid #262626;
  border-radius: 8px;
}
.wsc-search:focus-within {
  border-color: #3a3a3a;
}
.wsc-search svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}
/* #1682 find in a vault note: every match, and the one the reader is on. Painted
   by the CSS Custom Highlight API (component.js applyVaultFind), so the note's
   template blocks are never wrapped in elements a repaint would undo. */
::highlight(vault-find) {
  background-color: rgba(255, 180, 92, 0.32);
}
::highlight(vault-find-cur) {
  background-color: #ffb45c;
  color: #140a00;
}
.wsc-search input {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 12px;
  color: #e2e2e2;
  background: transparent;
  border: 0;
  outline: none;
  padding: 6px 0;
}
/* #2438 the home Connections overview: a block per workspace, a row per
   connection, the dot is the state. */
.hc-ws {
  flex: none;
  background: #101010;
  border: 1px solid #1e1e1e;
  border-radius: 12px;
  overflow: hidden;
}
.hc-ws-hd {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 12px 16px;
  background: #0d0d0d;
  border-bottom: 1px solid #1a1a1a;
}
.hc-ws-name {
  font-size: 13.5px;
  color: #ececec;
}
.hc-ws-role,
.hc-ws-here {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  color: #949494;
  border: 1px solid #262626;
  border-radius: 999px;
  padding: 2px 8px;
}
.hc-ws-attn {
  margin-left: auto;
  font-size: 11.5px;
}
.hc-row {
  display: grid;
  grid-template-columns: 10px 130px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 12px;
  padding: 11px 16px;
  border-bottom: 1px solid #171717;
  font-size: 12.5px;
}
.hc-row:last-child {
  border-bottom: 0;
}
.hc-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}
.hc-label {
  color: #ececec;
  font-weight: 600;
}
.hc-line {
  color: #adadad;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hc-state {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  white-space: nowrap;
}
.hc-state svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}
.hc-checked {
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  color: #818181;
  white-space: nowrap;
  min-width: 90px;
  text-align: right;
}
@media (max-width: 640px) {
  .hc-row {
    grid-template-columns: 10px minmax(0, 1fr) auto;
  }
  .hc-line,
  .hc-checked {
    grid-column: 2 / -1;
    text-align: left;
  }
}
/* Light theme inverts the whole page with a filter (prototype.js applyTheme);
   a cover is a picture, so it is inverted back and keeps its own colours. */
html[style*="invert"] .wsc-cover,
html[style*="invert"] .wsc-mark,
html[style*="invert"] .look-cover {
  filter: invert(1) hue-rotate(180deg);
}
/* A mark INSIDE a cover (the list card, the dialog's preview) is already
   counted back by its cover; a second filter would flip an uploaded logo. */
html[style*="invert"] .wsc-cover .wsc-mark {
  filter: none;
}
/* ⭐ EVERY PICTURE IS INVERTED BACK, not only covers. A profile photo is an
   inline `background: url(...)` and Relay's logo an <img>, and under the light
   theme's page wide invert both came out as negatives ("the avatar image is
   being somehow distorted by the light theme", 2026-10-22). Every inline url()
   background in the template is a picture (avatars, the logo, covers), so the
   attribute is the test. Anything inside a cover is already counted back by the
   cover, so it is left alone. */
html[style*="invert"] img,
html[style*="invert"] [style*="url("] {
  filter: invert(1) hue-rotate(180deg);
}
html[style*="invert"] .wsc-cover img,
html[style*="invert"] .wsc-cover [style*="url("] {
  filter: none;
}

/* ⭐ BRAND COLOURS IN THE LIGHT THEME (2026-10-22): "switching to light, it
   feels Claude theme; switching to dark, it looks like Relay". The page wide
   invert flips lightness as well as hue, so every brand colour came out darker
   and redder: #ff8a00 rendered #c64f00, #ffb45c rendered brown #7b2f00, and the
   dark text on an orange button turned cream. Rust on cream is Claude's palette.

   FILLS are restored exactly. A solid brand background, and the text on it, is
   run through the inverse of the page filter, so it renders as it does in dark.
   The inverse has to undo contrast and brightness too, not only the invert;
   `invert(1) hue-rotate(180deg)` alone leaves the orange a shade off.

   TEXT is not restored exactly, on purpose: #ffb45c on a light page is hard to
   read. Each brand text colour gets a chosen value that keeps its hue and reads
   on the light page. The variable holds the PRE filter value, so what renders
   is the colour named beside it. Class rules read the same variables. */
:root {
  --brand-text: #ffb45c;
  --brand-ink: #ff8a00;
  --warn-text: #ffb020;
  --ok-text: #3ecf8e;
}
html[style*="invert"] {
  --brand-text: #d27f1d; /* renders #b86300 */
  --brand-ink: #d27f1d; /* renders #b86300 */
  --warn-text: #bd841d; /* renders #a36900 */
  --ok-text: #21ae6f; /* renders #008f4f */
}
html[style*="invert"] [style*="background: #ff8a00" i],
html[style*="invert"] [style*="background:#ff8a00" i],
html[style*="invert"] [style*="background: #ffb45c" i],
html[style*="invert"] [style*="background:#ffb45c" i],
html[style*="invert"] [style*="background: #ffb020" i],
html[style*="invert"] [style*="background:#ffb020" i],
html[style*="invert"] [style*="background: #3ecf8e" i],
html[style*="invert"] [style*="background:#3ecf8e" i],
html[style*="invert"] .wsc-go,
html[style*="invert"] .look-save,
html[style*="invert"] .chat-linkpop .lp-apply,
html[style*="invert"] .dlg-btn.primary {
  filter: brightness(0.9804) contrast(1.1111) invert(1) hue-rotate(180deg);
}
html[style*="invert"] [style^="color: #ffb45c" i],
html[style*="invert"] [style*=";color: #ffb45c" i],
html[style*="invert"] [style*="; color: #ffb45c" i],
html[style*="invert"] [style^="color:#ffb45c" i],
html[style*="invert"] [style*=";color:#ffb45c" i],
html[style*="invert"] [style*="; color:#ffb45c" i] {
  color: var(--brand-text) !important;
}
html[style*="invert"] [style^="color: #ff8a00" i],
html[style*="invert"] [style*=";color: #ff8a00" i],
html[style*="invert"] [style*="; color: #ff8a00" i],
html[style*="invert"] [style^="color:#ff8a00" i],
html[style*="invert"] [style*=";color:#ff8a00" i],
html[style*="invert"] [style*="; color:#ff8a00" i] {
  color: var(--brand-ink) !important;
}
html[style*="invert"] [style^="color: #ffb020" i],
html[style*="invert"] [style*=";color: #ffb020" i],
html[style*="invert"] [style*="; color: #ffb020" i],
html[style*="invert"] [style^="color:#ffb020" i],
html[style*="invert"] [style*=";color:#ffb020" i],
html[style*="invert"] [style*="; color:#ffb020" i] {
  color: var(--warn-text) !important;
}
html[style*="invert"] [style^="color: #3ecf8e" i],
html[style*="invert"] [style*=";color: #3ecf8e" i],
html[style*="invert"] [style*="; color: #3ecf8e" i],
html[style*="invert"] [style^="color:#3ecf8e" i],
html[style*="invert"] [style*=";color:#3ecf8e" i],
html[style*="invert"] [style*="; color:#3ecf8e" i] {
  color: var(--ok-text) !important;
}
/* ⭐ #1983 The accessibility preferences from Home > Settings, each an
   attribute component.js sets on <html> and remembers per viewer. Text size is
   a zoom because the design fixes its 13px inline on the root; contrast is a
   filter for the same reason; the focus ring and underlines are the two the
   keyboard and colour-blind readers asked for. */
/* #3153 --tx-zoom repeats each zoom so a height taken from the window can be
   divided back by it. 100dvh under a zoom of 1.18 is 1.18 windows tall, which
   pushed Active work and the profile off the bottom at the largest size. */
html[data-text-size="s"] {
  zoom: 0.94;
  --tx-zoom: 0.94;
}
html[data-text-size="l"] {
  zoom: 1.08;
  --tx-zoom: 1.08;
}
html[data-text-size="xl"] {
  zoom: 1.18;
  --tx-zoom: 1.18;
}
html[data-contrast] {
  filter: contrast(1.12) brightness(1.04);
}
html[data-underline] a {
  text-decoration: underline;
}
/* #1374 Colour-blind safe states (on by default): priority keeps its colour
   and gains a shape, so it never rests on colour alone. High is a diamond,
   normal the filled dot, low a hollow ring. Its tooltip says it in words. */
html[data-colour-safe] [data-prio="high"] {
  border-radius: 1px !important;
  transform: rotate(45deg);
}
html[data-colour-safe] [data-prio="low"] {
  background: transparent !important;
  box-shadow: inset 0 0 0 1.5px #949494;
}
/* #1374 Compact density: list rows (to-dos, issues) tighten their vertical
   padding. The rows' padding is inline, hence !important; nothing else moves. */
html[data-density="compact"] [data-skin="row"] {
  padding-top: 5px !important;
  padding-bottom: 5px !important;
}
html[data-focus-ring] :focus-visible {
  outline: 2px solid #ff8a00;
  outline-offset: 2px;
}
/* A text field is focus-visible on every click, not only from the keyboard, so
   the ring landed on each search box a mouse clicked into, inside the box's own
   focus border (Loucas, 28 October 2026). The caret and that border already say
   where typing goes; buttons, links and switches keep the ring. */
html[data-focus-ring]
:is(
  input:not(
    [type="checkbox"],
    [type="radio"],
    [type="range"],
    [type="button"],
    [type="submit"],
    [type="reset"],
    [type="color"],
    [type="file"]
  ),
  textarea,
  [contenteditable]
):focus-visible {
  outline: none;
}

html[data-reduce-motion] *,
html[data-reduce-motion] *::before,
html[data-reduce-motion] *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}
html[data-reduce-motion] button:active,
html[data-reduce-motion] [role="switch"]:active {
  transform: none;
}
@keyframes om-pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(255, 138, 0, 0.55);
    opacity: 1;
  }
  70% {
    box-shadow: 0 0 0 5px rgba(255, 138, 0, 0);
    opacity: 0.75;
  }
  100% {
    box-shadow: 0 0 0 0 rgba(255, 138, 0, 0);
    opacity: 1;
  }
}
@keyframes om-marquee {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

/* ── the deploy notice ────────────────────────────────────────────────────────
 * A new version landed, so this page's JS and CSS may be stale. Ported from the
 * shipping shell, which this copy does not load.
 *
 * ⭐ EVERY COLOUR HERE IS A TOKEN, and that is why the port themed itself. The
 * upstream rule uses --surface-2, --accent, --border, --shadow and --text, and
 * this copy defines all five with identical values, so nothing had to be
 * retuned by hand. A literal would have had to be, and would have drifted the
 * first time the palette moved.
 *
 * ⭐ RAISED IS LIGHTER. --surface-2 sits above the #101010 panels on purpose:
 * the suite chrome standard says a raised surface is lighter than what it
 * floats over, and Bridge once ran that inverted and made a panel invisible
 * from inside its own app.
 */
.update-toast {
  position: fixed;
  left: 50%;
  top: 18px;
  z-index: var(--z-toast);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px 10px 18px;
  background: var(--surface-2);
  border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--border));
  border-radius: 999px;
  box-shadow: var(--shadow);
  color: var(--text);
  font-size: 13px;
  /* Off screen and transparent until .show, so the slide-in has somewhere to
   * come from. translateX keeps it centred while translateY does the moving. */
  transform: translate(-50%, -160%);
  opacity: 0;
  transition:
    transform 0.28s cubic-bezier(0.2, 0.8, 0.3, 1),
    opacity 0.28s ease;
}

.update-toast.show {
  transform: translate(-50%, 0);
  opacity: 1;
}

/* ⚠️ ONE FLEX ITEM FOR THE SENTENCE, NOT SEVERAL BARE TEXT RUNS. The upstream
 * rule carries this warning and it is worth keeping: the row is a flex
 * container, so every loose run beside the icon becomes its own item and each
 * wraps to its own line, turning one sentence into four. */
.update-toast .ut-msg {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}

.update-toast .ut-txt {
  white-space: nowrap;
}
.update-toast .ut-txt b {
  font-weight: 600;
  color: var(--accent-soft, var(--accent));
}

.update-toast .icn {
  width: 15px;
  height: 15px;
  flex: none;
  color: var(--accent);
}

.update-toast .ut-refresh {
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: #14100a;
  background: var(--accent);
  border: 0;
  border-radius: 999px;
  padding: 6px 14px;
  cursor: pointer;
  flex: none;
}

.update-toast .ut-refresh:hover {
  filter: brightness(1.08);
}

.update-toast .ut-x {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex: none;
  background: none;
  border: 0;
  border-radius: 50%;
  color: var(--muted, #adadad);
  cursor: pointer;
}

.update-toast .ut-x:hover {
  color: var(--text);
  background: rgba(255, 255, 255, 0.06);
}
.update-toast .ut-x .icn {
  width: 13px;
  height: 13px;
  color: currentColor;
}

/* A phone has no room for the sentence, and the button already says Refresh. */
@media (max-width: 560px) {
  .update-toast {
    left: 12px;
    right: 12px;
    top: 12px;
    transform: translateY(-160%);
  }
  .update-toast.show {
    transform: translateY(0);
  }
  .update-toast .ut-txt {
    white-space: normal;
  }
}

/* CONTROLS STAY ON ONE ROW, ON THE RIGHT, AT EVERY WIDTH.
 *
 * These rows are a grid on a wide screen and a flexbox under 1000px, because
 * `rowDisp` switches them. They also carried `flex-wrap: wrap`, so the narrow
 * form let the controls fall to a SECOND LINE and, with nothing pushing them
 * across, sit on the LEFT. Rows measured 119px against 102px, and WHICH rows
 * wrapped depended on how long the title happened to be, so a list looked
 * ragged rather than obviously broken. That is the whole of the reported
 * "layout shift", and it is not a stuck click state: base.css only ever gave
 * :active a transform, which is paint-only and cannot move anything.
 *
 * NOWRAP ALONE IS NOT ENOUGH, and this is the half that is easy to miss. A
 * flex child will not shrink below its own content by default, so removing the
 * wrap just moved the damage sideways: four rows began overflowing
 * horizontally instead. `min-width: 0` is what lets the title give up space,
 * and it has to sit on the CHILD, not on the row.
 *
 * The controls are the last child on every one of these rows, so pinning the
 * last child right is ONE rule rather than 28 template edits. The 28 row
 * templates are all different literals and are deliberately left alone. */
.rowflex {
  flex-wrap: nowrap;
}
.rowflex > * {
  min-width: 0;
}
.rowflex > *:last-child {
  margin-left: auto;
  flex: none;
}

/* ── THE BADGE, AND WHY IT IS ONE RULE ────────────────────────────────────────
 *
 * Reported as a flag badge overflowing its card, and it was never one badge:
 * the template carries 91 elements with the pill radius, 82 of them real
 * badges, and NOT ONE had an overflow guard of any kind. Eleven set
 * white-space: nowrap, which without a max-width makes it WORSE: the text
 * refuses to wrap and the badge grows straight out of its container.
 *
 * ⭐ One rule rather than 82 template edits, the same reasoning as .rowflex
 * above. A badge that cannot shrink is the default in flex and grid both, so
 * min-width: 0 is the half that actually does the work; max-width: 100% is
 * what stops it leaving the parent when nothing else can give.
 *
 * ⚠️ text-overflow needs its own container to be a block-ish box with hidden
 * overflow, and most of these badges are inline-flex with an icon beside the
 * words. So the ellipsis is put on the CHILDREN too, where the words actually
 * live, and the container only promises not to escape. */
.badge {
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.badge > * {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* An icon inside a badge is never the thing to shrink: it is 11 or 12 pixels
   and squeezing it to nothing loses the only non-text signal the badge has. */
.badge > svg {
  flex: none;
  overflow: visible;
}

/* ── THE MESSAGE LIST, AND WHY IT COULD NOT SCROLL ──────────────────────────
 *
 * ⚠️⚠️ `justify-content: flex-end` WITH `overflow-y: auto` MAKES THE TOP OF THE
 * CONTENT UNREACHABLE. It is the obvious way to pin a short conversation to the
 * bottom of its panel and it does that correctly, but once the messages are
 * taller than the box the overflow goes off the BLOCK-START edge, and overflow
 * in that direction cannot be scrolled to. Measured on the running board before
 * this rule existed: forty messages totalling 3,449px inside a 332px container
 * reporting scrollHeight 332. Not "the history is not loaded" — the history was
 * loaded, rendered, and walled off.
 *
 * ⭐ `margin-top: auto` ON THE FIRST CHILD DOES THE SAME JOB AND SCROLLS. The
 * auto margin absorbs the spare space when there is any, so a two-message room
 * still sits at the bottom, and when the content outgrows the box there is no
 * spare space, the margin collapses to nothing, and the container overflows
 * downward like an ordinary scroller.
 *
 * ⚠️ It is a RULE rather than an inline style because the first child is drawn
 * by an sc-for and there is no element to hang it on. */
.chatscroll {
  justify-content: flex-start;
}
.chatscroll > *:first-child {
  margin-top: auto;
}

/* ── chat composer: the WYSIWYG contenteditable (#2141) ──────────────────────
 * The box shows formatting live and serialises to markdown on input (chatmd.js).
 * It is a contenteditable, not a textarea, so its rules live here rather than
 * inline: a placeholder needs a pseudo-element, and the fused toolbar + link
 * popover need classes. Both chat surfaces (page and dock) share these. */
.chatcompose {
  overflow-y: auto;
  outline: none;
  word-break: break-word;
  white-space: pre-wrap;
  scrollbar-width: thin;
  scrollbar-color: #333 transparent;
}
.chatcompose[data-empty]:before {
  content: attr(data-ph);
  color: #6a6a6a;
  pointer-events: none;
}
.chatcompose::-webkit-scrollbar {
  width: 8px;
}
.chatcompose::-webkit-scrollbar-track {
  background: transparent;
}
.chatcompose::-webkit-scrollbar-thumb {
  background: #2e2e2e;
  border: 2px solid #141414;
  border-radius: 999px;
}
.chatcompose b,
.chatcompose strong {
  font-weight: 700;
}
.chatcompose code {
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
  background: rgba(255, 255, 255, 0.08);
  padding: 1px 5px;
  border-radius: 4px;
}
.chatcompose pre {
  margin: 4px 0;
  background: #0d0d0d;
  border: 1px solid #242424;
  border-radius: 8px;
  padding: 8px 10px;
  overflow-x: auto;
  font-family: "JetBrains Mono", monospace;
  font-size: 11px;
}
.chatcompose blockquote {
  margin: 4px 0;
  padding-left: 9px;
  border-left: 2px solid #3a3a3a;
  color: #b4b4b4;
}
.chatcompose ul,
.chatcompose ol {
  margin: 4px 0;
  padding-left: 22px;
}
.chatcompose a {
  color: #8fb3ff;
}

/* ── #2141: rendered markdown INSIDE A SENT BUBBLE (.chat-md) ─────────────────
 * The composer styles above are the input; these are the message once it is
 * sent, on all three surfaces (page, dock, thread) since every bubble renders
 * through mdChatNode. Colours are chosen to read on BOTH bubble colours (a dark
 * "theirs" bubble and the orange "mine" one) without knowing which is which:
 * links inherit the bubble's own text colour and underline, and code/quote use
 * translucent panels that sit correctly on either background. */
/* #2157: a link in a sent bubble has to READ as a link on both bubble colours
 * (the bright orange "mine" and the dark "theirs"), so native blue is wrong on
 * one of them. It inherits the bubble's text colour but is set apart by a
 * heavier weight and a clear offset underline drawn in a slightly translucent
 * currentColor, which lands legibly on either ground without a second hue. */
.chat-md a {
  color: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-decoration-color: color-mix(in srgb, currentColor 60%, transparent);
  text-underline-offset: 2.5px;
}
.chat-md a:hover {
  text-decoration-color: currentColor;
}
.chat-md code {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.86em;
  background: rgba(127, 127, 127, 0.22);
  padding: 1px 5px;
  border-radius: 4px;
}
.chat-md pre {
  margin: 5px 0;
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid rgba(127, 127, 127, 0.3);
  border-radius: 8px;
  padding: 8px 10px;
  overflow-x: auto;
}
.chat-md pre code {
  background: none;
  padding: 0;
  font-size: 11px;
}
.chat-md blockquote {
  margin: 5px 0;
  padding: 2px 0 2px 9px;
  border-left: 2px solid currentColor;
  opacity: 0.85;
}
.chat-md ul,
.chat-md ol {
  margin: 4px 0;
  padding-left: 22px;
}
.chat-md p {
  margin: 0 0 4px;
}
.chat-md p:last-child {
  margin-bottom: 0;
}
/* ── #2404: a vault note read IN PLACE, on a project's Overview > Vault ──────
 * The same renderVaultMd HTML the vault's graph shelf shows, given a reading
 * measure and the house type scale. Code, quotes and lists follow .chat-md
 * above so rendered markdown reads alike wherever the board draws it. */
.ov-note {
  overflow-wrap: anywhere;
}
.ov-note h1,
.ov-note h2,
.ov-note h3,
.ov-note h4,
.ov-note h5,
.ov-note h6 {
  margin: 16px 0 6px;
  color: #ececec;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.3;
}
.ov-note h1 {
  font-size: 17px;
  margin-top: 4px;
}
.ov-note h2 {
  font-size: 15px;
}
.ov-note h3 {
  font-size: 13.5px;
}
.ov-note h4,
.ov-note h5,
.ov-note h6 {
  font-size: 12.5px;
  color: #d6d6d6;
}
.ov-note p {
  margin: 0 0 9px;
  max-width: 760px;
}
.ov-note ul,
.ov-note ol {
  margin: 4px 0 10px;
  padding-left: 22px;
  max-width: 760px;
}
.ov-note li {
  margin: 2px 0;
}
.ov-note a {
  color: var(--brand-text, #ffb45c);
  text-decoration: none;
}
.ov-note a:hover {
  text-decoration: underline;
}
.ov-note code {
  font-family: "JetBrains Mono", monospace;
  font-size: 0.86em;
  background: rgba(127, 127, 127, 0.18);
  padding: 1px 5px;
  border-radius: 4px;
}
.ov-note pre {
  margin: 8px 0;
  background: #0b0b0b;
  border: 1px solid #1e1e1e;
  border-radius: 8px;
  padding: 9px 11px;
  white-space: pre-wrap;
}
.ov-note pre code {
  background: none;
  padding: 0;
  font-size: 11px;
}
.ov-note blockquote {
  margin: 8px 0;
  padding: 4px 0 4px 11px;
  border-left: 2px solid #3a3a3a;
  color: #adadad;
}
.ov-note hr {
  border: 0;
  border-top: 1px solid #1e1e1e;
  margin: 14px 0;
}
.ov-note .vtable {
  border-collapse: collapse;
  font-size: 12px;
}
.ov-note .vtable th,
.ov-note .vtable td {
  border-bottom: 1px solid #1c1c1c;
  padding: 6px 9px;
  text-align: left;
  vertical-align: top;
  min-width: 72px;
}
.ov-note .vtable th {
  color: #949494;
  font-weight: 600;
}
.ov-note img {
  max-width: 100%;
  height: auto;
}

/* #2188 a long chat message collapses to an expandable artifact, so a wall of
 * pasted text or code does not fill the room. Colours inherit the bubble like
 * .chat-md, so it reads on both the orange "mine" and the dark "theirs". */
.chat-artifact {
  display: block;
}
.chat-artifact .chat-artifact-body {
  display: block;
  max-height: 216px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, #000 72%, transparent);
  mask-image: linear-gradient(to bottom, #000 72%, transparent);
}
.chat-artifact.open .chat-artifact-body {
  max-height: none;
  -webkit-mask-image: none;
  mask-image: none;
}
.chat-artifact-toggle {
  display: inline-flex;
  align-items: center;
  margin-top: 6px;
  font-size: 11px;
  font-weight: 600;
  color: inherit;
  opacity: 0.8;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 2.5px;
}
.chat-artifact-toggle:hover {
  opacity: 1;
}

/* #2167: an inline deeplink card. A to-do or issue reference written in a
 * message (WK-01:PJ-02:TD-01) renders as this compact card, which resolves its
 * title and, clicked, jumps to the item and flashes it. A left stripe carries
 * the kind (orange for a to-do, soft red for an issue) so it reads at a glance
 * without a filled background fighting the bubble. */
.chat-ref-card {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  vertical-align: baseline;
  max-width: 320px;
  margin: 1px 0;
  padding: 3px 9px 3px 8px;
  background: #141414;
  border: 1px solid #2a2a2a;
  border-left: 3px solid #6a6a6a;
  border-radius: 7px;
  cursor: pointer;
  font-size: 0.92em;
  line-height: 1.3;
  color: #e2e2e2;
}
.chat-ref-card:hover {
  border-color: #3a3a3a;
  background: #181818;
}
.chat-ref-card:focus-visible {
  outline: 2px solid #ff8a00;
  outline-offset: 1px;
}
.chat-ref-card[data-kind="todo"] {
  border-left-color: #ff8a00;
}
.chat-ref-card[data-kind="issue"] {
  border-left-color: #ff8f8f;
}
.chat-ref-card[data-kind="message"] {
  border-left-color: #8fb3ff;
}
/* #2178 a note reference card, in the Knowledge accent so a NT- card reads as a
 * different kind of thing from a to-do (orange) or an issue (red). */
.chat-ref-card[data-kind="note"] {
  border-left-color: #5fd0c4;
}
/* #2167: brief flash on a message you jumped to from a message-link card. */
@keyframes chatMsgFlash {
  0% {
    background: rgba(255, 138, 0, 0.22);
  }
  100% {
    background: transparent;
  }
}
[data-flash="1"] {
  animation: chatMsgFlash 1.8s ease-out;
  border-radius: 8px;
}
.chat-ref-card.loading {
  color: #9a9a9a;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.86em;
}
.chat-ref-card .crc-kind {
  flex: none;
  font-size: 8.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 700;
  color: #949494;
}
.chat-ref-card .crc-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
}
.chat-ref-card .crc-status {
  flex: none;
  font-size: 8.5px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 1px 6px;
  border-radius: 999px;
  font-weight: 700;
}
.chat-ref-card .crc-open {
  color: #ffce8a;
  background: rgba(255, 138, 0, 0.14);
}
.chat-ref-card .crc-done,
.chat-ref-card .crc-closed,
.chat-ref-card .crc-resolved {
  color: #8fe0b0;
  background: rgba(62, 207, 142, 0.14);
}

/* the markdown toolbar button, lit when the caret is inside that formatting */
.chat-fmt.active {
  color: var(--brand-text, #ffb45c) !important;
  background: #2a1c0a !important;
  border-color: #5a3d17 !important;
}

/* the custom link popover (Slack-style), anchored inside the composer shell */
.chat-linkpop {
  position: absolute;
  left: 12px;
  bottom: 58px;
  z-index: 20;
  width: 290px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  background: #161616;
  border: 1px solid #2e2e2e;
  border-radius: 11px;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.55);
}
.chat-linkpop[hidden] {
  display: none;
}
.chat-linkpop .lp-ttl {
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #949494;
  font-weight: 700;
}
.chat-linkpop input {
  box-sizing: border-box;
  width: 100%;
  font: inherit;
  font-size: 12px;
  color: #ececec;
  background: #101010;
  border: 1px solid #262626;
  border-radius: 8px;
  padding: 8px 10px;
  outline: none;
}
.chat-linkpop input:focus {
  border-color: #3a3a3a;
}
.chat-linkpop .lp-row {
  display: flex;
  justify-content: flex-end;
  gap: 7px;
  margin-top: 2px;
}
.chat-linkpop .lp-apply {
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  color: #140a00;
  background: #ff8a00;
  border: 1px solid #ff8a00;
  border-radius: 7px;
  padding: 6px 13px;
  cursor: pointer;
}
.chat-linkpop .lp-apply:disabled {
  background: #1c1c1c;
  border-color: #262626;
  color: #4a4a4a;
  cursor: default;
}
.chat-linkpop .lp-cancel {
  font: inherit;
  font-size: 11.5px;
  color: #adadad;
  background: #171717;
  border: 1px solid #2a2a2a;
  border-radius: 7px;
  padding: 6px 13px;
  cursor: pointer;
}

/* the fused input shell: one bordered box holding toolbar + editor + bottom bar */
.chat-shell {
  position: relative;
  display: flex;
  flex-direction: column;
  background: #141414;
  border: 1px solid #242424;
  border-radius: 11px;
  overflow: hidden;
}
/* #2157: focus lands on the whole fused shell as ONE clean on-brand border.
 * The contenteditable fills the shell, so the accessibility focus ring (a 2px
 * offset outline, default on) drew a rectangle INSIDE the shell that ran
 * parallel to the toolbar divider and the bottom bar: it read as stray lines.
 * The shell border below is the focus indicator instead, so the inner editor's
 * own ring is suppressed (the container still shows focus clearly). */
.chat-shell:focus-within {
  border-color: #ff8a00;
}
.chat-shell .chatcompose:focus,
html[data-focus-ring] .chat-shell .chatcompose:focus-visible {
  outline: none;
}
.chat-shell .chat-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 3px;
  padding: 7px 9px;
  border-bottom: 1px solid #202020;
  background: #171717;
}
.chat-shell .chat-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 9px;
}

/* #2151: read receipts. The ticks sit under a sent message; hovering them opens
 * a small popover naming who read it (each name in that person's chat colour)
 * and when. CSS-only hover, so it needs no state. */
.chat-ticks {
  display: inline-flex;
}
.chat-receipt-pop {
  display: none;
  position: absolute;
  bottom: 18px;
  right: 0;
  z-index: 40;
  flex-direction: column;
  gap: 3px;
  width: max-content;
  max-width: 240px;
  padding: 6px 9px;
  background: #1c1c1c;
  border: 1px solid #383838;
  border-radius: 7px;
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.55);
}
.chat-ticks:hover .chat-receipt-pop {
  display: flex;
}
.chat-receipt-pop .crp-head {
  font-size: 10.5px;
  color: #949494;
}
.chat-receipt-pop .crp-row {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 10.5px;
  color: #cfcfcf;
  white-space: nowrap;
}
.chat-receipt-pop .crp-row b {
  font-weight: 600;
}
.chat-receipt-pop .crp-when {
  font-family: "JetBrains Mono", monospace;
  font-size: 9px;
  color: #818181;
}

/* ── #2143 menu overlay redesign ─────────────────────────────────────────────
 * Hero entry cards for Home and Dashboard, grouped rows with a one-line purpose
 * and a per-group accent (the --acc CSS var set inline from the view model), a
 * current-view marker and hover polish. The board name in the User space header
 * is brand orange. */
.menu-group {
  --acc: #8a8a8a;
}
.menu-sectitle {
  align-items: center;
  gap: 8px;
  font-size: 9.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #949494;
  font-weight: 700;
  margin-bottom: 10px;
}
.menu-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--acc);
  flex: none;
}
.menu-brand {
  margin-left: 8px;
  color: var(--brand-ink, #ff8a00);
}
.menu-cells {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.menu-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 15px;
  background: #171717;
  border: 1px solid #232323;
  border-radius: 11px;
  cursor: pointer;
  transition:
    background 0.14s,
    border-color 0.14s,
    transform 0.12s;
}
.menu-hero:hover {
  background: #1e1e1e;
  border-color: var(--acc);
  transform: translateY(-1px);
}
.menu-hero .menu-ic {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  color: var(--acc);
  background: rgba(255, 255, 255, 0.06); /* fallback for no color-mix */
  background: color-mix(in srgb, var(--acc) 14%, transparent);
  border: 1px solid #2e2e2e; /* fallback */
  border: 1px solid color-mix(in srgb, var(--acc) 30%, transparent);
}
.menu-hero .menu-nm {
  font-size: 15px;
  font-weight: 700;
  color: #f4f4f4;
}
.menu-hero .menu-ds {
  font-size: 11.5px;
  color: #9a9a9a;
  line-height: 1.45;
}

.menu-row {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: 10px 12px 10px 13px;
  background: #171717;
  border: 1px solid #232323;
  border-radius: 9px;
  cursor: pointer;
  overflow: hidden;
  transition:
    background 0.14s,
    border-color 0.14s;
}
/* #3131 No coloured bar down the left edge: the border and tint carry
 * hover and current on their own. */
.menu-row:hover {
  background: #1e1e1e;
  border-color: var(--acc);
}
.menu-row .menu-ic {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 7px;
  background: #202020;
  display: grid;
  place-items: center;
  color: #9a9a9a;
  margin-top: 1px;
  transition:
    background 0.14s,
    color 0.14s;
}
.menu-row:hover .menu-ic,
.menu-row.current .menu-ic {
  background: rgba(255, 255, 255, 0.06); /* fallback */
  background: color-mix(in srgb, var(--acc) 14%, transparent);
  color: var(--acc);
}
.menu-txt {
  min-width: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.menu-nm {
  font-size: 13px;
  font-weight: 600;
  color: #ececec;
  display: flex;
  align-items: center;
  gap: 7px;
}
.menu-ds {
  font-size: 11px;
  color: #8a8a8a;
  line-height: 1.4;
}
.menu-badge {
  flex: none;
  min-width: 18px;
  height: 18px;
  padding: 0 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: "JetBrains Mono", monospace;
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  border-radius: 999px;
}
.menu-row.current,
.menu-hero.current {
  border-color: var(--acc);
  background: #191919; /* fallback */
  background: color-mix(in srgb, var(--acc) 8%, #171717);
}
.menu-cur {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--acc);
  flex: none;
  place-items: center;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.08); /* fallback */
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--acc) 18%, transparent);
}
.menu-row .menu-cur {
  margin-left: auto;
  margin-top: 6px;
}
.menu-hero .menu-cur {
  position: absolute;
  top: 14px;
  right: 14px;
}

/* #3645 THE SESSIONS LIST AS A TABLE. A closed session's right side is a row of
   fixed columns (handle, time, steps, spend, when, then Route), so the numbers
   scan down the page. The column names sit above the list. Below 900px the
   middle columns fold away and the same facts ride on the meta line instead,
   which .sess-inline carries and hides while the columns are showing. */
.sess-cols {
  display: grid;
  grid-template-columns: 150px 66px 52px 78px 58px auto;
  gap: 12px;
  align-items: center;
  flex: none;
}
.sess-colh {
  display: grid;
  grid-template-columns: 150px 66px 52px 78px 58px 74px;
  gap: 12px;
  justify-content: end;
  padding: 0 14px;
  margin-top: 6px;
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: #6f6f6f;
}
.sess-colh span:not(:first-child) {
  text-align: right;
}
.sess-inline {
  display: none;
}
@media (max-width: 900px) {
  .sess-cols {
    grid-template-columns: auto auto;
  }
  .sess-cols .sess-c,
  .sess-colh {
    display: none;
  }
  .sess-inline {
    display: inline;
  }
}
/* #TD-2094 AND BY THE LIST'S OWN WIDTH, not only the window's. The list sits in
   a pane narrower than the window, so above 900px of window the five fixed
   columns (about 550px) stayed and squeezed the title to a few letters. Each
   card and the header row are size containers, and the same fold happens when
   THEY are narrower than 1000px: the columns take about 535px, and below that
   the title, badge and meta line are left under 450px and start to stack. */
[data-skin="sess-card"],
.sess-colh-wrap {
  container-type: inline-size;
}
@container (max-width: 1000px) {
  .sess-cols {
    grid-template-columns: auto auto;
  }
  .sess-cols .sess-c,
  .sess-colh {
    display: none;
  }
  .sess-inline {
    display: inline;
  }
}
