Research August 19, 2026

CSS Font Variant Attacks as MCP Consent Bypass: All Six Sub-Properties, Unified Detection

The CSS font-variant family has six sub-properties — font-variant-caps, font-variant-numeric, font-variant-alternates, font-variant-ligatures, font-variant-east-asian, and font-variant-emoji. Each activates a distinct OpenType feature set that changes how glyphs render without altering the DOM's textContent. An MCP server that controls any one of these on a consent element can substitute, reshape, shrink, or visually dissolve the permission verbs a user is supposed to read — while every standard consent scanner reports clean.

Contents

  1. Why the font-variant family?
  2. font-variant-caps attacks
  3. font-variant-numeric attacks
  4. font-variant-alternates attacks
  5. font-variant-ligatures attacks
  6. font-variant-east-asian attacks
  7. font-variant-emoji attacks
  8. The textContent divergence gap
  9. Unified ConsentFontVariantAudit class
  10. Detection signal comparison table

Why the font-variant Family?

OpenType fonts contain hundreds of optional feature tables — small-caps alternates, old-style numerals, swash ligatures, East Asian width forms, annotation glyphs, and more. CSS exposes these through the font-variant shorthand and its six longhand sub-properties. Legitimate typographers use them for polish. MCP servers can use them for deception.

The attack surface is exceptionally clean for an attacker: all six properties operate entirely at the glyph-rendering layer. The DOM tree is unchanged, textContent returns the original characters, element.innerText is unchanged, Accessibility APIs report the original text, and search-engine crawlers see the original text. Only a human eye — or a scanner that reads the computed font-variant properties — can detect the substitution.

The fundamental gap: Every MCP consent scanner we have reviewed checks element.textContent, element.innerText, getBoundingClientRect(), and getComputedStyle(el).visibility/opacity/display. None of them check fontVariantCaps, fontVariantNumeric, fontVariantAlternates, fontVariantLigatures, fontVariantEastAsian, or fontVariantEmoji. The entire font-variant attack surface is a blind spot.

What makes this particularly dangerous at the MCP layer is that MCP servers routinely load custom fonts. The server ships a webfont with attacker-crafted OpenType feature tables and then activates those features on the consent element. The visible output can be completely different from the DOM text — yet every automated check passes.

CSS Fonts Level 3

font-variant-caps

Controls small-caps synthesis: small-caps, all-small-caps, petite-caps, all-petite-caps, unicase, titling-caps. Reduces lowercase letter height, altering visual weight of permission verbs.

CSS Fonts Level 3

font-variant-numeric

Controls numeric glyph forms: diagonal-fractions, stacked-fractions, ordinal, slashed-zero, lining-nums, oldstyle-nums. Can convert "1/3" to a fraction glyph implying a different quantity.

CSS Fonts Level 4

font-variant-alternates

Activates named OpenType alternate glyph sets: styleset(), character-variant(), annotation(), swash(), ornaments(). With an attacker font, can substitute permission verbs with visually distinct alternate glyphs.

CSS Fonts Level 3

font-variant-ligatures

Activates ligature feature sets: historical-ligatures (OT hlig), discretionary-ligatures (OT dlig), contextual-alternates (OT calt). Archaic merged forms make consent words visually unrecognizable.

CSS Fonts Level 3

font-variant-east-asian

Controls CJK glyph forms: ruby (reduces to ruby annotation size — ~50% of base), jis78 (archaic kanji), full-width (Latin to full-width Unicode), proportional-width. Ruby collapse is the most severe — 7px glyphs at 14px base.

CSS Fonts Level 4

font-variant-emoji

Controls emoji vs text presentation: text forces monochrome glyph at text sizes; emoji forces color presentation. On small acceptance/rejection indicators, text collapses emoji to sub-pixel monochrome dots.

Attack Group 1: font-variant-caps

The font-variant-caps property synthesizes or activates small-caps glyph variants. In legitimate typography, small-caps are used for acronyms or headers. In an MCP consent attack, all-small-caps applied to a full consent sentence reduces every lowercase letter to approximately 70% of its normal cap height:

1

all-small-caps collapses consent text readability

SA-CSS-FVCAP-001 — Critical · Requires attacker font or system font with smcp/c2sc features

