Stimeo UI ships behavior, not CSS. Two things about styling it come up often enough to be worth saying up front: how controllers hide things, and where the words that change with a state belong.
Controllers hide with hidden
A controller shows and hides the regions you declare to it — a listbox option filtered out, the "no matches" row, the half of a label that does not belong to the current state. It does that with the hidden attribute, because showing and hiding is behavior rather than appearance.
hidden gets display: none from the browser's own stylesheet, which is the weakest source there is. Any rule of yours that sets display wins over it, and the element stays on screen.
This is most likely to bite with a utility-first framework. Tailwind v4 declares its layers in the order theme, base, components, utilities, and DaisyUI puts component classes such as .menu li, .tabs, and .steps in the last one. A hidden element inside one of those stays visible — and a display: none you add in @layer components still loses, because it sits in an earlier layer.
Put the override outside every layer. Unlayered rules beat layered ones, so you do not need !important:
/* Not inside @layer — that is the point. */
.menu li[hidden],
.menu [role="option"][hidden] {
display: none;
}
You are most likely to meet this with combobox, listbox, multi-select, empty-state, filter, and command-palette, whose options and empty rows are the ones being hidden.
Words that change with a state belong in your markup
When a state flips a label, it is tempting to put the words in CSS:
/* Please don't. */
.play::after { content: "Auto-advance: off"; }
.play[aria-pressed="true"]::after { content: "Auto-advance: on"; }
Two things go wrong. Text inside content never reaches a translation catalogue, so it stays in one language forever. And the usual way to find untranslated strings is to scan the rendered HTML, where this text does not appear at all — so the check comes back clean while the page is still wrong.
content: attr(aria-valuetext) fails the same way from the other end: the controller composes that attribute at runtime in its own default language.
Keep the words in your markup and let the controller show the half that applies. Components that swap a label accept the two halves as targets:
<button data-stimeo--read-more-target="trigger" aria-expanded="false">
<span data-stimeo--read-more-target="collapsedLabel">Read more</span>
<span data-stimeo--read-more-target="expandedLabel" hidden>Show less</span>
</button>
The controller writes hidden on the half that does not apply, so your CSS has nothing to do. Write the initial state's hidden yourself as above; it avoids a flash before the controller connects, and the controller corrects it either way.
For a toggle button (aria-pressed), keep the accessible name the same in both states — that is what the pattern expects — and use the label pair for the icon or glyph that changes.
For a value a controller reads out, pass the wording in instead of composing it in CSS: color-picker takes data-value-text, and the announcing controllers take announce-*-text.