Files

51 KiB

Revolut.Me PayPal.Me ko_fi buymecoffee patreon

Home Assistant Batch 6 Collection.

Other collections? watch these YouTube videos for more cards and instructions: Batch 1 | Batch 2 | Batch 3 | Batch 4 | Batch 5


Note

If you are using the Sections view type, you may need to set rows to around 1.5 for the card, otherwise the card may appear compressed.

grid_options:
  rows: 1.5

Cards:

665270527-ae6cccdf-0a74-4f4f-b61f-e893fa04d808
Presence sensor card
type: custom:button-card
entity: binary_sensor.aqara_presence_fp300_presence
name: Living Room
show_state: false
show_label: true
show_icon: false
variables:
  distance: sensor.aqara_presence_fp300_target_distance
  show_distance: true
  range: number.aqara_presence_fp300_detection_range
  show_range: true
  max_supported_limit: 6
  zone_steps: 24
  track_button: button.aqara_presence_fp300_track_target_distance
  show_track_button: true
  temp: sensor.aqara_presence_fp300_temperature
  humidity: sensor.aqara_presence_fp300_humidity
  lux: sensor.aqara_presence_fp300_illuminance
  show_environment: true
  temp_low: 18
  temp_mid: 23
  temp_high: 27
  hum_low: 30
  hum_high: 60
  lux_min: 50
  lux_max: 400
  size_shape: 75px
  size_card_height: 125px
  font_primary: 15px
  font_secondary: 12px
  font_badge: 10px
styles:
  card:
    - --config-shape-size: '[[[ return variables.size_shape ]]]'
    - --config-card-height: >
        [[[ return variables.show_range !== false ? variables.size_card_height :
        '99px'; ]]]
    - --config-font-primary: '[[[ return variables.font_primary ]]]'
    - --config-font-secondary: '[[[ return variables.font_secondary ]]]'
    - --config-font-badge: '[[[ return variables.font_badge ]]]'
    - height: var(--config-card-height) !important
    - padding: 0px !important
    - overflow: hidden
    - position: relative
  grid:
    - padding: 12px 16px
    - height: 100%
    - box-sizing: border-box
    - grid-template-areas: '"radar n" "radar l"'
    - grid-template-columns: var(--config-shape-size) 1fr
    - grid-template-rows: auto auto
    - align-content: start
    - gap: 0px 14px
    - position: relative
    - z-index: 2
  name:
    - justify-self: start
    - font-size: var(--config-font-primary)
    - font-weight: 500
    - align-self: end
    - margin-bottom: 2px
    - position: relative
    - color: var(--primary-text-color)
  label:
    - justify-self: start
    - font-size: var(--config-font-secondary)
    - opacity: 0.7
    - align-self: start
    - margin-top: 2px
    - position: relative
    - color: var(--secondary-text-color)
  custom_fields:
    radar:
      - grid-area: radar
      - justify-self: start
      - width: var(--config-shape-size)
      - height: var(--config-shape-size)
      - border-radius: 50%
      - border: 1px solid rgba(128, 128, 128, 0.15)
      - background: rgba(128, 128, 128, 0.05)
      - position: relative
      - overflow: hidden
      - box-shadow: inset 0 2px 8px rgba(0,0,0,0.1)
    badge1:
      - position: absolute
      - top: 12px
      - right: |
          [[[
            let btn_valid = variables.show_track_button !== false && variables.track_button && states[variables.track_button] && states[variables.track_button].state !== 'unknown' && states[variables.track_button].state !== 'unavailable';
            return btn_valid ? '46px' : '12px';
          ]]]
      - transition: right 0.3s ease-out
      - padding: 4px 10px
      - font-size: var(--config-font-badge)
      - letter-spacing: 0.5px
      - white-space: nowrap
      - font-weight: 600
      - text-transform: uppercase
      - z-index: 5
    badge2:
      - position: absolute
      - top: 45px
      - right: 12px
      - padding: 4px 10px
      - font-size: var(--config-font-badge)
      - letter-spacing: 0.5px
      - white-space: nowrap
      - opacity: 0.9
      - font-weight: 500
      - z-index: 5
    track_button:
      - position: absolute
      - top: 11px
      - right: 12px
      - z-index: 10
      - display: |
          [[[
            let btn_valid = variables.show_track_button !== false && variables.track_button && states[variables.track_button] && states[variables.track_button].state !== 'unknown' && states[variables.track_button].state !== 'unavailable';
            return btn_valid ? 'block' : 'none';
          ]]]
    zone_map:
      - position: absolute
      - bottom: 0
      - left: 0
      - width: 100%
      - height: 42px
      - z-index: 1
tap_action:
  action: more-info
label: |
  [[[ 
    if (!entity) return 'Entity Setup Required';
    
    let range_valid = variables.show_range !== false && variables.range && states[variables.range] && states[variables.range].state !== 'unknown' && states[variables.range].state !== 'unavailable';
    if (!range_valid) return '\u00A0';
    
    let max_l = parseFloat(variables.max_supported_limit) || 6.0;
    let bm = parseInt(states[variables.range].state);
    let highest_zone = -1;
    if (!isNaN(bm)) {
      for(let i=23; i>=0; i--) { if((bm & (1<<i)) !== 0) { highest_zone = i; break; } }
    }
    let limit = highest_zone >= 0 ? (highest_zone + 1) * 0.25 : max_l;
    return `Zone Limit: ${limit.toFixed(1)}m`; 
  ]]]
