/* Lassy Meet — reset, primitives and the shared Fluent-derived controls.

   The control rules below (button, switch, radio, input, menu, tooltip) are
   transcriptions of the Fluent v9 rules the reference capture actually
   served — including the states, which is where most of the Teams "feel"
   lives. Where a rule came from a specific Fluent class the class is named
   in a comment so it can be diffed against `team_html/` later.
*/

/* --------------------------------------------------------------------- */
/* Reset                                                                  */
/* --------------------------------------------------------------------- */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  /* 1rem = 10px, the unit base every value copied out of Teams' atomic CSS
     assumes.

     Absolute, not the usual `62.5%`. The percentage resolves against the
     browser's default font size, so a user who has raised theirs — or is at a
     non-100% zoom — gets every margin, radius and control size scaled up,
     while the text stays put because the type tokens are px. That reads as
     "the whole app is bigger than Teams", which is exactly what it is.
     Locking it keeps geometry deterministic; text size is unaffected either
     way, since none of it is expressed in rem. */
  font-size: 10px;
  height: 100%;
}

/* Type is the thing that should follow the reader, and it already does — the
   tokens are px and honour browser zoom. */

body {
  height: 100%;
  margin: 0;
  font-family: var(--fontFamilyBase);
  font-size: var(--fontSizeBase300);
  line-height: var(--lineHeightBase300);
  font-weight: var(--fontWeightRegular);
  color: var(--colorNeutralForeground1);
  background-color: var(--colorNeutralBackground3);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

/* The shell is a full-height grid, so every ancestor has to carry the
   height down or it collapses to its content and the rail stops short. */
#app { height: 100%; }

h1, h2, h3, h4, p, figure { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
button, input, select, textarea { font: inherit; color: inherit; }
svg { display: block; fill: currentColor; }
img { max-width: 100%; }

[hidden] { display: none !important; }

/* --------------------------------------------------------------------- */
/* Focus                                                                  */
/* --------------------------------------------------------------------- */

/* Fluent draws focus as a two-tone ring rather than a UA outline: a light
   inner stroke and a dark outer one, so it reads on any background. */
:focus-visible { outline: none; }

.focus-ring:focus-visible {
  position: relative;
  border-radius: var(--borderRadiusMedium);
  outline: var(--strokeWidthThick) solid var(--colorStrokeFocus2);
  outline-offset: calc(var(--strokeWidthThick) * -1);
  box-shadow: 0 0 0 var(--strokeWidthThin) var(--colorStrokeFocus1) inset;
  z-index: 1;
}

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

/* --------------------------------------------------------------------- */
/* Scrollbars — Teams overlays a translucent thumb on a transparent track  */
/* --------------------------------------------------------------------- */

/* The reference's own rules, applied globally as it applies them — its
   FluentProvider wraps the whole app, so every scrolling area gets them.
   14px gutter, transparent track, and a thumb with **no colour of its own**:
   it only takes `--colorScrollbarOverlay` while the scrolling area is
   hovered. That is why Teams looks like it has no scrollbars at rest, and
   why mine looked like it had one everywhere. */
::-webkit-scrollbar { width: 1.4rem; height: 1.4rem; }
::-webkit-scrollbar:disabled { display: none; }
::-webkit-scrollbar-track,
::-webkit-scrollbar-corner { background-color: transparent; }
::-webkit-scrollbar-thumb {
  border: 4px solid transparent;
  border-radius: 9px;
  background-clip: content-box;
  min-height: 32px;
  min-width: 32px;
}
:hover::-webkit-scrollbar-thumb { background-color: var(--colorScrollbarOverlay); }
::-webkit-scrollbar-thumb:hover { border-width: 2px; }

/* Firefox has no `::-webkit-scrollbar`, so the same effect is expressed with
   `scrollbar-color`: invisible at rest, visible while the pointer is in the
   window. Without this Firefox draws a permanent bar where Chromium draws
   none, which is not a difference anyone wants to explain. */
:root { scrollbar-width: thin; scrollbar-color: transparent transparent; }
:root:hover { scrollbar-color: var(--colorScrollbarOverlay) transparent; }

/* The document itself never scrolls — the app is a fixed frame and each
   screen scrolls its own content. A scrollbar out here is always a bug. */
html, body { overflow: hidden; }

.scroll { overflow-y: auto; }

/* --------------------------------------------------------------------- */
/* Icons                                                                  */
/* --------------------------------------------------------------------- */

/* Fluent ships every icon twice — outline by default, filled on hover and
   while pressed. `ft1hn21`/`fuxngvv` swap them; this is that swap. */
.icon { width: 1em; height: 1em; flex-shrink: 0; }
.icon-filled { display: none; }
.icon-regular { display: inline; }
.btn:hover > .btn__icon > .icon-filled,
.btn:active > .btn__icon > .icon-filled,
.btn[aria-pressed='true'] > .btn__icon > .icon-filled,
.btn[data-selected='true'] > .btn__icon > .icon-filled { display: inline; }
.btn:hover > .btn__icon > .icon-regular,
.btn:active > .btn__icon > .icon-regular,
.btn[aria-pressed='true'] > .btn__icon > .icon-regular,
.btn[data-selected='true'] > .btn__icon > .icon-regular { display: none; }

/* --------------------------------------------------------------------- */
/* Button — Fluent `r1f29ykk` plus its appearance variants                */
/* --------------------------------------------------------------------- */

.btn {
  align-items: center;
  box-sizing: border-box;
  display: inline-flex;
  justify-content: center;
  text-decoration-line: none;
  vertical-align: middle;
  margin: 0;
  overflow: hidden;
  background-color: var(--colorNeutralBackground1);
  color: var(--colorNeutralForeground1);
  border: var(--strokeWidthThin) solid var(--colorNeutralStroke1);
  font-family: var(--fontFamilyBase);
  outline-style: none;
  padding: 5px var(--spacingHorizontalM);
  min-width: 96px;
  border-radius: var(--borderRadiusMedium);
  font-size: var(--fontSizeBase300);
  font-weight: var(--fontWeightSemibold);
  line-height: var(--lineHeightBase300);
  gap: var(--spacingHorizontalS);
  transition-duration: var(--durationFaster);
  transition-property: background, border, color;
  transition-timing-function: var(--curveEasyEase);
}
.btn:hover {
  background-color: var(--colorNeutralBackground1Hover);
  border-color: var(--colorNeutralStroke1Hover);
  color: var(--colorNeutralForeground1Hover);
  cursor: pointer;
}
.btn:hover:active {
  background-color: var(--colorNeutralBackground1Pressed);
  border-color: var(--colorNeutralStroke1Pressed);
  color: var(--colorNeutralForeground1Pressed);
}
.btn:disabled,
.btn[aria-disabled='true'] {
  background-color: var(--colorNeutralBackgroundDisabled);
  border-color: var(--colorNeutralStrokeDisabled);
  color: var(--colorNeutralForegroundDisabled);
  cursor: not-allowed;
}
.btn__icon { display: inline-flex; align-items: center; font-size: 20px; line-height: 0; }

@media screen and (prefers-reduced-motion: reduce) { .btn { transition-duration: 0.01ms; } }

/* primary — `ffp7eso` family */
.btn--primary {
  background-color: var(--colorBrandBackground);
  color: var(--colorNeutralForegroundOnBrand);
  border-color: transparent;
}
.btn--primary:hover {
  background-color: var(--colorBrandBackgroundHover);
  color: var(--colorNeutralForegroundOnBrand);
  border-color: transparent;
}
.btn--primary:hover:active {
  background-color: var(--colorBrandBackgroundPressed);
  color: var(--colorNeutralForegroundOnBrand);
  border-color: transparent;
}
.btn--primary:disabled,
.btn--primary[aria-disabled='true'] {
  background-color: var(--colorNeutralBackgroundDisabled);
  color: var(--colorNeutralForegroundDisabled);
  border-color: transparent;
}

/* subtle — `f1c21dwh` family: transparent until hovered */
.btn--subtle {
  background-color: var(--colorTransparentBackground);
  color: var(--colorNeutralForeground2);
  border-color: transparent;
  min-width: 0;
}
.btn--subtle:hover {
  background-color: var(--colorSubtleBackgroundHover);
  color: var(--colorNeutralForeground2BrandHover);
  border-color: transparent;
}
.btn--subtle:hover:active {
  background-color: var(--colorSubtleBackgroundPressed);
  color: var(--colorNeutralForeground2BrandPressed);
  border-color: transparent;
}
.btn--subtle:disabled,
.btn--subtle[aria-disabled='true'] {
  background-color: transparent;
  color: var(--colorNeutralForegroundDisabled);
  border-color: transparent;
}

/* transparent — subtle, but keeps the neutral foreground on hover */
.btn--transparent {
  background-color: transparent;
  color: var(--colorNeutralForeground2);
  border-color: transparent;
  min-width: 0;
}
.btn--transparent:hover { background-color: transparent; color: var(--colorNeutralForeground2BrandHover); border-color: transparent; }
.btn--transparent:hover:active { background-color: transparent; color: var(--colorNeutralForeground2BrandPressed); border-color: transparent; }

/* secondary — default appearance, given a shadow like the pre-join Cancel */
.btn--elevated { box-shadow: var(--colorNeutralShadowAmbient) 0 0 0.2rem, var(--colorNeutralShadowKey) 0 0.2rem 0.4rem; }

/* icon-only square button */
.btn--icon {
  min-width: 3.2rem;
  width: 3.2rem;
  height: 3.2rem;
  padding: 0;
  gap: 0;
}
.btn--icon.btn--lg { min-width: 4rem; width: 4rem; height: 4rem; }

.btn--danger { background-color: var(--colorStatusDangerBackground3); color: #ffffff; border-color: transparent; }
.btn--danger:hover { background-color: var(--cranberryShade10); color: #ffffff; border-color: transparent; }
.btn--danger:hover:active { background-color: var(--cranberryShade20); color: #ffffff; border-color: transparent; }

.btn--circular { border-radius: var(--borderRadiusCircular); }
.btn--block { width: 100%; }

/* menu button — a button with a trailing chevron, e.g. the device pickers */
.menu-btn__chevron { font-size: 12px; display: inline-flex; align-items: center; margin-left: var(--spacingHorizontalXS); }

/* --------------------------------------------------------------------- */
/* Switch — Fluent `r2i81i2` / `r12ojtgy` / `r1c3hft5`                     */
/* --------------------------------------------------------------------- */

.switch {
  align-items: flex-start;
  box-sizing: border-box;
  display: inline-flex;
  position: relative;
  flex-shrink: 0;
}
.switch__input {
  box-sizing: border-box;
  cursor: pointer;
  height: 100%;
  margin: 0;
  opacity: 0;
  position: absolute;
  left: 0;
  width: calc(40px + 2 * var(--spacingHorizontalS));
}
.switch__indicator {
  border-radius: var(--borderRadiusCircular);
  border: 1px solid;
  line-height: 0;
  box-sizing: border-box;
  fill: currentColor;
  flex-shrink: 0;
  font-size: 18px;
  height: 20px;
  width: 40px;
  margin: var(--spacingVerticalS) var(--spacingHorizontalS);
  pointer-events: none;
  transition-duration: var(--durationNormal);
  transition-timing-function: var(--curveEasyEase);
  transition-property: background, border, color;
}
.switch__indicator > * {
  transition-duration: var(--durationNormal);
  transition-timing-function: var(--curveEasyEase);
  transition-property: transform;
}
.switch__input:checked ~ .switch__indicator > * { transform: translateX(20px); }

.switch__input:enabled:not(:checked) ~ .switch__indicator {
  color: var(--colorNeutralStrokeAccessible);
  border-color: var(--colorNeutralStrokeAccessible);
}
.switch__input:enabled:not(:checked):hover ~ .switch__indicator {
  color: var(--colorNeutralStrokeAccessibleHover);
  border-color: var(--colorNeutralStrokeAccessibleHover);
}
.switch__input:enabled:checked ~ .switch__indicator {
  background-color: var(--colorCompoundBrandBackground);
  color: var(--colorNeutralForegroundInverted);
  border-color: var(--colorTransparentStroke);
}
.switch__input:enabled:checked:hover ~ .switch__indicator {
  background-color: var(--colorCompoundBrandBackgroundHover);
}
.switch__input:disabled { cursor: default; }
.switch__input:disabled ~ .switch__indicator { color: var(--colorNeutralForegroundDisabled); border-color: var(--colorNeutralStrokeDisabled); }
.switch__input:disabled:checked ~ .switch__indicator { background-color: var(--colorNeutralBackgroundDisabled); border-color: transparent; }

@media screen and (prefers-reduced-motion: reduce) {
  .switch__indicator, .switch__indicator > * { transition-duration: 0.01ms; }
}

/* --------------------------------------------------------------------- */
/* Radio — Fluent `r1siqwd8` / `rg1upok` / `rwtekvw`                       */
/* --------------------------------------------------------------------- */

.radio { display: inline-flex; position: relative; }
.radio__input {
  position: absolute;
  left: 0; top: 0;
  width: calc(16px + 2 * var(--spacingHorizontalS));
  height: 100%;
  box-sizing: border-box;
  margin: 0;
  opacity: 0;
}
.radio__input:enabled { cursor: pointer; }
.radio__input:enabled ~ .radio__label { cursor: pointer; }
.radio__indicator {
  position: relative;
  width: 16px; height: 16px;
  font-size: 12px;
  box-sizing: border-box;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border: var(--strokeWidthThin) solid;
  border-radius: var(--borderRadiusCircular);
  margin: var(--spacingVerticalS) var(--spacingHorizontalS);
  fill: currentColor;
  pointer-events: none;
}
.radio__indicator::after {
  content: '';
  position: absolute;
  width: 16px; height: 16px;
  border-radius: var(--borderRadiusCircular);
  transform: scale(0.625);
  background-color: currentColor;
  opacity: 0;
}
.radio__input:enabled:not(:checked) ~ .radio__indicator { border-color: var(--colorNeutralStrokeAccessible); }
.radio__input:enabled:not(:checked) ~ .radio__label { color: var(--colorNeutralForeground3); }
.radio__input:enabled:not(:checked):hover ~ .radio__indicator { border-color: var(--colorNeutralStrokeAccessibleHover); }
.radio__input:enabled:not(:checked):hover ~ .radio__label { color: var(--colorNeutralForeground2); }
.radio__input:checked ~ .radio__indicator { border-color: var(--colorCompoundBrandStroke); color: var(--colorCompoundBrandForeground1); }
.radio__input:checked ~ .radio__indicator::after { opacity: 1; }
.radio__input:checked ~ .radio__label { color: var(--colorNeutralForeground1); }
.radio__input:checked:hover ~ .radio__indicator { border-color: var(--colorCompoundBrandStrokeHover); color: var(--colorCompoundBrandForeground1Hover); }
.radio__input:disabled ~ .radio__indicator { border-color: var(--colorNeutralStrokeDisabled); color: var(--colorNeutralForegroundDisabled); }
.radio__input:disabled ~ .radio__label { color: var(--colorNeutralForegroundDisabled); cursor: default; }
.radio__label { display: flex; align-items: center; padding-right: var(--spacingHorizontalS); }

/* --------------------------------------------------------------------- */
/* Text input — Fluent Input, underline + subtle fill                      */
/* --------------------------------------------------------------------- */

/* A column of fields with the dialog's own rhythm between them. */
.stack { display: flex; flex-direction: column; gap: var(--spacingVerticalM); }
.field { display: flex; flex-direction: column; gap: var(--spacingVerticalXS); }
.field__label { font-size: var(--fontSizeBase300); font-weight: var(--fontWeightSemibold); color: var(--colorNeutralForeground1); }
.field__hint { font-size: var(--fontSizeBase200); line-height: var(--lineHeightBase200); color: var(--colorNeutralForeground3); }
.field__error { font-size: var(--fontSizeBase200); line-height: var(--lineHeightBase200); color: var(--colorStatusDangerForeground1); }

.input {
  display: inline-flex;
  align-items: center;
  box-sizing: border-box;
  min-height: 3.2rem;
  padding: 0 var(--spacingHorizontalMNudge);
  width: 100%;
  background-color: var(--colorNeutralBackground1);
  border: var(--strokeWidthThin) solid var(--colorNeutralStroke1);
  border-bottom-color: var(--colorNeutralStrokeAccessible);
  border-radius: var(--borderRadiusMedium);
  font-size: var(--fontSizeBase300);
  line-height: var(--lineHeightBase300);
  color: var(--colorNeutralForeground1);
  outline: none;
}
.input::placeholder { color: var(--colorNeutralForeground4); opacity: 1; }
.input:hover { border-color: var(--colorNeutralStroke1Hover); border-bottom-color: var(--colorNeutralStrokeAccessibleHover); }
.input:focus {
  border-color: var(--colorNeutralStroke1);
  border-bottom-color: var(--colorCompoundBrandStroke);
  box-shadow: 0 1px 0 0 var(--colorCompoundBrandStroke);
}
.input:disabled { background-color: var(--colorNeutralBackgroundDisabled); border-color: var(--colorNeutralStrokeDisabled); color: var(--colorNeutralForegroundDisabled); }
.input--invalid, .input--invalid:focus { border-color: var(--colorStatusDangerBorder1); border-bottom-color: var(--colorStatusDangerBackground3); box-shadow: 0 1px 0 0 var(--colorStatusDangerBackground3); }

/* --------------------------------------------------------------------- */
/* Menu / popover — Fluent surface: radius XL, shadow16                    */
/* --------------------------------------------------------------------- */

.menu {
  position: absolute;
  min-width: 16rem;
  max-width: 40rem;
  padding: var(--spacingVerticalXS);
  background-color: var(--colorNeutralBackground1);
  border: var(--strokeWidthThin) solid var(--colorTransparentStroke);
  border-radius: var(--borderRadiusMedium);
  box-shadow: var(--shadow16);
  z-index: var(--zIndexPopup);
}
.menu__group + .menu__group { border-top: var(--strokeWidthThin) solid var(--colorNeutralStroke2); margin-top: var(--spacingVerticalXS); padding-top: var(--spacingVerticalXS); }
.menu__header {
  padding: var(--spacingVerticalS) var(--spacingHorizontalM) var(--spacingVerticalXS);
  font-size: var(--fontSizeBase200);
  line-height: var(--lineHeightBase200);
  font-weight: var(--fontWeightSemibold);
  color: var(--colorNeutralForeground3);
}
.menu__item {
  display: flex;
  align-items: center;
  gap: var(--spacingHorizontalS);
  width: 100%;
  min-height: 3.2rem;
  padding: 0 var(--spacingHorizontalM);
  background: none;
  border: 0;
  border-radius: var(--borderRadiusMedium);
  font-size: var(--fontSizeBase300);
  line-height: var(--lineHeightBase300);
  color: var(--colorNeutralForeground1);
  text-align: left;
  cursor: pointer;
}
.menu__item:hover { background-color: var(--colorSubtleBackgroundHover); }
.menu__item:active { background-color: var(--colorSubtleBackgroundPressed); }
/* The check alone carries selection — the reference does not embolden the
   row, and a heavier label next to a tick reads as two signals for one fact. */
.menu__item[aria-expanded='true'] { background-color: var(--colorSubtleBackgroundHover); }
.menu__item__text { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.menu__item:disabled { color: var(--colorNeutralForegroundDisabled); cursor: default; background: none; }

/* Leading glyph, then the label, then the state — the check and the submenu
   chevron share the trailing slot, which is where the reference flyout puts
   them. An item with no glyph simply starts at the label; Teams does not pad
   it out to the icon column. */
.menu__item__icon { font-size: 20px; line-height: 0; flex-shrink: 0; color: var(--colorNeutralForeground2); }
.menu__item__icon svg { width: 2rem; height: 2rem; }
/* The glyph takes the brand colour under the pointer, the same way a control
   in the toolbar does. The row's text and background stay neutral -- it is the
   icon alone that answers, which is what makes a Fluent menu feel responsive
   without lighting up. Excludes disabled rows, which must not look live. */
.menu__item:not(:disabled):hover .menu__item__icon,
.menu__item:not(:disabled):focus-visible .menu__item__icon {
  color: var(--colorNeutralForeground2BrandHover);
}
/* Colour is only half of it -- Fluent swaps outline for filled at the same
   moment (`ft1hn21`/`fuxngvv`), which is why a hovered Teams menu icon reads
   as solid rather than merely tinted. The `.btn` rules do this for buttons; a
   menu row is not a `.btn`, so it needs its own pair. */
.menu__item:not(:disabled):hover .menu__item__icon .icon-filled,
.menu__item:not(:disabled):focus-visible .menu__item__icon .icon-filled { display: inline; }
.menu__item:not(:disabled):hover .menu__item__icon .icon-regular,
.menu__item:not(:disabled):focus-visible .menu__item__icon .icon-regular { display: none; }
.menu__item:disabled .menu__item__icon { color: var(--colorNeutralForegroundDisabled); }

.menu__item__check,
.menu__item__sub { width: 1.6rem; line-height: 0; flex-shrink: 0; margin-left: var(--spacingHorizontalS); }
.menu__item__check { font-size: 16px; color: var(--colorNeutralForeground1); visibility: hidden; }
.menu__item[aria-checked='true'] .menu__item__check { visibility: visible; }
.menu__item__check svg { width: 1.6rem; height: 1.6rem; }
.menu__item__sub { font-size: 12px; color: var(--colorNeutralForeground3); }
.menu__item__sub svg { width: 1.2rem; height: 1.2rem; }

/* Radio, on the leading edge, for rows that pick one of a set — the device
   lists in the mic and camera flyouts. Fluent draws a ring in the neutral
   stroke and fills it with a brand dot; the ring thickens rather than the
   dot appearing, which is why the border is what changes. */
.menu__item__radio {
  position: relative;
  box-sizing: border-box;
  flex-shrink: 0;
  width: 1.6rem;
  height: 1.6rem;
  border: 0.1rem solid var(--colorNeutralStrokeAccessible);
  border-radius: var(--borderRadiusCircular);
}
.menu__item[aria-checked='true'] .menu__item__radio { border-color: var(--colorCompoundBrandStroke); }
.menu__item[aria-checked='true'] .menu__item__radio::after {
  content: '';
  position: absolute;
  inset: 0.3rem;
  border-radius: var(--borderRadiusCircular);
  background-color: var(--colorCompoundBrandForeground1);
}
.menu__item:disabled .menu__item__radio { border-color: var(--colorNeutralForegroundDisabled); }

/* A submenu is the same surface, positioned beside its parent row. */
.menu--sub { position: fixed; }

/* --------------------------------------------------------------------- */
/* Tooltip                                                                */
/* --------------------------------------------------------------------- */

/* Every value here was resolved from the `role="tooltip"` element saved in
   team_html/ — see js/tooltip.js for the class-to-rule mapping. Teams
   overrides Fluent's own padding (4px 11px 6px) and max-width (240px) with
   the two below.

   The one addition is the shadow. Nothing on the reference's tooltip carries
   `box-shadow`, but its border is `colorTransparentStroke` — literally
   `transparent` — which would leave a white surface with no edge at all
   sitting on the white control bar. Fluent's Tooltip ships `shadow4`, so that
   is what is used; if a capture ever shows otherwise, drop it. */
.tooltip {
  position: fixed;
  z-index: var(--zIndexPopup);
  max-width: 328px;
  padding: 12px;
  box-sizing: border-box;
  background-color: var(--colorNeutralBackground1);
  color: var(--colorNeutralForeground1);
  border: 1px solid var(--colorTransparentStroke);
  border-radius: var(--borderRadiusMedium);
  box-shadow: var(--shadow4);
  font-family: var(--fontFamilyBase);
  font-size: var(--fontSizeBase200);
  line-height: var(--lineHeightBase200);
  /* A tooltip may carry more than one line -- a chat reaction names itself and
     then everyone who gave it, one per line, which is the reference's stacked
     layout. `pre-line` keeps those breaks and still collapses the rest. */
  white-space: pre-line;
  overflow-wrap: break-word;
  /* The emoji picker's tooltip is two lines — a name and its shortcode, as the
     reference writes it. `pre-line` honours the newline without turning the
     surface into a <pre>: runs of spaces still collapse and long text still
     wraps at max-width. */
  white-space: pre-line;
  cursor: default;
  pointer-events: none;
}
.tooltip[hidden] { display: none; }

/* The beak: a 6px square rotated 45°, half its diagonal outside the surface —
   the reference's `--fui-positioning-arrow-offset: -4.242px`. */
.tooltip__arrow {
  position: absolute;
  width: 6px;
  height: 6px;
  transform: translateX(-50%) rotate(45deg);
  background-color: inherit;
  border: 1px solid var(--colorTransparentStroke);
  border-radius: var(--borderRadiusSmall);
  z-index: -1;
}
.tooltip__arrow[data-side='top'] { top: -4.242px; }
.tooltip__arrow[data-side='bottom'] { bottom: -4.242px; }

/* --------------------------------------------------------------------- */
/* MessageBar — the pre-join banner                                       */
/* --------------------------------------------------------------------- */

.msgbar {
  display: flex;
  align-items: start;
  gap: var(--spacingHorizontalS);
  padding: var(--spacingVerticalS) var(--spacingHorizontalM);
  border: var(--strokeWidthThin) solid var(--colorNeutralStroke2);
  border-radius: var(--borderRadiusMedium);
  background-color: var(--colorNeutralBackground3);
  font-size: var(--fontSizeBase300);
  line-height: var(--lineHeightBase300);
  color: var(--colorNeutralForeground1);
}
.msgbar__icon { font-size: 20px; line-height: 0; padding-top: 1px; }
.msgbar__body { flex: 1; }
.msgbar--warning { background-color: var(--colorStatusWarningBackground1); border-color: var(--colorStatusWarningBorder1); }
.msgbar--warning .msgbar__icon { color: var(--colorStatusWarningForeground1); }
.msgbar--error { background-color: var(--colorStatusDangerBackground1); border-color: var(--colorStatusDangerBorder1); }
.msgbar--error .msgbar__icon { color: var(--colorStatusDangerForeground1); }
.msgbar--success { background-color: var(--colorStatusSuccessBackground1); border-color: var(--colorStatusSuccessBorder1); }
.msgbar--success .msgbar__icon { color: var(--colorStatusSuccessForeground1); }

/* --------------------------------------------------------------------- */
/* Avatar                                                                 */
/* --------------------------------------------------------------------- */

.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 3.2rem;
  height: 3.2rem;
  border-radius: var(--borderRadiusCircular);
  background-color: var(--avatar-bg, var(--brand60));
  color: var(--avatar-ink, #ffffff);
  /* Fluent's own ratio, which is smaller than it looks like it should be: a
     32px avatar carries 12px initials, not 14px. Two points of type is the
     difference between initials sitting in the disc and filling it. */
  font-size: var(--fontSizeBase200);
  font-weight: var(--fontWeightSemibold);
  line-height: 1;
  overflow: hidden;
  user-select: none;
}
.avatar--sm { width: 2.4rem; height: 2.4rem; font-size: var(--fontSizeBase100); }
.avatar--lg { width: 7.2rem; height: 7.2rem; font-size: var(--fontSizeHero700); }
.avatar--xl { width: 12rem; height: 12rem; font-size: var(--fontSizeHero900); }
.avatar img { width: 100%; height: 100%; object-fit: cover; }

/* --------------------------------------------------------------------- */
/* Spinner                                                                */
/* --------------------------------------------------------------------- */

.spinner {
  width: 3.2rem; height: 3.2rem;
  border: 3px solid var(--colorBrandStroke2);
  border-top-color: var(--colorCompoundBrandStroke);
  border-radius: var(--borderRadiusCircular);
  animation: spin 1.5s var(--curveEasyEaseMax) infinite;
}
.spinner--sm { width: 2rem; height: 2rem; border-width: 2px; }
@keyframes spin { to { transform: rotate(360deg); } }
@media screen and (prefers-reduced-motion: reduce) { .spinner { animation-duration: 4s; } }

/* --------------------------------------------------------------------- */
/* Divider                                                                */
/* --------------------------------------------------------------------- */

.divider-v { width: 1px; align-self: stretch; background-color: var(--colorNeutralStroke2); margin: 0 var(--spacingHorizontalS); }
.divider-h { height: 1px; background-color: var(--colorNeutralStroke2); margin: var(--spacingVerticalS) 0; }

/* --------------------------------------------------------------------- */
/* Link                                                                   */
/* --------------------------------------------------------------------- */

.link {
  color: var(--colorBrandForegroundLink);
  text-decoration: none;
  font-size: var(--fontSizeBase300);
  border-radius: var(--borderRadiusSmall);
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
}
.link:hover { color: var(--colorBrandForegroundLinkHover); text-decoration: underline; }
.link:active { color: var(--colorBrandForegroundLinkPressed); }

/* --------------------------------------------------------------------- */
/* Text helpers                                                           */
/* --------------------------------------------------------------------- */

.truncate { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.text-caption { font-size: var(--fontSizeBase200); line-height: var(--lineHeightBase200); }
.text-secondary { color: var(--colorNeutralForeground2); }
.text-tertiary { color: var(--colorNeutralForeground3); }
.text-semibold { font-weight: var(--fontWeightSemibold); }

/* --------------------------------------------------------------------- */
/* Load screen                                                            */
/* --------------------------------------------------------------------- */

/* A transcription of the reference's own `<style id="loading-styles">`, the
   T2.1 branch: the six-layer mark, its 3s timeline, and the glint sweep. The
   numbers below are Microsoft's, not chosen here.

   `place-content`, not `place-items`. That distinction is the whole reason the
   mark and the caption used to sit a third of the viewport apart: `place-items`
   is shorthand for `align-items` + `justify-items` only, and leaves
   `align-content` at `normal`, which for a grid behaves as `stretch`. Two
   children make two implicit rows, each row stretches to half the height, and
   each item centres inside its own half. `place-content` centres the row group
   itself, which is what the reference uses on `#loading-screen`. */
.splash {
  position: fixed;
  inset: 0;
  z-index: 1500;
  display: grid;
  place-content: center;
  justify-items: center;
  background-color: var(--colorNeutralBackground3);
  opacity: 1;
}

/* `fade-out-animation-T2_1` - 320ms on the surface. */
.splash--out {
  pointer-events: none;
  animation: splash-fade-out 320ms cubic-bezier(1, 0, 0.78, 1) forwards;
}
@keyframes splash-fade-out { to { opacity: 0; } }

/* The reference sizes the mark against viewport *height* and steps it down as
   the window grows, so it stays a comparable share of a short window without
   dominating a tall one. `--target-size` is its variable name. */
.splash__mark {
  /* Own stacking context, so lifting the glint above the mark stays inside
     here rather than escaping into `.splash`. */
  position: relative;
  z-index: 0;
  /* The floor is inside `--target-size`, not a min-width. The wrapper scales by
     `--target-size / 200px`, so clamping the box separately would leave the
     artwork small inside a larger box — the two have to be the same number. */
  --target-size: max(12rem, 23.6vh);
  --base-size: 200px;
  width: var(--target-size);
  height: var(--target-size);
}
@media only screen and (min-height: 768px)  { .splash__mark { --target-size: 20.6vh; } }
@media only screen and (min-height: 1024px) { .splash__mark { --target-size: 17.6vh; } }
@media only screen and (min-height: 1280px) { .splash__mark { --target-size: 14.6vh; } }

/* The layer keyframes below translate in px against a fixed 200x200 space, so
   the artwork cannot be resized by changing the SVG box - it is scaled whole.
   Dividing a length by a length is CSS Values 4 arithmetic; verified resolving
   in this engine rather than assumed. */
.splash__mark .entry-svg-container {
  position: relative;
  width: 100%;
  height: 100%;
}
.splash__mark .entry-svg {
  position: absolute;
  inset: 0;
}
/* The sweep paints OVER the finished mark, not under it. Both `.entry-svg`
   layers are positioned and neither carried a z-index, so painting order fell
   to tree order and `.welcome-svg` -- the six opaque layers, second in the DOM
   -- covered the glint completely. The overlap is total rather than partial:
   the glint is clipped to the silhouette, so every pixel it draws is a pixel
   the mark also draws. Measured max channel delta across a whole cycle before
   this rule: 1/255. The reference lifts it with
   `.t2-icon-2025-glint > .entry-svg-container > .glint-svg { z-index: 1 }`. */
.splash__mark .glint-svg { z-index: 1; }
.splash__mark .logo-wrapper {
  transform: scale(calc(var(--target-size) / var(--base-size)));
  transform-origin: top left;
  will-change: transform;
}
.splash__mark .logo-container {
  position: relative;
  width: 200px;
  height: 200px;
}
.splash__mark .logo-layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  will-change: transform;
  transform-origin: 0 0;
}
.splash__mark .logo-layer svg {
  position: absolute;
  top: 0;
  left: 0;
  overflow: visible;
  width: 200px;
  height: 200px;
}
/* Referenceable but never painted. */
.splash__mark .gradient-defs {
  position: absolute;
  width: 0;
  height: 0;
  visibility: hidden;
}

/* ---- the 3s build, layer by layer (all values from the reference) ---- */

/* The clip is load-bearing and I dropped it when porting. The purple body is
   drawn from frame 0 and slides down into place; the clip is what hides it
   until it arrives, so body and head land together. Without it the body is
   simply visible from the start, sitting high, and only the head animates --
   which reads as the body appearing first. */
.layer-purple {
  animation: none;
  transform-origin: 0 0;
  clip-path: path('M121.055 87 L143.75 87 c13.125 0 23.75 10.625 23.75 23.75 v39.3 C167.5 164.95 155.425 177 140.55 177 l-15.37 0 c-14.9 0-26.95-12.075-26.95-26.95 v-46.01 C98.23 91.87 98.768 87 108.08 87 h12.975 Z');
}
.layer-purple-animated {
  animation: layer-purple-anim 3000ms linear normal forwards;
  transform-origin: 0 0;
}
@keyframes layer-purple-anim {
  0%   { transform: translate(130.0125px, 40px); }
  25%  { transform: translate(130.0125px, 40px); animation-timing-function: cubic-bezier(0, 0, 0, 1); }
  36.666667% { transform: translate(130.0125px, 132.5px); }
  100% { transform: translate(130.0125px, 132.5px); }
}

.layer-blue {
  animation: layer-blue-anim 3000ms linear normal forwards;
  transform-origin: 0 0;
}
@keyframes layer-blue-anim {
  0%   { transform: translate(140.0125px, 177.5px) scale(0.5, 0); }
  36%  { transform: translate(140.0125px, 177.5px) scale(0.5, 0); animation-timing-function: cubic-bezier(0, 0, 0, 1); }
  49.333333% { transform: translate(140.0125px, 177.5px) scale(1, 1); }
  100% { transform: translate(140.0125px, 177.5px) scale(1, 1); }
}

.layer-small-circle { animation: layer-small-circle-anim 3000ms linear normal forwards; }
@keyframes layer-small-circle-anim {
  0%   { transform: translate(135.0125px, 45px); }
  25%  { transform: translate(135.0125px, 45px); animation-timing-function: cubic-bezier(0, 0, 0, 1); }
  36%  { transform: translate(135.0125px, 60px); }
  100% { transform: translate(135.0125px, 60px); }
}
.layer-small-circle-inner {
  animation: layer-small-circle-inner-anim 3000ms linear normal forwards;
  transform-origin: 0 0;
}
@keyframes layer-small-circle-inner-anim {
  0%   { transform: scale(0, 0); }
  25%  { transform: scale(0, 0); animation-timing-function: cubic-bezier(0, 0, 0, 1); }
  36%  { transform: scale(1, 1); }
  100% { transform: scale(1, 1); }
}

/* The near head is the only piece that overshoots and settles - four damped
   steps between 49% and 68%. It is what stops the build reading as mechanical. */
.layer-medium-circle { animation: layer-medium-circle-anim 3000ms linear normal forwards; }
@keyframes layer-medium-circle-anim {
  0%   { transform: translate(77.5125px, 107.5px); }
  38.333333% { transform: translate(77.5125px, 107.5px); animation-timing-function: cubic-bezier(0, 0, 0, 1); }
  49.333333% { transform: translate(77.5125px, 37.5px);  animation-timing-function: cubic-bezier(0.8, 0, 0.68, 1); }
  57%  { transform: translate(77.5125px, 51.25px); animation-timing-function: cubic-bezier(0.33, 0, 0.67, 1); }
  60%  { transform: translate(77.5125px, 43.75px); animation-timing-function: cubic-bezier(0.33, 0, 0.67, 1); }
  63.333333% { transform: translate(77.5125px, 48.75px); animation-timing-function: cubic-bezier(0.33, 0, 0.67, 1); }
  68%  { transform: translate(77.5125px, 47.5px); }
  100% { transform: translate(77.5125px, 47.5px); }
}
.layer-medium-circle-inner {
  animation: layer-medium-circle-inner-anim 3000ms linear normal forwards;
  transform-origin: 0 0;
}
@keyframes layer-medium-circle-inner-anim {
  0%   { transform: scale(0, 0); }
  38.333333% { transform: scale(0, 0); animation-timing-function: cubic-bezier(0, 0, 0, 1); }
  49.333333% { transform: scale(1, 1); }
  100% { transform: scale(1, 1); }
}

.layer-teams-square {
  animation: layer-teams-square-anim 3000ms linear normal forwards;
  transform-origin: 0 0;
}
@keyframes layer-teams-square-anim {
  0%   { transform: translate(52.5125px, 129.9988px) scale(0.1, 0.1); }
  55%  { transform: translate(52.5125px, 129.9988px) scale(0.1, 0.1); animation-timing-function: cubic-bezier(0, 0, 0, 1); }
  65%  { transform: translate(52.5125px, 129.9988px) scale(1, 1); }
  100% { transform: translate(52.5125px, 129.9988px) scale(1, 1); }
}
.layer-teams-square-inner { animation: layer-teams-square-inner-anim 3000ms linear normal forwards; }
@keyframes layer-teams-square-inner-anim {
  0%   { opacity: 0; }
  55%  { opacity: 0; }
  58.333333% { opacity: 1; }
  100% { opacity: 1; }
}

.layer-t-letter {
  animation: layer-t-letter-anim 3000ms linear normal forwards;
  transform-origin: 0 0;
}
@keyframes layer-t-letter-anim {
  0%   { transform: translate(52.5121px, 129.9988px) scale(0.1, 0.1); }
  55%  { transform: translate(52.5121px, 129.9988px) scale(0.1, 0.1); animation-timing-function: cubic-bezier(0, 0, 0, 1); }
  71.666667% { transform: translate(52.5121px, 129.9988px) scale(1, 1); }
  100% { transform: translate(52.5121px, 129.9988px) scale(1, 1); }
}
.layer-t-letter-inner { animation: layer-t-letter-inner-anim 3000ms linear normal forwards; }
@keyframes layer-t-letter-inner-anim {
  0%   { opacity: 0; }
  55%  { opacity: 0; }
  58.333333% { opacity: 1; }
  100% { opacity: 1; }
}

/* The sweep, clipped to the finished silhouette so the highlight only ever
   travels across the mark and never the background. */
.layer-glint {
  transform: scale(2.5);
  animation: none;
  transform-origin: 0 0;
  clip-path: path('M13.254998,64.9995 c-2.89949,0 -5.25,-2.35051 -5.25,-5.25 v-15.5 c0,-2.85181 2.27383,-5.17254 5.1074,-5.2481 C13.80038,34.4699 17.71068,31 22.43498,31 h13.13 c3.18793,0 6.0052,1.57999 7.71183,4 L57.504998,35 c5.25,0 9.5,4.25 9.5,9.5 v15.72 C67.004998,66.18 62.174998,71 56.224998,71 h-6.14928 c-0.15711,0 -0.31343,-0.00336 -0.46889,-0.01 h-20.44184 c-5.07231,0 -9.59937,-2.33586 -12.5641,-5.9905 h-3.34589 Z M54.004998,33 c4.97,0 9,-4.03 9,-9 s-4.03,-9 -9,-9 s-9,4.03 -9,9 s4.03,9 9,9 Z M31.004998,29 c5.52,0 10,-4.48 10,-10 s-4.48,-10 -10,-10 s-10,4.48 -10,10 s4.48,10 10,10 Z');
}
/* The reference holds the glint at `display: none` until
   `startPulseAnimation()` adds `t2-icon-2025-glint` on a 2000ms timeout, so the
   sweep only starts once the mark is essentially built. A delay reproduces that
   without the class dance.

   `both`, not `forwards`: with `forwards` the pre-delay hold is the
   untransformed rect, which parks a static wash over the mark's upper-left for
   two seconds. The 0% keyframe holds it entirely off the silhouette. */
.layer-glint-animated {
  animation: layer-glint-anim 2500ms linear 2000ms infinite normal both;
  transform-origin: 0 0;
}
@keyframes layer-glint-anim {
  0%   { transform: translate(-48.004998px, -49px); }
  20%  { transform: translate(-48.004998px, -49px); }
  80%  { transform: translate(111.995002px, 111px); }
  100% { transform: translate(111.995002px, 111px); }
}

/* ---- caption ---- */

/* `.text-slider` in the reference: 1.8rem/2.4rem semibold, and its own muted
   grey rather than the body foreground. It arrives after the mark has started
   building, not with it. */
.splash__text {
  margin: 0.8rem 0 0;
  font-size: 1.8rem;
  line-height: 2.4rem;
  font-weight: var(--fontWeightSemibold);
  color: var(--colorNeutralForeground2);
  text-align: center;
  padding: 0 var(--spacingHorizontalL);
  animation: splash-caption 500ms cubic-bezier(0.33, 0, 0.1, 1) 900ms both;
}
@keyframes splash-caption {
  from { opacity: 0; transform: translateY(0.8rem); }
  to   { opacity: 1; transform: translateY(0); }
}
@media only screen and (max-height: 768px) { .splash__text { font-size: 1.6rem; } }
@media only screen and (max-height: 480px) { .splash__text { font-size: 1.4rem; } }

/* Reduced motion is not a reason to show a dead screen - this is a wait, and
   an indicator that never moves is indistinguishable from a hang. The build
   and the travelling glint go; a slow opacity pulse stays. Windows reports
   this preference for an entire Remote Desktop session regardless of the
   user's setting, so this branch is what anyone on RDP sees. */
@media (prefers-reduced-motion: reduce) {
  .splash__mark .logo-layer,
  .splash__mark .logo-layer > div {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
  }
  .layer-glint { display: none; }
  .splash__mark { animation: splash-pulse 1800ms ease-in-out infinite; }
  @keyframes splash-pulse {
    0%, 100% { opacity: 0.85; }
    50%      { opacity: 1; }
  }
  .splash__text { animation: splash-fade-in 200ms ease 100ms both; }
  @keyframes splash-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
  }
}
