Repository: adobe/adobe-design-website
Pull request #69: feat: callout block
Author: login: arnest00
Labels: name: Ready for Squash & Merge
Created: 2025-05-08T08:04:40Z | Merged: 2025-05-08T17:29:15Z

## Summary of changes
- Add missing typography variables
- Add missing typography utility classes
- Update multitone gradient values
- Create callout block

## Relevant Links
- Designs: [Figma](https://www.figma.com/design/QzvOszpLGT7fwSd6N7gaDW/Adobe-Design?node-id=1135-14473&t=9XsMpHkLUAq38dyK-1) (see Homepage designs)
- Story: [ADB-180](https://sparkbox.atlassian.net/browse/ADB-180)

## Test URLs:
- Before: https://main--adobe-design-website--adobe.aem.page/pattern-library/
- After: https://feat-callout-block--adobe-design-website--adobe.aem.page/pattern-library/

## Checklist
* [ ] This PR has visual changes, and has been reviewed by a designer.
* [ ] This PR has code changes, and our linters still pass.
* [ ] This PR has new code, so new tests were added or updated, and they pass.
* [ ] This PR affects production code, so it was browser tested (see below).
* [ ] The content of this PR requires documentation, so we added a detailed description of the component's purpose, requirements, quirks, and instructions for use by designers and developers. This includes accessibility information if pertinent.

## Validation
1. Visit the [Pattern Library page on the branch preview](https://feat-callout-block--adobe-design-website--adobe.aem.page/pattern-library/)
2. Scroll down to the Callout section
3. Verify the first block example is non-interactive
4. Verify the second block example renders the entire block as a link
5. Verify the third block example has a link button which is the only interactive part of the callout
6. Verify the block matches the design

---

## Browser Testing
We should aim to support the latest version of the listed browsers. For older versions or other browsers not on the list, content should be accessible, even if it doesn't completely match the designs.

Developers should test as they work in the browsers available on their machines. If they have access to other devices to test other browser/OS combinations, they should do that when possible.

**Windows**
* [ ] Firefox
* [ ] Chrome
* [ ] Edge

**MacOS**
* [x] Firefox
* [x] Chrome
* [ ] Safari
* [ ] Edge

**Android**
* [ ] Firefox
* [ ] Chrome
* [ ] Edge

**iOS**
* [ ] Safari

---



Diff:
diff --git a/blocks/callout/callout.css b/blocks/callout/callout.css
new file mode 100644
index 00000000..dd17932b
--- /dev/null
+++ b/blocks/callout/callout.css
@@ -0,0 +1,99 @@
+.callout-container {
+  container-type: inline-size;
+  container-name: callout-container;
+}
+
+.callout {
+  border-radius: var(--spectrum-corner-radius-800);
+  padding: 1.5rem;
+  background: var(--gradient-multitone);
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+
+  .button {
+    width: 100%;
+    align-self: center;
+
+    svg {
+      margin-inline-end: 0.5rem;
+    }
+  }
+  
+  @container callout-container (min-width: 35.5rem) {
+    padding: 2.5rem;
+    flex-direction: row;
+    gap: 2rem;
+
+    .button {
+      width: unset;
+    }
+  }
+  
+  @container callout-container (min-width: 44rem) {
+    padding: 1.5rem;
+  }
+  
+  @container callout-container (min-width: 49rem) {
+    padding: 3.625rem;
+    justify-content: space-between;
+  }
+}
+
+.callout--with-link {
+  &:hover {
+    color: var(--spectrum-white);
+    text-decoration: none;
+  }
+
+  &:hover .callout__title {
+    text-decoration: underline;
+  }
+}
+
+.callout__content {
+  color: var(--spectrum-white);
+
+  span {
+    display: block;
+    font-size: var(--spectrum-font-size-300);
+    line-height: 1.5;
+    
+    @container callout-container (min-width: 35.5rem) {
+      font-size: var(--spectrum-font-size-400);
+    }
+    
+    @container callout-container (min-width: 44rem) {
+      font-size: var(--spectrum-font-size-500);
+    }
+    
+    @container callout-container (min-width: 49rem) {
+      font-size: var(--spectrum-font-size-600);
+    }
+  }
+
+  .callout__title {
+    font-family: var(--spectrum-display-font);
+    font-weight: var(--spectrum-extra-bold-font-weight);
+    font-size: var(--spectrum-font-size-700);
+    line-height: 1.25;
+    margin-block-end: 1rem;
+    
+    @container callout-container (min-width: 35.5rem) {
+      font-size: var(--spectrum-font-size-900);
+      margin-block-end: 1.5rem;
+    }
+    
+    @container callout-container (min-width: 44rem) {
+      font-size: var(--spectrum-font-size-1000);
+      margin-block-end: 1rem;
+    }
+    
+    @container callout-container (min-width: 49rem) {
+      font-size: var(--spectrum-font-size-1100);
+      margin-block-end: 1.5rem;
+    }
+  }
+}
diff --git a/blocks/callout/callout.js b/blocks/callout/callout.js
new file mode 100644
index 00000000..386b7021
--- /dev/null
+++ b/blocks/callout/callout.js
@@ -0,0 +1,73 @@
+const PAPER_PLANE_ICON_SVG = `
+  <svg xmlns="http://www.w3.org/2000/svg" width="26" height="27" fill="none" viewBox="0 0 26 26">
+    <mask id="a" width="26" height="26" x="0" y="0" maskUnits="userSpaceOnUse" style="mask-type:alpha">
+      <path fill="#FFF" d="M24.414 2.085a.975.975 0 0 0-1.047-.216l-21.45 8.462a.973.973 0 0 0-.118 1.757l8.132 4.543 4.578 8.076a.977.977 0 0 0 1.755-.127l8.37-21.45a.975.975 0 0 0-.22-1.045ZM19.72 5.403l-9.246 9.298-5.927-3.312L19.72 5.403Zm-4.526 16.558-3.336-5.885 9.267-9.317-5.93 15.202Z"/>
+    </mask>
+    <g mask="url(#a)">
+      <path fill="#fff" fill-opacity=".85" d="M0 .5h26v26H0z"/>
+    </g>
+  </svg>
+`;
+
+export default async function decorate(block) {
+  const calloutData = {
+    title: block.children[0].children[0].textContent.trim(),
+    description: block.children[0].children[1].children,
+    url: block.children[1].children[0].textContent.trim(),
+    buttonLabel: block.children[1].children[1].textContent.trim(),
+    altText: block.children[1].children[2].textContent.trim(),
+  };
+
+  let calloutBlock;
+  let calloutButton = null;
+
+  // Create container element
+  const calloutContainer = document.createElement('div');
+  calloutContainer.classList.add('callout-container');
+
+  // Populate callout content
+  const calloutContent = document.createElement('div');
+  calloutContent.classList.add('callout__content');
+
+  // ...remove any automatic heading tag from title text
+  const calloutTitle = document.createElement('span');
+  calloutTitle.classList.add('callout__title');
+  calloutTitle.textContent = calloutData.title;
+  calloutContent.append(calloutTitle);
+
+  // ...remove semantic tags from description text
+  [...calloutData.description].forEach((textNode) => {
+    const calloutDescriptionPart = document.createElement('span');
+    calloutDescriptionPart.textContent = textNode.textContent.trim();
+    calloutContent.append(calloutDescriptionPart);
+  });
+
+  if (calloutData.url && calloutData.buttonLabel) {
+    // The callout has a button; the rest of the block is not interactive 
+    calloutBlock = document.createElement('div');
+    calloutButton = document.createElement('a');
+    calloutButton.classList.add('button', 'button--static-white');
+    calloutButton.href = calloutData.url;
+    calloutButton.innerHTML = `
+      ${PAPER_PLANE_ICON_SVG}
+      <span>${calloutData.buttonLabel}</span>
+    `;
+    if (calloutData.altText) calloutButton.title = calloutData.altText;
+  } else if (calloutData.url && !calloutData.buttonLabel) {
+    // The callout as a whole is interactive
+    calloutBlock = document.createElement('a');
+    calloutBlock.classList.add('callout--with-link');
+    calloutBlock.href = calloutData.url;
+    if (calloutData.altText) calloutButton.title = calloutData.altText;
+  } else {
+    // The callout is non-interactive
+    calloutBlock = document.createElement('div');
+  };
+
+  calloutBlock.classList.add('callout');
+  calloutBlock.append(calloutContent);
+  if (calloutButton) calloutBlock.append(calloutButton);
+  calloutContainer.append(calloutBlock);
+
+  block.replaceWith(calloutContainer);
+}
diff --git a/blocks/callout/callout.test.js b/blocks/callout/callout.test.js
new file mode 100644
index 00000000..09b1e52b
--- /dev/null
+++ b/blocks/callout/callout.test.js
@@ -0,0 +1,11 @@
+describe('Callout Block', () => {
+  beforeAll(async () => {
+    await page.goto(`${global.BASE_URL}pattern-library/`);
+  });
+
+  it('should render the callout block', async () => {
+    await page.waitForSelector('.callout');
+    const callouts = await page.$$('.callout');
+    expect(callouts.length).toBeGreaterThanOrEqual(1);
+  });
+});
diff --git a/styles/base.css b/styles/base.css
index 0ea86bb6..30a09215 100644
--- a/styles/base.css
+++ b/styles/base.css
@@ -279,9 +279,9 @@
   --gradient-indigo-light: var(--gradient-indigo-400);
 
   --gradient-multitone: linear-gradient(
-    271deg,
-    #eb1000 -38.76%,
-    #4b75ff 118.78%
+    269deg,
+    #eb1000 -0.72%,
+    #4b75ff 81.56%
   );
 
   --gradient-multitone-pink: linear-gradient(
@@ -524,33 +524,64 @@
   --spectrum-font-size-1000: 40px;
   --spectrum-font-size-1100: 45px;
   --spectrum-font-size-1200: 51px;
+  --spectrum-font-size-1300: 58px;
+  --spectrum-font-size-1400: 65px;
+  --spectrum-font-size-1500: 73px;
 
   /* heading */
   --heading-font-family: var(--spectrum-display-font);
   --heading-line-height: 1.25;
 
+  --spectrum-heading-size-xxl: var(--spectrum-font-size-1200);
+  --spectrum-heading-weight-xxl: var(--spectrum-black-font-weight);
+
   --spectrum-heading-size-xl: var(--spectrum-font-size-1000);
   --spectrum-heading-weight-xl: var(--spectrum-black-font-weight);
 
+  --spectrum-heading-size-l: var(--spectrum-font-size-800);
+  --spectrum-heading-weight-l: var(--spectrum-black-font-weight);
+
   --spectrum-heading-size-m: var(--spectrum-font-size-750);
-  --spectrum-heading-weight-m: var(--spectrum-black-font-weight);
+  --spectrum-heading-weight-m: var(--spectrum-extra-bold-font-weight);
 
   --spectrum-heading-size-s: var(--spectrum-font-size-700);
   --spectrum-heading-weight-s: var(--spectrum-extra-bold-font-weight);
 
+  @media (min-width: 48rem) {
+    --spectrum-heading-size-l: var(--spectrum-font-size-1300);
+    --spectrum-heading-size-m: var(--spectrum-font-size-800);
+    --spectrum-heading-size-s: var(--spectrum-font-size-900);
+  }
+
   @media (min-width: 80rem) {
     --spectrum-heading-size-xl: var(--spectrum-font-size-1200);
+    --spectrum-heading-size-l: var(--spectrum-font-size-1100);
     --spectrum-heading-size-m: var(--spectrum-font-size-1000);
-    --spectrum-heading-size-s: var(--spectrum-font-size-900);
+  }
+
+  @media (min-width: 105rem) {
+    --spectrum-heading-size-xxl: var(--spectrum-font-size-1500);
+    --spectrum-heading-size-xl: var(--spectrum-font-size-1400);
+    --spectrum-heading-size-l: var(--spectrum-font-size-1200);
+    --spectrum-heading-size-m: var(--spectrum-font-size-1100);
   }
 
   /* title */
   --title-font-family: var(--spectrum-sans-serif-font);
   --title-line-height: 1.3;
 
+  --spectrum-title-size-xxxl: var(--spectrum-font-size-700);
+  --spectrum-title-weight-xxxl: var(--spectrum-extra-bold-font-weight);
+
+  --spectrum-title-size-xxl: var(--spectrum-font-size-600);
+  --spectrum-title-weight-xxl: var(--spectrum-extra-bold-font-weight);
+
   --spectrum-title-size-xl: var(--spectrum-font-size-500);
   --spectrum-title-weight-xl: var(--spectrum-extra-bold-font-weight);
 
+  --spectrum-title-size-l: var(--spectrum-font-size-400);
+  --spectrum-title-weight-l: var(--spectrum-bold-font-weight);
+
   --spectrum-title-size-m: var(--spectrum-font-size-300);
   --spectrum-title-weight-m: var(--spectrum-bold-font-weight);
 
@@ -561,7 +592,10 @@
   --spectrum-title-weight-xs: var(--spectrum-bold-font-weight);
 
   @media (min-width: 80rem) {
+    --spectrum-title-size-xxxl: var(--spectrum-font-size-800);
+    --spectrum-title-size-xxl: var(--spectrum-font-size-700);
     --spectrum-title-size-xl: var(--spectrum-font-size-600);
+    --spectrum-title-size-l: var(--spectrum-font-size-500);
     --spectrum-title-size-m: var(--spectrum-font-size-400);
     --spectrum-title-size-s: var(--spectrum-font-size-300);
     --spectrum-title-size-xs: var(--spectrum-font-size-200);
@@ -576,6 +610,10 @@
   --spectrum-detail-size-m: var(--spectrum-font-size-200);
   --spectrum-detail-size-s: var(--spectrum-font-size-100);
 
+  @media (min-width: 48rem) {
+    --spectrum-detail-size-l: var(--spectrum-font-size-400);
+  }
+
   @media (min-width: 80rem) {
     --spectrum-detail-size-l: var(--spectrum-font-size-500);
     --spectrum-detail-size-m: var(--spectrum-font-size-300);
@@ -587,14 +625,18 @@
   --body-line-height: 1.5;
   --body-font-weight: var(--spectrum-regular-font-weight);
 
+  --spectrum-body-size-xl: var(--spectrum-font-size-500);
+  --spectrum-body-size-l: var(--spectrum-font-size-400);
   --spectrum-body-size-m: var(--spectrum-font-size-300);
   --spectrum-body-size-s: var(--spectrum-font-size-200);
   --spectrum-body-size-xs: var(--spectrum-font-size-100);
-
+  
   @media (min-width: 80rem) {
-    --spectrum-body-size-m: var(--spectrum-font-size-300);
-    --spectrum-body-size-s: var(--spectrum-font-size-200);
-    --spectrum-body-size-xs: var(--spectrum-font-size-100);
+    --spectrum-body-size-xl: var(--spectrum-font-size-600);
+    --spectrum-body-size-l: var(--spectrum-font-size-500);
+    --spectrum-body-size-m: var(--spectrum-font-size-400);
+    --spectrum-body-size-s: var(--spectrum-font-size-300);
+    --spectrum-body-size-xs: var(--spectrum-font-size-200);
   }
 
   /* functional */
diff --git a/styles/styles.css b/styles/styles.css
index 113b4745..d5cd022a 100644
--- a/styles/styles.css
+++ b/styles/styles.css
@@ -706,6 +706,13 @@ main .section.highlight {
 
 /* ** Type Utilities ** */
 
+.util-heading-xxl {
+  font-family: var(--heading-font-family);
+  line-height: var(--heading-line-height);
+  font-size: var(--spectrum-heading-size-xxl);
+  font-weight: var(--spectrum-heading-weight-xxl);
+}
+
 .util-heading-xl {
   font-family: var(--heading-font-family);
   line-height: var(--heading-line-height);
@@ -713,6 +720,13 @@ main .section.highlight {
   font-weight: var(--spectrum-heading-weight-xl);
 }
 
+.util-heading-l {
+  font-family: var(--heading-font-family);
+  line-height: var(--heading-line-height);
+  font-size: var(--spectrum-heading-size-l);
+  font-weight: var(--spectrum-heading-weight-l);
+}
+
 .util-heading-m {
   font-family: var(--heading-font-family);
   line-height: var(--heading-line-height);
@@ -727,6 +741,20 @@ main .section.highlight {
   font-weight: var(--spectrum-heading-weight-s);
 }
 
+.util-title-xxxl {
+  font-family: var(--title-font-family);
+  line-height: var(--title-line-height);
+  font-size: var(--spectrum-title-size-xxxl);
+  font-weight: var(--spectrum-title-weight-xl);
+}
+
+.util-title-xxl {
+  font-family: var(--title-font-family);
+  line-height: var(--title-line-height);
+  font-size: var(--spectrum-title-size-xxl);
+  font-weight: var(--spectrum-title-weight-xxl);
+}
+
 .util-title-xl {
   font-family: var(--title-font-family);
   line-height: var(--title-line-height);
@@ -734,6 +762,13 @@ main .section.highlight {
   font-weight: var(--spectrum-title-weight-xl);
 }
 
+.util-title-l {
+  font-family: var(--title-font-family);
+  line-height: var(--title-line-height);
+  font-size: var(--spectrum-title-size-l);
+  font-weight: var(--spectrum-title-weight-l);
+}
+
 .util-title-m {
   font-family: var(--title-font-family);
   line-height: var(--title-line-height);
@@ -776,6 +811,20 @@ main .section.highlight {
   font-weight: var(--detail-font-weight);
 }
 
+.util-body-xl {
+  font-family: var(--body-font-family);
+  line-height: var(--body-line-height);
+  font-size: var(--spectrum-body-size-xl);
+  font-weight: var(--body-font-weight);
+}
+
+.util-body-l {
+  font-family: var(--body-font-family);
+  line-height: var(--body-line-height);
+  font-size: var(--spectrum-body-size-l);
+  font-weight: var(--body-font-weight);
+}
+
 .util-body-m {
   font-family: var(--body-font-family);
   line-height: var(--body-line-height);


Reviews:
user: login: catheraaine
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-05-08T14:11:57Z
user: login: catheraaine
body: ## two visual things

### is this button supposed to be full-width? 
<img width="470" alt="Screenshot 2025-05-08 at 10 13 10 AM" src="https://github.com/user-attachments/assets/ad7351f8-0496-4078-b7d6-52d7d8e057f5" />

### also don't be mad

<img width="938" alt="Screenshot 2025-05-08 at 10 13 34 AM" src="https://github.com/user-attachments/assets/83e24220-7b84-4c3f-a1ed-130a0faff11c" />

state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-08T14:14:27Z
user: login: arnest00
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-08T15:23:45Z
user: login: arnest00
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-08T15:24:45Z
user: login: catheraaine
body: nice work
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-08T17:17:16Z

Review comments:
diff_hunk: @@ -0,0 +1,92 @@
+.callout-container {
+  container-type: inline-size;
+  container-name: callout-container;
+}
+
+.callout {
+  border-radius: var(--spectrum-corner-radius-800);
+  padding: 1.5rem;
+  background: var(--gradient-multitone);
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+
+  .button {
+    align-self: center;
+
+    svg {
+      margin-inline-end: 0.5rem;
+    }
+  }
+  
+  @container callout-container (min-width: 35.5rem) {
path: blocks/callout/callout.css
user: login: catheraaine
body: superb
created_at: 2025-05-08T14:05:53Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,92 @@
+.callout-container {
+  container-type: inline-size;
+  container-name: callout-container;
+}
+
+.callout {
+  border-radius: var(--spectrum-corner-radius-800);
+  padding: 1.5rem;
+  background: var(--gradient-multitone);
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+
+  .button {
+    align-self: center;
+
+    svg {
+      margin-inline-end: 0.5rem;
+    }
+  }
+  
+  @container callout-container (min-width: 35.5rem) {
+    padding: 2.5rem;
+    flex-direction: row;
+    gap: 2rem;
+  }
+  
+  @container callout-container (min-width: 44rem) {
+    padding: 1.5rem;
+  }
+  
+  @container callout-container (min-width: 49rem) {
+    padding: 3.625rem;
+    justify-content: space-between;
+  }
+}
+
+.callout--link {
path: blocks/callout/callout.css
user: login: catheraaine
body: could we name this like `.callout--with-link` so we know it's a modifier and not a subcomponent? 
created_at: 2025-05-08T14:06:26Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,69 @@
+export default async function decorate(block) {
+  const calloutData = {
path: blocks/callout/callout.js
user: login: catheraaine
body: I really like the solution of creating an object with the table data and using that to iterate over; it's super readable.
created_at: 2025-05-08T14:07:31Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,69 @@
+export default async function decorate(block) {
+  const calloutData = {
+    title: block.children[0].children[0].textContent.trim(),
+    description: block.children[0].children[1].children,
+    url: block.children[1].children[0].textContent.trim(),
+    buttonLabel: block.children[1].children[1].textContent.trim(),
+    altText: block.children[1].children[2].textContent.trim(),
+  };
+
+  let calloutBlock;
+  let calloutButton = null;
+
+  // Create container element
+  const calloutContainer = document.createElement('div');
+  calloutContainer.classList = 'callout-container';
+
+  // Populate callout content
+  const calloutContent = document.createElement('div');
+  calloutContent.classList = 'callout__content';
path: blocks/callout/callout.js
user: login: catheraaine
body: it doesn't quite matter in this situation, but I've been using `classList.add()` because it doesn't overwrite any classes already on the component
created_at: 2025-05-08T14:08:32Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,69 @@
+export default async function decorate(block) {
+  const calloutData = {
+    title: block.children[0].children[0].textContent.trim(),
+    description: block.children[0].children[1].children,
+    url: block.children[1].children[0].textContent.trim(),
+    buttonLabel: block.children[1].children[1].textContent.trim(),
+    altText: block.children[1].children[2].textContent.trim(),
+  };
+
+  let calloutBlock;
+  let calloutButton = null;
+
+  // Create container element
+  const calloutContainer = document.createElement('div');
+  calloutContainer.classList = 'callout-container';
+
+  // Populate callout content
+  const calloutContent = document.createElement('div');
+  calloutContent.classList = 'callout__content';
+
+  // ...remove any automatic heading tag from title text
+  const calloutTitle = document.createElement('span');
+  calloutTitle.classList = 'callout__title';
+  calloutTitle.textContent = calloutData.title;
+  calloutContent.append(calloutTitle);
+
+  // ...remove semantic tags from description text
+  [...calloutData.description].forEach((textNode) => {
+    const calloutDescriptionPart = document.createElement('span');
+    calloutDescriptionPart.textContent = textNode.textContent.trim();
+    calloutContent.append(calloutDescriptionPart);
+  });
+
+  if (calloutData.url && calloutData.buttonLabel) {
+    // The callout is non-interactive, but has a link button
path: blocks/callout/callout.js
user: login: catheraaine
body: what does this mean
created_at: 2025-05-08T14:08:56Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,69 @@
+export default async function decorate(block) {
+  const calloutData = {
+    title: block.children[0].children[0].textContent.trim(),
+    description: block.children[0].children[1].children,
+    url: block.children[1].children[0].textContent.trim(),
+    buttonLabel: block.children[1].children[1].textContent.trim(),
+    altText: block.children[1].children[2].textContent.trim(),
+  };
+
+  let calloutBlock;
+  let calloutButton = null;
+
+  // Create container element
+  const calloutContainer = document.createElement('div');
+  calloutContainer.classList = 'callout-container';
+
+  // Populate callout content
+  const calloutContent = document.createElement('div');
+  calloutContent.classList = 'callout__content';
+
+  // ...remove any automatic heading tag from title text
+  const calloutTitle = document.createElement('span');
+  calloutTitle.classList = 'callout__title';
+  calloutTitle.textContent = calloutData.title;
+  calloutContent.append(calloutTitle);
+
+  // ...remove semantic tags from description text
+  [...calloutData.description].forEach((textNode) => {
+    const calloutDescriptionPart = document.createElement('span');
+    calloutDescriptionPart.textContent = textNode.textContent.trim();
+    calloutContent.append(calloutDescriptionPart);
+  });
+
+  if (calloutData.url && calloutData.buttonLabel) {
+    // The callout is non-interactive, but has a link button
+    calloutBlock = document.createElement('div');
+    calloutButton = document.createElement('a');
+    calloutButton.classList = 'button button--static-white';
+    calloutButton.href = calloutData.url;
+    calloutButton.innerHTML = `
+      <svg width="26" height="27" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
+      <mask id="mask0_1480_1486" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="26" height="26">
+        <path d="M24.4136 2.08485C24.1381 1.81063 23.728 1.72685 23.3675 1.86903L1.91747 10.3305C1.56708 10.4676 1.32842 10.7964 1.30301 11.1722C1.27761 11.5479 1.4706 11.9047 1.79941 12.0875L9.93075 16.6311L14.5087 24.7066C14.6826 25.0126 15.0076 25.2005 15.3567 25.2005C15.3796 25.2005 15.4037 25.1992 15.4265 25.1979C15.8023 25.1713 16.1286 24.9301 16.2644 24.5797L24.6332 3.12968C24.7741 2.76913 24.6878 2.3578 24.4136 2.08485ZM19.7203 5.4034L10.4735 14.7005L4.54667 11.3892L19.7203 5.4034ZM15.1942 21.9606L11.8579 16.076L21.1248 6.75863L15.1942 21.9606Z" fill="#FFFFFF"/>
+      </mask>
+      <g mask="url(#mask0_1480_1486)">
+        <rect y="0.5" width="26" height="26" fill="white" fill-opacity="0.85"/>
+      </g>
+      </svg>
path: blocks/callout/callout.js
user: login: catheraaine
body: reminder to compress your svg https://jakearchibald.github.io/svgomg/

you can also assign this svg code to a constant outside the function, which will make your code more readable, e.g. 

```js
calloutButton.innerHTML = ICON_ARROW_OR_SOMESUCH

```
created_at: 2025-05-08T14:10:48Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,69 @@
+export default async function decorate(block) {
+  const calloutData = {
+    title: block.children[0].children[0].textContent.trim(),
+    description: block.children[0].children[1].children,
+    url: block.children[1].children[0].textContent.trim(),
+    buttonLabel: block.children[1].children[1].textContent.trim(),
+    altText: block.children[1].children[2].textContent.trim(),
+  };
+
+  let calloutBlock;
+  let calloutButton = null;
+
+  // Create container element
+  const calloutContainer = document.createElement('div');
+  calloutContainer.classList = 'callout-container';
+
+  // Populate callout content
+  const calloutContent = document.createElement('div');
+  calloutContent.classList = 'callout__content';
path: blocks/callout/callout.js
user: login: arnest00
body: I'll update for consistency!
created_at: 2025-05-08T15:23:45Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,69 @@
+export default async function decorate(block) {
+  const calloutData = {
+    title: block.children[0].children[0].textContent.trim(),
+    description: block.children[0].children[1].children,
+    url: block.children[1].children[0].textContent.trim(),
+    buttonLabel: block.children[1].children[1].textContent.trim(),
+    altText: block.children[1].children[2].textContent.trim(),
+  };
+
+  let calloutBlock;
+  let calloutButton = null;
+
+  // Create container element
+  const calloutContainer = document.createElement('div');
+  calloutContainer.classList = 'callout-container';
+
+  // Populate callout content
+  const calloutContent = document.createElement('div');
+  calloutContent.classList = 'callout__content';
+
+  // ...remove any automatic heading tag from title text
+  const calloutTitle = document.createElement('span');
+  calloutTitle.classList = 'callout__title';
+  calloutTitle.textContent = calloutData.title;
+  calloutContent.append(calloutTitle);
+
+  // ...remove semantic tags from description text
+  [...calloutData.description].forEach((textNode) => {
+    const calloutDescriptionPart = document.createElement('span');
+    calloutDescriptionPart.textContent = textNode.textContent.trim();
+    calloutContent.append(calloutDescriptionPart);
+  });
+
+  if (calloutData.url && calloutData.buttonLabel) {
+    // The callout is non-interactive, but has a link button
path: blocks/callout/callout.js
user: login: arnest00
body: I updated the text for clarity! The comments for this block of code are now:

```js
// The callout has a button; the rest of the block is not interactive 
// The callout as a whole is interactive
// The callout is non-interactive
```
created_at: 2025-05-08T15:24:45Z
author_association: COLLABORATOR

PR comments:
user: login: aem-code-sync[bot]
created_at: 2025-05-08T08:04:44Z
body: <!-- aem-bot-dash -->
Hello, I'm the AEM Code Sync Bot and I will run some actions to deploy your branch and validate page speed.
In case there are problems, just click a checkbox below to rerun the respective action.

- [ ] <!-- action-psi --> Re-run PSI checks
- [ ] <!-- action-sync --> Re-sync branch

<details>
<summary>Commits</summary>
<!-- commit-history -->

* [0c0b051](https://github.com/adobe/adobe-design-website/commit/0c0b051a3fb3f495780bab9370e5080170f55475) :white_check_mark: (latest)
* [963c8ce](https://github.com/adobe/adobe-design-website/commit/963c8ce66b597cc5a691a2ba76d0d93350697133) :white_check_mark:
* [6770430](https://github.com/adobe/adobe-design-website/commit/6770430aaf9e4c9c8ceb6889a0978fb1c446875a) :white_check_mark:
* [55992df](https://github.com/adobe/adobe-design-website/commit/55992dfb9c24d430ba0b21bfd14d24be1e23e70e) :white_check_mark:
* [a0836ca](https://github.com/adobe/adobe-design-website/commit/a0836ca449776e7f6b3c593bac81213c582c3905) :white_check_mark:

<!-- commit-history-end -->
</details>
author_association: NONE
user: login: aem-code-sync[bot]
created_at: 2025-05-08T08:05:06Z
body: <!-- aem-bot-psi -->
| | Page | Scores | Audits | Google |
|-|------|--------|--------|--------|
| :iphone: | [/pattern-library/](https://feat-callout-block--adobe-design-website--adobe.aem.page/pattern-library/) | [![PERFORMANCE](https://img.shields.io/badge/PERFORMANCE-96-green?style=for-the-badge "Performance")](https://googlechrome.github.io/lighthouse/scorecalc/#device=mobile&version=12.6.0&SI=2298.466225&FCP=2298.466225&LCP=2298.466225&TBT=0&CLS=0 "See Calculator") ![A11Y](https://img.shields.io/badge/A11Y-91-green?style=for-the-badge "Accessibility") ![SEO](https://img.shields.io/badge/SEO-61-orange?style=for-the-badge "SEO") ![BEST PRACTICES](https://img.shields.io/badge/BEST%20PRACTICES-96-green?style=for-the-badge "Best Practices") | ![SI](https://img.shields.io/badge/SI-2.3s-green?style=for-the-badge "Speed Index") ![FCP](https://img.shields.io/badge/FCP-2.3s-orange?style=for-the-badge "First Contentful Paint") ![LCP](https://img.shields.io/badge/LCP-2.3s-green?style=for-the-badge "Largest Contentful Paint") ![TBT](https://img.shields.io/badge/TBT-0ms-green?style=for-the-badge "Total Blocking Time") ![CLS](https://img.shields.io/badge/CLS-0-green?style=for-the-badge "Cumulative Layout Shift") | [![PSI](https://www.gstatic.com/images/icons/material/product/2x/pagespeed_16dp.png)](https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2Ffeat-callout-block--adobe-design-website--adobe.aem.page%2Fpattern-library%2F "Run again in Google PSI") |
| :desktop_computer: | [/pattern-library/](https://feat-callout-block--adobe-design-website--adobe.aem.page/pattern-library/) | [![PERFORMANCE](https://img.shields.io/badge/PERFORMANCE-100-green?style=for-the-badge "Performance")](https://googlechrome.github.io/lighthouse/scorecalc/#device=mobile&version=12.6.0&SI=641.30269&FCP=641.30269&LCP=646.8390449999999&TBT=0&CLS=0 "See Calculator") ![A11Y](https://img.shields.io/badge/A11Y-91-green?style=for-the-badge "Accessibility") ![SEO](https://img.shields.io/badge/SEO-61-orange?style=for-the-badge "SEO") ![BEST PRACTICES](https://img.shields.io/badge/BEST%20PRACTICES-96-green?style=for-the-badge "Best Practices") | ![SI](https://img.shields.io/badge/SI-0.6s-green?style=for-the-badge "Speed Index") ![FCP](https://img.shields.io/badge/FCP-0.6s-green?style=for-the-badge "First Contentful Paint") ![LCP](https://img.shields.io/badge/LCP-0.6s-green?style=for-the-badge "Largest Contentful Paint") ![TBT](https://img.shields.io/badge/TBT-0ms-green?style=for-the-badge "Total Blocking Time") ![CLS](https://img.shields.io/badge/CLS-0-green?style=for-the-badge "Cumulative Layout Shift") | [![PSI](https://www.gstatic.com/images/icons/material/product/2x/pagespeed_16dp.png)](https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2Ffeat-callout-block--adobe-design-website--adobe.aem.page%2Fpattern-library%2F "Run again in Google PSI") |

author_association: NONE