custom_fields:
  badge1: ' '
  badge2: ' '
  track_button:
    card:
      type: custom:button-card
      entity: '[[[ return variables.track_button ]]]'
      icon: mdi:crosshairs-gps
      show_name: false
      show_state: false
      styles:
        card:
          - width: 26px
          - height: 26px
          - border-radius: 50%
          - background: rgba(128, 128, 128, 0.1)
          - border: 1px solid rgba(128, 128, 128, 0.2)
          - box-shadow: 0 2px 4px rgba(0,0,0,0.1)
          - display: flex
        icon:
          - width: 16px
          - color: var(--primary-text-color)
      tap_action:
        action: call-service
        service: button.press
        service_data:
          entity_id: '[[[ return variables.track_button ]]]'
  radar: |
    [[[
      let is_on = entity && entity.state === 'on';
      
      let dist_valid = variables.show_distance !== false && variables.distance && states[variables.distance] && states[variables.distance].state !== 'unknown' && states[variables.distance].state !== 'unavailable';
      let safe_dist = dist_valid ? parseFloat(states[variables.distance].state) : 0;
      
      let range_valid = variables.show_range !== false && variables.range && states[variables.range] && states[variables.range].state !== 'unknown' && states[variables.range].state !== 'unavailable';
      let bm = range_valid ? parseInt(states[variables.range].state) : 0;
      
      let max_r = parseFloat(variables.max_supported_limit) || 6.0;
      let highest_zone = -1;
      if (range_valid && !isNaN(bm)) {
        for(let i=23; i>=0; i--) { if((bm & (1<<i)) !== 0) { highest_zone = i; break; } }
      }
      let range_val = range_valid ? (highest_zone >= 0 ? (highest_zone + 1) * 0.25 : max_r) : max_r;
      
      if (safe_dist > max_r) safe_dist = max_r;
      
      let raw_zone = Math.floor(safe_dist / 0.25);
      let is_zone_valid = range_valid ? ((bm & (1 << raw_zone)) !== 0) : true;
      
      let max_svg = 47.5;
      let range_pct = (range_val / max_r) * max_svg;
      let dist_pct = dist_valid ? ((safe_dist / max_r) * max_svg) : 0;
      
      let c_rgb = is_on ? '0, 229, 255' : '158, 158, 158'; 
      let t_rgb = is_zone_valid ? c_rgb : '255, 82, 82';   
      let stroke_color = 'rgba(128,128,128,0.2)';
      
      return `
        <svg viewBox="0 0 100 100" style="position: absolute; inset: 0; width: 100%; height: 100%; z-index: 2; pointer-events: none;">
          <circle cx="50" cy="50" r="${max_svg}" fill="none" stroke="${stroke_color}" stroke-width="0.5" />
          <circle cx="50" cy="50" r="${max_svg * 0.75}" fill="none" stroke="${stroke_color}" stroke-width="0.5" />
          <circle cx="50" cy="50" r="${max_svg * 0.50}" fill="none" stroke="${stroke_color}" stroke-width="0.5" />
          <circle cx="50" cy="50" r="${max_svg * 0.25}" fill="none" stroke="${stroke_color}" stroke-width="0.5" />
          <path d="M 50 ${50-max_svg} L 50 ${50+max_svg} M ${50-max_svg} 50 L ${50+max_svg} 50" stroke="${stroke_color}" stroke-width="0.5" />
          
          <circle cx="50" cy="50" r="${range_pct}" fill="rgba(${c_rgb}, 0.05)" stroke="rgba(${c_rgb}, 0.3)" stroke-width="0.75" stroke-dasharray="2 2" style="transition: r 0.5s ease;" />
          
          ${is_on && dist_valid ? `
            <circle cx="50" cy="50" r="${dist_pct}" fill="none" stroke="rgba(${t_rgb}, 0.6)" stroke-width="0.5" style="transition: r 0.3s ease-out, stroke 0.3s ease;" />
            <circle cx="50" cy="${50 - dist_pct}" r="2.5" fill="#FFF" filter="drop-shadow(0 0 3px rgba(${t_rgb}, 1))" style="transition: cy 0.3s ease-out;" />
          ` : ''}
          <circle cx="50" cy="50" r="1.5" fill="var(--primary-text-color)" opacity="0.5" />
        </svg>
        
        ${is_on ? `
          <div style="position: absolute; inset: 0; border-radius: 50%; clip-path: circle(${range_pct}% at 50% 50%); transition: clip-path 0.5s ease; z-index: 1;">
            <div style="width: 100%; height: 100%; background: conic-gradient(from 0deg, transparent 70%, rgba(${c_rgb}, 0.3) 100%); animation: radar-spin 2.5s linear infinite;"></div>
          </div>
        ` : ''}
      `;
    ]]]
  zone_map: |
    [[[
      let range_valid = variables.show_range !== false && variables.range && states[variables.range] && states[variables.range].state !== 'unknown' && states[variables.range].state !== 'unavailable';
      if (!range_valid) return '';
      
      let is_on = entity && entity.state === 'on';
      
      let dist_valid = variables.show_distance !== false && variables.distance && states[variables.distance] && states[variables.distance].state !== 'unknown' && states[variables.distance].state !== 'unavailable';
      let safe_dist = dist_valid ? parseFloat(states[variables.distance].state) : 0;
      
      let bm = parseInt(states[variables.range].state);
      if(isNaN(bm)) bm = 0;
      
      let max_r = parseFloat(variables.max_supported_limit) || 6.0;
      let visual_steps = parseInt(variables.zone_steps) || 12;
      
      safe_dist = Math.max(0, Math.min(safe_dist, max_r - 0.001));
      let step_size = max_r / visual_steps;
      let tracked_visual_step = Math.floor(safe_dist / step_size);
      
      let total_raw_zones = Math.ceil(max_r / 0.25); 
      let raw_per_step = total_raw_zones / visual_steps;
      let visual_array = Array(visual_steps).fill(false);
      
      for(let i=0; i<total_raw_zones; i++) {
        if ((bm & (1 << i)) !== 0) {
          let v_idx = Math.floor(i / raw_per_step);
          if (v_idx >= 0 && v_idx < visual_steps) visual_array[v_idx] = true;
        }
      }
      
      let zone_bars = `<div style="display: flex; gap: 2px; height: 16px; width: 100%; align-items: flex-end;">`;
      
      for(let i=0; i<visual_steps; i++) {
        let is_tracked = is_on && dist_valid && (i === tracked_visual_step);
        let is_active = visual_array[i]; 
        
        let h = '15%'; 
        let c = 'rgba(128, 128, 128, 0.2)'; 
        let s = 'z-index: 1;';

        if (is_tracked) {
          h = '100%';
          let raw_zone = Math.floor(safe_dist / 0.25);
          if ((bm & (1 << raw_zone)) !== 0) {
            c = '#00E5FF';
            s = 'box-shadow: 0 0 8px #00E5FF; z-index: 2;';
          } else {
            c = '#FF5252'; 
            s = 'box-shadow: 0 0 8px #FF5252; z-index: 2;';
          }
        } else if (is_active) {
          h = is_on ? '60%' : '35%'; 
          c = is_on ? 'rgba(0, 229, 255, 0.35)' : 'rgba(128, 128, 128, 0.4)';
        }
        
        zone_bars += `<div style="flex: 1; background: ${c}; height: ${h}; border-radius: 1px 1px 0 0; transition: height 0.3s ease, background 0.3s ease; ${s}"></div>`;
      }
      zone_bars += `</div>`;
      
      let l1 = (max_r * 0.25).toFixed(1) + 'm';
      let l2 = (max_r * 0.50).toFixed(1) + 'm';
      let l3 = (max_r * 0.75).toFixed(1) + 'm';
      let l4 = max_r.toFixed(0) + 'm';
      
      let labels = `<div style="display: flex; justify-content: space-between; font-size: 9px; color: var(--secondary-text-color, rgba(150,150,150,0.8)); font-weight: 600; margin-bottom: 4px; padding: 0 2px; letter-spacing: 0.5px;">
        <span>0m</span><span>${l1}</span><span>${l2}</span><span>${l3}</span><span>${l4}</span>
      </div>`;
      
      return `<div style="display: flex; flex-direction: column; width: 100%; height: 100%; justify-content: flex-end; padding: 0 16px 8px 16px; box-sizing: border-box;">${labels}${zone_bars}</div>`;
    ]]]
