/* ============================================================================
   SHELL - the global bar, the channel bar, the sidebar footer.

   Loaded last so it owns the chrome outright. The old header put thirteen
   identical monochrome icons in one row with the workspace name, the channel
   name, an Invite button and Sign out. Nothing was grouped, nothing was
   labelled, and the control people reach for most - search - was the same 18px
   glyph as the twelve beside it.

   The structure now matches how these products actually work:
     global bar   | where you are | SEARCH | who you are |
     channel bar  | # channel + topic ................ members, actions, more |
     sidebar foot | your avatar, your name, your status |
   ========================================================================= */

/* ---------------------------------------------------------------- typography
   A real UI face. system-ui resolves to Segoe UI on Windows, which is why the
   app read as "a web page" rather than "an application". Inter is the closest
   widely-available match to what Slack and Linear use, and it is loaded with a
   system fallback so nothing shifts if it fails. */
@font-face {
  font-family: "InterVar";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("https://rsms.me/inter/font-files/InterVariable.woff2?v=4.0") format("woff2");
}
:root {
  --t-font: "InterVar", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, sans-serif;
  --header-h: 44px;
  --channelbar-h: 49px;
}
body { font-feature-settings: "cv05" 1, "cv08" 1, "ss03" 1, "calt" 1; }

/* ============================================================================
   GLOBAL BAR
   ========================================================================= */
#topbar {
  display: grid;
  /* Three real zones. The centre column is what makes search the anchor of the
     product rather than one glyph among many. */
  grid-template-columns: minmax(180px, 1fr) minmax(280px, 720px) minmax(180px, 1fr);
  align-items: center;
  gap: var(--s-5);
  height: calc(var(--header-h) + env(safe-area-inset-top));
  padding: env(safe-area-inset-top) var(--s-5) 0;
  background: var(--c-nav-bg-2);
  border-bottom: 1px solid var(--c-nav-border);
  flex: none;
  z-index: var(--z-nav);
}
.tb-left { display: flex; align-items: center; gap: var(--s-3); min-width: 0; }
.tb-center { display: flex; justify-content: center; }
.tb-right { display: flex; align-items: center; justify-content: flex-end; gap: var(--s-2); }

/* The server name is a menu - Invite, hand over, Leave. Before it was, the only
   route to Leave was a right-click on the rail icon, which nothing advertised
   and a phone cannot perform. It has to look pressable. */
#topbar #spaceName.spacename-menu {
  cursor: pointer;
  border-radius: var(--r-sm, 6px);
  padding: 2px 6px;
  margin-left: -6px;
}
#topbar #spaceName.spacename-menu:hover,
#topbar #spaceName.spacename-menu:focus-visible {
  background: color-mix(in srgb, var(--c-nav-text, currentColor) 12%, transparent);
}
#topbar #spaceName.spacename-menu::after {
  content: '▾';
  font-size: 0.72em;
  opacity: 0.6;
  margin-left: 5px;
  vertical-align: 1px;
}

#topbar #spaceName {
  color: var(--c-nav-brand);
  font-size: var(--t-base);
  font-weight: var(--t-bold);
  letter-spacing: -0.01em;
  border: 0;
  padding: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------------------------------------------------------------- search */
.searchbar {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  max-width: 720px;
  height: 28px;
  padding: 0 var(--s-3) 0 var(--s-4);
  background: color-mix(in srgb, var(--c-nav-hover) 70%, transparent);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  color: var(--c-nav-text);
  font-size: var(--t-sm);
  font-weight: var(--t-medium);
  cursor: pointer;
  transition: background-color var(--m-fast) var(--m-ease),
              border-color var(--m-fast) var(--m-ease);
}
.searchbar:hover {
  background: var(--c-nav-hover);
  border-color: color-mix(in srgb, var(--c-nav-text) 30%, transparent);
}
.searchbar .ico { width: 15px; height: 15px; opacity: 0.85; }
.searchbar-text { flex: 1 1 auto; text-align: left; }
.searchbar-kbd {
  flex: none;
  border: 0;
  background: color-mix(in srgb, var(--c-nav-text) 16%, transparent);
  color: var(--c-nav-text);
  font-family: var(--t-font);
  font-size: var(--t-2xs);
  font-weight: var(--t-semibold);
  padding: 1px var(--s-3);
  border-radius: var(--r-xs);
  letter-spacing: 0.02em;
}