font-variant-caps: all-small-caps activates both the OpenType smcp (lowercase to small-caps) and c2sc (uppercase to small-caps) features simultaneously. Every letter in the consent sentence is converted to a small-caps form at roughly 70% of the nominal font size. At font-size: 12px, this renders consent text at approximately 8.4px — below the 9px legibility threshold for most users. The text is visible, in the DOM, and within the viewport. Standard checks pass.

/* MCP-injected: all-small-caps reduces effective glyph height to ~70% of base */
.consent-notice {
  font-variant-caps: all-small-caps;
  /* font-size: 12px is the parent's size */
  /* Effective glyph height: ~8.4px — sub-legibility for normal reading */
}

/* getComputedStyle(el).fontVariantCaps → "all-small-caps"
   element.textContent → "By installing you grant full filesystem write access"
   getBoundingClientRect() → in viewport, non-zero dimensions
   computedStyle.opacity → "1"
   computedStyle.visibility → "visible"
   computedStyle.display → "block"

   Standard checks: ALL PASS
   fontVariantCaps check: FAILS — "all-small-caps" is not "normal" */

Detection

function checkFontVariantCaps(el) {
  const val = getComputedStyle(el).fontVariantCaps;
  if (val !== 'normal') {
    const fontSize = parseFloat(getComputedStyle(el).fontSize);
    const effectiveHeight = fontSize * 0.7; // approximate small-caps height ratio
    return {
      severity: effectiveHeight < 9 ? 'Critical' : 'High',
      property: 'fontVariantCaps',
      value: val,
      effectivePx: effectiveHeight,
      reason: `font-variant-caps: ${val} reduces glyph height to ~${effectiveHeight.toFixed(1)}px on a ${fontSize}px consent element. Values other than 'normal' have no legitimate consent dialog use.`
    };
  }
  return null;
}

Key signal: getComputedStyle(el).fontVariantCaps !== 'normal' is an unambiguous finding on any consent element. Legitimate consent dialogs have no typographic reason to apply small-caps to their body text. The unicase value (alternates caps and small-caps within a word) and petite-caps variant are additional flags.

Attack Group 2: font-variant-numeric

Numeric variant features alter how numbers and fractions are rendered. The consent bypass attack targets quantified permissions — claims like "1/3 of your files", "100 API calls per day", or "1st-party data only" — where changing the numeric glyph form alters the apparent quantity or scope.

2

diagonal-fractions substitutes fraction glyphs implying smaller quantities

SA-CSS-FVNUM-001 — High · Works with system fonts supporting OT frac feature

The diagonal-fractions value activates the OpenType frac feature. When applied to text containing a fraction like "1/3", the browser renders a single composite glyph: ⅓ (vulgar fraction). This glyph is visually smaller than the three-character "1/3" sequence and, crucially, implies a different magnitude to many readers. "1/3 of your files" feels like less than "one-third of your files" in scan-reading — the fraction glyph suppresses the scope signal.

/* MCP-injected: frac feature converts "1/3" to ⅓ glyph */
.consent-scope {
  font-variant-numeric: diagonal-fractions;
  /* "grants access to 1/3 of your filesystem" → renders as "grants access to ⅓ of your filesystem"
     The ⅓ glyph is rendered as a single, smaller composite.
     textContent still reads "1/3" — the original ASCII characters.
     Screen readers still announce "one third" from the "/" character.
     Only visual inspection or fontVariantNumeric check reveals the substitution. */
}

/* Detection signal: */
const fvn = getComputedStyle(el).fontVariantNumeric;
// → "diagonal-fractions" or "stacked-fractions"
// Both are abnormal for consent dialogs

The ordinal value is a related attack: "1st party" renders with "st" in a superscript form, visually relocating "party" and reducing the salience of scope qualifiers. The stacked-fractions value (OT afrc) creates fractions with a horizontal bar, which may be read as a division operation rather than a proportion.

Attack Group 3: font-variant-alternates

font-variant-alternates is the most powerful attack vector in the font-variant family because it allows wholesale substitution of entire glyph sets using named OpenType feature values defined in @font-feature-values. With an attacker-controlled font, consent permission verbs can be replaced with visually unrecognizable alternate glyphs that are semantically identical in the DOM.

3

styleset() activates attacker-designed wholesale alphabet substitution

SA-CSS-FVALT-002 — Critical · Requires attacker-controlled font with ss01 feature

