CSS Framework Reference

Complete reference for the CSS framework powering ChatStyle chat overlays. For expert mode users writing custom CSS and HTML templates/skins.

How It Works

ChatStyle uses a three-layer system to style chat bubbles in the overlay:

  1. CSS Variables — named --cs-{element}-{property}, control all visual properties (colors, sizes, fonts, animations)
  2. HTML Template — defines the DOM structure with .cs-* class names and placeholder slots for chat data
  3. Framework CSS — binds variables to CSS properties with neutral defaults and provides structural toggle classes
Note: All framework defaults are neutral (0px padding, transparent backgrounds, no borders). Styles become visible through the settings values configured in the designer or via the API.

HTML Template Contract

Every chat bubble follows a defined HTML structure with required CSS classes and placeholder slots. The framework CSS targets these classes to apply styling.

Example Structure

HTML
<div class="cs-bubble">
    <div class="cs-avatar">{{avatar}}</div>
    <div class="cs-user" style="--cs-usercolor: {{usercolor}};">
        <span class="cs-badges">{{badges}}</span>
        <span class="cs-username">{{username}}</span>
        <span class="cs-pronouns">{{pronouns}}</span>
    </div>
    <div class="cs-content">
        <span class="cs-user--inline">
            <span class="cs-badges cs-badges--inline">{{badges}}</span>
            <span class="cs-username--inline" style="--cs-usercolor: {{usercolor}};">{{username}}</span>
            <span class="cs-pronouns cs-pronouns--inline">{{pronouns}}</span>
        </span>
        <div class="cs-message">{{message}}</div>
    </div>
</div>

Placeholders