/* ---------------------------------------------------------------- user chip */
.userchip {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  height: 30px;
  padding: 0 var(--s-3);
  background: transparent;
  border: 0;
  border-radius: var(--r-md);
  color: var(--c-nav-text);
  font-size: var(--t-sm);
  font-weight: var(--t-medium);
  cursor: pointer;
  max-width: 190px;
}
.userchip:hover { background: var(--c-nav-hover); color: var(--c-nav-text-active); }
.userchip-av .avatar { border-radius: var(--r-sm); font-size: 10px; }
.userchip .meName { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.userchip-caret .ico { width: 14px; height: 14px; opacity: 0.7; }

#topbar button.icon { color: var(--c-nav-text); width: 30px; height: 30px; }
#topbar button.icon:hover { background: var(--c-nav-hover); color: var(--c-nav-text-active); }
#topbar .install {
  height: 28px;
  padding: 0 var(--s-4);
  font-size: var(--t-sm);
}

/* ============================================================================
   CHANNEL BAR - content colours, because it belongs to the conversation, not
   to the navigation. That contrast is also what separates the two bars.
   ========================================================================= */
#channelbar {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  height: var(--channelbar-h);
  padding: 0 var(--s-6);
  background: var(--c-bg);
  border-bottom: 1px solid var(--c-border);
  flex: none;
  z-index: calc(var(--z-nav) - 1);
}
.cb-title {
  display: flex;
  align-items: baseline;
  gap: var(--s-4);
  min-width: 0;
}
.cb-title strong {
  color: var(--c-text);
  font-size: var(--t-md);
  font-weight: var(--t-bold);
  letter-spacing: -0.01em;
  white-space: nowrap;
  /* nowrap with nothing to clip it means the name simply grows past its box.
     Measured at 360px: "# field-team-daily-updates" took 194px of a bar that
     also has to hold the members chip and two actions, and ran underneath them.
     .cb-topic three rules below has always had this; the name never did. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cb-topic {
  font-size: var(--t-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  border-left: 1px solid var(--c-border);
  padding-left: var(--s-4);
}
.cb-topic:empty { display: none; }

.cb-members {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  height: 28px;
  padding: 0 var(--s-4);
  background: transparent;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  color: var(--c-text-2);
  font-size: var(--t-sm);
  font-weight: var(--t-semibold);
  cursor: pointer;
}
.cb-members:hover { background: var(--c-hover); color: var(--c-text); }

/* layout.css fades the last 18px of .hdr-actions to hint that the row scrolls
   past the edge. That row is the TOP bar's, which really does overflow. This one
   holds two buttons and never scrolls, so the hint was permanent: the second
   button sat under the transparent end of the gradient at every width, and read
   as disabled. The mask is the top bar's idea, so it is cleared here rather than
   weakened there. */
#channelbar .hdr-actions {
  display: flex;
  gap: var(--s-1);
  mask-image: none;
  -webkit-mask-image: none;
}
#channelbar button.icon { width: 30px; height: 30px; color: var(--c-text-2); }
#channelbar button.icon:hover { background: var(--c-hover); color: var(--c-text); }
#channelbar #btnInvite { height: 28px; padding: 0 var(--s-5); font-size: var(--t-sm); }

/* ============================================================================
   SIDEBAR - a scrolling list with your own presence pinned to the bottom.
   ========================================================================= */
#sidebar {
  display: flex;
  flex-direction: column;
  padding: 0;
  background: var(--c-nav-bg);
}
#sidebarScroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* Every other scrolling surface in the app has this; the channel list was
     missed. Standalone it means flicking past the last channel scrolls the page
     behind it. Embedded it means flicking past the last channel scrolls the
     customer's DASHBOARD, which is the single most obvious way for a panel to
     announce that it does not belong there. */
  overscroll-behavior: contain;
  padding: var(--s-4) var(--s-3) var(--s-6);
}
.sb-add {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: calc(100% - var(--s-2));
  margin: var(--s-5) var(--s-1) 0;
  padding: var(--s-3) var(--s-4);
  background: transparent;
  border: 0;
  border-radius: var(--r-md);
  color: var(--c-nav-text-2);
  font-size: var(--t-sm);
  font-weight: var(--t-medium);
  cursor: pointer;
}
.sb-add:hover { background: var(--c-nav-hover); color: var(--c-nav-text-active); }
.sb-add .ico { width: 16px; height: 16px; }

.sb-me {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  flex: none;
  width: 100%;
  padding: var(--s-4) var(--s-5) calc(var(--s-4) + env(safe-area-inset-bottom));
  background: transparent;
  border: 0;
  border-top: 1px solid var(--c-nav-border);
  color: var(--c-nav-text);
  cursor: pointer;
  text-align: left;
}
.sb-me:hover { background: var(--c-nav-hover); }
.sb-me-av { position: relative; flex: none; }
.sb-me-av .avatar { border-radius: var(--r-sm); }
/* The presence dot rides the avatar, punched out of the sidebar colour so it
   reads as a badge rather than a floating dot. */
