diff --git a/packages/layout-engine/style-engine/src/ooxml/index.test.ts b/packages/layout-engine/style-engine/src/ooxml/index.test.ts
index 7cd3505210..0286290c44 100644
--- a/packages/layout-engine/style-engine/src/ooxml/index.test.ts
+++ b/packages/layout-engine/style-engine/src/ooxml/index.test.ts
@@ -886,6 +886,92 @@ describe('ooxml - resolveTableCellProperties basedOn tblStylePr inheritance', ()
});
});
+// ──────────────────────────────────────────────────────────────────────────────
+// Style base-level tcPr as the wholeTable layer (ECMA-376 17.7.6, SD-3035)
+// A table style's base-level is stored on the style
+// def's own tableCellProperties (sibling of tableStyleProperties) and IS the
+// wholeTable conditional layer. Word paints it on every cell.
+// ──────────────────────────────────────────────────────────────────────────────
+
+describe('ooxml - style base-level tcPr surfaces as wholeTable (SD-3035)', () => {
+ const interiorCell = (styleId: string) => ({
+ tableProperties: { tableStyleId: styleId, tblLook: { noHBand: true, noVBand: true } },
+ rowIndex: 1,
+ cellIndex: 1,
+ numRows: 3,
+ numCells: 3,
+ });
+
+ it('resolves a base-level shading with no explicit wholeTable region', () => {
+ const styles = {
+ ...emptyStyles,
+ styles: {
+ CondStyle: {
+ type: 'table',
+ tableProperties: {},
+ tableCellProperties: { shading: { val: 'clear', color: 'auto', fill: 'F2F2F2' } },
+ },
+ },
+ };
+ const result = resolveTableCellProperties(null, interiorCell('CondStyle'), styles);
+ expect(result.shading).toEqual({ val: 'clear', color: 'auto', fill: 'F2F2F2' });
+ });
+
+ it('leaf base-level shading beats an ancestor base-level shading via basedOn', () => {
+ const styles = {
+ ...emptyStyles,
+ styles: {
+ BaseStyle: {
+ type: 'table',
+ tableProperties: {},
+ tableCellProperties: { shading: { fill: 'AAAAAA' } },
+ },
+ LeafStyle: {
+ type: 'table',
+ basedOn: 'BaseStyle',
+ tableProperties: {},
+ tableCellProperties: { shading: { fill: 'F2F2F2' } },
+ },
+ },
+ };
+ const result = resolveTableCellProperties(null, interiorCell('LeafStyle'), styles);
+ expect(result.shading).toEqual({ fill: 'F2F2F2' });
+ });
+
+ it('an explicit tableStyleProperties.wholeTable entry beats the base-level tcPr', () => {
+ const styles = {
+ ...emptyStyles,
+ styles: {
+ CondStyle: {
+ type: 'table',
+ tableProperties: {},
+ tableCellProperties: { shading: { fill: 'BASE99' } },
+ tableStyleProperties: {
+ wholeTable: { tableCellProperties: { shading: { fill: 'EXPL77' } } },
+ },
+ },
+ },
+ };
+ const result = resolveTableCellProperties(null, interiorCell('CondStyle'), styles);
+ expect(result.shading).toEqual({ fill: 'EXPL77' });
+ });
+
+ it('inline cell shading still wins over the base-level wholeTable fill', () => {
+ const styles = {
+ ...emptyStyles,
+ styles: {
+ CondStyle: {
+ type: 'table',
+ tableProperties: {},
+ tableCellProperties: { shading: { fill: 'F2F2F2' } },
+ },
+ },
+ };
+ const result = resolveTableCellProperties({ shading: { fill: '4472C4' } }, interiorCell('CondStyle'), styles);
+ expect(result.shading).toEqual({ fill: '4472C4' });
+ });
+});
+
// ──────────────────────────────────────────────────────────────────────────────
// cnfStyle supplementing index-based conditional type detection
// ──────────────────────────────────────────────────────────────────────────────
diff --git a/packages/layout-engine/style-engine/src/ooxml/index.ts b/packages/layout-engine/style-engine/src/ooxml/index.ts
index 0791ee9472..0f28d8cbd4 100644
--- a/packages/layout-engine/style-engine/src/ooxml/index.ts
+++ b/packages/layout-engine/style-engine/src/ooxml/index.ts
@@ -483,6 +483,15 @@ function resolveConditionalProps(
const def: StyleDefinition | undefined = translatedLinkedStyles.styles?.[currentId];
const props = def?.tableStyleProperties?.[styleType]?.[propertyType] as T | undefined;
if (props) chain.push(props);
+ // ECMA-376 17.7.6: a table style's BASE-LEVEL (stored on the def's own
+ // tableCellProperties, a sibling of tableStyleProperties) IS the wholeTable
+ // conditional layer; Word paints e.g. its w:shd on every cell. Pushed after the
+ // explicit wholeTable entry so, post-reverse, the explicit entry still wins within
+ // one def while a leaf's base props beat any ancestor's. (SD-3035)
+ if (styleType === 'wholeTable' && propertyType === 'tableCellProperties') {
+ const baseProps = def?.tableCellProperties as T | undefined;
+ if (baseProps) chain.push(baseProps);
+ }
currentId = def?.basedOn;
}
if (chain.length === 0) return undefined;