extra_styles: |
  [[[
    let is_on = entity && entity.state === 'on';
    
    let dist_valid = variables.show_distance !== false && variables.distance && states[variables.distance] && states[variables.distance].state !== 'unknown' && states[variables.distance].state !== 'unavailable' && !isNaN(parseFloat(states[variables.distance].state));
    let safe_dist = dist_valid ? parseFloat(states[variables.distance].state) : 0;
    if (safe_dist > variables.max_supported_limit) safe_dist = variables.max_supported_limit;
    
    let range_valid = variables.show_range !== false && variables.range && states[variables.range] && states[variables.range].state !== 'unknown' && states[variables.range].state !== 'unavailable' && !isNaN(parseInt(states[variables.range].state));
    let bm = range_valid ? parseInt(states[variables.range].state) : 0;
    
    let raw_zone = Math.floor(safe_dist / 0.25);
    let is_zone_valid = range_valid ? ((bm & (1 << raw_zone)) !== 0) : true;
    
    let status_text = 'CLEAR';
    if (!entity) {
      status_text = 'SETUP REQ';
    } else if (is_on) {
      if (dist_valid) {
        status_text = `PRESENCE • ${safe_dist.toFixed(1)}m`;
      } else {
        status_text = 'PRESENCE';
      }
    }
    
    let color = is_on ? (is_zone_valid ? '0, 229, 255' : '255, 82, 82') : '158, 158, 158'; 
    
    let env_parts = [];
    let c_temp = '128, 128, 128';
    let c_hum  = '128, 128, 128';
    let c_lux  = '128, 128, 128';
    
    if (variables.show_environment !== false && variables.temp && states[variables.temp]) {
      let st = states[variables.temp].state;
      if (st !== 'unknown' && st !== 'unavailable') {
        let v = parseFloat(st);
        if (!isNaN(v)) {
          env_parts.push(`${v.toFixed(1)}°C`);
          if (v < variables.temp_low) c_temp = '66, 165, 245';
          else if (v < variables.temp_mid) c_temp = '255, 235, 59';
          else if (v < variables.temp_high) c_temp = '255, 167, 38';
          else c_temp = '239, 83, 80';
        }
      }
    }
    
    if (variables.show_environment !== false && variables.humidity && states[variables.humidity]) {
      let st = states[variables.humidity].state;
      if (st !== 'unknown' && st !== 'unavailable') {
        let v = parseFloat(st);
        if (!isNaN(v)) {
          env_parts.push(`${v.toFixed(0)}%`);
          if (v < variables.hum_low) c_hum = '255, 167, 38';
          else if (v <= variables.hum_high) c_hum = '66, 165, 245';
          else c_hum = '255, 167, 38';
        }
      }
    }
    
    if (variables.show_environment !== false && variables.lux && states[variables.lux]) {
      let st = states[variables.lux].state;
      if (st !== 'unknown' && st !== 'unavailable') {
        let v = parseFloat(st);
        if (!isNaN(v)) {
          env_parts.push(`${v.toFixed(0)}lx`);
          c_lux = v < variables.lux_min ? '120, 144, 156' : (v > variables.lux_max ? '255, 235, 59' : '212, 225, 87');
        }
      }
    }
    
    let b2_text = env_parts.join(' • ');
    let display_b2 = env_parts.length > 0 ? 'block' : 'none';
    let bg_gradient = `linear-gradient(90deg, rgba(${c_temp}, 0.15) 0%, rgba(${c_hum}, 0.15) 50%, rgba(${c_lux}, 0.2) 100%)`;
    
    return `
      #card {
        --appliance-color: ${color};
      }
      
      #badge1 {
        display: block;
        background: rgba(var(--appliance-color), 0.07);
        color: var(--primary-text-color);
        border-top: 1px solid var(--divider-color, rgba(128,128,128,0.2));
        border-bottom: 1px solid var(--divider-color, rgba(128,128,128,0.2));
        border-left: 2.5px solid rgb(var(--appliance-color));
        border-radius: 6px !important;
      }
      #badge1::before { content: "${status_text}"; }
      
      #badge2 {
        display: ${display_b2};
        background: ${bg_gradient};
        color: var(--primary-text-color);
        border-top: 1px solid var(--divider-color, rgba(128,128,128,0.2));
        border-bottom: 1px solid var(--divider-color, rgba(128,128,128,0.2));
        border-left: 2.5px solid rgb(${c_temp});
        border-right: 2.5px solid rgb(${c_lux});
        border-radius: 6px !important;
      }
      #badge2::before { content: "${b2_text}"; }
      
      @keyframes radar-spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
      }
    `;
  ]]]


665270583-e99d9c97-0201-489e-99b3-9506c5fa2cb7
Smoke detector card
type: custom:button-card
entity: binary_sensor.aqara_smoke_detector_smoke
name: Smoke Detector
show_state: false
show_label: true
variables:
  sensor_density: sensor.aqara_smoke_detector_smoke_density
  sensor_battery: sensor.aqara_smoke_detector_battery
  show_bar: false
  theme_idle_colored: false
  heartbeat_color: '#4caf50'
  heartbeat_interval: 3s
  batt_red: 20
  batt_orange: 40
  batt_yellow: 70
  dens_yellow: 0.1
  dens_orange: 0.3
  dens_red: 0.5
  size_icon: 45px
  size_shape: 65px
  size_card_height: 95px
  font_primary: 15px
  font_secondary: 12px
  font_badge: 10px