.sb-me-av::after {
  content: "";
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 11px;
  height: 11px;
  border-radius: var(--r-full);
  background: var(--c-success);
  border: 2px solid var(--c-nav-bg);
}
.sb-me-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.sb-me-name {
  color: var(--c-nav-text-active);
  font-size: var(--t-sm);
  font-weight: var(--t-semibold);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sb-me-status {
  color: var(--c-nav-text-2);
  font-size: var(--t-xs);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sb-me-caret .ico { width: 14px; height: 14px; opacity: 0.6; }

/* ============================================================================
   THE COLUMN

   This used to left-align the column (margin-inline: 0 auto) on the argument
   that a right-hand gutter makes the app look like it is missing a panel. The
   argument was right and the implementation made it worse: with --reading-max at
   a flat 1080px the gutter was 492px on a 1920 window, so instead of a small
   asymmetry there was a third of the pane sitting empty behind a hard edge. Both
   organisations reported it as the chat being cut off three quarters of the way
   across the screen.

   --reading-max is now min(1600px, 100%), so the column fills the pane outright
   on every laptop and the cap only engages past 1920. Where it does engage the
   remainder is split evenly, which reads as a deliberate measure rather than a
   missing panel. Symmetry is only jarring when the gutter is large enough to
   look like a hole, and above 1920 that split is what every reading surface
   does.
   ========================================================================= */
.msg,
.daydiv,
.mx-newdiv,
#messages > .empty,
.bmk-bar,
#composerBar > .crow,
#composerBar > #replyBar,
#composerBar > #attachChips,
#typing,
#dmReceipt {
  margin-inline: auto;
}

/* ============================================================================
   MOBILE
   ========================================================================= */
@media (max-width: 860px) {
  #topbar {
    grid-template-columns: auto 1fr auto;
    gap: var(--s-3);
    padding-inline: var(--s-3);
  }
  /* The search field is the reason to keep the centre column on a phone too;
     the keyboard hint is not. */
  .searchbar-kbd { display: none; }
  .searchbar-text { font-size: var(--t-xs); }
  .userchip .meName { display: none; }
  .userchip { padding: 0 var(--s-2); }
  #topbar #spaceName { display: none; }
  #channelbar { padding-inline: var(--s-4); }
  .cb-topic { display: none; }
  #channelbar #btnInvite { display: none; }
  /* The two-on-a-phone cap used to live here, as
     `.hdr-actions button:nth-child(n + 3) { display: none }`. It was not wrong
     about the number, it was wrong about the layer: the overflow menu is built
     in JS from the same registry, and it could not see a CSS rule, so it started
     its slice at four while CSS showed two. Buttons three and four were painted
     and hidden and left out of the menu - present in the DOM, reachable by
     nobody. shell.js owns the number now and both sides read it. */
}

/* Touch ergonomics: the channel bar's icon buttons were 30x30 boxes while
   components.css extends every icon's tap area to 44x44 around its centre. With
   only 2px of gap the centres sat 32px apart but each extension reached 44px
   wide, so neighbours overlapped by 12px and the later sibling won - people
   tapping Members hit More. Full-size boxes put the centres far enough apart
   that the extensions no longer cross; 44px fits inside the 49px bar. */
@media (hover: none) {
  #channelbar button.icon {
    width: 44px;
    height: 44px;
  }
}

/* ---------------------------------------------------------------- corrections
   components.css gives every <button> a border, which is right for a real
   button and wrong for a quiet list affordance sitting inside the sidebar.
   Stated after it so the sidebar reads as a list rather than a stack of boxes. */
.sb-add {
  border: 1px solid transparent !important;
  background: transparent;
}
.sb-add:hover {
  background: var(--c-nav-hover);
  border-color: transparent !important;
}

/* Message rhythm. 16px between speakers plus a 36px avatar was leaving the
   column feeling sparse and scroll-hungry; this is closer to the density that
   lets you take in a conversation at a glance. */
.msg:not(.grouped) { margin-top: var(--s-5); }
.msg .gutter { width: 38px; }
.msg .avatar { width: 30px !important; height: 30px !important; font-size: 11px; }
.mhead { margin-bottom: var(--s-1); }
.msg .body { font-size: var(--t-base); line-height: 1.5; }
.msg { padding-block: var(--s-2); }
.msg.grouped { padding-block: 1px; }

/* The unread jump pill was floating in open space in the middle of the column.
   Pin it under the channel bar where it reads as a status about the channel. */
.sc-jump,
#unreadJump,
.jump-pill {
  position: absolute;
  top: var(--s-4);
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-sticky);
  box-shadow: var(--e-2);
}

/* The hover action bar was as wide as a toolbar. Quick reactions are useful;
   eleven of them is a menu. */