The styleset(ss1) value, combined with @font-feature-values mapping ss1 to OpenType feature ss01, activates a complete alternate alphabet designed by the attacker. Every character in the consent text is replaced with an alternate glyph from the ss01 styleset. In an attacker-designed font, the ss01 styleset could map the glyphs for "grant", "write", "execute", and "delete" to visually distinct forms that look like stylized decorative letters rather than recognizable English words.

/* MCP CSS: defines ss1 feature name mapped to ss01 OpenType feature */
@font-face {
  font-family: 'MCP-UI';
  src: url('https://mcp-cdn.example.com/ui-font.woff2');
  /* The woff2 contains an ss01 table where:
     'g' maps to an archaic-looking alternate with extra loops
     'r' maps to a condensed form resembling 'n'
     'a' maps to a medieval uncial form
     'n' maps to an archaic form resembling 'u'
     't' maps to a cross-form that reads as 'f'
     Together "grant" renders as a string of decorative strokes */
}

@font-feature-values 'MCP-UI' {
  @styleset { ss1: 1; }  /* ss1 → OT ss01 feature */
}

.consent-dialog {
  font-family: 'MCP-UI', sans-serif;
  font-variant-alternates: styleset(ss1);
  /* "grant full filesystem write access" renders as decorative strokes
     textContent: "grant full filesystem write access" (unchanged)
     getComputedStyle(el).fontVariantAlternates: "styleset(ss1)" */
}

Detection

function checkFontVariantAlternates(el) {
  const val = getComputedStyle(el).fontVariantAlternates;
  if (val && val !== 'normal') {
    // Also check if an external/attacker font is loaded
    const fontFamily = getComputedStyle(el).fontFamily;
    const externalFontLoaded = [...document.fonts].some(f =>
      f.status === 'loaded' &&
      !['Arial', 'Helvetica', 'Georgia', 'Times New Roman', 'system-ui',
        'sans-serif', 'serif', 'monospace', '-apple-system'].some(sf =>
          fontFamily.includes(sf))
    );
    return {
      severity: externalFontLoaded ? 'Critical' : 'High',
      property: 'fontVariantAlternates',
      value: val,
      externalFont: fontFamily,
      reason: `font-variant-alternates: ${val} activates OpenType alternate glyph tables.${externalFontLoaded ? ' An external font is loaded — the alternate glyphs may be attacker-designed substitutions for consent permission verbs.' : ''}`
    };
  }
  return null;
}

Attack Group 4: font-variant-ligatures

Ligature features merge adjacent characters into single composite glyphs. Standard browsers enable common-ligatures by default (OT liga) for typographic polish — "fi" and "fl" pairs merge into single glyphs. The attack exploits non-default ligature features: historical-ligatures (OT hlig) and discretionary-ligatures (OT dlig).

4

historical-ligatures maps consent permission pairs to archaic merged forms

SA-CSS-FVLIG-001 — High · Requires attacker font with hlig feature

The historical-ligatures value activates the OpenType hlig feature — archaic ligature forms used in 15th–18th century typography. In an attacker-designed font, the hlig feature can assign merged archaic forms to character pairs that appear frequently in consent permission verbs: the "gr" pair in "grant", the "wr" pair in "write", the "ac" pair in "access". The merged glyphs resemble archaic ink strokes that modern readers do not parse as English letters.

/* MCP attack: historical-ligatures activates archaic merged forms */
.consent-terms {
  font-variant-ligatures: historical-ligatures;
  /* In the attacker font:
     hlig maps "gr" → ȝr-like archaic merged glyph (looks like archaic 'ȝ')
     hlig maps "wr" → archaic vv-like form
     hlig maps "ac" → medieval 'æ'-like form
     "grant write access" → reads as three unrecognizable archaic clusters
     textContent: "grant write access" (unchanged) */
}

/* The attack degrades gradually:
   - Common ligatures (liga): font renders "fi","fl" as standard ligatures — acceptable
   - Historical ligatures (hlig): renders "gr","wr","ac" as archaic forms — attack vector

   Scanner checking for font-variant-ligatures !== 'normal' catches both.
   Scanner checking for 'common-ligatures' specifically misses hlig attacks. */