styles:
  card:
    - --config-icon-size: '[[[ return variables.size_icon ]]]'
    - --config-shape-size: '[[[ return variables.size_shape ]]]'
    - --config-card-height: '[[[ return variables.size_card_height ]]]'
    - --config-font-primary: '[[[ return variables.font_primary ]]]'
    - --config-font-secondary: '[[[ return variables.font_secondary ]]]'
    - --config-font-badge: '[[[ return variables.font_badge ]]]'
    - height: var(--config-card-height) !important
    - padding: 0px !important
    - overflow: hidden
    - position: relative
    - transition: background 0.5s ease
  grid:
    - padding: 12px 16px
    - height: 100%
    - box-sizing: border-box
    - grid-template-areas: '"i n" "i l"'
    - grid-template-columns: var(--config-shape-size) 1fr
    - grid-template-rows: auto auto
    - align-content: center
    - gap: 0px 12px
    - position: relative
    - z-index: 2
  icon:
    - width: var(--config-icon-size)
    - height: var(--config-icon-size)
    - color: var(--primary-text-color)
    - z-index: 3
    - animation: var(--anim-icon-shake)
    - transform-origin: center center
    - will-change: transform
  img_cell:
    - width: var(--config-shape-size)
    - height: var(--config-shape-size)
    - border-radius: 50%
    - border: 1px solid var(--divider-color, rgba(128,128,128,0.2)) !important
    - background: rgba(var(--appliance-color), 0.1) !important
    - position: relative
    - overflow: visible !important
    - justify-self: start
    - z-index: 2
  name:
    - justify-self: start
    - font-size: var(--config-font-primary)
    - font-weight: 500
    - align-self: end
    - margin-bottom: 2px
    - position: relative
    - z-index: 3
  label:
    - justify-self: start
    - font-size: var(--config-font-secondary)
    - opacity: 0.7
    - align-self: start
    - margin-top: 2px
    - position: relative
    - z-index: 3
  custom_fields:
    bg_smoke:
      - position: absolute
      - inset: 0
      - z-index: 0
      - pointer-events: none
      - display: var(--display-smoke)
    heartbeat:
      - position: absolute
      - top: 10px
      - left: 10px
      - width: 6px
      - height: 6px
      - border-radius: 50%
      - background: var(--hb-color)
      - box-shadow: 0 0 6px var(--hb-color)
      - display: var(--display-heartbeat)
      - animation: hardware-blink var(--hb-interval) infinite
      - z-index: 5
    badge1:
      - position: absolute
      - top: 10px
      - right: 10px
      - background: rgba(var(--appliance-color), 0.15)
      - color: var(--primary-text-color)
      - border-top: 1px solid rgba(128,128,128, 0.2)
      - border-bottom: 1px solid rgba(128,128,128, 0.2)
      - border-left: 2.5px solid rgb(var(--appliance-color))
      - padding: 2px 10px
      - border-radius: 6px
      - font-size: var(--config-font-badge)
      - font-weight: 600
      - text-transform: uppercase
      - letter-spacing: 0.5px
      - white-space: nowrap
      - z-index: 5
    badge2:
      - position: absolute
      - top: 38px
      - right: 10px
      - color: var(--primary-text-color)
      - border-top: 1px solid rgba(128,128,128, 0.2)
      - border-bottom: 1px solid rgba(128,128,128, 0.2)
      - padding: 4px 8px
      - font-size: 10px
      - letter-spacing: 0.5px
      - white-space: nowrap
      - opacity: 0.9
      - text-transform: uppercase
      - font-weight: 500
      - border-radius: 6px
      - display: var(--display-badge2)
      - z-index: 5
    bar:
      - position: absolute
      - bottom: 0
      - left: 0
      - height: 3.5px
      - width: var(--appliance-level)
      - background: rgb(var(--appliance-color))
      - box-shadow: 0 0 8px rgb(var(--appliance-color))
      - transition: width 0.5s ease
      - display: var(--display-bar)
      - z-index: 5
tap_action:
  action: more-info
label: |
  [[[ 
    let ent_smoke = entity ? entity.entity_id : null;
    if (!ent_smoke || !states[ent_smoke]) return 'Entity Setup Required';
    return states[ent_smoke].state === 'on' ? 'Smoke Detected' : 'Monitoring';
  ]]]
icon: mdi:smoke-detector
custom_fields:
  badge1: ' '
  badge2: ' '
  bar: ' '
  heartbeat: ' '
  bg_smoke: |
    [[[
      return `
        <div class="smoke-plume plume-1" style="left: 10%; width: 70px; height: 70px; animation-delay: 0s;"></div>
        <div class="smoke-plume plume-2" style="left: 45%; width: 90px; height: 90px; animation-delay: 1.2s;"></div>
        <div class="smoke-plume plume-3" style="left: 20%; width: 60px; height: 60px; animation-delay: 2.5s;"></div>
        <div class="smoke-plume plume-4" style="left: 35%; width: 85px; height: 85px; animation-delay: 3.8s;"></div>
      `;
    ]]]
