/**
 * CSS変数生成ヘルパー関数
 * buttonBasic, textBasic 等の複数ブロックで使用
 */

import { getEnabledBreakpoints } from '../../../core/breakpoints';
import { hexToRgba } from '../components/CustomColorPalette';

// alpha値を考慮した色の値を取得するヘルパー
const getColorWithAlpha = (color, alpha) => {
  if (!color) return "";
  const alphaVal = alpha !== undefined ? alpha : 1;
  if (alphaVal < 1) {
    return hexToRgba(color, alphaVal);
  }
  return color;
};

const getFontSizeV2Value = (fontSizeV2, breakpoint, useDefault = false) => {
  if (!fontSizeV2 || !fontSizeV2[breakpoint]) {
    return useDefault ? '1rem' : '';
  }
  
  const { preset, custom, unit } = fontSizeV2[breakpoint];
  
  if (preset === 'custom' && custom) {
    return `${custom}${unit || 'px'}`;
  } else if (preset && preset !== '' && preset !== 'custom') {
    if (preset.startsWith('preset:')) {
      const slug = preset.replace('preset:', '');
      return `var(--wp--preset--font-size--${slug})`;
    }
    return `${preset}${unit || 'px'}`;
  }
  
  return useDefault ? '1rem' : '';
};

const getFontSizeWithInheritance = (attributes, device, isHover = false) => {
  if (!attributes) return '';
  
  const v2Key = isHover ? 'fontSizeV2Hover' : 'fontSizeV2';
  const fontSizeData = attributes[v2Key];
  
  if (!fontSizeData) return '';

  const enabledBreakpoints = getEnabledBreakpoints();
  const currentIndex = enabledBreakpoints.indexOf(device);
  
  for (let i = currentIndex; i >= 0; i--) {
    const bp = enabledBreakpoints[i];
    const value = getFontSizeV2Value(fontSizeData, bp);
    if (value) return value;
  }
  
  return '';
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getFontSizeStyles = (attributes) => {
  const styles = {};
  const pcValue = getFontSizeV2Value(attributes.fontSizeV2, 'pc', true);
  styles['--font-size-pc'] = pcValue;
  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getFontSizeStylesForEditor = (attributes, previewDevice = 'pc') => {
  const styles = {};
  // プレビューデバイスの値を取得（フォールバック付き）
  const value = getFontSizeWithInheritance(attributes, previewDevice);
  // PC変数名で出力、値はプレビューデバイスの値
  styles['--font-size-pc'] = value || getFontSizeV2Value(attributes.fontSizeV2, 'pc', true);
  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getFontSizeHoverStyles = (attributes) => {
  const styles = {};
  const pcHoverValue = getFontSizeV2Value(attributes.fontSizeV2Hover, 'pc', false);
  if (pcHoverValue) {
    styles['--font-size-pc-hover'] = pcHoverValue;
  }
  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getFontSizeHoverStylesForEditor = (attributes, previewDevice = 'pc') => {
  const styles = {};
  // プレビューデバイスの値を取得（フォールバック付き）
  const hoverValue = getFontSizeWithInheritance(attributes, previewDevice, true);
  if (hoverValue) {
    // PC変数名で出力、値はプレビューデバイスの値
    styles['--font-size-pc-hover'] = hoverValue;
  }
  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getBorderStyles = (attributes, { skipDefaults = false } = {}) => {
  const data = attributes.borderV2;
  if (!data) return {};
  const styles = {};

  // Get PC values
  const pcWidth = getV2ValueWithInheritance(data, 'pc', "width", 0);
  const pcStyle = getV2ValueWithInheritance(data, 'pc', "style", "none");
  const pcColor = getV2ValueWithInheritance(data, 'pc', "color", "transparent");
  const pcColorAlpha = getV2ValueWithInheritance(data, 'pc', "colorAlpha", 1);
  const pcBoxSizing = getV2ValueWithInheritance(data, 'pc', "boxSizing", "border-box");

  const pcColorValue = pcColor === "transparent" ? "transparent" : hexToRgba(pcColor, pcColorAlpha);
  if (!skipDefaults || pcWidth !== 0) {
    styles['--styling-border-width-pc'] = `${pcWidth}px`;
  }
  if (!skipDefaults || pcStyle !== "none") {
    styles['--styling-border-style-pc'] = pcStyle;
  }
  if (!skipDefaults || pcColorValue !== "transparent") {
    styles['--styling-border-color-pc'] = pcColorValue;
  }
  if (!skipDefaults || pcBoxSizing !== "border-box") {
    styles['--styling-box-sizing-pc'] = pcBoxSizing;
  }

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getBorderStylesForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.borderV2;
  if (!data) return {};
  const styles = {};

  // プレビューデバイスの値を取得（フォールバック付き）
  const width = getV2ValueWithInheritance(data, previewDevice, "width", 0);
  const style = getV2ValueWithInheritance(data, previewDevice, "style", "none");
  const color = getV2ValueWithInheritance(data, previewDevice, "color", "transparent");
  const colorAlpha = getV2ValueWithInheritance(data, previewDevice, "colorAlpha", 1);
  const boxSizing = getV2ValueWithInheritance(data, previewDevice, "boxSizing", "border-box");

  // PC変数名で出力、値はプレビューデバイスの値（デフォルト値は省略）
  const colorValue = color === "transparent" ? "transparent" : hexToRgba(color, colorAlpha);
  if (width !== 0) {
    styles['--styling-border-width-pc'] = `${width}px`;
  }
  if (style !== "none") {
    styles['--styling-border-style-pc'] = style;
  }
  if (colorValue !== "transparent") {
    styles['--styling-border-color-pc'] = colorValue;
  }
  if (boxSizing !== "border-box") {
    styles['--styling-box-sizing-pc'] = boxSizing;
  }

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getBorderHoverStyles = (attributes, { skipDefaults = false } = {}) => {
  const data = attributes.borderV2Hover;
  const normalData = attributes.borderV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal
  const getHoverValue = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  // Get PC values
  const pcWidth = getHoverValue('pc', "width", 0);
  const pcStyle = getHoverValue('pc', "style", "none");
  const pcColor = getHoverValue('pc', "color", "transparent");
  const pcColorAlpha = getHoverValue('pc', "colorAlpha", 1);

  const pcColorValue = pcColor === "transparent" ? "transparent" : hexToRgba(pcColor, pcColorAlpha);
  if (!skipDefaults || pcWidth !== 0) {
    styles['--styling-border-width-pc-hover'] = `${pcWidth}px`;
  }
  if (!skipDefaults || pcStyle !== "none") {
    styles['--styling-border-style-pc-hover'] = pcStyle;
  }
  if (!skipDefaults || pcColorValue !== "transparent") {
    styles['--styling-border-color-pc-hover'] = pcColorValue;
  }

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getBorderHoverStylesForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.borderV2Hover;
  const normalData = attributes.borderV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal
  const getHoverValue = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  // プレビューデバイスの値を取得（フォールバック付き）
  const width = getHoverValue(previewDevice, "width", 0);
  const style = getHoverValue(previewDevice, "style", "none");
  const color = getHoverValue(previewDevice, "color", "transparent");
  const colorAlpha = getHoverValue(previewDevice, "colorAlpha", 1);

  // PC変数名で出力、値はプレビューデバイスの値（デフォルト値は省略）
  const colorHoverValue = color === "transparent" ? "transparent" : hexToRgba(color, colorAlpha);
  if (width !== 0) {
    styles['--styling-border-width-pc-hover'] = `${width}px`;
  }
  if (style !== "none") {
    styles['--styling-border-style-pc-hover'] = style;
  }
  if (colorHoverValue !== "transparent") {
    styles['--styling-border-color-pc-hover'] = colorHoverValue;
  }

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getRadiusStyles = (attributes, { skipDefaults = false } = {}) => {
  const data = attributes.radiusV2;
  if (!data) return {};
  const styles = {};
  const enabledBreakpoints = getEnabledBreakpoints();
  const corners = ['topLeft', 'topRight', 'bottomRight', 'bottomLeft'];

  // Helper to get value with inheritance from upper breakpoints
  const getInheritedValue = (bp, key, defaultVal) => {
    const currentIndex = enabledBreakpoints.indexOf(bp);
    for (let i = currentIndex; i >= 0; i--) {
      const checkBp = enabledBreakpoints[i];
      const bpData = data[checkBp];
      if (bpData && bpData[key] !== "" && bpData[key] !== undefined && bpData[key] !== null) {
        return bpData[key];
      }
    }
    return defaultVal;
  };

  // Get PC values only
  const pcBulk = getInheritedValue('pc', "bulk", 0);
  const pcBulkUnit = getInheritedValue('pc', "bulkUnit", "px") || "px";
  const pcUseIndividual = getInheritedValue('pc', "useIndividual", false);

  // ボーダー幅を取得（外側角丸計算用）
  const borderData = attributes.borderV2;
  const borderWidth = borderData ? getV2ValueWithInheritance(borderData, 'pc', "width", 0) : 0;

  const pcBulkStr = `${pcBulk}${pcBulkUnit}`;
  if (!skipDefaults || pcBulkStr !== "0px") {
    styles['--styling-radius-pc'] = pcBulkStr;
  }
  corners.forEach((corner) => {
    const cssCornerName = corner.replace(/([A-Z])/g, '-$1').toLowerCase();
    let cornerStr;
    let cornerValue;
    if (pcUseIndividual) {
      cornerValue = getInheritedValue('pc', corner, 0);
      const unit = getInheritedValue('pc', `${corner}Unit`, "px") || "px";
      cornerStr = `${cornerValue}${unit}`;
    } else {
      cornerValue = pcBulk;
      cornerStr = pcBulkStr;
    }
    if (!skipDefaults || cornerStr !== "0px") {
      styles[`--styling-radius-${cssCornerName}-pc`] = cornerStr;
    }
    // 外側角丸: 角丸が0のときは0、0以外のときは角丸+ボーダー幅
    const outerValue = Number(cornerValue) === 0 ? cornerStr : `${Number(cornerValue) + borderWidth}px`;
    if (!skipDefaults || outerValue !== "0px") {
      styles[`--styling-radius-outer-${cssCornerName}-pc`] = outerValue;
    }
  });

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getRadiusStylesForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.radiusV2;
  if (!data) return {};
  const styles = {};
  const enabledBreakpoints = getEnabledBreakpoints();
  const corners = ['topLeft', 'topRight', 'bottomRight', 'bottomLeft'];

  // Helper to get value with inheritance from upper breakpoints
  const getInheritedValue = (bp, key, defaultVal) => {
    const currentIndex = enabledBreakpoints.indexOf(bp);
    for (let i = currentIndex; i >= 0; i--) {
      const checkBp = enabledBreakpoints[i];
      const bpData = data[checkBp];
      if (bpData && bpData[key] !== "" && bpData[key] !== undefined && bpData[key] !== null) {
        return bpData[key];
      }
    }
    return defaultVal;
  };

  // プレビューデバイスの値を取得（フォールバック付き）
  const bulk = getInheritedValue(previewDevice, "bulk", 0);
  const bulkUnit = getInheritedValue(previewDevice, "bulkUnit", "px") || "px";
  const useIndividual = getInheritedValue(previewDevice, "useIndividual", false);

  // ボーダー幅を取得（外側角丸計算用）
  const borderData = attributes.borderV2;
  const borderWidth = borderData ? getV2ValueWithInheritance(borderData, previewDevice, "width", 0) : 0;

  // PC変数名で出力、値はプレビューデバイスの値（デフォルト値は省略）
  const bulkStr = `${bulk}${bulkUnit}`;
  if (bulkStr !== "0px") {
    styles['--styling-radius-pc'] = bulkStr;
  }
  corners.forEach((corner) => {
    const cssCornerName = corner.replace(/([A-Z])/g, '-$1').toLowerCase();
    let cornerStr;
    let cornerValue;
    if (useIndividual) {
      cornerValue = getInheritedValue(previewDevice, corner, 0);
      const unit = getInheritedValue(previewDevice, `${corner}Unit`, "px") || "px";
      cornerStr = `${cornerValue}${unit}`;
    } else {
      cornerValue = bulk;
      cornerStr = bulkStr;
    }
    if (cornerStr !== "0px") {
      styles[`--styling-radius-${cssCornerName}-pc`] = cornerStr;
    }
    // 外側角丸: 角丸が0のときは0、0以外のときは角丸+ボーダー幅
    const outerValue = Number(cornerValue) === 0 ? cornerStr : `${Number(cornerValue) + borderWidth}px`;
    if (outerValue !== "0px") {
      styles[`--styling-radius-outer-${cssCornerName}-pc`] = outerValue;
    }
  });

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getRadiusHoverStyles = (attributes, { skipDefaults = false } = {}) => {
  const data = attributes.radiusV2Hover;
  const normalData = attributes.radiusV2;
  if (!data && !normalData) return {};
  const styles = {};
  const enabledBreakpoints = getEnabledBreakpoints();
  const corners = ['topLeft', 'topRight', 'bottomRight', 'bottomLeft'];

  // Helper to get hover value with inheritance (hover → normal → upper breakpoints)
  const getInheritedHoverValue = (bp, key, defaultVal) => {
    const currentIndex = enabledBreakpoints.indexOf(bp);
    // First check hover data with inheritance
    for (let i = currentIndex; i >= 0; i--) {
      const checkBp = enabledBreakpoints[i];
      const hoverBpData = data ? data[checkBp] : null;
      if (hoverBpData && hoverBpData[key] !== "" && hoverBpData[key] !== undefined && hoverBpData[key] !== null) {
        return hoverBpData[key];
      }
    }
    // Then check normal data with inheritance
    for (let i = currentIndex; i >= 0; i--) {
      const checkBp = enabledBreakpoints[i];
      const normalBpData = normalData ? normalData[checkBp] : null;
      if (normalBpData && normalBpData[key] !== "" && normalBpData[key] !== undefined && normalBpData[key] !== null) {
        return normalBpData[key];
      }
    }
    return defaultVal;
  };

  // Get PC values only
  const pcBulk = getInheritedHoverValue('pc', "bulk", 0);
  const pcBulkUnit = getInheritedHoverValue('pc', "bulkUnit", "px") || "px";
  const pcUseIndividual = getInheritedHoverValue('pc', "useIndividual", false);

  const pcBulkStr = `${pcBulk}${pcBulkUnit}`;
  if (!skipDefaults || pcBulkStr !== "0px") {
    styles['--styling-radius-pc-hover'] = pcBulkStr;
  }
  corners.forEach((corner) => {
    const cssCornerName = corner.replace(/([A-Z])/g, '-$1').toLowerCase();
    let cornerStr;
    if (pcUseIndividual) {
      const value = getInheritedHoverValue('pc', corner, 0);
      const unit = getInheritedHoverValue('pc', `${corner}Unit`, "px") || "px";
      cornerStr = `${value}${unit}`;
    } else {
      cornerStr = pcBulkStr;
    }
    if (!skipDefaults || cornerStr !== "0px") {
      styles[`--styling-radius-${cssCornerName}-pc-hover`] = cornerStr;
    }
  });

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getRadiusHoverStylesForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.radiusV2Hover;
  const normalData = attributes.radiusV2;
  if (!data && !normalData) return {};
  const styles = {};
  const enabledBreakpoints = getEnabledBreakpoints();
  const corners = ['topLeft', 'topRight', 'bottomRight', 'bottomLeft'];

  // Helper to get hover value with inheritance (hover → normal → upper breakpoints)
  const getInheritedHoverValue = (bp, key, defaultVal) => {
    const currentIndex = enabledBreakpoints.indexOf(bp);
    // First check hover data with inheritance
    for (let i = currentIndex; i >= 0; i--) {
      const checkBp = enabledBreakpoints[i];
      const hoverBpData = data ? data[checkBp] : null;
      if (hoverBpData && hoverBpData[key] !== "" && hoverBpData[key] !== undefined && hoverBpData[key] !== null) {
        return hoverBpData[key];
      }
    }
    // Then check normal data with inheritance
    for (let i = currentIndex; i >= 0; i--) {
      const checkBp = enabledBreakpoints[i];
      const normalBpData = normalData ? normalData[checkBp] : null;
      if (normalBpData && normalBpData[key] !== "" && normalBpData[key] !== undefined && normalBpData[key] !== null) {
        return normalBpData[key];
      }
    }
    return defaultVal;
  };

  // プレビューデバイスの値を取得（フォールバック付き）
  const bulk = getInheritedHoverValue(previewDevice, "bulk", 0);
  const bulkUnit = getInheritedHoverValue(previewDevice, "bulkUnit", "px") || "px";
  const useIndividual = getInheritedHoverValue(previewDevice, "useIndividual", false);

  // PC変数名で出力、値はプレビューデバイスの値（デフォルト値は省略）
  const bulkStr = `${bulk}${bulkUnit}`;
  if (bulkStr !== "0px") {
    styles['--styling-radius-pc-hover'] = bulkStr;
  }
  corners.forEach((corner) => {
    const cssCornerName = corner.replace(/([A-Z])/g, '-$1').toLowerCase();
    let cornerStr;
    if (useIndividual) {
      const value = getInheritedHoverValue(previewDevice, corner, 0);
      const unit = getInheritedHoverValue(previewDevice, `${corner}Unit`, "px") || "px";
      cornerStr = `${value}${unit}`;
    } else {
      cornerStr = bulkStr;
    }
    if (cornerStr !== "0px") {
      styles[`--styling-radius-${cssCornerName}-pc-hover`] = cornerStr;
    }
  });

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getShadowStyles = (attributes, { skipDefaults = false } = {}) => {
  const data = attributes.shadowV2;
  if (!data) return {};
  const styles = {};

  const getShadowValueWithInheritance = (bp) => {
    const use = getV2ValueWithInheritance(data, bp, "use", false);
    if (use === undefined || use === null || use === '' || use === false) return "none";
    const horizontal = getV2ValueWithInheritance(data, bp, "horizontal", 0);
    const vertical = getV2ValueWithInheritance(data, bp, "vertical", 0);
    const blur = getV2ValueWithInheritance(data, bp, "blur", 0);
    const spread = getV2ValueWithInheritance(data, bp, "spread", 0);
    const color = getV2ValueWithInheritance(data, bp, "color", "transparent");
    const colorAlpha = getV2ValueWithInheritance(data, bp, "colorAlpha", 0.2);
    const inset = getV2ValueWithInheritance(data, bp, "inset", false);
    const insetStr = inset ? "inset " : "";
    const colorWithAlpha = color === "transparent" ? "transparent" : hexToRgba(color, colorAlpha);
    return `${insetStr}${horizontal}px ${vertical}px ${blur}px ${spread}px ${colorWithAlpha}`;
  };

  // Get PC value only
  const shadowValue = getShadowValueWithInheritance('pc');
  if (!skipDefaults || shadowValue !== "none") {
    styles['--styling-shadow-pc'] = shadowValue;
  }
  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getShadowStylesForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.shadowV2;
  if (!data) return {};
  const styles = {};

  const getShadowValueWithInheritance = (bp) => {
    const use = getV2ValueWithInheritance(data, bp, "use", false);
    if (use === undefined || use === null || use === '' || use === false) return "none";
    const horizontal = getV2ValueWithInheritance(data, bp, "horizontal", 0);
    const vertical = getV2ValueWithInheritance(data, bp, "vertical", 0);
    const blur = getV2ValueWithInheritance(data, bp, "blur", 0);
    const spread = getV2ValueWithInheritance(data, bp, "spread", 0);
    const color = getV2ValueWithInheritance(data, bp, "color", "transparent");
    const colorAlpha = getV2ValueWithInheritance(data, bp, "colorAlpha", 0.2);
    const inset = getV2ValueWithInheritance(data, bp, "inset", false);
    const insetStr = inset ? "inset " : "";
    const colorWithAlpha = color === "transparent" ? "transparent" : hexToRgba(color, colorAlpha);
    return `${insetStr}${horizontal}px ${vertical}px ${blur}px ${spread}px ${colorWithAlpha}`;
  };

  // PC変数名で出力、値はプレビューデバイスの値（デフォルト値は省略）
  const shadowValue = getShadowValueWithInheritance(previewDevice);
  if (shadowValue !== "none") {
    styles['--styling-shadow-pc'] = shadowValue;
  }
  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getInnerShadowStyles = (attributes, { skipDefaults = false } = {}) => {
  const innerData = attributes.innerShadowV2;
  const innerEnabled = attributes.innerShadowEnabled;
  if (!innerEnabled || !innerData) return {};
  const styles = {};

  const getInnerShadowValueWithInheritance = (bp) => {
    const use = getV2ValueWithInheritance(innerData, bp, "use", false);
    if (use === undefined || use === null || use === '' || use === false) return "none";
    const horizontal = getV2ValueWithInheritance(innerData, bp, "horizontal", 0);
    const vertical = getV2ValueWithInheritance(innerData, bp, "vertical", 0);
    const blur = getV2ValueWithInheritance(innerData, bp, "blur", 0);
    const spread = getV2ValueWithInheritance(innerData, bp, "spread", 0);
    const color = getV2ValueWithInheritance(innerData, bp, "color", "transparent");
    const colorAlpha = getV2ValueWithInheritance(innerData, bp, "colorAlpha", 1);
    const colorWithAlpha = color === "transparent" ? "transparent" : hexToRgba(color, colorAlpha);
    return `inset ${horizontal}px ${vertical}px ${blur}px ${spread}px ${colorWithAlpha}`;
  };

  // PCのみ出力（フォールバック付き）
  // MD/TB/SP用はPHP CSS Generatorで生成
  const innerShadowValue = getInnerShadowValueWithInheritance('pc');
  if (!skipDefaults || innerShadowValue !== "none") {
    styles['--styling-inner-shadow-pc'] = innerShadowValue;
  }
  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getInnerShadowStylesForEditor = (attributes, previewDevice = 'pc') => {
  const innerData = attributes.innerShadowV2;
  const innerEnabled = attributes.innerShadowEnabled;
  if (!innerEnabled || !innerData) return {};
  const styles = {};

  const getInnerShadowValueWithInheritance = (bp) => {
    const use = getV2ValueWithInheritance(innerData, bp, "use", false);
    if (use === undefined || use === null || use === '' || use === false) return "none";
    const horizontal = getV2ValueWithInheritance(innerData, bp, "horizontal", 0);
    const vertical = getV2ValueWithInheritance(innerData, bp, "vertical", 0);
    const blur = getV2ValueWithInheritance(innerData, bp, "blur", 0);
    const spread = getV2ValueWithInheritance(innerData, bp, "spread", 0);
    const color = getV2ValueWithInheritance(innerData, bp, "color", "transparent");
    const colorAlpha = getV2ValueWithInheritance(innerData, bp, "colorAlpha", 1);
    const colorWithAlpha = color === "transparent" ? "transparent" : hexToRgba(color, colorAlpha);
    return `inset ${horizontal}px ${vertical}px ${blur}px ${spread}px ${colorWithAlpha}`;
  };

  // PC変数名で出力、値はプレビューデバイスの値（デフォルト値は省略）
  const innerShadowValue = getInnerShadowValueWithInheritance(previewDevice);
  if (innerShadowValue !== "none") {
    styles['--styling-inner-shadow-pc'] = innerShadowValue;
  }
  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getShadowHoverStyles = (attributes, { skipDefaults = false } = {}) => {
  const data = attributes.shadowV2Hover;
  const normalData = attributes.shadowV2;
  const hoverEnabled = attributes.shadowEnabledHover;

  if (hoverEnabled === false) {
    // "none" is the SCSS fallback default - skip when optimizing
    if (skipDefaults) return {};
    return { '--styling-shadow-pc-hover': 'none' };
  }
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get value with inheritance, preferring hover data over normal
  const getHoverValueWithInheritance = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  const getShadowValueWithInheritance = (bp) => {
    const use = getHoverValueWithInheritance(bp, "use", false);
    if (use === undefined || use === null || use === '' || use === false) return "none";
    const horizontal = getHoverValueWithInheritance(bp, "horizontal", 0);
    const vertical = getHoverValueWithInheritance(bp, "vertical", 0);
    const blur = getHoverValueWithInheritance(bp, "blur", 0);
    const spread = getHoverValueWithInheritance(bp, "spread", 0);
    const color = getHoverValueWithInheritance(bp, "color", "transparent");
    const colorAlpha = getHoverValueWithInheritance(bp, "colorAlpha", 0.2);
    const inset = getHoverValueWithInheritance(bp, "inset", false);
    const insetStr = inset ? "inset " : "";
    const colorWithAlpha = color === "transparent" ? "transparent" : hexToRgba(color, colorAlpha);
    return `${insetStr}${horizontal}px ${vertical}px ${blur}px ${spread}px ${colorWithAlpha}`;
  };

  // Get PC value only
  const shadowHoverValue = getShadowValueWithInheritance('pc');
  if (!skipDefaults || shadowHoverValue !== "none") {
    styles['--styling-shadow-pc-hover'] = shadowHoverValue;
  }
  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getShadowHoverStylesForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.shadowV2Hover;
  const normalData = attributes.shadowV2;
  const hoverEnabled = attributes.shadowEnabledHover;

  // デフォルト値（none）は省略 - SCSSフォールバックが適用される
  if (hoverEnabled === false) {
    return {};
  }
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get value with inheritance, preferring hover data over normal
  const getHoverValueWithInheritance = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  const getShadowValueWithInheritance = (bp) => {
    const use = getHoverValueWithInheritance(bp, "use", false);
    if (use === undefined || use === null || use === '' || use === false) return "none";
    const horizontal = getHoverValueWithInheritance(bp, "horizontal", 0);
    const vertical = getHoverValueWithInheritance(bp, "vertical", 0);
    const blur = getHoverValueWithInheritance(bp, "blur", 0);
    const spread = getHoverValueWithInheritance(bp, "spread", 0);
    const color = getHoverValueWithInheritance(bp, "color", "transparent");
    const colorAlpha = getHoverValueWithInheritance(bp, "colorAlpha", 0.2);
    const inset = getHoverValueWithInheritance(bp, "inset", false);
    const insetStr = inset ? "inset " : "";
    const colorWithAlpha = color === "transparent" ? "transparent" : hexToRgba(color, colorAlpha);
    return `${insetStr}${horizontal}px ${vertical}px ${blur}px ${spread}px ${colorWithAlpha}`;
  };

  // PC変数名で出力、値はプレビューデバイスの値（デフォルト値は省略）
  const shadowHoverValue = getShadowValueWithInheritance(previewDevice);
  if (shadowHoverValue !== "none") {
    styles['--styling-shadow-pc-hover'] = shadowHoverValue;
  }
  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getInnerShadowHoverStyles = (attributes, { skipDefaults = false } = {}) => {
  const innerData = attributes.innerShadowV2Hover;
  const innerNormalData = attributes.innerShadowV2;
  const innerEnabled = attributes.innerShadowEnabledHover !== undefined ? attributes.innerShadowEnabledHover : attributes.innerShadowEnabled;
  if (!innerEnabled) return {};
  if (!innerData && !innerNormalData) return {};
  const styles = {};

  // Helper to get value with inheritance, preferring hover data over normal
  const getHoverValueWithInheritance = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(innerData, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(innerNormalData, bp, key, defaultVal);
  };

  const getInnerShadowValueWithInheritance = (bp) => {
    const use = getHoverValueWithInheritance(bp, "use", false);
    if (use === undefined || use === null || use === '' || use === false) return "none";
    const horizontal = getHoverValueWithInheritance(bp, "horizontal", 0);
    const vertical = getHoverValueWithInheritance(bp, "vertical", 0);
    const blur = getHoverValueWithInheritance(bp, "blur", 0);
    const spread = getHoverValueWithInheritance(bp, "spread", 0);
    const color = getHoverValueWithInheritance(bp, "color", "transparent");
    const colorAlpha = getHoverValueWithInheritance(bp, "colorAlpha", 1);
    const colorWithAlpha = color === "transparent" ? "transparent" : hexToRgba(color, colorAlpha);
    return `inset ${horizontal}px ${vertical}px ${blur}px ${spread}px ${colorWithAlpha}`;
  };

  // PCのみ出力（フォールバック付き）
  // MD/TB/SP用はPHP CSS Generatorで生成
  const innerShadowHoverValue = getInnerShadowValueWithInheritance('pc');
  if (!skipDefaults || innerShadowHoverValue !== "none") {
    styles['--styling-inner-shadow-pc-hover'] = innerShadowHoverValue;
  }
  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getInnerShadowHoverStylesForEditor = (attributes, previewDevice = 'pc') => {
  const innerData = attributes.innerShadowV2Hover;
  const innerNormalData = attributes.innerShadowV2;
  const innerEnabled = attributes.innerShadowEnabledHover !== undefined ? attributes.innerShadowEnabledHover : attributes.innerShadowEnabled;
  if (!innerEnabled) return {};
  if (!innerData && !innerNormalData) return {};
  const styles = {};

  // Helper to get value with inheritance, preferring hover data over normal
  const getHoverValueWithInheritance = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(innerData, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(innerNormalData, bp, key, defaultVal);
  };

  const getInnerShadowValueWithInheritance = (bp) => {
    const use = getHoverValueWithInheritance(bp, "use", false);
    if (use === undefined || use === null || use === '' || use === false) return "none";
    const horizontal = getHoverValueWithInheritance(bp, "horizontal", 0);
    const vertical = getHoverValueWithInheritance(bp, "vertical", 0);
    const blur = getHoverValueWithInheritance(bp, "blur", 0);
    const spread = getHoverValueWithInheritance(bp, "spread", 0);
    const color = getHoverValueWithInheritance(bp, "color", "transparent");
    const colorAlpha = getHoverValueWithInheritance(bp, "colorAlpha", 1);
    const colorWithAlpha = color === "transparent" ? "transparent" : hexToRgba(color, colorAlpha);
    return `inset ${horizontal}px ${vertical}px ${blur}px ${spread}px ${colorWithAlpha}`;
  };

  // PC変数名で出力、値はプレビューデバイスの値（デフォルト値は省略）
  const innerShadowHoverValue = getInnerShadowValueWithInheritance(previewDevice);
  if (innerShadowHoverValue !== "none") {
    styles['--styling-inner-shadow-pc-hover'] = innerShadowHoverValue;
  }
  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getOpacityStyles = (attributes, { skipDefaults = false } = {}) => {
  const data = attributes.opacityV2;
  if (!data) return {};
  const styles = {};
  const pcValue = getV2ValueWithInheritance(data, 'pc', "value", 100);
  const pcMixBlendMode = getV2ValueWithInheritance(data, 'pc', "mixBlendMode", "normal");

  if (!skipDefaults || pcValue !== 100) {
    styles['--styling-opacity-pc'] = String(pcValue / 100);
  }
  if (!skipDefaults || pcMixBlendMode !== "normal") {
    styles['--styling-mix-blend-mode-pc'] = pcMixBlendMode;
  }
  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getOpacityStylesForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.opacityV2;
  if (!data) return {};
  const styles = {};
  const value = getV2ValueWithInheritance(data, previewDevice, "value", 100);
  const mixBlendMode = getV2ValueWithInheritance(data, previewDevice, "mixBlendMode", "normal");

  // PC変数名で出力、値はプレビューデバイスの値（デフォルト値は省略）
  if (value !== 100) {
    styles['--styling-opacity-pc'] = String(value / 100);
  }
  if (mixBlendMode !== "normal") {
    styles['--styling-mix-blend-mode-pc'] = mixBlendMode;
  }
  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getOpacityHoverStyles = (attributes, { skipDefaults = false } = {}) => {
  const data = attributes.opacityV2Hover;
  const normalData = attributes.opacityV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal
  const getHoverValueWithInheritance = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  const pcValue = getHoverValueWithInheritance('pc', "value", 100);
  const pcMixBlendMode = getHoverValueWithInheritance('pc', "mixBlendMode", "normal");

  if (!skipDefaults || pcValue !== 100) {
    styles['--styling-opacity-pc-hover'] = String(pcValue / 100);
  }
  if (!skipDefaults || pcMixBlendMode !== "normal") {
    styles['--styling-mix-blend-mode-pc-hover'] = pcMixBlendMode;
  }
  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getOpacityHoverStylesForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.opacityV2Hover;
  const normalData = attributes.opacityV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal
  const getHoverValueWithInheritance = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  const value = getHoverValueWithInheritance(previewDevice, "value", 100);
  const mixBlendMode = getHoverValueWithInheritance(previewDevice, "mixBlendMode", "normal");

  // PC変数名で出力、値はプレビューデバイスの値（デフォルト値は省略）
  if (value !== 100) {
    styles['--styling-opacity-pc-hover'] = String(value / 100);
  }
  if (mixBlendMode !== "normal") {
    styles['--styling-mix-blend-mode-pc-hover'] = mixBlendMode;
  }
  return styles;
};

export const getLayoutPositionStyles = (attributes) => {
  const data = attributes.layoutPositionV2;
  if (!data) return {};
  const styles = {};
  const enabledBreakpoints = getEnabledBreakpoints();
  const directions = ['top', 'right', 'bottom', 'left'];

  enabledBreakpoints.forEach((bp, index) => {
    const isPC = index === 0;
    if (isPC) {
      const positionType = getV2ValueWithInheritance(data, bp, "type", "relative");
      styles[`--layout-position-type-${bp}`] = positionType;

      directions.forEach((dir) => {
        const value = getV2ValueWithInheritance(data, bp, dir, "auto");
        const unit = getV2ValueWithInheritance(data, bp, `${dir}Unit`, "px");
        styles[`--layout-position-${dir}-${bp}`] = value === "auto" ? "auto" : `${value}${unit}`;
      });

      const translateX = getV2ValueWithInheritance(data, bp, "translateX", 0);
      const translateXUnit = getV2ValueWithInheritance(data, bp, "translateXUnit", "%");
      const translateY = getV2ValueWithInheritance(data, bp, "translateY", 0);
      const translateYUnit = getV2ValueWithInheritance(data, bp, "translateYUnit", "%");
      styles[`--layout-transform-translate-x-${bp}`] = `${translateX}${translateXUnit}`;
      styles[`--layout-transform-translate-y-${bp}`] = `${translateY}${translateYUnit}`;

      const zIndex = getV2ValueWithInheritance(data, bp, "zIndex", "auto");
      styles[`--layout-z-index-${bp}`] = zIndex === "auto" ? "auto" : `${zIndex}`;
    }
    // MD/TB/SP: PHP CSSに任せる（出力しない）
  });

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getLayoutPositionStylesForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.layoutPositionV2;
  if (!data) return {};
  const styles = {};
  const directions = ['top', 'right', 'bottom', 'left'];

  const positionType = getV2ValueWithInheritance(data, previewDevice, "type", "relative");
  styles['--layout-position-type-pc'] = positionType;

  directions.forEach((dir) => {
    const value = getV2ValueWithInheritance(data, previewDevice, dir, "auto");
    const unit = getV2ValueWithInheritance(data, previewDevice, `${dir}Unit`, "px");
    styles[`--layout-position-${dir}-pc`] = value === "auto" ? "auto" : `${value}${unit}`;
  });

  const translateX = getV2ValueWithInheritance(data, previewDevice, "translateX", 0);
  const translateXUnit = getV2ValueWithInheritance(data, previewDevice, "translateXUnit", "%");
  const translateY = getV2ValueWithInheritance(data, previewDevice, "translateY", 0);
  const translateYUnit = getV2ValueWithInheritance(data, previewDevice, "translateYUnit", "%");
  styles['--layout-transform-translate-x-pc'] = `${translateX}${translateXUnit}`;
  styles['--layout-transform-translate-y-pc'] = `${translateY}${translateYUnit}`;

  const zIndex = getV2ValueWithInheritance(data, previewDevice, "zIndex", "auto");
  styles['--layout-z-index-pc'] = zIndex === "auto" ? "auto" : `${zIndex}`;

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getIconStyles = (attributes, getIconSizeValue, getIconSizeWithInheritance = null) => {
  const styles = {};

  // PC value for fallback
  const pcSize = getIconSizeValue(attributes, "pc");
  styles["--icon-size-pc"] = pcSize || undefined;

  // Icon gap - PC only
  styles["--icon-gap-pc"] = attributes.useResponsiveIconGap
    ? `${attributes.iconGapPC || 0.5}${attributes.iconGapUnitPC || "em"}`
    : `${attributes.iconGap || 0.5}${attributes.iconGapUnit || "em"}`;

  // Icon offset X - PC only
  styles["--icon-offset-x-pc"] = attributes.useResponsiveIconOffsetX
    ? `${attributes.iconOffsetXPC ?? 0}${attributes.iconOffsetXUnitPC || "px"}`
    : `${attributes.iconOffsetX ?? 0}${attributes.iconOffsetXUnit || "px"}`;

  // Icon offset Y - PC only
  styles["--icon-offset-y-pc"] = attributes.useResponsiveIconOffsetY
    ? `${attributes.iconOffsetYPC ?? 0}${attributes.iconOffsetYUnitPC || "px"}`
    : `${attributes.iconOffsetY ?? 0}${attributes.iconOffsetYUnit || "px"}`;

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getIconStylesForEditor = (attributes, getIconSizeValue, getIconSizeWithInheritance = null, previewDevice = "pc") => {
  const styles = {};
  const responsiveEnabled = attributes.useResponsiveIconSize || false;

  // PC value for fallback
  const pcSize = getIconSizeValue(attributes, "pc");

  // Get value for preview device with inheritance
  let sizeValue = pcSize;
  if (previewDevice !== "pc" && responsiveEnabled && getIconSizeWithInheritance) {
    sizeValue = getIconSizeWithInheritance(attributes, previewDevice) || pcSize;
  }
  styles["--icon-size-pc"] = sizeValue || undefined;

  // Icon gap - get value for preview device
  const gapPcValue = attributes.useResponsiveIconGap
    ? `${attributes.iconGapPC || 0.5}${attributes.iconGapUnitPC || "em"}`
    : `${attributes.iconGap || 0.5}${attributes.iconGapUnit || "em"}`;

  let gapValue = gapPcValue;
  if (previewDevice !== "pc" && attributes.useResponsiveIconGap) {
    const deviceMap = {
      md: { value: attributes.iconGapMD, unit: attributes.iconGapUnitMD },
      tb: { value: attributes.iconGapTB, unit: attributes.iconGapUnitTB },
      sp: { value: attributes.iconGapSP, unit: attributes.iconGapUnitSP },
    };
    const getGapWithInheritance = (device) => {
      const bpOrder = ["sp", "tb", "md", "pc"];
      const startIdx = bpOrder.indexOf(device);
      for (let i = startIdx; i < bpOrder.length; i++) {
        const bp = bpOrder[i];
        if (bp === "pc") {
          return gapPcValue;
        }
        const data = deviceMap[bp];
        if (data && data.value !== undefined) {
          return `${data.value}${data.unit || attributes.iconGapUnitPC || "em"}`;
        }
      }
      return gapPcValue;
    };
    gapValue = getGapWithInheritance(previewDevice);
  }
  styles["--icon-gap-pc"] = gapValue;

  // Icon offset X - get value for preview device
  const offsetXPcValue = attributes.useResponsiveIconOffsetX
    ? `${attributes.iconOffsetXPC ?? 0}${attributes.iconOffsetXUnitPC || "px"}`
    : `${attributes.iconOffsetX ?? 0}${attributes.iconOffsetXUnit || "px"}`;

  let offsetXValue = offsetXPcValue;
  if (previewDevice !== "pc") {
    const deviceMap = {
      md: { value: attributes.iconOffsetXMD, unit: attributes.iconOffsetXUnitMD },
      tb: { value: attributes.iconOffsetXTB, unit: attributes.iconOffsetXUnitTB },
      sp: { value: attributes.iconOffsetXSP, unit: attributes.iconOffsetXUnitSP },
    };
    const getOffsetWithInheritance = (device) => {
      const bpOrder = ["sp", "tb", "md", "pc"];
      const startIdx = bpOrder.indexOf(device);
      for (let i = startIdx; i < bpOrder.length; i++) {
        const bp = bpOrder[i];
        if (bp === "pc") {
          return offsetXPcValue;
        }
        const data = deviceMap[bp];
        if (data && data.value !== undefined) {
          return `${data.value}${data.unit || attributes.iconOffsetXUnitPC || "px"}`;
        }
      }
      return offsetXPcValue;
    };
    offsetXValue = getOffsetWithInheritance(previewDevice);
  }
  styles["--icon-offset-x-pc"] = offsetXValue;

  // Icon offset Y - get value for preview device
  const offsetYPcValue = attributes.useResponsiveIconOffsetY
    ? `${attributes.iconOffsetYPC ?? 0}${attributes.iconOffsetYUnitPC || "px"}`
    : `${attributes.iconOffsetY ?? 0}${attributes.iconOffsetYUnit || "px"}`;

  let offsetYValue = offsetYPcValue;
  if (previewDevice !== "pc") {
    const deviceMap = {
      md: { value: attributes.iconOffsetYMD, unit: attributes.iconOffsetYUnitMD },
      tb: { value: attributes.iconOffsetYTB, unit: attributes.iconOffsetYUnitTB },
      sp: { value: attributes.iconOffsetYSP, unit: attributes.iconOffsetYUnitSP },
    };
    const getOffsetWithInheritance = (device) => {
      const bpOrder = ["sp", "tb", "md", "pc"];
      const startIdx = bpOrder.indexOf(device);
      for (let i = startIdx; i < bpOrder.length; i++) {
        const bp = bpOrder[i];
        if (bp === "pc") {
          return offsetYPcValue;
        }
        const data = deviceMap[bp];
        if (data && data.value !== undefined) {
          return `${data.value}${data.unit || attributes.iconOffsetYUnitPC || "px"}`;
        }
      }
      return offsetYPcValue;
    };
    offsetYValue = getOffsetWithInheritance(previewDevice);
  }
  styles["--icon-offset-y-pc"] = offsetYValue;

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getIconHoverStyles = (attributes, getIconSizeValue, getIconSizeHoverWithInheritance = null) => {
  const styles = {};

  // PC hover value
  const pcHoverSize = getIconSizeValue ? getIconSizeValue(attributes, "pc", true) : undefined;
  styles["--icon-size-pc-hover"] = pcHoverSize || undefined;

  // Icon offset X hover - PC only
  styles["--icon-offset-x-pc-hover"] = `${attributes.iconOffsetXPCHover ?? attributes.iconOffsetXPC ?? 0}${attributes.iconOffsetXUnitPCHover || attributes.iconOffsetXUnitPC || "px"}`;

  // Icon offset Y hover - PC only
  styles["--icon-offset-y-pc-hover"] = `${attributes.iconOffsetYPCHover ?? attributes.iconOffsetYPC ?? 0}${attributes.iconOffsetYUnitPCHover || attributes.iconOffsetYUnitPC || "px"}`;

  // Icon transition (not responsive)
  styles["--icon-transition-duration"] = `${attributes.iconTransitionDuration ?? 300}ms`;
  styles["--icon-transition-delay"] = `${attributes.iconTransitionDelay ?? 0}ms`;
  styles["--icon-transition-easing"] = attributes.iconTransitionEasing || "ease";

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getIconHoverStylesForEditor = (attributes, getIconSizeValue, getIconSizeHoverWithInheritance = null, previewDevice = "pc") => {
  const styles = {};
  const responsiveEnabled = attributes.useResponsiveIconSizeHover || false;

  // PC hover value for fallback
  const pcHoverSize = getIconSizeValue ? getIconSizeValue(attributes, "pc", true) : undefined;

  // Get value for preview device with inheritance
  let sizeValue = pcHoverSize;
  if (previewDevice !== "pc" && responsiveEnabled && getIconSizeHoverWithInheritance) {
    sizeValue = getIconSizeHoverWithInheritance(attributes, previewDevice) || pcHoverSize;
  }
  styles["--icon-size-pc-hover"] = sizeValue || undefined;

  // Icon offset X hover - get value for preview device
  const offsetXPcValue = `${attributes.iconOffsetXPCHover ?? attributes.iconOffsetXPC ?? 0}${attributes.iconOffsetXUnitPCHover || attributes.iconOffsetXUnitPC || "px"}`;

  let offsetXValue = offsetXPcValue;
  if (previewDevice !== "pc") {
    const deviceMap = {
      md: { value: attributes.iconOffsetXMDHover ?? attributes.iconOffsetXMD, unit: attributes.iconOffsetXUnitMDHover || attributes.iconOffsetXUnitMD },
      tb: { value: attributes.iconOffsetXTBHover ?? attributes.iconOffsetXTB, unit: attributes.iconOffsetXUnitTBHover || attributes.iconOffsetXUnitTB },
      sp: { value: attributes.iconOffsetXSPHover ?? attributes.iconOffsetXSP, unit: attributes.iconOffsetXUnitSPHover || attributes.iconOffsetXUnitSP },
    };
    const getOffsetWithInheritance = (device) => {
      const bpOrder = ["sp", "tb", "md", "pc"];
      const startIdx = bpOrder.indexOf(device);
      for (let i = startIdx; i < bpOrder.length; i++) {
        const bp = bpOrder[i];
        if (bp === "pc") {
          return offsetXPcValue;
        }
        const data = deviceMap[bp];
        if (data && data.value !== undefined) {
          return `${data.value}${data.unit || attributes.iconOffsetXUnitPC || "px"}`;
        }
      }
      return offsetXPcValue;
    };
    offsetXValue = getOffsetWithInheritance(previewDevice);
  }
  styles["--icon-offset-x-pc-hover"] = offsetXValue;

  // Icon offset Y hover - get value for preview device
  const offsetYPcValue = `${attributes.iconOffsetYPCHover ?? attributes.iconOffsetYPC ?? 0}${attributes.iconOffsetYUnitPCHover || attributes.iconOffsetYUnitPC || "px"}`;

  let offsetYValue = offsetYPcValue;
  if (previewDevice !== "pc") {
    const deviceMap = {
      md: { value: attributes.iconOffsetYMDHover ?? attributes.iconOffsetYMD, unit: attributes.iconOffsetYUnitMDHover || attributes.iconOffsetYUnitMD },
      tb: { value: attributes.iconOffsetYTBHover ?? attributes.iconOffsetYTB, unit: attributes.iconOffsetYUnitTBHover || attributes.iconOffsetYUnitTB },
      sp: { value: attributes.iconOffsetYSPHover ?? attributes.iconOffsetYSP, unit: attributes.iconOffsetYUnitSPHover || attributes.iconOffsetYUnitSP },
    };
    const getOffsetWithInheritance = (device) => {
      const bpOrder = ["sp", "tb", "md", "pc"];
      const startIdx = bpOrder.indexOf(device);
      for (let i = startIdx; i < bpOrder.length; i++) {
        const bp = bpOrder[i];
        if (bp === "pc") {
          return offsetYPcValue;
        }
        const data = deviceMap[bp];
        if (data && data.value !== undefined) {
          return `${data.value}${data.unit || attributes.iconOffsetYUnitPC || "px"}`;
        }
      }
      return offsetYPcValue;
    };
    offsetYValue = getOffsetWithInheritance(previewDevice);
  }
  styles["--icon-offset-y-pc-hover"] = offsetYValue;

  // Icon transition (not responsive)
  styles["--icon-transition-duration"] = `${attributes.iconTransitionDuration ?? 300}ms`;
  styles["--icon-transition-delay"] = `${attributes.iconTransitionDelay ?? 0}ms`;
  styles["--icon-transition-easing"] = attributes.iconTransitionEasing || "ease";

  return styles;
};

export const getIconColorStyles = (attributes, textColor, getCurrentIconColor) => {
  if (!attributes.icon || attributes.icon === "") return {};
  
  return {
    "--icon-color": getCurrentIconColor(attributes.icon, attributes.iconColor, textColor),
    "--icon-stroke-width": attributes.iconStrokeWidth || 1.75,
    "--icon-color-hover": attributes.iconColorHover
      ? attributes.iconColorHover
      : getCurrentIconColor(attributes.iconHover || attributes.icon, attributes.iconColor, attributes.textColorHover || textColor),
    "--icon-stroke-width-hover": attributes.iconStrokeWidthHover !== undefined ? attributes.iconStrokeWidthHover : attributes.iconStrokeWidth || 1.75,
  };
};

const getIconFrameSizeValue = (attributes, device, dimension, isHover = false) => {
  const suffix = device.toUpperCase();
  const hoverSuffix = isHover ? "Hover" : "";
  const useIndividual = attributes[`iconFrameUseIndividualSize${hoverSuffix}`];
  const useResponsive = attributes[`responsiveIconFrameSize${hoverSuffix}`] || attributes[`useResponsiveIconFrameSize${hoverSuffix}`];
  
  if (useIndividual) {
    const value = useResponsive 
      ? (attributes[`iconFrame${dimension}${suffix}${hoverSuffix}`] ?? attributes[`iconFrame${dimension}PC${hoverSuffix}`] ?? attributes[`iconFrame${dimension}${hoverSuffix}`] ?? (isHover ? 40 : 0))
      : (attributes[`iconFrame${dimension}PC${hoverSuffix}`] ?? attributes[`iconFrame${dimension}${hoverSuffix}`] ?? (isHover ? 40 : 0));
    const unit = useResponsive
      ? (attributes[`iconFrame${dimension}Unit${suffix}${hoverSuffix}`] || attributes[`iconFrame${dimension}UnitPC${hoverSuffix}`] || attributes[`iconFrame${dimension}Unit${hoverSuffix}`] || "px")
      : (attributes[`iconFrame${dimension}UnitPC${hoverSuffix}`] || attributes[`iconFrame${dimension}Unit${hoverSuffix}`] || "px");
    return `${value}${unit}`;
  }
  
  const size = useResponsive
    ? (attributes[`iconFrameSize${suffix}${hoverSuffix}`] ?? attributes[`iconFrameSizePC${hoverSuffix}`] ?? attributes[`iconFrameSize${hoverSuffix}`] ?? (isHover ? 40 : 0))
    : (attributes[`iconFrameSizePC${hoverSuffix}`] ?? attributes[`iconFrameSize${hoverSuffix}`] ?? (isHover ? 40 : 0));
  const unit = useResponsive
    ? (attributes[`iconFrameSizeUnit${suffix}${hoverSuffix}`] || attributes[`iconFrameSizeUnitPC${hoverSuffix}`] || attributes[`iconFrameSizeUnit${hoverSuffix}`] || "px")
    : (attributes[`iconFrameSizeUnitPC${hoverSuffix}`] || attributes[`iconFrameSizeUnit${hoverSuffix}`] || "px");
  return `${size}${unit}`;
};

const isIconFrameSizeZero = (attributes, device, isHover = false) => {
  const suffix = device.toUpperCase();
  const hoverSuffix = isHover ? "Hover" : "";
  const useIndividual = attributes[`iconFrameUseIndividualSize${hoverSuffix}`];
  const useResponsive = attributes[`responsiveIconFrameSize${hoverSuffix}`] || attributes[`useResponsiveIconFrameSize${hoverSuffix}`];
  
  if (useIndividual) {
    const width = useResponsive 
      ? (attributes[`iconFrameWidth${suffix}${hoverSuffix}`] ?? attributes[`iconFrameWidthPC${hoverSuffix}`] ?? attributes[`iconFrameWidth${hoverSuffix}`] ?? (isHover ? 40 : 0))
      : (attributes[`iconFrameWidthPC${hoverSuffix}`] ?? attributes[`iconFrameWidth${hoverSuffix}`] ?? (isHover ? 40 : 0));
    const height = useResponsive 
      ? (attributes[`iconFrameHeight${suffix}${hoverSuffix}`] ?? attributes[`iconFrameHeightPC${hoverSuffix}`] ?? attributes[`iconFrameHeight${hoverSuffix}`] ?? (isHover ? 40 : 0))
      : (attributes[`iconFrameHeightPC${hoverSuffix}`] ?? attributes[`iconFrameHeight${hoverSuffix}`] ?? (isHover ? 40 : 0));
    return width === 0 && height === 0;
  }
  
  const size = useResponsive
    ? (attributes[`iconFrameSize${suffix}${hoverSuffix}`] ?? attributes[`iconFrameSizePC${hoverSuffix}`] ?? attributes[`iconFrameSize${hoverSuffix}`] ?? (isHover ? 40 : 0))
    : (attributes[`iconFrameSizePC${hoverSuffix}`] ?? attributes[`iconFrameSize${hoverSuffix}`] ?? (isHover ? 40 : 0));
  return size === 0;
};

const getIconFrameBorderWidthValue = (attributes, device, side, isHover = false) => {
  const suffix = device.toUpperCase();
  const hoverSuffix = isHover ? "Hover" : "";
  const useResponsive = attributes[`responsiveIconFrameBorder${hoverSuffix}`] || attributes[`useResponsiveIconFrameBorder${hoverSuffix}`];
  const defaultSides = ["top", "right", "bottom", "left"];

  // デバイス別のsidesを取得（レスポンシブ対応）
  // ホバー時は通常状態へのフォールバックを行わない（ホバーは独立した設定）
  let sides;
  if (isHover) {
    sides = useResponsive
      ? (attributes[`iconFrameBorderSides${suffix}Hover`] || attributes[`iconFrameBorderSidesPCHover`] || attributes[`iconFrameBorderSidesHover`] || defaultSides)
      : (attributes[`iconFrameBorderSidesPCHover`] || attributes[`iconFrameBorderSidesHover`] || defaultSides);
  } else {
    sides = useResponsive
      ? (attributes[`iconFrameBorderSides${suffix}`] || attributes[`iconFrameBorderSidesPC`] || attributes.iconFrameBorderSides || defaultSides)
      : (attributes[`iconFrameBorderSidesPC`] || attributes.iconFrameBorderSides || defaultSides);
  }

  if (!sides.includes(side)) return "0";

  const width = useResponsive
    ? (attributes[`iconFrameBorderWidth${suffix}${hoverSuffix}`] ?? attributes[`iconFrameBorderWidthPC${hoverSuffix}`] ?? attributes[`iconFrameBorderWidth${hoverSuffix}`] ?? attributes.iconFrameBorderWidth ?? 1)
    : (attributes[`iconFrameBorderWidthPC${hoverSuffix}`] ?? attributes[`iconFrameBorderWidth${hoverSuffix}`] ?? attributes.iconFrameBorderWidth ?? 1);
  const unit = useResponsive
    ? (attributes[`iconFrameBorderWidthUnit${suffix}${hoverSuffix}`] || attributes[`iconFrameBorderWidthUnitPC${hoverSuffix}`] || attributes[`iconFrameBorderWidthUnit${hoverSuffix}`] || attributes.iconFrameBorderWidthUnit || "px")
    : (attributes[`iconFrameBorderWidthUnitPC${hoverSuffix}`] || attributes[`iconFrameBorderWidthUnit${hoverSuffix}`] || attributes.iconFrameBorderWidthUnit || "px");

  return `${width}${unit}`;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getIconFrameStyles = (attributes) => {
  return {
    // PC only
    "--icon-frame-display-pc": isIconFrameSizeZero(attributes, "pc") ? "none" : "block",
    "--icon-frame-width-pc": getIconFrameSizeValue(attributes, "pc", "Width"),
    "--icon-frame-height-pc": getIconFrameSizeValue(attributes, "pc", "Height"),
    "--icon-frame-bg-color-pc": (attributes.iconFrameBgUseGradientPC || attributes.iconFrameBgUseGradient)
      ? (attributes.iconFrameBgGradientPC || attributes.iconFrameBgGradient || "linear-gradient(135deg, #007FD6 0%, #02439D 100%)")
      : ((attributes.iconFrameBgColorPC || attributes.iconFrameBgColor) ? getColorWithAlpha(attributes.iconFrameBgColorPC || attributes.iconFrameBgColor, attributes.iconFrameBgColorAlphaPC ?? attributes.iconFrameBgColorAlpha) : "transparent"),
    "--icon-frame-radius-pc": `${attributes.iconFrameRadiusPC ?? attributes.iconFrameRadius ?? 0}${attributes.iconFrameRadiusUnitPC ?? attributes.iconFrameRadiusUnit ?? "px"}`,
    "--icon-frame-border-width-pc": `${attributes.iconFrameBorderWidthPC ?? attributes.iconFrameBorderWidth ?? 1}${attributes.iconFrameBorderWidthUnitPC || attributes.iconFrameBorderWidthUnit || "px"}`,
    "--icon-frame-border-top-width-pc": getIconFrameBorderWidthValue(attributes, "pc", "top"),
    "--icon-frame-border-right-width-pc": getIconFrameBorderWidthValue(attributes, "pc", "right"),
    "--icon-frame-border-bottom-width-pc": getIconFrameBorderWidthValue(attributes, "pc", "bottom"),
    "--icon-frame-border-left-width-pc": getIconFrameBorderWidthValue(attributes, "pc", "left"),
    "--icon-frame-border-color": attributes.iconFrameBorderColor ? getColorWithAlpha(attributes.iconFrameBorderColor, attributes.iconFrameBorderColorAlpha) : "transparent",
    "--icon-frame-border-color-pc": (attributes.iconFrameBorderColorPC || attributes.iconFrameBorderColor) ? getColorWithAlpha(attributes.iconFrameBorderColorPC || attributes.iconFrameBorderColor, attributes.iconFrameBorderColorAlphaPC ?? attributes.iconFrameBorderColorAlpha) : "transparent",
    "--icon-frame-border-style-pc": attributes.iconFrameBorderStylePC || attributes.iconFrameBorderStyle || "solid",
    "--icon-frame-transition-duration": `${attributes.iconFrameTransitionDuration || 300}ms`,
    "--icon-frame-transition-delay": `${attributes.iconFrameTransitionDelay || 200}ms`,
    "--icon-frame-transition-easing": attributes.iconFrameTransitionEasing || "ease",
  };
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getIconFrameStylesForEditor = (attributes, previewDevice = "pc") => {
  const useResponsive = attributes.responsiveIconFrameBorder || attributes.useResponsiveIconFrameBorder;

  // Helper to get value with inheritance for preview device
  const getRadiusValue = (device) => {
    const bpOrder = ["sp", "tb", "md", "pc"];
    const startIdx = bpOrder.indexOf(device);
    for (let i = startIdx; i < bpOrder.length; i++) {
      const bp = bpOrder[i];
      const suffix = bp.toUpperCase();
      const value = attributes[`iconFrameRadius${suffix}`];
      if (value !== undefined) {
        const unit = attributes[`iconFrameRadiusUnit${suffix}`] || attributes.iconFrameRadiusUnit || "px";
        return `${value}${unit}`;
      }
    }
    return `${attributes.iconFrameRadius ?? 0}${attributes.iconFrameRadiusUnit ?? "px"}`;
  };

  const getBorderWidthValue = (device) => {
    if (!useResponsive) {
      return `${attributes.iconFrameBorderWidthPC ?? attributes.iconFrameBorderWidth ?? 1}${attributes.iconFrameBorderWidthUnitPC || attributes.iconFrameBorderWidthUnit || "px"}`;
    }
    const bpOrder = ["sp", "tb", "md", "pc"];
    const startIdx = bpOrder.indexOf(device);
    for (let i = startIdx; i < bpOrder.length; i++) {
      const bp = bpOrder[i];
      const suffix = bp.toUpperCase();
      const value = attributes[`iconFrameBorderWidth${suffix}`];
      if (value !== undefined) {
        const unit = attributes[`iconFrameBorderWidthUnit${suffix}`] || attributes.iconFrameBorderWidthUnit || "px";
        return `${value}${unit}`;
      }
    }
    return `${attributes.iconFrameBorderWidth ?? 1}${attributes.iconFrameBorderWidthUnit || "px"}`;
  };

  const getBorderColorValue = (device) => {
    if (!useResponsive) {
      return (attributes.iconFrameBorderColorPC || attributes.iconFrameBorderColor)
        ? getColorWithAlpha(attributes.iconFrameBorderColorPC || attributes.iconFrameBorderColor, attributes.iconFrameBorderColorAlphaPC ?? attributes.iconFrameBorderColorAlpha)
        : "transparent";
    }
    const bpOrder = ["sp", "tb", "md", "pc"];
    const startIdx = bpOrder.indexOf(device);
    for (let i = startIdx; i < bpOrder.length; i++) {
      const bp = bpOrder[i];
      const suffix = bp.toUpperCase();
      const color = attributes[`iconFrameBorderColor${suffix}`];
      if (color) {
        const alpha = attributes[`iconFrameBorderColorAlpha${suffix}`] ?? attributes.iconFrameBorderColorAlpha;
        return getColorWithAlpha(color, alpha);
      }
    }
    return attributes.iconFrameBorderColor
      ? getColorWithAlpha(attributes.iconFrameBorderColor, attributes.iconFrameBorderColorAlpha)
      : "transparent";
  };

  const getBorderStyleValue = (device) => {
    if (!useResponsive) {
      return attributes.iconFrameBorderStylePC || attributes.iconFrameBorderStyle || "solid";
    }
    const bpOrder = ["sp", "tb", "md", "pc"];
    const startIdx = bpOrder.indexOf(device);
    for (let i = startIdx; i < bpOrder.length; i++) {
      const bp = bpOrder[i];
      const suffix = bp.toUpperCase();
      const style = attributes[`iconFrameBorderStyle${suffix}`];
      if (style) {
        return style;
      }
    }
    return attributes.iconFrameBorderStyle || "solid";
  };

  const getBgColorValue = (device) => {
    const useResponsiveColor = attributes.useResponsiveIconFrameColor;
    if (!useResponsiveColor) {
      const useGradient = attributes.iconFrameBgUseGradientPC || attributes.iconFrameBgUseGradient;
      if (useGradient) {
        return attributes.iconFrameBgGradientPC || attributes.iconFrameBgGradient || "linear-gradient(135deg, #007FD6 0%, #02439D 100%)";
      }
      return (attributes.iconFrameBgColorPC || attributes.iconFrameBgColor)
        ? getColorWithAlpha(attributes.iconFrameBgColorPC || attributes.iconFrameBgColor, attributes.iconFrameBgColorAlphaPC ?? attributes.iconFrameBgColorAlpha)
        : "transparent";
    }
    const bpOrder = ["sp", "tb", "md", "pc"];
    const startIdx = bpOrder.indexOf(device);
    for (let i = startIdx; i < bpOrder.length; i++) {
      const bp = bpOrder[i];
      const suffix = bp.toUpperCase();
      const useGradient = attributes[`iconFrameBgUseGradient${suffix}`];
      if (useGradient) {
        const gradient = attributes[`iconFrameBgGradient${suffix}`];
        if (gradient) return gradient;
      }
      const color = attributes[`iconFrameBgColor${suffix}`];
      if (color) {
        const alpha = attributes[`iconFrameBgColorAlpha${suffix}`] ?? attributes.iconFrameBgColorAlpha;
        return getColorWithAlpha(color, alpha);
      }
    }
    const useGradient = attributes.iconFrameBgUseGradient;
    if (useGradient) {
      return attributes.iconFrameBgGradient || "linear-gradient(135deg, #007FD6 0%, #02439D 100%)";
    }
    return attributes.iconFrameBgColor
      ? getColorWithAlpha(attributes.iconFrameBgColor, attributes.iconFrameBgColorAlpha)
      : "transparent";
  };

  return {
    "--icon-frame-display-pc": isIconFrameSizeZero(attributes, previewDevice) ? "none" : "block",
    "--icon-frame-width-pc": getIconFrameSizeValue(attributes, previewDevice, "Width"),
    "--icon-frame-height-pc": getIconFrameSizeValue(attributes, previewDevice, "Height"),
    "--icon-frame-bg-color-pc": getBgColorValue(previewDevice),
    "--icon-frame-radius-pc": getRadiusValue(previewDevice),
    "--icon-frame-border-width-pc": getBorderWidthValue(previewDevice),
    "--icon-frame-border-top-width-pc": getIconFrameBorderWidthValue(attributes, previewDevice, "top"),
    "--icon-frame-border-right-width-pc": getIconFrameBorderWidthValue(attributes, previewDevice, "right"),
    "--icon-frame-border-bottom-width-pc": getIconFrameBorderWidthValue(attributes, previewDevice, "bottom"),
    "--icon-frame-border-left-width-pc": getIconFrameBorderWidthValue(attributes, previewDevice, "left"),
    "--icon-frame-border-color": attributes.iconFrameBorderColor ? getColorWithAlpha(attributes.iconFrameBorderColor, attributes.iconFrameBorderColorAlpha) : "transparent",
    "--icon-frame-border-color-pc": getBorderColorValue(previewDevice),
    "--icon-frame-border-style-pc": getBorderStyleValue(previewDevice),
    "--icon-frame-transition-duration": `${attributes.iconFrameTransitionDuration || 300}ms`,
    "--icon-frame-transition-delay": `${attributes.iconFrameTransitionDelay || 200}ms`,
    "--icon-frame-transition-easing": attributes.iconFrameTransitionEasing || "ease",
  };
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getIconFrameHoverStyles = (attributes) => {
  return {
    // PC only
    "--icon-frame-width-pc-hover": getIconFrameSizeValue(attributes, "pc", "Width", true),
    "--icon-frame-height-pc-hover": getIconFrameSizeValue(attributes, "pc", "Height", true),
    // ホバー背景色 - 通常状態へのフォールバックは行わない（ホバーは独立した設定）
    "--icon-frame-bg-color-pc-hover": (attributes.iconFrameBgUseGradientPCHover || attributes.iconFrameBgUseGradientHover)
      ? (attributes.iconFrameBgGradientPCHover || attributes.iconFrameBgGradientHover || "linear-gradient(135deg, #007FD6 0%, #02439D 100%)")
      : ((attributes.iconFrameBgColorPCHover || attributes.iconFrameBgColorHover) ? getColorWithAlpha(attributes.iconFrameBgColorPCHover || attributes.iconFrameBgColorHover, attributes.iconFrameBgColorAlphaPCHover ?? attributes.iconFrameBgColorAlphaHover ?? 1) : "transparent"),
    "--icon-frame-radius-pc-hover": `${attributes.iconFrameRadiusPCHover ?? attributes.iconFrameRadiusPC ?? 0}${attributes.iconFrameRadiusUnitPCHover ?? attributes.iconFrameRadiusUnitPC ?? "px"}`,
    "--icon-frame-border-width-pc-hover": `${attributes.iconFrameBorderWidthPCHover ?? attributes.iconFrameBorderWidthPC ?? attributes.iconFrameBorderWidth ?? 1}${attributes.iconFrameBorderWidthUnitPCHover || attributes.iconFrameBorderWidthUnitPC || attributes.iconFrameBorderWidthUnit || "px"}`,
    "--icon-frame-border-top-width-pc-hover": getIconFrameBorderWidthValue(attributes, "pc", "top", true),
    "--icon-frame-border-right-width-pc-hover": getIconFrameBorderWidthValue(attributes, "pc", "right", true),
    "--icon-frame-border-bottom-width-pc-hover": getIconFrameBorderWidthValue(attributes, "pc", "bottom", true),
    "--icon-frame-border-left-width-pc-hover": getIconFrameBorderWidthValue(attributes, "pc", "left", true),
    // ホバーボーダー色 - 通常状態へのフォールバックは行わない（ホバーは独立した設定）
    "--icon-frame-border-color-hover": attributes.iconFrameBorderColorHover ? getColorWithAlpha(attributes.iconFrameBorderColorHover, attributes.iconFrameBorderColorAlphaHover ?? 1) : "transparent",
    "--icon-frame-border-color-pc-hover": attributes.iconFrameBorderColorPCHover ? getColorWithAlpha(attributes.iconFrameBorderColorPCHover, attributes.iconFrameBorderColorAlphaPCHover ?? 1) : "transparent",
    "--icon-frame-border-style-pc-hover": attributes.iconFrameBorderStylePCHover || "solid",
  };
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getIconFrameHoverStylesForEditor = (attributes, previewDevice = "pc") => {
  const useResponsive = attributes.responsiveIconFrameBorderHover || attributes.useResponsiveIconFrameBorderHover;

  // Helper to get value with inheritance for preview device
  const getRadiusHoverValue = (device) => {
    const bpOrder = ["sp", "tb", "md", "pc"];
    const startIdx = bpOrder.indexOf(device);
    for (let i = startIdx; i < bpOrder.length; i++) {
      const bp = bpOrder[i];
      const suffix = bp.toUpperCase();
      const value = attributes[`iconFrameRadius${suffix}Hover`] ?? attributes[`iconFrameRadius${suffix}`];
      if (value !== undefined) {
        const unit = attributes[`iconFrameRadiusUnit${suffix}Hover`] || attributes[`iconFrameRadiusUnit${suffix}`] || "px";
        return `${value}${unit}`;
      }
    }
    return `${attributes.iconFrameRadiusHover ?? attributes.iconFrameRadius ?? 0}${attributes.iconFrameRadiusUnitHover ?? attributes.iconFrameRadiusUnit ?? "px"}`;
  };

  const getBorderWidthHoverValue = (device) => {
    if (!useResponsive) {
      return `${attributes.iconFrameBorderWidthPCHover ?? attributes.iconFrameBorderWidthPC ?? attributes.iconFrameBorderWidth ?? 1}${attributes.iconFrameBorderWidthUnitPCHover || attributes.iconFrameBorderWidthUnitPC || attributes.iconFrameBorderWidthUnit || "px"}`;
    }
    const bpOrder = ["sp", "tb", "md", "pc"];
    const startIdx = bpOrder.indexOf(device);
    for (let i = startIdx; i < bpOrder.length; i++) {
      const bp = bpOrder[i];
      const suffix = bp.toUpperCase();
      const value = attributes[`iconFrameBorderWidth${suffix}Hover`] ?? attributes[`iconFrameBorderWidth${suffix}`];
      if (value !== undefined) {
        const unit = attributes[`iconFrameBorderWidthUnit${suffix}Hover`] || attributes[`iconFrameBorderWidthUnit${suffix}`] || "px";
        return `${value}${unit}`;
      }
    }
    return `${attributes.iconFrameBorderWidthHover ?? attributes.iconFrameBorderWidth ?? 1}${attributes.iconFrameBorderWidthUnitHover || attributes.iconFrameBorderWidthUnit || "px"}`;
  };

  // 通常状態へのフォールバックは行わない（ホバーは独立した設定）
  const getBorderColorHoverValue = (device) => {
    if (!useResponsive) {
      return attributes.iconFrameBorderColorPCHover
        ? getColorWithAlpha(attributes.iconFrameBorderColorPCHover, attributes.iconFrameBorderColorAlphaPCHover ?? 1)
        : "transparent";
    }
    const bpOrder = ["sp", "tb", "md", "pc"];
    const startIdx = bpOrder.indexOf(device);
    for (let i = startIdx; i < bpOrder.length; i++) {
      const bp = bpOrder[i];
      const suffix = bp.toUpperCase();
      const color = attributes[`iconFrameBorderColor${suffix}Hover`];
      if (color) {
        const alpha = attributes[`iconFrameBorderColorAlpha${suffix}Hover`] ?? 1;
        return getColorWithAlpha(color, alpha);
      }
    }
    return attributes.iconFrameBorderColorHover
      ? getColorWithAlpha(attributes.iconFrameBorderColorHover, attributes.iconFrameBorderColorAlphaHover ?? 1)
      : "transparent";
  };

  // 通常状態へのフォールバックは行わない（ホバーは独立した設定）
  const getBorderStyleHoverValue = (device) => {
    if (!useResponsive) {
      return attributes.iconFrameBorderStylePCHover || "solid";
    }
    const bpOrder = ["sp", "tb", "md", "pc"];
    const startIdx = bpOrder.indexOf(device);
    for (let i = startIdx; i < bpOrder.length; i++) {
      const bp = bpOrder[i];
      const suffix = bp.toUpperCase();
      const style = attributes[`iconFrameBorderStyle${suffix}Hover`];
      if (style) {
        return style;
      }
    }
    return attributes.iconFrameBorderStyleHover || "solid";
  };

  // 通常状態へのフォールバックは行わない（ホバーは独立した設定）
  const getBgColorHoverValue = (device) => {
    const useResponsiveColor = attributes.useResponsiveIconFrameColorHover;
    if (!useResponsiveColor) {
      const useGradient = attributes.iconFrameBgUseGradientPCHover || attributes.iconFrameBgUseGradientHover;
      if (useGradient) {
        return attributes.iconFrameBgGradientPCHover || attributes.iconFrameBgGradientHover || "linear-gradient(135deg, #007FD6 0%, #02439D 100%)";
      }
      return (attributes.iconFrameBgColorPCHover || attributes.iconFrameBgColorHover)
        ? getColorWithAlpha(attributes.iconFrameBgColorPCHover || attributes.iconFrameBgColorHover, attributes.iconFrameBgColorAlphaPCHover ?? attributes.iconFrameBgColorAlphaHover ?? 1)
        : "transparent";
    }
    const bpOrder = ["sp", "tb", "md", "pc"];
    const startIdx = bpOrder.indexOf(device);
    for (let i = startIdx; i < bpOrder.length; i++) {
      const bp = bpOrder[i];
      const suffix = bp.toUpperCase();
      const useGradient = attributes[`iconFrameBgUseGradient${suffix}Hover`];
      if (useGradient) {
        const gradient = attributes[`iconFrameBgGradient${suffix}Hover`];
        if (gradient) return gradient;
      }
      const color = attributes[`iconFrameBgColor${suffix}Hover`];
      if (color) {
        const alpha = attributes[`iconFrameBgColorAlpha${suffix}Hover`] ?? 1;
        return getColorWithAlpha(color, alpha);
      }
    }
    const useGradient = attributes.iconFrameBgUseGradientHover;
    if (useGradient) {
      return attributes.iconFrameBgGradientHover || "linear-gradient(135deg, #007FD6 0%, #02439D 100%)";
    }
    return attributes.iconFrameBgColorHover
      ? getColorWithAlpha(attributes.iconFrameBgColorHover, attributes.iconFrameBgColorAlphaHover ?? 1)
      : "transparent";
  };

  return {
    "--icon-frame-width-pc-hover": getIconFrameSizeValue(attributes, previewDevice, "Width", true),
    "--icon-frame-height-pc-hover": getIconFrameSizeValue(attributes, previewDevice, "Height", true),
    // ホバー背景色 - 通常状態へのフォールバックは行わない（ホバーは独立した設定）
    "--icon-frame-bg-color-pc-hover": getBgColorHoverValue(previewDevice),
    "--icon-frame-radius-pc-hover": getRadiusHoverValue(previewDevice),
    "--icon-frame-border-width-pc-hover": getBorderWidthHoverValue(previewDevice),
    "--icon-frame-border-top-width-pc-hover": getIconFrameBorderWidthValue(attributes, previewDevice, "top", true),
    "--icon-frame-border-right-width-pc-hover": getIconFrameBorderWidthValue(attributes, previewDevice, "right", true),
    "--icon-frame-border-bottom-width-pc-hover": getIconFrameBorderWidthValue(attributes, previewDevice, "bottom", true),
    "--icon-frame-border-left-width-pc-hover": getIconFrameBorderWidthValue(attributes, previewDevice, "left", true),
    // ホバーボーダー色 - 通常状態へのフォールバックは行わない（ホバーは独立した設定）
    "--icon-frame-border-color-hover": attributes.iconFrameBorderColorHover ? getColorWithAlpha(attributes.iconFrameBorderColorHover, attributes.iconFrameBorderColorAlphaHover ?? 1) : "transparent",
    "--icon-frame-border-color-pc-hover": getBorderColorHoverValue(previewDevice),
    "--icon-frame-border-style-pc-hover": getBorderStyleHoverValue(previewDevice),
  };
};

// ============================================
// iconFrame V2 関数
// ============================================

/**
 * V2: iconFrameV2が実際に使用されているか判定
 * デフォルト値のみの場合はfalseを返す（V1へフォールバック）
 */
const isIconFrameV2Active = (data) => {
  if (!data || !data.pc) return false;
  // PC値がデフォルト（size=0, width=0, height=0）以外に設定されているかチェック
  const pc = data.pc;
  if (pc.size > 0) return true;
  if (pc.useIndividualSize && (pc.width > 0 || pc.height > 0)) return true;
  if (pc.bgColor && pc.bgColor !== 'transparent') return true;
  if (pc.borderWidth > 0) return true;
  if (pc.radius > 0) return true;
  // md/tb/spに値が設定されているかもチェック
  for (const bp of ['md', 'tb', 'sp']) {
    if (data[bp]) {
      if (data[bp].size && data[bp].size !== '' && data[bp].size > 0) return true;
      if (data[bp].width && data[bp].width !== '' && data[bp].width > 0) return true;
      if (data[bp].height && data[bp].height !== '' && data[bp].height > 0) return true;
    }
  }
  return false;
};

/**
 * V2: iconFrameV2Hoverが実際に使用されているか判定
 * デフォルト値（空文字）のみの場合はfalseを返す（V1ホバーへフォールバック）
 */
const isIconFrameV2HoverActive = (data) => {
  if (!data) return false;
  // 全ブレークポイントをチェック
  for (const bp of ['pc', 'md', 'tb', 'sp']) {
    if (data[bp]) {
      // いずれかのプロパティに実際の値が設定されているかチェック
      if (data[bp].size && data[bp].size !== '') return true;
      if (data[bp].width && data[bp].width !== '') return true;
      if (data[bp].height && data[bp].height !== '') return true;
      if (data[bp].bgColor && data[bp].bgColor !== '') return true;
      if (data[bp].radius && data[bp].radius !== '') return true;
      if (data[bp].borderWidth && data[bp].borderWidth !== '') return true;
      if (data[bp].borderColor && data[bp].borderColor !== '') return true;
    }
  }
  return false;
};

/**
 * V2: iconFrameのサイズが0かどうかを判定
 */
const isIconFrameV2SizeZero = (data, device) => {
  if (!data || !data[device]) return true;
  const useIndividual = getV2ValueWithInheritance(data, device, 'useIndividualSize', false);
  if (useIndividual) {
    const width = getV2ValueWithInheritance(data, device, 'width', 0);
    const height = getV2ValueWithInheritance(data, device, 'height', 0);
    return width === 0 && height === 0;
  }
  const size = getV2ValueWithInheritance(data, device, 'size', 0);
  return size === 0;
};

/**
 * V2: iconFrameのサイズ値を取得
 */
const getIconFrameV2SizeValue = (data, device, dimension) => {
  if (!data) return '0px';
  const useIndividual = getV2ValueWithInheritance(data, device, 'useIndividualSize', false);
  if (useIndividual) {
    const value = getV2ValueWithInheritance(data, device, dimension.toLowerCase(), 0);
    const unit = getV2ValueWithInheritance(data, device, `${dimension.toLowerCase()}Unit`, 'px');
    return `${value}${unit}`;
  }
  const size = getV2ValueWithInheritance(data, device, 'size', 0);
  const unit = getV2ValueWithInheritance(data, device, 'sizeUnit', 'px');
  return `${size}${unit}`;
};

/**
 * V2: iconFrameのボーダー幅を取得（サイド指定）
 */
const getIconFrameV2BorderWidthValue = (data, device, side) => {
  if (!data) return '0px';
  const sides = getV2ValueWithInheritance(data, device, 'borderSides', ['top', 'right', 'bottom', 'left']);
  if (!Array.isArray(sides) || !sides.includes(side)) return '0';
  const width = getV2ValueWithInheritance(data, device, 'borderWidth', 0);
  const unit = getV2ValueWithInheritance(data, device, 'borderWidthUnit', 'px');
  return `${width}${unit}`;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 * iconFrameV2が使用されていない場合は空を返す（V1へフォールバック）
 */
export const getIconFrameStylesV2 = (attributes) => {
  const data = attributes.iconFrameV2;
  if (!data || !isIconFrameV2Active(data)) return {};

  const styles = {};
  const device = 'pc';

  // Display
  styles['--icon-frame-display-pc'] = isIconFrameV2SizeZero(data, device) ? 'none' : 'block';

  // Size
  styles['--icon-frame-width-pc'] = getIconFrameV2SizeValue(data, device, 'Width');
  styles['--icon-frame-height-pc'] = getIconFrameV2SizeValue(data, device, 'Height');

  // Background color
  const bgColor = getV2ValueWithInheritance(data, device, 'bgColor', 'transparent');
  styles['--icon-frame-bg-color-pc'] = bgColor;

  // Radius
  const radius = getV2ValueWithInheritance(data, device, 'radius', 0);
  const radiusUnit = getV2ValueWithInheritance(data, device, 'radiusUnit', 'px');
  styles['--icon-frame-radius-pc'] = `${radius}${radiusUnit}`;

  // Border width
  const borderWidth = getV2ValueWithInheritance(data, device, 'borderWidth', 0);
  const borderWidthUnit = getV2ValueWithInheritance(data, device, 'borderWidthUnit', 'px');
  styles['--icon-frame-border-width-pc'] = `${borderWidth}${borderWidthUnit}`;
  styles['--icon-frame-border-top-width-pc'] = getIconFrameV2BorderWidthValue(data, device, 'top');
  styles['--icon-frame-border-right-width-pc'] = getIconFrameV2BorderWidthValue(data, device, 'right');
  styles['--icon-frame-border-bottom-width-pc'] = getIconFrameV2BorderWidthValue(data, device, 'bottom');
  styles['--icon-frame-border-left-width-pc'] = getIconFrameV2BorderWidthValue(data, device, 'left');

  // Border color
  const borderColor = getV2ValueWithInheritance(data, device, 'borderColor', 'transparent');
  styles['--icon-frame-border-color'] = borderColor;
  styles['--icon-frame-border-color-pc'] = borderColor;

  // Border style
  const borderStyle = getV2ValueWithInheritance(data, device, 'borderStyle', 'solid');
  styles['--icon-frame-border-style-pc'] = borderStyle;

  // Transition
  styles['--icon-frame-transition-duration'] = `${attributes.iconFrameTransitionDuration || 300}ms`;
  styles['--icon-frame-transition-delay'] = `${attributes.iconFrameTransitionDelay || 200}ms`;
  styles['--icon-frame-transition-easing'] = attributes.iconFrameTransitionEasing || 'ease';

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * iconFrameV2が使用されていない場合は空を返す（V1へフォールバック）
 */
export const getIconFrameStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.iconFrameV2;
  if (!data || !isIconFrameV2Active(data)) return {};

  const styles = {};

  // Display
  styles['--icon-frame-display-pc'] = isIconFrameV2SizeZero(data, previewDevice) ? 'none' : 'block';

  // Size
  styles['--icon-frame-width-pc'] = getIconFrameV2SizeValue(data, previewDevice, 'Width');
  styles['--icon-frame-height-pc'] = getIconFrameV2SizeValue(data, previewDevice, 'Height');

  // Background color
  const bgColor = getV2ValueWithInheritance(data, previewDevice, 'bgColor', 'transparent');
  styles['--icon-frame-bg-color-pc'] = bgColor;

  // Radius
  const radius = getV2ValueWithInheritance(data, previewDevice, 'radius', 0);
  const radiusUnit = getV2ValueWithInheritance(data, previewDevice, 'radiusUnit', 'px');
  styles['--icon-frame-radius-pc'] = `${radius}${radiusUnit}`;

  // Border width
  const borderWidth = getV2ValueWithInheritance(data, previewDevice, 'borderWidth', 0);
  const borderWidthUnit = getV2ValueWithInheritance(data, previewDevice, 'borderWidthUnit', 'px');
  styles['--icon-frame-border-width-pc'] = `${borderWidth}${borderWidthUnit}`;
  styles['--icon-frame-border-top-width-pc'] = getIconFrameV2BorderWidthValue(data, previewDevice, 'top');
  styles['--icon-frame-border-right-width-pc'] = getIconFrameV2BorderWidthValue(data, previewDevice, 'right');
  styles['--icon-frame-border-bottom-width-pc'] = getIconFrameV2BorderWidthValue(data, previewDevice, 'bottom');
  styles['--icon-frame-border-left-width-pc'] = getIconFrameV2BorderWidthValue(data, previewDevice, 'left');

  // Border color
  const borderColor = getV2ValueWithInheritance(data, previewDevice, 'borderColor', 'transparent');
  styles['--icon-frame-border-color'] = borderColor;
  styles['--icon-frame-border-color-pc'] = borderColor;

  // Border style
  const borderStyle = getV2ValueWithInheritance(data, previewDevice, 'borderStyle', 'solid');
  styles['--icon-frame-border-style-pc'] = borderStyle;

  // Transition
  styles['--icon-frame-transition-duration'] = `${attributes.iconFrameTransitionDuration || 300}ms`;
  styles['--icon-frame-transition-delay'] = `${attributes.iconFrameTransitionDelay || 200}ms`;
  styles['--icon-frame-transition-easing'] = attributes.iconFrameTransitionEasing || 'ease';

  return styles;
};

/**
 * save.js用: PCのみ出力（ホバー）
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getIconFrameHoverStylesV2 = (attributes) => {
  const data = attributes.iconFrameV2Hover;
  const normalData = attributes.iconFrameV2;
  // V2通常がアクティブでない場合はV1にフォールバック
  // V2通常がアクティブな場合はV2ホバー（V2通常へのフォールバック付き）を出力
  if (!normalData || !isIconFrameV2Active(normalData)) return {};

  const styles = {};
  const device = 'pc';

  // Size (hover uses normal as fallback)
  const getHoverSizeValue = (dimension) => {
    if (data) {
      const value = getV2ValueWithInheritance(data, device, dimension.toLowerCase(), '');
      if (value !== '') {
        const unit = getV2ValueWithInheritance(data, device, `${dimension.toLowerCase()}Unit`, 'px');
        return `${value}${unit}`;
      }
    }
    return normalData ? getIconFrameV2SizeValue(normalData, device, dimension) : '0px';
  };

  styles['--icon-frame-width-pc-hover'] = getHoverSizeValue('Width');
  styles['--icon-frame-height-pc-hover'] = getHoverSizeValue('Height');

  // Background color - 通常状態へのフォールバックは行わない（ホバーは独立した設定）
  const bgColor = data ? getV2ValueWithInheritance(data, device, 'bgColor', '') : '';
  styles['--icon-frame-bg-color-pc-hover'] = bgColor || 'transparent';

  // Radius
  const radius = data ? getV2ValueWithInheritance(data, device, 'radius', '') : '';
  const normalRadius = normalData ? getV2ValueWithInheritance(normalData, device, 'radius', 0) : 0;
  const radiusUnit = data ? getV2ValueWithInheritance(data, device, 'radiusUnit', '') : '';
  const normalRadiusUnit = normalData ? getV2ValueWithInheritance(normalData, device, 'radiusUnit', 'px') : 'px';
  styles['--icon-frame-radius-pc-hover'] = `${radius !== '' ? radius : normalRadius}${radiusUnit || normalRadiusUnit}`;

  // Border width
  const borderWidth = data ? getV2ValueWithInheritance(data, device, 'borderWidth', '') : '';
  const normalBorderWidth = normalData ? getV2ValueWithInheritance(normalData, device, 'borderWidth', 0) : 0;
  const borderWidthUnit = data ? getV2ValueWithInheritance(data, device, 'borderWidthUnit', '') : '';
  const normalBorderWidthUnit = normalData ? getV2ValueWithInheritance(normalData, device, 'borderWidthUnit', 'px') : 'px';
  styles['--icon-frame-border-width-pc-hover'] = `${borderWidth !== '' ? borderWidth : normalBorderWidth}${borderWidthUnit || normalBorderWidthUnit}`;

  // Border sides
  const getHoverBorderWidthValue = (side) => {
    const effectiveData = data || normalData;
    if (!effectiveData) return '0';
    const sides = getV2ValueWithInheritance(effectiveData, device, 'borderSides', ['top', 'right', 'bottom', 'left']);
    if (!Array.isArray(sides) || !sides.includes(side)) return '0';
    const width = borderWidth !== '' ? borderWidth : normalBorderWidth;
    const unit = borderWidthUnit || normalBorderWidthUnit;
    return `${width}${unit}`;
  };
  styles['--icon-frame-border-top-width-pc-hover'] = getHoverBorderWidthValue('top');
  styles['--icon-frame-border-right-width-pc-hover'] = getHoverBorderWidthValue('right');
  styles['--icon-frame-border-bottom-width-pc-hover'] = getHoverBorderWidthValue('bottom');
  styles['--icon-frame-border-left-width-pc-hover'] = getHoverBorderWidthValue('left');

  // Border color - 通常状態へのフォールバックは行わない（ホバーは独立した設定）
  const borderColor = data ? getV2ValueWithInheritance(data, device, 'borderColor', '') : '';
  styles['--icon-frame-border-color-hover'] = borderColor || 'transparent';
  styles['--icon-frame-border-color-pc-hover'] = borderColor || 'transparent';

  // Border style - 通常状態へのフォールバックは行わない（ホバーは独立した設定）
  const borderStyle = data ? getV2ValueWithInheritance(data, device, 'borderStyle', '') : '';
  styles['--icon-frame-border-style-pc-hover'] = borderStyle || 'solid';

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更（ホバー）
 */
export const getIconFrameHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.iconFrameV2Hover;
  const normalData = attributes.iconFrameV2;
  // V2通常がアクティブでない場合はV1にフォールバック
  // V2通常がアクティブな場合はV2ホバー（V2通常へのフォールバック付き）を出力
  if (!normalData || !isIconFrameV2Active(normalData)) return {};

  const styles = {};

  // Size (hover uses normal as fallback)
  const getHoverSizeValue = (dimension) => {
    if (data) {
      const value = getV2ValueWithInheritance(data, previewDevice, dimension.toLowerCase(), '');
      if (value !== '') {
        const unit = getV2ValueWithInheritance(data, previewDevice, `${dimension.toLowerCase()}Unit`, 'px');
        return `${value}${unit}`;
      }
    }
    return normalData ? getIconFrameV2SizeValue(normalData, previewDevice, dimension) : '0px';
  };

  styles['--icon-frame-width-pc-hover'] = getHoverSizeValue('Width');
  styles['--icon-frame-height-pc-hover'] = getHoverSizeValue('Height');

  // Background color - 通常状態へのフォールバックは行わない（ホバーは独立した設定）
  const bgColor = data ? getV2ValueWithInheritance(data, previewDevice, 'bgColor', '') : '';
  styles['--icon-frame-bg-color-pc-hover'] = bgColor || 'transparent';

  // Radius
  const radius = data ? getV2ValueWithInheritance(data, previewDevice, 'radius', '') : '';
  const normalRadius = normalData ? getV2ValueWithInheritance(normalData, previewDevice, 'radius', 0) : 0;
  const radiusUnit = data ? getV2ValueWithInheritance(data, previewDevice, 'radiusUnit', '') : '';
  const normalRadiusUnit = normalData ? getV2ValueWithInheritance(normalData, previewDevice, 'radiusUnit', 'px') : 'px';
  styles['--icon-frame-radius-pc-hover'] = `${radius !== '' ? radius : normalRadius}${radiusUnit || normalRadiusUnit}`;

  // Border width
  const borderWidth = data ? getV2ValueWithInheritance(data, previewDevice, 'borderWidth', '') : '';
  const normalBorderWidth = normalData ? getV2ValueWithInheritance(normalData, previewDevice, 'borderWidth', 0) : 0;
  const borderWidthUnit = data ? getV2ValueWithInheritance(data, previewDevice, 'borderWidthUnit', '') : '';
  const normalBorderWidthUnit = normalData ? getV2ValueWithInheritance(normalData, previewDevice, 'borderWidthUnit', 'px') : 'px';
  styles['--icon-frame-border-width-pc-hover'] = `${borderWidth !== '' ? borderWidth : normalBorderWidth}${borderWidthUnit || normalBorderWidthUnit}`;

  // Border sides
  const getHoverBorderWidthValue = (side) => {
    const effectiveData = data || normalData;
    if (!effectiveData) return '0';
    const sides = getV2ValueWithInheritance(effectiveData, previewDevice, 'borderSides', ['top', 'right', 'bottom', 'left']);
    if (!Array.isArray(sides) || !sides.includes(side)) return '0';
    const width = borderWidth !== '' ? borderWidth : normalBorderWidth;
    const unit = borderWidthUnit || normalBorderWidthUnit;
    return `${width}${unit}`;
  };
  styles['--icon-frame-border-top-width-pc-hover'] = getHoverBorderWidthValue('top');
  styles['--icon-frame-border-right-width-pc-hover'] = getHoverBorderWidthValue('right');
  styles['--icon-frame-border-bottom-width-pc-hover'] = getHoverBorderWidthValue('bottom');
  styles['--icon-frame-border-left-width-pc-hover'] = getHoverBorderWidthValue('left');

  // Border color - 通常状態へのフォールバックは行わない（ホバーは独立した設定）
  const borderColor = data ? getV2ValueWithInheritance(data, previewDevice, 'borderColor', '') : '';
  styles['--icon-frame-border-color-hover'] = borderColor || 'transparent';
  styles['--icon-frame-border-color-pc-hover'] = borderColor || 'transparent';

  // Border style - 通常状態へのフォールバックは行わない（ホバーは独立した設定）
  const borderStyle = data ? getV2ValueWithInheritance(data, previewDevice, 'borderStyle', '') : '';
  styles['--icon-frame-border-style-pc-hover'] = borderStyle || 'solid';

  return styles;
};

const getV2ValueWithInheritance = (data, device, key, defaultValue = '') => {
  if (!data) return defaultValue;
  const enabledBreakpoints = getEnabledBreakpoints();
  const currentIndex = enabledBreakpoints.indexOf(device);
  for (let i = currentIndex; i >= 0; i--) {
    const bp = enabledBreakpoints[i];
    if (data[bp] && data[bp][key] !== undefined && data[bp][key] !== '' && data[bp][key] !== null) {
      return data[bp][key];
    }
  }
  return defaultValue;
};

const getV2DirectValue = (data, device, key) => {
  if (!data || !data[device]) return undefined;
  const val = data[device][key];
  if (val !== undefined && val !== '' && val !== null) {
    return val;
  }
  return undefined;
};

const getBackgroundColorV2Value = (attributes, device, isHover = false) => {
  const attrName = isHover ? 'backgroundColorV2Hover' : 'backgroundColorV2';
  const data = attributes[attrName];
  if (!data) return 'transparent';
  const useGradient = getV2ValueWithInheritance(data, device, 'useGradient', false);
  const gradient = getV2ValueWithInheritance(data, device, 'gradient', '');
  const color = getV2ValueWithInheritance(data, device, 'color', '');
  if (useGradient && gradient) return gradient;
  const effectiveColor = color || 'transparent';
  return `linear-gradient(90deg, ${effectiveColor} 0%, ${effectiveColor} 100%)`;
};

const getBackgroundColorV2DirectValue = (attributes, device) => {
  const data = attributes.backgroundColorV2Hover;
  if (!data || !data[device]) return '';
  const bpData = data[device];
  const color = bpData.color;
  const gradient = bpData.gradient;
  const useGradient = bpData.useGradient;
  if (useGradient && gradient) return gradient;
  if (color && color !== '') return `linear-gradient(90deg, ${color} 0%, ${color} 100%)`;
  return '';
};

const getBackgroundColorV2HoverValueWithInheritance = (attributes, device) => {
  const data = attributes.backgroundColorV2Hover;
  if (!data) return '';
  const enabledBreakpoints = getEnabledBreakpoints();
  const currentIndex = enabledBreakpoints.indexOf(device);
  for (let i = currentIndex; i >= 0; i--) {
    const bp = enabledBreakpoints[i];
    if (!data[bp]) continue;
    const bpData = data[bp];
    const color = bpData.color;
    const gradient = bpData.gradient;
    const useGradient = bpData.useGradient;
    if (useGradient && gradient) return gradient;
    if (color && color !== '') return `linear-gradient(90deg, ${color} 0%, ${color} 100%)`;
  }
  return '';
};

const getBackgroundColorV2DirectValueForBp = (attributes, device) => {
  const data = attributes.backgroundColorV2;
  if (!data || !data[device]) return undefined;
  const bpData = data[device];
  const color = bpData.color;
  const gradient = bpData.gradient;
  const useGradient = bpData.useGradient;
  if (useGradient && gradient) return gradient;
  if (color && color !== '') return `linear-gradient(90deg, ${color} 0%, ${color} 100%)`;
  return undefined;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getBackgroundColorStylesV2 = (attributes) => {
  const data = attributes.backgroundColorV2;
  const styles = {};

  // Get PC values only
  const pcValue = getBackgroundColorV2Value(attributes, 'pc');
  const pcOpacity = getV2ValueWithInheritance(data, 'pc', "opacity", 1);
  const pcMixBlendMode = getV2ValueWithInheritance(data, 'pc', "mixBlendMode", "normal");

  styles['--background-color-pc'] = pcValue;
  styles['--background-color-opacity-pc'] = pcOpacity;
  styles['--background-color-mix-blend-mode-pc'] = pcMixBlendMode;

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBackgroundColorStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.backgroundColorV2;
  const styles = {};

  // プレビューデバイスの値を取得（継承付き）
  const value = getBackgroundColorV2Value(attributes, previewDevice);
  const opacity = getV2ValueWithInheritance(data, previewDevice, "opacity", 1);
  const mixBlendMode = getV2ValueWithInheritance(data, previewDevice, "mixBlendMode", "normal");

  styles['--background-color-pc'] = value;
  styles['--background-color-opacity-pc'] = opacity;
  styles['--background-color-mix-blend-mode-pc'] = mixBlendMode;

  return styles;
};

const getBackgroundColorV2HoverDirectValueForBp = (attributes, device) => {
  const data = attributes.backgroundColorV2Hover;
  if (!data || !data[device]) return undefined;
  const bpData = data[device];
  const color = bpData.color;
  const gradient = bpData.gradient;
  const useGradient = bpData.useGradient;
  if (useGradient && gradient) return gradient;
  if (color && color !== '') return `linear-gradient(90deg, ${color} 0%, ${color} 100%)`;
  return undefined;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getBackgroundColorHoverStylesV2 = (attributes) => {
  const data = attributes.backgroundColorV2Hover;
  const normalData = attributes.backgroundColorV2;
  const styles = {};

  // Helper to get hover value with fallback to normal (PC only)
  // 空文字もフォールバック対象とする（block.jsonのデフォルト値が空文字のため）
  const getHoverOpacity = () => {
    const hoverOpacity = getV2ValueWithInheritance(data, 'pc', "opacity", undefined);
    if (hoverOpacity !== undefined && hoverOpacity !== '') return hoverOpacity;
    return getV2ValueWithInheritance(normalData, 'pc', "opacity", 1);
  };

  const getHoverMixBlend = () => {
    const hoverMixBlend = getV2ValueWithInheritance(data, 'pc', "mixBlendMode", undefined);
    if (hoverMixBlend !== undefined && hoverMixBlend !== '') return hoverMixBlend;
    return getV2ValueWithInheritance(normalData, 'pc', "mixBlendMode", "normal");
  };

  const getHoverColor = () => {
    const hoverValue = getBackgroundColorV2HoverValueWithInheritance(attributes, 'pc');
    if (hoverValue) return hoverValue;
    return getBackgroundColorV2Value(attributes, 'pc', false);
  };

  // Get PC values only
  styles['--background-color-pc-hover'] = getHoverColor();
  styles['--background-color-opacity-pc-hover'] = getHoverOpacity();
  styles['--background-color-mix-blend-mode-pc-hover'] = getHoverMixBlend();

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * ホバー値がなければ通常値にフォールバック
 */
export const getBackgroundColorHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.backgroundColorV2Hover;
  const normalData = attributes.backgroundColorV2;
  const styles = {};

  // Helper to get hover value with fallback to normal
  // 空文字もフォールバック対象とする（block.jsonのデフォルト値が空文字のため）
  const getHoverOpacity = (bp) => {
    const hoverOpacity = getV2ValueWithInheritance(data, bp, "opacity", undefined);
    if (hoverOpacity !== undefined && hoverOpacity !== '') return hoverOpacity;
    return getV2ValueWithInheritance(normalData, bp, "opacity", 1);
  };

  const getHoverMixBlend = (bp) => {
    const hoverMixBlend = getV2ValueWithInheritance(data, bp, "mixBlendMode", undefined);
    if (hoverMixBlend !== undefined && hoverMixBlend !== '') return hoverMixBlend;
    return getV2ValueWithInheritance(normalData, bp, "mixBlendMode", "normal");
  };

  const getHoverColor = (bp) => {
    const hoverValue = getBackgroundColorV2HoverValueWithInheritance(attributes, bp);
    if (hoverValue) return hoverValue;
    return getBackgroundColorV2Value(attributes, bp, false);
  };

  // プレビューデバイスの値を取得、PC変数名で出力
  styles['--background-color-pc-hover'] = getHoverColor(previewDevice);
  styles['--background-color-opacity-pc-hover'] = getHoverOpacity(previewDevice);
  styles['--background-color-mix-blend-mode-pc-hover'] = getHoverMixBlend(previewDevice);

  return styles;
};

// Helper to get background image size value including custom dimensions
const getBackgroundImageSizeValue = (data, bp) => {
  const size = getV2ValueWithInheritance(data, bp, "size", "cover");
  if (size === "fill" || size === "none") {
    const customWidth = getV2ValueWithInheritance(data, bp, "customWidth", "auto");
    const customWidthUnit = getV2ValueWithInheritance(data, bp, "customWidthUnit", "%");
    const customHeight = getV2ValueWithInheritance(data, bp, "customHeight", "auto");
    const customHeightUnit = getV2ValueWithInheritance(data, bp, "customHeightUnit", "%");
    const width = customWidth === "auto" ? "auto" : `${customWidth}${customWidthUnit}`;
    const height = customHeight === "auto" ? "auto" : `${customHeight}${customHeightUnit}`;
    return `${width} ${height}`;
  }
  return size;
};

const getBackgroundImageRotateValue = (data, bp, fallback = "0deg") => {
  const rawValue = getV2ValueWithInheritance(data, bp, "rotate", "0");
  const normalized = String(rawValue ?? "").trim();
  if (!normalized) return fallback;
  if (normalized.endsWith("deg")) return normalized;
  const parsed = Number.parseFloat(normalized);
  return Number.isFinite(parsed) ? `${parsed}deg` : fallback;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getBackgroundImageStylesV2 = (attributes) => {
  const data = attributes.backgroundImageV2;
  if (!data) return {};
  const styles = {};

  // Get PC values only
  const pcUrl = getV2ValueWithInheritance(data, 'pc', "url", '');
  const pcPosition = getV2ValueWithInheritance(data, 'pc', "position", "center center");
  const pcSize = getBackgroundImageSizeValue(data, 'pc');
  const pcRepeat = getV2ValueWithInheritance(data, 'pc', "repeat", "no-repeat");
  const pcRotate = getBackgroundImageRotateValue(data, 'pc', "0deg");

  styles['--background-image-pc'] = pcUrl ? `url(${pcUrl})` : "none";
  styles['--background-position-pc'] = pcPosition;
  styles['--background-size-pc'] = pcSize;
  styles['--background-repeat-pc'] = pcRepeat;
  styles['--background-rotate-pc'] = pcRotate;

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBackgroundImageStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.backgroundImageV2;
  if (!data) return {};
  const styles = {};

  // プレビューデバイスの値を取得（継承付き）
  const url = getV2ValueWithInheritance(data, previewDevice, "url", '');
  const position = getV2ValueWithInheritance(data, previewDevice, "position", "center center");
  const size = getBackgroundImageSizeValue(data, previewDevice);
  const repeat = getV2ValueWithInheritance(data, previewDevice, "repeat", "no-repeat");
  const rotate = getBackgroundImageRotateValue(data, previewDevice, "0deg");

  styles['--background-image-pc'] = url ? `url(${url})` : "none";
  styles['--background-position-pc'] = position;
  styles['--background-size-pc'] = size;
  styles['--background-repeat-pc'] = repeat;
  styles['--background-rotate-pc'] = rotate;

  return styles;
};

/**
 * ホバー時の背景画像スタイル（位置・サイズ・リピートのみ）
 * 注意: 画像URL自体は通常状態から継承するため出力しない
 */
export const getBackgroundImageHoverStylesV2 = (attributes) => {
  const data = attributes.backgroundImageV2Hover;
  const normalData = attributes.backgroundImageV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal
  const getHoverValue = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  // Helper to get size value including custom dimensions
  const getSizeValue = (bp) => {
    const size = getHoverValue(bp, "size", "cover");
    if (size === "fill" || size === "none") {
      const customWidth = getHoverValue(bp, "customWidth", "auto");
      const customWidthUnit = getHoverValue(bp, "customWidthUnit", "%");
      const customHeight = getHoverValue(bp, "customHeight", "auto");
      const customHeightUnit = getHoverValue(bp, "customHeightUnit", "%");
      const width = customWidth === "auto" ? "auto" : `${customWidth}${customWidthUnit}`;
      const height = customHeight === "auto" ? "auto" : `${customHeight}${customHeightUnit}`;
      return `${width} ${height}`;
    }
    return size;
  };

  // Get PC values only (position, size, repeat - no URL)
  const pcPosition = getHoverValue('pc', "position", "center center");
  const pcSize = getSizeValue('pc');
  const pcRepeat = getHoverValue('pc', "repeat", "no-repeat");
  const pcRotate = getBackgroundImageRotateValue(
    {
      pc: {
        rotate: getHoverValue('pc', "rotate", "0"),
      },
    },
    'pc',
    getBackgroundImageRotateValue(normalData, 'pc', "0deg")
  );

  // PC用のみ出力（MD/TB/SP用はPHP CSSのフォールバックに任せる）
  styles[`--background-position-pc-hover`] = pcPosition;
  styles[`--background-size-pc-hover`] = pcSize;
  styles[`--background-repeat-pc-hover`] = pcRepeat;
  styles[`--background-rotate-pc-hover`] = pcRotate;

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * ホバー時の背景画像スタイル（位置・サイズ・リピートのみ）
 */
export const getBackgroundImageHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.backgroundImageV2Hover;
  const normalData = attributes.backgroundImageV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal
  const getHoverValue = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  // Helper to get size value including custom dimensions
  const getHoverSizeValue = (bp) => {
    const size = getHoverValue(bp, "size", "cover");
    if (size === "fill" || size === "none") {
      const customWidth = getHoverValue(bp, "customWidth", "auto");
      const customWidthUnit = getHoverValue(bp, "customWidthUnit", "%");
      const customHeight = getHoverValue(bp, "customHeight", "auto");
      const customHeightUnit = getHoverValue(bp, "customHeightUnit", "%");
      const width = customWidth === "auto" ? "auto" : `${customWidth}${customWidthUnit}`;
      const height = customHeight === "auto" ? "auto" : `${customHeight}${customHeightUnit}`;
      return `${width} ${height}`;
    }
    return size;
  };

  // プレビューデバイスの値を取得
  const position = getHoverValue(previewDevice, "position", "center center");
  const size = getHoverSizeValue(previewDevice);
  const repeat = getHoverValue(previewDevice, "repeat", "no-repeat");
  const rotate = getBackgroundImageRotateValue(
    {
      [previewDevice]: {
        rotate: getHoverValue(previewDevice, "rotate", "0"),
      },
    },
    previewDevice,
    getBackgroundImageRotateValue(normalData, previewDevice, "0deg")
  );

  styles['--background-position-pc-hover'] = position;
  styles['--background-size-pc-hover'] = size;
  styles['--background-repeat-pc-hover'] = repeat;
  styles['--background-rotate-pc-hover'] = rotate;

  return styles;
};

/**
 * save.js用: PCのみ出力
 * 背景ベースカラー（bg-imageのbackground-color）
 */
export const getBackgroundBaseColorStylesV2 = (attributes) => {
  const data = attributes.backgroundBaseColorV2;
  if (!data) return {};
  const styles = {};
  const DEFAULT_GRADIENT = 'linear-gradient(135deg, #007FD6 0%, #02439D 100%)';

  // Get PC value only
  const useGradient = getV2ValueWithInheritance(data, 'pc', "useGradient", false);
  const gradient = getV2ValueWithInheritance(data, 'pc', "gradient", '');

  // グラデーションモードの場合（gradientが空でもデフォルト値を使用）
  if (useGradient) {
    const gradientValue = gradient || DEFAULT_GRADIENT;
    styles['--background-base-gradient-pc'] = gradientValue;
    styles['--background-base-color-pc'] = 'transparent';
  } else {
    const pcColor = getV2ValueWithInheritance(data, 'pc', "color", '');
    const pcAlpha = getV2ValueWithInheritance(data, 'pc', "alpha", 1);
    if (pcColor) {
      styles['--background-base-color-pc'] = getColorWithAlpha(pcColor, pcAlpha);
    }
  }

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBackgroundBaseColorStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.backgroundBaseColorV2;
  if (!data) return {};
  const styles = {};
  const DEFAULT_GRADIENT = 'linear-gradient(135deg, #007FD6 0%, #02439D 100%)';

  // プレビューデバイスの値を取得（継承付き）
  const useGradient = getV2ValueWithInheritance(data, previewDevice, "useGradient", false);
  const gradient = getV2ValueWithInheritance(data, previewDevice, "gradient", '');

  // グラデーションモードの場合（gradientが空でもデフォルト値を使用）
  if (useGradient) {
    const gradientValue = gradient || DEFAULT_GRADIENT;
    styles['--background-base-gradient-pc'] = gradientValue;
    styles['--background-base-color-pc'] = 'transparent';
  } else {
    const color = getV2ValueWithInheritance(data, previewDevice, "color", '');
    const alpha = getV2ValueWithInheritance(data, previewDevice, "alpha", 1);
    if (color) {
      styles['--background-base-color-pc'] = getColorWithAlpha(color, alpha);
    }
  }

  return styles;
};

/**
 * save.js用: PCのみ出力
 * 背景ベースカラー（ホバー）
 */
export const getBackgroundBaseColorHoverStylesV2 = (attributes) => {
  const data = attributes.backgroundBaseColorV2Hover;
  const normalData = attributes.backgroundBaseColorV2;
  if (!data && !normalData) return {};
  const styles = {};
  const DEFAULT_GRADIENT = 'linear-gradient(135deg, #007FD6 0%, #02439D 100%)';

  // Determine if hover uses gradient
  const getHoverUseGradient = (bp) => {
    const hoverUseGradient = getV2ValueWithInheritance(data, bp, "useGradient", null);
    if (hoverUseGradient !== null && hoverUseGradient !== '') return hoverUseGradient;
    return getV2ValueWithInheritance(normalData, bp, "useGradient", false);
  };

  // Get hover gradient with fallback to normal
  const getHoverGradient = (bp) => {
    const hoverUseGradient = getV2ValueWithInheritance(data, bp, "useGradient", null);
    const hoverGradient = getV2ValueWithInheritance(data, bp, "gradient", '');
    if (hoverUseGradient) return hoverGradient || DEFAULT_GRADIENT;
    if (hoverUseGradient === false) return '';
    const normalUseGradient = getV2ValueWithInheritance(normalData, bp, "useGradient", false);
    const normalGradient = getV2ValueWithInheritance(normalData, bp, "gradient", '');
    if (normalUseGradient) return normalGradient || DEFAULT_GRADIENT;
    return '';
  };

  // Get hover color with fallback to normal
  const getHoverColorWithAlpha = (bp) => {
    const hoverColor = getV2ValueWithInheritance(data, bp, "color", '');
    const hoverAlpha = getV2ValueWithInheritance(data, bp, "alpha", '');
    if (hoverColor) {
      const alpha = hoverAlpha !== '' ? hoverAlpha : 1;
      return getColorWithAlpha(hoverColor, alpha);
    }
    // Fallback to normal
    const normalColor = getV2ValueWithInheritance(normalData, bp, "color", '');
    const normalAlpha = getV2ValueWithInheritance(normalData, bp, "alpha", 1);
    if (normalColor) {
      return getColorWithAlpha(normalColor, normalAlpha);
    }
    return '';
  };

  const useGradient = getHoverUseGradient('pc');
  if (useGradient) {
    const hoverGradient = getHoverGradient('pc');
    styles['--background-base-gradient-pc-hover'] = hoverGradient;
    styles['--background-base-color-pc-hover'] = 'transparent';
  } else {
    const pcHoverColor = getHoverColorWithAlpha('pc');
    if (pcHoverColor) {
      styles['--background-base-color-pc-hover'] = pcHoverColor;
      // グラデーション→単色切り替え時、単色をグラデーションとしても設定（白フラッシュ防止）
      styles['--background-base-gradient-pc-hover'] = `linear-gradient(0deg, ${pcHoverColor} 0%, ${pcHoverColor} 100%)`;
    } else {
      styles['--background-base-gradient-pc-hover'] = 'none';
    }
  }

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBackgroundBaseColorHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.backgroundBaseColorV2Hover;
  const normalData = attributes.backgroundBaseColorV2;
  if (!data && !normalData) return {};
  const styles = {};
  const DEFAULT_GRADIENT = 'linear-gradient(135deg, #007FD6 0%, #02439D 100%)';

  // Determine if hover uses gradient
  const getHoverUseGradient = (bp) => {
    const hoverUseGradient = getV2ValueWithInheritance(data, bp, "useGradient", null);
    if (hoverUseGradient !== null && hoverUseGradient !== '') return hoverUseGradient;
    return getV2ValueWithInheritance(normalData, bp, "useGradient", false);
  };

  // Get hover gradient with fallback to normal
  const getHoverGradient = (bp) => {
    const hoverUseGradient = getV2ValueWithInheritance(data, bp, "useGradient", null);
    const hoverGradient = getV2ValueWithInheritance(data, bp, "gradient", '');
    if (hoverUseGradient) return hoverGradient || DEFAULT_GRADIENT;
    if (hoverUseGradient === false) return '';
    const normalUseGradient = getV2ValueWithInheritance(normalData, bp, "useGradient", false);
    const normalGradient = getV2ValueWithInheritance(normalData, bp, "gradient", '');
    if (normalUseGradient) return normalGradient || DEFAULT_GRADIENT;
    return '';
  };

  // Get hover color with fallback to normal
  const getHoverColorWithAlpha = (bp) => {
    const hoverColor = getV2ValueWithInheritance(data, bp, "color", '');
    const hoverAlpha = getV2ValueWithInheritance(data, bp, "alpha", '');
    if (hoverColor) {
      const alpha = hoverAlpha !== '' ? hoverAlpha : 1;
      return getColorWithAlpha(hoverColor, alpha);
    }
    // Fallback to normal
    const normalColor = getV2ValueWithInheritance(normalData, bp, "color", '');
    const normalAlpha = getV2ValueWithInheritance(normalData, bp, "alpha", 1);
    if (normalColor) {
      return getColorWithAlpha(normalColor, normalAlpha);
    }
    return '';
  };

  const useGradient = getHoverUseGradient(previewDevice);
  if (useGradient) {
    const hoverGradient = getHoverGradient(previewDevice);
    styles['--background-base-gradient-pc-hover'] = hoverGradient;
    styles['--background-base-color-pc-hover'] = 'transparent';
  } else {
    const hoverColor = getHoverColorWithAlpha(previewDevice);
    if (hoverColor) {
      styles['--background-base-color-pc-hover'] = hoverColor;
      // グラデーション→単色切り替え時、単色をグラデーションとしても設定（白フラッシュ防止）
      styles['--background-base-gradient-pc-hover'] = `linear-gradient(0deg, ${hoverColor} 0%, ${hoverColor} 100%)`;
    } else {
      styles['--background-base-gradient-pc-hover'] = 'none';
    }
  }

  return styles;
};

/**
 * save.js用: PCのみ出力
 * サムネイル画像ベースカラー（thumbnail-imageのbackground-color）
 */
export const getThumbnailImageBaseColorStylesV2 = (attributes) => {
  const data = attributes.thumbnailImageBaseColorV2;
  if (!data) return {};
  const styles = {};

  // Get PC value only
  const pcColor = getV2ValueWithInheritance(data, 'pc', "color", '');
  const pcAlpha = getV2ValueWithInheritance(data, 'pc', "alpha", 1);
  if (pcColor) {
    styles['--thumbnail-image-base-color-pc'] = getColorWithAlpha(pcColor, pcAlpha);
  }

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getThumbnailImageBaseColorStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.thumbnailImageBaseColorV2;
  if (!data) return {};
  const styles = {};

  // プレビューデバイスの値を取得（継承付き）
  const color = getV2ValueWithInheritance(data, previewDevice, "color", '');
  const alpha = getV2ValueWithInheritance(data, previewDevice, "alpha", 1);
  if (color) {
    styles['--thumbnail-image-base-color-pc'] = getColorWithAlpha(color, alpha);
  }

  return styles;
};

/**
 * save.js用: PCのみ出力
 * サムネイル画像ベースカラー（ホバー）
 */
export const getThumbnailImageBaseColorHoverStylesV2 = (attributes) => {
  const data = attributes.thumbnailImageBaseColorV2Hover;
  const normalData = attributes.thumbnailImageBaseColorV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Get hover color with fallback to normal
  const getHoverColorWithAlpha = (bp) => {
    const hoverColor = getV2ValueWithInheritance(data, bp, "color", '');
    const hoverAlpha = getV2ValueWithInheritance(data, bp, "alpha", '');
    if (hoverColor) {
      const alpha = hoverAlpha !== '' ? hoverAlpha : 1;
      return getColorWithAlpha(hoverColor, alpha);
    }
    // Fallback to normal
    const normalColor = getV2ValueWithInheritance(normalData, bp, "color", '');
    const normalAlpha = getV2ValueWithInheritance(normalData, bp, "alpha", 1);
    if (normalColor) {
      return getColorWithAlpha(normalColor, normalAlpha);
    }
    return '';
  };

  const pcHoverColor = getHoverColorWithAlpha('pc');
  if (pcHoverColor) styles['--thumbnail-image-base-color-pc-hover'] = pcHoverColor;

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getThumbnailImageBaseColorHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.thumbnailImageBaseColorV2Hover;
  const normalData = attributes.thumbnailImageBaseColorV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Get hover color with fallback to normal
  const getHoverColorWithAlpha = (bp) => {
    const hoverColor = getV2ValueWithInheritance(data, bp, "color", '');
    const hoverAlpha = getV2ValueWithInheritance(data, bp, "alpha", '');
    if (hoverColor) {
      const alpha = hoverAlpha !== '' ? hoverAlpha : 1;
      return getColorWithAlpha(hoverColor, alpha);
    }
    // Fallback to normal
    const normalColor = getV2ValueWithInheritance(normalData, bp, "color", '');
    const normalAlpha = getV2ValueWithInheritance(normalData, bp, "alpha", 1);
    if (normalColor) {
      return getColorWithAlpha(normalColor, normalAlpha);
    }
    return '';
  };

  const hoverColor = getHoverColorWithAlpha(previewDevice);
  if (hoverColor) styles['--thumbnail-image-base-color-pc-hover'] = hoverColor;

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getBackgroundPatternStylesV2 = (attributes) => {
  const data = attributes.backgroundPatternV2;
  if (!data) return {};
  const styles = {};

  // Get PC values only
  const pcType = getV2ValueWithInheritance(data, 'pc', "type", '');
  const pcColor = getV2ValueWithInheritance(data, 'pc', "color", '');
  const pcOpacity = getV2ValueWithInheritance(data, 'pc', "opacity", '');
  const pcSize = getV2ValueWithInheritance(data, 'pc', "size", '');
  const pcSizeUnit = getV2ValueWithInheritance(data, 'pc', "sizeUnit", "px");
  const pcRotate = getV2ValueWithInheritance(data, 'pc', "rotate", '');

  if (pcType) styles['--background-pattern-type-pc'] = pcType;
  if (pcColor) styles['--background-pattern-color-pc'] = pcColor;
  if (pcOpacity !== '' && pcOpacity !== undefined) styles['--background-pattern-opacity-pc'] = pcOpacity;
  if (pcSize !== '' && pcSize !== undefined && pcSize !== null) styles['--background-pattern-size-pc'] = `${pcSize}${pcSizeUnit}`;
  if (pcRotate !== '' && pcRotate !== undefined) styles['--background-pattern-rotate-pc'] = `${pcRotate}deg`;

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBackgroundPatternStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.backgroundPatternV2;
  if (!data) return {};
  const styles = {};

  // プレビューデバイスの値を取得（継承付き）
  const type = getV2ValueWithInheritance(data, previewDevice, "type", '');
  const color = getV2ValueWithInheritance(data, previewDevice, "color", '');
  const opacity = getV2ValueWithInheritance(data, previewDevice, "opacity", '');
  const size = getV2ValueWithInheritance(data, previewDevice, "size", '');
  const sizeUnit = getV2ValueWithInheritance(data, previewDevice, "sizeUnit", "px");
  const mixBlendMode = getV2ValueWithInheritance(data, previewDevice, "mixBlendMode", '');

  if (type) styles['--background-pattern-type-pc'] = type;
  if (color) styles['--background-pattern-color-pc'] = color;
  if (opacity !== '' && opacity !== undefined) styles['--background-pattern-opacity-pc'] = opacity;
  if (size !== '' && size !== undefined && size !== null) styles['--background-pattern-size-pc'] = `${size}${sizeUnit}`;
  if (mixBlendMode) styles['--background-pattern-blend-mode-pc'] = mixBlendMode;

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getBackgroundPatternHoverStylesV2 = (attributes) => {
  const data = attributes.backgroundPatternV2Hover;
  const normalData = attributes.backgroundPatternV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal (PC only)
  const getHoverValue = (key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, 'pc', key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, 'pc', key, defaultVal);
  };

  // Get PC values only
  const pcType = getHoverValue("type", '');
  const pcColor = getHoverValue("color", '');
  const pcOpacity = getHoverValue("opacity", '');
  const pcSize = getHoverValue("size", '');
  const pcSizeUnit = getHoverValue("sizeUnit", "px");
  const pcMixBlendMode = getHoverValue("mixBlendMode", '');

  if (pcType) styles['--background-pattern-type-pc-hover'] = pcType;
  if (pcColor) styles['--background-pattern-color-pc-hover'] = pcColor;
  if (pcOpacity !== '' && pcOpacity !== undefined) styles['--background-pattern-opacity-pc-hover'] = pcOpacity;
  if (pcSize !== '' && pcSize !== undefined && pcSize !== null) styles['--background-pattern-size-pc-hover'] = `${pcSize}${pcSizeUnit}`;
  if (pcMixBlendMode) styles['--background-pattern-blend-mode-pc-hover'] = pcMixBlendMode;

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * ホバー値がなければ通常値にフォールバック
 */
export const getBackgroundPatternHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.backgroundPatternV2Hover;
  const normalData = attributes.backgroundPatternV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal
  const getHoverValue = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  // プレビューデバイスの値を取得、PC変数名で出力
  const type = getHoverValue(previewDevice, "type", '');
  const color = getHoverValue(previewDevice, "color", '');
  const opacity = getHoverValue(previewDevice, "opacity", '');
  const size = getHoverValue(previewDevice, "size", '');
  const sizeUnit = getHoverValue(previewDevice, "sizeUnit", "px");
  const mixBlendMode = getHoverValue(previewDevice, "mixBlendMode", '');

  if (type) styles['--background-pattern-type-pc-hover'] = type;
  if (color) styles['--background-pattern-color-pc-hover'] = color;
  if (opacity !== '' && opacity !== undefined) styles['--background-pattern-opacity-pc-hover'] = opacity;
  if (size !== '' && size !== undefined && size !== null) styles['--background-pattern-size-pc-hover'] = `${size}${sizeUnit}`;
  if (mixBlendMode) styles['--background-pattern-blend-mode-pc-hover'] = mixBlendMode;

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getIconSizeStylesV2 = (attributes) => {
  const data = attributes.iconSizeV2;
  if (!data) return {};
  const styles = {};

  // Get PC value with inheritance
  const pcValue = getV2ValueWithInheritance(data, 'pc', "value", '');
  const pcUnit = getV2ValueWithInheritance(data, 'pc', "unit", "px");
  if (pcValue) {
    styles['--icon-size-pc'] = `${pcValue}${pcUnit}`;
  }
  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getIconSizeStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.iconSizeV2;
  if (!data) return {};
  const styles = {};

  // プレビューデバイスの値を取得（フォールバック付き）
  const value = getV2ValueWithInheritance(data, previewDevice, "value", '');
  const unit = getV2ValueWithInheritance(data, previewDevice, "unit", "px");
  if (value) {
    // PC変数名で出力、値はプレビューデバイスの値
    styles['--icon-size-pc'] = `${value}${unit}`;
  }
  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getIconSizeHoverStylesV2 = (attributes) => {
  const data = attributes.iconSizeV2Hover;
  const normalData = attributes.iconSizeV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value (hover data first, then normal data)
  const getHoverValue = (bp) => {
    // Try hover data first
    if (data && data[bp] && data[bp].value !== undefined && data[bp].value !== '' && data[bp].value !== null) {
      const unit = data[bp].unit || 'px';
      return `${data[bp].value}${unit}`;
    }
    // Try normal data
    if (normalData && normalData[bp] && normalData[bp].value !== undefined && normalData[bp].value !== '' && normalData[bp].value !== null) {
      const unit = normalData[bp].unit || 'px';
      return `${normalData[bp].value}${unit}`;
    }
    return null;
  };

  // Get PC value only
  const pcValue = getHoverValue('pc');
  if (pcValue) {
    styles['--icon-size-pc-hover'] = pcValue;
  }
  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getIconSizeHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.iconSizeV2Hover;
  const normalData = attributes.iconSizeV2;
  if (!data && !normalData) return {};
  const styles = {};
  const enabledBreakpoints = getEnabledBreakpoints();

  // Helper to get hover value with inheritance
  const getInheritedHoverValue = (targetBp) => {
    const currentIndex = enabledBreakpoints.indexOf(targetBp);
    for (let i = currentIndex; i >= 0; i--) {
      const bp = enabledBreakpoints[i];
      // Try hover data first
      if (data && data[bp] && data[bp].value !== undefined && data[bp].value !== '' && data[bp].value !== null) {
        const unit = data[bp].unit || 'px';
        return `${data[bp].value}${unit}`;
      }
      // Try normal data
      if (normalData && normalData[bp] && normalData[bp].value !== undefined && normalData[bp].value !== '' && normalData[bp].value !== null) {
        const unit = normalData[bp].unit || 'px';
        return `${normalData[bp].value}${unit}`;
      }
    }
    return null;
  };

  // プレビューデバイスの値を取得（フォールバック付き）
  const value = getInheritedHoverValue(previewDevice);
  if (value) {
    // PC変数名で出力、値はプレビューデバイスの値
    styles['--icon-size-pc-hover'] = value;
  }
  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getIconPositionStylesV2 = (attributes) => {
  const data = attributes.iconPositionV2;
  if (!data) return {};
  const styles = {};

  // Get PC values with inheritance
  const pcGap = getV2ValueWithInheritance(data, 'pc', "gap", '');
  const pcGapUnit = getV2ValueWithInheritance(data, 'pc', "gapUnit", "px");
  if (pcGap) styles['--icon-gap-pc'] = `${pcGap}${pcGapUnit}`;

  const pcOffsetX = getV2ValueWithInheritance(data, 'pc', "offsetX", 0);
  const pcOffsetXUnit = getV2ValueWithInheritance(data, 'pc', "offsetXUnit", "%");
  const pcOffsetY = getV2ValueWithInheritance(data, 'pc', "offsetY", 0);
  const pcOffsetYUnit = getV2ValueWithInheritance(data, 'pc', "offsetYUnit", "px");
  const pcOriginX = getV2ValueWithInheritance(data, 'pc', "originX", "center");
  const pcOriginY = getV2ValueWithInheritance(data, 'pc', "originY", "center");

  // Origin-based positioning
  const pcOffsetXValue = `${pcOffsetX}${pcOffsetXUnit}`;
  const pcOffsetYValue = `${pcOffsetY}${pcOffsetYUnit}`;

  if (pcOriginX === 'center') {
    styles['--icon-left-pc'] = pcOffsetX === 0 ? '50%' : `calc(50% + ${pcOffsetXValue})`;
    styles['--icon-right-pc'] = 'auto';
    styles['--icon-transform-x-pc'] = '-50%';
  } else {
    styles['--icon-left-pc'] = pcOriginX === 'left' ? pcOffsetXValue : 'auto';
    styles['--icon-right-pc'] = pcOriginX === 'right' ? pcOffsetXValue : 'auto';
    styles['--icon-transform-x-pc'] = '0';
  }

  if (pcOriginY === 'center') {
    styles['--icon-top-pc'] = pcOffsetY === 0 ? '50%' : `calc(50% + ${pcOffsetYValue})`;
    styles['--icon-bottom-pc'] = 'auto';
    styles['--icon-transform-y-pc'] = '-50%';
  } else {
    styles['--icon-top-pc'] = pcOriginY === 'top' ? pcOffsetYValue : 'auto';
    styles['--icon-bottom-pc'] = pcOriginY === 'bottom' ? pcOffsetYValue : 'auto';
    styles['--icon-transform-y-pc'] = '0';
  }

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * @param {Object} attributes - ブロック属性
 * @param {string} previewDevice - プレビューデバイス ('pc', 'md', 'tb', 'sp')
 */
export const getIconPositionStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.iconPositionV2;
  if (!data) return {};
  const styles = {};

  // プレビューデバイスの値を取得（フォールバック付き）
  const gap = getV2ValueWithInheritance(data, previewDevice, "gap", '');
  const gapUnit = getV2ValueWithInheritance(data, previewDevice, "gapUnit", "px");
  if (gap) styles['--icon-gap-pc'] = `${gap}${gapUnit}`;

  const offsetX = getV2ValueWithInheritance(data, previewDevice, "offsetX", 0);
  const offsetXUnit = getV2ValueWithInheritance(data, previewDevice, "offsetXUnit", "%");
  const offsetY = getV2ValueWithInheritance(data, previewDevice, "offsetY", 0);
  const offsetYUnit = getV2ValueWithInheritance(data, previewDevice, "offsetYUnit", "px");
  const originX = getV2ValueWithInheritance(data, previewDevice, "originX", "center");
  const originY = getV2ValueWithInheritance(data, previewDevice, "originY", "center");

  // Origin-based positioning
  const offsetXValue = `${offsetX}${offsetXUnit}`;
  const offsetYValue = `${offsetY}${offsetYUnit}`;

  if (originX === 'center') {
    styles['--icon-left-pc'] = offsetX === 0 ? '50%' : `calc(50% + ${offsetXValue})`;
    styles['--icon-right-pc'] = 'auto';
    styles['--icon-transform-x-pc'] = '-50%';
  } else {
    styles['--icon-left-pc'] = originX === 'left' ? offsetXValue : 'auto';
    styles['--icon-right-pc'] = originX === 'right' ? offsetXValue : 'auto';
    styles['--icon-transform-x-pc'] = '0';
  }

  if (originY === 'center') {
    styles['--icon-top-pc'] = offsetY === 0 ? '50%' : `calc(50% + ${offsetYValue})`;
    styles['--icon-bottom-pc'] = 'auto';
    styles['--icon-transform-y-pc'] = '-50%';
  } else {
    styles['--icon-top-pc'] = originY === 'top' ? offsetYValue : 'auto';
    styles['--icon-bottom-pc'] = originY === 'bottom' ? offsetYValue : 'auto';
    styles['--icon-transform-y-pc'] = '0';
  }

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getIconPositionHoverStylesV2 = (attributes) => {
  const data = attributes.iconPositionV2Hover;
  const normalData = attributes.iconPositionV2;
  if (!data && !normalData) return {};
  const styles = {};

  // PCの値を取得（ホバー値がなければ通常値にフォールバック）
  // getV2ValueWithInheritanceを使用して空文字列を正しく処理する
  const pcGap = getV2ValueWithInheritance(data, 'pc', "gap", null) ??
                getV2ValueWithInheritance(normalData, 'pc', "gap", '');
  const pcGapUnit = getV2ValueWithInheritance(data, 'pc', "gapUnit", null) ||
                    getV2ValueWithInheritance(normalData, 'pc', "gapUnit", "px");
  if (pcGap !== null && pcGap !== '' && pcGap !== undefined) {
    styles['--icon-gap-pc-hover'] = `${pcGap}${pcGapUnit}`;
  }

  const pcOffsetX = getV2ValueWithInheritance(data, 'pc', "offsetX", null) ??
                    getV2ValueWithInheritance(normalData, 'pc', "offsetX", 0);
  const pcOffsetXUnit = getV2ValueWithInheritance(data, 'pc', "offsetXUnit", null) ||
                        getV2ValueWithInheritance(normalData, 'pc', "offsetXUnit", "%");
  const pcOffsetY = getV2ValueWithInheritance(data, 'pc', "offsetY", null) ??
                    getV2ValueWithInheritance(normalData, 'pc', "offsetY", 0);
  const pcOffsetYUnit = getV2ValueWithInheritance(data, 'pc', "offsetYUnit", null) ||
                        getV2ValueWithInheritance(normalData, 'pc', "offsetYUnit", "px");
  const pcOriginX = getV2ValueWithInheritance(data, 'pc', "originX", null) ||
                    getV2ValueWithInheritance(normalData, 'pc', "originX", "center");
  const pcOriginY = getV2ValueWithInheritance(data, 'pc', "originY", null) ||
                    getV2ValueWithInheritance(normalData, 'pc', "originY", "center");

  // Origin-based positioning (hover)
  const pcOffsetXValue = `${pcOffsetX}${pcOffsetXUnit}`;
  const pcOffsetYValue = `${pcOffsetY}${pcOffsetYUnit}`;

  if (pcOriginX === 'center') {
    styles['--icon-left-pc-hover'] = pcOffsetX === 0 ? '50%' : `calc(50% + ${pcOffsetXValue})`;
    styles['--icon-right-pc-hover'] = 'auto';
    styles['--icon-transform-x-pc-hover'] = '-50%';
  } else {
    styles['--icon-left-pc-hover'] = pcOriginX === 'left' ? pcOffsetXValue : 'auto';
    styles['--icon-right-pc-hover'] = pcOriginX === 'right' ? pcOffsetXValue : 'auto';
    styles['--icon-transform-x-pc-hover'] = '0';
  }

  if (pcOriginY === 'center') {
    styles['--icon-top-pc-hover'] = pcOffsetY === 0 ? '50%' : `calc(50% + ${pcOffsetYValue})`;
    styles['--icon-bottom-pc-hover'] = 'auto';
    styles['--icon-transform-y-pc-hover'] = '-50%';
  } else {
    styles['--icon-top-pc-hover'] = pcOriginY === 'top' ? pcOffsetYValue : 'auto';
    styles['--icon-bottom-pc-hover'] = pcOriginY === 'bottom' ? pcOffsetYValue : 'auto';
    styles['--icon-transform-y-pc-hover'] = '0';
  }

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * ホバー値がなければ通常値にフォールバック
 */
export const getIconPositionHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.iconPositionV2Hover;
  const normalData = attributes.iconPositionV2;
  if (!data && !normalData) return {};
  const styles = {};

  // プレビューデバイスの値を取得（ホバーデータ優先、なければ通常データにフォールバック）
  const gap = getV2ValueWithInheritance(data, previewDevice, "gap", null) ??
              getV2ValueWithInheritance(normalData, previewDevice, "gap", '');
  const gapUnit = getV2ValueWithInheritance(data, previewDevice, "gapUnit", null) ||
                  getV2ValueWithInheritance(normalData, previewDevice, "gapUnit", "px");
  if (gap !== null && gap !== '' && gap !== undefined) {
    styles['--icon-gap-pc-hover'] = `${gap}${gapUnit}`;
  }

  const offsetX = getV2ValueWithInheritance(data, previewDevice, "offsetX", null) ??
                  getV2ValueWithInheritance(normalData, previewDevice, "offsetX", 0);
  const offsetXUnit = getV2ValueWithInheritance(data, previewDevice, "offsetXUnit", null) ||
                      getV2ValueWithInheritance(normalData, previewDevice, "offsetXUnit", "%");
  const offsetY = getV2ValueWithInheritance(data, previewDevice, "offsetY", null) ??
                  getV2ValueWithInheritance(normalData, previewDevice, "offsetY", 0);
  const offsetYUnit = getV2ValueWithInheritance(data, previewDevice, "offsetYUnit", null) ||
                      getV2ValueWithInheritance(normalData, previewDevice, "offsetYUnit", "px");
  const originX = getV2ValueWithInheritance(data, previewDevice, "originX", null) ||
                  getV2ValueWithInheritance(normalData, previewDevice, "originX", "center");
  const originY = getV2ValueWithInheritance(data, previewDevice, "originY", null) ||
                  getV2ValueWithInheritance(normalData, previewDevice, "originY", "center");

  // Origin-based positioning (hover)
  const offsetXValue = `${offsetX}${offsetXUnit}`;
  const offsetYValue = `${offsetY}${offsetYUnit}`;

  if (originX === 'center') {
    styles['--icon-left-pc-hover'] = offsetX === 0 ? '50%' : `calc(50% + ${offsetXValue})`;
    styles['--icon-right-pc-hover'] = 'auto';
    styles['--icon-transform-x-pc-hover'] = '-50%';
  } else {
    styles['--icon-left-pc-hover'] = originX === 'left' ? offsetXValue : 'auto';
    styles['--icon-right-pc-hover'] = originX === 'right' ? offsetXValue : 'auto';
    styles['--icon-transform-x-pc-hover'] = '0';
  }

  if (originY === 'center') {
    styles['--icon-top-pc-hover'] = offsetY === 0 ? '50%' : `calc(50% + ${offsetYValue})`;
    styles['--icon-bottom-pc-hover'] = 'auto';
    styles['--icon-transform-y-pc-hover'] = '-50%';
  } else {
    styles['--icon-top-pc-hover'] = originY === 'top' ? offsetYValue : 'auto';
    styles['--icon-bottom-pc-hover'] = originY === 'bottom' ? offsetYValue : 'auto';
    styles['--icon-transform-y-pc-hover'] = '0';
  }

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getIconColorStylesV2 = (attributes) => {
  const data = attributes.iconColorV2;
  const styles = {};

  // 新しい属性から色を取得、存在しない場合は古い属性からフォールバック
  let pcColor = data?.pc?.color || "";
  let pcAlpha = data?.pc?.alpha;
  if (!pcColor) {
    // 古い属性からのフォールバック
    pcColor = attributes.iconColorPC || attributes.iconColor || "";
    pcAlpha = 1;
  }
  const pcColorValue = getColorWithAlpha(pcColor, pcAlpha);

  if (pcColorValue) {
    styles['--icon-color-pc'] = pcColorValue;
  }

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getIconColorStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.iconColorV2;
  const styles = {};

  // 古い属性からブレークポイント別の色を取得するヘルパー
  const getLegacyColor = (bp) => {
    const bpUpper = bp.toUpperCase();
    return attributes[`iconColor${bpUpper}`] || "";
  };

  // プレビューデバイスの値を取得（継承付き）
  const enabledBreakpoints = getEnabledBreakpoints();
  const currentIndex = enabledBreakpoints.indexOf(previewDevice);

  let color = "";
  let alpha = 1;

  for (let i = currentIndex; i >= 0; i--) {
    const checkBp = enabledBreakpoints[i];
    if (data && data[checkBp]?.color) {
      color = data[checkBp].color;
      alpha = data[checkBp].alpha !== undefined ? data[checkBp].alpha : 1;
      break;
    }
    // 新しい属性に値がない場合、古い属性を試す
    const legacyColor = getLegacyColor(checkBp);
    if (legacyColor) {
      color = legacyColor;
      alpha = 1;
      break;
    }
  }

  // フォールバック: 古い属性のデフォルト
  if (!color) {
    color = attributes.iconColorPC || attributes.iconColor || "";
    alpha = 1;
  }

  const colorValue = getColorWithAlpha(color, alpha);
  if (colorValue) {
    styles['--icon-color-pc'] = colorValue;
  }

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getIconColorHoverStylesV2 = (attributes) => {
  const data = attributes.iconColorV2Hover;
  const styles = {};

  // PCの値を取得 - 通常状態へのフォールバックは行わない（ホバーは独立した設定）
  let pcColor = data?.pc?.color || "";
  let pcAlpha = data?.pc?.alpha ?? 1;

  if (!pcColor) {
    // 古い属性からのフォールバック（ホバー属性のみ）
    pcColor = attributes.iconColorPCHover || attributes.iconColorHover || "";
    pcAlpha = 1;
  }

  const pcColorValue = getColorWithAlpha(pcColor, pcAlpha);
  if (pcColorValue) {
    styles['--icon-color-pc-hover'] = pcColorValue;
  }

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * 通常状態へのフォールバックは行わない（ホバーは独立した設定）
 */
export const getIconColorHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.iconColorV2Hover;
  const styles = {};

  const enabledBreakpoints = getEnabledBreakpoints();
  const currentIndex = enabledBreakpoints.indexOf(previewDevice);

  // 古い属性からのヘルパー（ホバーのみ）
  const getLegacyHoverColor = (bp) => attributes[`iconColor${bp.toUpperCase()}Hover`] || "";

  let color = "";
  let alpha = 1;

  // プレビューデバイスの値を継承付きで取得（ホバー属性のみ、通常状態にはフォールバックしない）
  for (let i = currentIndex; i >= 0; i--) {
    const checkBp = enabledBreakpoints[i];
    // ホバーデータから探す
    if (data && data[checkBp]?.color) {
      color = data[checkBp].color;
      alpha = data[checkBp].alpha !== undefined ? data[checkBp].alpha : 1;
      break;
    }
    // 古い属性を試す（ホバーのみ）
    const legacyHoverColor = getLegacyHoverColor(checkBp);
    if (legacyHoverColor) {
      color = legacyHoverColor;
      alpha = 1;
      break;
    }
  }

  // フォールバック（ホバー属性のみ）
  if (!color) {
    color = attributes.iconColorPCHover || attributes.iconColorHover || "";
    alpha = 1;
  }

  const colorValue = getColorWithAlpha(color, alpha);
  if (colorValue) {
    styles['--icon-color-pc-hover'] = colorValue;
  }

  return styles;
};

export const getLayoutWidthStylesV2 = (attributes) => {
  const data = attributes.layoutWidthV2;
  if (!data) return {};
  const styles = {};
  const enabledBreakpoints = getEnabledBreakpoints();
  const responsiveEnabled = attributes.useResponsiveLayoutWidth || false;

  // Helper to get width value with inheritance
  const getWidthValue = (bp) => {
    const useCustom = getV2ValueWithInheritance(data, bp, "useCustom", false);
    if (!useCustom) return '';
    const value = getV2ValueWithInheritance(data, bp, "value", "auto");
    const unit = getV2ValueWithInheritance(data, bp, "unit", "px");
    if (unit === "fit-content") return "auto";
    return value === "auto" ? "auto" : `${value}${unit}`;
  };

  const getMinWidthValue = (bp) => {
    const useCustom = getV2ValueWithInheritance(data, bp, "minUseCustom", false);
    if (!useCustom) return '';
    const value = getV2ValueWithInheritance(data, bp, "minValue", 0);
    const unit = getV2ValueWithInheritance(data, bp, "minUnit", "px");
    if (unit === "fit-content") return "fit-content";
    return `${value}${unit}`;
  };

  const getMaxWidthValue = (bp) => {
    const useCustom = getV2ValueWithInheritance(data, bp, "maxUseCustom", false);
    if (!useCustom) return '';
    const value = getV2ValueWithInheritance(data, bp, "maxValue", "none");
    const unit = getV2ValueWithInheritance(data, bp, "maxUnit", "px");
    if (unit === "fit-content") return "fit-content";
    return value === "none" ? "none" : `${value}${unit}`;
  };

  // Get PC values
  const pcWidth = getWidthValue('pc');
  const pcMinWidth = getMinWidthValue('pc');
  const pcMaxWidth = getMaxWidthValue('pc');

  let hasFitContent = false;
  const pcUnit = getV2ValueWithInheritance(data, 'pc', "unit", "px");
  if (pcUnit === "fit-content") hasFitContent = true;

  enabledBreakpoints.forEach((bp, index) => {
    const isPC = index === 0;
    if (isPC) {
      if (pcWidth) styles[`--layout-width-${bp}`] = pcWidth;
      if (pcMinWidth) styles[`--layout-width-min-${bp}`] = pcMinWidth;
      if (pcMaxWidth) styles[`--layout-width-max-${bp}`] = pcMaxWidth;
    } else if (responsiveEnabled) {
      // fit-contentチェックのみ（MD/TB/SP変数はPHP CSSに任せる）
      const bpUnit = getV2ValueWithInheritance(data, bp, "unit", "px");
      if (bpUnit === "fit-content") hasFitContent = true;
    }
    // MD/TB/SP: PHP CSSに任せる（出力しない）
  });
  if (hasFitContent) {
    styles["--button-white-space"] = "nowrap";
  }
  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getLayoutWidthStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.layoutWidthV2;
  if (!data) return {};
  const styles = {};

  const getWidthValue = (bp) => {
    const useCustom = getV2ValueWithInheritance(data, bp, "useCustom", false);
    if (!useCustom) return '';
    const value = getV2ValueWithInheritance(data, bp, "value", "auto");
    const unit = getV2ValueWithInheritance(data, bp, "unit", "px");
    if (unit === "fit-content") return "auto";
    return value === "auto" ? "auto" : `${value}${unit}`;
  };

  const getMinWidthValue = (bp) => {
    const useCustom = getV2ValueWithInheritance(data, bp, "minUseCustom", false);
    if (!useCustom) return '';
    const value = getV2ValueWithInheritance(data, bp, "minValue", 0);
    const unit = getV2ValueWithInheritance(data, bp, "minUnit", "px");
    if (unit === "fit-content") return "fit-content";
    return `${value}${unit}`;
  };

  const getMaxWidthValue = (bp) => {
    const useCustom = getV2ValueWithInheritance(data, bp, "maxUseCustom", false);
    if (!useCustom) return '';
    const value = getV2ValueWithInheritance(data, bp, "maxValue", "none");
    const unit = getV2ValueWithInheritance(data, bp, "maxUnit", "px");
    if (unit === "fit-content") return "fit-content";
    return value === "none" ? "none" : `${value}${unit}`;
  };

  // PC変数名で出力、値はプレビューデバイスの値
  const width = getWidthValue(previewDevice);
  const minWidth = getMinWidthValue(previewDevice);
  const maxWidth = getMaxWidthValue(previewDevice);
  if (width) styles['--layout-width-pc'] = width;
  if (minWidth) styles['--layout-width-min-pc'] = minWidth;
  if (maxWidth) styles['--layout-width-max-pc'] = maxWidth;

  // fit-contentチェック（全BPを確認）
  const enabledBreakpoints = getEnabledBreakpoints();
  let hasFitContent = false;
  enabledBreakpoints.forEach((bp) => {
    const bpUnit = getV2ValueWithInheritance(data, bp, "unit", "px");
    if (bpUnit === "fit-content") hasFitContent = true;
  });
  if (hasFitContent) {
    styles["--button-white-space"] = "nowrap";
  }

  return styles;
};

export const getLayoutHeightStylesV2 = (attributes) => {
  const data = attributes.layoutHeightV2;
  if (!data) return {};
  const styles = {};
  const enabledBreakpoints = getEnabledBreakpoints();

  // Helper to get height value with inheritance
  const getHeightValue = (bp) => {
    const useCustom = getV2ValueWithInheritance(data, bp, "useCustom", false);
    if (!useCustom) return '';
    const value = getV2ValueWithInheritance(data, bp, "value", "auto");
    const unit = getV2ValueWithInheritance(data, bp, "unit", "px");
    return value === "auto" ? "auto" : `${value}${unit}`;
  };

  const getMinHeightValue = (bp) => {
    const useCustom = getV2ValueWithInheritance(data, bp, "minUseCustom", false);
    if (!useCustom) return '';
    const value = getV2ValueWithInheritance(data, bp, "minValue", 0);
    const unit = getV2ValueWithInheritance(data, bp, "minUnit", "px");
    return `${value}${unit}`;
  };

  const getMaxHeightValue = (bp) => {
    const useCustom = getV2ValueWithInheritance(data, bp, "maxUseCustom", false);
    if (!useCustom) return '';
    const value = getV2ValueWithInheritance(data, bp, "maxValue", "none");
    const unit = getV2ValueWithInheritance(data, bp, "maxUnit", "px");
    return value === "none" ? "none" : `${value}${unit}`;
  };

  enabledBreakpoints.forEach((bp, index) => {
    const isPC = index === 0;
    if (isPC) {
      const height = getHeightValue(bp);
      const minHeight = getMinHeightValue(bp);
      const maxHeight = getMaxHeightValue(bp);
      if (height) styles[`--layout-height-${bp}`] = height;
      if (minHeight) styles[`--layout-height-min-${bp}`] = minHeight;
      if (maxHeight) styles[`--layout-height-max-${bp}`] = maxHeight;
    }
    // MD/TB/SP: PHP CSSに任せる（出力しない）
  });
  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getLayoutHeightStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.layoutHeightV2;
  if (!data) return {};
  const styles = {};

  const getHeightValue = (bp) => {
    const useCustom = getV2ValueWithInheritance(data, bp, "useCustom", false);
    if (!useCustom) return '';
    const value = getV2ValueWithInheritance(data, bp, "value", "auto");
    const unit = getV2ValueWithInheritance(data, bp, "unit", "px");
    return value === "auto" ? "auto" : `${value}${unit}`;
  };

  const getMinHeightValue = (bp) => {
    const useCustom = getV2ValueWithInheritance(data, bp, "minUseCustom", false);
    if (!useCustom) return '';
    const value = getV2ValueWithInheritance(data, bp, "minValue", 0);
    const unit = getV2ValueWithInheritance(data, bp, "minUnit", "px");
    return `${value}${unit}`;
  };

  const getMaxHeightValue = (bp) => {
    const useCustom = getV2ValueWithInheritance(data, bp, "maxUseCustom", false);
    if (!useCustom) return '';
    const value = getV2ValueWithInheritance(data, bp, "maxValue", "none");
    const unit = getV2ValueWithInheritance(data, bp, "maxUnit", "px");
    return value === "none" ? "none" : `${value}${unit}`;
  };

  // PC変数名で出力、値はプレビューデバイスの値
  const height = getHeightValue(previewDevice);
  const minHeight = getMinHeightValue(previewDevice);
  const maxHeight = getMaxHeightValue(previewDevice);
  if (height) styles['--layout-height-pc'] = height;
  if (minHeight) styles['--layout-height-min-pc'] = minHeight;
  if (maxHeight) styles['--layout-height-max-pc'] = maxHeight;

  return styles;
};

/**
 * save.js用: PCのみ出力（背景画像と同様の構造）
 * サムネイル画像スタイル
 */
export const getThumbnailImageStylesV2 = (attributes) => {
  const data = attributes.thumbnailImageV2;
  if (!data) return {};
  const styles = {};

  // Helper to get size value including custom dimensions
  const getSizeValue = (bp) => {
    const objectFit = getV2ValueWithInheritance(data, bp, "objectFit", "cover");
    if (objectFit === "fill" || objectFit === "none") {
      const bgWidth = getV2ValueWithInheritance(data, bp, "bgWidth", "100");
      const bgWidthUnit = getV2ValueWithInheritance(data, bp, "bgWidthUnit", "%");
      const bgHeight = getV2ValueWithInheritance(data, bp, "bgHeight", "auto");
      const bgHeightUnit = getV2ValueWithInheritance(data, bp, "bgHeightUnit", "%");
      const width = bgWidth === "auto" ? "auto" : `${bgWidth}${bgWidthUnit}`;
      const height = bgHeight === "auto" ? "auto" : `${bgHeight}${bgHeightUnit}`;
      return `${width} ${height}`;
    }
    return objectFit;
  };

  // Get PC values only
  const pcUrl = getV2ValueWithInheritance(data, 'pc', "url", "");
  const pcPosition = getV2ValueWithInheritance(data, 'pc', "focalPosition", "50% 50%");
  const pcSize = getSizeValue('pc');
  const pcRepeat = getV2ValueWithInheritance(data, 'pc', "repeat", "no-repeat");
  const pcRotate = getBackgroundImageRotateValue(data, 'pc', "0deg");
  const pcFrameWidth = getV2ValueWithInheritance(data, 'pc', "frameWidth", 60);
  const pcFrameWidthUnit = getV2ValueWithInheritance(data, 'pc', "frameWidthUnit", "px");
  const pcFrameHeight = getV2ValueWithInheritance(data, 'pc', "frameHeight", 60);
  const pcFrameHeightUnit = getV2ValueWithInheritance(data, 'pc', "frameHeightUnit", "px");
  const pcBorderRadius = getV2ValueWithInheritance(data, 'pc', "borderRadius", 0);
  const pcBorderRadiusUnit = getV2ValueWithInheritance(data, 'pc', "borderRadiusUnit", "px");
  const pcBorderWidth = getV2ValueWithInheritance(data, 'pc', "borderWidth", 0);
  const pcBorderStyle = getV2ValueWithInheritance(data, 'pc', "borderStyle", "none");
  const pcBorderColor = getV2ValueWithInheritance(data, 'pc', "borderColor", "transparent");
  const pcBorderColorAlpha = getV2ValueWithInheritance(data, 'pc', "borderColorAlpha", 1);
  const pcBorderBoxSizing = getV2ValueWithInheritance(data, 'pc', "borderBoxSizing", "border-box");
  const pcOffsetX = getV2ValueWithInheritance(data, 'pc', "offsetX", 0);
  const pcOffsetXUnit = getV2ValueWithInheritance(data, 'pc', "offsetXUnit", "%");
  const pcOffsetY = getV2ValueWithInheritance(data, 'pc', "offsetY", 0);
  const pcOffsetYUnit = getV2ValueWithInheritance(data, 'pc', "offsetYUnit", "%");
  const pcOriginX = getV2ValueWithInheritance(data, 'pc', "originX", "left");
  const pcOriginY = getV2ValueWithInheritance(data, 'pc', "originY", "top");

  // PC用のみ出力（MD/TB/SP用はPHP CSSのフォールバックに任せる）
  styles['--thumbnail-image-pc'] = pcUrl ? `url(${pcUrl})` : "none";
  styles['--thumbnail-position-pc'] = pcPosition;
  styles['--thumbnail-size-pc'] = pcSize;
  styles['--thumbnail-repeat-pc'] = pcRepeat;
  styles['--thumbnail-rotate-pc'] = pcRotate;
  styles['--thumbnail-frame-width-pc'] = `${pcFrameWidth}${pcFrameWidthUnit}`;
  styles['--thumbnail-frame-height-pc'] = `${pcFrameHeight}${pcFrameHeightUnit}`;
  styles['--thumbnail-radius-pc'] = `${pcBorderRadius}${pcBorderRadiusUnit}`;
  styles['--thumbnail-border-width-pc'] = `${pcBorderWidth}px`;
  styles['--thumbnail-border-style-pc'] = pcBorderStyle;
  styles['--thumbnail-border-color-pc'] = pcBorderColor === "transparent" ? "transparent" : hexToRgba(pcBorderColor, pcBorderColorAlpha);
  styles['--thumbnail-box-sizing-pc'] = pcBorderBoxSizing;

  // Origin-based positioning
  const pcOffsetXValue = `${pcOffsetX}${pcOffsetXUnit}`;
  const pcOffsetYValue = `${pcOffsetY}${pcOffsetYUnit}`;

  if (pcOriginX === 'center') {
    styles['--thumbnail-left-pc'] = pcOffsetX === 0 ? '50%' : `calc(50% + ${pcOffsetXValue})`;
    styles['--thumbnail-right-pc'] = 'auto';
    styles['--thumbnail-transform-x-pc'] = '-50%';
  } else {
    styles['--thumbnail-left-pc'] = pcOriginX === 'left' ? pcOffsetXValue : 'auto';
    styles['--thumbnail-right-pc'] = pcOriginX === 'right' ? pcOffsetXValue : 'auto';
    styles['--thumbnail-transform-x-pc'] = '0';
  }

  if (pcOriginY === 'center') {
    styles['--thumbnail-top-pc'] = pcOffsetY === 0 ? '50%' : `calc(50% + ${pcOffsetYValue})`;
    styles['--thumbnail-bottom-pc'] = 'auto';
    styles['--thumbnail-transform-y-pc'] = '-50%';
  } else {
    styles['--thumbnail-top-pc'] = pcOriginY === 'top' ? pcOffsetYValue : 'auto';
    styles['--thumbnail-bottom-pc'] = pcOriginY === 'bottom' ? pcOffsetYValue : 'auto';
    styles['--thumbnail-transform-y-pc'] = '0';
  }

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * サムネイル画像スタイル（エディタプレビュー用）
 */
export const getThumbnailImageStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.thumbnailImageV2;
  if (!data) return {};
  const styles = {};

  // Helper to get size value including custom dimensions
  const getSizeValue = (bp) => {
    const objectFit = getV2ValueWithInheritance(data, bp, "objectFit", "cover");
    if (objectFit === "fill" || objectFit === "none") {
      const bgWidth = getV2ValueWithInheritance(data, bp, "bgWidth", "100");
      const bgWidthUnit = getV2ValueWithInheritance(data, bp, "bgWidthUnit", "%");
      const bgHeight = getV2ValueWithInheritance(data, bp, "bgHeight", "auto");
      const bgHeightUnit = getV2ValueWithInheritance(data, bp, "bgHeightUnit", "%");
      const width = bgWidth === "auto" ? "auto" : `${bgWidth}${bgWidthUnit}`;
      const height = bgHeight === "auto" ? "auto" : `${bgHeight}${bgHeightUnit}`;
      return `${width} ${height}`;
    }
    return objectFit;
  };

  // プレビューデバイスの値を取得（継承付き）
  const url = getV2ValueWithInheritance(data, previewDevice, "url", "");
  const position = getV2ValueWithInheritance(data, previewDevice, "focalPosition", "50% 50%");
  const size = getSizeValue(previewDevice);
  const repeat = getV2ValueWithInheritance(data, previewDevice, "repeat", "no-repeat");
  const rotate = getBackgroundImageRotateValue(data, previewDevice, "0deg");
  const frameWidth = getV2ValueWithInheritance(data, previewDevice, "frameWidth", 60);
  const frameWidthUnit = getV2ValueWithInheritance(data, previewDevice, "frameWidthUnit", "px");
  const frameHeight = getV2ValueWithInheritance(data, previewDevice, "frameHeight", 100);
  const frameHeightUnit = getV2ValueWithInheritance(data, previewDevice, "frameHeightUnit", "%");
  const borderRadius = getV2ValueWithInheritance(data, previewDevice, "borderRadius", 0);
  const borderRadiusUnit = getV2ValueWithInheritance(data, previewDevice, "borderRadiusUnit", "px");
  const borderWidth = getV2ValueWithInheritance(data, previewDevice, "borderWidth", 0);
  const borderStyle = getV2ValueWithInheritance(data, previewDevice, "borderStyle", "none");
  const borderColor = getV2ValueWithInheritance(data, previewDevice, "borderColor", "transparent");
  const borderColorAlpha = getV2ValueWithInheritance(data, previewDevice, "borderColorAlpha", 1);
  const borderBoxSizing = getV2ValueWithInheritance(data, previewDevice, "borderBoxSizing", "border-box");
  const offsetX = getV2ValueWithInheritance(data, previewDevice, "offsetX", 0);
  const offsetXUnit = getV2ValueWithInheritance(data, previewDevice, "offsetXUnit", "%");
  const offsetY = getV2ValueWithInheritance(data, previewDevice, "offsetY", 0);
  const offsetYUnit = getV2ValueWithInheritance(data, previewDevice, "offsetYUnit", "%");
  const originX = getV2ValueWithInheritance(data, previewDevice, "originX", "left");
  const originY = getV2ValueWithInheritance(data, previewDevice, "originY", "top");

  // PC変数に出力（エディタでプレビューデバイスの値を反映）
  styles['--thumbnail-image-pc'] = url ? `url(${url})` : "none";
  styles['--thumbnail-position-pc'] = position;
  styles['--thumbnail-size-pc'] = size;
  styles['--thumbnail-repeat-pc'] = repeat;
  styles['--thumbnail-rotate-pc'] = rotate;
  styles['--thumbnail-frame-width-pc'] = `${frameWidth}${frameWidthUnit}`;
  styles['--thumbnail-frame-height-pc'] = `${frameHeight}${frameHeightUnit}`;
  styles['--thumbnail-radius-pc'] = `${borderRadius}${borderRadiusUnit}`;
  styles['--thumbnail-border-width-pc'] = `${borderWidth}px`;
  styles['--thumbnail-border-style-pc'] = borderStyle;
  styles['--thumbnail-border-color-pc'] = borderColor === "transparent" ? "transparent" : hexToRgba(borderColor, borderColorAlpha);
  styles['--thumbnail-box-sizing-pc'] = borderBoxSizing;

  // Origin-based positioning
  const offsetXValue = `${offsetX}${offsetXUnit}`;
  const offsetYValue = `${offsetY}${offsetYUnit}`;

  if (originX === 'center') {
    styles['--thumbnail-left-pc'] = offsetX === 0 ? '50%' : `calc(50% + ${offsetXValue})`;
    styles['--thumbnail-right-pc'] = 'auto';
    styles['--thumbnail-transform-x-pc'] = '-50%';
  } else {
    styles['--thumbnail-left-pc'] = originX === 'left' ? offsetXValue : 'auto';
    styles['--thumbnail-right-pc'] = originX === 'right' ? offsetXValue : 'auto';
    styles['--thumbnail-transform-x-pc'] = '0';
  }

  if (originY === 'center') {
    styles['--thumbnail-top-pc'] = offsetY === 0 ? '50%' : `calc(50% + ${offsetYValue})`;
    styles['--thumbnail-bottom-pc'] = 'auto';
    styles['--thumbnail-transform-y-pc'] = '-50%';
  } else {
    styles['--thumbnail-top-pc'] = originY === 'top' ? offsetYValue : 'auto';
    styles['--thumbnail-bottom-pc'] = originY === 'bottom' ? offsetYValue : 'auto';
    styles['--thumbnail-transform-y-pc'] = '0';
  }

  return styles;
};

/**
 * save.js用: PCのみ出力（背景画像ホバーと同様の構造）
 * ホバー時のサムネイル画像スタイル（位置・サイズ・リピート）
 * 注意: 画像URL自体は通常状態から継承するため必要に応じて出力
 */
export const getThumbnailImageHoverStylesV2 = (attributes) => {
  const data = attributes.thumbnailImageV2Hover;
  const normalData = attributes.thumbnailImageV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal
  const getHoverValue = (key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, 'pc', key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, 'pc', key, defaultVal);
  };

  // Helper to get size value including custom dimensions
  const getSizeValue = () => {
    const objectFit = getHoverValue("objectFit", "cover");
    if (objectFit === "fill" || objectFit === "none") {
      const bgWidth = getHoverValue("bgWidth", "100");
      const bgWidthUnit = getHoverValue("bgWidthUnit", "%");
      const bgHeight = getHoverValue("bgHeight", "auto");
      const bgHeightUnit = getHoverValue("bgHeightUnit", "%");
      const width = bgWidth === "auto" ? "auto" : `${bgWidth}${bgWidthUnit}`;
      const height = bgHeight === "auto" ? "auto" : `${bgHeight}${bgHeightUnit}`;
      return `${width} ${height}`;
    }
    return objectFit;
  };

  // Get PC values only (with fallback to normal)
  const pcPosition = getHoverValue("focalPosition", "50% 50%");
  const pcSize = getSizeValue();
  const pcRepeat = getHoverValue("repeat", "no-repeat");
  const pcRotate = getBackgroundImageRotateValue({ pc: { rotate: getHoverValue("rotate", "0") } }, 'pc', getBackgroundImageRotateValue(normalData, 'pc', "0deg"));
  const pcFrameWidth = getHoverValue("frameWidth", 60);
  const pcFrameWidthUnit = getHoverValue("frameWidthUnit", "px");
  const pcFrameHeight = getHoverValue("frameHeight", 60);
  const pcFrameHeightUnit = getHoverValue("frameHeightUnit", "px");
  const pcBorderRadius = getHoverValue("borderRadius", 0);
  const pcBorderRadiusUnit = getHoverValue("borderRadiusUnit", "px");
  const pcBorderWidth = getHoverValue("borderWidth", 0);
  const pcBorderStyle = getHoverValue("borderStyle", "none");
  const pcBorderColor = getHoverValue("borderColor", "transparent");
  const pcBorderColorAlpha = getHoverValue("borderColorAlpha", 1);
  const pcBorderBoxSizing = getHoverValue("borderBoxSizing", "border-box");
  const pcOffsetX = getHoverValue("offsetX", 0);
  const pcOffsetXUnit = getHoverValue("offsetXUnit", "%");
  const pcOffsetY = getHoverValue("offsetY", 0);
  const pcOffsetYUnit = getHoverValue("offsetYUnit", "%");
  const pcOriginX = getHoverValue("originX", "left");
  const pcOriginY = getHoverValue("originY", "top");

  // PC用のみ出力（MD/TB/SP用はPHP CSSのフォールバックに任せる）
  styles['--thumbnail-position-pc-hover'] = pcPosition;
  styles['--thumbnail-size-pc-hover'] = pcSize;
  styles['--thumbnail-repeat-pc-hover'] = pcRepeat;
  styles['--thumbnail-rotate-pc-hover'] = pcRotate;
  styles['--thumbnail-frame-width-pc-hover'] = `${pcFrameWidth}${pcFrameWidthUnit}`;
  styles['--thumbnail-frame-height-pc-hover'] = `${pcFrameHeight}${pcFrameHeightUnit}`;
  styles['--thumbnail-radius-pc-hover'] = `${pcBorderRadius}${pcBorderRadiusUnit}`;
  styles['--thumbnail-border-width-pc-hover'] = `${pcBorderWidth}px`;
  styles['--thumbnail-border-style-pc-hover'] = pcBorderStyle;
  styles['--thumbnail-border-color-pc-hover'] = pcBorderColor === "transparent" ? "transparent" : hexToRgba(pcBorderColor, pcBorderColorAlpha);
  styles['--thumbnail-box-sizing-pc-hover'] = pcBorderBoxSizing;

  // Origin-based positioning for hover
  const pcOffsetXValue = `${pcOffsetX}${pcOffsetXUnit}`;
  const pcOffsetYValue = `${pcOffsetY}${pcOffsetYUnit}`;

  if (pcOriginX === 'center') {
    styles['--thumbnail-left-pc-hover'] = pcOffsetX === 0 ? '50%' : `calc(50% + ${pcOffsetXValue})`;
    styles['--thumbnail-right-pc-hover'] = 'auto';
    styles['--thumbnail-transform-x-pc-hover'] = '-50%';
  } else {
    styles['--thumbnail-left-pc-hover'] = pcOriginX === 'left' ? pcOffsetXValue : 'auto';
    styles['--thumbnail-right-pc-hover'] = pcOriginX === 'right' ? pcOffsetXValue : 'auto';
    styles['--thumbnail-transform-x-pc-hover'] = '0';
  }

  if (pcOriginY === 'center') {
    styles['--thumbnail-top-pc-hover'] = pcOffsetY === 0 ? '50%' : `calc(50% + ${pcOffsetYValue})`;
    styles['--thumbnail-bottom-pc-hover'] = 'auto';
    styles['--thumbnail-transform-y-pc-hover'] = '-50%';
  } else {
    styles['--thumbnail-top-pc-hover'] = pcOriginY === 'top' ? pcOffsetYValue : 'auto';
    styles['--thumbnail-bottom-pc-hover'] = pcOriginY === 'bottom' ? pcOffsetYValue : 'auto';
    styles['--thumbnail-transform-y-pc-hover'] = '0';
  }

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * ホバー時のサムネイル画像スタイル（エディタプレビュー用）
 */
export const getThumbnailImageHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.thumbnailImageV2Hover;
  const normalData = attributes.thumbnailImageV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal
  const getHoverValue = (key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, previewDevice, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, previewDevice, key, defaultVal);
  };

  // Helper to get size value including custom dimensions
  const getSizeValue = () => {
    const objectFit = getHoverValue("objectFit", "cover");
    if (objectFit === "fill" || objectFit === "none") {
      const bgWidth = getHoverValue("bgWidth", "100");
      const bgWidthUnit = getHoverValue("bgWidthUnit", "%");
      const bgHeight = getHoverValue("bgHeight", "auto");
      const bgHeightUnit = getHoverValue("bgHeightUnit", "%");
      const width = bgWidth === "auto" ? "auto" : `${bgWidth}${bgWidthUnit}`;
      const height = bgHeight === "auto" ? "auto" : `${bgHeight}${bgHeightUnit}`;
      return `${width} ${height}`;
    }
    return objectFit;
  };

  // プレビューデバイスの値を取得（継承付き、ホバーから通常へのフォールバック）
  const position = getHoverValue("focalPosition", "50% 50%");
  const size = getSizeValue();
  const repeat = getHoverValue("repeat", "no-repeat");
  const rotate = getBackgroundImageRotateValue({ [previewDevice]: { rotate: getHoverValue("rotate", "0") } }, previewDevice, getBackgroundImageRotateValue(normalData, previewDevice, "0deg"));
  const frameWidth = getHoverValue("frameWidth", 60);
  const frameWidthUnit = getHoverValue("frameWidthUnit", "px");
  const frameHeight = getHoverValue("frameHeight", 100);
  const frameHeightUnit = getHoverValue("frameHeightUnit", "%");
  const borderRadius = getHoverValue("borderRadius", 0);
  const borderRadiusUnit = getHoverValue("borderRadiusUnit", "px");
  const borderWidth = getHoverValue("borderWidth", 0);
  const borderStyle = getHoverValue("borderStyle", "none");
  const borderColor = getHoverValue("borderColor", "transparent");
  const borderColorAlpha = getHoverValue("borderColorAlpha", 1);
  const borderBoxSizing = getHoverValue("borderBoxSizing", "border-box");
  const offsetX = getHoverValue("offsetX", 0);
  const offsetXUnit = getHoverValue("offsetXUnit", "%");
  const offsetY = getHoverValue("offsetY", 0);
  const offsetYUnit = getHoverValue("offsetYUnit", "%");
  const originX = getHoverValue("originX", "left");
  const originY = getHoverValue("originY", "top");

  // PC変数に出力（エディタでプレビューデバイスの値を反映）
  styles['--thumbnail-position-pc-hover'] = position;
  styles['--thumbnail-size-pc-hover'] = size;
  styles['--thumbnail-repeat-pc-hover'] = repeat;
  styles['--thumbnail-rotate-pc-hover'] = rotate;
  styles['--thumbnail-frame-width-pc-hover'] = `${frameWidth}${frameWidthUnit}`;
  styles['--thumbnail-frame-height-pc-hover'] = `${frameHeight}${frameHeightUnit}`;
  styles['--thumbnail-radius-pc-hover'] = `${borderRadius}${borderRadiusUnit}`;
  styles['--thumbnail-border-width-pc-hover'] = `${borderWidth}px`;
  styles['--thumbnail-border-style-pc-hover'] = borderStyle;
  styles['--thumbnail-border-color-pc-hover'] = borderColor === "transparent" ? "transparent" : hexToRgba(borderColor, borderColorAlpha);
  styles['--thumbnail-box-sizing-pc-hover'] = borderBoxSizing;

  // Origin-based positioning for hover
  const offsetXValue = `${offsetX}${offsetXUnit}`;
  const offsetYValue = `${offsetY}${offsetYUnit}`;

  // X positioning for hover
  if (originX === 'center') {
    styles['--thumbnail-left-pc-hover'] = offsetX === 0 ? '50%' : `calc(50% + ${offsetXValue})`;
    styles['--thumbnail-right-pc-hover'] = 'auto';
    styles['--thumbnail-transform-x-pc-hover'] = '-50%';
  } else {
    styles['--thumbnail-left-pc-hover'] = originX === 'left' ? offsetXValue : 'auto';
    styles['--thumbnail-right-pc-hover'] = originX === 'right' ? offsetXValue : 'auto';
    styles['--thumbnail-transform-x-pc-hover'] = '0';
  }

  // Y positioning for hover
  if (originY === 'center') {
    styles['--thumbnail-top-pc-hover'] = offsetY === 0 ? '50%' : `calc(50% + ${offsetYValue})`;
    styles['--thumbnail-bottom-pc-hover'] = 'auto';
    styles['--thumbnail-transform-y-pc-hover'] = '-50%';
  } else {
    styles['--thumbnail-top-pc-hover'] = originY === 'top' ? offsetYValue : 'auto';
    styles['--thumbnail-bottom-pc-hover'] = originY === 'bottom' ? offsetYValue : 'auto';
    styles['--thumbnail-transform-y-pc-hover'] = '0';
  }

  return styles;
};

/**
 * サムネイルカラー値を取得（常にlinear-gradient()形式で返す）
 * バンドカラーの getBandColorV2Value と同じパターン
 */
const getThumbnailColorV2Value = (attributes, device, isHover = false) => {
  const attrName = isHover ? 'thumbnailColorV2Hover' : 'thumbnailColorV2';
  const data = attributes[attrName];
  if (!data) return 'linear-gradient(90deg, transparent 0%, transparent 100%)';
  const useGradient = getV2ValueWithInheritance(data, device, 'useGradient', false);
  const gradient = getV2ValueWithInheritance(data, device, 'gradient', '');
  const color = getV2ValueWithInheritance(data, device, 'color', '');
  if (useGradient && gradient) return gradient;
  const effectiveColor = color || 'transparent';
  return `linear-gradient(90deg, ${effectiveColor} 0%, ${effectiveColor} 100%)`;
};

/**
 * サムネイルカラーホバー値を直接取得（ブレークポイント継承あり、通常値へのフォールバックなし）
 * バンドカラーの getBandColorV2HoverValueWithInheritance と同じパターン
 */
const getThumbnailColorV2HoverValueWithInheritance = (attributes, device) => {
  const data = attributes.thumbnailColorV2Hover;
  if (!data) return '';
  const enabledBreakpoints = getEnabledBreakpoints();
  const currentIndex = enabledBreakpoints.indexOf(device);
  for (let i = currentIndex; i >= 0; i--) {
    const bp = enabledBreakpoints[i];
    if (!data[bp]) continue;
    const bpData = data[bp];
    const color = bpData.color;
    const gradient = bpData.gradient;
    const useGradient = bpData.useGradient;
    if (useGradient && gradient) return gradient;
    if (color && color !== '' && color !== 'transparent') return `linear-gradient(90deg, ${color} 0%, ${color} 100%)`;
  }
  return '';
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 * 値は常にlinear-gradient()形式（クロスフェード方式でbackground-imageに統一）
 */
export const getThumbnailColorStylesV2 = (attributes) => {
  const data = attributes.thumbnailColorV2;
  const styles = {};

  const opacity = data ? getV2ValueWithInheritance(data, 'pc', "opacity", 1) : 1;
  const mixBlendMode = data ? getV2ValueWithInheritance(data, 'pc', "mixBlendMode", "normal") : "normal";

  styles['--thumbnail-color-pc'] = getThumbnailColorV2Value(attributes, 'pc');
  styles['--thumbnail-color-opacity-pc'] = opacity;
  styles['--thumbnail-color-blend-mode-pc'] = mixBlendMode;

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * 値は常にlinear-gradient()形式（クロスフェード方式でbackground-imageに統一）
 */
export const getThumbnailColorStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.thumbnailColorV2;
  const styles = {};

  styles['--thumbnail-color-pc'] = getThumbnailColorV2Value(attributes, previewDevice);
  styles['--thumbnail-color-opacity-pc'] = data ? getV2ValueWithInheritance(data, previewDevice, "opacity", 1) : 1;
  styles['--thumbnail-color-blend-mode-pc'] = data ? getV2ValueWithInheritance(data, previewDevice, "mixBlendMode", "normal") : "normal";

  return styles;
};

/**
 * save.js用: PCのみ出力
 * MD/TB/SP用はPHP CSSのフォールバックに任せる
 * ホバー値がなければ通常値にフォールバック（バンドカラーと同じパターン）
 */
export const getThumbnailColorHoverStylesV2 = (attributes) => {
  const data = attributes.thumbnailColorV2Hover;
  const normalData = attributes.thumbnailColorV2;
  const styles = {};

  const getHoverOpacity = () => {
    const hoverOpacity = getV2ValueWithInheritance(data, 'pc', "opacity", undefined);
    if (hoverOpacity !== undefined && hoverOpacity !== '') return hoverOpacity;
    return getV2ValueWithInheritance(normalData, 'pc', "opacity", 1);
  };

  const getHoverMixBlend = () => {
    const hoverMixBlend = getV2ValueWithInheritance(data, 'pc', "mixBlendMode", undefined);
    if (hoverMixBlend !== undefined && hoverMixBlend !== '') return hoverMixBlend;
    return getV2ValueWithInheritance(normalData, 'pc', "mixBlendMode", "normal");
  };

  const getHoverColor = () => {
    const hoverValue = getThumbnailColorV2HoverValueWithInheritance(attributes, 'pc');
    if (hoverValue) return hoverValue;
    return getThumbnailColorV2Value(attributes, 'pc', false);
  };

  styles['--thumbnail-color-pc-hover'] = getHoverColor();
  styles['--thumbnail-color-opacity-pc-hover'] = getHoverOpacity();
  styles['--thumbnail-color-blend-mode-pc-hover'] = getHoverMixBlend();

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * ホバー値がなければ通常値にフォールバック（バンドカラーと同じパターン）
 */
export const getThumbnailColorHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.thumbnailColorV2Hover;
  const normalData = attributes.thumbnailColorV2;
  const styles = {};

  const getHoverOpacity = () => {
    const hoverOpacity = getV2ValueWithInheritance(data, previewDevice, "opacity", undefined);
    if (hoverOpacity !== undefined && hoverOpacity !== '') return hoverOpacity;
    return getV2ValueWithInheritance(normalData, previewDevice, "opacity", 1);
  };

  const getHoverMixBlend = () => {
    const hoverMixBlend = getV2ValueWithInheritance(data, previewDevice, "mixBlendMode", undefined);
    if (hoverMixBlend !== undefined && hoverMixBlend !== '') return hoverMixBlend;
    return getV2ValueWithInheritance(normalData, previewDevice, "mixBlendMode", "normal");
  };

  const getHoverColor = () => {
    const hoverValue = getThumbnailColorV2HoverValueWithInheritance(attributes, previewDevice);
    if (hoverValue) return hoverValue;
    return getThumbnailColorV2Value(attributes, previewDevice, false);
  };

  styles['--thumbnail-color-pc-hover'] = getHoverColor();
  styles['--thumbnail-color-opacity-pc-hover'] = getHoverOpacity();
  styles['--thumbnail-color-blend-mode-pc-hover'] = getHoverMixBlend();

  return styles;
};

/**
 * Thumbnail Opacity - save.js用: PCのみ出力
 */
export const getThumbnailOpacityStylesV2 = (attributes, { skipDefaults = false } = {}) => {
  const data = attributes.thumbnailOpacityV2;
  if (!data) return {};
  const styles = {};
  const pcValue = getV2ValueWithInheritance(data, 'pc', "value", 100);
  const pcMixBlendMode = getV2ValueWithInheritance(data, 'pc', "mixBlendMode", "normal");

  if (!skipDefaults || pcValue !== 100) {
    styles['--thumbnail-opacity-pc'] = String(pcValue / 100);
  }
  if (!skipDefaults || pcMixBlendMode !== "normal") {
    styles['--thumbnail-blend-mode-pc'] = pcMixBlendMode;
  }
  return styles;
};

/**
 * Thumbnail Opacity - edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getThumbnailOpacityStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.thumbnailOpacityV2;
  if (!data) return {};
  const styles = {};
  const value = getV2ValueWithInheritance(data, previewDevice, "value", 100);
  const mixBlendMode = getV2ValueWithInheritance(data, previewDevice, "mixBlendMode", "normal");

  // デフォルト値は省略
  if (value !== 100) {
    styles['--thumbnail-opacity-pc'] = String(value / 100);
  }
  if (mixBlendMode !== "normal") {
    styles['--thumbnail-blend-mode-pc'] = mixBlendMode;
  }
  return styles;
};

/**
 * Thumbnail Opacity Hover - save.js用: PCのみ出力
 */
export const getThumbnailOpacityHoverStylesV2 = (attributes, { skipDefaults = false } = {}) => {
  const data = attributes.thumbnailOpacityV2Hover;
  const normalData = attributes.thumbnailOpacityV2;
  if (!data && !normalData) return {};
  const styles = {};

  const getHoverValueWithInheritance = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  const pcValue = getHoverValueWithInheritance('pc', "value", 100);
  const pcMixBlendMode = getHoverValueWithInheritance('pc', "mixBlendMode", "normal");

  if (!skipDefaults || pcValue !== 100) {
    styles['--thumbnail-opacity-pc-hover'] = String(pcValue / 100);
  }
  if (!skipDefaults || pcMixBlendMode !== "normal") {
    styles['--thumbnail-blend-mode-pc-hover'] = pcMixBlendMode;
  }
  return styles;
};

/**
 * Thumbnail Opacity Hover - edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getThumbnailOpacityHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.thumbnailOpacityV2Hover;
  const normalData = attributes.thumbnailOpacityV2;
  if (!data && !normalData) return {};
  const styles = {};

  const getHoverValueWithInheritance = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  const value = getHoverValueWithInheritance(previewDevice, "value", 100);
  const mixBlendMode = getHoverValueWithInheritance(previewDevice, "mixBlendMode", "normal");

  // デフォルト値は省略
  if (value !== 100) {
    styles['--thumbnail-opacity-pc-hover'] = String(value / 100);
  }
  if (mixBlendMode !== "normal") {
    styles['--thumbnail-blend-mode-pc-hover'] = mixBlendMode;
  }
  return styles;
};

/**
 * 背景色の通常設定とホバー設定が同じかどうかを判定する
 * クロスフェードが不要な場合はtrueを返す
 * @param {Object} attributes - ブロックの属性
 * @returns {boolean} クロスフェードをスキップすべきかどうか
 */
export const shouldSkipBackgroundColorCrossfade = (attributes) => {
  const normalData = attributes.backgroundColorV2;
  const hoverData = attributes.backgroundColorV2Hover;

  // ホバーデータが存在しない場合はスキップ
  if (!hoverData) return true;

  // PC設定を比較（メインのブレークポイント）
  const normalPc = normalData?.pc || {};
  const hoverPc = hoverData?.pc || {};

  // ホバーのPC設定が空の場合はスキップ（空文字も空とみなす）
  const hoverHasColor = hoverPc.color && hoverPc.color !== '';
  const hoverHasGradient = hoverPc.gradient && hoverPc.gradient !== '';
  const hoverHasOpacity = hoverPc.opacity !== undefined && hoverPc.opacity !== '';
  const hoverHasValue = hoverHasColor || hoverHasGradient || hoverHasOpacity;
  if (!hoverHasValue) return true;

  // 各プロパティを比較
  const normalColor = normalPc.color || '';
  const hoverColor = hoverPc.color || '';
  const normalGradient = normalPc.gradient || '';
  const hoverGradient = hoverPc.gradient || '';
  const normalUseGradient = normalPc.useGradient || false;
  const hoverUseGradient = hoverPc.useGradient || false;
  // 空文字もフォールバック対象とする
  const normalOpacity = (normalPc.opacity !== undefined && normalPc.opacity !== '') ? normalPc.opacity : 1;
  const hoverOpacity = (hoverPc.opacity !== undefined && hoverPc.opacity !== '') ? hoverPc.opacity : normalOpacity;
  const normalMixBlend = (normalPc.mixBlendMode && normalPc.mixBlendMode !== '') ? normalPc.mixBlendMode : 'normal';
  const hoverMixBlend = (hoverPc.mixBlendMode && hoverPc.mixBlendMode !== '') ? hoverPc.mixBlendMode : normalMixBlend;

  // グラデーション使用状態が異なる場合はクロスフェードが必要
  if (normalUseGradient !== hoverUseGradient) return false;

  // グラデーション使用時
  if (normalUseGradient) {
    if (normalGradient !== hoverGradient) return false;
  } else {
    // 単色使用時
    if (normalColor !== hoverColor) return false;
  }

  // opacity比較
  if (normalOpacity !== hoverOpacity) return false;

  // mixBlendMode比較
  if (normalMixBlend !== hoverMixBlend) return false;

  // すべて同じならスキップ
  return true;
};

/**
 * 背景色のクロスフェードをスキップすべきかを特定のブレークポイントで判定
 * @param {Object} normalData - 通常状態のデータ (backgroundColorV2)
 * @param {Object} hoverData - ホバー状態のデータ (backgroundColorV2Hover)
 * @param {string} breakpoint - ブレークポイント ('pc', 'md', 'tb', 'sp')
 * @returns {boolean} スキップすべきかどうか
 */
export const shouldSkipColorCrossfadeForBreakpoint = (normalData, hoverData, breakpoint) => {
  if (!hoverData) return true;

  const normalBp = normalData?.[breakpoint] || {};
  const hoverBp = hoverData?.[breakpoint] || {};

  // ホバーに値がない場合（空文字も含む）
  const hoverHasColor = hoverBp.color && hoverBp.color !== '';
  const hoverHasGradient = hoverBp.gradient && hoverBp.gradient !== '';
  const hoverHasOpacity = hoverBp.opacity !== undefined && hoverBp.opacity !== '';
  const hoverHasValue = hoverHasColor || hoverHasGradient || hoverHasOpacity;

  // ホバー値がない場合はスキップ（通常値を継承）
  if (!hoverHasValue) return true;

  // 各プロパティを比較
  const normalColor = normalBp.color || '';
  const hoverColor = hoverBp.color || '';
  const normalGradient = normalBp.gradient || '';
  const hoverGradient = hoverBp.gradient || '';
  const normalUseGradient = normalBp.useGradient || false;
  const hoverUseGradient = hoverBp.useGradient || false;
  const normalOpacity = (normalBp.opacity !== undefined && normalBp.opacity !== '') ? normalBp.opacity : 1;
  const hoverOpacity = (hoverBp.opacity !== undefined && hoverBp.opacity !== '') ? hoverBp.opacity : normalOpacity;
  const normalMixBlend = (normalBp.mixBlendMode && normalBp.mixBlendMode !== '') ? normalBp.mixBlendMode : 'normal';
  const hoverMixBlend = (hoverBp.mixBlendMode && hoverBp.mixBlendMode !== '') ? hoverBp.mixBlendMode : normalMixBlend;

  // グラデーション使用状態が異なる場合はクロスフェードが必要
  if (normalUseGradient !== hoverUseGradient) return false;

  // グラデーション使用時
  if (normalUseGradient) {
    if (normalGradient !== hoverGradient) return false;
  } else {
    // 単色使用時
    if (normalColor !== hoverColor) return false;
  }

  // opacity比較
  if (normalOpacity !== hoverOpacity) return false;

  // mixBlendMode比較
  if (normalMixBlend !== hoverMixBlend) return false;

  return true;
};

/**
 * 背景画像のクロスフェードをスキップすべきかを特定のブレークポイントで判定
 * @param {Object} normalData - 通常状態のデータ (backgroundImageV2)
 * @param {Object} hoverData - ホバー状態のデータ (backgroundImageV2Hover)
 * @param {string} breakpoint - ブレークポイント ('pc', 'md', 'tb', 'sp')
 * @returns {boolean} スキップすべきかどうか
 */
export const shouldSkipImageCrossfadeForBreakpoint = (normalData, hoverData, breakpoint) => {
  if (!hoverData) return true;

  const normalBp = normalData?.[breakpoint] || {};
  const hoverBp = hoverData?.[breakpoint] || {};

  // ホバーに画像URLがない場合
  const hoverUrl = hoverBp.url || '';
  if (!hoverUrl) return true;

  // 通常の画像URL
  const normalUrl = normalBp.url || '';

  // 画像URLが同じ場合はスキップ（position/sizeはアニメーション可能）
  return normalUrl === hoverUrl;
};

/**
 * 背景パターンのクロスフェードをスキップすべきかを特定のブレークポイントで判定
 * @param {Object} normalData - 通常状態のデータ (backgroundPatternV2)
 * @param {Object} hoverData - ホバー状態のデータ (backgroundPatternV2Hover)
 * @param {string} breakpoint - ブレークポイント ('pc', 'md', 'tb', 'sp')
 * @returns {boolean} スキップすべきかどうか
 */
export const shouldSkipPatternCrossfadeForBreakpoint = (normalData, hoverData, breakpoint) => {
  if (!hoverData) return true;

  const normalBp = normalData?.[breakpoint] || {};
  const hoverBp = hoverData?.[breakpoint] || {};

  // ホバーにパターンがない場合
  const hoverPattern = hoverBp.pattern || '';
  if (!hoverPattern) return true;

  // 通常のパターン
  const normalPattern = normalBp.pattern || '';

  // パターン種類が同じ場合はスキップ（color/size/opacityはアニメーション可能）
  return normalPattern === hoverPattern;
};

/**
 * 背景要素のクロスフェードスキップクラスを生成
 * @param {string} type - 'color' | 'image' | 'pattern'
 * @param {Object} normalData - 通常状態のデータ
 * @param {Object} hoverData - ホバー状態のデータ
 * @returns {string[]} スキップクラスの配列
 */
export const getCrossfadeSkipClasses = (type, normalData, hoverData) => {
  const classes = [];
  const breakpoints = ['pc', 'md', 'tb', 'sp'];

  breakpoints.forEach(bp => {
    let shouldSkip = false;

    switch (type) {
      case 'color':
        shouldSkip = shouldSkipColorCrossfadeForBreakpoint(normalData, hoverData, bp);
        break;
      case 'image':
        shouldSkip = shouldSkipImageCrossfadeForBreakpoint(normalData, hoverData, bp);
        break;
      case 'pattern':
        shouldSkip = shouldSkipPatternCrossfadeForBreakpoint(normalData, hoverData, bp);
        break;
    }

    if (shouldSkip) {
      classes.push(`no-crossfade-${type}-${bp}`);
    }
  });

  return classes;
};

// ============================================
// Band (帯) CSS Variables Helpers
// ============================================

/**
 * save.js用: PCのみ出力
 * バンド画像ベースカラー（通常）
 */
export const getBandImageBaseColorStylesV2 = (attributes) => {
  const data = attributes.bandImageBaseColorV2;
  if (!data) return {};
  const styles = {};
  const enabledBreakpoints = getEnabledBreakpoints();

  enabledBreakpoints.forEach((bp, index) => {
    const isPC = index === 0;

    if (isPC) {
      // PC: always output with inheritance
      const useGradient = getV2ValueWithInheritance(data, bp, "useGradient", false);
      const gradient = getV2ValueWithInheritance(data, bp, "gradient", '');

      // グラデーションモードの場合（gradientが空でもデフォルト値を使用）
      if (useGradient) {
        const gradientValue = gradient || 'linear-gradient(135deg, #007FD6 0%, #02439D 100%)';
        styles[`--band-base-gradient-${bp}`] = gradientValue;
        styles[`--band-image-base-color-${bp}`] = 'transparent';
      } else {
        const color = getV2ValueWithInheritance(data, bp, "color", '');
        const alpha = getV2ValueWithInheritance(data, bp, "alpha", 1);
        if (color) {
          styles[`--band-image-base-color-${bp}`] = getColorWithAlpha(color, alpha);
        }
      }
    }
      // MD/TB/SP: PHP CSSに任せる（出力しない）
  });

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBandImageBaseColorStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.bandImageBaseColorV2;
  if (!data) return {};
  const styles = {};

  // プレビューデバイスの値を取得（継承付き）
  const useGradient = getV2ValueWithInheritance(data, previewDevice, "useGradient", false);
  const gradient = getV2ValueWithInheritance(data, previewDevice, "gradient", '');

  // グラデーションモードの場合（gradientが空でもデフォルト値を使用）
  if (useGradient) {
    const gradientValue = gradient || 'linear-gradient(135deg, #007FD6 0%, #02439D 100%)';
    styles['--band-base-gradient-pc'] = gradientValue;
    styles['--band-image-base-color-pc'] = 'transparent';
  } else {
    const color = getV2ValueWithInheritance(data, previewDevice, "color", '');
    const alpha = getV2ValueWithInheritance(data, previewDevice, "alpha", 1);
    if (color) {
      styles['--band-image-base-color-pc'] = getColorWithAlpha(color, alpha);
    }
  }

  return styles;
};

/**
 * save.js用: PCのみ出力
 * バンド画像ベースカラー（ホバー）
 */
export const getBandImageBaseColorHoverStylesV2 = (attributes) => {
  const data = attributes.bandImageBaseColorV2Hover;
  const normalData = attributes.bandImageBaseColorV2;
  if (!data && !normalData) return {};
  const styles = {};
  const enabledBreakpoints = getEnabledBreakpoints();

  const DEFAULT_GRADIENT = 'linear-gradient(135deg, #007FD6 0%, #02439D 100%)';

  // Get hover gradient with fallback to normal (for PC)
  const getHoverGradientForPC = (bp) => {
    // Check hover data first
    const hoverUseGradient = getV2ValueWithInheritance(data, bp, "useGradient", null);
    const hoverGradient = getV2ValueWithInheritance(data, bp, "gradient", '');
    if (hoverUseGradient) {
      return hoverGradient || DEFAULT_GRADIENT;
    }
    // If hover explicitly set to NOT use gradient, return empty
    if (hoverUseGradient === false) return '';
    // Fallback to normal
    const normalUseGradient = getV2ValueWithInheritance(normalData, bp, "useGradient", false);
    const normalGradient = getV2ValueWithInheritance(normalData, bp, "gradient", '');
    if (normalUseGradient) {
      return normalGradient || DEFAULT_GRADIENT;
    }
    return '';
  };

  // Get hover color with fallback to normal (for PC)
  const getHoverColorWithAlphaForPC = (bp) => {
    const hoverColor = getV2ValueWithInheritance(data, bp, "color", '');
    const hoverAlpha = getV2ValueWithInheritance(data, bp, "alpha", '');
    if (hoverColor) {
      const alpha = hoverAlpha !== '' ? hoverAlpha : 1;
      return getColorWithAlpha(hoverColor, alpha);
    }
    // Fallback to normal
    const normalColor = getV2ValueWithInheritance(normalData, bp, "color", '');
    const normalAlpha = getV2ValueWithInheritance(normalData, bp, "alpha", 1);
    if (normalColor) {
      return getColorWithAlpha(normalColor, normalAlpha);
    }
    return '';
  };

  // Determine if hover uses gradient
  const getHoverUseGradient = (bp) => {
    const hoverUseGradient = getV2ValueWithInheritance(data, bp, "useGradient", null);
    if (hoverUseGradient !== null && hoverUseGradient !== '') return hoverUseGradient;
    // Fallback to normal
    return getV2ValueWithInheritance(normalData, bp, "useGradient", false);
  };

  enabledBreakpoints.forEach((bp, index) => {
    const isPC = index === 0;

    if (isPC) {
      // PC: always output with inheritance
      const useGradient = getHoverUseGradient(bp);
      if (useGradient) {
        const hoverGradient = getHoverGradientForPC(bp);
        styles[`--band-base-gradient-${bp}-hover`] = hoverGradient;
        styles[`--band-image-base-color-${bp}-hover`] = 'transparent';
      } else {
        const hoverColor = getHoverColorWithAlphaForPC(bp);
        if (hoverColor) {
          styles[`--band-image-base-color-${bp}-hover`] = hoverColor;
          // グラデーション→単色切り替え時、単色をグラデーションとしても設定（白フラッシュ防止）
          styles[`--band-base-gradient-${bp}-hover`] = `linear-gradient(0deg, ${hoverColor} 0%, ${hoverColor} 100%)`;
        } else {
          styles[`--band-base-gradient-${bp}-hover`] = 'none';
        }
      }
    }
      // MD/TB/SP: PHP CSSに任せる（出力しない）
  });

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBandImageBaseColorHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.bandImageBaseColorV2Hover;
  const normalData = attributes.bandImageBaseColorV2;
  if (!data && !normalData) return {};
  const styles = {};
  const DEFAULT_GRADIENT = 'linear-gradient(135deg, #007FD6 0%, #02439D 100%)';

  // Determine if hover uses gradient
  const getHoverUseGradient = (bp) => {
    const hoverUseGradient = getV2ValueWithInheritance(data, bp, "useGradient", null);
    if (hoverUseGradient !== null && hoverUseGradient !== '') return hoverUseGradient;
    return getV2ValueWithInheritance(normalData, bp, "useGradient", false);
  };

  // Get hover gradient with fallback to normal
  const getHoverGradient = (bp) => {
    const hoverUseGradient = getV2ValueWithInheritance(data, bp, "useGradient", null);
    const hoverGradient = getV2ValueWithInheritance(data, bp, "gradient", '');
    if (hoverUseGradient) return hoverGradient || DEFAULT_GRADIENT;
    if (hoverUseGradient === false) return '';
    const normalUseGradient = getV2ValueWithInheritance(normalData, bp, "useGradient", false);
    const normalGradient = getV2ValueWithInheritance(normalData, bp, "gradient", '');
    if (normalUseGradient) return normalGradient || DEFAULT_GRADIENT;
    return '';
  };

  // Get hover color with fallback to normal
  const getHoverColorWithAlpha = (bp) => {
    const hoverColor = getV2ValueWithInheritance(data, bp, "color", '');
    const hoverAlpha = getV2ValueWithInheritance(data, bp, "alpha", '');
    if (hoverColor) {
      const alpha = hoverAlpha !== '' ? hoverAlpha : 1;
      return getColorWithAlpha(hoverColor, alpha);
    }
    // Fallback to normal
    const normalColor = getV2ValueWithInheritance(normalData, bp, "color", '');
    const normalAlpha = getV2ValueWithInheritance(normalData, bp, "alpha", 1);
    if (normalColor) {
      return getColorWithAlpha(normalColor, normalAlpha);
    }
    return '';
  };

  const useGradient = getHoverUseGradient(previewDevice);
  if (useGradient) {
    const hoverGradient = getHoverGradient(previewDevice);
    styles['--band-base-gradient-pc-hover'] = hoverGradient;
    styles['--band-image-base-color-pc-hover'] = 'transparent';
  } else {
    const hoverColor = getHoverColorWithAlpha(previewDevice);
    if (hoverColor) {
      styles['--band-image-base-color-pc-hover'] = hoverColor;
      // グラデーション→単色切り替え時、単色をグラデーションとしても設定（白フラッシュ防止）
      styles['--band-base-gradient-pc-hover'] = `linear-gradient(0deg, ${hoverColor} 0%, ${hoverColor} 100%)`;
    } else {
      styles['--band-base-gradient-pc-hover'] = 'none';
    }
  }

  return styles;
};

/**
 * save.js用: PCのみ出力
 * バンド画像スタイル（通常）
 */
export const getBandImageStylesV2 = (attributes) => {
  const data = attributes.bandImageV2;
  if (!data) return {};
  const styles = {};
  const enabledBreakpoints = getEnabledBreakpoints();

  // Helper to get size value including custom dimensions (for PC with inheritance)
  const getSizeValueWithInheritance = (bp) => {
    const objectFit = getV2ValueWithInheritance(data, bp, "objectFit", "cover");
    if (objectFit === "fill" || objectFit === "none") {
      const bgWidth = getV2ValueWithInheritance(data, bp, "bgWidth", "100");
      const bgWidthUnit = getV2ValueWithInheritance(data, bp, "bgWidthUnit", "%");
      const bgHeight = getV2ValueWithInheritance(data, bp, "bgHeight", "auto");
      const bgHeightUnit = getV2ValueWithInheritance(data, bp, "bgHeightUnit", "%");
      const width = bgWidth === "auto" ? "auto" : `${bgWidth}${bgWidthUnit}`;
      const height = bgHeight === "auto" ? "auto" : `${bgHeight}${bgHeightUnit}`;
      return `${width} ${height}`;
    }
    return objectFit;
  };

  // Helper to get size value for non-PC breakpoints (direct value only)
  const getSizeValueDirect = (bp) => {
    const objectFit = getV2DirectValue(data, bp, "objectFit");
    const bgWidth = getV2DirectValue(data, bp, "bgWidth");
    const bgHeight = getV2DirectValue(data, bp, "bgHeight");

    // If objectFit is explicitly set for this breakpoint
    if (objectFit !== undefined) {
      if (objectFit === "fill" || objectFit === "none") {
        const bgWidthUnit = getV2DirectValue(data, bp, "bgWidthUnit") || "%";
        const bgHeightUnit = getV2DirectValue(data, bp, "bgHeightUnit") || "%";
        const width = bgWidth === "auto" ? "auto" : (bgWidth !== undefined ? `${bgWidth}${bgWidthUnit}` : "100%");
        const height = bgHeight === "auto" ? "auto" : (bgHeight !== undefined ? `${bgHeight}${bgHeightUnit}` : "auto");
        return `${width} ${height}`;
      }
      return objectFit;
    }

    // If only bgWidth or bgHeight is set, we need to include them
    if (bgWidth !== undefined || bgHeight !== undefined) {
      const objectFitInherited = getV2ValueWithInheritance(data, bp, "objectFit", "cover");
      if (objectFitInherited === "fill" || objectFitInherited === "none") {
        const bgWidthUnit = getV2DirectValue(data, bp, "bgWidthUnit") || getV2ValueWithInheritance(data, bp, "bgWidthUnit", "%");
        const bgHeightUnit = getV2DirectValue(data, bp, "bgHeightUnit") || getV2ValueWithInheritance(data, bp, "bgHeightUnit", "%");
        const widthVal = bgWidth !== undefined ? bgWidth : getV2ValueWithInheritance(data, bp, "bgWidth", "100");
        const heightVal = bgHeight !== undefined ? bgHeight : getV2ValueWithInheritance(data, bp, "bgHeight", "auto");
        const width = widthVal === "auto" ? "auto" : `${widthVal}${bgWidthUnit}`;
        const height = heightVal === "auto" ? "auto" : `${heightVal}${bgHeightUnit}`;
        return `${width} ${height}`;
      }
    }

    return undefined;
  };

  enabledBreakpoints.forEach((bp, index) => {
    const isPC = index === 0;

    if (isPC) {
      // PC: always output with inheritance
      const url = getV2ValueWithInheritance(data, bp, "url", "");
      const position = getV2ValueWithInheritance(data, bp, "focalPosition", "50% 50%");
      const size = getSizeValueWithInheritance(bp);
      const repeat = getV2ValueWithInheritance(data, bp, "repeat", "no-repeat");
      const rotate = getBackgroundImageRotateValue(data, bp, "0deg");
      const frameWidth = getV2ValueWithInheritance(data, bp, "frameWidth", 100);
      const frameWidthUnit = getV2ValueWithInheritance(data, bp, "frameWidthUnit", "%");
      const frameHeight = getV2ValueWithInheritance(data, bp, "frameHeight", 100);
      const frameHeightUnit = getV2ValueWithInheritance(data, bp, "frameHeightUnit", "%");
      const borderRadius = getV2ValueWithInheritance(data, bp, "borderRadius", 0);
      const borderRadiusUnit = getV2ValueWithInheritance(data, bp, "borderRadiusUnit", "px");
      const borderWidth = getV2ValueWithInheritance(data, bp, "borderWidth", 0);
      const borderStyle = getV2ValueWithInheritance(data, bp, "borderStyle", "none");
      const borderColor = getV2ValueWithInheritance(data, bp, "borderColor", "transparent");
      const borderColorAlpha = getV2ValueWithInheritance(data, bp, "borderColorAlpha", 1);
      const borderBoxSizing = getV2ValueWithInheritance(data, bp, "borderBoxSizing", "border-box");
      const offsetX = getV2ValueWithInheritance(data, bp, "offsetX", 0);
      const offsetXUnit = getV2ValueWithInheritance(data, bp, "offsetXUnit", "%");
      const offsetY = getV2ValueWithInheritance(data, bp, "offsetY", 0);
      const offsetYUnit = getV2ValueWithInheritance(data, bp, "offsetYUnit", "%");
      const originX = getV2ValueWithInheritance(data, bp, "originX", "left");
      const originY = getV2ValueWithInheritance(data, bp, "originY", "top");

      styles[`--band-image-${bp}`] = url ? `url(${url})` : "none";
      styles[`--band-position-${bp}`] = position;
      styles[`--band-size-${bp}`] = size;
      styles[`--band-repeat-${bp}`] = repeat;
      styles[`--band-rotate-${bp}`] = rotate;
      styles[`--band-frame-width-${bp}`] = `${frameWidth}${frameWidthUnit}`;
      styles[`--band-frame-height-${bp}`] = `${frameHeight}${frameHeightUnit}`;
      styles[`--band-radius-${bp}`] = `${borderRadius}${borderRadiusUnit}`;
      styles[`--band-border-width-${bp}`] = `${borderWidth}px`;
      styles[`--band-border-style-${bp}`] = borderStyle;
      styles[`--band-border-color-${bp}`] = borderColor === "transparent" ? "transparent" : hexToRgba(borderColor, borderColorAlpha);
      styles[`--band-box-sizing-${bp}`] = borderBoxSizing;

      // Image opacity
      const opacity = getV2ValueWithInheritance(data, bp, "opacity", 1);
      styles[`--band-image-opacity-${bp}`] = `${opacity}`;

      // Origin-based positioning
      const offsetXValue = `${offsetX}${offsetXUnit}`;
      const offsetYValue = `${offsetY}${offsetYUnit}`;

      if (originX === 'center') {
        styles[`--band-left-${bp}`] = offsetX === 0 ? '50%' : `calc(50% + ${offsetXValue})`;
        styles[`--band-right-${bp}`] = 'auto';
        styles[`--band-transform-x-${bp}`] = '-50%';
      } else {
        styles[`--band-left-${bp}`] = originX === 'left' ? offsetXValue : 'auto';
        styles[`--band-right-${bp}`] = originX === 'right' ? offsetXValue : 'auto';
        styles[`--band-transform-x-${bp}`] = '0';
      }

      if (originY === 'center') {
        styles[`--band-top-${bp}`] = offsetY === 0 ? '50%' : `calc(50% + ${offsetYValue})`;
        styles[`--band-bottom-${bp}`] = 'auto';
        styles[`--band-transform-y-${bp}`] = '-50%';
      } else {
        styles[`--band-top-${bp}`] = originY === 'top' ? offsetYValue : 'auto';
        styles[`--band-bottom-${bp}`] = originY === 'bottom' ? offsetYValue : 'auto';
        styles[`--band-transform-y-${bp}`] = '0';
      }
    }
      // MD/TB/SP: PHP CSSに任せる（出力しない）
  });

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * バンド画像スタイル（エディタプレビュー用）
 */
export const getBandImageStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.bandImageV2;
  if (!data) return {};
  const styles = {};

  // Helper to get size value including custom dimensions
  const getSizeValue = (bp) => {
    const objectFit = getV2ValueWithInheritance(data, bp, "objectFit", "cover");
    if (objectFit === "fill" || objectFit === "none") {
      const bgWidth = getV2ValueWithInheritance(data, bp, "bgWidth", "100");
      const bgWidthUnit = getV2ValueWithInheritance(data, bp, "bgWidthUnit", "%");
      const bgHeight = getV2ValueWithInheritance(data, bp, "bgHeight", "auto");
      const bgHeightUnit = getV2ValueWithInheritance(data, bp, "bgHeightUnit", "%");
      const width = bgWidth === "auto" ? "auto" : `${bgWidth}${bgWidthUnit}`;
      const height = bgHeight === "auto" ? "auto" : `${bgHeight}${bgHeightUnit}`;
      return `${width} ${height}`;
    }
    return objectFit;
  };

  // プレビューデバイスの値を取得（継承付き）
  const url = getV2ValueWithInheritance(data, previewDevice, "url", "");
  const position = getV2ValueWithInheritance(data, previewDevice, "focalPosition", "50% 50%");
  const size = getSizeValue(previewDevice);
  const repeat = getV2ValueWithInheritance(data, previewDevice, "repeat", "no-repeat");
  const rotate = getBackgroundImageRotateValue(data, previewDevice, "0deg");
  const frameWidth = getV2ValueWithInheritance(data, previewDevice, "frameWidth", 100);
  const frameWidthUnit = getV2ValueWithInheritance(data, previewDevice, "frameWidthUnit", "%");
  const frameHeight = getV2ValueWithInheritance(data, previewDevice, "frameHeight", 100);
  const frameHeightUnit = getV2ValueWithInheritance(data, previewDevice, "frameHeightUnit", "%");
  const borderRadius = getV2ValueWithInheritance(data, previewDevice, "borderRadius", 0);
  const borderRadiusUnit = getV2ValueWithInheritance(data, previewDevice, "borderRadiusUnit", "px");
  const borderWidth = getV2ValueWithInheritance(data, previewDevice, "borderWidth", 0);
  const borderStyle = getV2ValueWithInheritance(data, previewDevice, "borderStyle", "none");
  const borderColor = getV2ValueWithInheritance(data, previewDevice, "borderColor", "transparent");
  const borderColorAlpha = getV2ValueWithInheritance(data, previewDevice, "borderColorAlpha", 1);
  const borderBoxSizing = getV2ValueWithInheritance(data, previewDevice, "borderBoxSizing", "border-box");
  const offsetX = getV2ValueWithInheritance(data, previewDevice, "offsetX", 0);
  const offsetXUnit = getV2ValueWithInheritance(data, previewDevice, "offsetXUnit", "%");
  const offsetY = getV2ValueWithInheritance(data, previewDevice, "offsetY", 0);
  const offsetYUnit = getV2ValueWithInheritance(data, previewDevice, "offsetYUnit", "%");
  const originX = getV2ValueWithInheritance(data, previewDevice, "originX", "left");
  const originY = getV2ValueWithInheritance(data, previewDevice, "originY", "top");

  // PC変数に出力（エディタでプレビューデバイスの値を反映）
  styles['--band-image-pc'] = url ? `url(${url})` : "none";
  styles['--band-position-pc'] = position;
  styles['--band-size-pc'] = size;
  styles['--band-repeat-pc'] = repeat;
  styles['--band-rotate-pc'] = rotate;
  styles['--band-frame-width-pc'] = `${frameWidth}${frameWidthUnit}`;
  styles['--band-frame-height-pc'] = `${frameHeight}${frameHeightUnit}`;
  styles['--band-radius-pc'] = `${borderRadius}${borderRadiusUnit}`;
  styles['--band-border-width-pc'] = `${borderWidth}px`;
  styles['--band-border-style-pc'] = borderStyle;
  styles['--band-border-color-pc'] = borderColor === "transparent" ? "transparent" : hexToRgba(borderColor, borderColorAlpha);
  styles['--band-box-sizing-pc'] = borderBoxSizing;

  // Image opacity
  const imageOpacity = getV2ValueWithInheritance(data, previewDevice, "opacity", 1);
  styles['--band-image-opacity-pc'] = `${imageOpacity}`;

  // Origin-based positioning: output left/right and top/bottom based on origin
  const offsetXValue = `${offsetX}${offsetXUnit}`;
  const offsetYValue = `${offsetY}${offsetYUnit}`;

  // X positioning
  if (originX === 'center') {
    styles['--band-left-pc'] = offsetX === 0 ? '50%' : `calc(50% + ${offsetXValue})`;
    styles['--band-right-pc'] = 'auto';
    styles['--band-transform-x-pc'] = '-50%';
  } else {
    styles['--band-left-pc'] = originX === 'left' ? offsetXValue : 'auto';
    styles['--band-right-pc'] = originX === 'right' ? offsetXValue : 'auto';
    styles['--band-transform-x-pc'] = '0';
  }

  // Y positioning
  if (originY === 'center') {
    styles['--band-top-pc'] = offsetY === 0 ? '50%' : `calc(50% + ${offsetYValue})`;
    styles['--band-bottom-pc'] = 'auto';
    styles['--band-transform-y-pc'] = '-50%';
  } else {
    styles['--band-top-pc'] = originY === 'top' ? offsetYValue : 'auto';
    styles['--band-bottom-pc'] = originY === 'bottom' ? offsetYValue : 'auto';
    styles['--band-transform-y-pc'] = '0';
  }

  return styles;
};

/**
 * save.js用: PCのみ出力
 * ホバー時のバンド画像スタイル（位置・サイズ・リピート）
 */
export const getBandImageHoverStylesV2 = (attributes) => {
  const data = attributes.bandImageV2Hover;
  const normalData = attributes.bandImageV2;
  if (!data && !normalData) return {};
  const styles = {};
  const enabledBreakpoints = getEnabledBreakpoints();

  // Helper to get hover value with fallback to normal (for PC with inheritance)
  const getHoverValueForPC = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  // Helper to get size value for PC (with inheritance)
  const getSizeValueForPC = (bp) => {
    const objectFit = getHoverValueForPC(bp, "objectFit", "cover");
    if (objectFit === "fill" || objectFit === "none") {
      const bgWidth = getHoverValueForPC(bp, "bgWidth", "100");
      const bgWidthUnit = getHoverValueForPC(bp, "bgWidthUnit", "%");
      const bgHeight = getHoverValueForPC(bp, "bgHeight", "auto");
      const bgHeightUnit = getHoverValueForPC(bp, "bgHeightUnit", "%");
      const width = bgWidth === "auto" ? "auto" : `${bgWidth}${bgWidthUnit}`;
      const height = bgHeight === "auto" ? "auto" : `${bgHeight}${bgHeightUnit}`;
      return `${width} ${height}`;
    }
    return objectFit;
  };

  // Helper to get size value for non-PC breakpoints (direct value only)
  const getSizeValueDirect = (bp) => {
    const objectFit = getV2DirectValue(data, bp, "objectFit");
    const bgWidth = getV2DirectValue(data, bp, "bgWidth");
    const bgHeight = getV2DirectValue(data, bp, "bgHeight");

    if (objectFit !== undefined) {
      if (objectFit === "fill" || objectFit === "none") {
        const bgWidthUnit = getV2DirectValue(data, bp, "bgWidthUnit") || "%";
        const bgHeightUnit = getV2DirectValue(data, bp, "bgHeightUnit") || "%";
        const width = bgWidth === "auto" ? "auto" : (bgWidth !== undefined ? `${bgWidth}${bgWidthUnit}` : "100%");
        const height = bgHeight === "auto" ? "auto" : (bgHeight !== undefined ? `${bgHeight}${bgHeightUnit}` : "auto");
        return `${width} ${height}`;
      }
      return objectFit;
    }

    if (bgWidth !== undefined || bgHeight !== undefined) {
      const objectFitInherited = getV2ValueWithInheritance(data, bp, "objectFit", "cover");
      if (objectFitInherited === "fill" || objectFitInherited === "none") {
        const bgWidthUnit = getV2DirectValue(data, bp, "bgWidthUnit") || getV2ValueWithInheritance(data, bp, "bgWidthUnit", "%");
        const bgHeightUnit = getV2DirectValue(data, bp, "bgHeightUnit") || getV2ValueWithInheritance(data, bp, "bgHeightUnit", "%");
        const widthVal = bgWidth !== undefined ? bgWidth : getV2ValueWithInheritance(data, bp, "bgWidth", "100");
        const heightVal = bgHeight !== undefined ? bgHeight : getV2ValueWithInheritance(data, bp, "bgHeight", "auto");
        const width = widthVal === "auto" ? "auto" : `${widthVal}${bgWidthUnit}`;
        const height = heightVal === "auto" ? "auto" : `${heightVal}${bgHeightUnit}`;
        return `${width} ${height}`;
      }
    }

    return undefined;
  };

  enabledBreakpoints.forEach((bp, index) => {
    const isPC = index === 0;

    if (isPC) {
      // PC: always output with inheritance and fallback to normal
      const position = getHoverValueForPC(bp, "focalPosition", "50% 50%");
      const size = getSizeValueForPC(bp);
      const repeat = getHoverValueForPC(bp, "repeat", "no-repeat");
      const rotate = getBackgroundImageRotateValue(
        { [bp]: { rotate: getHoverValueForPC(bp, "rotate", "0") } },
        bp,
        getBackgroundImageRotateValue(normalData, bp, "0deg")
      );
      const frameWidth = getHoverValueForPC(bp, "frameWidth", 100);
      const frameWidthUnit = getHoverValueForPC(bp, "frameWidthUnit", "%");
      const frameHeight = getHoverValueForPC(bp, "frameHeight", 60);
      const frameHeightUnit = getHoverValueForPC(bp, "frameHeightUnit", "px");
      const borderRadius = getHoverValueForPC(bp, "borderRadius", 0);
      const borderRadiusUnit = getHoverValueForPC(bp, "borderRadiusUnit", "px");
      const borderWidth = getHoverValueForPC(bp, "borderWidth", 0);
      const borderStyle = getHoverValueForPC(bp, "borderStyle", "none");
      const borderColor = getHoverValueForPC(bp, "borderColor", "transparent");
      const borderColorAlpha = getHoverValueForPC(bp, "borderColorAlpha", 1);
      const borderBoxSizing = getHoverValueForPC(bp, "borderBoxSizing", "border-box");
      const offsetX = getHoverValueForPC(bp, "offsetX", 0);
      const offsetXUnit = getHoverValueForPC(bp, "offsetXUnit", "%");
      const offsetY = getHoverValueForPC(bp, "offsetY", 0);
      const offsetYUnit = getHoverValueForPC(bp, "offsetYUnit", "%");
      const originX = getHoverValueForPC(bp, "originX", "left");
      const originY = getHoverValueForPC(bp, "originY", "top");

      styles[`--band-position-${bp}-hover`] = position;
      styles[`--band-size-${bp}-hover`] = size;
      styles[`--band-repeat-${bp}-hover`] = repeat;
      styles[`--band-rotate-${bp}-hover`] = rotate;
      styles[`--band-frame-width-${bp}-hover`] = `${frameWidth}${frameWidthUnit}`;
      styles[`--band-frame-height-${bp}-hover`] = `${frameHeight}${frameHeightUnit}`;
      styles[`--band-radius-${bp}-hover`] = `${borderRadius}${borderRadiusUnit}`;
      styles[`--band-border-width-${bp}-hover`] = `${borderWidth}px`;
      styles[`--band-border-style-${bp}-hover`] = borderStyle;
      styles[`--band-border-color-${bp}-hover`] = borderColor === "transparent" ? "transparent" : hexToRgba(borderColor, borderColorAlpha);
      styles[`--band-box-sizing-${bp}-hover`] = borderBoxSizing;

      // Image opacity hover
      const hoverOpacity = getHoverValueForPC(bp, "opacity", 1);
      styles[`--band-image-opacity-${bp}-hover`] = `${hoverOpacity}`;

      // Origin-based positioning for hover
      const offsetXValue = `${offsetX}${offsetXUnit}`;
      const offsetYValue = `${offsetY}${offsetYUnit}`;

      if (originX === 'center') {
        styles[`--band-left-${bp}-hover`] = offsetX === 0 ? '50%' : `calc(50% + ${offsetXValue})`;
        styles[`--band-right-${bp}-hover`] = 'auto';
        styles[`--band-transform-x-${bp}-hover`] = '-50%';
      } else {
        styles[`--band-left-${bp}-hover`] = originX === 'left' ? offsetXValue : 'auto';
        styles[`--band-right-${bp}-hover`] = originX === 'right' ? offsetXValue : 'auto';
        styles[`--band-transform-x-${bp}-hover`] = '0';
      }

      if (originY === 'center') {
        styles[`--band-top-${bp}-hover`] = offsetY === 0 ? '50%' : `calc(50% + ${offsetYValue})`;
        styles[`--band-bottom-${bp}-hover`] = 'auto';
        styles[`--band-transform-y-${bp}-hover`] = '-50%';
      } else {
        styles[`--band-top-${bp}-hover`] = originY === 'top' ? offsetYValue : 'auto';
        styles[`--band-bottom-${bp}-hover`] = originY === 'bottom' ? offsetYValue : 'auto';
        styles[`--band-transform-y-${bp}-hover`] = '0';
      }
    }
      // MD/TB/SP: PHP CSSに任せる（出力しない）
  });

  return styles;
};

/**
 * edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 * ホバー時のバンド画像スタイル（エディタプレビュー用）
 */
export const getBandImageHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.bandImageV2Hover;
  const normalData = attributes.bandImageV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal
  const getHoverValue = (key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, previewDevice, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, previewDevice, key, defaultVal);
  };

  // Helper to get size value including custom dimensions
  const getSizeValue = () => {
    const objectFit = getHoverValue("objectFit", "cover");
    if (objectFit === "fill" || objectFit === "none") {
      const bgWidth = getHoverValue("bgWidth", "100");
      const bgWidthUnit = getHoverValue("bgWidthUnit", "%");
      const bgHeight = getHoverValue("bgHeight", "auto");
      const bgHeightUnit = getHoverValue("bgHeightUnit", "%");
      const width = bgWidth === "auto" ? "auto" : `${bgWidth}${bgWidthUnit}`;
      const height = bgHeight === "auto" ? "auto" : `${bgHeight}${bgHeightUnit}`;
      return `${width} ${height}`;
    }
    return objectFit;
  };

  // プレビューデバイスの値を取得（継承付き、ホバーから通常へのフォールバック）
  const position = getHoverValue("focalPosition", "50% 50%");
  const size = getSizeValue();
  const repeat = getHoverValue("repeat", "no-repeat");
  const rotate = getBackgroundImageRotateValue(
    { [previewDevice]: { rotate: getHoverValue("rotate", "0") } },
    previewDevice,
    getBackgroundImageRotateValue(normalData, previewDevice, "0deg")
  );
  const frameWidth = getHoverValue("frameWidth", 100);
  const frameWidthUnit = getHoverValue("frameWidthUnit", "%");
  const frameHeight = getHoverValue("frameHeight", 100);
  const frameHeightUnit = getHoverValue("frameHeightUnit", "%");
  const borderRadius = getHoverValue("borderRadius", 0);
  const borderRadiusUnit = getHoverValue("borderRadiusUnit", "px");
  const borderWidth = getHoverValue("borderWidth", 0);
  const borderStyle = getHoverValue("borderStyle", "none");
  const borderColor = getHoverValue("borderColor", "transparent");
  const borderColorAlpha = getHoverValue("borderColorAlpha", 1);
  const borderBoxSizing = getHoverValue("borderBoxSizing", "border-box");
  const offsetX = getHoverValue("offsetX", 0);
  const offsetXUnit = getHoverValue("offsetXUnit", "%");
  const offsetY = getHoverValue("offsetY", 0);
  const offsetYUnit = getHoverValue("offsetYUnit", "%");
  const originX = getHoverValue("originX", "left");
  const originY = getHoverValue("originY", "top");

  // PC変数に出力（エディタでプレビューデバイスの値を反映）
  styles['--band-position-pc-hover'] = position;
  styles['--band-size-pc-hover'] = size;
  styles['--band-repeat-pc-hover'] = repeat;
  styles['--band-rotate-pc-hover'] = rotate;
  styles['--band-frame-width-pc-hover'] = `${frameWidth}${frameWidthUnit}`;
  styles['--band-frame-height-pc-hover'] = `${frameHeight}${frameHeightUnit}`;
  styles['--band-radius-pc-hover'] = `${borderRadius}${borderRadiusUnit}`;
  styles['--band-border-width-pc-hover'] = `${borderWidth}px`;
  styles['--band-border-style-pc-hover'] = borderStyle;
  styles['--band-border-color-pc-hover'] = borderColor === "transparent" ? "transparent" : hexToRgba(borderColor, borderColorAlpha);
  styles['--band-box-sizing-pc-hover'] = borderBoxSizing;

  // Image opacity hover
  const hoverOpacity = getHoverValue("opacity", 1);
  styles['--band-image-opacity-pc-hover'] = `${hoverOpacity}`;

  // Origin-based positioning for hover
  const offsetXValue = `${offsetX}${offsetXUnit}`;
  const offsetYValue = `${offsetY}${offsetYUnit}`;

  // X positioning for hover
  if (originX === 'center') {
    styles['--band-left-pc-hover'] = offsetX === 0 ? '50%' : `calc(50% + ${offsetXValue})`;
    styles['--band-right-pc-hover'] = 'auto';
    styles['--band-transform-x-pc-hover'] = '-50%';
  } else {
    styles['--band-left-pc-hover'] = originX === 'left' ? offsetXValue : 'auto';
    styles['--band-right-pc-hover'] = originX === 'right' ? offsetXValue : 'auto';
    styles['--band-transform-x-pc-hover'] = '0';
  }

  // Y positioning for hover
  if (originY === 'center') {
    styles['--band-top-pc-hover'] = offsetY === 0 ? '50%' : `calc(50% + ${offsetYValue})`;
    styles['--band-bottom-pc-hover'] = 'auto';
    styles['--band-transform-y-pc-hover'] = '-50%';
  } else {
    styles['--band-top-pc-hover'] = originY === 'top' ? offsetYValue : 'auto';
    styles['--band-bottom-pc-hover'] = originY === 'bottom' ? offsetYValue : 'auto';
    styles['--band-transform-y-pc-hover'] = '0';
  }

  return styles;
};

/**
 * バンドカラー値を取得（背景カラーと同じ方式 — 単色もlinear-gradient()でラップ）
 */
const getBandColorV2Value = (attributes, device, isHover = false) => {
  const attrName = isHover ? 'bandColorV2Hover' : 'bandColorV2';
  const data = attributes[attrName];
  if (!data) return 'linear-gradient(90deg, transparent 0%, transparent 100%)';
  const useGradient = getV2ValueWithInheritance(data, device, 'useGradient', false);
  const gradient = getV2ValueWithInheritance(data, device, 'gradient', '');
  const color = getV2ValueWithInheritance(data, device, 'color', '');
  if (useGradient && gradient) return gradient;
  const effectiveColor = color || 'transparent';
  return `linear-gradient(90deg, ${effectiveColor} 0%, ${effectiveColor} 100%)`;
};

/**
 * バンドカラーホバー値を直接取得（ブレークポイント継承あり、通常値へのフォールバックなし）
 * 背景カラーの getBackgroundColorV2HoverValueWithInheritance と同じパターン
 */
const getBandColorV2HoverValueWithInheritance = (attributes, device) => {
  const data = attributes.bandColorV2Hover;
  if (!data) return '';
  const enabledBreakpoints = getEnabledBreakpoints();
  const currentIndex = enabledBreakpoints.indexOf(device);
  for (let i = currentIndex; i >= 0; i--) {
    const bp = enabledBreakpoints[i];
    if (!data[bp]) continue;
    const bpData = data[bp];
    const color = bpData.color;
    const gradient = bpData.gradient;
    const useGradient = bpData.useGradient;
    if (useGradient && gradient) return gradient;
    if (color && color !== '' && color !== 'transparent') return `linear-gradient(90deg, ${color} 0%, ${color} 100%)`;
  }
  return '';
};

/**
 * バンドオーバーレイ色スタイル（通常）
 */
export const getBandColorStylesV2 = (attributes) => {
  const data = attributes.bandColorV2;
  const styles = {};

  // PC値のみ出力（MD/TB/SPはPHP CSSに任せる）
  const pcValue = getBandColorV2Value(attributes, 'pc');
  const pcOpacity = data ? getV2ValueWithInheritance(data, 'pc', "opacity", 1) : 1;
  const pcMixBlendMode = data ? getV2ValueWithInheritance(data, 'pc', "mixBlendMode", "normal") : "normal";

  styles['--band-color-pc'] = pcValue;
  styles['--band-color-opacity-pc'] = pcOpacity;
  styles['--band-color-blend-mode-pc'] = pcMixBlendMode;

  return styles;
};

/**
 * edit.js用: バンドオーバーレイ色スタイル（通常）
 * PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBandColorStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.bandColorV2;
  const styles = {};

  styles['--band-color-pc'] = getBandColorV2Value(attributes, previewDevice);
  styles['--band-color-opacity-pc'] = data ? getV2ValueWithInheritance(data, previewDevice, "opacity", 1) : 1;
  styles['--band-color-blend-mode-pc'] = data ? getV2ValueWithInheritance(data, previewDevice, "mixBlendMode", "normal") : "normal";

  return styles;
};

/**
 * バンドオーバーレイ色スタイル（ホバー）
 * ホバー値がなければ通常値にフォールバック（背景カラーと同じパターン）
 */
export const getBandColorHoverStylesV2 = (attributes) => {
  const data = attributes.bandColorV2Hover;
  const normalData = attributes.bandColorV2;
  const styles = {};

  const getHoverOpacity = () => {
    const hoverOpacity = getV2ValueWithInheritance(data, 'pc', "opacity", undefined);
    if (hoverOpacity !== undefined && hoverOpacity !== '') return hoverOpacity;
    return getV2ValueWithInheritance(normalData, 'pc', "opacity", 1);
  };

  const getHoverMixBlend = () => {
    const hoverMixBlend = getV2ValueWithInheritance(data, 'pc', "mixBlendMode", undefined);
    if (hoverMixBlend !== undefined && hoverMixBlend !== '') return hoverMixBlend;
    return getV2ValueWithInheritance(normalData, 'pc', "mixBlendMode", "normal");
  };

  const getHoverColor = () => {
    const hoverValue = getBandColorV2HoverValueWithInheritance(attributes, 'pc');
    if (hoverValue) return hoverValue;
    return getBandColorV2Value(attributes, 'pc', false);
  };

  // PC値のみ出力（MD/TB/SPはPHP CSSに任せる）
  styles['--band-color-pc-hover'] = getHoverColor();
  styles['--band-color-opacity-pc-hover'] = getHoverOpacity();
  styles['--band-color-blend-mode-pc-hover'] = getHoverMixBlend();

  return styles;
};

/**
 * edit.js用: バンドオーバーレイ色スタイル（ホバー）
 * PC変数のみ出力、値はプレビューデバイスに応じて変更
 * ホバー値がなければ通常値にフォールバック（背景カラーと同じパターン）
 */
export const getBandColorHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.bandColorV2Hover;
  const normalData = attributes.bandColorV2;
  const styles = {};

  const getHoverOpacity = (bp) => {
    const hoverOpacity = getV2ValueWithInheritance(data, bp, "opacity", undefined);
    if (hoverOpacity !== undefined && hoverOpacity !== '') return hoverOpacity;
    return getV2ValueWithInheritance(normalData, bp, "opacity", 1);
  };

  const getHoverMixBlend = (bp) => {
    const hoverMixBlend = getV2ValueWithInheritance(data, bp, "mixBlendMode", undefined);
    if (hoverMixBlend !== undefined && hoverMixBlend !== '') return hoverMixBlend;
    return getV2ValueWithInheritance(normalData, bp, "mixBlendMode", "normal");
  };

  const getHoverColor = (bp) => {
    const hoverValue = getBandColorV2HoverValueWithInheritance(attributes, bp);
    if (hoverValue) return hoverValue;
    return getBandColorV2Value(attributes, bp, false);
  };

  // プレビューデバイスの値を取得、PC変数名で出力
  styles['--band-color-pc-hover'] = getHoverColor(previewDevice);
  styles['--band-color-opacity-pc-hover'] = getHoverOpacity(previewDevice);
  styles['--band-color-blend-mode-pc-hover'] = getHoverMixBlend(previewDevice);

  return styles;
};

/**
 * save.js用: バンドパターンスタイル（通常）
 * PCのみ出力、MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getBandPatternStylesV2 = (attributes) => {
  const data = attributes.bandPatternV2;
  if (!data) return {};
  const styles = {};

  // Get PC values only
  const pcType = getV2ValueWithInheritance(data, 'pc', "type", '');
  const pcColor = getV2ValueWithInheritance(data, 'pc', "color", '');
  const pcOpacity = getV2ValueWithInheritance(data, 'pc', "opacity", '');
  const pcSize = getV2ValueWithInheritance(data, 'pc', "size", '');
  const pcSizeUnit = getV2ValueWithInheritance(data, 'pc', "sizeUnit", "px");
  const pcMixBlendMode = getV2ValueWithInheritance(data, 'pc', "mixBlendMode", '');

  if (pcType) styles['--band-pattern-type-pc'] = pcType;
  if (pcColor) styles['--band-pattern-color-pc'] = pcColor;
  if (pcOpacity !== '' && pcOpacity !== undefined) styles['--band-pattern-opacity-pc'] = pcOpacity;
  if (pcSize !== '' && pcSize !== undefined && pcSize !== null) styles['--band-pattern-size-pc'] = `${pcSize}${pcSizeUnit}`;
  if (pcMixBlendMode) styles['--band-pattern-blend-mode-pc'] = pcMixBlendMode;

  return styles;
};

/**
 * edit.js用: バンドパターンスタイル（通常）
 * PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBandPatternStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.bandPatternV2;
  if (!data) return {};
  const styles = {};

  // プレビューデバイスの値を取得（継承付き）
  const type = getV2ValueWithInheritance(data, previewDevice, "type", '');
  const color = getV2ValueWithInheritance(data, previewDevice, "color", '');
  const opacity = getV2ValueWithInheritance(data, previewDevice, "opacity", '');
  const size = getV2ValueWithInheritance(data, previewDevice, "size", '');
  const sizeUnit = getV2ValueWithInheritance(data, previewDevice, "sizeUnit", "px");
  const mixBlendMode = getV2ValueWithInheritance(data, previewDevice, "mixBlendMode", '');

  if (type) styles['--band-pattern-type-pc'] = type;
  if (color) styles['--band-pattern-color-pc'] = color;
  if (opacity !== '' && opacity !== undefined) styles['--band-pattern-opacity-pc'] = opacity;
  if (size !== '' && size !== undefined && size !== null) styles['--band-pattern-size-pc'] = `${size}${sizeUnit}`;
  if (mixBlendMode) styles['--band-pattern-blend-mode-pc'] = mixBlendMode;

  return styles;
};

/**
 * save.js用: バンドパターンホバースタイル
 * PCのみ出力、MD/TB/SP用はPHP CSSのフォールバックに任せる
 */
export const getBandPatternHoverStylesV2 = (attributes) => {
  const data = attributes.bandPatternV2Hover;
  const normalData = attributes.bandPatternV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal (PC only)
  const getHoverValue = (key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, 'pc', key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, 'pc', key, defaultVal);
  };

  // Get PC values only
  const pcType = getHoverValue("type", '');
  const pcColor = getHoverValue("color", '');
  const pcOpacity = getHoverValue("opacity", '');
  const pcSize = getHoverValue("size", '');
  const pcSizeUnit = getHoverValue("sizeUnit", "px");
  const pcMixBlendMode = getHoverValue("mixBlendMode", '');

  if (pcType) styles['--band-pattern-type-pc-hover'] = pcType;
  if (pcColor) styles['--band-pattern-color-pc-hover'] = pcColor;
  if (pcOpacity !== '' && pcOpacity !== undefined) styles['--band-pattern-opacity-pc-hover'] = pcOpacity;
  if (pcSize !== '' && pcSize !== undefined && pcSize !== null) styles['--band-pattern-size-pc-hover'] = `${pcSize}${pcSizeUnit}`;
  if (pcMixBlendMode) styles['--band-pattern-blend-mode-pc-hover'] = pcMixBlendMode;

  return styles;
};

/**
 * edit.js用: バンドパターンホバースタイル
 * PC変数のみ出力、値はプレビューデバイスに応じて変更
 * ホバー値がなければ通常値にフォールバック
 */
export const getBandPatternHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.bandPatternV2Hover;
  const normalData = attributes.bandPatternV2;
  if (!data && !normalData) return {};
  const styles = {};

  // Helper to get hover value with fallback to normal
  const getHoverValue = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  // プレビューデバイスの値を取得、PC変数名で出力
  const type = getHoverValue(previewDevice, "type", '');
  const color = getHoverValue(previewDevice, "color", '');
  const opacity = getHoverValue(previewDevice, "opacity", '');
  const size = getHoverValue(previewDevice, "size", '');
  const sizeUnit = getHoverValue(previewDevice, "sizeUnit", "px");
  const mixBlendMode = getHoverValue(previewDevice, "mixBlendMode", '');

  if (type) styles['--band-pattern-type-pc-hover'] = type;
  if (color) styles['--band-pattern-color-pc-hover'] = color;
  if (opacity !== '' && opacity !== undefined) styles['--band-pattern-opacity-pc-hover'] = opacity;
  if (size !== '' && size !== undefined && size !== null) styles['--band-pattern-size-pc-hover'] = `${size}${sizeUnit}`;
  if (mixBlendMode) styles['--band-pattern-blend-mode-pc-hover'] = mixBlendMode;

  return styles;
};

/**
 * Band Opacity - save.js用: PCのみ出力
 */
export const getBandOpacityStylesV2 = (attributes, { skipDefaults = false } = {}) => {
  const data = attributes.bandOpacityV2;
  if (!data) return {};
  const styles = {};
  const pcValue = getV2ValueWithInheritance(data, 'pc', "value", 100);
  const pcMixBlendMode = getV2ValueWithInheritance(data, 'pc', "mixBlendMode", "normal");

  if (!skipDefaults || pcValue !== 100) {
    styles['--band-opacity-pc'] = String(pcValue / 100);
  }
  if (!skipDefaults || pcMixBlendMode !== "normal") {
    styles['--band-blend-mode-pc'] = pcMixBlendMode;
  }
  return styles;
};

/**
 * Band Opacity - edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBandOpacityStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.bandOpacityV2;
  if (!data) return {};
  const styles = {};
  const value = getV2ValueWithInheritance(data, previewDevice, "value", 100);
  const mixBlendMode = getV2ValueWithInheritance(data, previewDevice, "mixBlendMode", "normal");

  // デフォルト値は省略
  if (value !== 100) {
    styles['--band-opacity-pc'] = String(value / 100);
  }
  if (mixBlendMode !== "normal") {
    styles['--band-blend-mode-pc'] = mixBlendMode;
  }
  return styles;
};

/**
 * Band Opacity Hover - save.js用: PCのみ出力
 */
export const getBandOpacityHoverStylesV2 = (attributes, { skipDefaults = false } = {}) => {
  const data = attributes.bandOpacityV2Hover;
  const normalData = attributes.bandOpacityV2;
  if (!data && !normalData) return {};
  const styles = {};

  const getHoverValueWithInheritance = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  const pcValue = getHoverValueWithInheritance('pc', "value", 100);
  const pcMixBlendMode = getHoverValueWithInheritance('pc', "mixBlendMode", "normal");

  if (!skipDefaults || pcValue !== 100) {
    styles['--band-opacity-pc-hover'] = String(pcValue / 100);
  }
  if (!skipDefaults || pcMixBlendMode !== "normal") {
    styles['--band-blend-mode-pc-hover'] = pcMixBlendMode;
  }
  return styles;
};

/**
 * Band Opacity Hover - edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBandOpacityHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.bandOpacityV2Hover;
  const normalData = attributes.bandOpacityV2;
  if (!data && !normalData) return {};
  const styles = {};

  const getHoverValueWithInheritance = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  const value = getHoverValueWithInheritance(previewDevice, "value", 100);
  const mixBlendMode = getHoverValueWithInheritance(previewDevice, "mixBlendMode", "normal");

  // デフォルト値は省略
  if (value !== 100) {
    styles['--band-opacity-pc-hover'] = String(value / 100);
  }
  if (mixBlendMode !== "normal") {
    styles['--band-blend-mode-pc-hover'] = mixBlendMode;
  }
  return styles;
};

/**
 * Band Transform - save.js用: PCのみ出力
 */
export const getBandTransformStylesV2 = (attributes) => {
  const data = attributes.bandTransformV2;
  if (!data) return {};
  const styles = {};
  const pcSkewX = getV2ValueWithInheritance(data, 'pc', "skewX", 0);
  const pcSkewY = getV2ValueWithInheritance(data, 'pc', "skewY", 0);

  styles['--band-skew-x-pc'] = `${pcSkewX}deg`;
  styles['--band-skew-y-pc'] = `${pcSkewY}deg`;
  return styles;
};

/**
 * Band Transform - edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBandTransformStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.bandTransformV2;
  if (!data) return {};
  const styles = {};
  const skewX = getV2ValueWithInheritance(data, previewDevice, "skewX", 0);
  const skewY = getV2ValueWithInheritance(data, previewDevice, "skewY", 0);

  styles['--band-skew-x-pc'] = `${skewX}deg`;
  styles['--band-skew-y-pc'] = `${skewY}deg`;
  return styles;
};

/**
 * Band Transform Hover - save.js用: PCのみ出力
 */
export const getBandTransformHoverStylesV2 = (attributes) => {
  const data = attributes.bandTransformV2Hover;
  const normalData = attributes.bandTransformV2;
  if (!data && !normalData) return {};
  const styles = {};

  const getHoverValueWithInheritance = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  const pcSkewX = getHoverValueWithInheritance('pc', "skewX", 0);
  const pcSkewY = getHoverValueWithInheritance('pc', "skewY", 0);

  styles['--band-skew-x-pc-hover'] = `${pcSkewX}deg`;
  styles['--band-skew-y-pc-hover'] = `${pcSkewY}deg`;
  return styles;
};

/**
 * Band Transform Hover - edit.js用: PC変数のみ出力、値はプレビューデバイスに応じて変更
 */
export const getBandTransformHoverStylesV2ForEditor = (attributes, previewDevice = 'pc') => {
  const data = attributes.bandTransformV2Hover;
  const normalData = attributes.bandTransformV2;
  if (!data && !normalData) return {};
  const styles = {};

  const getHoverValueWithInheritance = (bp, key, defaultVal) => {
    const hoverVal = getV2ValueWithInheritance(data, bp, key, '');
    if (hoverVal !== '' && hoverVal !== undefined && hoverVal !== null) return hoverVal;
    return getV2ValueWithInheritance(normalData, bp, key, defaultVal);
  };

  const skewX = getHoverValueWithInheritance(previewDevice, "skewX", 0);
  const skewY = getHoverValueWithInheritance(previewDevice, "skewY", 0);

  styles['--band-skew-x-pc-hover'] = `${skewX}deg`;
  styles['--band-skew-y-pc-hover'] = `${skewY}deg`;
  return styles;
};