PlaceholderReplaced With
{{avatar}}<img> tag with the user's profile picture, or empty string
{{badges}}<img> tags for Twitch badges (subscriber, mod, VIP, etc.), or empty string
{{timestamp}}Formatted local time string from the overlay browser (for example 12:34 or 12:34:56)
{{pronouns}}Optional chatter pronouns string resolved in the overlay browser (for example she/her), or empty string
{{broadcaster}}Broadcaster channel login for current overlay (for example propz_tv)
{{username}}The chatter's display name
{{usercolor}}Hex color string from Twitch (e.g. #ff4500)
{{message}}Message HTML containing text, emote images, and Twitch GIF images

Required CSS Classes

ClassElementPurpose
.cs-bubbleOuter containerRoot element, receives toggle and position classes
.cs-avatarAvatar containerContains the user's profile image
.cs-userHeader rowUsername header above the message (badges + username)
.cs-badgesBadges containerContains Twitch badge images
.cs-usernameUsername textDisplay name text inside the header row
.cs-pronounsPronouns textOptional pronouns element; hidden when empty or when pronoun visibility is off
.cs-contentContent wrapperContains the message area and inline username
.cs-user--inlineInline headerInline username + badges wrapper, shown when username position is inline
.cs-username--inlineInline usernameUsername text when displayed inline with the message
.cs-pronouns--inlineInline pronounsOptional inline pronouns copy, hidden with the standard pronouns element
.cs-messageMessage textContains the chat message text and emotes
Note: .cs-user is the header-style username (above the message). .cs-user--inline is the inline variant (displayed on the same line as the message). The framework toggles between them using the cs-username-position-inline class.

Twitch GIF images use .cs-gif inside the message. They preserve their aspect ratio without upscaling, with a maximum height of 140px and a maximum width of the available bubble width. The global Show GIFs setting controls new messages; disabled or failed GIFs show their description text.

Bubble Modifier Classes

The overlay and previews add public modifier classes to .cs-bubble for platform, sender roles, Twitch Turbo status, and emote-only messages. Use these hooks for platform-specific, role-specific, or message-specific styling.

ClassApplied When
.cs-twitchMessage is from Twitch, or platform is missing/unknown
.cs-kickMessage is from Kick
.cs-youtubeMessage is from YouTube
.cs-broadcasterSender has the broadcaster badge
.cs-modSender is a moderator
.cs-vipSender is a VIP
.cs-subSender is a subscriber
.cs-turboSender has Twitch Turbo enabled for this message
.cs-sub-tier-1Sender's subscription tier is known as Tier 1 (data-cs-sub-tier="1000")
.cs-sub-tier-2Sender's subscription tier is known as Tier 2 (data-cs-sub-tier="2000")
.cs-sub-tier-3Sender's subscription tier is known as Tier 3 (data-cs-sub-tier="3000")
.cs-oddFirst bubble rendered by the overlay, then every other bubble after that
.cs-evenSecond bubble rendered by the overlay, then every other bubble after that
.cs-follow-upSender matches the previous rendered overlay message; the first message in a sequence does not receive this class
.cs-twitch-gifMessage displays at least one Twitch GIF; GIFs do not count as emotes
.cs-emote-onlyMessage contains only emotes and whitespace
.cs-ends-bangDisplayed message text ends with !
.cs-ends-questionDisplayed message text ends with ?
.cs-ends-bang-questionDisplayed message text ends with !?
.cs-ends-question-bangDisplayed message text ends with ?!

Known subscriber tenure is exposed as data-cs-sub-months="N" on .cs-bubble. Missing data-cs-sub-months or data-cs-sub-tier means unknown or not subscribed.

CSS Variables Reference

All CSS variables follow the naming pattern --cs-{element}-{property}. The framework binds these variables to actual CSS properties with neutral defaults (0px, transparent, none). Styles override these defaults through settings values.

Variable Scoping

All CSS variables are set as inline styles on .cs-bubble — not on their respective elements. Variables like --cs-avatar-size, --cs-username-font-size, and --cs-message-font-color all live on the bubble root element. Child elements (.cs-avatar img, .cs-user, .cs-message) consume these variables via CSS inheritance.

Container-scoped variables live on .cs-chat instead. Today that includes --cs-bubble-gap (spacing between bubbles) and --cs-chat-padding* (inner spacing around the whole chat stack).

Expert mode tip: When overriding variables in expert CSS, target .cs-bubble to match how the system applies them. For example, .cs-bubble { --cs-message-font-size: 20px; } is the correct approach. Setting variables on child elements also works (via inheritance), but .cs-bubble is the canonical scope.

Helper Color Tokens

The framework exposes shared Twitch color constants on .cs-chat. They are inherited into every bubble, useful with role modifier classes such as .cs-sub, .cs-mod, .cs-vip, and .cs-broadcaster, and are not customizer-managed settings.

VariableDefaultDescription
--cs-color-twitch#9146ffTwitch brand purple helper color
--cs-color-twitch-subscriber#8205b4Subscriber role helper color for .cs-sub styles
--cs-color-twitch-moderator#05af08Moderator role helper color for .cs-mod styles
--cs-color-twitch-vip#e006b9VIP role helper color for .cs-vip styles
--cs-color-twitch-broadcaster#e91916Broadcaster role helper color for .cs-broadcaster styles

Pronoun Vars

The framework reads these plain CSS variables for pronoun elements. They are not part of the customizer registry, but styles and skins may override them.

VariableDefaultDescription
--cs-pronouns-font-colorinheritOptional text color hook for the pronoun chip, overridden from expert CSS or skin CSS
--cs-pronouns-background-colortransparentOptional background hook for the pronoun chip, overridden from expert CSS or skin CSS
Note: Pronoun visibility is separate from these colors. The pronouns.show structural setting adds .cs-pronouns-hidden, which hides both .cs-pronouns and .cs-pronouns--inline.

Chat Container (--cs-chat-*)

The chat stack container. These variables affect the whole message column, not an individual bubble. In the designer, this control is shown as Space Inside Chat Area.

Spacing

VariableDefaultDescription
--cs-chat-padding0pxUniform inner spacing around the full chat container
--cs-chat-padding-topvar(--cs-chat-padding)Top inner spacing (when advanced spacing is on)
--cs-chat-padding-rightvar(--cs-chat-padding)Right inner spacing (when advanced spacing is on)
--cs-chat-padding-bottomvar(--cs-chat-padding)Bottom inner spacing (when advanced spacing is on)
--cs-chat-padding-leftvar(--cs-chat-padding)Left inner spacing (when advanced spacing is on)

Bubble (--cs-bubble-*)

The main chat bubble container. Controls overall bubble appearance including padding, background, border, shadow, animation, width, and gap between bubbles.

Spacing

VariableDefaultDescription
--cs-bubble-padding0pxUniform inner padding (all sides)
--cs-bubble-padding-topvar(--cs-bubble-padding)Top padding (when advanced padding is on)
--cs-bubble-padding-rightvar(--cs-bubble-padding)Right padding (when advanced padding is on)
--cs-bubble-padding-bottomvar(--cs-bubble-padding)Bottom padding (when advanced padding is on)
--cs-bubble-padding-leftvar(--cs-bubble-padding)Left padding (when advanced padding is on)
--cs-bubble-gap10pxGap between chat bubbles
--cs-bubble-width400pxMaximum bubble width

Background

VariableDefaultDescription
--cs-bubble-background-colortransparentBackground color
--cs-bubble-background-gradientnoneComplete CSS gradient used as background-image

Border

VariableDefaultDescription
--cs-bubble-border-width0pxBorder width
--cs-bubble-border-stylesolidBorder line style
--cs-bubble-border-colortransparentBorder color
--cs-bubble-border-radius0pxUniform border radius (all corners)
--cs-bubble-border-radius-top-leftvar(--cs-bubble-border-radius)Top-left corner radius
--cs-bubble-border-radius-top-rightvar(--cs-bubble-border-radius)Top-right corner radius
--cs-bubble-border-radius-bottom-rightvar(--cs-bubble-border-radius)Bottom-right corner radius
--cs-bubble-border-radius-bottom-leftvar(--cs-bubble-border-radius)Bottom-left corner radius

Shadow

VariableDefaultDescription
--cs-bubble-box-shadow-offset-x0pxHorizontal shadow offset
--cs-bubble-box-shadow-offset-y0pxVertical shadow offset
--cs-bubble-box-shadow-blur-radius0pxShadow blur radius
--cs-bubble-box-shadow-spread-radius0pxShadow spread radius
--cs-bubble-box-shadow-colortransparentShadow color
--cs-bubble-box-shadow-insetInset shadow toggle (empty = outset, inset = inset)

Animation

VariableDefaultDescription
--cs-bubble-animationbp-slide-in-upEntrance animation keyframe name
--cs-bubble-animation-duration750msAnimation duration
--cs-bubble-animation-delay0msDelay before animation starts
--cs-bubble-animation-timing-functionease-outAnimation timing function

Avatar (--cs-avatar-*)

The user's profile image. Applied to the img element inside .cs-avatar. Has the same box properties (padding, background, border, shadow) plus a size property.

VariableDefaultDescription
--cs-avatar-size60pxAvatar width and height
--cs-avatar-padding0pxUniform inner padding
--cs-avatar-background-colortransparentBackground color
--cs-avatar-background-gradientnoneComplete CSS gradient used as background-image
--cs-avatar-border-width0pxBorder width
--cs-avatar-border-stylesolidBorder style
--cs-avatar-border-colortransparentBorder color
--cs-avatar-border-radius0pxBorder radius
--cs-avatar-box-shadow-offset-x0pxHorizontal shadow offset
--cs-avatar-box-shadow-offset-y0pxVertical shadow offset
--cs-avatar-box-shadow-blur-radius0pxShadow blur
--cs-avatar-box-shadow-spread-radius0pxShadow spread
--cs-avatar-box-shadow-colortransparentShadow color
--cs-avatar-animationnoneEntrance animation
--cs-avatar-animation-duration750msAnimation duration
--cs-avatar-animation-delay0msAnimation delay
--cs-avatar-animation-timing-functionease-outAnimation easing

Username (--cs-username-*)

The username text in the header row. Controls font properties, text effects, and has the same box properties (padding, background, border, shadow) as the bubble.

Typography

VariableDefaultDescription
--cs-username-font-family'Space Grotesk'Font family
--cs-username-font-size16pxFont size
--cs-username-font-weight700Font weight
--cs-username-font-colorvar(--cs-usercolor, #ffffff)Text color (defaults to chatter's Twitch color)
--cs-username-text-stroke-width0pxText stroke (outline) width
--cs-username-text-stroke-color#000000Text stroke color
--cs-username-text-shadow-offset-x0pxHorizontal text shadow offset
--cs-username-text-shadow-offset-y0pxVertical text shadow offset
--cs-username-text-shadow-blur-radius0pxText shadow blur
--cs-username-text-shadow-colortransparentText shadow color

Box Properties

The username element also supports padding, background, border, border-radius, box-shadow, and animation — following the same variable pattern as the bubble element (--cs-username-padding, --cs-username-background-color, etc.).

Message (--cs-message-*)

The chat message text. Controls font appearance and has the same box properties as the username element.

Typography

VariableDefaultDescription
--cs-message-font-family'Inter'Font family
--cs-message-font-size16pxFont size
--cs-message-font-weight400Font weight
--cs-message-font-color#ffffffText color
--cs-message-text-stroke-width0pxText stroke width
--cs-message-text-stroke-color#000000Text stroke color
--cs-message-text-shadow-offset-x0pxHorizontal text shadow
--cs-message-text-shadow-offset-y0pxVertical text shadow
--cs-message-text-shadow-blur-radius0pxText shadow blur
--cs-message-text-shadow-colortransparentText shadow color

Box Properties

The message element also supports padding, background, border, border-radius, box-shadow, and animation — following the same variable pattern as the bubble element (--cs-message-padding, --cs-message-background-color, etc.).

Events (--cs-events-*)

The events section inside a bubble (e.g. sub gifts, raids). Controls entrance animation independently from the bubble animation.

VariableDefaultDescription
--cs-events-animationnoneEntrance animation keyframe name
--cs-events-animation-duration750msAnimation duration

Structural Toggle Classes

These CSS classes are applied to bubble or container elements based on structural settings. They control layout, visibility, and positioning without CSS variables.

Position Classes

ClassApplied ToEffect
.cs-avatar-position-left.cs-bubblePosition avatar at start (left in LTR)
.cs-avatar-position-center.cs-bubblePosition avatar at center
.cs-avatar-position-right.cs-bubblePosition avatar at end (right in LTR)
.cs-username-position-inline.cs-bubbleSwitch from header username to inline (same line as message)
.cs-badges-position-after-name.cs-bubbleMove badges after the username (CSS order: 1)
.cs-direction-rtl.cs-bubbleSet text direction to right-to-left

Visibility Classes

ClassApplied ToEffect
.cs-avatar-hidden.cs-bubbleHide the avatar element
.cs-badges-hidden.cs-bubbleHide all badge images
.cs-pronouns-hidden.cs-bubbleHide both .cs-pronouns and .cs-pronouns--inline
.cs-events-hidden.cs-bubbleHide the events element

Container Classes

ClassApplied ToEffect
.cs-full-width.cs-chatBubbles stretch to 100% width with no max-width
.cs-chat--bottom-up.cs-chatFlow messages upward from the bottom
.cs-chat--top-down.cs-chatFlow messages downward from the top
.cs-chat--left-to-right.cs-chatFlow messages horizontally left to right
.cs-chat--right-to-left.cs-chatFlow messages horizontally right to left
.cs-chat--horizontal.cs-chatAdded with left-to-right and right-to-left flows for shared horizontal layout rules
.cs-align-left.cs-chatAlign bubbles to the start
.cs-align-center.cs-chatAlign bubbles to center
.cs-align-right.cs-chatAlign bubbles to the end
.cs-align-top.cs-chatAlign bubbles to the top (for horizontal message directions)
.cs-align-bottom.cs-chatAlign bubbles to the bottom (for horizontal message directions)

Event Classes

When a chat message is an event (not a regular chat message), event classes are added to .cs-bubble: the shared .cs-event marker and one or more specific .cs-event-* classes for the event type or provider. Use these to style events independently.

ClassSourceDescription
.cs-eventAll eventsPresent on every event bubble — use as a shared event hook
PRIVMSG events
.cs-event-action/me messageItalic action message (/me does a thing)
.cs-event-cheerBits cheerMessage containing a Bits cheer
.cs-event-highlightChannel PointsHighlighted message redeemed with Channel Points
.cs-event-channel-pointsChannel PointsMessage sent with a channel points reward (skip subs mode)
.cs-event-announcementAnnouncementModerator announcement
.cs-event-gigantifiedChannel PointsGigantified emote message
USERNOTICE events (rendered as system message bubbles)
.cs-event-subUSERNOTICENew subscriber
.cs-event-resubUSERNOTICEResubscriber (may include a personal message)
.cs-event-subgiftUSERNOTICEGifted subscription to another viewer
.cs-event-mystery-giftUSERNOTICEMystery gift sub (random recipient)
.cs-event-gift-upgradeUSERNOTICEViewer upgraded a gifted sub to paid
.cs-event-reward-giftUSERNOTICEReward gift event
.cs-event-anon-gift-upgradeUSERNOTICEViewer upgraded an anonymous gifted sub to paid
.cs-event-raidUSERNOTICEIncoming raid from another channel
.cs-event-unraidUSERNOTICERaid was cancelled
.cs-event-bits-badgeUSERNOTICEViewer unlocked a Bits badge tier
.cs-event-shared-chatUSERNOTICEShared chat notice
External webhook events
.cs-event-externalWebhookProvider-neutral hook for all external webhook events
.cs-event-kofiKo-fi webhookProvider-specific hook. Future services use .cs-event-{provider}.
Usage example:
.cs-bubble.cs-event-raid { background: gold; } — style only raid bubbles.
.cs-bubble.cs-event { opacity: 0.8; } — dim all event bubbles uniformly.

Font Modifier Classes

ClassEffect
.cs-username-italicApply font-style: italic to username
.cs-username-underlineApply text-decoration: underline to username
.cs-username-uppercaseApply text-transform: uppercase to username
.cs-username-lowercaseApply text-transform: lowercase to username
.cs-username-capitalizeApply text-transform: capitalize to username
.cs-username-align-centerApply text-align: center to username
.cs-username-align-endApply text-align: end to username
.cs-message-italicApply font-style: italic to message
.cs-message-underlineApply text-decoration: underline to message
.cs-message-uppercaseApply text-transform: uppercase to message
.cs-message-lowercaseApply text-transform: lowercase to message
.cs-message-capitalizeApply text-transform: capitalize to message
.cs-message-align-centerApply text-align: center to message
.cs-message-align-endApply text-align: end to message
Note: Font modifier classes are generated from structural settings, not CSS variables. Start text alignment is the default and does not emit a class.

Animations

Entrance animations control how chat bubbles appear in the overlay. Each element (bubble, avatar, username, message) can have its own entrance animation.

Note: Animation names are stored without prefix in settings (e.g. slide-in-up) but compiled with a bp- prefix for CSS (e.g. bp-slide-in-up). Use the bp- prefixed name when referencing animations in custom CSS.
Setting ValueCSS @keyframes Name
nonenone
fade-inbp-fade-in
fade-in-upbp-fade-in-up
fade-in-downbp-fade-in-down
fade-in-leftbp-fade-in-left
fade-in-rightbp-fade-in-right
slide-in-upbp-slide-in-up
slide-in-downbp-slide-in-down
slide-in-leftbp-slide-in-left
slide-in-rightbp-slide-in-right
bounce-inbp-bounce-in
bounce-in-upbp-bounce-in-up
bounce-in-downbp-bounce-in-down
zoom-inbp-zoom-in
zoom-in-upbp-zoom-in-up
flip-in-xbp-flip-in-x
flip-in-ybp-flip-in-y
rotate-inbp-rotate-in
jack-in-the-boxbp-jack-in-the-box
roll-inbp-roll-in
light-speed-in-rightbp-light-speed-in-right

Special Values

User Color (--cs-usercolor)

The special value __usercolor__ can be used in any color property. It compiles to var(--cs-usercolor), which resolves to each chatter's Twitch chat color at render time. The --cs-usercolor variable is set per-bubble via inline style on the .cs-user element. The username font color defaults to this value.

CSS
.cs-username {
    color: var(--cs-usercolor, #ffffff);
}

Gradient Values

The background-gradient setting stores a complete normalized CSS gradient string. Supported families are linear-gradient(...), radial-gradient(...), and conic-gradient(...).

Advanced Toggles

These designer-only toggles control how CSS variables are emitted. They are not CSS variables themselves:

  • border-radius-advanced — When OFF, uniform --cs-{el}-border-radius synced to all corners. When ON, individual per-corner radius values.
  • padding-advanced — When OFF, uniform --cs-{el}-padding synced to all sides. When ON, individual per-side padding values.

Expert Mode CSS

Expert Mode lets you write custom CSS targeting any element in the chat bubble DOM. Your CSS loads after the framework and style template, so it can override any property.

Targeting Elements

Target any .cs-* class and their children. You can also use CSS custom properties (var()) and reference the --cs-usercolor variable for the chatter's Twitch color.

CSS
.cs-bubble {
    background: linear-gradient(135deg, #1a0030, #2a0050);
    border: 2px solid #ff00aa;
    border-radius: 12px;
}

.cs-message {
    font-size: 18px;
    color: #ffccee;
    text-shadow: 0 0 8px rgba(255, 0, 170, 0.5);
}

.cs-username {
    color: var(--cs-usercolor);
    font-weight: 900;
    text-transform: uppercase;
}

Restrictions

Maximum 10,000 characters. CSS comments are stripped during sanitization. Premium streamer and admin expert CSS may load trusted font stylesheets with @import url("https://fonts.googleapis.com/css2?...");, @import "https://fonts.googleapis.com/css2?...";, or @import url("https://fonts.cdnfonts.com/css/...");. All other imports are blocked.

BlockedReason
@importOnly strict Google Fonts /css2 and CDNFonts /css/... imports are allowed for premium/admin expert CSS
@font-faceUser-defined font files are blocked; use trusted font @import instead
@charsetEncoding interference
url()Controlado por política; contextos estritos bloqueiam o carregamento de URL; contextos especializados premium permitem imagens auto-hospedadas, URLs de imagem i.ibb.co e URLs de dados SVG higienizados não base64
data:image/*;base64Raster data images and base64 SVG data URLs are blocked. Use ImgBB direct CDN URLs from i.ibb.co for external images.
expression()Legacy IE JavaScript execution
javascript:Script injection prevention
-moz-bindingXUL binding attack prevention
behavior:IE HTC component attack prevention

What's Allowed

  • All standard CSS properties (color, background, border, etc.)
  • CSS animations and transitions
  • CSS transforms (translate, rotate, scale, etc.)
  • CSS custom properties (var(--my-prop))
  • @keyframes definitions
  • @media queries
  • Premium/admin only: image URLs from ChatStyle domains or direct ImgBB CDN URLs on i.ibb.co. Use imgbb.com to upload, then copy the direct i.ibb.co image URL.

Expert Mode HTML

Expert Mode also lets you customize the HTML structure of chat bubbles. You can rearrange elements, add wrapper divs, or create entirely new layouts.

Requirements

  • Template must contain an element with the cs-bubble class
  • Must include the core placeholders your layout depends on: {{username}}, {{message}}, {{badges}}, {{avatar}}, {{usercolor}}
  • Optional placeholders: {{timestamp}}, {{pronouns}}, {{broadcaster}}
  • Maximum 10,000 characters

Blocked Elements

BlockedReason
<script>, <style>, <iframe>, <object>Script execution and embedding prevention
<svg>, <math>, <template>Complex embedded content prevention
<form>, <link>, <embed>, <base>External resource and form injection prevention
on* attributesJavaScript event handler prevention
javascript:, vbscript:, data:Dangerous protocol prevention

Framework CSS

The complete framework.css file that provides structural layout, CSS variable bindings, and toggle classes. This file is loaded before each style's CSS template.

CSS
/* ==========================================================
   ChatStyle — Framework CSS
   https://chatstyle.gg

   Loaded before each style's CSS template. Provides structural
   layout, animation defaults, toggle classes, and ALL standard
   CSS variable bindings for system elements.

   All defaults are neutral/zero (0px, transparent, no shadow).
   Styles become visible through settings_values overrides.
   ========================================================== */

/*  ====================
    Chat Container
    ==================== */

.cs-chat {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    flex: 1;
    gap: var(--cs-bubble-gap, 10px);
    inline-size: 100%;
    /* Needed for proper chat flow */
    overflow: hidden;
    /* Safe area for shadows */
    padding-block-start: var(--cs-chat-padding-top, var(--cs-chat-padding, 0px));
    padding-block-end: var(--cs-chat-padding-bottom, var(--cs-chat-padding, 0px));
    padding-inline-start: var(--cs-chat-padding-left, var(--cs-chat-padding, 0px));
    padding-inline-end: var(--cs-chat-padding-right, var(--cs-chat-padding, 0px));

    /* Twitch helper colors */
    --cs-color-twitch: #9146ff;
    --cs-color-twitch-subscriber: #8205b4;
    --cs-color-twitch-moderator: #05af08;
    --cs-color-twitch-vip: #e006b9;
    --cs-color-twitch-broadcaster: #e91916;
}

/* Chat Flow */
.cs-chat.cs-chat--bottom-up {
    justify-content: flex-end;
}

.cs-chat.cs-chat--top-down {
    justify-content: flex-start;
}

.cs-chat.cs-chat--left-to-right {
    flex-direction: row-reverse;
    flex-wrap: nowrap;
    justify-content: flex-end;
    align-items: flex-end;
}

.cs-chat.cs-chat--right-to-left {
    flex-direction: row;
    flex-wrap: nowrap;
    justify-content: flex-end;
    align-items: flex-end;
}

.cs-chat.cs-chat--horizontal > * {
    flex-shrink: 0;
    max-inline-size: 300px;
    margin-block-start: 0;
    margin-inline-start: var(--cs-bubble-gap, 20px);
}

/*  ====================
    Bubble Base
    ==================== */

.cs-bubble {
    position: relative;
    display: flex;
    flex-direction: column;
    line-height: 1.5;
    color: #fff;
    max-inline-size: var(--cs-bubble-width, 400px);
    /* We need this, so bubbles never shrink. Super mega weird conflict with overflow:hidden on .cs-bubble element */
    flex-shrink: 0;
    paint-order: stroke fill;

    padding-block-start: var(--cs-bubble-padding-top, var(--cs-bubble-padding, 0px));
    padding-inline-end: var(--cs-bubble-padding-right, var(--cs-bubble-padding, 0px));
    padding-block-end: var(--cs-bubble-padding-bottom, var(--cs-bubble-padding, 0px));
    padding-inline-start: var(--cs-bubble-padding-left, var(--cs-bubble-padding, 0px));

    background-color: var(--cs-bubble-background-color, transparent);
    background-image: var(--cs-bubble-background-gradient, none);
    background-repeat: no-repeat;

    border-width: var(--cs-bubble-border-width, 0px);
    border-style: var(--cs-bubble-border-style, solid);
    border-color: var(--cs-bubble-border-color, transparent);

    border-start-start-radius: var(--cs-bubble-border-radius-top-left, var(--cs-bubble-border-radius, 0px));
    border-start-end-radius: var(--cs-bubble-border-radius-top-right, var(--cs-bubble-border-radius, 0px));
    border-end-end-radius: var(--cs-bubble-border-radius-bottom-right, var(--cs-bubble-border-radius, 0px));
    border-end-start-radius: var(--cs-bubble-border-radius-bottom-left, var(--cs-bubble-border-radius, 0px));

    box-shadow: var(--cs-bubble-box-shadow-inset,) var(--cs-bubble-box-shadow-offset-x, 0px) var(--cs-bubble-box-shadow-offset-y, 0px) var(--cs-bubble-box-shadow-blur-radius, 0px) var(--cs-bubble-box-shadow-spread-radius, 0px) var(--cs-bubble-box-shadow-color, transparent);

    /* Animation */
    animation-name: var(--cs-bubble-animation, bp-slide-in-up);
    animation-duration: var(--cs-bubble-animation-duration, 750ms);
    animation-delay: var(--cs-bubble-animation-delay, 0ms);
    animation-timing-function: var(--cs-bubble-animation-timing-function, ease-out);
    animation-fill-mode: both;
}

/* Full Width */
.cs-chat.cs-full-width {
    align-items: stretch !important;
}

.cs-chat.cs-full-width .cs-bubble {
    inline-size: 100%;
    max-inline-size: none;
}

/* Direction */
.cs-bubble.cs-direction-rtl {
    direction: rtl;
}

/* Alignment (applied to .cs-chat container) */
.cs-chat.cs-align-left {
    align-items: flex-start !important;
}

.cs-chat.cs-align-center {
    align-items: center !important;
}

.cs-chat.cs-align-right {
    align-items: flex-end !important;
}

.cs-chat.cs-align-top {
    align-items: flex-start !important;
}

.cs-chat.cs-align-bottom {
    align-items: flex-end !important;
}

/*  ====================
    Avatar
    ==================== */

.cs-avatar {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    position: relative;
    z-index: 1;

    &:empty {
        display: none;
    }

    img {
        inline-size: var(--cs-avatar-size, 60px);
        block-size: var(--cs-avatar-size, 60px);
        object-fit: cover;

        /* Box Properties */
        padding-block-start: var(--cs-avatar-padding-top, var(--cs-avatar-padding, 0px));
        padding-inline-end: var(--cs-avatar-padding-right, var(--cs-avatar-padding, 0px));
        padding-block-end: var(--cs-avatar-padding-bottom, var(--cs-avatar-padding, 0px));
        padding-inline-start: var(--cs-avatar-padding-left, var(--cs-avatar-padding, 0px));

        background-color: var(--cs-avatar-background-color, transparent);
        background-image: var(--cs-avatar-background-gradient, none);
        background-repeat: no-repeat;

        border-width: var(--cs-avatar-border-width, 0px);
        border-style: var(--cs-avatar-border-style, solid);
        border-color: var(--cs-avatar-border-color, transparent);

        border-start-start-radius: var(--cs-avatar-border-radius-top-left, var(--cs-avatar-border-radius, 0px));
        border-start-end-radius: var(--cs-avatar-border-radius-top-right, var(--cs-avatar-border-radius, 0px));
        border-end-end-radius: var(--cs-avatar-border-radius-bottom-right, var(--cs-avatar-border-radius, 0px));
        border-end-start-radius: var(--cs-avatar-border-radius-bottom-left, var(--cs-avatar-border-radius, 0px));

        box-shadow: var(--cs-avatar-box-shadow-inset,) var(--cs-avatar-box-shadow-offset-x, 0px) var(--cs-avatar-box-shadow-offset-y, 0px) var(--cs-avatar-box-shadow-blur-radius, 0px) var(--cs-avatar-box-shadow-spread-radius, 0px) var(--cs-avatar-box-shadow-color, transparent);

        /* Animation */
        animation-name: var(--cs-avatar-animation, none);
        animation-duration: var(--cs-avatar-animation-duration, 750ms);
        animation-delay: var(--cs-avatar-animation-delay, 0ms);
        animation-timing-function: var(--cs-avatar-animation-timing-function, ease-out);
        animation-fill-mode: both;
    }
}

.cs-bubble.cs-avatar-hidden .cs-avatar {
    display: none;
}


/*  ====================
    User (Username Header Container)
    ==================== */

.cs-user {
    display: flex;
    align-items: center;
    gap: 4px;
    line-height: 1;
    z-index: 1;

    padding-block-start: var(--cs-username-padding-top, var(--cs-username-padding, 0px));
    padding-inline-end: var(--cs-username-padding-right, var(--cs-username-padding, 0px));
    padding-block-end: var(--cs-username-padding-bottom, var(--cs-username-padding, 0px));
    padding-inline-start: var(--cs-username-padding-left, var(--cs-username-padding, 0px));

    background-color: var(--cs-username-background-color, transparent);
    background-image: var(--cs-username-background-gradient, none);
    background-repeat: no-repeat;

    border-width: var(--cs-username-border-width, 0px);
    border-style: var(--cs-username-border-style, solid);
    border-color: var(--cs-username-border-color, transparent);

    border-start-start-radius: var(--cs-username-border-radius-top-left, var(--cs-username-border-radius, 0px));
    border-start-end-radius: var(--cs-username-border-radius-top-right, var(--cs-username-border-radius, 0px));
    border-end-end-radius: var(--cs-username-border-radius-bottom-right, var(--cs-username-border-radius, 0px));
    border-end-start-radius: var(--cs-username-border-radius-bottom-left, var(--cs-username-border-radius, 0px));

    box-shadow: var(--cs-username-box-shadow-inset,) var(--cs-username-box-shadow-offset-x, 0px) var(--cs-username-box-shadow-offset-y, 0px) var(--cs-username-box-shadow-blur-radius, 0px) var(--cs-username-box-shadow-spread-radius, 0px) var(--cs-username-box-shadow-color, transparent);

    animation-name: var(--cs-username-animation, none);
    animation-duration: var(--cs-username-animation-duration, 750ms);
    animation-delay: var(--cs-username-animation-delay, 0ms);
    animation-timing-function: var(--cs-username-animation-timing-function, ease-out);
    animation-fill-mode: both;
}

/* Inside .cs-content */
.cs-user--inline {
    display: none;
    align-items: baseline;
    gap: 4px;
}

.cs-username,
.cs-username--inline {
    font-family: var(--cs-username-font-family, 'Space Grotesk'), sans-serif;
    font-size: var(--cs-username-font-size, 16px);
    font-weight: var(--cs-username-font-weight, 700);
    color: var(--cs-username-font-color, var(--cs-usercolor, #ffffff));
    -webkit-text-stroke: var(--cs-username-text-stroke-width, 0px) var(--cs-username-text-stroke-color, #000000);
    text-shadow: var(--cs-username-text-shadow-offset-x, 0px) var(--cs-username-text-shadow-offset-y, 0px) var(--cs-username-text-shadow-blur-radius, 0px) var(--cs-username-text-shadow-color, transparent);
    text-align: start;
    white-space: nowrap;
}

.cs-pronouns {
    text-align: start;
}

.cs-bubble.cs-username-position-inline .cs-user {
    display: none;
}

.cs-bubble.cs-username-position-inline .cs-user--inline {
    display: inline-flex;
}

.cs-bubble.cs-username-position-inline .cs-badges--inline {
    display: inline-flex;
}

.cs-bubble.cs-username-position-inline .cs-username--inline {
    display: inline;
}

.cs-bubble.cs-username-position-inline .cs-message {
    display: inline;
}

/*  ====================
    Pronouns
    ==================== */

.cs-pronouns:empty,
.cs-pronouns:has(>*:empty),
.cs-pronouns > *:empty{display:none}

.cs-pronouns {
    color: var(--cs-pronouns-font-color, currentColor);
    background-color: var(--cs-pronouns-background-color, transparent);
}

/*  ====================
    Timestamp
    ==================== */

.cs-timestamp:empty {display:none}

/*  ====================
    Content Wrapper - Inline Elements Wrapper
    ==================== */

.cs-content {
    flex: 1;
    min-inline-size: 0;
}

/*  ====================
    Badges
    ==================== */

.cs-badges {
    display: inline-flex;
    align-items: center;
    gap: 4px;

    &:empty {
        display: none !important;
    }

    img {
        inline-size: calc(var(--cs-username-font-size, 14px) + 2px);
        aspect-ratio: 1;
        border-radius: 1px;
    }
}

.cs-badges--inline {
    display: none;
    align-self: stretch;
    align-items: center;
    gap: 3px;
    margin-inline-end: 3px;
}

.cs-bubble.cs-badges-hidden {
    .cs-badges,
    .cs-badges--inline {
        display: none;
    }
}

.cs-bubble.cs-pronouns-hidden {
    .cs-pronouns,
    .cs-pronouns--inline {
        display: none;
    }
}

/* Badges Position */
/* Header: after-name → badges come after username */
.cs-bubble.cs-badges-position-after-name .cs-user .cs-badges {
    order: 1;
}

/* Inline: after-name → badges after username inside inline wrapper */
.cs-bubble.cs-badges-position-after-name .cs-user--inline .cs-badges--inline {
    order: 1;
}

/*  ====================
    Message
    ==================== */

.cs-message {
    position: relative;
    word-break: break-word;
    display: block;

    padding-block-start: var(--cs-message-padding-top, var(--cs-message-padding, 0px));
    padding-inline-end: var(--cs-message-padding-right, var(--cs-message-padding, 0px));
    padding-block-end: var(--cs-message-padding-bottom, var(--cs-message-padding, 0px));
    padding-inline-start: var(--cs-message-padding-left, var(--cs-message-padding, 0px));

    background-color: var(--cs-message-background-color, transparent);
    background-image: var(--cs-message-background-gradient, none);
    background-repeat: no-repeat;

    border-width: var(--cs-message-border-width, 0px);
    border-style: var(--cs-message-border-style, solid);
    border-color: var(--cs-message-border-color, transparent);

    border-start-start-radius: var(--cs-message-border-radius-top-left, var(--cs-message-border-radius, 0px));
    border-start-end-radius: var(--cs-message-border-radius-top-right, var(--cs-message-border-radius, 0px));
    border-end-end-radius: var(--cs-message-border-radius-bottom-right, var(--cs-message-border-radius, 0px));
    border-end-start-radius: var(--cs-message-border-radius-bottom-left, var(--cs-message-border-radius, 0px));

    box-shadow: var(--cs-message-box-shadow-inset,) var(--cs-message-box-shadow-offset-x, 0px) var(--cs-message-box-shadow-offset-y, 0px) var(--cs-message-box-shadow-blur-radius, 0px) var(--cs-message-box-shadow-spread-radius, 0px) var(--cs-message-box-shadow-color, transparent);

    font-family: var(--cs-message-font-family, 'Inter'), sans-serif;
    font-size: var(--cs-message-font-size, 16px);
    font-weight: var(--cs-message-font-weight, 400);
    color: var(--cs-message-font-color, #ffffff);
    -webkit-text-stroke: var(--cs-message-text-stroke-width, 0px) var(--cs-message-text-stroke-color, #000000);
    text-shadow: var(--cs-message-text-shadow-offset-x, 0px) var(--cs-message-text-shadow-offset-y, 0px) var(--cs-message-text-shadow-blur-radius, 0px) var(--cs-message-text-shadow-color, transparent);
    text-align: start;

    animation-name: var(--cs-message-animation, none);
    animation-duration: var(--cs-message-animation-duration, 750ms);
    animation-delay: var(--cs-message-animation-delay, 0ms);
    animation-timing-function: var(--cs-message-animation-timing-function, ease-out);
    animation-fill-mode: both;

    .cs-gif {
        inline-size: auto;
        block-size: auto;
        max-block-size: 140px;
        max-inline-size: 100%;
        vertical-align: middle;
    }

    .emote {
        inline-size: calc(var(--cs-message-font-size, 14px) + 16px);
        margin-inline: 2px;
        vertical-align: middle;
    }

    img {
        max-inline-size: 100%;
    }
}

/*  ====================
    Events
    ==================== */

.cs-events {
    animation-name: var(--cs-events-animation, none);
    animation-duration: var(--cs-events-animation-duration, 750ms);
    animation-timing-function: ease-out;
    animation-fill-mode: both;
}

.cs-bubble.cs-events-hidden .cs-events {
    display: none;
}

/*  ====================
    Font Modifiers
    ==================== */

/* Username */
.cs-bubble.cs-username-italic .cs-username,
.cs-bubble.cs-username-italic .cs-username--inline,
.cs-bubble.cs-username-italic .cs-pronouns {
    font-style: italic;
}

.cs-bubble.cs-username-underline .cs-username,
.cs-bubble.cs-username-underline .cs-username--inline,
.cs-bubble.cs-username-underline .cs-pronouns {
    text-decoration: underline;
}

.cs-bubble.cs-username-uppercase .cs-username,
.cs-bubble.cs-username-uppercase .cs-username--inline,
.cs-bubble.cs-username-uppercase .cs-pronouns {
    text-transform: uppercase;
}

.cs-bubble.cs-username-lowercase .cs-username,
.cs-bubble.cs-username-lowercase .cs-username--inline,
.cs-bubble.cs-username-lowercase .cs-pronouns {
    text-transform: lowercase;
}

.cs-bubble.cs-username-capitalize .cs-username,
.cs-bubble.cs-username-capitalize .cs-username--inline,
.cs-bubble.cs-username-capitalize .cs-pronouns {
    text-transform: capitalize;
}

.cs-bubble.cs-username-align-center .cs-username,
.cs-bubble.cs-username-align-center .cs-username--inline,
.cs-bubble.cs-username-align-center .cs-pronouns {
    text-align: center;
}

.cs-bubble.cs-username-align-end .cs-username,
.cs-bubble.cs-username-align-end .cs-username--inline,
.cs-bubble.cs-username-align-end .cs-pronouns {
    text-align: end;
}

/* Message */
.cs-bubble.cs-message-italic .cs-message {
    font-style: italic;
}

.cs-bubble.cs-message-underline .cs-message {
    text-decoration: underline;
}

.cs-bubble.cs-message-uppercase .cs-message {
    text-transform: uppercase;
}

.cs-bubble.cs-message-lowercase .cs-message {
    text-transform: lowercase;
}

.cs-bubble.cs-message-capitalize .cs-message {
    text-transform: capitalize;
}

.cs-bubble.cs-message-align-center .cs-message {
    text-align: center;
}

.cs-bubble.cs-message-align-end .cs-message {
    text-align: end;
}

CSS Load Order

The overlay loads CSS in this order. Later sources override earlier ones:

  1. animations.css — Keyframe definitions for all entrance animations (bp-fade-in, bp-slide-in-up, etc.)
  2. framework.css — Structural layout, all CSS variable bindings with neutral defaults, toggle classes
  3. Style CSS Template — Style-specific CSS rules, custom layout, and decorative styling
  4. Skin CSS Variables — Per-bubble inline CSS variable overrides from skin settings
  5. Expert Mode CSS — Your custom CSS rules (highest priority)
Note: Expert Mode CSS loads last, giving your custom rules the highest priority in the cascade. You can override any framework or style property.

Default Cascade

CSS property values are resolved in this priority order (lowest to highest):

  1. Framework Defaults — Neutral zero/transparent defaults from var() fallbacks in framework.css
  2. Style Template — CSS template defaults from the style's var() fallback values
  3. Style Settings — The style author's intended base values, compiled to CSS variables
  4. Skin Overrides — Skin-specific CSS variable overrides (delta only — only changed values)
  5. Viewer Skin — Personal viewer skin overrides applied per-bubble
  6. Expert Mode CSS — Your custom CSS rules (highest priority, can override everything)