/* Copyright 2026 Element Creations Ltd. SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ .container { display: flex; flex-direction: row; align-items: center; background-color: var(--cpd-color-bg-subtle-secondary); border-radius: 32px; transition: background-color 0.2s ease-in-out; } .containerOpen { background-color: var(--cpd-color-bg-action-primary-pressed); } .chevronIconOpen > svg { color: var(--cpd-color-icon-on-solid-primary); } .menuButton { width: 40px; background-color: transparent !important; } .itemIcon { color: var(--cpd-color-text-secondary); } .rotate { animation: spinner 1.5s linear infinite; } @keyframes spinner { to { transform: rotate(360deg); } } .menu { display: flex; flex-direction: column; } /* Compound underlines every menu heading. The design has a single line, the one dividing the speaker list from the microphone list, so the headings carry none and that divider is drawn explicitly. */ .menu h3 { border-block-end: none; padding-block-end: var(--cpd-space-2x); } /* The menu zeroes separator spacing, but the design gives the heading below the divider room to breathe. */ .menu [role="separator"] { margin-block-end: var(--cpd-space-5x); } /* Only the device lists scroll; the level meter stays put beneath them. The bound comes from the measured height of the call area, set by the component: the menu is portalled outside the root, so neither a container query nor a viewport unit describes the space it is allowed to fill. */ .deviceList { overflow-y: auto; min-block-size: 0; max-block-size: var(--device-list-max-height); /* The heading stands over the head of this list and the level meter over its foot. Scrolling a row flush to either edge would put it underneath one of them, which is how a row reached by the keyboard ends up half-readable; this keeps both their heights clear for anything the browser scrolls to. Set by the component, which is the only thing that can measure them. */ scroll-padding-block: var(--device-list-scroll-padding-start, 0) var(--device-list-scroll-padding-end, 0); } /* Each section's heading stays at the top of the scrollport while any of that section is still in view, so a long list never leaves you wondering which kind of device you are looking at. It leaves with its own section, because sticky only holds while the group it belongs to is in view. Opaque, and held a border width clear of the sides, for the same reason as the meter below: this is a positioned element, so it paints above the outline the menu draws its frame with, and would swallow it. */ .sectionHeading { position: sticky; inset-block-start: 0; background: var(--cpd-color-bg-canvas-default); margin-inline: var(--cpd-border-width-1); margin-block-start: var(--cpd-border-width-1); } /* The meter belongs to the microphone section: it stays at the bottom of the scrollport while that section is in view, and leaves with it when the list is scrolled up to the speakers. The wrapper is deliberately unpositioned — a positioned one paints above the menu's outline and swallows the frame along this whole section. Sticky is resolved against the scroll container, so it does not need one. */ .stickyMeter { position: sticky; inset-block-end: 0; /* Opaque, so the list does not show through it as it scrolls past. The menu draws its frame as an outline inset by one border width, and the device rows are transparent at rest, so this is the only thing that can cover it: hold it clear on the sides and the bottom. */ background: var(--cpd-color-bg-canvas-default); margin-inline: var(--cpd-border-width-1); margin-block-end: var(--cpd-border-width-1); } /* Radix focuses whatever the pointer is over, so the browser's own ring marks the item under the mouse. It cannot distinguish the two modalities here, so it is suppressed and replaced by one that can. Every kind of item the menu can focus, not only the device rows: the camera menu's blur toggle is a checkbox item and a child of the menu rather than of the list, and left out it kept the browser's own ring and followed the pointer with it. */ .menu [role^="menuitem"]:focus, .menu [role^="menuitem"]:focus-visible { outline: none; } /* Shown only when the keyboard is what moved the focus. */ .menu[data-focus-modality="keyboard"] [role^="menuitem"]:focus { outline: var(--cpd-border-width-2) solid var(--cpd-color-border-focused); outline-offset: calc(-1 * var(--cpd-border-width-2)); }