extra_styles: |
  [[[
    let ent_smoke = entity ? entity.entity_id : null;
    let ent_bat = variables.sensor_battery;
    let ent_den = variables.sensor_density;
    
    let is_smoke = ent_smoke && states[ent_smoke] && states[ent_smoke].state === 'on';
    let raw_bat = states[ent_bat] ? parseFloat(states[ent_bat].state) : NaN;
    let raw_den = states[ent_den] ? parseFloat(states[ent_den].state) : NaN;
    
    let theme_colored = variables.theme_idle_colored !== undefined ? variables.theme_idle_colored : false;
    let status = 'CLEAR';
    let color = theme_colored ? '0, 229, 255' : '158, 158, 158'; 
    
    let anim_shake = 'none';
    let anim_strobe = 'none';
    let display_smoke = 'none';
    let display_heartbeat = 'block';

    if (is_smoke) {
        status = 'SMOKE ALARM';
        color = '244, 67, 54'; 
        anim_shake = 'buzzer-shake 0.1s linear infinite';
        anim_strobe = 'strobe-fade 0.8s ease-in-out infinite';
        display_smoke = 'block';
        display_heartbeat = 'none'; 
    } 

    let progress = isNaN(raw_bat) ? 100 : Math.max(0, Math.min(100, raw_bat));
    let display_bar = (variables.show_bar !== false && !isNaN(raw_bat)) ? 'block' : 'none';
    
    let c_bat = '76, 175, 80'; 
    if (!isNaN(raw_bat)) {
        if (raw_bat <= (variables.batt_red || 20)) { c_bat = '244, 67, 54'; }
        else if (raw_bat <= (variables.batt_orange || 40)) { c_bat = '255, 152, 0'; }
        else if (raw_bat <= (variables.batt_yellow || 70)) { c_bat = '255, 235, 59'; }
    }

    let c_den = '76, 175, 80'; 
    if (!isNaN(raw_den)) {
        if (raw_den >= (variables.dens_red || 0.5)) { c_den = '244, 67, 54'; }
        else if (raw_den >= (variables.dens_orange || 0.3)) { c_den = '255, 152, 0'; }
        else if (raw_den >= (variables.dens_yellow || 0.1)) { c_den = '255, 235, 59'; }
    }

    let b2_arr = [];
    let b2_text = '';
    if (!isNaN(raw_bat)) b2_arr.push(`Bat ${Math.round(raw_bat)}%`);
    if (!isNaN(raw_den)) b2_arr.push(`Den ${raw_den}`);
    
    let display_badge2 = b2_arr.length > 0 ? 'block' : 'none';
    if (b2_arr.length > 0) {
        b2_text = b2_arr.join(' • ');
    }
    
    let bg_badge2 = 'rgba(128,128,128,0.05)';
    let b2_left = '1px solid rgba(128,128,128,0.2)';
    let b2_right = '1px solid rgba(128,128,128,0.2)';

    if (!isNaN(raw_bat) && !isNaN(raw_den)) {
        bg_badge2 = `linear-gradient(90deg, rgba(${c_bat}, 0.15) 30%, rgba(${c_den}, 0.2) 75%)`;
        b2_left = `2.5px solid rgb(${c_bat})`;
        b2_right = `2.5px solid rgb(${c_den})`;
    } else if (!isNaN(raw_bat)) {
        bg_badge2 = `rgba(${c_bat}, 0.15)`;
        b2_left = `2.5px solid rgb(${c_bat})`;
    } else if (!isNaN(raw_den)) {
        bg_badge2 = `rgba(${c_den}, 0.15)`;
        b2_right = `2.5px solid rgb(${c_den})`;
    }

    return `
      #card {
        --appliance-color: ${color};
        --appliance-level: ${progress}%;
        --anim-icon-shake: ${anim_shake};
        --anim-cell-strobe: ${anim_strobe};
        --display-smoke: ${display_smoke};
        --display-bar: ${display_bar};
        --display-heartbeat: ${display_heartbeat};
        --display-badge2: ${display_badge2};
        --hb-color: ${variables.heartbeat_color || '#4caf50'};
        --hb-interval: ${variables.heartbeat_interval || '5s'};
      }
      
      #badge1::before { content: "${status}"; }
      
      #badge2 {
        background: ${bg_badge2};
        border-left: ${b2_left};
        border-right: ${b2_right};
      }
      
      #badge2::before { content: "${b2_text}"; }
      
      #img-cell::before {
        content: '';
        position: absolute;
        inset: 0;
        border-radius: 50%;
        background-color: rgba(var(--appliance-color), 0.5);
        box-shadow: 0 0 20px rgba(var(--appliance-color), 0.6);
        opacity: 0;
        animation: var(--anim-cell-strobe);
        pointer-events: none;
        will-change: opacity;
      }

      .smoke-plume {
        position: absolute;
        bottom: -40px;
        background: radial-gradient(circle at center, color-mix(in srgb, var(--primary-text-color) 40%, transparent) 0%, transparent 65%);
        border-radius: 50%;
        opacity: 0;
        will-change: transform, opacity;
      }

      .plume-1 { animation: drift-1 4s ease-in infinite; }
      .plume-2 { animation: drift-2 4.5s ease-in infinite; }
      .plume-3 { animation: drift-3 5s ease-in infinite; }
      .plume-4 { animation: drift-1 5.5s ease-in infinite; }

      @keyframes buzzer-shake {
        0%, 100% { transform: translate3d(0, 0, 0); }
        25% { transform: translate3d(-1px, 0.5px, 0) rotate(-1.5deg); }
        75% { transform: translate3d(1px, -0.5px, 0) rotate(1.5deg); }
      }
      
      @keyframes strobe-fade {
        0%, 100% { opacity: 0; }
        50% { opacity: 1; }
      }
      
      @keyframes hardware-blink {
        0%, 8%, 100% { opacity: 0; }
        4% { opacity: 1; }
      }

      @keyframes drift-1 {
        0% { transform: translate3d(0, 10px, 0) scale(0.5); opacity: 0; }
        30% { opacity: 0.7; }
        100% { transform: translate3d(-15px, -110px, 0) scale(2.8); opacity: 0; }
      }
      
      @keyframes drift-2 {
        0% { transform: translate3d(0, 10px, 0) scale(0.5); opacity: 0; }
        30% { opacity: 0.6; }
        100% { transform: translate3d(20px, -100px, 0) scale(3.2); opacity: 0; }
      }
      
      @keyframes drift-3 {
        0% { transform: translate3d(0, 10px, 0) scale(0.5); opacity: 0; }
        30% { opacity: 0.8; }
        100% { transform: translate3d(-5px, -120px, 0) scale(3.0); opacity: 0; }
      }
    `;
  ]]]


665270603-0e21a7c6-cfbb-47fd-8f92-ea5fa3a7038f
Liquid card (Water)
type: custom:button-card
entity: sensor.water_tank_level
name: Water Tank
show_icon: true
show_name: true
show_state: true
icon: mdi:water
variables:
  card_h: 150
  circle_size: 100
styles:
  card:
    - height: '[[[ return variables.card_h + ''px'' ]]]'
    - position: relative
    - overflow: hidden
    - background: transparent
    - box-shadow: var(--ha-card-box-shadow, none)
    - border-radius: var(--ha-card-border-radius, 12px)
    - border: |
        [[[
          let level = entity ? parseFloat(entity.state) || 0 : 0;
          let rgb = level <= 20 ? "150, 29, 29" : "29, 130, 150";
          return `1px solid rgba(${rgb}, 0.3)`;
        ]]]
  grid:
    - grid-template-areas: '"i" "s" "n"'
    - grid-template-columns: 1fr
    - grid-template-rows: min-content min-content min-content
    - height: 100%
    - align-content: center
    - justify-content: center
    - gap: '[[[ return (variables.circle_size * 0.02) + ''px'' ]]]'
  icon:
    - color: white
    - width: '[[[ return (variables.circle_size * 0.35) + ''px'' ]]]'
    - justify-self: center
    - filter: drop-shadow(0px 1px 3px rgba(0,0,0,0.8))
    - position: relative
    - z-index: 3
  state:
    - color: white
    - font-size: '[[[ return (variables.circle_size * 0.15) + ''px'' ]]]'
    - font-weight: bold
    - justify-self: center
    - text-shadow: 0px 1px 3px rgba(0,0,0,0.8)
    - position: relative
    - z-index: 3
  name:
    - color: white
    - font-size: '[[[ return (variables.circle_size * 0.10) + ''px'' ]]]'
    - justify-self: center
    - text-shadow: 0px 1px 3px rgba(0,0,0,0.8)
    - position: relative
    - z-index: 3
  custom_fields:
    glass_circle:
      - position: absolute
      - top: 50%
      - left: 50%
      - transform: translate(-50%, -50%)
      - width: '[[[ return variables.circle_size + ''px'' ]]]'
      - height: '[[[ return variables.circle_size + ''px'' ]]]'
      - border-radius: 50%
      - background: rgba(0, 0, 0, 0.25)
      - backdrop-filter: blur(6px)
      - -webkit-backdrop-filter: blur(6px)
      - border: 1px solid rgba(255, 255, 255, 0.15)
      - box-shadow: 0 4px 15px rgba(0,0,0,0.3)
      - z-index: 2
    back_wave:
      - position: absolute
      - inset: 0
      - z-index: 1
      - pointer-events: none
      - display: |-
          [[[ 
            let level = entity ? parseFloat(entity.state) || 0 : 0;
            return level <= 0 ? "none" : "block"; 
          ]]]
    front_wave:
      - position: absolute
      - inset: 0
      - z-index: 1
      - pointer-events: none
      - display: |-
          [[[ 
            let level = entity ? parseFloat(entity.state) || 0 : 0;
            return level <= 0 ? "none" : "block"; 
          ]]]