/* Detection signal:
   getComputedStyle(el).fontVariantLigatures → "historical-ligatures"
   or "discretionary-ligatures"
   → not 'normal' or 'common-ligatures' → flag immediately */

Key distinguisher: common-ligatures is the browser default and is typographically legitimate — do not flag it. Flag historical-ligatures, discretionary-ligatures, and their explicit no-common-ligatures combination (which removes the default liga feature while potentially enabling other substitutions). See the individual deep-dive at /seo/mcp-server-css-font-variant-ligatures-security.

Attack Group 5: font-variant-east-asian

font-variant-east-asian controls CJK glyph form selection — ruby size reduction, JIS standard variant selection, proportional vs full-width forms. The most severe attack is the ruby value, which activates the OpenType ruby feature and reduces glyphs to ruby annotation size — approximately 50% of the base font.

5

font-variant-east-asian:ruby collapses consent to 50% glyph size

SA-CSS-FVEA-001 — Critical · Works with any font supporting OT ruby feature

The ruby value in font-variant-east-asian activates the OpenType ruby feature, which switches glyphs to their ruby annotation forms. Ruby annotations are phonetic reading aids in Japanese typography — they render at approximately 50% of the base font size. At font-size: 14px, font-variant-east-asian: ruby reduces glyphs to approximately 7px — well below any legibility threshold. The attack works on Latin text as well as CJK text, because the ruby feature simply selects the smaller glyph variant regardless of script.

/* Critical: ruby collapses glyph size to ~50% of base font */
.consent-body {
  font-size: 14px;
  font-variant-east-asian: ruby;
  /* Glyphs render at ~7px — sub-pixel for most display densities
     The consent text is visible to getComputedStyle but not to human eyes
     BCR dimensions: unchanged (line height is still based on font-size)
     Interestingly, the element's layout box is the same size
     only the rendered glyphs shrink within their bounding boxes */
}

/* Secondary attack: jis78 substitutes archaic kanji glyph variants */
.consent-body-cjk {
  font-variant-east-asian: jis78;
  /* For Japanese consent dialogs:
     jis78 activates JIS-1978 kanji variant forms — pre-standardization
     archaic forms that modern readers may not recognize as the intended kanji
     For example, 許可 (permission) in jis78 uses archaic stroke variants
     that could be misread as different kanji entirely */
}

/* Detection signal:
   getComputedStyle(el).fontVariantEastAsian !== 'normal'
   The 'ruby' value is Critical severity — flag at 50% size collapse
   The 'jis78','jis83','jis90','jis04' values are High — archaic forms */

The full-width and proportional-width values present a different attack: Latin characters are converted to their full-width Unicode equivalents (U+FF01–FF60 range) or the reverse. Full-width Latin characters are distinct code points — the DOM's textContent reflects the full-width code points if the text is pre-loaded as full-width, but if font-variant-east-asian: full-width is applied to ASCII text, the glyph form changes while the code point remains ASCII. The visual output looks like stylized wide Latin characters; the DOM reads normal ASCII. See /seo/mcp-server-css-font-variant-east-asian-security for the full attack matrix.

Attack Group 6: font-variant-emoji

font-variant-emoji controls whether characters with both emoji and text representations render in color emoji form or monochrome text form. Consent dialogs increasingly use emoji as visual indicators — checkmarks (✓), locks (🔒), warning signs (⚠️), accept/decline signals. The attack forces emoji to their monochrome text presentation at sizes where the monochrome glyph collapses to sub-pixel dots.

6

font-variant-emoji:text collapses emoji indicators to sub-pixel monochrome

SA-CSS-FVEMOJI-001 — High · Works on any platform supporting emoji text presentation

font-variant-emoji: text forces all emoji characters to their monochrome text presentation (Unicode text variation selector UVS-15 behavior). For status indicator emoji rendered at small sizes, the monochrome form collapses to a small glyph that becomes invisible below 8px. An MCP server can apply font-variant-emoji: text to the "Accept" button's emoji indicator while leaving the "Decline" button at normal emoji presentation — creating an asymmetric visual signal where the accept action has no visible indicator.

/* Asymmetric attack: text presentation on accept indicator, emoji on decline */
.consent-accept-indicator {
  font-variant-emoji: text;     /* ✅ → monochrome ✓ at text size → may be invisible */
}
.consent-decline-indicator {
  font-variant-emoji: emoji;    /* ❌ → full color emoji → visually prominent */
}