.actions { gap: 1px; padding: var(--s-1); box-shadow: var(--e-2); }
.actions .quick:nth-child(n + 5) { display: none; }

/* ---------------------------------------------------------------- channel guide
   The first-visit orientation card. A banner above the conversation, never a
   dialog: a modal on channel entry steals focus, blocks the composer, and fires
   once per channel, so joining a Space with six channels means six interruptions
   and nobody reads the sixth. */
.chguide-banner {
  flex: none;
  margin: var(--s-4) var(--s-6) 0;
  padding: var(--s-5);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-left: 3px solid var(--c-accent);
  border-radius: var(--r-md);
  max-width: var(--reading-max);
}
.chguide-bannerhead {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin-bottom: var(--s-3);
}
.chguide-bannerhead strong { flex: 1 1 auto; font-size: var(--t-base); }
@media (max-width: 860px) { .chguide-banner { margin-inline: var(--s-4); } }

/* ------------------------------------------------------- connection state
   Shown only while delivery is actually down, so its absence is the good news.
   Amber rather than red: the connection coming back is the normal outcome and
   the usual cause is a tunnel, not a fault. It goes red only when the device
   itself reports being offline, which is the one case the app cannot fix. */
.connstate {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: 4px var(--s-3) 4px var(--s-4);
  border-radius: var(--r-pill, 999px);
  background: color-mix(in srgb, var(--c-warn, #b7791f) 16%, var(--c-nav-bg));
  border: 1px solid color-mix(in srgb, var(--c-warn, #b7791f) 42%, transparent);
  color: var(--c-nav-text);
  font-size: var(--t-xs);
  line-height: 1.3;
  white-space: nowrap;
}
.connstate.offline {
  background: color-mix(in srgb, var(--c-danger) 16%, var(--c-nav-bg));
  border-color: color-mix(in srgb, var(--c-danger) 45%, transparent);
}
.connstate-dot {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: var(--c-warn, #b7791f);
  animation: connpulse 1.6s ease-in-out infinite;
}
.connstate.offline .connstate-dot { background: var(--c-danger); animation: none; }
@keyframes connpulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .connstate-dot { animation: none; } }

.connstate-btn {
  padding: 2px var(--s-3);
  min-height: 0;
  border-radius: var(--r-sm);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--c-nav-text) 32%, transparent);
  color: var(--c-nav-text);
  font-size: var(--t-xs);
  font-weight: var(--t-medium);
}
.connstate-btn:hover:not(:disabled) { background: color-mix(in srgb, var(--c-nav-text) 12%, transparent); }
.connstate-btn:disabled { opacity: 0.6; }

/* On a phone the bar would push the user chip off the edge, so it loses its
   button and keeps only the word - which is the part that matters. */
@media (max-width: 620px) {
  .connstate-btn { display: none; }
  .connstate { padding-right: var(--s-4); }
}

/* ============================================================================
   BOTTOM TAB BAR - the phone shell.
   A sibling of main inside the #chat flex column: normal flow means every
   scroll container above it already reserves its height, and nothing floats
   over the composer. Hidden by default; owns the bottom edge under 860px only,
   never in embeds, never on the no-team or auth screens (it lives in #chat).
   ========================================================================== */
.tabbar { display: none; }

@media (max-width: 860px) {
  :root { --tabbar-h: calc(56px + env(safe-area-inset-bottom)); }
.tabbar {
    display: flex;
    height: var(--tabbar-h);
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--c-nav-bg);
    border-top: 1px solid var(--c-border);
    z-index: calc(var(--z-sticky) + 5);
  }
  .tabbar .tab {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-height: 44px;
    background: none;
    border: none;
    color: var(--c-text-3);
    font-size: 10px;
    cursor: pointer;
    position: relative;
  }
  .tabbar .tab.on { color: var(--c-accent); }
  .tabbar .tab-dot {
    position: absolute;
    top: 7px;
    right: calc(50% - 20px);
    width: 8px;
    height: 8px;
    border-radius: var(--r-full);
    background: var(--c-danger);
    opacity: 0;
    pointer-events: none;
  }
  .tabbar .tab-dot.show {
    opacity: 1;
    min-width: 15px;
    height: 15px;
    line-height: 15px;
    padding: 0 3px;
    font-style: normal;
    font-size: 10px;
    color: #fff;
    text-align: center;
  }
  /* Keyboard parity: tabs are buttons; focus must be as visible as on desktop. */
  .tabbar .tab:focus-visible {
    outline: 2px solid var(--c-accent);
    outline-offset: -2px;
    border-radius: var(--r-md);
  }
}

@media (min-width: 861px) {
  .tabbar { display: none !important; }
}
html.embed-minimal .tabbar,
body.no-team .tabbar { display: none !important; }
