@@ -3724,12 +3724,12 @@ fn attrs_to_css(
3724 "type" | "placeholder" | "name" | "value" | "disabled" | "required" | "checked"
3724 "type" | "placeholder" | "name" | "value" | "disabled" | "required" | "checked"
3725 | "for" | "action" | "method" | "autocomplete" | "min" | "max" | "step" | "pattern"
3725 | "for" | "action" | "method" | "autocomplete" | "min" | "max" | "step" | "pattern"
3726 | "maxlength" | "rows" | "cols" | "multiple" | "alt" | "role" | "tabindex"
3726 | "maxlength" | "rows" | "cols" | "multiple" | "alt" | "role" | "tabindex"
3727− | "title" | "controls" | "autoplay" | "loop" | "muted" | "playsinline" | "poster" | "preload"
3727+ | "title" | "controls" | "autoplay" | "loop" | "muted" | "playsinline" | "poster"
3728− | "loading" | "decoding" | "ordered" | "src" | "open" | "novalidate" | "low"
3728+ | "preload" | "loading" | "decoding" | "ordered" | "src" | "open" | "novalidate"
3729− | "high" | "optimum" | "colspan" | "rowspan" | "scope" | "inline" | "responsive"
3729+ | "low" | "high" | "optimum" | "colspan" | "rowspan" | "scope" | "inline"
3730− | "datetime" | "media" | "sizes" | "srcset" | "cite" | "list" | "sandbox" | "allow"
3730+ | "responsive" | "datetime" | "media" | "sizes" | "srcset" | "cite" | "list"
3731− | "allowfullscreen" | "referrerpolicy" | "formaction" | "formmethod" | "formtarget"
3731+ | "sandbox" | "allow" | "allowfullscreen" | "referrerpolicy" | "formaction"
3732− | "target" | "autofocus" => {}
3732+ | "formmethod" | "formtarget" | "target" | "autofocus" => {}
@@ -3795,17 +3795,11 @@ fn substitute_css_vars(css: &str, vars: &[(String, String)]) -> String {
3796 let is_boundary_before = |b: Option<u8>| match b {
3796 let is_boundary_before = |b: Option<u8>| match b {
3797 None => true,
3797 None => true,
3798− Some(c) => matches!(
3798+ Some(c) => matches!(c, b':' | b' ' | b',' | b'(' | b';' | b'{' | b'\n' | b'\t'),
3800− b':' | b' ' | b',' | b'(' | b';' | b'{' | b'\n' | b'\t'
3803 let is_boundary_after = |b: Option<u8>| match b {
3800 let is_boundary_after = |b: Option<u8>| match b {
3804 None => true,
3801 None => true,
3805− Some(c) => matches!(
3802+ Some(c) => matches!(c, b';' | b'}' | b',' | b' ' | b')' | b'\n' | b'\t'),
3807− b';' | b'}' | b',' | b' ' | b')' | b'\n' | b'\t'
3811 let bytes = css.as_bytes();
3805 let bytes = css.as_bytes();
@@ -3920,16 +3914,10 @@ fn auto_extract_repeats(
3920 // two-digit indices, which only affects very large extraction counts.
3914 // two-digit indices, which only affects very large extraction counts.
3921 let existing: std::collections::HashSet<&str> =
3915 let existing: std::collections::HashSet<&str> =
3922 existing_vars.iter().map(|(n, _)| n.as_str()).collect();
3916 existing_vars.iter().map(|(n, _)| n.as_str()).collect();
3923− let mut candidates: Vec<(String, usize)> = counts
3917+ let mut candidates: Vec<(String, usize)> =
3925− .filter(|(_, n)| *n >= 2)
3918+ counts.into_iter().filter(|(_, n)| *n >= 2).collect();
3927 // Stable, deterministic ordering — longest values first, tiebreak by text.
3919 // Stable, deterministic ordering — longest values first, tiebreak by text.
3928− candidates.sort_by(|a, b| {
3920+ candidates.sort_by(|a, b| b.0.len().cmp(&a.0.len()).then_with(|| a.0.cmp(&b.0)));
3931− .then_with(|| a.0.cmp(&b.0))
3934 let mut extracted: Vec<(String, String)> = Vec::new();
3922 let mut extracted: Vec<(String, String)> = Vec::new();
3935 let mut next_idx: usize = 0;
3923 let mut next_idx: usize = 0;