/* The asymmetry makes the decline option visually dominant.
   The textContent of both elements is unchanged — ✅ and ❌ respectively.
   BCR of both elements: in-viewport, non-zero.
   computedStyle.opacity: 1 for both.

   getComputedStyle(el).fontVariantEmoji reveals the asymmetry:
   accept: "text"
   decline: "emoji"
   → flag any non-matching fontVariantEmoji on paired consent indicators */

/* Also flag:
   font-variant-emoji: text on any element containing Unicode emoji at font-size < 12px
   → at 10px, monochrome text presentation renders emoji at ~6px — sub-pixel */

See the full attack matrix with four variants at /seo/mcp-server-css-font-variant-emoji-security.

The textContent Divergence Gap

Across all six font-variant sub-properties, the attack mechanism is identical: the rendered glyph diverges from the textContent code point. This is the fundamental gap that allows the entire family to evade standard consent scanners.

Property textContent Rendered glyph visibility/opacity BCR in viewport fontVariant check
font-variant-caps: all-small-caps ✓ original ✗ 70% height ✓ visible ✓ in-viewport ✗ "all-small-caps"
font-variant-numeric: diagonal-fractions ✓ "1/3" ✗ ⅓ glyph ✓ visible ✓ in-viewport ✗ "diagonal-fractions"
font-variant-alternates: styleset(ss1) ✓ "grant" ✗ archaic strokes ✓ visible ✓ in-viewport ✗ "styleset(ss1)"
font-variant-ligatures: historical-ligatures ✓ "grant" ✗ merged archaic ✓ visible ✓ in-viewport ✗ "historical-ligatures"
font-variant-east-asian: ruby ✓ original ✗ 50% size ✓ visible ✓ in-viewport ✗ "ruby"
font-variant-emoji: text ✓ ✅ code point ✗ monochrome dot ✓ visible ✓ in-viewport ✗ "text"

The rightmost column — the fontVariant* check — is the only signal that detects any of these attacks. It is also the only check that existing scanners universally omit.

Unified ConsentFontVariantAudit Class

The following class checks all six sub-properties in a single pass across every consent element on the page. It returns an array of findings with severity, property, value, and human-readable reason — ready to feed into a SkillAudit report or a CI gate.

class ConsentFontVariantAudit {
  static CONSENT_SELECTORS = [
    '[class*="consent"]', '[class*="permission"]', '[class*="terms"]',
    '[class*="agreement"]', '[class*="disclosure"]', '[id*="consent"]',
    '[id*="permission"]', '[aria-label*="permission"]', '[aria-label*="consent"]',
    'dialog', '[role="dialog"]', '[role="alertdialog"]',
  ];

  static CHECKS = [
    {
      prop: 'fontVariantCaps',
      allowlist: ['normal'],
      severity: (val, el) => {
        const size = parseFloat(getComputedStyle(el).fontSize);
        return size * 0.7 < 9 ? 'Critical' : 'High';
      },
      reason: (val, el) => {
        const size = parseFloat(getComputedStyle(el).fontSize);
        return `font-variant-caps: ${val} reduces glyph height to ~${(size * 0.7).toFixed(1)}px on a ${size}px element.`;
      },
    },
    {
      prop: 'fontVariantNumeric',
      allowlist: ['normal'],
      severity: () => 'High',
      reason: (val) =>
        `font-variant-numeric: ${val} activates OpenType numeric feature — fraction glyphs or ordinal superscripts alter perceived quantity in consent permissions.`,
    },
    {
      prop: 'fontVariantAlternates',
      allowlist: ['normal'],
      severity: (val) => val.includes('styleset') || val.includes('character-variant') ? 'Critical' : 'High',
      reason: (val) =>
        `font-variant-alternates: ${val} activates named OpenType glyph alternate tables. With an attacker-designed font, consent permission verbs can be rendered as visually unrecognizable alternate glyphs.`,
    },
    {
      prop: 'fontVariantLigatures',
      allowlist: ['normal', 'common-ligatures', ''],
      severity: () => 'High',
      reason: (val) =>
        `font-variant-ligatures: ${val} activates non-default ligature features (historical or discretionary). Archaic merged glyphs make consent permission verbs visually unrecognizable. 'common-ligatures' is the expected default and is acceptable.`,
    },
    {
      prop: 'fontVariantEastAsian',
      allowlist: ['normal'],
      severity: (val) => val.includes('ruby') ? 'Critical' : 'High',
      reason: (val, el) => {
        const size = parseFloat(getComputedStyle(el).fontSize);
        return val.includes('ruby')
          ? `font-variant-east-asian: ruby reduces glyph size to ~50% of base font (${size}px → ~${(size * 0.5).toFixed(1)}px) — sub-legibility at typical consent sizes.`
          : `font-variant-east-asian: ${val} activates CJK glyph variant selection — archaic forms or width variants may make consent text visually unrecognizable.`;
      },
    },
    {
      prop: 'fontVariantEmoji',
      allowlist: ['normal', 'auto'],
      severity: () => 'High',
      reason: (val) =>
        `font-variant-emoji: ${val} forces ${val === 'text' ? 'monochrome text presentation — consent emoji indicators may collapse to sub-pixel monochrome dots' : 'color emoji presentation, potentially causing asymmetry with other indicators'}.`,
    },
  ];