custom_fields:
  glass_circle: |
    [[[ return ``; ]]]
  back_wave: |
    [[[
      let level = entity ? parseFloat(entity.state) || 0 : 0;
      let rgb = level <= 20 ? "150, 29, 29" : "29, 130, 150";
      let color = `rgba(${rgb}, 0.6)`;
      
      /* Draw SVG path */
      let path = "M0 7.5 Q30 0 60 7.5 T120 7.5 L120 15 L0 15 Z";
      let svg = `<svg viewBox="0 0 120 15" style="width:120px; height:15px; display:block; flex-shrink:0;"><path d="${path}" fill="${color}"/></svg>`;
      
      /* Repeat the SVG 10 times */
      let wave_row = svg.repeat(10); 

      return `
        <div style="position:absolute; bottom:0; width:100%; height:calc(${level}% + 5px);">
          <div style="position:absolute; top:0; left:0; display:flex; animation:scroll-right 4s linear infinite;">
            ${wave_row}
          </div>
          <div style="position:absolute; top:14px; bottom:0; left:0; width:100%; background:${color};"></div>
        </div>
      `;
    ]]]
  front_wave: |
    [[[
      let level = entity ? parseFloat(entity.state) || 0 : 0;
      let rgb = level <= 20 ? "150, 29, 29" : "29, 130, 150";
      let color = `rgba(${rgb}, 1)`;
      
      /* Draw SVG path */
      let path = "M0 7.5 Q30 0 60 7.5 T120 7.5 L120 15 L0 15 Z";
      let svg = `<svg viewBox="0 0 120 15" style="width:120px; height:15px; display:block; flex-shrink:0;"><path d="${path}" fill="${color}"/></svg>`;

      /* Repeat the SVG 10 times */
      let wave_row = svg.repeat(10); 

      return `
        <div style="position:absolute; bottom:0; width:100%; height:${level}%;">
          <div style="position:absolute; top:0; left:0; display:flex; animation:scroll-left 3s linear infinite;">
            ${wave_row}
          </div>
          <div style="position:absolute; top:14px; bottom:0; left:0; width:100%; background:${color};"></div>
        </div>
      `;
    ]]]
extra_styles: |
  @keyframes scroll-left {
    0% { transform: translateX(0); }
    100% { transform: translateX(-120px); }
  }
  @keyframes scroll-right {
    0% { transform: translateX(-120px); }
    100% { transform: translateX(0); }
  }

Liquid card (Fuel)
type: custom:button-card
entity: sensor.fuel_tank_level
name: Fuel Tank
show_icon: true
show_name: true
show_state: true
icon: mdi:barrel
variables:
  card_h: 150
  circle_size: 100
styles:
  card:
    - height: '[[[ return variables.card_h + ''px'' ]]]'
    - position: relative
    - overflow: hidden
    - background: transparent
    - box-shadow: var(--ha-card-box-shadow, none)
    - border-radius: var(--ha-card-border-radius, 12px)
    - border: |
        [[[
          let level = entity ? parseFloat(entity.state) || 0 : 0;
          let rgb = level <= 20 ? "211, 47, 47" : "245, 124, 0";
          return `1px solid rgba(${rgb}, 0.3)`;
        ]]]
  grid:
    - grid-template-areas: '"i" "s" "n"'
    - grid-template-columns: 1fr
    - grid-template-rows: min-content min-content min-content
    - height: 100%
    - align-content: center
    - justify-content: center
    - gap: '[[[ return (variables.circle_size * 0.02) + ''px'' ]]]'
  icon:
    - color: white
    - width: '[[[ return (variables.circle_size * 0.35) + ''px'' ]]]'
    - justify-self: center
    - filter: drop-shadow(0px 1px 3px rgba(0,0,0,0.8))
    - position: relative
    - z-index: 3
  state:
    - color: white
    - font-size: '[[[ return (variables.circle_size * 0.15) + ''px'' ]]]'
    - font-weight: bold
    - justify-self: center
    - text-shadow: 0px 1px 3px rgba(0,0,0,0.8)
    - position: relative
    - z-index: 3
  name:
    - color: white
    - font-size: '[[[ return (variables.circle_size * 0.10) + ''px'' ]]]'
    - justify-self: center
    - text-shadow: 0px 1px 3px rgba(0,0,0,0.8)
    - position: relative
    - z-index: 3
  custom_fields:
    glass_circle:
      - position: absolute
      - top: 50%
      - left: 50%
      - transform: translate(-50%, -50%)
      - width: '[[[ return variables.circle_size + ''px'' ]]]'
      - height: '[[[ return variables.circle_size + ''px'' ]]]'
      - border-radius: 50%
      - background: rgba(0, 0, 0, 0.25)
      - backdrop-filter: blur(6px)
      - -webkit-backdrop-filter: blur(6px)
      - border: 1px solid rgba(255, 255, 255, 0.15)
      - box-shadow: 0 4px 15px rgba(0,0,0,0.3)
      - z-index: 2
    back_wave:
      - position: absolute
      - inset: 0
      - z-index: 1
      - pointer-events: none
      - display: >-
          [[[ return ((entity ? parseFloat(entity.state) || 0 : 0) <= 0) ?
          "none" : "block"; ]]]
    front_wave:
      - position: absolute
      - inset: 0
      - z-index: 1
      - pointer-events: none
      - display: >-
          [[[ return ((entity ? parseFloat(entity.state) || 0 : 0) <= 0) ?
          "none" : "block"; ]]]
