dragon-iso/src/TeamsISO.App/Themes/WildDragonTheme.xaml
Zac Gaetano 25229bdf1b
Some checks failed
CI / build-and-test (push) Failing after 27s
ISO toggle: square corners to match the rest of the button family
Wd.Button.IsoToggle was the only button in the GUI using CornerRadius=999
(full pill). It read as a different control type from the toolbar buttons
around it (Enable all, Refresh, Presets, Stop all, Mute, Cam, Leave —
all Radius.M). The pill shape was meant to make the LIVE state visually
distinct, but the status-coded fill (cyan/coral/amber) already carries
that signal — the geometry was double-duty.

Swap the IsoToggle's CornerRadius from 999 to Radius.M so every button
in the app shares the same shape language. Status read remains via the
fill color.
2026-05-15 16:19:19 -04:00

1039 lines
56 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<!--
TeamsISO design system — Wild Dragon brand × Microsoft Teams layout.
Brand reference: wilddragon.net
Primary canvas: #0a0a0a
Accent cyan: #97EDF0
Secondary blue: #9AE0FD
Coral (errors): #FB819C
Earth (warnings): #423825
Fonts: Inter (primary), JetBrains Mono
Layout reference: Microsoft Teams desktop
- Left rail (72px) for app icon + primary nav
- Top header inside content area
- Card-based main panel with rounded corners (8-12px)
- Subtle elevation through tone, not heavy shadows
- Avatar circles for participants
Inter is not a Windows system font; we list it first and fall back to
Segoe UI Variable Display (Windows 11) and Segoe UI. JetBrains Mono
falls back to Cascadia Mono.
-->
<!-- ════ Spacing (8px grid) ════ -->
<sys:Double x:Key="Space.XS">4</sys:Double>
<sys:Double x:Key="Space.S">8</sys:Double>
<sys:Double x:Key="Space.M">12</sys:Double>
<sys:Double x:Key="Space.L">16</sys:Double>
<sys:Double x:Key="Space.XL">24</sys:Double>
<sys:Double x:Key="Space.XXL">32</sys:Double>
<!-- ════ Radii (Teams uses 6/8/12) ════ -->
<CornerRadius x:Key="Radius.S">6</CornerRadius>
<CornerRadius x:Key="Radius.M">8</CornerRadius>
<CornerRadius x:Key="Radius.L">12</CornerRadius>
<CornerRadius x:Key="Radius.XL">16</CornerRadius>
<!--
Color brushes moved to Theme.Dark.xaml / Theme.Light.xaml so they
can be swapped at runtime. Styles below reference them via
{DynamicResource} so the swap re-resolves the visual tree.
The two color files MUST stay in lockstep — adding a brush
in one without the other breaks the missing-mode rendering.
New key (v2 redesign): Wd.Accent.CyanText. Use this when cyan
is the FOREGROUND on a light or dark canvas (status text,
captions, icons). Wd.Accent.Cyan stays for BACKGROUND fills
where the on-top text is near-black (LIVE pill, focus ring).
-->
<!-- ════ Animation defaults for theme-aware micro-interactions ════ -->
<Duration x:Key="Wd.Motion.Fast">0:0:0.090</Duration>
<Duration x:Key="Wd.Motion.Med">0:0:0.180</Duration>
<Duration x:Key="Wd.Motion.Slow">0:0:0.280</Duration>
<!-- ════ Typography ════ -->
<!--
Inter is bundled as Assets\Fonts\Inter.ttf (Variable, OFL — rsms/inter v3.19).
The pack URI loads it from this assembly's resources at runtime so we don't
depend on the user having Inter installed system-wide. Fallback chain to
Segoe UI if the resource is somehow missing.
-->
<FontFamily x:Key="Wd.Font.Sans">pack://application:,,,/Assets/Fonts/#Inter, Inter, Segoe UI Variable Display, Segoe UI, sans-serif</FontFamily>
<FontFamily x:Key="Wd.Font.Mono">pack://application:,,,/Assets/Fonts/#JetBrains Mono, JetBrains Mono, Cascadia Mono, Consolas, monospace</FontFamily>
<Style x:Key="Wd.Text.Title" TargetType="TextBlock">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
</Style>
<Style x:Key="Wd.Text.Heading" TargetType="TextBlock">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
</Style>
<Style x:Key="Wd.Text.Body" TargetType="TextBlock">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
</Style>
<Style x:Key="Wd.Text.Subtle" TargetType="TextBlock" BasedOn="{StaticResource Wd.Text.Body}">
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Secondary}"/>
</Style>
<Style x:Key="Wd.Text.Caption" TargetType="TextBlock">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="FontWeight" Value="Medium"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Tertiary}"/>
<Setter Property="Typography.Capitals" Value="AllSmallCaps"/>
</Style>
<Style x:Key="Wd.Text.Mono" TargetType="TextBlock">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Mono}"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Secondary}"/>
</Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource Wd.Text.Body}"/>
<!-- ════ Buttons ════ -->
<!-- Ghost: bordered, transparent fill -->
<Style x:Key="Wd.Button.Ghost" TargetType="Button">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="FontWeight" Value="Medium"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{DynamicResource Wd.BorderStrong}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="14,8"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{StaticResource Radius.M}"
SnapsToDevicePixels="True">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}"/>
</Border>
<ControlTemplate.Triggers>
<!--
Hover: strong fill change PLUS a cyan accent border.
The dual-cue (lighter surface + bright border) is
what gives the affordance an unmistakable read on
the dark canvas — a background-only change in this
palette is too subtle to spot at a glance.
-->
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Button.HoverBg}"/>
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.Accent.Cyan}"/>
</Trigger>
<!--
Keyboard focus ring (Tab-navigation). FocusVisualStyle
is x:Null on all themed buttons — without this trigger
you'd have NO visual cue when tab-cycling through.
Match the hover treatment so mouse + keyboard land
on the same affordance.
-->
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.Accent.Cyan}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Button.PressBg}"/>
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.Accent.CyanHover}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Disabled}"/>
<Setter TargetName="Bd" Property="Opacity" Value="0.6"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Primary: cyan-on-black for the brand action -->
<Style x:Key="Wd.Button.Primary" TargetType="Button" BasedOn="{StaticResource Wd.Button.Ghost}">
<Setter Property="Background" Value="{DynamicResource Wd.Accent.Cyan}"/>
<Setter Property="BorderBrush" Value="{DynamicResource Wd.Accent.Cyan}"/>
<Setter Property="Foreground" Value="#0A0A0A"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{StaticResource Radius.M}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="{TemplateBinding Padding}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Accent.CyanHover}"/>
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.Accent.CyanHover}"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Accent.CyanHover}"/>
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.Accent.CyanHover}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Bd" Property="Opacity" Value="0.85"/>
</Trigger>
<!--
Disabled state: ghost the cyan to a muted tone +
knock the foreground back. Without this trigger
the disabled Apply button looked just like the
enabled one (Apply Changes is the most-frequently
disabled button in the app — its state has to read
distinctly so the operator knows when changes are
pending vs. when nothing's queued to apply).
-->
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Accent.CyanMuted}"/>
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.Accent.CyanMuted}"/>
<Setter TargetName="Bd" Property="Opacity" Value="0.7"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Disabled}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--
Window-caption buttons: minimize / maximize / close. Match the Windows 11
Teams look — slim 46x32, hover-tinted, Close turns red on hover.
-->
<Style x:Key="Wd.Button.Caption" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Width" Value="46"/>
<Setter Property="Height" Value="32"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="Bd" Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Button.HoverBg}"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Button.HoverBg}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Button.PressBg}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="Wd.Button.CaptionClose" TargetType="Button" BasedOn="{StaticResource Wd.Button.Caption}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="Bd" Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="Background" Value="#C42B1C"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Bd" Property="Background" Value="#A52A1F"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Rail-icon button: square 48x48, used on the Teams-style left rail -->
<Style x:Key="Wd.Button.RailIcon" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Secondary}"/>
<Setter Property="Width" Value="48"/>
<Setter Property="Height" Value="48"/>
<Setter Property="Margin" Value="0,4"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="Bd"
Background="{TemplateBinding Background}"
CornerRadius="{StaticResource Radius.M}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<!-- Rail icons sit on Wd.Rail (#080808) — a darker
surface than Wd.Canvas. Use Wd.Button.HoverBg so
the affordance reads clearly. -->
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Button.HoverBg}"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Accent.Cyan}"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Button.HoverBg}"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Accent.Cyan}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Button.PressBg}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ISO toggle: rounded-rect (Radius.M) to match the rest of the button
family, status-coded background (LIVE cyan / ERROR coral / NO SIGNAL
amber). Previously a full pill (CornerRadius=999); pill made the LIVE
indicator visually distinct from the toolbar buttons in a way that
read as "different control type" rather than "different state". -->
<Style x:Key="Wd.Button.IsoToggle" TargetType="Button">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
<Setter Property="Background" Value="{DynamicResource Wd.SurfaceHover}"/>
<Setter Property="BorderBrush" Value="{DynamicResource Wd.BorderStrong}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="14,6"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="MinWidth" Value="84"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{StaticResource Radius.M}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="{TemplateBinding Padding}"/>
</Border>
<ControlTemplate.Triggers>
<!--
IsoToggle has a status-coded background (LIVE cyan,
ERROR coral, NO SIGNAL amber) set inline by the row
template. Hover *keeps* that background color (so
the at-a-glance status read is preserved) and adds
a thicker cyan-tinted border so the affordance is
unmistakable. We don't override Background here so
the data-trigger setter wins.
-->
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.Accent.CyanHover}"/>
<Setter TargetName="Bd" Property="BorderThickness" Value="2"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.Accent.CyanHover}"/>
<Setter TargetName="Bd" Property="BorderThickness" Value="2"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.Accent.Cyan}"/>
<Setter TargetName="Bd" Property="BorderThickness" Value="2"/>
<Setter TargetName="Bd" Property="Opacity" Value="0.85"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ════ TextBox ════ -->
<Style x:Key="Wd.TextBox.Default" TargetType="TextBox">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
<Setter Property="Background" Value="{DynamicResource Wd.Surface}"/>
<Setter Property="CaretBrush" Value="{DynamicResource Wd.Accent.Cyan}"/>
<Setter Property="SelectionBrush" Value="{DynamicResource Wd.Accent.CyanMuted}"/>
<Setter Property="BorderBrush" Value="{DynamicResource Wd.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="12,9"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border x:Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{StaticResource Radius.M}">
<ScrollViewer x:Name="PART_ContentHost"
Margin="{TemplateBinding Padding}"
VerticalAlignment="Center"
Focusable="False"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.Accent.Cyan}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.BorderStrong}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource Wd.TextBox.Default}"/>
<!-- ════ ComboBox ════ -->
<Style x:Key="Wd.ComboToggle" TargetType="ToggleButton">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="ClickMode" Value="Press"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<!--
Grid Background="Transparent" is required so the ENTIRE
ComboBox face opens the dropdown, not just the chevron.
Previously the template was just the <Path> with no
Background-bearing container — WPF hit-tests only the
rendered triangle (~8x4px), so the operator's click on
the visible field fell through and nothing happened.
-->
<Grid Background="Transparent">
<Path HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="0,0,14,0"
Data="M 0,0 L 4,4 L 8,0 Z"
Fill="{DynamicResource Wd.Text.Secondary}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ComboBox">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
<Setter Property="Background" Value="{DynamicResource Wd.Surface}"/>
<Setter Property="BorderBrush" Value="{DynamicResource Wd.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="12,9"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<Border x:Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{StaticResource Radius.M}"/>
<ToggleButton Style="{StaticResource Wd.ComboToggle}"
IsChecked="{Binding IsDropDownOpen,
RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"/>
<ContentPresenter Margin="{TemplateBinding Padding}"
IsHitTestVisible="False"
VerticalAlignment="Center"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"/>
<Popup IsOpen="{TemplateBinding IsDropDownOpen}"
Placement="Bottom"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="None">
<Border Background="{DynamicResource Wd.SurfaceElevated}"
BorderBrush="{DynamicResource Wd.BorderStrong}"
BorderThickness="1"
CornerRadius="{StaticResource Radius.M}"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="280"
Margin="0,4,0,0">
<ScrollViewer><ItemsPresenter/></ScrollViewer>
</Border>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.BorderStrong}"/>
</Trigger>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Wd.Accent.Cyan}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ComboBoxItem">
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
<Setter Property="Padding" Value="12,9"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border x:Name="Bd"
Background="Transparent"
CornerRadius="{StaticResource Radius.S}"
Margin="4,2"
Padding="{TemplateBinding Padding}">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.SurfaceHover}"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.SurfaceHover}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ════ CheckBox ════ -->
<Style TargetType="CheckBox">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Padding" Value="10,0,0,0"/>
<!--
Stretch + a Grid template lets long Content strings wrap rather
than get clipped by the 380px settings panel. Without this, the
previous StackPanel template let the ContentPresenter grow
unbounded horizontally and the parent's clip-to-bounds chopped
off the right side.
-->
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="Box"
Grid.Column="0"
Width="18" Height="18"
BorderBrush="{DynamicResource Wd.BorderStrong}"
BorderThickness="1"
Background="{DynamicResource Wd.Surface}"
CornerRadius="4"
VerticalAlignment="Center">
<Path x:Name="Tick"
Data="M 4,9 L 7.5,12.5 L 14,5"
Stroke="#0A0A0A" StrokeThickness="2"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
Visibility="Collapsed"/>
</Border>
<!--
ContentPresenter resources inject a TextBlock
style with TextWrapping=Wrap. When CheckBox's
Content is a plain string (the common case here),
WPF wraps it in an auto-generated TextBlock; the
resource lookup applies our wrapping default so
long labels flow onto multiple lines instead of
being clipped at the column edge.
-->
<ContentPresenter Grid.Column="1"
Margin="{TemplateBinding Padding}"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
RecognizesAccessKey="True">
<ContentPresenter.Resources>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="Box" Property="Background" Value="{DynamicResource Wd.Accent.Cyan}"/>
<Setter TargetName="Box" Property="BorderBrush" Value="{DynamicResource Wd.Accent.Cyan}"/>
<Setter TargetName="Tick" Property="Visibility" Value="Visible"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Box" Property="BorderBrush" Value="{DynamicResource Wd.Accent.Cyan}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ════ TabControl (settings panel) ════ -->
<!--
Lightweight, flush tabs that match the dark surface. Underline-on-active
rather than the WPF default raised-border, so the tab strip reads as a
section header rather than a separate widget.
-->
<Style TargetType="TabControl" x:Key="Wd.TabControl">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0"
BorderBrush="{DynamicResource Wd.Border}"
BorderThickness="0,0,0,1">
<TabPanel x:Name="HeaderPanel"
IsItemsHost="True"
Background="Transparent"/>
</Border>
<ContentPresenter Grid.Row="1"
ContentSource="SelectedContent"
Margin="0,16,0,0"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TabItem" x:Key="Wd.TabItem">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="FontWeight" Value="Medium"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Tertiary}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="0,8,0,10"/>
<Setter Property="Margin" Value="0,0,20,0"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<!--
Transparent Background is REQUIRED for the whole header area to be
hit-testable. Without it, only clicks landing exactly on the rendered
glyphs of the header text fire IsSelected — clicks on the padding
around the text fall through and the tab never switches. The template
shipped without this for months; this is the fix.
-->
<Grid Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ContentPresenter x:Name="Content"
Grid.Row="0"
ContentSource="Header"
HorizontalAlignment="Left"
VerticalAlignment="Center"
TextBlock.FontFamily="{TemplateBinding FontFamily}"
TextBlock.FontSize="{TemplateBinding FontSize}"
TextBlock.FontWeight="{TemplateBinding FontWeight}"
TextBlock.Foreground="{TemplateBinding Foreground}"
Margin="{TemplateBinding Padding}"/>
<Rectangle x:Name="Underline"
Grid.Row="1"
Height="2"
Fill="{DynamicResource Wd.Accent.Cyan}"
Visibility="Hidden"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Underline" Property="Visibility" Value="Visible"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Secondary}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ════ Card ════ -->
<Style x:Key="Wd.Card" TargetType="Border">
<Setter Property="Background" Value="{DynamicResource Wd.Surface}"/>
<Setter Property="BorderBrush" Value="{DynamicResource Wd.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="{StaticResource Radius.L}"/>
<Setter Property="Padding" Value="16"/>
</Style>
<!-- ════ DataGrid (re-skinned, Teams-style) ════ -->
<Style TargetType="DataGrid">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="GridLinesVisibility" Value="None"/>
<Setter Property="HeadersVisibility" Value="Column"/>
<Setter Property="RowHeight" Value="56"/>
<Setter Property="RowBackground" Value="Transparent"/>
<Setter Property="AlternatingRowBackground" Value="Transparent"/>
<Setter Property="HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="CanUserAddRows" Value="False"/>
<Setter Property="CanUserDeleteRows" Value="False"/>
<Setter Property="CanUserResizeRows" Value="False"/>
<Setter Property="SelectionMode" Value="Single"/>
<Setter Property="SelectionUnit" Value="FullRow"/>
<Setter Property="AutoGenerateColumns" Value="False"/>
</Style>
<Style TargetType="DataGridColumnHeader">
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="FontWeight" Value="Medium"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Tertiary}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{DynamicResource Wd.Border}"/>
<Setter Property="BorderThickness" Value="0,0,0,1"/>
<Setter Property="Padding" Value="14,12"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="Typography.Capitals" Value="AllSmallCaps"/>
</Style>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{DynamicResource Wd.Border}"/>
<Setter Property="BorderThickness" Value="0,0,0,1"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource Wd.SurfaceHover}"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{DynamicResource Wd.SurfaceElevated}"/>
</Trigger>
<!-- Active speaker highlight (v2): full-row cyan-muted background
tint. NOT a left-edge stripe — that would trip the impeccable
side-stripe-border ban and reads as AI-design vocabulary.
Full-row tint is bigger and broadcast-engineering-vocabulary:
the row whose channel is hot stands out across the screen. -->
<DataTrigger Binding="{Binding IsActiveSpeaker}" Value="True">
<Setter Property="Background" Value="{DynamicResource Wd.Accent.CyanMuted}"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="DataGridCell">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="14,0"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridCell">
<Border Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}">
<ContentPresenter VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ════ ScrollBar (slim, dark-theme-native) ════ -->
<!--
The default WPF ScrollBar template is a chunky Win9x affair (line-up
/ line-down arrow buttons + a 3D thumb) that clashes hard with the
dark canvas. Replace with a slim, transparent track + thumb pattern
like Edge / VS Code / GitHub use: thumb is barely visible at rest,
pops a tone brighter on hover/drag. Track-clicks still page-scroll
(the RepeatButton does the work) but render as invisible hit zones.
-->
<Style x:Key="Wd.ScrollBar.Thumb" TargetType="Thumb">
<Setter Property="Background" Value="{DynamicResource Wd.BorderStrong}"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Border x:Name="Bd"
Background="{TemplateBinding Background}"
CornerRadius="4"
Margin="2"/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Text.Tertiary}"/>
</Trigger>
<Trigger Property="IsDragging" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Accent.Cyan}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Invisible page-scroll RepeatButton (clicks above/below thumb still page-scroll). -->
<Style x:Key="Wd.ScrollBar.PageButton" TargetType="RepeatButton">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton">
<Border Background="{TemplateBinding Background}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ScrollBar">
<Setter Property="Width" Value="10"/>
<Setter Property="MinWidth" Value="10"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ScrollBar">
<Grid x:Name="Bg" Background="{TemplateBinding Background}">
<Track x:Name="PART_Track" IsDirectionReversed="True">
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource Wd.ScrollBar.PageButton}"
Command="ScrollBar.PageUpCommand"/>
</Track.DecreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource Wd.ScrollBar.Thumb}"/>
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource Wd.ScrollBar.PageButton}"
Command="ScrollBar.PageDownCommand"/>
</Track.IncreaseRepeatButton>
</Track>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Orientation" Value="Horizontal">
<Setter Property="Height" Value="10"/>
<Setter Property="MinHeight" Value="10"/>
<Setter Property="Width" Value="Auto"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ScrollBar">
<Grid x:Name="Bg" Background="{TemplateBinding Background}">
<Track x:Name="PART_Track" IsDirectionReversed="False">
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource Wd.ScrollBar.PageButton}"
Command="ScrollBar.PageLeftCommand"/>
</Track.DecreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource Wd.ScrollBar.Thumb}"/>
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource Wd.ScrollBar.PageButton}"
Command="ScrollBar.PageRightCommand"/>
</Track.IncreaseRepeatButton>
</Track>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<!-- ════ Avatar (28px circle with initials) ════ -->
<Style x:Key="Wd.Avatar" TargetType="Border">
<Setter Property="Width" Value="32"/>
<Setter Property="Height" Value="32"/>
<Setter Property="CornerRadius" Value="16"/>
<Setter Property="Background" Value="{DynamicResource Wd.Accent.CyanMuted}"/>
<Setter Property="BorderBrush" Value="{DynamicResource Wd.Accent.Cyan}"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<!-- ════ ToolTip ════ -->
<!--
Default WPF ToolTips render as cream-on-black with a thin border —
Win98 aesthetic. Replace with a slim dark card so the dozens of
tooltips throughout MainWindow read as part of the same UI rather
than as OS popups bolted on. Wraps long tooltip text at 320px so a
verbose explanation doesn't stretch across a whole monitor.
-->
<Style TargetType="ToolTip">
<Setter Property="Background" Value="{DynamicResource Wd.SurfaceElevated}"/>
<Setter Property="BorderBrush" Value="{DynamicResource Wd.BorderStrong}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Padding" Value="10,6"/>
<Setter Property="HasDropShadow" Value="False"/>
<Setter Property="Placement" Value="Bottom"/>
<Setter Property="VerticalOffset" Value="6"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{StaticResource Radius.S}"
Padding="{TemplateBinding Padding}"
MaxWidth="320">
<!-- Most tooltips in this app pass a plain string for
Content; bind directly to a TextBlock so we get
TextWrapping="Wrap" and respect the parent's
MaxWidth. ContentPresenter wouldn't honor
TextBlock.TextWrapping (not an attached prop). -->
<TextBlock Text="{TemplateBinding Content}"
TextWrapping="Wrap"
Foreground="{TemplateBinding Foreground}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ════ ContextMenu (right-click) ════ -->
<!--
WPF's default ContextMenu renders white-on-grey with a 3D border —
looks like Notepad on the dark canvas. Match the rest of the theme:
SurfaceElevated background, slim cyan-muted highlight on hover, no
chevron arrows on items without submenus, rounded outer corner.
-->
<Style TargetType="ContextMenu">
<Setter Property="Background" Value="{DynamicResource Wd.SurfaceElevated}"/>
<Setter Property="BorderBrush" Value="{DynamicResource Wd.BorderStrong}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContextMenu">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{StaticResource Radius.M}"
Padding="{TemplateBinding Padding}">
<StackPanel IsItemsHost="True"
KeyboardNavigation.DirectionalNavigation="Cycle"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="MenuItem">
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Primary}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="FontFamily" Value="{StaticResource Wd.Font.Sans}"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="Padding" Value="12,8"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MenuItem">
<Border x:Name="Bd"
Background="{TemplateBinding Background}"
CornerRadius="{StaticResource Radius.S}"
Margin="0,1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0"
ContentSource="Icon"
Margin="0,0,8,0"
VerticalAlignment="Center"/>
<ContentPresenter Grid.Column="1"
ContentSource="Header"
Margin="{TemplateBinding Padding}"
VerticalAlignment="Center"
RecognizesAccessKey="True"
TextBlock.Foreground="{TemplateBinding Foreground}"/>
<TextBlock Grid.Column="2"
Text="{TemplateBinding InputGestureText}"
Margin="16,0,12,0"
VerticalAlignment="Center"
FontFamily="{StaticResource Wd.Font.Mono}"
FontSize="11"
Foreground="{DynamicResource Wd.Text.Tertiary}"/>
<Popup x:Name="PART_Popup"
Placement="Right"
IsOpen="{TemplateBinding IsSubmenuOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="None">
<Border Background="{DynamicResource Wd.SurfaceElevated}"
BorderBrush="{DynamicResource Wd.BorderStrong}"
BorderThickness="1"
CornerRadius="{StaticResource Radius.M}"
Padding="4"
Margin="2,0,0,0">
<StackPanel IsItemsHost="True"/>
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Wd.Button.HoverBg}"/>
<Setter Property="Foreground" Value="{DynamicResource Wd.Accent.Cyan}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Disabled}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ════ Status pill ════ -->
<Style x:Key="Wd.Pill" TargetType="Border">
<Setter Property="Background" Value="{DynamicResource Wd.SurfaceElevated}"/>
<Setter Property="CornerRadius" Value="999"/>
<Setter Property="Padding" Value="10,4"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
</ResourceDictionary>