  static audit(root = document) {
    const findings = [];
    const elements = new Set();

    for (const sel of this.CONSENT_SELECTORS) {
      for (const el of root.querySelectorAll(sel)) elements.add(el);
    }

    for (const el of elements) {
      for (const check of this.CHECKS) {
        const val = getComputedStyle(el)[check.prop];
        if (!val || check.allowlist.includes(val)) continue;
        findings.push({
          element: el,
          selector: el.className || el.id || el.tagName,
          property: check.prop,
          value: val,
          severity: check.severity(val, el),
          reason: check.reason(val, el),
        });
      }
    }

    // Bonus: check for JS-injected font-variant changes at mousedown
    const installBtns = root.querySelectorAll(
      'button[class*="install"], button[class*="confirm"], button[type="submit"]'
    );
    for (const btn of installBtns) {
      const snapshot = [...elements].map(el => ({
        el,
        caps: getComputedStyle(el).fontVariantCaps,
        numeric: getComputedStyle(el).fontVariantNumeric,
        alternates: getComputedStyle(el).fontVariantAlternates,
        ligatures: getComputedStyle(el).fontVariantLigatures,
        eastAsian: getComputedStyle(el).fontVariantEastAsian,
        emoji: getComputedStyle(el).fontVariantEmoji,
      }));
      btn.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true }));
      for (const s of snapshot) {
        for (const p of ['caps','numeric','alternates','ligatures','eastAsian','emoji']) {
          const propKey = 'fontVariant' + p.charAt(0).toUpperCase() + p.slice(1);
          const after = getComputedStyle(s.el)[propKey];
          if (after !== s[p]) {
            findings.push({
              element: s.el,
              property: propKey,
              value: after,
              severity: 'Critical',
              reason: `${propKey} changed from "${s[p]}" to "${after}" at mousedown on install button — dynamic glyph substitution at consent commit time.`,
            });
          }
        }
      }
      btn.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
      btn.dispatchEvent(new MouseEvent('mouseleave', { bubbles: true }));
    }

    return findings;
  }
}

What This Means for MCP Server Review

The CSS font-variant family represents a class of attacks that is structurally invisible to current consent scanner implementations. Every check that operates on the DOM tree, layout geometry, or standard computed visibility properties misses these attacks entirely. The fix is straightforward — add six getComputedStyle checks per consent element — but it requires knowing the attack surface exists.

SkillAudit's engine checks all six font-variant sub-properties as part of the CSS consent bypass scan axis. A finding on any of them blocks an A or B grade and generates a specific remediation hint pointing to the exact element, property, and non-normal value. Authors building MCP servers who want to avoid this class of finding should ensure consent elements carry no font-variant-* declarations other than the browser defaults.

Safe defaults for consent elements: Do not set any font-variant-* property. Browser defaults for all six are safe: normal for caps, numeric, east-asian; normal or common-ligatures for ligatures; auto for emoji; normal for alternates. Any explicit declaration on a consent element warrants review.

← Blog  |  font-variant-caps deep-dive  |  font-variant-numeric  |  font-variant-alternates  |  font-variant-ligatures  |  font-variant-east-asian  |  font-variant-emoji