custom_fields:
  glass_circle: |
    [[[ return ``; ]]]
  back_wave: |
    [[[
      let level = entity ? parseFloat(entity.state) || 0 : 0;
      let rgb = level <= 20 ? "211, 47, 47" : "245, 124, 0";
      let color = `rgba(${rgb}, 0.6)`;
      
      /* Draw SVG path */
      let path = "M0 7.5 Q30 0 60 7.5 T120 7.5 L120 15 L0 15 Z";
      let svg = `<svg viewBox="0 0 120 15" style="width:120px; height:15px; display:block; flex-shrink:0;"><path d="${path}" fill="${color}"/></svg>`;
      
      /* Repeat the SVG 10 times */
      let wave_row = svg.repeat(10); 

      return `
        <div style="position:absolute; bottom:0; width:100%; height:calc(${level}% + 5px);">
          <div style="position:absolute; top:0; left:0; display:flex; animation:scroll-right 5s linear infinite;">
            ${wave_row}
          </div>
          <div style="position:absolute; top:14px; bottom:0; left:0; width:100%; background:${color};"></div>
        </div>
      `;
    ]]]
  front_wave: |
    [[[
      let level = entity ? parseFloat(entity.state) || 0 : 0;
      let rgb = level <= 20 ? "211, 47, 47" : "245, 124, 0";
      let color = `rgba(${rgb}, 1)`;
      
      /* Draw SVG path */
      let path = "M0 7.5 Q30 0 60 7.5 T120 7.5 L120 15 L0 15 Z";
      let svg = `<svg viewBox="0 0 120 15" style="width:120px; height:15px; display:block; flex-shrink:0;"><path d="${path}" fill="${color}"/></svg>`;

      /* Repeat the SVG 10 times */
      let wave_row = svg.repeat(10); 

      return `
        <div style="position:absolute; bottom:0; width:100%; height:${level}%;">
          <div style="position:absolute; top:0; left:0; display:flex; animation:scroll-left 4s linear infinite;">
            ${wave_row}
          </div>
          <div style="position:absolute; top:14px; bottom:0; left:0; width:100%; background:${color};"></div>
        </div>
      `;
    ]]]
extra_styles: |
  @keyframes scroll-left {
    0% { transform: translateX(0); }
    100% { transform: translateX(-120px); }
  }
  @keyframes scroll-right {
    0% { transform: translateX(-120px); }
    100% { transform: translateX(0); }
  }

Liquid card (Battery/percentage)
type: custom:button-card
entity: sensor.anasbox_battery_level
name: Battery
show_icon: true
show_name: true
show_state: true
variables:
  card_h: 150
  circle_size: 110
  threshold_red: 20
  threshold_orange: 50
  threshold_green: 100
  charger_entity: binary_sensor.anasbox_is_charging
icon: |
  [[[
    if (entity && entity.attributes && entity.attributes.icon) return entity.attributes.icon;
    let level = entity && entity.state && !isNaN(entity.state) ? parseFloat(entity.state) : 0;
    let charger = variables.charger_entity && states[variables.charger_entity] ? states[variables.charger_entity] : null;
    let is_charging = charger ? ['on', 'charging', 'plugged'].includes(charger.state.toLowerCase()) : false;
    let rounded = Math.round(level / 10) * 10;
    if (is_charging) {
      if (rounded === 0) return "mdi:battery-charging-outline";
      return `mdi:battery-charging-${rounded}`;
    }
    if (rounded === 100) return "mdi:battery";
    if (rounded === 0) return "mdi:battery-outline";
    return `mdi:battery-${rounded}`;
  ]]]
styles:
  card:
    - height: '[[[ return variables.card_h + ''px'' ]]]'
    - position: relative
    - overflow: hidden
    - background: transparent
    - box-shadow: var(--ha-card-box-shadow, none)
    - border-radius: var(--ha-card-border-radius, 12px)
    - border: |
        [[[
          let level = entity && entity.state && !isNaN(entity.state) ? parseFloat(entity.state) : 0;
          let is_charging = variables.charger_entity && states[variables.charger_entity] ? ['on', 'charging', 'plugged'].includes(states[variables.charger_entity].state.toLowerCase()) : false;
          let rgb = "0, 255, 100";
          if (is_charging) rgb = "0, 255, 255";
          else if (level <= variables.threshold_red) rgb = "244, 67, 54";
          else if (level <= variables.threshold_orange) rgb = "255, 152, 0";
          return `1px solid rgba(${rgb}, 0.3)`;
        ]]]
  grid:
    - grid-template-areas: '"i" "s" "n"'
    - grid-template-columns: 1fr
    - grid-template-rows: min-content min-content min-content
    - height: 100%
    - align-content: center
    - justify-content: center
    - gap: '[[[ return (variables.circle_size * 0.02) + ''px'' ]]]'
  icon:
    - color: white
    - width: '[[[ return (variables.circle_size * 0.35) + ''px'' ]]]'
    - justify-self: center
    - filter: drop-shadow(0px 1px 3px rgba(0,0,0,0.8))
    - position: relative
    - z-index: 3
  state:
    - color: white
    - font-size: '[[[ return (variables.circle_size * 0.15) + ''px'' ]]]'
    - font-weight: bold
    - justify-self: center
    - text-shadow: 0px 1px 3px rgba(0,0,0,0.8)
    - position: relative
    - z-index: 3
  name:
    - color: white
    - font-size: '[[[ return (variables.circle_size * 0.10) + ''px'' ]]]'
    - justify-self: center
    - text-shadow: 0px 1px 3px rgba(0,0,0,0.8)
    - position: relative
    - z-index: 3
  custom_fields:
    glass_circle:
      - position: absolute
      - top: 50%
      - left: 50%
      - transform: translate(-50%, -50%)
      - width: '[[[ return variables.circle_size + ''px'' ]]]'
      - height: '[[[ return variables.circle_size + ''px'' ]]]'
      - border-radius: 50%
      - background: rgba(0, 0, 0, 0.25)
      - backdrop-filter: blur(6px)
      - -webkit-backdrop-filter: blur(6px)
      - border: 1px solid rgba(255, 255, 255, 0.15)
      - box-shadow: 0 4px 15px rgba(0,0,0,0.3)
      - z-index: 2
    back_wave:
      - position: absolute
      - inset: 0
      - z-index: 1
      - pointer-events: none
    front_wave:
      - position: absolute
      - inset: 0
      - z-index: 1
      - pointer-events: none
custom_fields:
  glass_circle: |
    [[[ return ``; ]]]
  back_wave: |
    [[[
      let level = entity && entity.state && !isNaN(entity.state) ? parseFloat(entity.state) : 0;
      let display_level = Math.max(level, 5);
      let is_charging = variables.charger_entity && states[variables.charger_entity] ? ['on', 'charging', 'plugged'].includes(states[variables.charger_entity].state.toLowerCase()) : false;
      let rgb = "46, 204, 113";
      if (is_charging) rgb = "52, 152, 219";
      else if (level <= variables.threshold_red) rgb = "231, 76, 60";
      else if (level <= variables.threshold_orange) rgb = "243, 156, 18";
      let color = `rgba(${rgb}, 0.6)`;
      let speed = is_charging ? "2s" : "4s";
      let path = "M0 7.5 Q30 0 60 7.5 T120 7.5 L120 15 L0 15 Z";
      let svg = `<svg viewBox="0 0 120 15" style="width:120px; height:15px; display:block; flex-shrink:0;"><path d="${path}" fill="${color}"/></svg>`;
      let wave_row = svg.repeat(10); 
      return `
        <div style="position:absolute; bottom:0; width:100%; height:calc(${display_level}% + 5px);">
          <div style="position:absolute; top:0; left:0; display:flex; animation:scroll-right ${speed} linear infinite;">
            ${wave_row}
          </div>
          <div style="position:absolute; top:14px; bottom:0; left:0; width:100%; background:${color};"></div>
        </div>
      `;
    ]]]
  front_wave: |
    [[[
      let level = entity && entity.state && !isNaN(entity.state) ? parseFloat(entity.state) : 0;
      let display_level = Math.max(level, 5);
      let is_charging = variables.charger_entity && states[variables.charger_entity] ? ['on', 'charging', 'plugged'].includes(states[variables.charger_entity].state.toLowerCase()) : false;
      let rgb = "46, 204, 113";
      if (is_charging) rgb = "52, 152, 219";
      else if (level <= variables.threshold_red) rgb = "231, 76, 60";
      else if (level <= variables.threshold_orange) rgb = "243, 156, 18";
      let color = `rgba(${rgb}, 1)`;
      let speed = is_charging ? "1.5s" : "3s";
      let path = "M0 7.5 Q30 0 60 7.5 T120 7.5 L120 15 L0 15 Z";
      let svg = `<svg viewBox="0 0 120 15" style="width:120px; height:15px; display:block; flex-shrink:0;"><path d="${path}" fill="${color}"/></svg>`;
      let wave_row = svg.repeat(10); 
      return `
        <div style="position:absolute; bottom:0; width:100%; height:${display_level}%;">
          <div style="position:absolute; top:0; left:0; display:flex; animation:scroll-left ${speed} linear infinite;">
            ${wave_row}
          </div>
          <div style="position:absolute; top:14px; bottom:0; left:0; width:100%; background:${color};"></div>
        </div>
      `;
    ]]]
extra_styles: |
  @keyframes scroll-left {
    0% { transform: translateX(0); }
    100% { transform: translateX(-120px); }
  }
  @keyframes scroll-right {
    0% { transform: translateX(-120px); }
    100% { transform: translateX(0); }
  }


665270619-e1f31ec9-da72-4c9f-bdfc-ed20abf2d10c
Mushroom light card with color temps quick toggles
  • after pasting this card, use the Find & Replace ALL feature in the card editor (CTRL+F) and Replace light.CHANGE_ME with your light entity, to change it everywhere at once.
type: custom:vertical-stack-in-card
cards:
  - type: custom:mushroom-light-card
    entity: light.CHANGE_ME
    name: Light Card Name
    icon: mdi:led-strip-variant
    show_brightness_control: true
    show_color_control: true
    show_color_temp_control: true
    use_light_color: true
    card_mod:
      style:
        mushroom-light-brightness-control$:
          mushroom-slider$: |
            .slider {
              background: rgba(255, 255, 255, 0.05) !important;
            }
            .slider-track-active {
              box-shadow: inset 0 2px 4px rgba(0,0,0,0.15) !important;
            }
        .: |
          ha-card {
            background: none !important;
            border: none !important;
            box-shadow: none !important;
            
            padding-top: 10px !important;
            padding-bottom: 10px !important; 
            
            --control-height: 38px;
            --control-border-radius: 19px; 
          }
          mushroom-state-info {
            max-width: calc(100% - 140px) !important; 
          }
  - type: custom:mushroom-chips-card
    alignment: end
    card_mod:
      style: |
        ha-card {
          position: absolute;
          top: 10px;
          right: 10px;
          background: none !important;
          border: none !important;
          box-shadow: none !important;
          
          width: max-content;
          pointer-events: none;
          z-index: 10;
          
          --chip-background: rgba(255, 255, 255, 0.05);
          --chip-box-shadow: none;
          --chip-border-width: 0px;
          --chip-spacing: 6px;
          --chip-padding: 0 10px;
          --chip-height: 38px;
          --chip-icon-size: 20px;
        }
        mushroom-template-chip {
          pointer-events: auto;
        }
    chips:
      - type: template
        entity: light.CHANGE_ME
        icon: mdi:weather-sunset
        icon_color: >-
          {% set temp = state_attr(entity, 'color_temp_kelvin') %}

          {% set mode = state_attr(entity, 'color_mode') %}

          {{ 'orange' if is_state(entity, 'on') and mode == 'color_temp' and
          temp != None and temp <= 3200 else 'disabled' }}
        tap_action:
          action: call-service
          service: light.turn_on
          target:
            entity_id: light.CHANGE_ME
          data:
            color_temp_kelvin: 2702
      - type: template
        entity: light.CHANGE_ME
        icon: mdi:white-balance-sunny
        icon_color: >-
          {% set temp = state_attr(entity, 'color_temp_kelvin') %}

          {% set mode = state_attr(entity, 'color_mode') %}

          {{ 'amber' if is_state(entity, 'on') and mode == 'color_temp' and temp
          != None and 3200 < temp < 5000 else 'disabled' }}
        tap_action:
          action: call-service
          service: light.turn_on
          target:
            entity_id: light.CHANGE_ME
          data:
            color_temp_kelvin: 4000
      - type: template
        entity: light.CHANGE_ME
        icon: mdi:snowflake
        icon_color: >-
          {% set temp = state_attr(entity, 'color_temp_kelvin') %}

          {% set mode = state_attr(entity, 'color_mode') %}

          {{ 'light-blue' if is_state(entity, 'on') and mode == 'color_temp' and
          temp != None and temp >= 5000 else 'disabled' }}
        tap_action:
          action: call-service
          service: light.turn_on
          target:
            entity_id: light.CHANGE_ME
          data:
            color_temp_kelvin: 6535
card_mod:
  style: |
    ha-card {
      position: relative;
    }