From 30833b93ed5e1225480299ff7659ca09ddf6512f Mon Sep 17 00:00:00 2001
From: Jonathan Kingston <jkingston@duckduckgo.com>
Date: Thu, 24 Oct 2024 16:03:03 +0100
Subject: [PATCH 01/40] Create asana.yml (#1159)


From 9b2b8e304ba40ae126bc78ba504a497ec593e1a6 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Tue, 15 Oct 2024 21:44:09 -0600
Subject: [PATCH 02/40] chore: Start RemoteMessagingFramework component

---
 .../new-tab/app/components/Components.jsx     | 23 +++++++++++--------
 .../RemoteMessagingFramework.js               | 16 +++++++++++++
 .../RemoteMessagingFramework.module.css       |  0
 3 files changed, 29 insertions(+), 10 deletions(-)
 create mode 100644 special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
 create mode 100644 special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css

diff --git a/special-pages/pages/new-tab/app/components/Components.jsx b/special-pages/pages/new-tab/app/components/Components.jsx
index 993cc6d0e..2679f3a56 100644
--- a/special-pages/pages/new-tab/app/components/Components.jsx
+++ b/special-pages/pages/new-tab/app/components/Components.jsx
@@ -1,7 +1,6 @@
 import { Fragment, h } from "preact";
 import styles from "./Components.module.css";
 import { mainExamples, otherExamples } from "./Examples.jsx";
-
 const url = new URL(window.location.href);
 
 export function Components() {
@@ -23,7 +22,7 @@ export function Components() {
 
     return (
         <div>
-            <DebugBar id={ids[0]} ids={ids} entries={entries}/>
+            <DebugBar id={ids[0]} ids={ids} entries={entries} />
             <Stage entries={/** @type {any} */(filtered)} />
         </div>
     )
@@ -70,18 +69,22 @@ function Stage({ entries }) {
                             <div class={styles.itemLinks}>
                                 <code>{id}</code>
                                 <a href={next.toString()}
-                                   target="_blank"
-                                   title="open in new tab">Open šŸ”—</a>{" "}
+                                    target="_blank"
+                                    title="open in new tab">Open šŸ”—</a>{" "}
                                 <a href={without.toString()} hidden={current.length === 0}>Remove</a>
                             </div>
                             <div class={styles.itemLinks}>
                                 <a href={selected.toString()}
-                                   class={styles.itemLink}
-                                   title="show this component only">select</a>{" "}
+                                    class={styles.itemLink}
+                                    title="show this component only">select</a>{" "}
+                                <a href={next.toString()}
+                                    target="_blank"
+                                    class={styles.itemLink}
+                                    title="isolate this component">isolate</a>{" "}
                                 <a href={e2e.toString()}
-                                   target="_blank"
-                                   class={styles.itemLink}
-                                   title="isolate this component">edge-to-edge</a>
+                                    target="_blank"
+                                    class={styles.itemLink}
+                                    title="isolate this component">edge-to-edge</a>
                             </div>
                         </div>
                         <div className={styles.item} key={id}>
@@ -180,7 +183,7 @@ function ExampleSelector({ entries, id }) {
         if (!(event.target instanceof HTMLSelectElement)) return;
         const selectedId = event.target.value;
         if (selectedId) {
-            if (selectedId==="none") return onReset();
+            if (selectedId === "none") return onReset();
             const url = new URL(window.location.href);
             url.searchParams.set("id", selectedId);
             window.location.href = url.toString();
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
new file mode 100644
index 000000000..59cf92a72
--- /dev/null
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -0,0 +1,16 @@
+import {h} from "preact";
+import cn from "classnames";
+import styles from "./RemoteMessagingFramework.module.css"
+/**
+ * 
+ * @param {object} props 
+ */
+
+export function RemoteMessagingFramework(props) {
+    const {id, messageType, titleText, descriptionText, icon, primaryActionText = "", primaryAction, secondaryActionText = "", secondaryAction} = props;
+
+
+    return (
+        <div id={id} class={styles.root}>{messageType}</div>
+    )
+}
\ No newline at end of file
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
new file mode 100644
index 000000000..e69de29bb

From 809b92560ee0ad58698f02d36e3c76d391a24968 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Fri, 18 Oct 2024 21:27:15 -0600
Subject: [PATCH 03/40] chore: Update RMF components

---
 .../MessageIcons.js                           | 74 +++++++++++++++
 .../RemoteMessagingFramework.js               | 58 ++++++++++--
 .../RemoteMessagingFramework.module.css       | 93 +++++++++++++++++++
 3 files changed, 216 insertions(+), 9 deletions(-)
 create mode 100644 special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js b/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js
new file mode 100644
index 000000000..058cccf85
--- /dev/null
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js
@@ -0,0 +1,74 @@
+import { h, Fragment } from 'preact'
+
+export default function MessageIcons(props) {
+    const { name } = props
+    return (
+        <>
+            {name === 'Announce' && (
+                <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M19 28.5V31.8648C19 33.5005 19.9958 34.9713 21.5144 35.5787C24.1419 36.6297 27 34.6947 27 31.8648V28.9857H29V31.8648C29 36.1096 24.7128 39.0122 20.7717 37.4357C18.4937 36.5245 17 34.3183 17 31.8648V28.5H19Z" fill="#557FF3" />
+                    <path d="M36.5 11.5L9.5 19V28L36.5 35.5V11.5Z" fill="#8FABF9" />
+                    <path d="M36.5 27L9.5 25V28L36.5 35.5V27Z" fill="#7295F6" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M36.977 15.2856C37.0954 15.825 36.7541 16.3583 36.2146 16.4767L15.7146 20.9767C15.1752 21.0951 14.6419 20.7538 14.5235 20.2144C14.4051 19.6749 14.7464 19.1416 15.2858 19.0232L35.7858 14.5232C36.3252 14.4048 36.8585 14.7461 36.977 15.2856Z" fill="#ADC2FC" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M40.25 24C40.25 23.5858 40.5858 23.25 41 23.25H44C44.4142 23.25 44.75 23.5858 44.75 24C44.75 24.4142 44.4142 24.75 44 24.75H41C40.5858 24.75 40.25 24.4142 40.25 24Z" fill="#CCCCCC" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M39.3506 19.3751C39.1435 19.0164 39.2664 18.5577 39.6251 18.3506L42.2232 16.8506C42.5819 16.6435 43.0406 16.7664 43.2477 17.1251C43.4548 17.4838 43.3319 17.9425 42.9732 18.1496L40.3751 19.6496C40.0164 19.8567 39.5577 19.7338 39.3506 19.3751Z" fill="#CCCCCC" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M39.3506 28.6251C39.5577 28.2664 40.0164 28.1435 40.3751 28.3506L42.9732 29.8506C43.3319 30.0577 43.4548 30.5164 43.2477 30.8751C43.0406 31.2338 42.5819 31.3567 42.2232 31.1496L39.6251 29.6496C39.2664 29.4425 39.1435 28.9838 39.3506 28.6251Z" fill="#CCCCCC" />
+                    <path d="M35 11.5C35 10.6716 35.6716 10 36.5 10C37.3284 10 38 10.6716 38 11.5V35.5C38 36.3284 37.3284 37 36.5 37C35.6716 37 35 36.3284 35 35.5V11.5Z" fill="#3969EF" />
+                    <path d="M8 19C8 18.1716 8.67157 17.5 9.5 17.5C10.3284 17.5 11 18.1716 11 19V28C11 28.8284 10.3284 29.5 9.5 29.5C8.67157 29.5 8 28.8284 8 28V19Z" fill="#3969EF" />
+                </svg>
+            )}
+            {name === "AppUpdate" && (
+                <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+                    <path d="M25 39C33.2843 39 40 32.2843 40 24C40 15.7157 33.2843 9 25 9C16.7157 9 10 15.7157 10 24C10 32.2843 16.7157 39 25 39Z" fill="#399F29" />
+                    <path d="M23 9H25V39H23V9Z" fill="#399F29" />
+                    <path d="M23 39C31.2843 39 38 32.2843 38 24C38 15.7157 31.2843 9 23 9C14.7157 9 8 15.7157 8 24C8 32.2843 14.7157 39 23 39Z" fill="#4CBA3C" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M25.3389 18.8067C22.6654 17.4255 19.3882 18.4284 17.8588 21.1608L17.8531 21.1668C17.3471 22.0676 17.0999 23.0465 17.0711 24.0193C17.0596 24.5358 16.7434 24.9802 16.2662 25.1123L14.3631 25.6348C14.0296 25.7249 13.7019 25.4786 13.6674 25.1183C13.4892 23.1726 13.8686 21.1548 14.8863 19.3412C17.3873 14.8792 22.7862 13.3058 27.1041 15.708C27.2995 15.8161 27.541 15.75 27.6503 15.5518L28.3919 14.2247C28.5759 13.9004 29.0416 13.9664 29.1336 14.3327L30.4215 19.5093C30.479 19.7315 30.3525 19.9657 30.1341 20.0258L25.1952 21.377C24.8445 21.4731 24.557 21.0767 24.741 20.7524L25.4999 19.4012C25.6149 19.1911 25.5459 18.9148 25.3389 18.8067ZM20.2104 29.2678C22.9868 30.649 26.39 29.6462 27.9782 26.9137L27.9842 26.9077C28.5096 26.0069 28.7664 25.028 28.7962 24.0552C28.8082 23.5387 29.1366 23.0943 29.6321 22.9622L31.6084 22.4397C31.9547 22.3497 32.295 22.5959 32.3309 22.9562C32.5159 24.9019 32.1219 26.9197 31.0651 28.7333C28.4678 33.1953 22.8614 34.7687 18.3774 32.3666C18.1744 32.2585 17.9236 32.3245 17.8102 32.5227L17.04 33.8499C16.8489 34.1742 16.3653 34.1081 16.2698 33.7418L14.9323 28.5652C14.8726 28.343 15.004 28.1088 15.2309 28.0487L20.3597 26.6975C20.7239 26.6015 21.0224 26.9978 20.8313 27.3221L20.0432 28.6733C19.9238 28.8835 19.9955 29.1597 20.2104 29.2678Z" fill="white" />
+                </svg>
+            )}
+            {name === "CriticalUpdate" && (
+                <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+                    <path d="M34.3532 25.565C29.3703 26.1337 25.4998 30.3648 25.4998 35.4999C25.4998 36.8807 24.3805 38 22.9997 38H14.4312C11.0068 38 8.83727 34.3271 10.4901 31.328L21.0585 12.1513C21.5331 11.2902 22.2193 10.6679 22.9998 10.2846V9.82495H24.8743C26.4585 9.78177 28.0623 10.5572 28.9408 12.1513L35.3579 23.7953C35.7802 24.5615 35.2225 25.4657 34.3532 25.565Z" fill="#E2A412" />
+                    <path d="M34.3344 25.5671C29.3606 26.1444 25.4998 30.3713 25.4998 35.4999C25.4998 36.8807 24.3805 38 22.9997 38H12.4312C9.00682 38 6.83727 34.3271 8.4901 31.328L19.0585 12.1513C20.7692 9.04724 25.2301 9.04724 26.9408 12.1513L34.3344 25.5671Z" fill="#F9BE1A" />
+                    <path d="M35.5 43.5C39.9183 43.5 43.5 39.9183 43.5 35.5C43.5 31.0817 39.9183 27.5 35.5 27.5C31.0817 27.5 27.5 31.0817 27.5 35.5C27.5 39.9183 31.0817 43.5 35.5 43.5Z" fill="#4CBA3C" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M36.7474 32.7303C35.3216 31.9936 33.5737 32.5285 32.758 33.9858L32.755 33.989C32.4851 34.4694 32.3533 34.9915 32.3379 35.5104C32.3318 35.7858 32.1631 36.0228 31.9086 36.0933L30.8936 36.3719C30.7158 36.42 30.541 36.2887 30.5226 36.0965C30.4276 35.0588 30.6299 33.9826 31.1727 33.0153C32.5066 30.6356 35.386 29.7965 37.6888 31.0776C37.7931 31.1353 37.9219 31.1001 37.9801 30.9944L38.3757 30.2865C38.4738 30.1136 38.7222 30.1488 38.7713 30.3442L39.4581 33.105C39.4888 33.2235 39.4214 33.3484 39.3048 33.3805L36.6708 34.1011C36.4837 34.1524 36.3304 33.941 36.4285 33.768L36.8333 33.0474C36.8946 32.9353 36.8578 32.7879 36.7474 32.7303ZM34.0122 38.3096C35.4929 39.0462 37.308 38.5113 38.1551 37.054L38.1582 37.0508C38.4385 36.5704 38.5754 36.0483 38.5913 35.5295C38.5977 35.254 38.7728 35.017 39.0371 34.9466L40.0912 34.6679C40.2758 34.6199 40.4574 34.7512 40.4765 34.9434C40.5752 35.9811 40.365 37.0572 39.8014 38.0245C38.4162 40.4042 35.4261 41.2434 33.0346 39.9622C32.9263 39.9046 32.7926 39.9398 32.7321 40.0455L32.3213 40.7533C32.2194 40.9263 31.9615 40.891 31.9105 40.6957L31.1972 37.9348C31.1654 37.8163 31.2355 37.6914 31.3565 37.6594L34.0918 36.9387C34.2861 36.8875 34.4453 37.0989 34.3434 37.2718L33.9231 37.9925C33.8594 38.1046 33.8976 38.2519 34.0122 38.3096Z" fill="white" />
+                    <path d="M46.2507 29.5C46.3994 29.5 46.5481 29.56 46.6618 29.677C46.8892 29.9109 46.8892 30.2919 46.6618 30.5258L45.4956 31.7256C45.2682 31.9596 44.898 31.9596 44.6706 31.7256C44.4431 31.4917 44.4431 31.1107 44.6706 30.8768L45.8367 29.677C45.9505 29.56 46.0991 29.5 46.2478 29.5H46.2507Z" fill="#CCCCCC" />
+                    <path d="M45.6676 34.8991H47.4169C47.7376 34.8991 48 35.1691 48 35.499C48 35.829 47.7376 36.0989 47.4169 36.0989H45.6676C45.3469 36.0989 45.0845 35.829 45.0845 35.499C45.0845 35.1691 45.3469 34.8991 45.6676 34.8991Z" fill="#CCCCCC" />
+                    <path d="M44.6765 39.2759C44.7902 39.1589 44.9389 39.0989 45.0876 39.0989H45.0905C45.2392 39.0989 45.3879 39.1589 45.5016 39.2759L46.6678 40.4757C46.8952 40.7096 46.8952 41.0906 46.6678 41.3245C46.4403 41.5585 46.0701 41.5585 45.8427 41.3245L44.6765 40.1247C44.4491 39.8908 44.4491 39.5098 44.6765 39.2759Z" fill="#CCCCCC" />
+                    <path d="M23 34C24.1046 34 25 33.1046 25 32C25 30.8954 24.1046 30 23 30C21.8954 30 21 30.8954 21 32C21 33.1046 21.8954 34 23 34Z" fill="#92540C" />
+                    <path d="M22.5637 16C21.7108 16 21.0295 16.7103 21.065 17.5624L21.44 26.5624C21.4735 27.3659 22.1346 28 22.9387 28H23.0611C23.8653 28 24.5264 27.3659 24.5598 26.5624L24.9348 17.5624C24.9704 16.7103 24.2891 16 23.4361 16H22.5637Z" fill="#92540C" />
+                </svg>
+            )}
+            {name === "DDGAnnounce" && (
+                <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+                    <rect x="8" y="8" width="32" height="32" rx="16" fill="#DE5833" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M27.6052 38.3435C26.933 37.0366 26.2903 35.8342 25.8913 35.0388C24.8308 32.9152 23.7649 29.9212 24.2497 27.9903C24.338 27.6395 23.2508 14.9993 22.4822 14.5922C21.6279 14.1369 20.5768 13.4148 19.6154 13.2541C19.1276 13.176 18.488 13.213 17.988 13.2803C17.8992 13.2923 17.8955 13.452 17.9804 13.4808C18.3087 13.592 18.7072 13.7851 18.9421 14.077C18.9866 14.1323 18.9269 14.2192 18.856 14.2218C18.6346 14.23 18.2329 14.3228 17.703 14.773C17.6417 14.825 17.6926 14.9217 17.7715 14.9061C18.9104 14.6808 20.0736 14.7918 20.7591 15.4149C20.8036 15.4553 20.7803 15.5278 20.7223 15.5436C14.7736 17.1602 15.9512 22.3349 17.5348 28.6852C19.027 34.6686 19.7347 37.0285 19.82 37.3087C19.8257 37.3275 19.8362 37.342 19.8535 37.3514C21.0795 38.0243 27.5263 38.4328 27.2529 37.6624L27.6052 38.3435Z" fill="#DDDDDD" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M38.75 24C38.75 32.1462 32.1462 38.75 24 38.75C15.8538 38.75 9.25 32.1462 9.25 24C9.25 15.8538 15.8538 9.25 24 9.25C32.1462 9.25 38.75 15.8538 38.75 24ZM20.5608 37.0398C20.1134 35.6496 18.9707 31.9777 17.8859 27.5312C17.8485 27.3776 17.811 27.2246 17.7738 27.0724L17.7728 27.0686C16.411 21.506 15.2986 16.9627 21.3949 15.5354C21.4507 15.5223 21.4779 15.4557 21.441 15.4119C20.7416 14.5821 19.4312 14.3102 17.7744 14.8818C17.7064 14.9052 17.6474 14.8367 17.6896 14.7785C18.0145 14.3307 18.6494 13.9863 18.9629 13.8354C19.0277 13.8042 19.0237 13.7093 18.9551 13.6878C18.7501 13.6237 18.401 13.5254 18.0083 13.4621C17.9154 13.4471 17.907 13.2879 18.0003 13.2753C20.3492 12.9593 22.802 13.6645 24.0329 15.215C24.0445 15.2296 24.0612 15.2398 24.0794 15.2437C28.5867 16.2116 28.9095 23.3367 28.3902 23.6612C28.2879 23.7252 27.9598 23.6885 27.5271 23.6401C25.7733 23.4439 22.3004 23.0553 25.1667 28.3971C25.195 28.4498 25.1575 28.5197 25.0984 28.5289C23.506 28.7764 25.5552 33.7922 27.0719 37.1309C33.0379 35.7407 37.4824 30.3894 37.4824 24C37.4824 16.5539 31.4461 10.5176 24 10.5176C16.5539 10.5176 10.5176 16.5539 10.5176 24C10.5176 30.2575 14.7806 35.5194 20.5608 37.0398Z" fill="white" />
+                    <path d="M29.0913 30.703C28.7482 30.544 27.4288 31.4902 26.5532 32.2165C26.3702 31.9575 26.0251 31.7693 25.2467 31.9047C24.5655 32.0231 24.1894 32.1874 24.0216 32.4706C22.9463 32.0629 21.1374 31.4337 20.7003 32.0414C20.2226 32.7056 20.8197 35.8476 21.4542 36.2556C21.7855 36.4686 23.37 35.4501 24.1974 34.7478C24.3309 34.9359 24.5458 35.0435 24.9877 35.0333C25.6559 35.0178 26.7397 34.8623 26.9079 34.5511C26.9181 34.5322 26.9269 34.5098 26.9344 34.4844C27.7849 34.8022 29.2817 35.1386 29.6161 35.0884C30.4875 34.9575 29.4947 30.8899 29.0913 30.703Z" fill="#3CA82B" />
+                    <path d="M26.6335 32.3093C26.6696 32.3736 26.6986 32.4415 26.7233 32.5105C26.8445 32.8496 27.042 33.9283 26.8926 34.1947C26.7433 34.4612 25.7731 34.5898 25.1745 34.6002C24.576 34.6105 24.4413 34.3916 24.32 34.0525C24.2231 33.7813 24.1753 33.1435 24.1765 32.7783C24.1519 32.2367 24.3498 32.0462 25.2646 31.8982C25.9415 31.7887 26.2994 31.9161 26.506 32.1341C27.467 31.4168 29.0705 30.4046 29.2269 30.5896C30.0068 31.512 30.1053 33.7079 29.9365 34.5914C29.8813 34.8802 27.2991 34.3052 27.2991 33.9938C27.2991 32.7004 26.9635 32.3456 26.6335 32.3093Z" fill="#4CBA3C" />
+                    <path d="M20.9771 31.9054C21.1886 31.5707 22.9036 31.9869 23.8451 32.4059C23.8451 32.4059 23.6516 33.2824 23.9596 34.315C24.0497 34.617 21.7937 35.9614 21.4992 35.7301C21.1589 35.4628 20.5326 32.6089 20.9771 31.9054Z" fill="#4CBA3C" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M21.8077 25.1063C21.9465 24.5029 22.5929 23.3659 24.9011 23.3935C26.0681 23.3887 27.5176 23.393 28.4786 23.2839C29.907 23.1216 30.9672 22.7761 31.6737 22.5068C32.6729 22.1256 33.0275 22.2106 33.1518 22.4387C33.2884 22.6893 33.1274 23.1221 32.7783 23.5205C32.1114 24.2814 30.9126 24.8711 28.7952 25.0461C26.6779 25.2211 25.2751 24.6531 24.6713 25.5778C24.4109 25.9766 24.6122 26.9166 26.6598 27.2126C29.4268 27.6119 31.6992 26.7314 31.98 27.2632C32.2608 27.795 30.6434 28.8769 27.8719 28.8996C25.1005 28.9222 23.3694 27.9292 22.7556 27.4356C21.9767 26.8094 21.6282 25.8961 21.8077 25.1063Z" fill="#FFCC33" />
+                    <g opacity="0.8">
+                        <path d="M25.3372 18.5086C25.4918 18.2554 25.8346 18.0601 26.3956 18.0601C26.9565 18.0601 27.2205 18.2833 27.4032 18.5322C27.4403 18.5829 27.384 18.6425 27.3264 18.6175C27.3125 18.6115 27.2985 18.6054 27.2842 18.5992C27.079 18.5096 26.8271 18.3995 26.3956 18.3934C25.934 18.3868 25.6429 18.5024 25.4597 18.6021C25.3979 18.6356 25.3006 18.5686 25.3372 18.5086Z" fill="#14307E" />
+                        <path d="M19.0214 18.8324C19.5661 18.6048 19.9942 18.6342 20.2969 18.7058C20.3606 18.7209 20.4049 18.6523 20.3539 18.6112C20.119 18.4217 19.5933 18.1865 18.9076 18.4422C18.2959 18.6703 18.0076 19.1441 18.0059 19.4557C18.0055 19.5291 18.1565 19.5354 18.1956 19.4732C18.3012 19.3053 18.4767 19.0601 19.0214 18.8324Z" fill="#14307E" />
+                        <path fill-rule="evenodd" clip-rule="evenodd" d="M26.8721 21.9714C26.3905 21.9714 25.9999 21.5819 25.9999 21.1024C25.9999 20.623 26.3905 20.2334 26.8721 20.2334C27.3537 20.2334 27.7443 20.623 27.7443 21.1024C27.7443 21.5819 27.3537 21.9714 26.8721 21.9714ZM27.4864 20.8145C27.4864 20.6904 27.3847 20.5898 27.2605 20.5898C27.1364 20.5898 27.0358 20.6904 27.0347 20.8145C27.0347 20.9387 27.1364 21.0393 27.2605 21.0393C27.3858 21.0393 27.4864 20.9387 27.4864 20.8145Z" fill="#14307E" />
+                        <path fill-rule="evenodd" clip-rule="evenodd" d="M21.0933 21.7038C21.0933 22.2635 20.6385 22.7173 20.0766 22.7173C19.5159 22.7173 19.06 22.2635 19.06 21.7038C19.06 21.1441 19.5159 20.6904 20.0766 20.6904C20.6374 20.6904 21.0933 21.1441 21.0933 21.7038ZM20.7936 21.3678C20.7936 21.2233 20.6759 21.1056 20.5304 21.1056C20.3859 21.1056 20.2682 21.2223 20.2671 21.3678C20.2671 21.5123 20.3848 21.63 20.5304 21.63C20.6759 21.63 20.7936 21.5123 20.7936 21.3678Z" fill="#14307E" />
+                    </g>
+                </svg>
+            )}
+            {name === "PrivacyPro" && (
+                <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M27.629 9.23049C26.8 8.34395 25.7498 7.99321 24.4999 8.0001C21.2503 7.99324 21.7126 8.46165 21.0003 9.21477C19.73 10.5579 19.4795 11.283 18.3526 11.661C17.22 12.0408 15.9189 12.7539 14 12.5C11.8615 12.2171 9.02112 11.9033 9.00175 14.2896C8.94035 21.8556 10.4937 28.0976 12.7723 31.6739C15.296 35.6347 17.8011 37.6973 21.2503 39.5324C22.422 40.1559 25.4632 40.1559 26.6348 39.5323C30.084 37.6972 34.2058 35.6346 36.7294 31.6739C39.0081 28.0976 40.0589 23.1568 39.9975 15.5905C39.9781 13.2022 38.0998 11.8892 35.5646 11.8892C35.2955 11.8892 34.3346 11.8361 33.9988 11.8603C33.696 11.8821 33.9083 12.0335 33.6341 12.0349C32.6677 12.0396 31.8684 11.9194 31.1599 11.6889C30.0308 11.3214 28.9118 10.6022 27.629 9.23049Z" fill="#C18010" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M25.8311 9.237C24.3178 7.59213 21.6746 7.58847 20.1552 9.22129C18.9056 10.5641 17.8147 11.2891 16.7062 11.6669C15.5921 12.0467 14.2457 12.1488 12.3581 11.895C10.2546 11.6121 8.02155 13.2104 8.0025 15.5962C7.9421 23.1605 8.97575 28.1002 11.2172 31.6756C13.6996 35.6356 17.7541 37.6977 21.147 39.5325C22.2995 40.1559 23.7006 40.1558 24.8532 39.5324C28.246 37.6977 32.3004 35.6356 34.7828 31.6756C37.0243 28.1001 38.0579 23.1603 37.9975 15.5957C37.9784 13.2078 35.742 11.6094 33.6371 11.8951C31.7607 12.1498 30.4182 12.0633 29.3044 11.6949C28.1937 11.3275 27.0929 10.6084 25.8311 9.237Z" fill="#FFCC33" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M25.8311 9.237C24.3178 7.59213 21.6746 7.58847 20.1552 9.22129C18.9056 10.5641 17.8147 11.2891 16.7062 11.6669C15.5921 12.0467 14.2457 12.1488 12.3581 11.895C10.2546 11.6121 8.02155 13.2104 8.0025 15.5962C7.9421 23.1605 8.97575 28.1002 11.2172 31.6756C13.6996 35.6356 17.7541 37.6977 21.147 39.5325C22.2995 40.1559 23.7006 40.1558 24.8532 39.5324C28.246 37.6977 32.3004 35.6356 34.7828 31.6756C37.0243 28.1001 38.0579 23.1603 37.9975 15.5957C37.9784 13.2078 35.742 11.6094 33.6371 11.8951C31.7607 12.1498 30.4182 12.0633 29.3044 11.6949C28.1937 11.3275 27.0929 10.6084 25.8311 9.237Z" fill="#FFD65C" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M23.063 39.9995C22.4036 40.0101 21.742 39.8544 21.1468 39.5325C20.9942 39.45 20.8403 39.367 20.6853 39.2834C17.3924 37.5084 13.5878 35.4575 11.217 31.6756C8.97559 28.1002 7.94194 23.1605 8.00234 15.5962C8.02138 13.2104 10.2544 11.6121 12.3579 11.895C14.2455 12.1488 15.592 12.0467 16.7061 11.6669C17.8146 11.2891 18.9054 10.5641 20.155 9.22129C20.9125 8.40729 21.9492 8 22.986 8C23.0718 8 23.1576 8.00279 23.2432 8.00836C23.1999 8.24461 22.2612 13.4877 22.2612 23.7377C22.2612 31.3487 22.7787 37.3033 23.063 39.9995Z" fill="#FFDE7A" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.3363 37.3335L22.3361 37.3334C22.2395 37.2811 22.1429 37.229 22.0465 37.1769C18.6189 35.325 15.3476 33.5576 13.3354 30.3478C11.4696 27.3715 10.4434 23.0044 10.5024 15.6162C10.5054 15.2466 10.6669 14.9331 10.9655 14.6929C11.2889 14.4328 11.6941 14.3282 12.0249 14.3727C14.1505 14.6585 15.9152 14.5779 17.5129 14.0332C19.1172 13.4863 20.5415 12.476 21.9854 10.9244C22.5139 10.3564 23.4662 10.3589 23.9913 10.9297C25.457 12.5228 26.9015 13.5333 28.5193 14.0684C30.1176 14.5971 31.8746 14.6573 33.9733 14.3724C34.3043 14.3275 34.71 14.4318 35.0338 14.6919C35.3329 14.9321 35.4946 15.2458 35.4976 15.6157C35.5566 23.0042 34.5305 27.3714 32.6646 30.3478C30.6524 33.5577 27.3808 35.3252 23.9531 37.1771C23.8569 37.2291 23.7605 37.2812 23.664 37.3333L23.6637 37.3335C23.2533 37.5555 22.7467 37.5555 22.3363 37.3335ZM24.8532 39.5324C23.7006 40.1558 22.2995 40.1559 21.147 39.5325C20.9944 39.45 20.8405 39.367 20.6854 39.2834C17.3926 37.5084 13.588 35.4575 11.2172 31.6756C8.97575 28.1002 7.9421 23.1605 8.0025 15.5962C8.02155 13.2104 10.2546 11.6121 12.3581 11.895C14.2457 12.1488 15.5921 12.0467 16.7062 11.6669C17.8147 11.2891 18.9056 10.5641 20.1552 9.22129C21.6746 7.58847 24.3178 7.59213 25.8311 9.237C27.0929 10.6084 28.1937 11.3275 29.3044 11.6949C30.4182 12.0633 31.7607 12.1498 33.6371 11.8951C35.742 11.6094 37.9784 13.2078 37.9975 15.5957C38.0579 23.1603 37.0243 28.1001 34.7828 31.6756C32.412 35.4577 28.6071 37.5086 25.3142 39.2836C25.1594 39.3671 25.0056 39.45 24.8532 39.5324Z" fill="#E2A412" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M23.1069 39.9985C22.4331 40.0169 21.7553 39.8616 21.1469 39.5325C20.9946 39.4501 20.841 39.3673 20.6863 39.2839L20.6854 39.2834C17.3926 37.5084 13.5879 35.4575 11.2171 31.6756C8.9757 28.1002 7.94205 23.1605 8.00245 15.5962C8.0215 13.2104 10.2545 11.6121 12.3581 11.895C14.2456 12.1488 15.5921 12.0467 16.7062 11.6669C17.8147 11.2891 18.9056 10.5641 20.1551 9.22129C20.9126 8.40729 21.9493 8 22.9862 8C23.072 8 23.1579 8.00279 23.2437 8.00838C23.2311 8.09934 23.1185 8.93031 22.9845 10.5C22.6164 10.5003 22.2484 10.6417 21.9853 10.9244C20.5414 12.476 19.1171 13.4863 17.5128 14.0332C15.9152 14.5779 14.1505 14.6585 12.0249 14.3727C11.6941 14.3282 11.2888 14.4328 10.9655 14.6929C10.6668 14.9331 10.5053 15.2466 10.5024 15.6162C10.4434 23.0044 11.4695 27.3715 13.3353 30.3478C15.3475 33.5576 18.6188 35.325 22.0464 37.1769L22.0464 37.1769L22.3361 37.3334L22.3363 37.3335C22.52 37.4329 22.7229 37.4878 22.9279 37.4982C22.9926 38.5066 23.0549 39.3475 23.1069 39.9985Z" fill="#F9BE1A" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M30 23.75C30 24.7165 29.2165 25.5 28.25 25.5L17.25 25.5C16.2835 25.5 15.5 24.7165 15.5 23.75C15.5 22.7835 16.2835 22 17.25 22L28.25 22C29.2165 22 30 22.7835 30 23.75Z" fill="#F9BE1A" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.75 16.5C23.7165 16.5 24.5 17.2835 24.5 18.25V29.25C24.5 30.2165 23.7165 31 22.75 31C21.7835 31 21 30.2165 21 29.25V18.25C21 17.2835 21.7835 16.5 22.75 16.5Z" fill="#F9BE1A" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.75 16.5C23.7165 16.5 24.5 17.2835 24.5 18.25V22H28.25C29.2165 22 30 22.7835 30 23.75C30 24.7165 29.2165 25.5 28.25 25.5H24.5V29.25C24.5 30.2165 23.7165 31 22.75 31C21.7835 31 21 30.2165 21 29.25V18.25C21 17.2835 21.7835 16.5 22.75 16.5Z" fill="#E2A412" />
+                    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.6392 30.9967C21.7243 30.9395 21 30.1794 21 29.2501V25.5001H17.25C16.2836 25.5001 15.5001 24.7166 15.5001 23.7501C15.5001 22.7836 16.2836 22.0001 17.25 22.0001H21V18.2501C21 17.3226 21.7215 16.5637 22.6339 16.5039C22.5543 18.4727 22.4998 20.8048 22.4998 23.5001C22.4998 26.2544 22.5567 28.7811 22.6392 30.9967Z" fill="#F9BE1A" />
+                </svg>
+            )}
+        </>
+    )
+}
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index 59cf92a72..cad21a17b 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -1,16 +1,56 @@
-import {h} from "preact";
-import cn from "classnames";
-import styles from "./RemoteMessagingFramework.module.css"
+import { h, Fragment } from 'preact'
+import cn from 'classnames'
+import styles from './RemoteMessagingFramework.module.css'
+import MessageIcons from './MessageIcons'
+
 /**
- * 
- * @param {object} props 
+ *
+ * @param {object} props;
  */
 
-export function RemoteMessagingFramework(props) {
-    const {id, messageType, titleText, descriptionText, icon, primaryActionText = "", primaryAction, secondaryActionText = "", secondaryAction} = props;
+// icon : "Announce"|"DDGAnnounce"|"CriticalUpdate"|"AppUpdate"
+// messageType : "small"|"medium"|"big_single_action"|"big_two_action"
+
+export function RemoteMessagingFramework (props) {
+    const { id, messageType, titleText, descriptionText, icon, primaryActionText = '', primaryAction, secondaryActionText = '', secondaryAction } = props
+
+    const handlePrimaryClick = () => {
+        primaryAction()
+    }
 
+    const handleSecondaryClick = () => {
+        secondaryAction()
+    }
 
     return (
-        <div id={id} class={styles.root}>{messageType}</div>
+        <>
+            <p>
+                {messageType}
+            </p>
+            <div id={id} class={cn(styles.root, icon && styles.icon)}>
+                {icon && (
+                    <span class={styles.iconBlock}>
+                        <MessageIcons name={icon} />
+                    </span>
+                )}
+                <div class={styles.content}>
+                    <p class={styles.title}>{titleText}</p>
+                    <p>{descriptionText}</p>
+                    {messageType === 'big_two_action' && (
+                        <div className="buttonRow">
+                            {primaryActionText.length && (
+                                <button class={cn(styles.btn, styles.primary)} onClick={handlePrimaryClick}>{primaryActionText}</button>
+                            )}
+                            {secondaryActionText.length > 0 && (
+                                <button class={cn(styles.btn, styles.secondary)} onClick={handleSecondaryClick}>{secondaryActionText}</button>
+                            )}
+                        </div>
+                    )}
+                </div>
+                {messageType === 'big_single_action' && primaryActionText && primaryAction && (
+                    <button class={cn(styles.btn)} onClick={handlePrimaryClick}>{primaryActionText}</button>
+                )}
+            </div>
+        </>
     )
-}
\ No newline at end of file
+}
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
index e69de29bb..3c6b50f66 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
@@ -0,0 +1,93 @@
+.root {
+    background: var(--ntp-rmf-surface-background-color);
+    border: 1px solid var(--ntp-surface-border-color);
+    padding: 14px var(--sp-8) 14px var(--sp-4);
+    border-radius: var(--sp-3);
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+
+
+    @media screen and (prefers-color-scheme: dark) {
+        border-color: var(--color-white-at-9);
+    }
+}
+
+.icon {
+    padding-left: var(--sp-2);
+
+}
+
+.iconBlock {
+    margin-right: var(--sp-2);
+    width: var(--sp-12);
+    min-width: var(--sp-12);
+}
+
+.content {
+    display: grid;
+    gap: 8px;
+}
+
+.title {
+    font-weight: var(--title-2-font-weight);
+    line-height: var(--title-2-line-height);
+}
+
+.btn {
+    padding-left: var(--sp-3);
+    padding-right: var(--sp-3);
+    height: var(--Windows-Button-Height-Medium, 32px);
+    background-color: var(--color-black-at-6);
+    border-width: 0;
+    border-radius: 6px;
+    text-wrap: nowrap;
+
+    @media screen and (prefers-color-scheme: dark) {
+        color: var(--color-white);
+    }
+}
+
+.btn:hover {
+    background-color: var(--color-black-at-9);
+}
+
+.btn:active {
+    background-color: var(--color-black-at-12);
+}
+
+.btn:disabled {
+    color: var(--color-black-at-84);
+}
+
+.btn:disabled:hover {
+    cursor: not-allowed;
+    background-color: var(--color-white-at-6);
+}
+
+.btn:focus-visible {
+    outline: 2px solid var(--ddg-color-primary);
+    border: 1px solid white;
+}
+
+.primary {
+    background-color: var(--ddg-color-primary);
+    color: white;
+    margin-right: 10px;
+
+    @media screen and (prefers-color-scheme: dark) {
+        color: var(--color-white);
+    }
+}
+
+.primary:hover {
+    background-color: var(--color-blue-60);
+}
+
+.primary:active {
+    background-color: var(--color-blue-70);
+}
+
+.secondary {
+    margin-top: 10px;
+}
\ No newline at end of file

From e7f88e8cc1cdbd763fbe063613d0c31a477027fc Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Fri, 18 Oct 2024 21:46:29 -0600
Subject: [PATCH 04/40] chore: Add to Examples.jsx

---
 .../pages/new-tab/app/components/Examples.jsx | 58 +++++++++++++------
 1 file changed, 39 insertions(+), 19 deletions(-)

diff --git a/special-pages/pages/new-tab/app/components/Examples.jsx b/special-pages/pages/new-tab/app/components/Examples.jsx
index 630378bce..a5c2a1638 100644
--- a/special-pages/pages/new-tab/app/components/Examples.jsx
+++ b/special-pages/pages/new-tab/app/components/Examples.jsx
@@ -1,6 +1,7 @@
 import { Fragment, h } from "preact";
 import { PrivacyStatsMockProvider } from "../privacy-stats/mocks/PrivacyStatsMockProvider.js";
 import { Body, Heading, PrivacyStatsConsumer } from "../privacy-stats/PrivacyStats.js";
+import { RemoteMessagingFramework } from "../remote-messaging-framework/RemoteMessagingFramework.js";
 import { stats } from "../privacy-stats/mocks/stats.js";
 import { noop } from "../utils.js";
 import { VisibilityMenu } from "../customizer/VisibilityMenu.js";
@@ -9,42 +10,61 @@ import { CustomizerButton } from "../customizer/Customizer.js";
 /** @type {Record<string, {factory: () => import("preact").ComponentChild}>} */
 export const mainExamples = {
     'stats.few': {
-        factory: () => <PrivacyStatsMockProvider ticker={true}><PrivacyStatsConsumer/></PrivacyStatsMockProvider>
+        factory: () => <PrivacyStatsMockProvider ticker={true}><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },
     'stats.few.collapsed': {
-        factory: () => <PrivacyStatsMockProvider config={{expansion: "collapsed"}}><PrivacyStatsConsumer/></PrivacyStatsMockProvider>
+        factory: () => <PrivacyStatsMockProvider config={{ expansion: "collapsed" }}><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },
     'stats.single': {
-        factory: () => <PrivacyStatsMockProvider data={stats.single}><PrivacyStatsConsumer/></PrivacyStatsMockProvider>
+        factory: () => <PrivacyStatsMockProvider data={stats.single}><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },
     'stats.none': {
-        factory: () => <PrivacyStatsMockProvider data={stats.none}><PrivacyStatsConsumer/></PrivacyStatsMockProvider>
+        factory: () => <PrivacyStatsMockProvider data={stats.none}><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },
     'stats.norecent': {
         factory: () => <PrivacyStatsMockProvider
-            data={stats.norecent}><PrivacyStatsConsumer/></PrivacyStatsMockProvider>
+            data={stats.norecent}><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },
     'stats.list': {
-        factory: () => <Body trackerCompanies={stats.few.trackerCompanies} listAttrs={{id: 'example-stats.list'}}/>
+        factory: () => <Body trackerCompanies={stats.few.trackerCompanies} id='example-stats.list' />
     },
     'stats.heading': {
-        factory: () => <Heading
-            trackerCompanies={stats.few.trackerCompanies}
-            totalCount={stats.few.totalCount}
-            expansion={"expanded"}
-            onToggle={noop("stats.heading onToggle")}
-        />
+        factory: () => <Heading trackerCompanies={stats.few.trackerCompanies} totalCount={stats.few.totalCount} />
     },
     'stats.heading.none': {
+        factory: () => <Heading trackerCompanies={stats.none.trackerCompanies} totalCount={stats.none.totalCount} />
+    },
+    'rmf-small': {
+        factory: () => (
+            <RemoteMessagingFramework
+                messageType="small"
+                title="Update Available"
+                descriptionText="A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
+            />
+        )
+    },
+    'rmf-medium': {
         factory: () => (
-            <Heading
-                trackerCompanies={stats.none.trackerCompanies}
-                totalCount={stats.none.totalCount}
-                expansion={"expanded"}
-                onToggle={noop("stats.heading.none")}
+            <RemoteMessagingFramework
+                messageType="medium"
+                icon="Announce"
+                title="Tell Us Your Thoughts on Privacy Pro"
+                descriptionText="A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
             />
         )
     },
+    'rmf-big-single-action': {
+        factory: () => (
+            <RemoteMessagingFramework
+                messageType="big-single-action"
+                icon="DDGAnnounce"
+                title="New Search Feature!"
+                descriptionText="DuckDuckGo now offers Instant Answers for quicker access to the information you need."
+                primaryAction={() => { }}
+                primaryActionText="Learn More"
+            />
+        )
+    }
 }
 
 export const otherExamples = {
@@ -55,7 +75,7 @@ export const otherExamples = {
                 expansion: "expanded",
                 animation: {kind: "none"}
             }}
-        ><PrivacyStatsConsumer/></PrivacyStatsMockProvider>
+        ><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },
     'stats.with-view-transitions': {
         factory: () => <PrivacyStatsMockProvider
@@ -64,7 +84,7 @@ export const otherExamples = {
                 expansion: "expanded",
                 animation: {kind: "view-transitions"}
             }}
-        ><PrivacyStatsConsumer/></PrivacyStatsMockProvider>
+        ><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },
     'customizer-menu': {
         factory: () => (

From 3d4934b2fdf4c66d5e8eab6fda2405dccedf261e Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Fri, 18 Oct 2024 21:52:06 -0600
Subject: [PATCH 05/40] chore: Add to Examples.jsx

---
 .../pages/new-tab/app/components/Examples.jsx          | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/special-pages/pages/new-tab/app/components/Examples.jsx b/special-pages/pages/new-tab/app/components/Examples.jsx
index a5c2a1638..ca8a607b1 100644
--- a/special-pages/pages/new-tab/app/components/Examples.jsx
+++ b/special-pages/pages/new-tab/app/components/Examples.jsx
@@ -13,7 +13,7 @@ export const mainExamples = {
         factory: () => <PrivacyStatsMockProvider ticker={true}><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },
     'stats.few.collapsed': {
-        factory: () => <PrivacyStatsMockProvider config={{ expansion: "collapsed" }}><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
+        factory: () => <PrivacyStatsMockProvider config={{ expansion: 'collapsed' }}><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },
     'stats.single': {
         factory: () => <PrivacyStatsMockProvider data={stats.single}><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
@@ -72,8 +72,8 @@ export const otherExamples = {
         factory: () => <PrivacyStatsMockProvider
             ticker={true}
             config={{
-                expansion: "expanded",
-                animation: {kind: "none"}
+                expansion: 'expanded',
+                animation: { kind: 'none' }
             }}
         ><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },
@@ -81,8 +81,8 @@ export const otherExamples = {
         factory: () => <PrivacyStatsMockProvider
             ticker={true}
             config={{
-                expansion: "expanded",
-                animation: {kind: "view-transitions"}
+                expansion: 'expanded',
+                animation: { kind: 'view-transitions' }
             }}
         ><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },

From 2568b706c06e5135ed6d4c4c0a18619f499357aa Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Fri, 18 Oct 2024 21:57:36 -0600
Subject: [PATCH 06/40] chore: Fix styles ref

---
 .../RemoteMessagingFramework.module.css                          | 1 +
 1 file changed, 1 insertion(+)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
index 3c6b50f66..15724dc15 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
@@ -1,4 +1,5 @@
 .root {
+    --ntp-rmf-surface-background-color: rgba(0, 0, 0, .06);
     background: var(--ntp-rmf-surface-background-color);
     border: 1px solid var(--ntp-surface-border-color);
     padding: 14px var(--sp-8) 14px var(--sp-4);

From a8738957882af6cc246ed97852afb77eaea539de Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Fri, 18 Oct 2024 21:59:33 -0600
Subject: [PATCH 07/40] fix: MessageIcon lint

---
 .../app/remote-messaging-framework/MessageIcons.js     | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js b/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js
index 058cccf85..2f4f7d144 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js
@@ -1,6 +1,6 @@
 import { h, Fragment } from 'preact'
 
-export default function MessageIcons(props) {
+export default function MessageIcons (props) {
     const { name } = props
     return (
         <>
@@ -17,7 +17,7 @@ export default function MessageIcons(props) {
                     <path d="M8 19C8 18.1716 8.67157 17.5 9.5 17.5C10.3284 17.5 11 18.1716 11 19V28C11 28.8284 10.3284 29.5 9.5 29.5C8.67157 29.5 8 28.8284 8 28V19Z" fill="#3969EF" />
                 </svg>
             )}
-            {name === "AppUpdate" && (
+            {name === 'AppUpdate' && (
                 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
                     <path d="M25 39C33.2843 39 40 32.2843 40 24C40 15.7157 33.2843 9 25 9C16.7157 9 10 15.7157 10 24C10 32.2843 16.7157 39 25 39Z" fill="#399F29" />
                     <path d="M23 9H25V39H23V9Z" fill="#399F29" />
@@ -25,7 +25,7 @@ export default function MessageIcons(props) {
                     <path fill-rule="evenodd" clip-rule="evenodd" d="M25.3389 18.8067C22.6654 17.4255 19.3882 18.4284 17.8588 21.1608L17.8531 21.1668C17.3471 22.0676 17.0999 23.0465 17.0711 24.0193C17.0596 24.5358 16.7434 24.9802 16.2662 25.1123L14.3631 25.6348C14.0296 25.7249 13.7019 25.4786 13.6674 25.1183C13.4892 23.1726 13.8686 21.1548 14.8863 19.3412C17.3873 14.8792 22.7862 13.3058 27.1041 15.708C27.2995 15.8161 27.541 15.75 27.6503 15.5518L28.3919 14.2247C28.5759 13.9004 29.0416 13.9664 29.1336 14.3327L30.4215 19.5093C30.479 19.7315 30.3525 19.9657 30.1341 20.0258L25.1952 21.377C24.8445 21.4731 24.557 21.0767 24.741 20.7524L25.4999 19.4012C25.6149 19.1911 25.5459 18.9148 25.3389 18.8067ZM20.2104 29.2678C22.9868 30.649 26.39 29.6462 27.9782 26.9137L27.9842 26.9077C28.5096 26.0069 28.7664 25.028 28.7962 24.0552C28.8082 23.5387 29.1366 23.0943 29.6321 22.9622L31.6084 22.4397C31.9547 22.3497 32.295 22.5959 32.3309 22.9562C32.5159 24.9019 32.1219 26.9197 31.0651 28.7333C28.4678 33.1953 22.8614 34.7687 18.3774 32.3666C18.1744 32.2585 17.9236 32.3245 17.8102 32.5227L17.04 33.8499C16.8489 34.1742 16.3653 34.1081 16.2698 33.7418L14.9323 28.5652C14.8726 28.343 15.004 28.1088 15.2309 28.0487L20.3597 26.6975C20.7239 26.6015 21.0224 26.9978 20.8313 27.3221L20.0432 28.6733C19.9238 28.8835 19.9955 29.1597 20.2104 29.2678Z" fill="white" />
                 </svg>
             )}
-            {name === "CriticalUpdate" && (
+            {name === 'CriticalUpdate' && (
                 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
                     <path d="M34.3532 25.565C29.3703 26.1337 25.4998 30.3648 25.4998 35.4999C25.4998 36.8807 24.3805 38 22.9997 38H14.4312C11.0068 38 8.83727 34.3271 10.4901 31.328L21.0585 12.1513C21.5331 11.2902 22.2193 10.6679 22.9998 10.2846V9.82495H24.8743C26.4585 9.78177 28.0623 10.5572 28.9408 12.1513L35.3579 23.7953C35.7802 24.5615 35.2225 25.4657 34.3532 25.565Z" fill="#E2A412" />
                     <path d="M34.3344 25.5671C29.3606 26.1444 25.4998 30.3713 25.4998 35.4999C25.4998 36.8807 24.3805 38 22.9997 38H12.4312C9.00682 38 6.83727 34.3271 8.4901 31.328L19.0585 12.1513C20.7692 9.04724 25.2301 9.04724 26.9408 12.1513L34.3344 25.5671Z" fill="#F9BE1A" />
@@ -38,7 +38,7 @@ export default function MessageIcons(props) {
                     <path d="M22.5637 16C21.7108 16 21.0295 16.7103 21.065 17.5624L21.44 26.5624C21.4735 27.3659 22.1346 28 22.9387 28H23.0611C23.8653 28 24.5264 27.3659 24.5598 26.5624L24.9348 17.5624C24.9704 16.7103 24.2891 16 23.4361 16H22.5637Z" fill="#92540C" />
                 </svg>
             )}
-            {name === "DDGAnnounce" && (
+            {name === 'DDGAnnounce' && (
                 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
                     <rect x="8" y="8" width="32" height="32" rx="16" fill="#DE5833" />
                     <path fill-rule="evenodd" clip-rule="evenodd" d="M27.6052 38.3435C26.933 37.0366 26.2903 35.8342 25.8913 35.0388C24.8308 32.9152 23.7649 29.9212 24.2497 27.9903C24.338 27.6395 23.2508 14.9993 22.4822 14.5922C21.6279 14.1369 20.5768 13.4148 19.6154 13.2541C19.1276 13.176 18.488 13.213 17.988 13.2803C17.8992 13.2923 17.8955 13.452 17.9804 13.4808C18.3087 13.592 18.7072 13.7851 18.9421 14.077C18.9866 14.1323 18.9269 14.2192 18.856 14.2218C18.6346 14.23 18.2329 14.3228 17.703 14.773C17.6417 14.825 17.6926 14.9217 17.7715 14.9061C18.9104 14.6808 20.0736 14.7918 20.7591 15.4149C20.8036 15.4553 20.7803 15.5278 20.7223 15.5436C14.7736 17.1602 15.9512 22.3349 17.5348 28.6852C19.027 34.6686 19.7347 37.0285 19.82 37.3087C19.8257 37.3275 19.8362 37.342 19.8535 37.3514C21.0795 38.0243 27.5263 38.4328 27.2529 37.6624L27.6052 38.3435Z" fill="#DDDDDD" />
@@ -55,7 +55,7 @@ export default function MessageIcons(props) {
                     </g>
                 </svg>
             )}
-            {name === "PrivacyPro" && (
+            {name === 'PrivacyPro' && (
                 <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
                     <path fill-rule="evenodd" clip-rule="evenodd" d="M27.629 9.23049C26.8 8.34395 25.7498 7.99321 24.4999 8.0001C21.2503 7.99324 21.7126 8.46165 21.0003 9.21477C19.73 10.5579 19.4795 11.283 18.3526 11.661C17.22 12.0408 15.9189 12.7539 14 12.5C11.8615 12.2171 9.02112 11.9033 9.00175 14.2896C8.94035 21.8556 10.4937 28.0976 12.7723 31.6739C15.296 35.6347 17.8011 37.6973 21.2503 39.5324C22.422 40.1559 25.4632 40.1559 26.6348 39.5323C30.084 37.6972 34.2058 35.6346 36.7294 31.6739C39.0081 28.0976 40.0589 23.1568 39.9975 15.5905C39.9781 13.2022 38.0998 11.8892 35.5646 11.8892C35.2955 11.8892 34.3346 11.8361 33.9988 11.8603C33.696 11.8821 33.9083 12.0335 33.6341 12.0349C32.6677 12.0396 31.8684 11.9194 31.1599 11.6889C30.0308 11.3214 28.9118 10.6022 27.629 9.23049Z" fill="#C18010" />
                     <path fill-rule="evenodd" clip-rule="evenodd" d="M25.8311 9.237C24.3178 7.59213 21.6746 7.58847 20.1552 9.22129C18.9056 10.5641 17.8147 11.2891 16.7062 11.6669C15.5921 12.0467 14.2457 12.1488 12.3581 11.895C10.2546 11.6121 8.02155 13.2104 8.0025 15.5962C7.9421 23.1605 8.97575 28.1002 11.2172 31.6756C13.6996 35.6356 17.7541 37.6977 21.147 39.5325C22.2995 40.1559 23.7006 40.1558 24.8532 39.5324C28.246 37.6977 32.3004 35.6356 34.7828 31.6756C37.0243 28.1001 38.0579 23.1603 37.9975 15.5957C37.9784 13.2078 35.742 11.6094 33.6371 11.8951C31.7607 12.1498 30.4182 12.0633 29.3044 11.6949C28.1937 11.3275 27.0929 10.6084 25.8311 9.237Z" fill="#FFCC33" />

From b20cdc542904ed6edd9dc91f0ddd1d4720a7d19a Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Sun, 20 Oct 2024 20:58:55 -0600
Subject: [PATCH 08/40] chore: Improve the RMF component

---
 .../pages/new-tab/app/components/Examples.jsx | 42 +++++++++--
 .../RemoteMessagingFramework.js               | 73 +++++++++----------
 2 files changed, 69 insertions(+), 46 deletions(-)

diff --git a/special-pages/pages/new-tab/app/components/Examples.jsx b/special-pages/pages/new-tab/app/components/Examples.jsx
index ca8a607b1..66eae0f7f 100644
--- a/special-pages/pages/new-tab/app/components/Examples.jsx
+++ b/special-pages/pages/new-tab/app/components/Examples.jsx
@@ -34,36 +34,50 @@ export const mainExamples = {
     'stats.heading.none': {
         factory: () => <Heading trackerCompanies={stats.none.trackerCompanies} totalCount={stats.none.totalCount} />
     },
-    'rmf-small': {
+    'rmf.small': {
         factory: () => (
             <RemoteMessagingFramework
                 messageType="small"
-                title="Update Available"
+                titleText="Update Available"
                 descriptionText="A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
             />
         )
     },
-    'rmf-medium': {
+    'rmf.medium': {
         factory: () => (
             <RemoteMessagingFramework
                 messageType="medium"
                 icon="Announce"
-                title="Tell Us Your Thoughts on Privacy Pro"
+                titleText="Tell Us Your Thoughts on Privacy Pro"
                 descriptionText="A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
             />
         )
     },
-    'rmf-big-single-action': {
+    'rmf.big-single-action': {
         factory: () => (
             <RemoteMessagingFramework
-                messageType="big-single-action"
+                messageType="big_single_action"
                 icon="DDGAnnounce"
-                title="New Search Feature!"
+                titleText="New Search Feature!"
                 descriptionText="DuckDuckGo now offers Instant Answers for quicker access to the information you need."
                 primaryAction={() => { }}
                 primaryActionText="Learn More"
             />
         )
+    },
+    'rmf.big-two-action': {
+        factory: () => (
+            <RemoteMessagingFramework
+                messageType="big_two_action"
+                icon="AppUpdate"
+                titleText="Update Available"
+                descriptionText="A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
+                primaryAction={() => { }}
+                primaryActionText="How to update"
+                secondaryAction={() => { }}
+                secondaryActionText="Remind me later"
+            />
+        )
     }
 }
 
@@ -86,6 +100,20 @@ export const otherExamples = {
             }}
         ><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },
+    'rmf.big-two-action-overflow': {
+        factory: () => (
+            <RemoteMessagingFramework
+                messageType="big_two_action"
+                icon="CriticalUpdate"
+                titleText="Update Available"
+                descriptionText="A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance. A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
+                primaryAction={() => { }}
+                primaryActionText="How to update Windows"
+                secondaryAction={() => { }}
+                secondaryActionText="Remind me later, but only if Iā€™m actually going to update soon"
+            />
+        )
+    },
     'customizer-menu': {
         factory: () => (
             <Fragment>
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index cad21a17b..43c444a47 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -6,51 +6,46 @@ import MessageIcons from './MessageIcons'
 /**
  *
  * @param {object} props;
+ * @param {string} props.id
+ * @param {'small'|'medium'|'big_single_action'|'big_two_action'} props.messageType
+ * @param {string} props.titleText
+ * @param {string} props.descriptionText
+ * @param {"Announce"|"DDGAnnounce"|"CriticalUpdate"|"AppUpdate"|"PrivacyPro"} [props.icon]
+ * @param {string} [props.primaryActionText]
+ * @param {function} [props.primaryAction]
+ * @param {string} [props.secondaryActionText]
+ * @param {function} [props.secondaryAction]
  */
 
-// icon : "Announce"|"DDGAnnounce"|"CriticalUpdate"|"AppUpdate"
-// messageType : "small"|"medium"|"big_single_action"|"big_two_action"
+export function RemoteMessagingFramework({ id, messageType, titleText, descriptionText, icon, primaryActionText = '', primaryAction, secondaryActionText = '', secondaryAction }) {
 
-export function RemoteMessagingFramework (props) {
-    const { id, messageType, titleText, descriptionText, icon, primaryActionText = '', primaryAction, secondaryActionText = '', secondaryAction } = props
-
-    const handlePrimaryClick = () => {
-        primaryAction()
-    }
-
-    const handleSecondaryClick = () => {
-        secondaryAction()
-    }
 
     return (
-        <>
-            <p>
-                {messageType}
-            </p>
-            <div id={id} class={cn(styles.root, icon && styles.icon)}>
-                {icon && (
-                    <span class={styles.iconBlock}>
-                        <MessageIcons name={icon} />
-                    </span>
-                )}
-                <div class={styles.content}>
-                    <p class={styles.title}>{titleText}</p>
-                    <p>{descriptionText}</p>
-                    {messageType === 'big_two_action' && (
-                        <div className="buttonRow">
-                            {primaryActionText.length && (
-                                <button class={cn(styles.btn, styles.primary)} onClick={handlePrimaryClick}>{primaryActionText}</button>
-                            )}
-                            {secondaryActionText.length > 0 && (
-                                <button class={cn(styles.btn, styles.secondary)} onClick={handleSecondaryClick}>{secondaryActionText}</button>
-                            )}
-                        </div>
-                    )}
-                </div>
-                {messageType === 'big_single_action' && primaryActionText && primaryAction && (
-                    <button class={cn(styles.btn)} onClick={handlePrimaryClick}>{primaryActionText}</button>
+
+        <div id={id} class={cn(styles.root, icon && styles.icon)}>
+            {icon && (
+                <span class={styles.iconBlock}>
+                    <MessageIcons name={icon} />
+                </span>
+            )}
+            <div class={styles.content}>
+                <p class={styles.title}>{titleText}</p>
+                <p>{descriptionText}</p>
+                {messageType === 'big_two_action' && (
+                    <div className="buttonRow">
+                        {primaryActionText.length && (
+                            <button class={cn(styles.btn, styles.primary)} onClick={primaryAction}>{primaryActionText}</button>
+                        )}
+                        {secondaryActionText.length > 0 && (
+                            <button class={cn(styles.btn, styles.secondary)} onClick={secondaryAction}>{secondaryActionText}</button>
+                        )}
+                    </div>
                 )}
             </div>
-        </>
+            {messageType === 'big_single_action' && primaryActionText && primaryAction && (
+                <button class={cn(styles.btn)} onClick={primaryAction}>{primaryActionText}</button>
+            )}
+        </div>
+
     )
 }

From 7be2081d56d41877561651f2b28638e08d43d070 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Sun, 20 Oct 2024 21:04:21 -0600
Subject: [PATCH 09/40] fix: Lint

---
 .../remote-messaging-framework/RemoteMessagingFramework.js | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index 43c444a47..d0d5163dd 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -1,4 +1,4 @@
-import { h, Fragment } from 'preact'
+import { h } from 'preact'
 import cn from 'classnames'
 import styles from './RemoteMessagingFramework.module.css'
 import MessageIcons from './MessageIcons'
@@ -17,11 +17,8 @@ import MessageIcons from './MessageIcons'
  * @param {function} [props.secondaryAction]
  */
 
-export function RemoteMessagingFramework({ id, messageType, titleText, descriptionText, icon, primaryActionText = '', primaryAction, secondaryActionText = '', secondaryAction }) {
-
-
+export function RemoteMessagingFramework ({ id, messageType, titleText, descriptionText, icon, primaryActionText = '', primaryAction, secondaryActionText = '', secondaryAction }) {
     return (
-
         <div id={id} class={cn(styles.root, icon && styles.icon)}>
             {icon && (
                 <span class={styles.iconBlock}>

From 9b920681d884142fa4dd5b3c2e37bd15824f1036 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Sun, 20 Oct 2024 21:20:26 -0600
Subject: [PATCH 10/40] chore: Incorporate the stuff from #1140 that make sense

---
 .../remote-messaging-framework/RemoteMessagingFramework.js    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index d0d5163dd..f01220a84 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -12,9 +12,9 @@ import MessageIcons from './MessageIcons'
  * @param {string} props.descriptionText
  * @param {"Announce"|"DDGAnnounce"|"CriticalUpdate"|"AppUpdate"|"PrivacyPro"} [props.icon]
  * @param {string} [props.primaryActionText]
- * @param {function} [props.primaryAction]
+ * @param {() => void} [props.primaryAction]
  * @param {string} [props.secondaryActionText]
- * @param {function} [props.secondaryAction]
+ * @param {() => void} [props.secondaryAction]
  */
 
 export function RemoteMessagingFramework ({ id, messageType, titleText, descriptionText, icon, primaryActionText = '', primaryAction, secondaryActionText = '', secondaryAction }) {

From e23c087021f224f3194c3f8db0f590cf9d7742d5 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Sun, 20 Oct 2024 21:20:46 -0600
Subject: [PATCH 11/40] fix: All the stuff i meant to commit last time

---
 .../new-tab/rmf_onDataUpdate.subscribe.json   |   8 +
 .../messages/new-tab/types/rmf-message.json   | 137 ++++++++++++++++++
 special-pages/types/new-tab.ts                |  12 +-
 3 files changed, 151 insertions(+), 6 deletions(-)
 create mode 100644 special-pages/messages/new-tab/rmf_onDataUpdate.subscribe.json
 create mode 100644 special-pages/messages/new-tab/types/rmf-message.json

diff --git a/special-pages/messages/new-tab/rmf_onDataUpdate.subscribe.json b/special-pages/messages/new-tab/rmf_onDataUpdate.subscribe.json
new file mode 100644
index 000000000..fc14a4c00
--- /dev/null
+++ b/special-pages/messages/new-tab/rmf_onDataUpdate.subscribe.json
@@ -0,0 +1,8 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema#",
+    "allOf": [
+        {
+            "$ref": "types/rmf-message.json"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/special-pages/messages/new-tab/types/rmf-message.json b/special-pages/messages/new-tab/types/rmf-message.json
new file mode 100644
index 000000000..43128d1e2
--- /dev/null
+++ b/special-pages/messages/new-tab/types/rmf-message.json
@@ -0,0 +1,137 @@
+"$schema": "http://json-schema.org/draft-07/schema#",
+"type": "object",
+"required": [
+    "content"
+],
+"properties": {
+    "content": {
+        "title": "RMF Message",
+        "oneOf": [
+            {
+                "title": "Small Message",
+                "type": "object",
+                "properties": {
+                    "messageType": {
+                        "const": "small"
+                    },
+                    "id": {
+                        "type": "string"
+                    },
+                    "titleText": {
+                        "type": "string"
+                    },
+                    "descriptionText": {
+                        "type": "string"
+                    }
+                },
+                "required": [
+                    "messageType",
+                    "id",
+                    "titleText",
+                    "descriptionText"
+                ]
+            },
+            {
+                "title": "Medium Message",
+                "type": "object",
+                "properties": {
+                    "messageType": {
+                        "const": "medium"
+                    },
+                    "id": {
+                        "type": "string"
+                    },
+                    "titleText": {
+                        "type": "string"
+                    },
+                    "descriptionText": {
+                        "type": "string"
+                    },
+                    "icon": {
+                        "type": "string"
+                    }
+                },
+                "required": [
+                    "messageType",
+                    "id",
+                    "titleText",
+                    "descriptionText",
+                    "icon"
+                ]
+            },
+            {
+                "title": "Big Single Action Message",
+                "type": "object",
+                "properties": {
+                    "messageType": {
+                        "const": "big_single_action"
+                    },
+                    "id": {
+                        "type": "string"
+                    },
+                    "titleText": {
+                        "type": "string"
+                    },
+                    "descriptionText": {
+                        "type": "string"
+                    },
+                    "icon": {
+                        "type": "string"
+                    },
+                    "primaryActionText": {
+                        "type": "string"
+                    },
+                    "primaryAction": {
+                        "type": () => void
+                    }
+                },
+                "required": [
+                    "messageType",
+                    "id",
+                    "titleText",
+                    "descriptionText",
+                    "icon",
+                    "primaryActionText",
+                    "primaryAction"
+                ]
+            },
+            {
+                "title": "Big Two Action Message",
+                "type": "object",
+                "properties": {
+                    "messageType": {
+                        "const": "big_two_action"
+                    },
+                    "id": {
+                        "type": "string"
+                    },
+                    "titleText": {
+                        "type": "string"
+                    },
+                    "descriptionText": {
+                        "type": "string"
+                    },
+                    "icon": {
+                        "type": "string"
+                    },
+                    "primaryActionText": {
+                        "type": "string"
+                    },
+                    "secondaryActionText": {
+                        "type": "string"
+                    }
+                },
+                "required": [
+                    "messageType",
+                    "id",
+                    "titleText",
+                    "descriptionText",
+                    "icon",
+                    "primaryActionText",
+                    "secondaryActionText"
+                ]
+            }
+        ]
+    }
+}
+}
\ No newline at end of file
diff --git a/special-pages/types/new-tab.ts b/special-pages/types/new-tab.ts
index a4c64aef1..564be1065 100644
--- a/special-pages/types/new-tab.ts
+++ b/special-pages/types/new-tab.ts
@@ -26,18 +26,18 @@ export type WidgetConfigs = WidgetConfigItem[];
  * An ordered list of supported Widgets. Use this to communicate what's supported
  */
 export type Widgets = WidgetListItem[];
-
+export type RMFMessage = SmallMessage | MediumMessage | BigSingleActionMessage | BigTwoActionMessage;
 /**
  * Requests, Notifications and Subscriptions from the NewTab feature
  */
 export interface NewTabMessages {
   notifications:
-    | ReportInitExceptionNotification
-    | ReportPageExceptionNotification
-    | StatsSetConfigNotification
-    | WidgetsSetConfigNotification;
+  | ReportInitExceptionNotification
+  | ReportPageExceptionNotification
+  | StatsSetConfigNotification
+  | WidgetsSetConfigNotification;
   requests: InitialSetupRequest | StatsGetConfigRequest | StatsGetDataRequest;
-  subscriptions: StatsOnConfigUpdateSubscription | StatsOnDataUpdateSubscription | WidgetsOnConfigUpdatedSubscription;
+  subscriptions: RmfOnDataUpdateSubscription | StatsOnConfigUpdateSubscription | StatsOnDataUpdateSubscription | WidgetsOnConfigUpdatedSubscription;
 }
 /**
  * Generated from @see "../messages/new-tab/reportInitException.notify.json"

From f92498e21c0e89eed702a9c4f73dad2ced558dd2 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Sun, 20 Oct 2024 22:27:22 -0600
Subject: [PATCH 12/40] chore: Add more of 1140 solution with small edits

---
 .../messages/new-tab/types/rmf-message.json   |   4 -
 .../pages/new-tab/app/components/Examples.jsx | 109 ++++++++++--------
 .../MessageIcons.js                           |   9 +-
 .../RemoteMessagingFramework.js               |  39 +++----
 4 files changed, 86 insertions(+), 75 deletions(-)

diff --git a/special-pages/messages/new-tab/types/rmf-message.json b/special-pages/messages/new-tab/types/rmf-message.json
index 43128d1e2..13bf618c7 100644
--- a/special-pages/messages/new-tab/types/rmf-message.json
+++ b/special-pages/messages/new-tab/types/rmf-message.json
@@ -80,9 +80,6 @@
                     },
                     "primaryActionText": {
                         "type": "string"
-                    },
-                    "primaryAction": {
-                        "type": () => void
                     }
                 },
                 "required": [
@@ -92,7 +89,6 @@
                     "descriptionText",
                     "icon",
                     "primaryActionText",
-                    "primaryAction"
                 ]
             },
             {
diff --git a/special-pages/pages/new-tab/app/components/Examples.jsx b/special-pages/pages/new-tab/app/components/Examples.jsx
index 66eae0f7f..cf97df566 100644
--- a/special-pages/pages/new-tab/app/components/Examples.jsx
+++ b/special-pages/pages/new-tab/app/components/Examples.jsx
@@ -37,48 +37,60 @@ export const mainExamples = {
     'rmf.small': {
         factory: () => (
             <RemoteMessagingFramework
-                messageType="small"
-                titleText="Update Available"
-                descriptionText="A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
-            />
-        )
-    },
-    'rmf.medium': {
-        factory: () => (
-            <RemoteMessagingFramework
-                messageType="medium"
-                icon="Announce"
-                titleText="Tell Us Your Thoughts on Privacy Pro"
-                descriptionText="A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
-            />
-        )
-    },
-    'rmf.big-single-action': {
-        factory: () => (
-            <RemoteMessagingFramework
-                messageType="big_single_action"
-                icon="DDGAnnounce"
-                titleText="New Search Feature!"
-                descriptionText="DuckDuckGo now offers Instant Answers for quicker access to the information you need."
-                primaryAction={() => { }}
-                primaryActionText="Learn More"
-            />
+                message={
+                    id: "small",
+        messageType: "small",
+        titleText: "Update Available",
+        descriptionText: "A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
+    }
+        />
         )
     },
-    'rmf.big-two-action': {
-        factory: () => (
-            <RemoteMessagingFramework
-                messageType="big_two_action"
-                icon="AppUpdate"
-                titleText="Update Available"
-                descriptionText="A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
-                primaryAction={() => { }}
-                primaryActionText="How to update"
-                secondaryAction={() => { }}
-                secondaryActionText="Remind me later"
-            />
-        )
-    }
+'rmf.medium': {
+    factory: () => (
+        <RemoteMessagingFramework
+            message={
+                id:"medium",
+                    messageType: "medium",
+                        icon: "Announce",
+                            titleText: "Tell Us Your Thoughts on Privacy Pro",
+                                descriptionText: "A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
+}
+        />
+    )
+},
+'rmf.big-single-action': {
+    factory: () => (
+        <RemoteMessagingFramework
+            message={
+                id:"big-single",
+                    messageType: "big_single_action",
+                        icon: "DDGAnnounce",
+                            titleText: "New Search Feature!",
+                                descriptionText: "DuckDuckGo now offers Instant Answers for quicker access to the information you need.",
+                                    primaryActionText: "Learn More",
+            }
+primaryAction = {() => { }}
+        />
+    )
+},
+'rmf.big-two-action': {
+    factory: () => (
+        <RemoteMessagingFramework
+            message={
+                id:"big-two",
+                    messageType: "big_two_action",
+                        icon: "AppUpdate",
+                            titleText: "Update Available",
+                                descriptionText: "A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.",
+                                    primaryActionText: "How to update",
+                                        secondaryActionText: "Remind me later",
+            }
+primaryAction = {() => { }}
+secondaryAction = {() => { }}
+        />
+    )
+}
 }
 
 export const otherExamples = {
@@ -103,14 +115,17 @@ export const otherExamples = {
     'rmf.big-two-action-overflow': {
         factory: () => (
             <RemoteMessagingFramework
-                messageType="big_two_action"
-                icon="CriticalUpdate"
-                titleText="Update Available"
-                descriptionText="A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance. A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
+                message={
+                    id: "big-two-overflow",
+        messageType: "big_two_action",
+        icon: "CriticalUpdate",
+        titleText: "Update Available",
+        descriptionText: "A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance. A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.",
+        primaryActionText: "How to update Windows",
+        secondaryActionText: "Remind me later, but only if Iā€™m actually going to update soon",
+    }
                 primaryAction={() => { }}
-                primaryActionText="How to update Windows"
-                secondaryAction={() => { }}
-                secondaryActionText="Remind me later, but only if Iā€™m actually going to update soon"
+secondaryAction = {() => { }}
             />
         )
     },
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js b/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js
index 2f4f7d144..7b064a5bf 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js
@@ -1,7 +1,12 @@
 import { h, Fragment } from 'preact'
 
-export default function MessageIcons (props) {
-    const { name } = props
+/**
+ *
+ * @param {object} props;
+ * @param {"Announce"|"DDGAnnounce"|"CriticalUpdate"|"AppUpdate"|"PrivacyPro"} [props.name]
+ */
+
+export default function MessageIcons ({ name }) {
     return (
         <>
             {name === 'Announce' && (
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index f01220a84..1715dc2de 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -4,25 +4,20 @@ import styles from './RemoteMessagingFramework.module.css'
 import MessageIcons from './MessageIcons'
 
 /**
- *
- * @param {object} props;
- * @param {string} props.id
- * @param {'small'|'medium'|'big_single_action'|'big_two_action'} props.messageType
- * @param {string} props.titleText
- * @param {string} props.descriptionText
- * @param {"Announce"|"DDGAnnounce"|"CriticalUpdate"|"AppUpdate"|"PrivacyPro"} [props.icon]
- * @param {string} [props.primaryActionText]
- * @param {() => void} [props.primaryAction]
- * @param {string} [props.secondaryActionText]
- * @param {() => void} [props.secondaryAction]
- */
+  * @import { RMFMessage } from "../../../../types/new-tab"
+  * @param {object} props
+  * @param {RMFMessage} props.message
+  * @param {() => void} [props.primaryAction]
+  * @param {() => void} [props.secondaryAction]
+  */
 
-export function RemoteMessagingFramework ({ id, messageType, titleText, descriptionText, icon, primaryActionText = '', primaryAction, secondaryActionText = '', secondaryAction }) {
+export function RemoteMessagingFramework ({ message, primaryAction, secondaryAction }) {
+    const { id, messageType, titleText, descriptionText } = message
     return (
-        <div id={id} class={cn(styles.root, icon && styles.icon)}>
-            {icon && (
+        <div id={id} class={cn(styles.root, message.icon && styles.icon)}>
+            {message.icon && (
                 <span class={styles.iconBlock}>
-                    <MessageIcons name={icon} />
+                    <MessageIcons name={message.icon} />
                 </span>
             )}
             <div class={styles.content}>
@@ -30,17 +25,17 @@ export function RemoteMessagingFramework ({ id, messageType, titleText, descript
                 <p>{descriptionText}</p>
                 {messageType === 'big_two_action' && (
                     <div className="buttonRow">
-                        {primaryActionText.length && (
-                            <button class={cn(styles.btn, styles.primary)} onClick={primaryAction}>{primaryActionText}</button>
+                        {primaryAction && message.primaryActionText.length > 0 && (
+                            <button class={cn(styles.btn, styles.primary)} onClick={primaryAction}>{message.primaryActionText}</button>
                         )}
-                        {secondaryActionText.length > 0 && (
-                            <button class={cn(styles.btn, styles.secondary)} onClick={secondaryAction}>{secondaryActionText}</button>
+                        {secondaryAction && message.secondaryActionText.length > 0 && (
+                            <button class={cn(styles.btn, styles.secondary)} onClick={secondaryAction}>{message.secondaryActionText}</button>
                         )}
                     </div>
                 )}
             </div>
-            {messageType === 'big_single_action' && primaryActionText && primaryAction && (
-                <button class={cn(styles.btn)} onClick={primaryAction}>{primaryActionText}</button>
+            {messageType === 'big_single_action' && message.primaryActionText && primaryAction && (
+                <button class={cn(styles.btn)} onClick={primaryAction}>{message.primaryActionText}</button>
             )}
         </div>
 

From 2b22d9afc2776d6b020dbfef148a4282442cd40e Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Sun, 20 Oct 2024 22:40:02 -0600
Subject: [PATCH 13/40] fix: Examples.jsx prop mess

---
 .../pages/new-tab/app/components/Examples.jsx | 124 +++++++++---------
 1 file changed, 62 insertions(+), 62 deletions(-)

diff --git a/special-pages/pages/new-tab/app/components/Examples.jsx b/special-pages/pages/new-tab/app/components/Examples.jsx
index cf97df566..5c204d3fe 100644
--- a/special-pages/pages/new-tab/app/components/Examples.jsx
+++ b/special-pages/pages/new-tab/app/components/Examples.jsx
@@ -37,60 +37,60 @@ export const mainExamples = {
     'rmf.small': {
         factory: () => (
             <RemoteMessagingFramework
-                message={
-                    id: "small",
-        messageType: "small",
-        titleText: "Update Available",
-        descriptionText: "A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
-    }
-        />
+                message={{
+                    id: 'small',
+                    messageType: 'small',
+                    titleText: 'Update Available',
+                    descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.'
+                }}
+            />
         )
     },
-'rmf.medium': {
-    factory: () => (
-        <RemoteMessagingFramework
-            message={
-                id:"medium",
-                    messageType: "medium",
-                        icon: "Announce",
-                            titleText: "Tell Us Your Thoughts on Privacy Pro",
-                                descriptionText: "A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance."
-}
-        />
-    )
-},
-'rmf.big-single-action': {
-    factory: () => (
-        <RemoteMessagingFramework
-            message={
-                id:"big-single",
-                    messageType: "big_single_action",
-                        icon: "DDGAnnounce",
-                            titleText: "New Search Feature!",
-                                descriptionText: "DuckDuckGo now offers Instant Answers for quicker access to the information you need.",
-                                    primaryActionText: "Learn More",
-            }
-primaryAction = {() => { }}
-        />
-    )
-},
-'rmf.big-two-action': {
-    factory: () => (
-        <RemoteMessagingFramework
-            message={
-                id:"big-two",
-                    messageType: "big_two_action",
-                        icon: "AppUpdate",
-                            titleText: "Update Available",
-                                descriptionText: "A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.",
-                                    primaryActionText: "How to update",
-                                        secondaryActionText: "Remind me later",
-            }
-primaryAction = {() => { }}
-secondaryAction = {() => { }}
-        />
-    )
-}
+    'rmf.medium': {
+        factory: () => (
+            <RemoteMessagingFramework
+                message={{
+                    id: 'medium',
+                    messageType: 'medium',
+                    icon: 'Announce',
+                    titleText: 'Tell Us Your Thoughts on Privacy Pro',
+                    descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.'
+                }}
+            />
+        )
+    },
+    'rmf.big-single-action': {
+        factory: () => (
+            <RemoteMessagingFramework
+                message={{
+                    id: 'big-single',
+                    messageType: 'big_single_action',
+                    icon: 'DDGAnnounce',
+                    titleText: 'New Search Feature!',
+                    descriptionText: 'DuckDuckGo now offers Instant Answers for quicker access to the information you need.',
+                    primaryActionText: 'Learn More',
+                }}
+                primaryAction={() => { }}
+            />
+        )
+    },
+    'rmf.big-two-action': {
+        factory: () => (
+            <RemoteMessagingFramework
+                message={{
+                    id: 'big-two',
+                    messageType: 'big_two_action',
+                    icon: 'AppUpdate',
+                    titleText: 'Update Available',
+                    descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.',
+                    primaryActionText: 'How to update',
+                    secondaryActionText: 'Remind me later',
+                }}
+                primaryAction={() => { }}
+                secondaryAction={() => { }}
+            />
+        )
+    }
 }
 
 export const otherExamples = {
@@ -115,17 +115,17 @@ export const otherExamples = {
     'rmf.big-two-action-overflow': {
         factory: () => (
             <RemoteMessagingFramework
-                message={
-                    id: "big-two-overflow",
-        messageType: "big_two_action",
-        icon: "CriticalUpdate",
-        titleText: "Update Available",
-        descriptionText: "A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance. A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.",
-        primaryActionText: "How to update Windows",
-        secondaryActionText: "Remind me later, but only if Iā€™m actually going to update soon",
-    }
+                message={{
+                    id: 'big-two-overflow',
+                    messageType: 'big_two_action',
+                    icon: 'CriticalUpdate',
+                    titleText: 'Update Available',
+                    descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance. A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.',
+                    primaryActionText: 'How to update Windows',
+                    secondaryActionText: 'Remind me later, but only if Iā€™m actually going to update soon',
+                }}
                 primaryAction={() => { }}
-secondaryAction = {() => { }}
+                secondaryAction={() => { }}
             />
         )
     },

From 5ed13bd44561354d213c9baf56e978f0b5a8b22f Mon Sep 17 00:00:00 2001
From: Shane Osbourne <sosbourne@duckduckgo.com>
Date: Mon, 21 Oct 2024 21:31:52 +0100
Subject: [PATCH 14/40] data example

---
 .../new-tab/rmf_getConfig.request.json        |   3 +
 .../new-tab/rmf_getConfig.response.json       |   8 +
 .../messages/new-tab/rmf_getData.request.json |   3 +
 .../new-tab/rmf_getData.response.json         |   8 +
 .../messages/new-tab/types/rmf-config.json    |   9 +
 .../messages/new-tab/types/rmf-message.json   | 258 +++++++++---------
 .../remote-messaging-framework/RMFProvider.js | 106 +++++++
 .../RemoteMessagingFramework.js               |  16 ++
 .../remote-messaging-framework/rmf.service.js |  71 +++++
 .../new-tab/app/widget-list/WidgetList.js     |   7 +
 .../pages/new-tab/src/js/mock-transport.js    |  41 ++-
 special-pages/types/new-tab.ts                |  74 ++++-
 12 files changed, 468 insertions(+), 136 deletions(-)
 create mode 100644 special-pages/messages/new-tab/rmf_getConfig.request.json
 create mode 100644 special-pages/messages/new-tab/rmf_getConfig.response.json
 create mode 100644 special-pages/messages/new-tab/rmf_getData.request.json
 create mode 100644 special-pages/messages/new-tab/rmf_getData.response.json
 create mode 100644 special-pages/messages/new-tab/types/rmf-config.json
 create mode 100644 special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
 create mode 100644 special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js

diff --git a/special-pages/messages/new-tab/rmf_getConfig.request.json b/special-pages/messages/new-tab/rmf_getConfig.request.json
new file mode 100644
index 000000000..0af74a319
--- /dev/null
+++ b/special-pages/messages/new-tab/rmf_getConfig.request.json
@@ -0,0 +1,3 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#"
+}
diff --git a/special-pages/messages/new-tab/rmf_getConfig.response.json b/special-pages/messages/new-tab/rmf_getConfig.response.json
new file mode 100644
index 000000000..4d206fc5d
--- /dev/null
+++ b/special-pages/messages/new-tab/rmf_getConfig.response.json
@@ -0,0 +1,8 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "allOf": [
+    {
+      "$ref": "./types/rmf-config.json"
+    }
+  ]
+}
diff --git a/special-pages/messages/new-tab/rmf_getData.request.json b/special-pages/messages/new-tab/rmf_getData.request.json
new file mode 100644
index 000000000..fbdeff52e
--- /dev/null
+++ b/special-pages/messages/new-tab/rmf_getData.request.json
@@ -0,0 +1,3 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema#"
+}
diff --git a/special-pages/messages/new-tab/rmf_getData.response.json b/special-pages/messages/new-tab/rmf_getData.response.json
new file mode 100644
index 000000000..df9f441e5
--- /dev/null
+++ b/special-pages/messages/new-tab/rmf_getData.response.json
@@ -0,0 +1,8 @@
+{
+    "$schema": "http://json-schema.org/draft-07/schema#",
+    "allOf": [
+        {
+            "$ref": "types/rmf-message.json"
+        }
+    ]
+}
diff --git a/special-pages/messages/new-tab/types/rmf-config.json b/special-pages/messages/new-tab/types/rmf-config.json
new file mode 100644
index 000000000..e518b2453
--- /dev/null
+++ b/special-pages/messages/new-tab/types/rmf-config.json
@@ -0,0 +1,9 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "RMFConfig",
+  "type": "object",
+  "required": ["expansion"],
+  "properties": {
+    "expansion": {"$ref":  "./expansion.json"}
+  }
+}
diff --git a/special-pages/messages/new-tab/types/rmf-message.json b/special-pages/messages/new-tab/types/rmf-message.json
index 13bf618c7..9f9020fc1 100644
--- a/special-pages/messages/new-tab/types/rmf-message.json
+++ b/special-pages/messages/new-tab/types/rmf-message.json
@@ -1,133 +1,135 @@
-"$schema": "http://json-schema.org/draft-07/schema#",
-"type": "object",
-"required": [
-    "content"
-],
-"properties": {
-    "content": {
-        "title": "RMF Message",
-        "oneOf": [
-            {
-                "title": "Small Message",
-                "type": "object",
-                "properties": {
-                    "messageType": {
-                        "const": "small"
-                    },
-                    "id": {
-                        "type": "string"
-                    },
-                    "titleText": {
-                        "type": "string"
-                    },
-                    "descriptionText": {
-                        "type": "string"
-                    }
+{
+    "$schema": "http://json-schema.org/draft-07/schema#",
+    "type": "object",
+    "title": "RMF Data",
+    "required": [
+        "content"
+    ],
+    "properties": {
+        "content": {
+            "title": "RMF Message",
+            "oneOf": [
+                {
+                    "title": "Small Message",
+                    "type": "object",
+                    "properties": {
+                        "messageType": {
+                            "const": "small"
+                        },
+                        "id": {
+                            "type": "string"
+                        },
+                        "titleText": {
+                            "type": "string"
+                        },
+                        "descriptionText": {
+                            "type": "string"
+                        }
+                    },
+                    "required": [
+                        "messageType",
+                        "id",
+                        "titleText",
+                        "descriptionText"
+                    ]
                 },
-                "required": [
-                    "messageType",
-                    "id",
-                    "titleText",
-                    "descriptionText"
-                ]
-            },
-            {
-                "title": "Medium Message",
-                "type": "object",
-                "properties": {
-                    "messageType": {
-                        "const": "medium"
-                    },
-                    "id": {
-                        "type": "string"
-                    },
-                    "titleText": {
-                        "type": "string"
-                    },
-                    "descriptionText": {
-                        "type": "string"
-                    },
-                    "icon": {
-                        "type": "string"
-                    }
+                {
+                    "title": "Medium Message",
+                    "type": "object",
+                    "properties": {
+                        "messageType": {
+                            "const": "medium"
+                        },
+                        "id": {
+                            "type": "string"
+                        },
+                        "titleText": {
+                            "type": "string"
+                        },
+                        "descriptionText": {
+                            "type": "string"
+                        },
+                        "icon": {
+                            "type": "string"
+                        }
+                    },
+                    "required": [
+                        "messageType",
+                        "id",
+                        "titleText",
+                        "descriptionText",
+                        "icon"
+                    ]
                 },
-                "required": [
-                    "messageType",
-                    "id",
-                    "titleText",
-                    "descriptionText",
-                    "icon"
-                ]
-            },
-            {
-                "title": "Big Single Action Message",
-                "type": "object",
-                "properties": {
-                    "messageType": {
-                        "const": "big_single_action"
-                    },
-                    "id": {
-                        "type": "string"
-                    },
-                    "titleText": {
-                        "type": "string"
-                    },
-                    "descriptionText": {
-                        "type": "string"
-                    },
-                    "icon": {
-                        "type": "string"
-                    },
-                    "primaryActionText": {
-                        "type": "string"
-                    }
-                },
-                "required": [
-                    "messageType",
-                    "id",
-                    "titleText",
-                    "descriptionText",
-                    "icon",
-                    "primaryActionText",
-                ]
-            },
-            {
-                "title": "Big Two Action Message",
-                "type": "object",
-                "properties": {
-                    "messageType": {
-                        "const": "big_two_action"
-                    },
-                    "id": {
-                        "type": "string"
-                    },
-                    "titleText": {
-                        "type": "string"
-                    },
-                    "descriptionText": {
-                        "type": "string"
-                    },
-                    "icon": {
-                        "type": "string"
-                    },
-                    "primaryActionText": {
-                        "type": "string"
-                    },
-                    "secondaryActionText": {
-                        "type": "string"
-                    }
+                {
+                    "title": "Big Single Action Message",
+                    "type": "object",
+                    "properties": {
+                        "messageType": {
+                            "const": "big_single_action"
+                        },
+                        "id": {
+                            "type": "string"
+                        },
+                        "titleText": {
+                            "type": "string"
+                        },
+                        "descriptionText": {
+                            "type": "string"
+                        },
+                        "icon": {
+                            "type": "string"
+                        },
+                        "primaryActionText": {
+                            "type": "string"
+                        }
+                    },
+                    "required": [
+                        "messageType",
+                        "id",
+                        "titleText",
+                        "descriptionText",
+                        "icon",
+                        "primaryActionText"
+                    ]
                 },
-                "required": [
-                    "messageType",
-                    "id",
-                    "titleText",
-                    "descriptionText",
-                    "icon",
-                    "primaryActionText",
-                    "secondaryActionText"
-                ]
-            }
-        ]
+                {
+                    "title": "Big Two Action Message",
+                    "type": "object",
+                    "properties": {
+                        "messageType": {
+                            "const": "big_two_action"
+                        },
+                        "id": {
+                            "type": "string"
+                        },
+                        "titleText": {
+                            "type": "string"
+                        },
+                        "descriptionText": {
+                            "type": "string"
+                        },
+                        "icon": {
+                            "type": "string"
+                        },
+                        "primaryActionText": {
+                            "type": "string"
+                        },
+                        "secondaryActionText": {
+                            "type": "string"
+                        }
+                    },
+                    "required": [
+                        "messageType",
+                        "id",
+                        "titleText",
+                        "descriptionText",
+                        "icon",
+                        "primaryActionText",
+                        "secondaryActionText"
+                    ]
+                }
+            ]
+        }
     }
 }
-}
\ No newline at end of file
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
new file mode 100644
index 000000000..c3f2dc37d
--- /dev/null
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
@@ -0,0 +1,106 @@
+import { createContext, h } from 'preact'
+import { useCallback, useEffect, useReducer, useRef } from 'preact/hooks'
+import { useMessaging } from '../types.js'
+import { RMFService } from './rmf.service.js'
+import { reducer, useConfigSubscription, useDataSubscription, useInitialData } from '../service.hooks.js'
+
+/**
+ * @typedef {import('../../../../types/new-tab.js').RMFData} RMFData
+ * @typedef {import('../../../../types/new-tab.js').RMFConfig} RMFConfig
+ * @typedef {import('../service.hooks.js').State<RMFData, RMFConfig>} State
+ * @typedef {import('../service.hooks.js').Events<RMFData, RMFConfig>} Events
+ */
+
+/**
+ * These are the values exposed to consumers.
+ */
+export const RMFContext = createContext({
+    /** @type {State} */
+    state: { status: 'idle', data: null, config: null },
+    /** @type {() => void} */
+    toggle: () => {
+        throw new Error('must implement')
+    },
+    /** @type {() => void} */
+    onDismiss: () => {
+        throw new Error('must implement')
+    },
+    /** @type {() => void} */
+    primaryAction: () => {
+        throw new Error('must implement')
+    },
+    /** @type {() => void} */
+    secondaryAction: () => {
+        throw new Error('must implement')
+    }
+})
+
+export const RMFDispatchContext = createContext(/** @type {import("preact/hooks").Dispatch<Events>} */({}))
+
+/**
+ * A data provider that will use `RMFService` to fetch data, subscribe
+ * to updates and modify state.
+ *
+ * @param {Object} props
+ * @param {import("preact").ComponentChild} props.children
+ */
+export function RMFProvider (props) {
+    const initial = /** @type {State} */({
+        status: 'idle',
+        data: null,
+        config: null
+    })
+
+    // const [state, dispatch] = useReducer(withLog('RMFProvider', reducer), initial)
+    const [state, dispatch] = useReducer(reducer, initial)
+
+    // create an instance of `RMFService` for the lifespan of this component.
+    const service = useService()
+
+    // get initial data
+    useInitialData({ dispatch, service })
+
+    // subscribe to data updates
+    useDataSubscription({ dispatch, service })
+
+    // subscribe to toggle + expose a fn for sync toggling
+    const { toggle } = useConfigSubscription({ dispatch, service })
+
+    const onDismiss = useCallback(() => {
+        console.log('onDismiss')
+    }, [service]);
+
+    const primaryAction = useCallback(() => {
+        console.log('primaryAction')
+    }, [service]);
+
+    const secondaryAction = useCallback(() => {
+        console.log('secondaryAction')
+    }, [service]);
+
+    console.log(state)
+
+    return (
+        <RMFContext.Provider value={{ state, toggle, onDismiss, primaryAction, secondaryAction }}>
+            <RMFDispatchContext.Provider value={dispatch}>
+                {props.children}
+            </RMFDispatchContext.Provider>
+        </RMFContext.Provider>
+    )
+}
+
+/**
+ * @return {import("preact").RefObject<RMFService>}
+ */
+export function useService () {
+    const service = useRef(/** @type {RMFService|null} */(null))
+    const ntp = useMessaging()
+    useEffect(() => {
+        const stats = new RMFService(ntp)
+        service.current = stats
+        return () => {
+            stats.destroy()
+        }
+    }, [ntp])
+    return service
+}
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index 1715dc2de..770f7cfe1 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -2,6 +2,8 @@ import { h } from 'preact'
 import cn from 'classnames'
 import styles from './RemoteMessagingFramework.module.css'
 import MessageIcons from './MessageIcons'
+import { useContext } from "preact/hooks";
+import { RMFContext } from "./RMFProvider.js";
 
 /**
   * @import { RMFMessage } from "../../../../types/new-tab"
@@ -41,3 +43,17 @@ export function RemoteMessagingFramework ({ message, primaryAction, secondaryAct
 
     )
 }
+
+export function RMFConsumer () {
+    const { state, primaryAction, secondaryAction } = useContext(RMFContext)
+    if (state.status === 'ready') {
+        return (
+            <RemoteMessagingFramework
+                message={state.data.content}
+                primaryAction={primaryAction}
+                secondaryAction={secondaryAction}
+            />
+        )
+    }
+    return null
+}
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js b/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
new file mode 100644
index 000000000..43bc3729f
--- /dev/null
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
@@ -0,0 +1,71 @@
+/**
+ * @typedef {import("../../../../types/new-tab.js").RMFData} RMFData
+ * @typedef {import("../../../../types/new-tab.js").StatsConfig} StatsConfig
+ * @typedef {import("../../../../types/new-tab.js").RMFConfig} RMFConfig
+ */
+import { Service } from '../service.js'
+
+/**
+ *
+ */
+export class RMFService {
+    /**
+     * @param {import("../../src/js/index.js").NewTabPage} ntp - The internal data feed, expected to have a `subscribe` method.
+     * @internal
+     */
+    constructor (ntp) {
+        this.ntp = ntp;
+        /** @type {Service<RMFData>} */
+        this.dataService = new Service({
+            initial: () => ntp.messaging.request('rmf_getData'),
+            subscribe: (cb) => ntp.messaging.subscribe('rmf_onDataUpdate', cb)
+        })
+        /** @type {Service<RMFConfig>} */
+        this.configService = new Service({
+            initial: () => ntp.messaging.request('rmf_getConfig'),
+        })
+    }
+
+    /**
+     * @returns {Promise<{data: RMFData; config: RMFConfig}>}
+     * @internal
+     */
+    async getInitial () {
+        const p1 = this.configService.fetchInitial()
+        const p2 = this.dataService.fetchInitial()
+        const [config, data] = await Promise.all([p1, p2])
+        return { config, data }
+    }
+
+    /**
+     * @internal
+     */
+    destroy () {
+        this.dataService.destroy()
+    }
+
+    /**
+     * @param {(evt: {data: RMFData, source: 'manual' | 'subscription'}) => void} cb
+     * @internal
+     */
+    onData (cb) {
+        return this.dataService.onData(cb)
+    }
+    /**
+     * @param {(evt: {data: RMFConfig, source: 'manual' | 'subscription'}) => void} cb
+     * @internal
+     */
+    onConfig (cb) {
+        return this.configService.onData(cb)
+    }
+
+    /**
+     * @param {(evt: {data: RMFData, source: 'manual' | 'subscription'}) => void} cb
+     * @internal
+     */
+    dismiss (cb) {
+        // return this.ntp.messaging.notify('')
+    }
+
+    toggleExpansion() {}
+}
diff --git a/special-pages/pages/new-tab/app/widget-list/WidgetList.js b/special-pages/pages/new-tab/app/widget-list/WidgetList.js
index 1c5c34a51..995ca53d1 100644
--- a/special-pages/pages/new-tab/app/widget-list/WidgetList.js
+++ b/special-pages/pages/new-tab/app/widget-list/WidgetList.js
@@ -8,6 +8,8 @@ import {
     Customizer,
     CustomizerMenuPositionedFixed
 } from '../customizer/Customizer.js'
+import { RMFProvider } from "../remote-messaging-framework/RMFProvider.js";
+import { RMFConsumer } from "../remote-messaging-framework/RemoteMessagingFramework.js";
 
 const widgetMap = {
     privacyStats: () => (
@@ -15,6 +17,11 @@ const widgetMap = {
     ),
     favorites: () => (
         <FavoritesCustomized />
+    ),
+    rmf: () => (
+        <RMFProvider>
+            <RMFConsumer />
+        </RMFProvider>
     )
 }
 
diff --git a/special-pages/pages/new-tab/src/js/mock-transport.js b/special-pages/pages/new-tab/src/js/mock-transport.js
index ff7903fc8..fc465ea4e 100644
--- a/special-pages/pages/new-tab/src/js/mock-transport.js
+++ b/special-pages/pages/new-tab/src/js/mock-transport.js
@@ -102,6 +102,20 @@ export function mockTransport () {
                 }, { signal: controller.signal })
                 return () => controller.abort()
             }
+            case 'rmf_onDataUpdate': {
+                // const timeout = setTimeout(() => {
+                //     /** @type {import('../../../../types/new-tab.js').SmallMessage} */
+                //     const payload = {
+                //         id: "id-1",
+                //         messageType: "small",
+                //         titleText: "Hello world",
+                //         descriptionText: "My Description"
+                //     }
+                //     cb(payload)
+                // }, 2000)
+                // return () => clearTimeout(timeout)
+                return () => {}
+            }
             }
             return () => {}
         },
@@ -126,15 +140,38 @@ export function mockTransport () {
                 }
                 return Promise.resolve(fromStorage)
             }
+            case 'rmf_getConfig':{
+                /** @type {import('../../../../types/new-tab').RMFConfig} */
+                const defaultConfig = { expansion: 'expanded' }
+                return Promise.resolve(defaultConfig)
+            }
+            case 'rmf_getData':{
+                /** @type {import('../../../../types/new-tab.js').RMFData} */
+                const payload = {
+                    content: {
+                        id: "id-1",
+                        messageType: "small",
+                        titleText: "Hello world",
+                        descriptionText: "My Description"
+                    }
+                }
+                if (url.searchParams.get('rmf') === 'medium') {
+                    payload.content.messageType = 'medium'
+                    payload.content.icon = 'Announce'
+                }
+                return Promise.resolve(payload)
+            }
             case 'initialSetup': {
                 const widgetsFromStorage = read('widgets') || [
+                    { id: 'rmf' },
                     { id: 'favorites' },
-                    { id: 'privacyStats' }
+                    { id: 'privacyStats' },
                 ]
 
                 const widgetConfigFromStorage = read('widget_config') || [
                     { id: 'favorites', visibility: 'visible' },
-                    { id: 'privacyStats', visibility: 'visible' }
+                    { id: 'privacyStats', visibility: 'visible' },
+                    { id: 'rmf', visibility: 'visible' }
                 ]
 
                 /** @type {import('../../../../types/new-tab.js').InitialSetupResponse} */
diff --git a/special-pages/types/new-tab.ts b/special-pages/types/new-tab.ts
index 564be1065..e95671ce5 100644
--- a/special-pages/types/new-tab.ts
+++ b/special-pages/types/new-tab.ts
@@ -27,17 +27,22 @@ export type WidgetConfigs = WidgetConfigItem[];
  */
 export type Widgets = WidgetListItem[];
 export type RMFMessage = SmallMessage | MediumMessage | BigSingleActionMessage | BigTwoActionMessage;
+
 /**
  * Requests, Notifications and Subscriptions from the NewTab feature
  */
 export interface NewTabMessages {
   notifications:
-  | ReportInitExceptionNotification
-  | ReportPageExceptionNotification
-  | StatsSetConfigNotification
-  | WidgetsSetConfigNotification;
-  requests: InitialSetupRequest | StatsGetConfigRequest | StatsGetDataRequest;
-  subscriptions: RmfOnDataUpdateSubscription | StatsOnConfigUpdateSubscription | StatsOnDataUpdateSubscription | WidgetsOnConfigUpdatedSubscription;
+    | ReportInitExceptionNotification
+    | ReportPageExceptionNotification
+    | StatsSetConfigNotification
+    | WidgetsSetConfigNotification;
+  requests: InitialSetupRequest | RmfGetConfigRequest | RmfGetDataRequest | StatsGetConfigRequest | StatsGetDataRequest;
+  subscriptions:
+    | RmfOnDataUpdateSubscription
+    | StatsOnConfigUpdateSubscription
+    | StatsOnDataUpdateSubscription
+    | WidgetsOnConfigUpdatedSubscription;
 }
 /**
  * Generated from @see "../messages/new-tab/reportInitException.notify.json"
@@ -121,6 +126,56 @@ export interface WidgetListItem {
    */
   id: string;
 }
+/**
+ * Generated from @see "../messages/new-tab/rmf_getConfig.request.json"
+ */
+export interface RmfGetConfigRequest {
+  method: "rmf_getConfig";
+  result: RMFConfig;
+}
+export interface RMFConfig {
+  expansion: Expansion;
+}
+/**
+ * Generated from @see "../messages/new-tab/rmf_getData.request.json"
+ */
+export interface RmfGetDataRequest {
+  method: "rmf_getData";
+  result: RMFData;
+}
+export interface RMFData {
+  content: RMFMessage;
+}
+export interface SmallMessage {
+  messageType: "small";
+  id: string;
+  titleText: string;
+  descriptionText: string;
+}
+export interface MediumMessage {
+  messageType: "medium";
+  id: string;
+  titleText: string;
+  descriptionText: string;
+  icon: string;
+}
+export interface BigSingleActionMessage {
+  messageType: "big_single_action";
+  id: string;
+  titleText: string;
+  descriptionText: string;
+  icon: string;
+  primaryActionText: string;
+}
+export interface BigTwoActionMessage {
+  messageType: "big_two_action";
+  id: string;
+  titleText: string;
+  descriptionText: string;
+  icon: string;
+  primaryActionText: string;
+  secondaryActionText: string;
+}
 /**
  * Generated from @see "../messages/new-tab/stats_getConfig.request.json"
  */
@@ -146,6 +201,13 @@ export interface TrackerCompany {
   displayName: string;
   count: number;
 }
+/**
+ * Generated from @see "../messages/new-tab/rmf_onDataUpdate.subscribe.json"
+ */
+export interface RmfOnDataUpdateSubscription {
+  subscriptionEvent: "rmf_onDataUpdate";
+  params: RMFData;
+}
 /**
  * Generated from @see "../messages/new-tab/stats_onConfigUpdate.subscribe.json"
  */

From 7bfe6f8b89c3e6f78316b4bcd6c87363e88f3c6e Mon Sep 17 00:00:00 2001
From: Shane Osbourne <sosbourne@duckduckgo.com>
Date: Mon, 21 Oct 2024 21:37:21 +0100
Subject: [PATCH 15/40] better types override

---
 special-pages/pages/new-tab/src/js/mock-transport.js | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/special-pages/pages/new-tab/src/js/mock-transport.js b/special-pages/pages/new-tab/src/js/mock-transport.js
index fc465ea4e..e13cb089e 100644
--- a/special-pages/pages/new-tab/src/js/mock-transport.js
+++ b/special-pages/pages/new-tab/src/js/mock-transport.js
@@ -156,8 +156,13 @@ export function mockTransport () {
                     }
                 }
                 if (url.searchParams.get('rmf') === 'medium') {
-                    payload.content.messageType = 'medium'
-                    payload.content.icon = 'Announce'
+                    payload.content = {
+                        messageType: 'medium',
+                        icon: '',
+                        id: '',
+                        titleText: ',',
+                        descriptionText: ''
+                    }
                 }
                 return Promise.resolve(payload)
             }

From 531c3e1537f1bd0d84090354e5ee37786a5680f2 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Mon, 21 Oct 2024 21:42:26 -0600
Subject: [PATCH 16/40] fix: message.icon issues and lint fix

---
 .../messages/new-tab/types/rmf-message.json   | 28 +++++++++++++++----
 .../remote-messaging-framework/RMFProvider.js |  6 ++--
 .../RemoteMessagingFramework.js               |  6 ++--
 .../remote-messaging-framework/rmf.service.js |  8 ++++--
 .../new-tab/app/widget-list/WidgetList.js     |  9 ++----
 .../pages/new-tab/src/js/mock-transport.js    | 26 ++++++++---------
 special-pages/types/new-tab.ts                |  6 ++--
 7 files changed, 53 insertions(+), 36 deletions(-)

diff --git a/special-pages/messages/new-tab/types/rmf-message.json b/special-pages/messages/new-tab/types/rmf-message.json
index 9f9020fc1..4110572e6 100644
--- a/special-pages/messages/new-tab/types/rmf-message.json
+++ b/special-pages/messages/new-tab/types/rmf-message.json
@@ -50,8 +50,14 @@
                             "type": "string"
                         },
                         "icon": {
-                            "type": "string"
-                        }
+                            "enum": [
+                                "Announce",
+                                "DDGAnnounce",
+                                "CriticalUpdate",
+                                "AppUpdate",
+                                "PrivacyPro"
+                            ]
+                        },
                     },
                     "required": [
                         "messageType",
@@ -78,7 +84,13 @@
                             "type": "string"
                         },
                         "icon": {
-                            "type": "string"
+                            "enum": [
+                                "Announce",
+                                "DDGAnnounce",
+                                "CriticalUpdate",
+                                "AppUpdate",
+                                "PrivacyPro"
+                            ]
                         },
                         "primaryActionText": {
                             "type": "string"
@@ -110,7 +122,13 @@
                             "type": "string"
                         },
                         "icon": {
-                            "type": "string"
+                            "enum": [
+                                "Announce",
+                                "DDGAnnounce",
+                                "CriticalUpdate",
+                                "AppUpdate",
+                                "PrivacyPro"
+                            ]
                         },
                         "primaryActionText": {
                             "type": "string"
@@ -132,4 +150,4 @@
             ]
         }
     }
-}
+}
\ No newline at end of file
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
index c3f2dc37d..e50f02d07 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
@@ -68,15 +68,15 @@ export function RMFProvider (props) {
 
     const onDismiss = useCallback(() => {
         console.log('onDismiss')
-    }, [service]);
+    }, [service])
 
     const primaryAction = useCallback(() => {
         console.log('primaryAction')
-    }, [service]);
+    }, [service])
 
     const secondaryAction = useCallback(() => {
         console.log('secondaryAction')
-    }, [service]);
+    }, [service])
 
     console.log(state)
 
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index 770f7cfe1..24cdcafcb 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -2,8 +2,8 @@ import { h } from 'preact'
 import cn from 'classnames'
 import styles from './RemoteMessagingFramework.module.css'
 import MessageIcons from './MessageIcons'
-import { useContext } from "preact/hooks";
-import { RMFContext } from "./RMFProvider.js";
+import { useContext } from 'preact/hooks'
+import { RMFContext } from './RMFProvider.js'
 
 /**
   * @import { RMFMessage } from "../../../../types/new-tab"
@@ -17,7 +17,7 @@ export function RemoteMessagingFramework ({ message, primaryAction, secondaryAct
     const { id, messageType, titleText, descriptionText } = message
     return (
         <div id={id} class={cn(styles.root, message.icon && styles.icon)}>
-            {message.icon && (
+            {messageType !== 'small' && message.icon && (
                 <span class={styles.iconBlock}>
                     <MessageIcons name={message.icon} />
                 </span>
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js b/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
index 43bc3729f..e4d6870de 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
@@ -14,7 +14,7 @@ export class RMFService {
      * @internal
      */
     constructor (ntp) {
-        this.ntp = ntp;
+        this.ntp = ntp
         /** @type {Service<RMFData>} */
         this.dataService = new Service({
             initial: () => ntp.messaging.request('rmf_getData'),
@@ -22,7 +22,7 @@ export class RMFService {
         })
         /** @type {Service<RMFConfig>} */
         this.configService = new Service({
-            initial: () => ntp.messaging.request('rmf_getConfig'),
+            initial: () => ntp.messaging.request('rmf_getConfig')
         })
     }
 
@@ -51,6 +51,7 @@ export class RMFService {
     onData (cb) {
         return this.dataService.onData(cb)
     }
+
     /**
      * @param {(evt: {data: RMFConfig, source: 'manual' | 'subscription'}) => void} cb
      * @internal
@@ -65,7 +66,8 @@ export class RMFService {
      */
     dismiss (cb) {
         // return this.ntp.messaging.notify('')
+        console.log(cb)
     }
 
-    toggleExpansion() {}
+    toggleExpansion () { }
 }
diff --git a/special-pages/pages/new-tab/app/widget-list/WidgetList.js b/special-pages/pages/new-tab/app/widget-list/WidgetList.js
index 995ca53d1..16727a31d 100644
--- a/special-pages/pages/new-tab/app/widget-list/WidgetList.js
+++ b/special-pages/pages/new-tab/app/widget-list/WidgetList.js
@@ -4,12 +4,9 @@ import { useContext } from 'preact/hooks'
 import { PrivacyStatsCustomized } from '../privacy-stats/PrivacyStats.js'
 import { FavoritesCustomized } from '../favorites/Favorites.js'
 import { Stack } from '../../../onboarding/app/components/Stack.js'
-import {
-    Customizer,
-    CustomizerMenuPositionedFixed
-} from '../customizer/Customizer.js'
-import { RMFProvider } from "../remote-messaging-framework/RMFProvider.js";
-import { RMFConsumer } from "../remote-messaging-framework/RemoteMessagingFramework.js";
+import { Customizer } from '../customizer/Customizer.js'
+import { RMFProvider } from '../remote-messaging-framework/RMFProvider.js'
+import { RMFConsumer } from '../remote-messaging-framework/RemoteMessagingFramework.js'
 
 const widgetMap = {
     privacyStats: () => (
diff --git a/special-pages/pages/new-tab/src/js/mock-transport.js b/special-pages/pages/new-tab/src/js/mock-transport.js
index e13cb089e..91ea9b986 100644
--- a/special-pages/pages/new-tab/src/js/mock-transport.js
+++ b/special-pages/pages/new-tab/src/js/mock-transport.js
@@ -114,10 +114,10 @@ export function mockTransport () {
                 //     cb(payload)
                 // }, 2000)
                 // return () => clearTimeout(timeout)
-                return () => {}
+                return () => { }
             }
             }
-            return () => {}
+            return () => { }
         },
         // eslint-ignore-next-line require-await
         request (_msg) {
@@ -140,28 +140,28 @@ export function mockTransport () {
                 }
                 return Promise.resolve(fromStorage)
             }
-            case 'rmf_getConfig':{
+            case 'rmf_getConfig': {
                 /** @type {import('../../../../types/new-tab').RMFConfig} */
                 const defaultConfig = { expansion: 'expanded' }
                 return Promise.resolve(defaultConfig)
             }
-            case 'rmf_getData':{
+            case 'rmf_getData': {
                 /** @type {import('../../../../types/new-tab.js').RMFData} */
                 const payload = {
                     content: {
-                        id: "id-1",
-                        messageType: "small",
-                        titleText: "Hello world",
-                        descriptionText: "My Description"
+                        id: 'id-1',
+                        messageType: 'small',
+                        titleText: 'Hello world',
+                        descriptionText: 'My Description'
                     }
                 }
                 if (url.searchParams.get('rmf') === 'medium') {
                     payload.content = {
                         messageType: 'medium',
-                        icon: '',
-                        id: '',
-                        titleText: ',',
-                        descriptionText: ''
+                        icon: 'Announce',
+                        id: 'id-2',
+                        titleText: 'Hello Medium!',
+                        descriptionText: 'Here is some mighty fine content'
                     }
                 }
                 return Promise.resolve(payload)
@@ -170,7 +170,7 @@ export function mockTransport () {
                 const widgetsFromStorage = read('widgets') || [
                     { id: 'rmf' },
                     { id: 'favorites' },
-                    { id: 'privacyStats' },
+                    { id: 'privacyStats' }
                 ]
 
                 const widgetConfigFromStorage = read('widget_config') || [
diff --git a/special-pages/types/new-tab.ts b/special-pages/types/new-tab.ts
index e95671ce5..312c23b08 100644
--- a/special-pages/types/new-tab.ts
+++ b/special-pages/types/new-tab.ts
@@ -157,14 +157,14 @@ export interface MediumMessage {
   id: string;
   titleText: string;
   descriptionText: string;
-  icon: string;
+  icon: "Announce" | "DDGAnnounce" | "CriticalUpdate" | "AppUpdate" | "PrivacyPro";
 }
 export interface BigSingleActionMessage {
   messageType: "big_single_action";
   id: string;
   titleText: string;
   descriptionText: string;
-  icon: string;
+  icon: "Announce" | "DDGAnnounce" | "CriticalUpdate" | "AppUpdate" | "PrivacyPro";
   primaryActionText: string;
 }
 export interface BigTwoActionMessage {
@@ -172,7 +172,7 @@ export interface BigTwoActionMessage {
   id: string;
   titleText: string;
   descriptionText: string;
-  icon: string;
+  icon: "Announce" | "DDGAnnounce" | "CriticalUpdate" | "AppUpdate" | "PrivacyPro";
   primaryActionText: string;
   secondaryActionText: string;
 }

From 953a03beba777c3406d0152724377a3d76e207ab Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Mon, 21 Oct 2024 22:40:18 -0600
Subject: [PATCH 17/40] chore: Complete dark mode styles

---
 .../RemoteMessagingFramework.js               |   8 +-
 .../RemoteMessagingFramework.module.css       | 137 ++++++++++++------
 2 files changed, 99 insertions(+), 46 deletions(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index 24cdcafcb..32802ab93 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -16,7 +16,7 @@ import { RMFContext } from './RMFProvider.js'
 export function RemoteMessagingFramework ({ message, primaryAction, secondaryAction }) {
     const { id, messageType, titleText, descriptionText } = message
     return (
-        <div id={id} class={cn(styles.root, message.icon && styles.icon)}>
+        <div id={id} class={cn(styles.root, (messageType !== 'small' && message.icon) && styles.icon)}>
             {messageType !== 'small' && message.icon && (
                 <span class={styles.iconBlock}>
                     <MessageIcons name={message.icon} />
@@ -26,7 +26,7 @@ export function RemoteMessagingFramework ({ message, primaryAction, secondaryAct
                 <p class={styles.title}>{titleText}</p>
                 <p>{descriptionText}</p>
                 {messageType === 'big_two_action' && (
-                    <div className="buttonRow">
+                    <div class={styles.btnRow}>
                         {primaryAction && message.primaryActionText.length > 0 && (
                             <button class={cn(styles.btn, styles.primary)} onClick={primaryAction}>{message.primaryActionText}</button>
                         )}
@@ -37,7 +37,9 @@ export function RemoteMessagingFramework ({ message, primaryAction, secondaryAct
                 )}
             </div>
             {messageType === 'big_single_action' && message.primaryActionText && primaryAction && (
-                <button class={cn(styles.btn)} onClick={primaryAction}>{message.primaryActionText}</button>
+                <div class={styles.btnBlock}>
+                    <button class={cn(styles.btn)} onClick={primaryAction}>{message.primaryActionText}</button>
+                </div>
             )}
         </div>
 
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
index 15724dc15..2edeb87a6 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
@@ -1,24 +1,24 @@
 .root {
     --ntp-rmf-surface-background-color: rgba(0, 0, 0, .06);
     background: var(--ntp-rmf-surface-background-color);
-    border: 1px solid var(--ntp-surface-border-color);
     padding: 14px var(--sp-8) 14px var(--sp-4);
     border-radius: var(--sp-3);
     display: flex;
-    justify-content: space-between;
-    align-items: center;
+    justify-content: flex-start;
+    align-items: flex-start;
+    font-family: 'Segoe UI', system-ui, Tahoma, Geneva, Verdana, sans-serif;
+    color: var(--color-black);
 
+    &.icon {
+        padding-left: var(--sp-2);
+    }
 
     @media screen and (prefers-color-scheme: dark) {
-        border-color: var(--color-white-at-9);
+        background-color: var(--color-white-at-6);
+        color: var(--color-white-at-84);
     }
 }
 
-.icon {
-    padding-left: var(--sp-2);
-
-}
-
 .iconBlock {
     margin-right: var(--sp-2);
     width: var(--sp-12);
@@ -26,13 +26,25 @@
 }
 
 .content {
+    flex-grow: 1;
     display: grid;
-    gap: 8px;
+    gap: var(--sp-3);
 }
 
 .title {
     font-weight: var(--title-2-font-weight);
-    line-height: var(--title-2-line-height);
+    font-size: 14px;
+}
+
+.btnBlock {
+    margin-left: var(--sp-3);
+    align-self: center;
+}
+
+.btnRow {
+    display: flex;
+    flex-wrap: wrap;
+    gap: calc(10 * var(--px-in-rem));
 }
 
 .btn {
@@ -44,51 +56,90 @@
     border-radius: 6px;
     text-wrap: nowrap;
 
-    @media screen and (prefers-color-scheme: dark) {
-        color: var(--color-white);
+    &:hover {
+        background-color: var(--color-black-at-9);
     }
-}
 
-.btn:hover {
-    background-color: var(--color-black-at-9);
-}
+    &:active {
+        background-color: var(--color-black-at-12);
+    }
 
-.btn:active {
-    background-color: var(--color-black-at-12);
-}
+    &:disabled {
+        color: var(--color-black-at-84);
+    }
 
-.btn:disabled {
-    color: var(--color-black-at-84);
-}
+    &:disabled:hover {
+        cursor: not-allowed;
+        background-color: var(--color-white-at-6);
+    }
 
-.btn:disabled:hover {
-    cursor: not-allowed;
-    background-color: var(--color-white-at-6);
-}
+    &:focus-visible {
+        outline: 2px solid var(--ddg-color-primary);
+        border: 1px solid white;
+    }
 
-.btn:focus-visible {
-    outline: 2px solid var(--ddg-color-primary);
-    border: 1px solid white;
+    @media screen and (prefers-color-scheme: dark) {
+        color: var(--color-white-at-84);
+        background-color: var(--color-white-at-12);
+
+        &:hover {
+            background-color: var(--color-white-at-18);
+        }
+
+        &:active {
+            background-color: var(--color-white-at-24);
+        }
+
+        &:disabled {
+            color: var(--color-white-at-12);
+            opacity: 0.8;
+        }
+
+        &:disabled:hover {
+            cursor: not-allowed;
+            background-color: var(--color-white-at-12);
+        }
+
+        &:focus-visible {
+            outline: 2px solid var(--ddg-color-primary);
+            border: 1px solid white;
+        }
+    }
 }
 
+
 .primary {
     background-color: var(--ddg-color-primary);
-    color: white;
-    margin-right: 10px;
+    color: var(--color-white);
 
-    @media screen and (prefers-color-scheme: dark) {
-        color: var(--color-white);
+
+    &:hover {
+        background-color: var(--color-blue-60);
     }
-}
 
-.primary:hover {
-    background-color: var(--color-blue-60);
-}
+    &:active {
+        background-color: var(--color-blue-70);
+    }
 
-.primary:active {
-    background-color: var(--color-blue-70);
-}
+    @media screen and (prefers-color-scheme: dark) {
+        color: var(--color-black-at-84);
+        background-color: var(--color-blue-20);
 
-.secondary {
-    margin-top: 10px;
+        &:hover {
+            background-color: var(--color-blue-30);
+        }
+
+        &:active {
+            background-color: var(--color-blue-40);
+        }
+
+        &:disabled {
+            background-color: var(--color-white-at-36);
+            color: var(--color-black-at-84);
+        }
+
+        &:focus-visible {
+            box-shadow: 0px 0px 0px 1px var(--color-blue-90), 0px 0px 0px 3px var(--color-white);
+        }
+    }
 }
\ No newline at end of file

From 2b335eedc9f5a8c523c1932c3e329fdf9fc895f4 Mon Sep 17 00:00:00 2001
From: Shane Osbourne <sosbourne@duckduckgo.com>
Date: Tue, 22 Oct 2024 14:25:17 +0100
Subject: [PATCH 18/40] re-use a json schema type for icons

---
 .../messages/new-tab/types/rmf-message.json   | 41 ++++++++-----------
 special-pages/types/new-tab.ts                |  7 ++--
 2 files changed, 22 insertions(+), 26 deletions(-)

diff --git a/special-pages/messages/new-tab/types/rmf-message.json b/special-pages/messages/new-tab/types/rmf-message.json
index 4110572e6..25df8891e 100644
--- a/special-pages/messages/new-tab/types/rmf-message.json
+++ b/special-pages/messages/new-tab/types/rmf-message.json
@@ -50,14 +50,8 @@
                             "type": "string"
                         },
                         "icon": {
-                            "enum": [
-                                "Announce",
-                                "DDGAnnounce",
-                                "CriticalUpdate",
-                                "AppUpdate",
-                                "PrivacyPro"
-                            ]
-                        },
+                            "$ref": "#/definitions/rmf-icon"
+                        }
                     },
                     "required": [
                         "messageType",
@@ -84,13 +78,7 @@
                             "type": "string"
                         },
                         "icon": {
-                            "enum": [
-                                "Announce",
-                                "DDGAnnounce",
-                                "CriticalUpdate",
-                                "AppUpdate",
-                                "PrivacyPro"
-                            ]
+                            "$ref": "#/definitions/rmf-icon"
                         },
                         "primaryActionText": {
                             "type": "string"
@@ -122,13 +110,7 @@
                             "type": "string"
                         },
                         "icon": {
-                            "enum": [
-                                "Announce",
-                                "DDGAnnounce",
-                                "CriticalUpdate",
-                                "AppUpdate",
-                                "PrivacyPro"
-                            ]
+                            "$ref": "#/definitions/rmf-icon"
                         },
                         "primaryActionText": {
                             "type": "string"
@@ -149,5 +131,18 @@
                 }
             ]
         }
+    },
+    "definitions": {
+        "rmf-icon": {
+            "title": "RMF Icon",
+            "type": "string",
+            "enum": [
+                "Announce",
+                "DDGAnnounce",
+                "CriticalUpdate",
+                "AppUpdate",
+                "PrivacyPro"
+            ]
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/special-pages/types/new-tab.ts b/special-pages/types/new-tab.ts
index 312c23b08..f713b7cbf 100644
--- a/special-pages/types/new-tab.ts
+++ b/special-pages/types/new-tab.ts
@@ -27,6 +27,7 @@ export type WidgetConfigs = WidgetConfigItem[];
  */
 export type Widgets = WidgetListItem[];
 export type RMFMessage = SmallMessage | MediumMessage | BigSingleActionMessage | BigTwoActionMessage;
+export type RMFIcon = "Announce" | "DDGAnnounce" | "CriticalUpdate" | "AppUpdate" | "PrivacyPro";
 
 /**
  * Requests, Notifications and Subscriptions from the NewTab feature
@@ -157,14 +158,14 @@ export interface MediumMessage {
   id: string;
   titleText: string;
   descriptionText: string;
-  icon: "Announce" | "DDGAnnounce" | "CriticalUpdate" | "AppUpdate" | "PrivacyPro";
+  icon: RMFIcon;
 }
 export interface BigSingleActionMessage {
   messageType: "big_single_action";
   id: string;
   titleText: string;
   descriptionText: string;
-  icon: "Announce" | "DDGAnnounce" | "CriticalUpdate" | "AppUpdate" | "PrivacyPro";
+  icon: RMFIcon;
   primaryActionText: string;
 }
 export interface BigTwoActionMessage {
@@ -172,7 +173,7 @@ export interface BigTwoActionMessage {
   id: string;
   titleText: string;
   descriptionText: string;
-  icon: "Announce" | "DDGAnnounce" | "CriticalUpdate" | "AppUpdate" | "PrivacyPro";
+  icon: RMFIcon;
   primaryActionText: string;
   secondaryActionText: string;
 }

From 8bb14199045578424407189e989a700e20867efa Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Tue, 22 Oct 2024 14:15:55 -0600
Subject: [PATCH 19/40] trying to not regress Examples.jsx

---
 .../pages/new-tab/app/components/Examples.jsx | 37 ++++++++++++-------
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/special-pages/pages/new-tab/app/components/Examples.jsx b/special-pages/pages/new-tab/app/components/Examples.jsx
index 5c204d3fe..9f76890ae 100644
--- a/special-pages/pages/new-tab/app/components/Examples.jsx
+++ b/special-pages/pages/new-tab/app/components/Examples.jsx
@@ -1,11 +1,9 @@
-import { Fragment, h } from "preact";
-import { PrivacyStatsMockProvider } from "../privacy-stats/mocks/PrivacyStatsMockProvider.js";
-import { Body, Heading, PrivacyStatsConsumer } from "../privacy-stats/PrivacyStats.js";
-import { RemoteMessagingFramework } from "../remote-messaging-framework/RemoteMessagingFramework.js";
-import { stats } from "../privacy-stats/mocks/stats.js";
-import { noop } from "../utils.js";
-import { VisibilityMenu } from "../customizer/VisibilityMenu.js";
-import { CustomizerButton } from "../customizer/Customizer.js";
+import { h } from 'preact'
+import { PrivacyStatsMockProvider } from '../privacy-stats/mocks/PrivacyStatsMockProvider.js'
+import { Body, Heading, PrivacyStatsConsumer } from '../privacy-stats/PrivacyStats.js'
+import { RemoteMessagingFramework } from '../remote-messaging-framework/RemoteMessagingFramework.js'
+import { stats } from '../privacy-stats/mocks/stats.js'
+import { noop } from '../utils.js'
 
 /** @type {Record<string, {factory: () => import("preact").ComponentChild}>} */
 export const mainExamples = {
@@ -26,13 +24,24 @@ export const mainExamples = {
             data={stats.norecent}><PrivacyStatsConsumer /></PrivacyStatsMockProvider>
     },
     'stats.list': {
-        factory: () => <Body trackerCompanies={stats.few.trackerCompanies} id='example-stats.list' />
+        factory: () => <Body trackerCompanies={stats.few.trackerCompanies} listAttrs={{ id: 'example-stats.list' }} />
     },
     'stats.heading': {
-        factory: () => <Heading trackerCompanies={stats.few.trackerCompanies} totalCount={stats.few.totalCount} />
+        factory: () => <Heading
+            trackerCompanies={stats.few.trackerCompanies}
+            totalCount={stats.few.totalCount}
+            expansion={'expanded'}
+            onToggle={noop('stats.heading onToggle')}
+        />
     },
     'stats.heading.none': {
-        factory: () => <Heading trackerCompanies={stats.none.trackerCompanies} totalCount={stats.none.totalCount} />
+        factory: () => (
+            <Heading
+                trackerCompanies={stats.none.trackerCompanies}
+                totalCount={stats.none.totalCount}
+                expansion={'expanded'}
+                onToggle={noop('stats.heading.none')}
+            />)
     },
     'rmf.small': {
         factory: () => (
@@ -68,7 +77,7 @@ export const mainExamples = {
                     icon: 'DDGAnnounce',
                     titleText: 'New Search Feature!',
                     descriptionText: 'DuckDuckGo now offers Instant Answers for quicker access to the information you need.',
-                    primaryActionText: 'Learn More',
+                    primaryActionText: 'Learn More'
                 }}
                 primaryAction={() => { }}
             />
@@ -84,7 +93,7 @@ export const mainExamples = {
                     titleText: 'Update Available',
                     descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.',
                     primaryActionText: 'How to update',
-                    secondaryActionText: 'Remind me later',
+                    secondaryActionText: 'Remind me later'
                 }}
                 primaryAction={() => { }}
                 secondaryAction={() => { }}
@@ -122,7 +131,7 @@ export const otherExamples = {
                     titleText: 'Update Available',
                     descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance. A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.',
                     primaryActionText: 'How to update Windows',
-                    secondaryActionText: 'Remind me later, but only if Iā€™m actually going to update soon',
+                    secondaryActionText: 'Remind me later, but only if Iā€™m actually going to update soon'
                 }}
                 primaryAction={() => { }}
                 secondaryAction={() => { }}

From 5fdc055b59bf503c014ca35fe5e92fd8471f5b2c Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Tue, 22 Oct 2024 17:33:01 -0600
Subject: [PATCH 20/40] chore: Improve rmf example on new-tab route

---
 special-pages/pages/new-tab/src/js/mock-transport.js | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/special-pages/pages/new-tab/src/js/mock-transport.js b/special-pages/pages/new-tab/src/js/mock-transport.js
index 91ea9b986..3e545915a 100644
--- a/special-pages/pages/new-tab/src/js/mock-transport.js
+++ b/special-pages/pages/new-tab/src/js/mock-transport.js
@@ -150,9 +150,11 @@ export function mockTransport () {
                 const payload = {
                     content: {
                         id: 'id-1',
-                        messageType: 'small',
-                        titleText: 'Hello world',
-                        descriptionText: 'My Description'
+                        messageType: 'big_single_action',
+                        titleText: 'Tell Us Your Thoughts on Privacy Pro',
+                        descriptionText: 'Take our short anonymous survey and share your feedback.',
+                        icon: 'Announce',
+                        primaryActionText: 'Take Survey'
                     }
                 }
                 if (url.searchParams.get('rmf') === 'medium') {

From 579df6f42f86ab7e0c876c37348643a9947e6c1a Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Tue, 22 Oct 2024 17:42:38 -0600
Subject: [PATCH 21/40] chore: Add tests for RMF

---
 .../integration-tests/rmf.spec.js             | 31 +++++++++++++++++++
 .../new-tab/integration-tests/new-tab.page.js |  4 +++
 .../new-tab/integration-tests/new-tab.spec.js |  2 ++
 special-pages/playwright.config.js            |  1 +
 4 files changed, 38 insertions(+)
 create mode 100644 special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
new file mode 100644
index 000000000..451fd7538
--- /dev/null
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
@@ -0,0 +1,31 @@
+import { test, expect } from '@playwright/test'
+import { NewtabPage } from '../../../integration-tests/new-tab.page.js'
+
+test.describe('newtab remote messaging framework rmf', () => {
+    test('fetches config + data', async ({ page }, workerInfo) => {
+        const ntp = NewtabPage.create(page, workerInfo)
+        await ntp.reducedMotion()
+        await ntp.openPage()
+
+        const calls1 = await ntp.mocks.waitForCallCount({ method: 'initialSetup', count: 1 })
+        const calls2 = await ntp.mocks.waitForCallCount({ method: 'rmf_getData', count: 1 })
+        const calls3 = await ntp.mocks.waitForCallCount({ method: 'rmf_getConfig', count: 1 })
+
+        expect(calls1.length).toBe(1)
+        expect(calls2.length).toBe(1)
+        expect(calls3.length).toBe(1)
+    })
+
+    test('renders a title and button', async ({ page }, workerInfo) => {
+        const ntp = NewtabPage.create(page, workerInfo)
+        await ntp.reducedMotion()
+        await ntp.openPage()
+
+        const titleText = page.getByText('Tell Us Your Thoughts on Privacy Pro')
+        const button = page.getByRole('button', { name: 'Take Survey' })
+        // await page.waitForTimeout(200)
+
+        expect(titleText).toBeVisible()
+        expect(button).toBeVisible()
+    })
+})
diff --git a/special-pages/pages/new-tab/integration-tests/new-tab.page.js b/special-pages/pages/new-tab/integration-tests/new-tab.page.js
index 75f645ec1..2fd314549 100644
--- a/special-pages/pages/new-tab/integration-tests/new-tab.page.js
+++ b/special-pages/pages/new-tab/integration-tests/new-tab.page.js
@@ -30,10 +30,12 @@ export class NewtabPage {
             /** @type {import('../../../types/new-tab.ts').InitialSetupResponse} */
             initialSetup: {
                 widgets: [
+                    { id: 'rmf' },
                     { id: 'favorites' },
                     { id: 'privacyStats' }
                 ],
                 widgetConfigs: [
+                    { id: 'rmf', visibility: 'visible' },
                     { id: 'favorites', visibility: 'visible' },
                     { id: 'privacyStats', visibility: 'visible' }
                 ],
@@ -45,6 +47,8 @@ export class NewtabPage {
             },
             stats_getConfig: {},
             stats_getData: {},
+            rmf_getConfig: {},
+            rmf_getData: {},
             widgets_setConfig: {}
         })
     }
diff --git a/special-pages/pages/new-tab/integration-tests/new-tab.spec.js b/special-pages/pages/new-tab/integration-tests/new-tab.spec.js
index c7e39d860..0c2f42db9 100644
--- a/special-pages/pages/new-tab/integration-tests/new-tab.spec.js
+++ b/special-pages/pages/new-tab/integration-tests/new-tab.spec.js
@@ -24,6 +24,7 @@ test.describe('newtab widgets', () => {
                 context: 'specialPages',
                 featureName: 'newTabPage',
                 params: [
+                    { id: 'rmf', visibility: 'visible' },
                     { id: 'favorites', visibility: 'visible' },
                     { id: 'privacyStats', visibility: 'hidden' }
                 ],
@@ -55,6 +56,7 @@ test.describe('newtab widgets', () => {
                 context: 'specialPages',
                 featureName: 'newTabPage',
                 params: [
+                    { id: 'rmf', visibility: 'visible' },
                     { id: 'favorites', visibility: 'visible' },
                     { id: 'privacyStats', visibility: 'visible' }
                 ],
diff --git a/special-pages/playwright.config.js b/special-pages/playwright.config.js
index 2fe20c951..2ce0b63ac 100644
--- a/special-pages/playwright.config.js
+++ b/special-pages/playwright.config.js
@@ -19,6 +19,7 @@ export default defineConfig({
             name: 'integration',
             testMatch: [
                 'privacy-stats.spec.js',
+                'rmf.spec.js',
                 'new-tab.spec.js'
             ],
             use: {

From a005adffc907b345d82d7f533541a6202637f962 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Tue, 22 Oct 2024 17:55:02 -0600
Subject: [PATCH 22/40] fix(attempt): Added an rmfParam to ntp.openPage method

---
 .../integration-tests/rmf.spec.js                         | 7 +++----
 .../pages/new-tab/integration-tests/new-tab.page.js       | 8 +++++++-
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
index 451fd7538..924b04ec7 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
@@ -19,11 +19,10 @@ test.describe('newtab remote messaging framework rmf', () => {
     test('renders a title and button', async ({ page }, workerInfo) => {
         const ntp = NewtabPage.create(page, workerInfo)
         await ntp.reducedMotion()
-        await ntp.openPage()
+        await ntp.openPage({ rmfParam: 'rmf.big-two-action' })
 
-        const titleText = page.getByText('Tell Us Your Thoughts on Privacy Pro')
-        const button = page.getByRole('button', { name: 'Take Survey' })
-        // await page.waitForTimeout(200)
+        const titleText = page.getByText('Update Available')
+        const button = page.getByRole('button', { name: 'How to update' })
 
         expect(titleText).toBeVisible()
         expect(button).toBeVisible()
diff --git a/special-pages/pages/new-tab/integration-tests/new-tab.page.js b/special-pages/pages/new-tab/integration-tests/new-tab.page.js
index 2fd314549..7e3813731 100644
--- a/special-pages/pages/new-tab/integration-tests/new-tab.page.js
+++ b/special-pages/pages/new-tab/integration-tests/new-tab.page.js
@@ -61,8 +61,9 @@ export class NewtabPage {
      * @param {'debug' | 'production'} [params.mode] - Optional parameters for opening the page.
      * @param {boolean} [params.willThrow] - Optional flag to simulate an exception
      * @param {number} [params.favoritesCount] - Optional flag to preload a list of favorites
+     * @param {string} [params.rmfParam] - Optional flag to point to display=components view with certain rmf example visible
      */
-    async openPage ({ mode = 'debug', willThrow = false, favoritesCount } = { }) {
+    async openPage ({ mode = 'debug', willThrow = false, favoritesCount, rmfParam } = { }) {
         await this.mocks.install()
         await this.page.route('/**', (route, req) => {
             const url = new URL(req.url())
@@ -81,6 +82,11 @@ export class NewtabPage {
             searchParams.set('favorites', String(favoritesCount))
         }
 
+        if (rmfParam !== undefined) {
+            searchParams.set('display', 'components')
+            searchParams.set('id', rmfParam)
+        }
+
         await this.page.goto('/' + '?' + searchParams.toString())
     }
 

From 7861e627d03623d2f95863b5b8db061f2e1205d2 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Tue, 22 Oct 2024 18:20:21 -0600
Subject: [PATCH 23/40] feat: Added type to shared Button component

---
 special-pages/shared/components/Button/Button.js | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/special-pages/shared/components/Button/Button.js b/special-pages/shared/components/Button/Button.js
index 4007583bc..1f0d4ad21 100644
--- a/special-pages/shared/components/Button/Button.js
+++ b/special-pages/shared/components/Button/Button.js
@@ -6,14 +6,16 @@ import styles from './Button.module.css'
  * @param {object} props
  * @param {string} [props.className]
  * @param {'primary'|'standard'|'accent'|'ghost'} [props.variant]
+ * @param {'button'|'submit'|'reset'} [props.type]
  * @param {import("preact").ComponentChild} props.children
  * @param {import("preact").JSX.MouseEventHandler<EventTarget>} [props.onClick]
  * @param {import('preact').ComponentProps<'button'>} [props.otherProps]
  */
-export function Button ({ variant, className, children, onClick }) {
+export function Button ({ variant, className, children, onClick, type = 'button' }) {
     return (
         <button
             className={classNames(styles.button, { [styles[`${variant}`]]: !!variant }, className)}
+            type={type}
             onClick={
                 /**
                  * @param {import("preact").JSX.TargetedMouseEvent<EventTarget>} event

From 9afe9cb551febf60d469713086eb5fd8ff07c39d Mon Sep 17 00:00:00 2001
From: Shane Osbourne <sosbourne@duckduckgo.com>
Date: Wed, 23 Oct 2024 14:25:13 +0100
Subject: [PATCH 24/40] rmf: removed configurability + fixed tests

---
 .../new-tab/rmf_getConfig.request.json        |  3 --
 .../new-tab/rmf_getConfig.response.json       |  8 ----
 .../messages/new-tab/types/rmf-config.json    |  9 -----
 .../messages/new-tab/types/rmf-message.json   |  4 +-
 .../app/privacy-stats/PrivacyStatsProvider.js |  4 +-
 .../remote-messaging-framework/RMFProvider.js | 27 +++++--------
 .../RemoteMessagingFramework.js               |  4 +-
 .../integration-tests/rmf.spec.js             |  9 ++---
 .../remote-messaging-framework/rmf.service.js | 20 +---------
 .../pages/new-tab/app/service.hooks.js        | 40 ++++++++++++++++++-
 .../new-tab/integration-tests/new-tab.page.js |  9 ++---
 .../pages/new-tab/src/js/mock-transport.js    | 20 +++++-----
 special-pages/types/new-tab.ts                | 17 +++-----
 13 files changed, 78 insertions(+), 96 deletions(-)
 delete mode 100644 special-pages/messages/new-tab/rmf_getConfig.request.json
 delete mode 100644 special-pages/messages/new-tab/rmf_getConfig.response.json
 delete mode 100644 special-pages/messages/new-tab/types/rmf-config.json

diff --git a/special-pages/messages/new-tab/rmf_getConfig.request.json b/special-pages/messages/new-tab/rmf_getConfig.request.json
deleted file mode 100644
index 0af74a319..000000000
--- a/special-pages/messages/new-tab/rmf_getConfig.request.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "$schema": "http://json-schema.org/draft-07/schema#"
-}
diff --git a/special-pages/messages/new-tab/rmf_getConfig.response.json b/special-pages/messages/new-tab/rmf_getConfig.response.json
deleted file mode 100644
index 4d206fc5d..000000000
--- a/special-pages/messages/new-tab/rmf_getConfig.response.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "$schema": "http://json-schema.org/draft-07/schema#",
-  "allOf": [
-    {
-      "$ref": "./types/rmf-config.json"
-    }
-  ]
-}
diff --git a/special-pages/messages/new-tab/types/rmf-config.json b/special-pages/messages/new-tab/types/rmf-config.json
deleted file mode 100644
index e518b2453..000000000
--- a/special-pages/messages/new-tab/types/rmf-config.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "$schema": "http://json-schema.org/draft-07/schema#",
-  "title": "RMFConfig",
-  "type": "object",
-  "required": ["expansion"],
-  "properties": {
-    "expansion": {"$ref":  "./expansion.json"}
-  }
-}
diff --git a/special-pages/messages/new-tab/types/rmf-message.json b/special-pages/messages/new-tab/types/rmf-message.json
index 25df8891e..a0ffad633 100644
--- a/special-pages/messages/new-tab/types/rmf-message.json
+++ b/special-pages/messages/new-tab/types/rmf-message.json
@@ -2,9 +2,7 @@
     "$schema": "http://json-schema.org/draft-07/schema#",
     "type": "object",
     "title": "RMF Data",
-    "required": [
-        "content"
-    ],
+    "description": "The 'content' field is optional. Use that fact to show/hide messages",
     "properties": {
         "content": {
             "title": "RMF Message",
diff --git a/special-pages/pages/new-tab/app/privacy-stats/PrivacyStatsProvider.js b/special-pages/pages/new-tab/app/privacy-stats/PrivacyStatsProvider.js
index 8bf86a074..e778c0825 100644
--- a/special-pages/pages/new-tab/app/privacy-stats/PrivacyStatsProvider.js
+++ b/special-pages/pages/new-tab/app/privacy-stats/PrivacyStatsProvider.js
@@ -2,7 +2,7 @@ import { createContext, h } from 'preact'
 import { useEffect, useReducer, useRef } from 'preact/hooks'
 import { useMessaging } from '../types.js'
 import { PrivacyStatsService } from './privacy-stats.service.js'
-import { reducer, useConfigSubscription, useDataSubscription, useInitialData } from '../service.hooks.js'
+import { reducer, useConfigSubscription, useDataSubscription, useInitialDataAndConfig } from '../service.hooks.js'
 
 /**
  * @typedef {import('../../../../types/new-tab.js').PrivacyStatsData} PrivacyStatsData
@@ -46,7 +46,7 @@ export function PrivacyStatsProvider (props) {
     const service = useService()
 
     // get initial data
-    useInitialData({ dispatch, service })
+    useInitialDataAndConfig({ dispatch, service })
 
     // subscribe to data updates
     useDataSubscription({ dispatch, service })
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
index e50f02d07..524f1a4d2 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
@@ -2,13 +2,16 @@ import { createContext, h } from 'preact'
 import { useCallback, useEffect, useReducer, useRef } from 'preact/hooks'
 import { useMessaging } from '../types.js'
 import { RMFService } from './rmf.service.js'
-import { reducer, useConfigSubscription, useDataSubscription, useInitialData } from '../service.hooks.js'
+import {
+    reducer,
+    useDataSubscription,
+    useInitialData
+} from '../service.hooks.js'
 
 /**
  * @typedef {import('../../../../types/new-tab.js').RMFData} RMFData
- * @typedef {import('../../../../types/new-tab.js').RMFConfig} RMFConfig
- * @typedef {import('../service.hooks.js').State<RMFData, RMFConfig>} State
- * @typedef {import('../service.hooks.js').Events<RMFData, RMFConfig>} Events
+ * @typedef {import('../service.hooks.js').State<RMFData, undefined>} State
+ * @typedef {import('../service.hooks.js').Events<RMFData, undefined>} Events
  */
 
 /**
@@ -18,11 +21,7 @@ export const RMFContext = createContext({
     /** @type {State} */
     state: { status: 'idle', data: null, config: null },
     /** @type {() => void} */
-    toggle: () => {
-        throw new Error('must implement')
-    },
-    /** @type {() => void} */
-    onDismiss: () => {
+    dismiss: () => {
         throw new Error('must implement')
     },
     /** @type {() => void} */
@@ -63,10 +62,8 @@ export function RMFProvider (props) {
     // subscribe to data updates
     useDataSubscription({ dispatch, service })
 
-    // subscribe to toggle + expose a fn for sync toggling
-    const { toggle } = useConfigSubscription({ dispatch, service })
-
-    const onDismiss = useCallback(() => {
+    // todo(valerie): implement onDismiss in the service
+    const dismiss = useCallback(() => {
         console.log('onDismiss')
     }, [service])
 
@@ -78,10 +75,8 @@ export function RMFProvider (props) {
         console.log('secondaryAction')
     }, [service])
 
-    console.log(state)
-
     return (
-        <RMFContext.Provider value={{ state, toggle, onDismiss, primaryAction, secondaryAction }}>
+        <RMFContext.Provider value={{ state, dismiss, primaryAction, secondaryAction }}>
             <RMFDispatchContext.Provider value={dispatch}>
                 {props.children}
             </RMFDispatchContext.Provider>
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index 32802ab93..645c11122 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -48,7 +48,9 @@ export function RemoteMessagingFramework ({ message, primaryAction, secondaryAct
 
 export function RMFConsumer () {
     const { state, primaryAction, secondaryAction } = useContext(RMFContext)
-    if (state.status === 'ready') {
+
+    // `state.data.content` can be empty - meaning there's no message to display!
+    if (state.status === 'ready' && state.data.content) {
         return (
             <RemoteMessagingFramework
                 message={state.data.content}
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
index 924b04ec7..3bc75259f 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
@@ -19,12 +19,9 @@ test.describe('newtab remote messaging framework rmf', () => {
     test('renders a title and button', async ({ page }, workerInfo) => {
         const ntp = NewtabPage.create(page, workerInfo)
         await ntp.reducedMotion()
-        await ntp.openPage({ rmfParam: 'rmf.big-two-action' })
+        await ntp.openPage({ rmf: 'big_single_action' })
 
-        const titleText = page.getByText('Update Available')
-        const button = page.getByRole('button', { name: 'How to update' })
-
-        expect(titleText).toBeVisible()
-        expect(button).toBeVisible()
+        await page.getByRole('button', { name: 'Take Survey' }).waitFor()
+        await page.getByText('Tell Us Your Thoughts on Privacy Pro').waitFor()
     })
 })
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js b/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
index e4d6870de..9f932fc42 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
@@ -1,7 +1,6 @@
 /**
  * @typedef {import("../../../../types/new-tab.js").RMFData} RMFData
  * @typedef {import("../../../../types/new-tab.js").StatsConfig} StatsConfig
- * @typedef {import("../../../../types/new-tab.js").RMFConfig} RMFConfig
  */
 import { Service } from '../service.js'
 
@@ -20,21 +19,14 @@ export class RMFService {
             initial: () => ntp.messaging.request('rmf_getData'),
             subscribe: (cb) => ntp.messaging.subscribe('rmf_onDataUpdate', cb)
         })
-        /** @type {Service<RMFConfig>} */
-        this.configService = new Service({
-            initial: () => ntp.messaging.request('rmf_getConfig')
-        })
     }
 
     /**
-     * @returns {Promise<{data: RMFData; config: RMFConfig}>}
+     * @returns {Promise<RMFData>}
      * @internal
      */
     async getInitial () {
-        const p1 = this.configService.fetchInitial()
-        const p2 = this.dataService.fetchInitial()
-        const [config, data] = await Promise.all([p1, p2])
-        return { config, data }
+        return await this.dataService.fetchInitial()
     }
 
     /**
@@ -52,14 +44,6 @@ export class RMFService {
         return this.dataService.onData(cb)
     }
 
-    /**
-     * @param {(evt: {data: RMFConfig, source: 'manual' | 'subscription'}) => void} cb
-     * @internal
-     */
-    onConfig (cb) {
-        return this.configService.onData(cb)
-    }
-
     /**
      * @param {(evt: {data: RMFData, source: 'manual' | 'subscription'}) => void} cb
      * @internal
diff --git a/special-pages/pages/new-tab/app/service.hooks.js b/special-pages/pages/new-tab/app/service.hooks.js
index 89a0918c8..da00ec355 100644
--- a/special-pages/pages/new-tab/app/service.hooks.js
+++ b/special-pages/pages/new-tab/app/service.hooks.js
@@ -26,7 +26,7 @@ import { useCallback, useEffect } from 'preact/hooks'
 
 /**
  * @template D
- * @template {{expansion: import("../../../types/new-tab").Expansion}} C
+ * @template {{expansion: import("../../../types/new-tab").Expansion}|undefined} C
  * @param {State<D, C>} state
  * @param {Events<D, C>} event
  */
@@ -88,7 +88,7 @@ export function reducer (state, event) {
  *   destroy: () => void;
  * }>} params.service
  */
-export function useInitialData ({ dispatch, service }) {
+export function useInitialDataAndConfig ({ dispatch, service }) {
     useEffect(() => {
         if (!service.current) return console.warn('missing service')
         const stats = service.current
@@ -115,6 +115,42 @@ export function useInitialData ({ dispatch, service }) {
     }, [])
 }
 
+/**
+ * @template D
+ * @param {object} params
+ * @param {import("preact/hooks").Dispatch<any>} params.dispatch
+ * @param {import("preact").RefObject<{
+ *   getInitial: () => Promise<D>;
+ *   destroy: () => void;
+ * }>} params.service
+ */
+export function useInitialData ({ dispatch, service }) {
+    useEffect(() => {
+        if (!service.current) return console.warn('missing service')
+        const stats = service.current
+        async function init () {
+            const data = await stats.getInitial()
+            if (data) {
+                dispatch({ kind: 'initial-data', data })
+            } else {
+                dispatch({ kind: 'error', error: 'missing data from getInitial' })
+            }
+        }
+
+        dispatch({ kind: 'load-initial' })
+
+        // eslint-disable-next-line promise/prefer-await-to-then
+        init().catch((e) => {
+            console.error('uncaught error', e)
+            dispatch({ kind: 'error', error: e })
+        })
+
+        return () => {
+            stats.destroy()
+        }
+    }, [])
+}
+
 /**
  * Subscribe to data updates
  * @template Data
diff --git a/special-pages/pages/new-tab/integration-tests/new-tab.page.js b/special-pages/pages/new-tab/integration-tests/new-tab.page.js
index 7e3813731..b49eccff1 100644
--- a/special-pages/pages/new-tab/integration-tests/new-tab.page.js
+++ b/special-pages/pages/new-tab/integration-tests/new-tab.page.js
@@ -61,9 +61,9 @@ export class NewtabPage {
      * @param {'debug' | 'production'} [params.mode] - Optional parameters for opening the page.
      * @param {boolean} [params.willThrow] - Optional flag to simulate an exception
      * @param {number} [params.favoritesCount] - Optional flag to preload a list of favorites
-     * @param {string} [params.rmfParam] - Optional flag to point to display=components view with certain rmf example visible
+     * @param {string} [params.rmf] - Optional flag to point to display=components view with certain rmf example visible
      */
-    async openPage ({ mode = 'debug', willThrow = false, favoritesCount, rmfParam } = { }) {
+    async openPage ({ mode = 'debug', willThrow = false, favoritesCount, rmf } = { }) {
         await this.mocks.install()
         await this.page.route('/**', (route, req) => {
             const url = new URL(req.url())
@@ -82,9 +82,8 @@ export class NewtabPage {
             searchParams.set('favorites', String(favoritesCount))
         }
 
-        if (rmfParam !== undefined) {
-            searchParams.set('display', 'components')
-            searchParams.set('id', rmfParam)
+        if (rmf !== undefined) {
+            searchParams.set('rmf', rmf)
         }
 
         await this.page.goto('/' + '?' + searchParams.toString())
diff --git a/special-pages/pages/new-tab/src/js/mock-transport.js b/special-pages/pages/new-tab/src/js/mock-transport.js
index 3e545915a..3ce45d975 100644
--- a/special-pages/pages/new-tab/src/js/mock-transport.js
+++ b/special-pages/pages/new-tab/src/js/mock-transport.js
@@ -140,15 +140,13 @@ export function mockTransport () {
                 }
                 return Promise.resolve(fromStorage)
             }
-            case 'rmf_getConfig': {
-                /** @type {import('../../../../types/new-tab').RMFConfig} */
-                const defaultConfig = { expansion: 'expanded' }
-                return Promise.resolve(defaultConfig)
-            }
             case 'rmf_getData': {
                 /** @type {import('../../../../types/new-tab.js').RMFData} */
-                const payload = {
-                    content: {
+                const message = { content: undefined }
+
+                /** @type {import('../../../../types/new-tab.js').RMFData} */
+                if (url.searchParams.get('rmf') === 'big_single_action') {
+                    message.content = {
                         id: 'id-1',
                         messageType: 'big_single_action',
                         titleText: 'Tell Us Your Thoughts on Privacy Pro',
@@ -158,7 +156,7 @@ export function mockTransport () {
                     }
                 }
                 if (url.searchParams.get('rmf') === 'medium') {
-                    payload.content = {
+                    message.content = {
                         messageType: 'medium',
                         icon: 'Announce',
                         id: 'id-2',
@@ -166,7 +164,8 @@ export function mockTransport () {
                         descriptionText: 'Here is some mighty fine content'
                     }
                 }
-                return Promise.resolve(payload)
+
+                return Promise.resolve(message)
             }
             case 'initialSetup': {
                 const widgetsFromStorage = read('widgets') || [
@@ -177,8 +176,7 @@ export function mockTransport () {
 
                 const widgetConfigFromStorage = read('widget_config') || [
                     { id: 'favorites', visibility: 'visible' },
-                    { id: 'privacyStats', visibility: 'visible' },
-                    { id: 'rmf', visibility: 'visible' }
+                    { id: 'privacyStats', visibility: 'visible' }
                 ]
 
                 /** @type {import('../../../../types/new-tab.js').InitialSetupResponse} */
diff --git a/special-pages/types/new-tab.ts b/special-pages/types/new-tab.ts
index f713b7cbf..5e335e455 100644
--- a/special-pages/types/new-tab.ts
+++ b/special-pages/types/new-tab.ts
@@ -38,7 +38,7 @@ export interface NewTabMessages {
     | ReportPageExceptionNotification
     | StatsSetConfigNotification
     | WidgetsSetConfigNotification;
-  requests: InitialSetupRequest | RmfGetConfigRequest | RmfGetDataRequest | StatsGetConfigRequest | StatsGetDataRequest;
+  requests: InitialSetupRequest | RmfGetDataRequest | StatsGetConfigRequest | StatsGetDataRequest;
   subscriptions:
     | RmfOnDataUpdateSubscription
     | StatsOnConfigUpdateSubscription
@@ -127,16 +127,6 @@ export interface WidgetListItem {
    */
   id: string;
 }
-/**
- * Generated from @see "../messages/new-tab/rmf_getConfig.request.json"
- */
-export interface RmfGetConfigRequest {
-  method: "rmf_getConfig";
-  result: RMFConfig;
-}
-export interface RMFConfig {
-  expansion: Expansion;
-}
 /**
  * Generated from @see "../messages/new-tab/rmf_getData.request.json"
  */
@@ -144,8 +134,11 @@ export interface RmfGetDataRequest {
   method: "rmf_getData";
   result: RMFData;
 }
+/**
+ * The 'content' field is optional. Use that fact to show/hide messages
+ */
 export interface RMFData {
-  content: RMFMessage;
+  content?: RMFMessage;
 }
 export interface SmallMessage {
   messageType: "small";

From 2f1bcccdaafe6421f7a28ba28298d3126953b8fd Mon Sep 17 00:00:00 2001
From: Shane Osbourne <sosbourne@duckduckgo.com>
Date: Wed, 23 Oct 2024 14:32:20 +0100
Subject: [PATCH 25/40] support widgets without config

---
 .../integration-tests/rmf.spec.js                         | 4 +---
 special-pages/pages/new-tab/app/widget-list/WidgetList.js | 8 ++++++++
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
index 3bc75259f..2739aa47a 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
@@ -5,15 +5,13 @@ test.describe('newtab remote messaging framework rmf', () => {
     test('fetches config + data', async ({ page }, workerInfo) => {
         const ntp = NewtabPage.create(page, workerInfo)
         await ntp.reducedMotion()
-        await ntp.openPage()
+        await ntp.openPage({ rmf: 'medium' })
 
         const calls1 = await ntp.mocks.waitForCallCount({ method: 'initialSetup', count: 1 })
         const calls2 = await ntp.mocks.waitForCallCount({ method: 'rmf_getData', count: 1 })
-        const calls3 = await ntp.mocks.waitForCallCount({ method: 'rmf_getConfig', count: 1 })
 
         expect(calls1.length).toBe(1)
         expect(calls2.length).toBe(1)
-        expect(calls3.length).toBe(1)
     })
 
     test('renders a title and button', async ({ page }, workerInfo) => {
diff --git a/special-pages/pages/new-tab/app/widget-list/WidgetList.js b/special-pages/pages/new-tab/app/widget-list/WidgetList.js
index 16727a31d..df0da9708 100644
--- a/special-pages/pages/new-tab/app/widget-list/WidgetList.js
+++ b/special-pages/pages/new-tab/app/widget-list/WidgetList.js
@@ -30,6 +30,14 @@ export function WidgetList () {
             {widgets.map((widget) => {
                 const matchingConfig = widgetConfigItems.find(item => item.id === widget.id)
                 if (!matchingConfig) {
+                    const matching = widgetMap[widget.id];
+                    if (matching) {
+                        return (
+                            <Fragment key={widget.id}>
+                                {matching?.()}
+                            </Fragment>
+                        )
+                    }
                     console.warn('missing config for widget: ', widget)
                     return null
                 }

From 25e1b5c76fc2b7f965fd8cd71c9e08eb236d6de2 Mon Sep 17 00:00:00 2001
From: Shane Osbourne <sosbourne@duckduckgo.com>
Date: Wed, 23 Oct 2024 16:35:44 +0100
Subject: [PATCH 26/40] added primary action

---
 .../messages/new-tab/rmf_primaryAction.notify.json  | 11 +++++++++++
 .../app/remote-messaging-framework/RMFProvider.js   | 13 +++++++------
 .../RemoteMessagingFramework.js                     |  6 +++---
 .../integration-tests/rmf.spec.js                   |  3 ++-
 .../app/remote-messaging-framework/rmf.service.js   |  7 +++++++
 .../pages/new-tab/src/js/mock-transport.js          |  4 ++++
 special-pages/types/new-tab.ts                      | 11 +++++++++++
 7 files changed, 45 insertions(+), 10 deletions(-)
 create mode 100644 special-pages/messages/new-tab/rmf_primaryAction.notify.json

diff --git a/special-pages/messages/new-tab/rmf_primaryAction.notify.json b/special-pages/messages/new-tab/rmf_primaryAction.notify.json
new file mode 100644
index 000000000..e42af6ffc
--- /dev/null
+++ b/special-pages/messages/new-tab/rmf_primaryAction.notify.json
@@ -0,0 +1,11 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "RMF Primary Action",
+  "type": "object",
+  "required": ["id"],
+  "properties": {
+    "id": {
+      "type": "string"
+    }
+  }
+}
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
index 524f1a4d2..13a53add1 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
@@ -24,9 +24,9 @@ export const RMFContext = createContext({
     dismiss: () => {
         throw new Error('must implement')
     },
-    /** @type {() => void} */
-    primaryAction: () => {
-        throw new Error('must implement')
+    /** @type {(id: string) => void} */
+    primaryAction: (id) => {
+        throw new Error('must implement ' + id)
     },
     /** @type {() => void} */
     secondaryAction: () => {
@@ -63,12 +63,13 @@ export function RMFProvider (props) {
     useDataSubscription({ dispatch, service })
 
     // todo(valerie): implement onDismiss in the service
-    const dismiss = useCallback(() => {
+    const dismiss = useCallback((id) => {
         console.log('onDismiss')
+        service.current?.dismiss(id)
     }, [service])
 
-    const primaryAction = useCallback(() => {
-        console.log('primaryAction')
+    const primaryAction = useCallback((id) => {
+        service.current?.primaryAction(id)
     }, [service])
 
     const secondaryAction = useCallback(() => {
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index 645c11122..cc01e535e 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -9,7 +9,7 @@ import { RMFContext } from './RMFProvider.js'
   * @import { RMFMessage } from "../../../../types/new-tab"
   * @param {object} props
   * @param {RMFMessage} props.message
-  * @param {() => void} [props.primaryAction]
+  * @param {(id: string) => void} [props.primaryAction]
   * @param {() => void} [props.secondaryAction]
   */
 
@@ -28,7 +28,7 @@ export function RemoteMessagingFramework ({ message, primaryAction, secondaryAct
                 {messageType === 'big_two_action' && (
                     <div class={styles.btnRow}>
                         {primaryAction && message.primaryActionText.length > 0 && (
-                            <button class={cn(styles.btn, styles.primary)} onClick={primaryAction}>{message.primaryActionText}</button>
+                            <button class={cn(styles.btn, styles.primary)} onClick={() => primaryAction(id)}>{message.primaryActionText}</button>
                         )}
                         {secondaryAction && message.secondaryActionText.length > 0 && (
                             <button class={cn(styles.btn, styles.secondary)} onClick={secondaryAction}>{message.secondaryActionText}</button>
@@ -38,7 +38,7 @@ export function RemoteMessagingFramework ({ message, primaryAction, secondaryAct
             </div>
             {messageType === 'big_single_action' && message.primaryActionText && primaryAction && (
                 <div class={styles.btnBlock}>
-                    <button class={cn(styles.btn)} onClick={primaryAction}>{message.primaryActionText}</button>
+                    <button class={cn(styles.btn)} onClick={() => primaryAction(id)}>{message.primaryActionText}</button>
                 </div>
             )}
         </div>
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
index 2739aa47a..621ba523a 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
@@ -19,7 +19,8 @@ test.describe('newtab remote messaging framework rmf', () => {
         await ntp.reducedMotion()
         await ntp.openPage({ rmf: 'big_single_action' })
 
-        await page.getByRole('button', { name: 'Take Survey' }).waitFor()
         await page.getByText('Tell Us Your Thoughts on Privacy Pro').waitFor()
+        await page.getByRole('button', { name: 'Take Survey' }).click();
+        await ntp.mocks.waitForCallCount({ method: 'rmf_primaryAction', count: 1 })
     })
 })
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js b/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
index 9f932fc42..b8d32060a 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
@@ -54,4 +54,11 @@ export class RMFService {
     }
 
     toggleExpansion () { }
+
+    /**
+     * @param {string} id
+     */
+    primaryAction(id) {
+        this.ntp.messaging.notify('rmf_primaryAction', { id })
+    }
 }
diff --git a/special-pages/pages/new-tab/src/js/mock-transport.js b/special-pages/pages/new-tab/src/js/mock-transport.js
index 3ce45d975..29f99d824 100644
--- a/special-pages/pages/new-tab/src/js/mock-transport.js
+++ b/special-pages/pages/new-tab/src/js/mock-transport.js
@@ -68,6 +68,10 @@ export function mockTransport () {
                 broadcast('stats_config')
                 return
             }
+            case 'rmf_primaryAction': {
+                console.log('ignoring rmf_primaryAction', msg.params)
+                return
+            }
             default: {
                 console.warn('unhandled notification', msg)
             }
diff --git a/special-pages/types/new-tab.ts b/special-pages/types/new-tab.ts
index 5e335e455..c7e573c8b 100644
--- a/special-pages/types/new-tab.ts
+++ b/special-pages/types/new-tab.ts
@@ -36,6 +36,7 @@ export interface NewTabMessages {
   notifications:
     | ReportInitExceptionNotification
     | ReportPageExceptionNotification
+    | RmfPrimaryActionNotification
     | StatsSetConfigNotification
     | WidgetsSetConfigNotification;
   requests: InitialSetupRequest | RmfGetDataRequest | StatsGetConfigRequest | StatsGetDataRequest;
@@ -65,6 +66,16 @@ export interface ReportPageExceptionNotification {
 export interface ReportPageExceptionNotify {
   message: string;
 }
+/**
+ * Generated from @see "../messages/new-tab/rmf_primaryAction.notify.json"
+ */
+export interface RmfPrimaryActionNotification {
+  method: "rmf_primaryAction";
+  params: RMFPrimaryAction;
+}
+export interface RMFPrimaryAction {
+  id: string;
+}
 /**
  * Generated from @see "../messages/new-tab/stats_setConfig.notify.json"
  */

From c8bc344ea1493c03afdcd6b40c62470f0c1a9c79 Mon Sep 17 00:00:00 2001
From: Shane Osbourne <sosbourne@duckduckgo.com>
Date: Wed, 23 Oct 2024 16:38:55 +0100
Subject: [PATCH 27/40] lint

---
 .../remote-messaging-framework/integration-tests/rmf.spec.js    | 2 +-
 .../pages/new-tab/app/remote-messaging-framework/rmf.service.js | 2 +-
 special-pages/pages/new-tab/app/widget-list/WidgetList.js       | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
index 621ba523a..36d26c92a 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
@@ -20,7 +20,7 @@ test.describe('newtab remote messaging framework rmf', () => {
         await ntp.openPage({ rmf: 'big_single_action' })
 
         await page.getByText('Tell Us Your Thoughts on Privacy Pro').waitFor()
-        await page.getByRole('button', { name: 'Take Survey' }).click();
+        await page.getByRole('button', { name: 'Take Survey' }).click()
         await ntp.mocks.waitForCallCount({ method: 'rmf_primaryAction', count: 1 })
     })
 })
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js b/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
index b8d32060a..db5e5b6b2 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
@@ -58,7 +58,7 @@ export class RMFService {
     /**
      * @param {string} id
      */
-    primaryAction(id) {
+    primaryAction (id) {
         this.ntp.messaging.notify('rmf_primaryAction', { id })
     }
 }
diff --git a/special-pages/pages/new-tab/app/widget-list/WidgetList.js b/special-pages/pages/new-tab/app/widget-list/WidgetList.js
index df0da9708..b6b6712f5 100644
--- a/special-pages/pages/new-tab/app/widget-list/WidgetList.js
+++ b/special-pages/pages/new-tab/app/widget-list/WidgetList.js
@@ -30,7 +30,7 @@ export function WidgetList () {
             {widgets.map((widget) => {
                 const matchingConfig = widgetConfigItems.find(item => item.id === widget.id)
                 if (!matchingConfig) {
-                    const matching = widgetMap[widget.id];
+                    const matching = widgetMap[widget.id]
                     if (matching) {
                         return (
                             <Fragment key={widget.id}>

From 2b57ca726705e61c5620601588bdd0dd09c97bc8 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Wed, 23 Oct 2024 19:26:45 -0600
Subject: [PATCH 28/40] chore: Add dismiss and secondaryAction

---
 .../messages/new-tab/rmf_dismiss.notify.json  | 13 +++++
 .../new-tab/rmf_secondaryAction.notify.json   | 13 +++++
 .../pages/new-tab/app/components/Examples.jsx | 13 +++--
 .../remote-messaging-framework/RMFProvider.js | 17 +++---
 .../RemoteMessagingFramework.js               | 14 +++--
 .../RemoteMessagingFramework.module.css       | 37 +++++++++++-
 .../integration-tests/rmf.spec.js             | 14 ++++-
 .../remote-messaging-framework/rmf.service.js | 14 +++--
 .../pages/new-tab/src/js/mock-transport.js    | 56 ++++++++++++++++---
 special-pages/types/new-tab.ts                | 22 ++++++++
 10 files changed, 180 insertions(+), 33 deletions(-)
 create mode 100644 special-pages/messages/new-tab/rmf_dismiss.notify.json
 create mode 100644 special-pages/messages/new-tab/rmf_secondaryAction.notify.json

diff --git a/special-pages/messages/new-tab/rmf_dismiss.notify.json b/special-pages/messages/new-tab/rmf_dismiss.notify.json
new file mode 100644
index 000000000..e529e778e
--- /dev/null
+++ b/special-pages/messages/new-tab/rmf_dismiss.notify.json
@@ -0,0 +1,13 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "RMF Dismiss Action",
+  "type": "object",
+  "required": [
+    "id"
+  ],
+  "properties": {
+    "id": {
+      "type": "string"
+    }
+  }
+}
\ No newline at end of file
diff --git a/special-pages/messages/new-tab/rmf_secondaryAction.notify.json b/special-pages/messages/new-tab/rmf_secondaryAction.notify.json
new file mode 100644
index 000000000..0108c8e88
--- /dev/null
+++ b/special-pages/messages/new-tab/rmf_secondaryAction.notify.json
@@ -0,0 +1,13 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "RMF Secondary Action",
+  "type": "object",
+  "required": [
+    "id"
+  ],
+  "properties": {
+    "id": {
+      "type": "string"
+    }
+  }
+}
\ No newline at end of file
diff --git a/special-pages/pages/new-tab/app/components/Examples.jsx b/special-pages/pages/new-tab/app/components/Examples.jsx
index 9f76890ae..b6bd93a43 100644
--- a/special-pages/pages/new-tab/app/components/Examples.jsx
+++ b/special-pages/pages/new-tab/app/components/Examples.jsx
@@ -49,9 +49,10 @@ export const mainExamples = {
                 message={{
                     id: 'small',
                     messageType: 'small',
-                    titleText: 'Update Available',
-                    descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.'
+                    titleText: 'No searchy-search today!',
+                    descriptionText: 'The ravens have left Bing Tower and the internet is broken. Sorry.'
                 }}
+                dismiss={() => {}}
             />
         )
     },
@@ -65,6 +66,7 @@ export const mainExamples = {
                     titleText: 'Tell Us Your Thoughts on Privacy Pro',
                     descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.'
                 }}
+                dismiss={() => {}}
             />
         )
     },
@@ -80,6 +82,7 @@ export const mainExamples = {
                     primaryActionText: 'Learn More'
                 }}
                 primaryAction={() => { }}
+                dismiss={() => {}}
             />
         )
     },
@@ -97,6 +100,7 @@ export const mainExamples = {
                 }}
                 primaryAction={() => { }}
                 secondaryAction={() => { }}
+                dismiss={() => {}}
             />
         )
     }
@@ -128,13 +132,14 @@ export const otherExamples = {
                     id: 'big-two-overflow',
                     messageType: 'big_two_action',
                     icon: 'CriticalUpdate',
-                    titleText: 'Update Available',
-                    descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance. A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.',
+                    titleText: 'Critical Browser Update Available',
+                    descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.  And a little more long text for science.',
                     primaryActionText: 'How to update Windows',
                     secondaryActionText: 'Remind me later, but only if Iā€™m actually going to update soon'
                 }}
                 primaryAction={() => { }}
                 secondaryAction={() => { }}
+                dismiss={() => {}}
             />
         )
     },
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
index 13a53add1..b53c4b032 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RMFProvider.js
@@ -20,17 +20,17 @@ import {
 export const RMFContext = createContext({
     /** @type {State} */
     state: { status: 'idle', data: null, config: null },
-    /** @type {() => void} */
-    dismiss: () => {
-        throw new Error('must implement')
+    /** @type {(id: string) => void} */
+    dismiss: (id) => {
+        throw new Error('must implement dismiss' + id)
     },
     /** @type {(id: string) => void} */
     primaryAction: (id) => {
-        throw new Error('must implement ' + id)
+        throw new Error('must implement primaryAction' + id)
     },
-    /** @type {() => void} */
-    secondaryAction: () => {
-        throw new Error('must implement')
+    /** @type {(id: string) => void} */
+    secondaryAction: (id) => {
+        throw new Error('must implement secondaryAction' + id)
     }
 })
 
@@ -72,8 +72,9 @@ export function RMFProvider (props) {
         service.current?.primaryAction(id)
     }, [service])
 
-    const secondaryAction = useCallback(() => {
+    const secondaryAction = useCallback((id) => {
         console.log('secondaryAction')
+        service.current?.secondaryAction(id)
     }, [service])
 
     return (
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index cc01e535e..a033c89a4 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -9,11 +9,12 @@ import { RMFContext } from './RMFProvider.js'
   * @import { RMFMessage } from "../../../../types/new-tab"
   * @param {object} props
   * @param {RMFMessage} props.message
+  * @param {(id: string) => void} props.dismiss
   * @param {(id: string) => void} [props.primaryAction]
-  * @param {() => void} [props.secondaryAction]
+  * @param {(id: string) => void} [props.secondaryAction]
   */
 
-export function RemoteMessagingFramework ({ message, primaryAction, secondaryAction }) {
+export function RemoteMessagingFramework ({ message, primaryAction, secondaryAction, dismiss }) {
     const { id, messageType, titleText, descriptionText } = message
     return (
         <div id={id} class={cn(styles.root, (messageType !== 'small' && message.icon) && styles.icon)}>
@@ -31,7 +32,7 @@ export function RemoteMessagingFramework ({ message, primaryAction, secondaryAct
                             <button class={cn(styles.btn, styles.primary)} onClick={() => primaryAction(id)}>{message.primaryActionText}</button>
                         )}
                         {secondaryAction && message.secondaryActionText.length > 0 && (
-                            <button class={cn(styles.btn, styles.secondary)} onClick={secondaryAction}>{message.secondaryActionText}</button>
+                            <button class={cn(styles.btn, styles.secondary)} onClick={() => secondaryAction(id)}>{message.secondaryActionText}</button>
                         )}
                     </div>
                 )}
@@ -41,13 +42,17 @@ export function RemoteMessagingFramework ({ message, primaryAction, secondaryAct
                     <button class={cn(styles.btn)} onClick={() => primaryAction(id)}>{message.primaryActionText}</button>
                 </div>
             )}
+            <button className={cn(styles.btn, styles.dismissBtn)} onClick={() => dismiss(id)} aria-label="Close">
+                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" >
+                    <path d="M11.4419 5.44194C11.686 5.19786 11.686 4.80214 11.4419 4.55806C11.1979 4.31398 10.8021 4.31398 10.5581 4.55806L8 7.11612L5.44194 4.55806C5.19786 4.31398 4.80214 4.31398 4.55806 4.55806C4.31398 4.80214 4.31398 5.19786 4.55806 5.44194L7.11612 8L4.55806 10.5581C4.31398 10.8021 4.31398 11.1979 4.55806 11.4419C4.80214 11.686 5.19786 11.686 5.44194 11.4419L8 8.88388L10.5581 11.4419C10.8021 11.686 11.1979 11.686 11.4419 11.4419C11.686 11.1979 11.686 10.8021 11.4419 10.5581L8.88388 8L11.4419 5.44194Z" fill="currentColor" />
+                </svg></button>
         </div>
 
     )
 }
 
 export function RMFConsumer () {
-    const { state, primaryAction, secondaryAction } = useContext(RMFContext)
+    const { state, primaryAction, secondaryAction, dismiss } = useContext(RMFContext)
 
     // `state.data.content` can be empty - meaning there's no message to display!
     if (state.status === 'ready' && state.data.content) {
@@ -56,6 +61,7 @@ export function RMFConsumer () {
                 message={state.data.content}
                 primaryAction={primaryAction}
                 secondaryAction={secondaryAction}
+                dismiss={dismiss}
             />
         )
     }
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
index 2edeb87a6..a4179606e 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
@@ -3,11 +3,13 @@
     background: var(--ntp-rmf-surface-background-color);
     padding: 14px var(--sp-8) 14px var(--sp-4);
     border-radius: var(--sp-3);
+    position: relative;
     display: flex;
     justify-content: flex-start;
     align-items: flex-start;
-    font-family: 'Segoe UI', system-ui, Tahoma, Geneva, Verdana, sans-serif;
+    font-family: system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto;
     color: var(--color-black);
+    line-height: 1.25rem;
 
     &.icon {
         padding-left: var(--sp-2);
@@ -29,11 +31,13 @@
     flex-grow: 1;
     display: grid;
     gap: var(--sp-3);
+    line-height: 1.25rem;
+    font-size: calc(14 * var(--px-in-rem));
 }
 
 .title {
     font-weight: var(--title-2-font-weight);
-    font-size: 14px;
+    line-height: normal;
 }
 
 .btnBlock {
@@ -50,12 +54,16 @@
 .btn {
     padding-left: var(--sp-3);
     padding-right: var(--sp-3);
-    height: var(--Windows-Button-Height-Medium, 32px);
+    height: var(--sp-8);
     background-color: var(--color-black-at-6);
     border-width: 0;
     border-radius: 6px;
     text-wrap: nowrap;
 
+    * {
+        user-select: none;
+    }
+
     &:hover {
         background-color: var(--color-black-at-9);
     }
@@ -142,4 +150,27 @@
             box-shadow: 0px 0px 0px 1px var(--color-blue-90), 0px 0px 0px 3px var(--color-white);
         }
     }
+}
+
+.dismissBtn {
+    position: absolute;
+    top: 0.5rem;
+    right: 0.5rem;
+    height: 1rem;
+    width: 1rem;
+    padding: 0;
+    line-height: 1;
+    font-size: 12px;
+    background-color: transparent;
+    color: var(--color-black-at-60);
+    border: none;
+    border-radius: 50%;
+
+    * {
+        user-select: none;
+    }
+
+    @media screen and (prefers-color-scheme: dark) {
+        color: var(--color-white-at-60);
+    }
 }
\ No newline at end of file
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
index 36d26c92a..9fec61205 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
@@ -14,13 +14,25 @@ test.describe('newtab remote messaging framework rmf', () => {
         expect(calls2.length).toBe(1)
     })
 
-    test('renders a title and button', async ({ page }, workerInfo) => {
+    test('renders a title and dismiss button for small variant', async ({ page }, workerInfo) => {
+        const ntp = NewtabPage.create(page, workerInfo)
+        await ntp.reducedMotion()
+        await ntp.openPage({ rmf: 'small' })
+
+        await page.getByText('Tell Us Your Thoughts on Privacy Pro').waitFor()
+        await page.getByLabel('Close').click()
+        await ntp.mocks.waitForCallCount({ method: 'rmf_dismiss', count: 1 })
+    })
+
+    test('renders two buttons for big_two_action variant', async ({ page }, workerInfo) => {
         const ntp = NewtabPage.create(page, workerInfo)
         await ntp.reducedMotion()
         await ntp.openPage({ rmf: 'big_single_action' })
 
         await page.getByText('Tell Us Your Thoughts on Privacy Pro').waitFor()
         await page.getByRole('button', { name: 'Take Survey' }).click()
+        await page.getByRole('button', { name: 'Remind me' }).click()
         await ntp.mocks.waitForCallCount({ method: 'rmf_primaryAction', count: 1 })
+        await ntp.mocks.waitForCallCount({ method: 'rmf_secondaryAction', count: 1 })
     })
 })
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js b/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
index db5e5b6b2..8262c0f99 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/rmf.service.js
@@ -45,12 +45,11 @@ export class RMFService {
     }
 
     /**
-     * @param {(evt: {data: RMFData, source: 'manual' | 'subscription'}) => void} cb
+     * @param {string} id
      * @internal
      */
-    dismiss (cb) {
-        // return this.ntp.messaging.notify('')
-        console.log(cb)
+    dismiss (id) {
+        return this.ntp.messaging.notify('rmf_dismiss', { id })
     }
 
     toggleExpansion () { }
@@ -61,4 +60,11 @@ export class RMFService {
     primaryAction (id) {
         this.ntp.messaging.notify('rmf_primaryAction', { id })
     }
+
+    /**
+     * @param {string} id
+     */
+    secondaryAction (id) {
+        this.ntp.messaging.notify('rmf_secondaryAction', { id })
+    }
 }
diff --git a/special-pages/pages/new-tab/src/js/mock-transport.js b/special-pages/pages/new-tab/src/js/mock-transport.js
index 29f99d824..1ca8f1076 100644
--- a/special-pages/pages/new-tab/src/js/mock-transport.js
+++ b/special-pages/pages/new-tab/src/js/mock-transport.js
@@ -72,6 +72,14 @@ export function mockTransport () {
                 console.log('ignoring rmf_primaryAction', msg.params)
                 return
             }
+            case 'rmf_secondaryAction': {
+                console.log('ignoring rmf_secondaryAction', msg.params)
+                return
+            }
+            case 'rmf_dismiss': {
+                console.log('ignoring rmf_dismiss', msg.params)
+                return
+            }
             default: {
                 console.warn('unhandled notification', msg)
             }
@@ -147,25 +155,55 @@ export function mockTransport () {
             case 'rmf_getData': {
                 /** @type {import('../../../../types/new-tab.js').RMFData} */
                 const message = { content: undefined }
-
+                const rmfParam = url.searchParams.get('rmf')
                 /** @type {import('../../../../types/new-tab.js').RMFData} */
-                if (url.searchParams.get('rmf') === 'big_single_action') {
+                if (rmfParam === 'small') {
+                    message.content = {
+                        messageType: 'small',
+                        id: 'id-small',
+                        titleText: 'Search services limited',
+                        descriptionText: 'Search services are impacted by a Bing outage, results may not be what you expect'
+                    }
+                }
+                if (rmfParam === 'medium') {
+                    message.content = {
+                        messageType: 'medium',
+                        id: 'id-2',
+                        icon: 'DDGAnnounce',
+                        titleText: 'New Search Feature!',
+                        descriptionText: 'DuckDuckGo now offers Instant Answers for quicker access to the information you need.'
+                    }
+                }
+                if (rmfParam === 'big_single_action') {
                     message.content = {
-                        id: 'id-1',
                         messageType: 'big_single_action',
+                        id: 'id-big-single',
                         titleText: 'Tell Us Your Thoughts on Privacy Pro',
                         descriptionText: 'Take our short anonymous survey and share your feedback.',
-                        icon: 'Announce',
+                        icon: 'PrivacyPro',
                         primaryActionText: 'Take Survey'
                     }
                 }
-                if (url.searchParams.get('rmf') === 'medium') {
+                if (rmfParam === 'big_two_action') {
                     message.content = {
-                        messageType: 'medium',
+                        messageType: 'big_two_action',
+                        id: 'id-big-two',
+                        titleText: 'Tell Us Your Thoughts on Privacy Pro',
+                        descriptionText: 'Take our short anonymous survey and share your feedback.',
                         icon: 'Announce',
-                        id: 'id-2',
-                        titleText: 'Hello Medium!',
-                        descriptionText: 'Here is some mighty fine content'
+                        primaryActionText: 'Take Survey',
+                        secondaryActionText: 'Remind me'
+                    }
+                }
+                if (rmfParam === 'big_two_action_overflow') {
+                    message.content = {
+                        id: 'big-two-overflow',
+                        messageType: 'big_two_action',
+                        icon: 'CriticalUpdate',
+                        titleText: 'Windows Update Recommended',
+                        descriptionText: 'Support for Windows 10 is ending soon. Update to Windows 11 or newer before July 8, 2024, to keep getting the latest browser updates and improvements.',
+                        primaryActionText: 'How to update Windows',
+                        secondaryActionText: 'Remind me later, but only if Iā€™m actually going to update soon'
                     }
                 }
 
diff --git a/special-pages/types/new-tab.ts b/special-pages/types/new-tab.ts
index c7e573c8b..675e9f2b7 100644
--- a/special-pages/types/new-tab.ts
+++ b/special-pages/types/new-tab.ts
@@ -36,7 +36,9 @@ export interface NewTabMessages {
   notifications:
     | ReportInitExceptionNotification
     | ReportPageExceptionNotification
+    | RmfDismissNotification
     | RmfPrimaryActionNotification
+    | RmfSecondaryActionNotification
     | StatsSetConfigNotification
     | WidgetsSetConfigNotification;
   requests: InitialSetupRequest | RmfGetDataRequest | StatsGetConfigRequest | StatsGetDataRequest;
@@ -66,6 +68,16 @@ export interface ReportPageExceptionNotification {
 export interface ReportPageExceptionNotify {
   message: string;
 }
+/**
+ * Generated from @see "../messages/new-tab/rmf_dismiss.notify.json"
+ */
+export interface RmfDismissNotification {
+  method: "rmf_dismiss";
+  params: RMFDismissAction;
+}
+export interface RMFDismissAction {
+  id: string;
+}
 /**
  * Generated from @see "../messages/new-tab/rmf_primaryAction.notify.json"
  */
@@ -76,6 +88,16 @@ export interface RmfPrimaryActionNotification {
 export interface RMFPrimaryAction {
   id: string;
 }
+/**
+ * Generated from @see "../messages/new-tab/rmf_secondaryAction.notify.json"
+ */
+export interface RmfSecondaryActionNotification {
+  method: "rmf_secondaryAction";
+  params: RMFSecondaryAction;
+}
+export interface RMFSecondaryAction {
+  id: string;
+}
 /**
  * Generated from @see "../messages/new-tab/stats_setConfig.notify.json"
  */

From 29f454eb66daac5df218e15302ff40a7b83cf888 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Wed, 23 Oct 2024 19:51:12 -0600
Subject: [PATCH 29/40] fix: after rebase

---
 .../pages/new-tab/app/components/Examples.jsx | 33 +++++++++++--------
 .../new-tab/app/widget-list/WidgetList.js     |  5 ++-
 2 files changed, 23 insertions(+), 15 deletions(-)

diff --git a/special-pages/pages/new-tab/app/components/Examples.jsx b/special-pages/pages/new-tab/app/components/Examples.jsx
index b6bd93a43..38f67ed9c 100644
--- a/special-pages/pages/new-tab/app/components/Examples.jsx
+++ b/special-pages/pages/new-tab/app/components/Examples.jsx
@@ -1,9 +1,11 @@
-import { h } from 'preact'
+import { Fragment, h } from 'preact'
 import { PrivacyStatsMockProvider } from '../privacy-stats/mocks/PrivacyStatsMockProvider.js'
 import { Body, Heading, PrivacyStatsConsumer } from '../privacy-stats/PrivacyStats.js'
 import { RemoteMessagingFramework } from '../remote-messaging-framework/RemoteMessagingFramework.js'
 import { stats } from '../privacy-stats/mocks/stats.js'
 import { noop } from '../utils.js'
+import { VisibilityMenu } from '../customizer/VisibilityMenu.js'
+import { CustomizerButton } from '../customizer/Customizer.js'
 
 /** @type {Record<string, {factory: () => import("preact").ComponentChild}>} */
 export const mainExamples = {
@@ -27,12 +29,14 @@ export const mainExamples = {
         factory: () => <Body trackerCompanies={stats.few.trackerCompanies} listAttrs={{ id: 'example-stats.list' }} />
     },
     'stats.heading': {
-        factory: () => <Heading
-            trackerCompanies={stats.few.trackerCompanies}
-            totalCount={stats.few.totalCount}
-            expansion={'expanded'}
-            onToggle={noop('stats.heading onToggle')}
-        />
+        factory: () => (
+            <Heading
+                trackerCompanies={stats.few.trackerCompanies}
+                totalCount={stats.few.totalCount}
+                expansion={'expanded'}
+                onToggle={noop('stats.heading onToggle')}
+            />
+        )
     },
     'stats.heading.none': {
         factory: () => (
@@ -40,8 +44,9 @@ export const mainExamples = {
                 trackerCompanies={stats.none.trackerCompanies}
                 totalCount={stats.none.totalCount}
                 expansion={'expanded'}
-                onToggle={noop('stats.heading.none')}
-            />)
+                onToggle={noop('stats.heading onToggle')}
+            />
+        )
     },
     'rmf.small': {
         factory: () => (
@@ -166,19 +171,19 @@ export const otherExamples = {
                             }
                         ]}
                         state={[
-                            {checked: true},
-                            {checked: false},
+                            { checked: true },
+                            { checked: false }
                         ]}
                     />
                 </MaxContent>
             </Fragment>
         )
-    },
+    }
 }
 
-function MaxContent({children}) {
+function MaxContent ({ children }) {
     return (
-        <div style={{display: 'grid', gridTemplateColumns: 'max-content'}}>
+        <div style={{ display: 'grid', gridTemplateColumns: 'max-content' }}>
             {children}
         </div>
     )
diff --git a/special-pages/pages/new-tab/app/widget-list/WidgetList.js b/special-pages/pages/new-tab/app/widget-list/WidgetList.js
index b6b6712f5..647fce3c1 100644
--- a/special-pages/pages/new-tab/app/widget-list/WidgetList.js
+++ b/special-pages/pages/new-tab/app/widget-list/WidgetList.js
@@ -4,7 +4,10 @@ import { useContext } from 'preact/hooks'
 import { PrivacyStatsCustomized } from '../privacy-stats/PrivacyStats.js'
 import { FavoritesCustomized } from '../favorites/Favorites.js'
 import { Stack } from '../../../onboarding/app/components/Stack.js'
-import { Customizer } from '../customizer/Customizer.js'
+import {
+    Customizer,
+    CustomizerMenuPositionedFixed
+} from '../customizer/Customizer.js'
 import { RMFProvider } from '../remote-messaging-framework/RMFProvider.js'
 import { RMFConsumer } from '../remote-messaging-framework/RemoteMessagingFramework.js'
 

From a0e6b21e45386203de38a5f81dad50cb483cac49 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Wed, 23 Oct 2024 19:58:59 -0600
Subject: [PATCH 30/40] fix: RMF test

---
 .../remote-messaging-framework/integration-tests/rmf.spec.js   | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
index 9fec61205..db24e7c87 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
@@ -19,7 +19,7 @@ test.describe('newtab remote messaging framework rmf', () => {
         await ntp.reducedMotion()
         await ntp.openPage({ rmf: 'small' })
 
-        await page.getByText('Tell Us Your Thoughts on Privacy Pro').waitFor()
+        await page.getByText('Search services limited').waitFor()
         await page.getByLabel('Close').click()
         await ntp.mocks.waitForCallCount({ method: 'rmf_dismiss', count: 1 })
     })
@@ -29,7 +29,6 @@ test.describe('newtab remote messaging framework rmf', () => {
         await ntp.reducedMotion()
         await ntp.openPage({ rmf: 'big_single_action' })
 
-        await page.getByText('Tell Us Your Thoughts on Privacy Pro').waitFor()
         await page.getByRole('button', { name: 'Take Survey' }).click()
         await page.getByRole('button', { name: 'Remind me' }).click()
         await ntp.mocks.waitForCallCount({ method: 'rmf_primaryAction', count: 1 })

From 28bcf02dfa6a600be922fe1bcf509e40cf16610a Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Wed, 23 Oct 2024 20:07:54 -0600
Subject: [PATCH 31/40] fix: RMF test

---
 .../remote-messaging-framework/integration-tests/rmf.spec.js    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
index db24e7c87..56daeb7a7 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
@@ -27,7 +27,7 @@ test.describe('newtab remote messaging framework rmf', () => {
     test('renders two buttons for big_two_action variant', async ({ page }, workerInfo) => {
         const ntp = NewtabPage.create(page, workerInfo)
         await ntp.reducedMotion()
-        await ntp.openPage({ rmf: 'big_single_action' })
+        await ntp.openPage({ rmf: 'big_two_action' })
 
         await page.getByRole('button', { name: 'Take Survey' }).click()
         await page.getByRole('button', { name: 'Remind me' }).click()

From c8e45b6cafbcef6e24d2da251f4be735164690b4 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Wed, 23 Oct 2024 21:33:41 -0600
Subject: [PATCH 32/40] chore: Add the show/hide functionality for the
 dismissBtn commented out in the CSS

---
 .../RemoteMessagingFramework.module.css                    | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
index a4179606e..05fa94e4f 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
@@ -15,6 +15,12 @@
         padding-left: var(--sp-2);
     }
 
+    /* &:hover {
+        .dismissBtn {
+            opacity: 1;
+        }
+    } */
+
     @media screen and (prefers-color-scheme: dark) {
         background-color: var(--color-white-at-6);
         color: var(--color-white-at-84);
@@ -165,6 +171,7 @@
     color: var(--color-black-at-60);
     border: none;
     border-radius: 50%;
+    /* opacity: 0; */
 
     * {
         user-select: none;

From 34811f7ba43227db7ec678249cd62e6f1bf735d3 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Wed, 23 Oct 2024 21:40:41 -0600
Subject: [PATCH 33/40] fix: Add focus visible css for dismiss btn

---
 .../RemoteMessagingFramework.module.css                       | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
index 05fa94e4f..c14ee2976 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
@@ -177,6 +177,10 @@
         user-select: none;
     }
 
+    /* &:focus-visible {
+        opacity: 1;
+    } */
+
     @media screen and (prefers-color-scheme: dark) {
         color: var(--color-white-at-60);
     }

From 41131b26a231b181e6ebb1d3d8f33d9dd9376ede Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Wed, 23 Oct 2024 23:14:02 -0600
Subject: [PATCH 34/40] fix: Dismiss btn colors

---
 .../RemoteMessagingFramework.module.css       | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
index c14ee2976..66ce4bbed 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
@@ -72,6 +72,7 @@
 
     &:hover {
         background-color: var(--color-black-at-9);
+        cursor: pointer;
     }
 
     &:active {
@@ -177,11 +178,29 @@
         user-select: none;
     }
 
+    &:active {
+        background-color: var(--color-black-at-18);
+        color: var(--color-black-at-84);
+    }
+
     /* &:focus-visible {
         opacity: 1;
     } */
 
+    &:hover {
+        background-color: var(--color-black-at-9);
+    }
+
     @media screen and (prefers-color-scheme: dark) {
         color: var(--color-white-at-60);
+
+        &:hover {
+            background-color: var(--color-white-at-9);
+        }
+
+        &:active {
+            background-color: var(--color-white-at-18);
+            color: var(--color-white-at-84);
+        }
     }
 }
\ No newline at end of file

From eaff43be60a14ff24d02a55f9840837b20fdcf89 Mon Sep 17 00:00:00 2001
From: Shane Osbourne <sosbourne@duckduckgo.com>
Date: Thu, 24 Oct 2024 14:37:37 +0100
Subject: [PATCH 35/40] extract mock data and inert svgs

---
 .../pages/new-tab/app/components/Examples.jsx |  45 +-------
 .../MessageIcons.js                           |  79 -------------
 .../RemoteMessagingFramework.js               |   3 +-
 .../mocks/rmf.data.js                         |  54 +++++++++
 .../pages/new-tab/src/icons/Announce.svg      |  11 ++
 .../pages/new-tab/src/icons/AppUpdate.svg     |   6 +
 .../new-tab/src/icons/CriticalUpdate.svg      |  11 ++
 .../pages/new-tab/src/icons/DDGAnnounce.svg   |  15 +++
 .../pages/new-tab/src/icons/PrivacyPro.svg    |  12 ++
 .../pages/new-tab/src/js/mock-transport.js    | 105 +++++++-----------
 10 files changed, 159 insertions(+), 182 deletions(-)
 delete mode 100644 special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js
 create mode 100644 special-pages/pages/new-tab/app/remote-messaging-framework/mocks/rmf.data.js
 create mode 100644 special-pages/pages/new-tab/src/icons/Announce.svg
 create mode 100644 special-pages/pages/new-tab/src/icons/AppUpdate.svg
 create mode 100644 special-pages/pages/new-tab/src/icons/CriticalUpdate.svg
 create mode 100644 special-pages/pages/new-tab/src/icons/DDGAnnounce.svg
 create mode 100644 special-pages/pages/new-tab/src/icons/PrivacyPro.svg

diff --git a/special-pages/pages/new-tab/app/components/Examples.jsx b/special-pages/pages/new-tab/app/components/Examples.jsx
index 38f67ed9c..30fb4ba0e 100644
--- a/special-pages/pages/new-tab/app/components/Examples.jsx
+++ b/special-pages/pages/new-tab/app/components/Examples.jsx
@@ -6,6 +6,7 @@ import { stats } from '../privacy-stats/mocks/stats.js'
 import { noop } from '../utils.js'
 import { VisibilityMenu } from '../customizer/VisibilityMenu.js'
 import { CustomizerButton } from '../customizer/Customizer.js'
+import { rmfDataExamples } from "../remote-messaging-framework/mocks/rmf.data.js";
 
 /** @type {Record<string, {factory: () => import("preact").ComponentChild}>} */
 export const mainExamples = {
@@ -51,12 +52,7 @@ export const mainExamples = {
     'rmf.small': {
         factory: () => (
             <RemoteMessagingFramework
-                message={{
-                    id: 'small',
-                    messageType: 'small',
-                    titleText: 'No searchy-search today!',
-                    descriptionText: 'The ravens have left Bing Tower and the internet is broken. Sorry.'
-                }}
+                message={rmfDataExamples.small.content}
                 dismiss={() => {}}
             />
         )
@@ -64,13 +60,7 @@ export const mainExamples = {
     'rmf.medium': {
         factory: () => (
             <RemoteMessagingFramework
-                message={{
-                    id: 'medium',
-                    messageType: 'medium',
-                    icon: 'Announce',
-                    titleText: 'Tell Us Your Thoughts on Privacy Pro',
-                    descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.'
-                }}
+                message={rmfDataExamples.medium.content}
                 dismiss={() => {}}
             />
         )
@@ -78,14 +68,7 @@ export const mainExamples = {
     'rmf.big-single-action': {
         factory: () => (
             <RemoteMessagingFramework
-                message={{
-                    id: 'big-single',
-                    messageType: 'big_single_action',
-                    icon: 'DDGAnnounce',
-                    titleText: 'New Search Feature!',
-                    descriptionText: 'DuckDuckGo now offers Instant Answers for quicker access to the information you need.',
-                    primaryActionText: 'Learn More'
-                }}
+                message={rmfDataExamples.big_single_action.content}
                 primaryAction={() => { }}
                 dismiss={() => {}}
             />
@@ -94,15 +77,7 @@ export const mainExamples = {
     'rmf.big-two-action': {
         factory: () => (
             <RemoteMessagingFramework
-                message={{
-                    id: 'big-two',
-                    messageType: 'big_two_action',
-                    icon: 'AppUpdate',
-                    titleText: 'Update Available',
-                    descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.',
-                    primaryActionText: 'How to update',
-                    secondaryActionText: 'Remind me later'
-                }}
+                message={rmfDataExamples.big_two_action.content}
                 primaryAction={() => { }}
                 secondaryAction={() => { }}
                 dismiss={() => {}}
@@ -133,15 +108,7 @@ export const otherExamples = {
     'rmf.big-two-action-overflow': {
         factory: () => (
             <RemoteMessagingFramework
-                message={{
-                    id: 'big-two-overflow',
-                    messageType: 'big_two_action',
-                    icon: 'CriticalUpdate',
-                    titleText: 'Critical Browser Update Available',
-                    descriptionText: 'A new version of DuckDuckGo Browser is available. Update now to enjoy improved privacy features and enhanced performance.  And a little more long text for science.',
-                    primaryActionText: 'How to update Windows',
-                    secondaryActionText: 'Remind me later, but only if Iā€™m actually going to update soon'
-                }}
+                message={rmfDataExamples.big_two_action_overflow.content}
                 primaryAction={() => { }}
                 secondaryAction={() => { }}
                 dismiss={() => {}}
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js b/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js
deleted file mode 100644
index 7b064a5bf..000000000
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/MessageIcons.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import { h, Fragment } from 'preact'
-
-/**
- *
- * @param {object} props;
- * @param {"Announce"|"DDGAnnounce"|"CriticalUpdate"|"AppUpdate"|"PrivacyPro"} [props.name]
- */
-
-export default function MessageIcons ({ name }) {
-    return (
-        <>
-            {name === 'Announce' && (
-                <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M19 28.5V31.8648C19 33.5005 19.9958 34.9713 21.5144 35.5787C24.1419 36.6297 27 34.6947 27 31.8648V28.9857H29V31.8648C29 36.1096 24.7128 39.0122 20.7717 37.4357C18.4937 36.5245 17 34.3183 17 31.8648V28.5H19Z" fill="#557FF3" />
-                    <path d="M36.5 11.5L9.5 19V28L36.5 35.5V11.5Z" fill="#8FABF9" />
-                    <path d="M36.5 27L9.5 25V28L36.5 35.5V27Z" fill="#7295F6" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M36.977 15.2856C37.0954 15.825 36.7541 16.3583 36.2146 16.4767L15.7146 20.9767C15.1752 21.0951 14.6419 20.7538 14.5235 20.2144C14.4051 19.6749 14.7464 19.1416 15.2858 19.0232L35.7858 14.5232C36.3252 14.4048 36.8585 14.7461 36.977 15.2856Z" fill="#ADC2FC" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M40.25 24C40.25 23.5858 40.5858 23.25 41 23.25H44C44.4142 23.25 44.75 23.5858 44.75 24C44.75 24.4142 44.4142 24.75 44 24.75H41C40.5858 24.75 40.25 24.4142 40.25 24Z" fill="#CCCCCC" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M39.3506 19.3751C39.1435 19.0164 39.2664 18.5577 39.6251 18.3506L42.2232 16.8506C42.5819 16.6435 43.0406 16.7664 43.2477 17.1251C43.4548 17.4838 43.3319 17.9425 42.9732 18.1496L40.3751 19.6496C40.0164 19.8567 39.5577 19.7338 39.3506 19.3751Z" fill="#CCCCCC" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M39.3506 28.6251C39.5577 28.2664 40.0164 28.1435 40.3751 28.3506L42.9732 29.8506C43.3319 30.0577 43.4548 30.5164 43.2477 30.8751C43.0406 31.2338 42.5819 31.3567 42.2232 31.1496L39.6251 29.6496C39.2664 29.4425 39.1435 28.9838 39.3506 28.6251Z" fill="#CCCCCC" />
-                    <path d="M35 11.5C35 10.6716 35.6716 10 36.5 10C37.3284 10 38 10.6716 38 11.5V35.5C38 36.3284 37.3284 37 36.5 37C35.6716 37 35 36.3284 35 35.5V11.5Z" fill="#3969EF" />
-                    <path d="M8 19C8 18.1716 8.67157 17.5 9.5 17.5C10.3284 17.5 11 18.1716 11 19V28C11 28.8284 10.3284 29.5 9.5 29.5C8.67157 29.5 8 28.8284 8 28V19Z" fill="#3969EF" />
-                </svg>
-            )}
-            {name === 'AppUpdate' && (
-                <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
-                    <path d="M25 39C33.2843 39 40 32.2843 40 24C40 15.7157 33.2843 9 25 9C16.7157 9 10 15.7157 10 24C10 32.2843 16.7157 39 25 39Z" fill="#399F29" />
-                    <path d="M23 9H25V39H23V9Z" fill="#399F29" />
-                    <path d="M23 39C31.2843 39 38 32.2843 38 24C38 15.7157 31.2843 9 23 9C14.7157 9 8 15.7157 8 24C8 32.2843 14.7157 39 23 39Z" fill="#4CBA3C" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M25.3389 18.8067C22.6654 17.4255 19.3882 18.4284 17.8588 21.1608L17.8531 21.1668C17.3471 22.0676 17.0999 23.0465 17.0711 24.0193C17.0596 24.5358 16.7434 24.9802 16.2662 25.1123L14.3631 25.6348C14.0296 25.7249 13.7019 25.4786 13.6674 25.1183C13.4892 23.1726 13.8686 21.1548 14.8863 19.3412C17.3873 14.8792 22.7862 13.3058 27.1041 15.708C27.2995 15.8161 27.541 15.75 27.6503 15.5518L28.3919 14.2247C28.5759 13.9004 29.0416 13.9664 29.1336 14.3327L30.4215 19.5093C30.479 19.7315 30.3525 19.9657 30.1341 20.0258L25.1952 21.377C24.8445 21.4731 24.557 21.0767 24.741 20.7524L25.4999 19.4012C25.6149 19.1911 25.5459 18.9148 25.3389 18.8067ZM20.2104 29.2678C22.9868 30.649 26.39 29.6462 27.9782 26.9137L27.9842 26.9077C28.5096 26.0069 28.7664 25.028 28.7962 24.0552C28.8082 23.5387 29.1366 23.0943 29.6321 22.9622L31.6084 22.4397C31.9547 22.3497 32.295 22.5959 32.3309 22.9562C32.5159 24.9019 32.1219 26.9197 31.0651 28.7333C28.4678 33.1953 22.8614 34.7687 18.3774 32.3666C18.1744 32.2585 17.9236 32.3245 17.8102 32.5227L17.04 33.8499C16.8489 34.1742 16.3653 34.1081 16.2698 33.7418L14.9323 28.5652C14.8726 28.343 15.004 28.1088 15.2309 28.0487L20.3597 26.6975C20.7239 26.6015 21.0224 26.9978 20.8313 27.3221L20.0432 28.6733C19.9238 28.8835 19.9955 29.1597 20.2104 29.2678Z" fill="white" />
-                </svg>
-            )}
-            {name === 'CriticalUpdate' && (
-                <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
-                    <path d="M34.3532 25.565C29.3703 26.1337 25.4998 30.3648 25.4998 35.4999C25.4998 36.8807 24.3805 38 22.9997 38H14.4312C11.0068 38 8.83727 34.3271 10.4901 31.328L21.0585 12.1513C21.5331 11.2902 22.2193 10.6679 22.9998 10.2846V9.82495H24.8743C26.4585 9.78177 28.0623 10.5572 28.9408 12.1513L35.3579 23.7953C35.7802 24.5615 35.2225 25.4657 34.3532 25.565Z" fill="#E2A412" />
-                    <path d="M34.3344 25.5671C29.3606 26.1444 25.4998 30.3713 25.4998 35.4999C25.4998 36.8807 24.3805 38 22.9997 38H12.4312C9.00682 38 6.83727 34.3271 8.4901 31.328L19.0585 12.1513C20.7692 9.04724 25.2301 9.04724 26.9408 12.1513L34.3344 25.5671Z" fill="#F9BE1A" />
-                    <path d="M35.5 43.5C39.9183 43.5 43.5 39.9183 43.5 35.5C43.5 31.0817 39.9183 27.5 35.5 27.5C31.0817 27.5 27.5 31.0817 27.5 35.5C27.5 39.9183 31.0817 43.5 35.5 43.5Z" fill="#4CBA3C" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M36.7474 32.7303C35.3216 31.9936 33.5737 32.5285 32.758 33.9858L32.755 33.989C32.4851 34.4694 32.3533 34.9915 32.3379 35.5104C32.3318 35.7858 32.1631 36.0228 31.9086 36.0933L30.8936 36.3719C30.7158 36.42 30.541 36.2887 30.5226 36.0965C30.4276 35.0588 30.6299 33.9826 31.1727 33.0153C32.5066 30.6356 35.386 29.7965 37.6888 31.0776C37.7931 31.1353 37.9219 31.1001 37.9801 30.9944L38.3757 30.2865C38.4738 30.1136 38.7222 30.1488 38.7713 30.3442L39.4581 33.105C39.4888 33.2235 39.4214 33.3484 39.3048 33.3805L36.6708 34.1011C36.4837 34.1524 36.3304 33.941 36.4285 33.768L36.8333 33.0474C36.8946 32.9353 36.8578 32.7879 36.7474 32.7303ZM34.0122 38.3096C35.4929 39.0462 37.308 38.5113 38.1551 37.054L38.1582 37.0508C38.4385 36.5704 38.5754 36.0483 38.5913 35.5295C38.5977 35.254 38.7728 35.017 39.0371 34.9466L40.0912 34.6679C40.2758 34.6199 40.4574 34.7512 40.4765 34.9434C40.5752 35.9811 40.365 37.0572 39.8014 38.0245C38.4162 40.4042 35.4261 41.2434 33.0346 39.9622C32.9263 39.9046 32.7926 39.9398 32.7321 40.0455L32.3213 40.7533C32.2194 40.9263 31.9615 40.891 31.9105 40.6957L31.1972 37.9348C31.1654 37.8163 31.2355 37.6914 31.3565 37.6594L34.0918 36.9387C34.2861 36.8875 34.4453 37.0989 34.3434 37.2718L33.9231 37.9925C33.8594 38.1046 33.8976 38.2519 34.0122 38.3096Z" fill="white" />
-                    <path d="M46.2507 29.5C46.3994 29.5 46.5481 29.56 46.6618 29.677C46.8892 29.9109 46.8892 30.2919 46.6618 30.5258L45.4956 31.7256C45.2682 31.9596 44.898 31.9596 44.6706 31.7256C44.4431 31.4917 44.4431 31.1107 44.6706 30.8768L45.8367 29.677C45.9505 29.56 46.0991 29.5 46.2478 29.5H46.2507Z" fill="#CCCCCC" />
-                    <path d="M45.6676 34.8991H47.4169C47.7376 34.8991 48 35.1691 48 35.499C48 35.829 47.7376 36.0989 47.4169 36.0989H45.6676C45.3469 36.0989 45.0845 35.829 45.0845 35.499C45.0845 35.1691 45.3469 34.8991 45.6676 34.8991Z" fill="#CCCCCC" />
-                    <path d="M44.6765 39.2759C44.7902 39.1589 44.9389 39.0989 45.0876 39.0989H45.0905C45.2392 39.0989 45.3879 39.1589 45.5016 39.2759L46.6678 40.4757C46.8952 40.7096 46.8952 41.0906 46.6678 41.3245C46.4403 41.5585 46.0701 41.5585 45.8427 41.3245L44.6765 40.1247C44.4491 39.8908 44.4491 39.5098 44.6765 39.2759Z" fill="#CCCCCC" />
-                    <path d="M23 34C24.1046 34 25 33.1046 25 32C25 30.8954 24.1046 30 23 30C21.8954 30 21 30.8954 21 32C21 33.1046 21.8954 34 23 34Z" fill="#92540C" />
-                    <path d="M22.5637 16C21.7108 16 21.0295 16.7103 21.065 17.5624L21.44 26.5624C21.4735 27.3659 22.1346 28 22.9387 28H23.0611C23.8653 28 24.5264 27.3659 24.5598 26.5624L24.9348 17.5624C24.9704 16.7103 24.2891 16 23.4361 16H22.5637Z" fill="#92540C" />
-                </svg>
-            )}
-            {name === 'DDGAnnounce' && (
-                <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
-                    <rect x="8" y="8" width="32" height="32" rx="16" fill="#DE5833" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M27.6052 38.3435C26.933 37.0366 26.2903 35.8342 25.8913 35.0388C24.8308 32.9152 23.7649 29.9212 24.2497 27.9903C24.338 27.6395 23.2508 14.9993 22.4822 14.5922C21.6279 14.1369 20.5768 13.4148 19.6154 13.2541C19.1276 13.176 18.488 13.213 17.988 13.2803C17.8992 13.2923 17.8955 13.452 17.9804 13.4808C18.3087 13.592 18.7072 13.7851 18.9421 14.077C18.9866 14.1323 18.9269 14.2192 18.856 14.2218C18.6346 14.23 18.2329 14.3228 17.703 14.773C17.6417 14.825 17.6926 14.9217 17.7715 14.9061C18.9104 14.6808 20.0736 14.7918 20.7591 15.4149C20.8036 15.4553 20.7803 15.5278 20.7223 15.5436C14.7736 17.1602 15.9512 22.3349 17.5348 28.6852C19.027 34.6686 19.7347 37.0285 19.82 37.3087C19.8257 37.3275 19.8362 37.342 19.8535 37.3514C21.0795 38.0243 27.5263 38.4328 27.2529 37.6624L27.6052 38.3435Z" fill="#DDDDDD" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M38.75 24C38.75 32.1462 32.1462 38.75 24 38.75C15.8538 38.75 9.25 32.1462 9.25 24C9.25 15.8538 15.8538 9.25 24 9.25C32.1462 9.25 38.75 15.8538 38.75 24ZM20.5608 37.0398C20.1134 35.6496 18.9707 31.9777 17.8859 27.5312C17.8485 27.3776 17.811 27.2246 17.7738 27.0724L17.7728 27.0686C16.411 21.506 15.2986 16.9627 21.3949 15.5354C21.4507 15.5223 21.4779 15.4557 21.441 15.4119C20.7416 14.5821 19.4312 14.3102 17.7744 14.8818C17.7064 14.9052 17.6474 14.8367 17.6896 14.7785C18.0145 14.3307 18.6494 13.9863 18.9629 13.8354C19.0277 13.8042 19.0237 13.7093 18.9551 13.6878C18.7501 13.6237 18.401 13.5254 18.0083 13.4621C17.9154 13.4471 17.907 13.2879 18.0003 13.2753C20.3492 12.9593 22.802 13.6645 24.0329 15.215C24.0445 15.2296 24.0612 15.2398 24.0794 15.2437C28.5867 16.2116 28.9095 23.3367 28.3902 23.6612C28.2879 23.7252 27.9598 23.6885 27.5271 23.6401C25.7733 23.4439 22.3004 23.0553 25.1667 28.3971C25.195 28.4498 25.1575 28.5197 25.0984 28.5289C23.506 28.7764 25.5552 33.7922 27.0719 37.1309C33.0379 35.7407 37.4824 30.3894 37.4824 24C37.4824 16.5539 31.4461 10.5176 24 10.5176C16.5539 10.5176 10.5176 16.5539 10.5176 24C10.5176 30.2575 14.7806 35.5194 20.5608 37.0398Z" fill="white" />
-                    <path d="M29.0913 30.703C28.7482 30.544 27.4288 31.4902 26.5532 32.2165C26.3702 31.9575 26.0251 31.7693 25.2467 31.9047C24.5655 32.0231 24.1894 32.1874 24.0216 32.4706C22.9463 32.0629 21.1374 31.4337 20.7003 32.0414C20.2226 32.7056 20.8197 35.8476 21.4542 36.2556C21.7855 36.4686 23.37 35.4501 24.1974 34.7478C24.3309 34.9359 24.5458 35.0435 24.9877 35.0333C25.6559 35.0178 26.7397 34.8623 26.9079 34.5511C26.9181 34.5322 26.9269 34.5098 26.9344 34.4844C27.7849 34.8022 29.2817 35.1386 29.6161 35.0884C30.4875 34.9575 29.4947 30.8899 29.0913 30.703Z" fill="#3CA82B" />
-                    <path d="M26.6335 32.3093C26.6696 32.3736 26.6986 32.4415 26.7233 32.5105C26.8445 32.8496 27.042 33.9283 26.8926 34.1947C26.7433 34.4612 25.7731 34.5898 25.1745 34.6002C24.576 34.6105 24.4413 34.3916 24.32 34.0525C24.2231 33.7813 24.1753 33.1435 24.1765 32.7783C24.1519 32.2367 24.3498 32.0462 25.2646 31.8982C25.9415 31.7887 26.2994 31.9161 26.506 32.1341C27.467 31.4168 29.0705 30.4046 29.2269 30.5896C30.0068 31.512 30.1053 33.7079 29.9365 34.5914C29.8813 34.8802 27.2991 34.3052 27.2991 33.9938C27.2991 32.7004 26.9635 32.3456 26.6335 32.3093Z" fill="#4CBA3C" />
-                    <path d="M20.9771 31.9054C21.1886 31.5707 22.9036 31.9869 23.8451 32.4059C23.8451 32.4059 23.6516 33.2824 23.9596 34.315C24.0497 34.617 21.7937 35.9614 21.4992 35.7301C21.1589 35.4628 20.5326 32.6089 20.9771 31.9054Z" fill="#4CBA3C" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M21.8077 25.1063C21.9465 24.5029 22.5929 23.3659 24.9011 23.3935C26.0681 23.3887 27.5176 23.393 28.4786 23.2839C29.907 23.1216 30.9672 22.7761 31.6737 22.5068C32.6729 22.1256 33.0275 22.2106 33.1518 22.4387C33.2884 22.6893 33.1274 23.1221 32.7783 23.5205C32.1114 24.2814 30.9126 24.8711 28.7952 25.0461C26.6779 25.2211 25.2751 24.6531 24.6713 25.5778C24.4109 25.9766 24.6122 26.9166 26.6598 27.2126C29.4268 27.6119 31.6992 26.7314 31.98 27.2632C32.2608 27.795 30.6434 28.8769 27.8719 28.8996C25.1005 28.9222 23.3694 27.9292 22.7556 27.4356C21.9767 26.8094 21.6282 25.8961 21.8077 25.1063Z" fill="#FFCC33" />
-                    <g opacity="0.8">
-                        <path d="M25.3372 18.5086C25.4918 18.2554 25.8346 18.0601 26.3956 18.0601C26.9565 18.0601 27.2205 18.2833 27.4032 18.5322C27.4403 18.5829 27.384 18.6425 27.3264 18.6175C27.3125 18.6115 27.2985 18.6054 27.2842 18.5992C27.079 18.5096 26.8271 18.3995 26.3956 18.3934C25.934 18.3868 25.6429 18.5024 25.4597 18.6021C25.3979 18.6356 25.3006 18.5686 25.3372 18.5086Z" fill="#14307E" />
-                        <path d="M19.0214 18.8324C19.5661 18.6048 19.9942 18.6342 20.2969 18.7058C20.3606 18.7209 20.4049 18.6523 20.3539 18.6112C20.119 18.4217 19.5933 18.1865 18.9076 18.4422C18.2959 18.6703 18.0076 19.1441 18.0059 19.4557C18.0055 19.5291 18.1565 19.5354 18.1956 19.4732C18.3012 19.3053 18.4767 19.0601 19.0214 18.8324Z" fill="#14307E" />
-                        <path fill-rule="evenodd" clip-rule="evenodd" d="M26.8721 21.9714C26.3905 21.9714 25.9999 21.5819 25.9999 21.1024C25.9999 20.623 26.3905 20.2334 26.8721 20.2334C27.3537 20.2334 27.7443 20.623 27.7443 21.1024C27.7443 21.5819 27.3537 21.9714 26.8721 21.9714ZM27.4864 20.8145C27.4864 20.6904 27.3847 20.5898 27.2605 20.5898C27.1364 20.5898 27.0358 20.6904 27.0347 20.8145C27.0347 20.9387 27.1364 21.0393 27.2605 21.0393C27.3858 21.0393 27.4864 20.9387 27.4864 20.8145Z" fill="#14307E" />
-                        <path fill-rule="evenodd" clip-rule="evenodd" d="M21.0933 21.7038C21.0933 22.2635 20.6385 22.7173 20.0766 22.7173C19.5159 22.7173 19.06 22.2635 19.06 21.7038C19.06 21.1441 19.5159 20.6904 20.0766 20.6904C20.6374 20.6904 21.0933 21.1441 21.0933 21.7038ZM20.7936 21.3678C20.7936 21.2233 20.6759 21.1056 20.5304 21.1056C20.3859 21.1056 20.2682 21.2223 20.2671 21.3678C20.2671 21.5123 20.3848 21.63 20.5304 21.63C20.6759 21.63 20.7936 21.5123 20.7936 21.3678Z" fill="#14307E" />
-                    </g>
-                </svg>
-            )}
-            {name === 'PrivacyPro' && (
-                <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M27.629 9.23049C26.8 8.34395 25.7498 7.99321 24.4999 8.0001C21.2503 7.99324 21.7126 8.46165 21.0003 9.21477C19.73 10.5579 19.4795 11.283 18.3526 11.661C17.22 12.0408 15.9189 12.7539 14 12.5C11.8615 12.2171 9.02112 11.9033 9.00175 14.2896C8.94035 21.8556 10.4937 28.0976 12.7723 31.6739C15.296 35.6347 17.8011 37.6973 21.2503 39.5324C22.422 40.1559 25.4632 40.1559 26.6348 39.5323C30.084 37.6972 34.2058 35.6346 36.7294 31.6739C39.0081 28.0976 40.0589 23.1568 39.9975 15.5905C39.9781 13.2022 38.0998 11.8892 35.5646 11.8892C35.2955 11.8892 34.3346 11.8361 33.9988 11.8603C33.696 11.8821 33.9083 12.0335 33.6341 12.0349C32.6677 12.0396 31.8684 11.9194 31.1599 11.6889C30.0308 11.3214 28.9118 10.6022 27.629 9.23049Z" fill="#C18010" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M25.8311 9.237C24.3178 7.59213 21.6746 7.58847 20.1552 9.22129C18.9056 10.5641 17.8147 11.2891 16.7062 11.6669C15.5921 12.0467 14.2457 12.1488 12.3581 11.895C10.2546 11.6121 8.02155 13.2104 8.0025 15.5962C7.9421 23.1605 8.97575 28.1002 11.2172 31.6756C13.6996 35.6356 17.7541 37.6977 21.147 39.5325C22.2995 40.1559 23.7006 40.1558 24.8532 39.5324C28.246 37.6977 32.3004 35.6356 34.7828 31.6756C37.0243 28.1001 38.0579 23.1603 37.9975 15.5957C37.9784 13.2078 35.742 11.6094 33.6371 11.8951C31.7607 12.1498 30.4182 12.0633 29.3044 11.6949C28.1937 11.3275 27.0929 10.6084 25.8311 9.237Z" fill="#FFCC33" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M25.8311 9.237C24.3178 7.59213 21.6746 7.58847 20.1552 9.22129C18.9056 10.5641 17.8147 11.2891 16.7062 11.6669C15.5921 12.0467 14.2457 12.1488 12.3581 11.895C10.2546 11.6121 8.02155 13.2104 8.0025 15.5962C7.9421 23.1605 8.97575 28.1002 11.2172 31.6756C13.6996 35.6356 17.7541 37.6977 21.147 39.5325C22.2995 40.1559 23.7006 40.1558 24.8532 39.5324C28.246 37.6977 32.3004 35.6356 34.7828 31.6756C37.0243 28.1001 38.0579 23.1603 37.9975 15.5957C37.9784 13.2078 35.742 11.6094 33.6371 11.8951C31.7607 12.1498 30.4182 12.0633 29.3044 11.6949C28.1937 11.3275 27.0929 10.6084 25.8311 9.237Z" fill="#FFD65C" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M23.063 39.9995C22.4036 40.0101 21.742 39.8544 21.1468 39.5325C20.9942 39.45 20.8403 39.367 20.6853 39.2834C17.3924 37.5084 13.5878 35.4575 11.217 31.6756C8.97559 28.1002 7.94194 23.1605 8.00234 15.5962C8.02138 13.2104 10.2544 11.6121 12.3579 11.895C14.2455 12.1488 15.592 12.0467 16.7061 11.6669C17.8146 11.2891 18.9054 10.5641 20.155 9.22129C20.9125 8.40729 21.9492 8 22.986 8C23.0718 8 23.1576 8.00279 23.2432 8.00836C23.1999 8.24461 22.2612 13.4877 22.2612 23.7377C22.2612 31.3487 22.7787 37.3033 23.063 39.9995Z" fill="#FFDE7A" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.3363 37.3335L22.3361 37.3334C22.2395 37.2811 22.1429 37.229 22.0465 37.1769C18.6189 35.325 15.3476 33.5576 13.3354 30.3478C11.4696 27.3715 10.4434 23.0044 10.5024 15.6162C10.5054 15.2466 10.6669 14.9331 10.9655 14.6929C11.2889 14.4328 11.6941 14.3282 12.0249 14.3727C14.1505 14.6585 15.9152 14.5779 17.5129 14.0332C19.1172 13.4863 20.5415 12.476 21.9854 10.9244C22.5139 10.3564 23.4662 10.3589 23.9913 10.9297C25.457 12.5228 26.9015 13.5333 28.5193 14.0684C30.1176 14.5971 31.8746 14.6573 33.9733 14.3724C34.3043 14.3275 34.71 14.4318 35.0338 14.6919C35.3329 14.9321 35.4946 15.2458 35.4976 15.6157C35.5566 23.0042 34.5305 27.3714 32.6646 30.3478C30.6524 33.5577 27.3808 35.3252 23.9531 37.1771C23.8569 37.2291 23.7605 37.2812 23.664 37.3333L23.6637 37.3335C23.2533 37.5555 22.7467 37.5555 22.3363 37.3335ZM24.8532 39.5324C23.7006 40.1558 22.2995 40.1559 21.147 39.5325C20.9944 39.45 20.8405 39.367 20.6854 39.2834C17.3926 37.5084 13.588 35.4575 11.2172 31.6756C8.97575 28.1002 7.9421 23.1605 8.0025 15.5962C8.02155 13.2104 10.2546 11.6121 12.3581 11.895C14.2457 12.1488 15.5921 12.0467 16.7062 11.6669C17.8147 11.2891 18.9056 10.5641 20.1552 9.22129C21.6746 7.58847 24.3178 7.59213 25.8311 9.237C27.0929 10.6084 28.1937 11.3275 29.3044 11.6949C30.4182 12.0633 31.7607 12.1498 33.6371 11.8951C35.742 11.6094 37.9784 13.2078 37.9975 15.5957C38.0579 23.1603 37.0243 28.1001 34.7828 31.6756C32.412 35.4577 28.6071 37.5086 25.3142 39.2836C25.1594 39.3671 25.0056 39.45 24.8532 39.5324Z" fill="#E2A412" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M23.1069 39.9985C22.4331 40.0169 21.7553 39.8616 21.1469 39.5325C20.9946 39.4501 20.841 39.3673 20.6863 39.2839L20.6854 39.2834C17.3926 37.5084 13.5879 35.4575 11.2171 31.6756C8.9757 28.1002 7.94205 23.1605 8.00245 15.5962C8.0215 13.2104 10.2545 11.6121 12.3581 11.895C14.2456 12.1488 15.5921 12.0467 16.7062 11.6669C17.8147 11.2891 18.9056 10.5641 20.1551 9.22129C20.9126 8.40729 21.9493 8 22.9862 8C23.072 8 23.1579 8.00279 23.2437 8.00838C23.2311 8.09934 23.1185 8.93031 22.9845 10.5C22.6164 10.5003 22.2484 10.6417 21.9853 10.9244C20.5414 12.476 19.1171 13.4863 17.5128 14.0332C15.9152 14.5779 14.1505 14.6585 12.0249 14.3727C11.6941 14.3282 11.2888 14.4328 10.9655 14.6929C10.6668 14.9331 10.5053 15.2466 10.5024 15.6162C10.4434 23.0044 11.4695 27.3715 13.3353 30.3478C15.3475 33.5576 18.6188 35.325 22.0464 37.1769L22.0464 37.1769L22.3361 37.3334L22.3363 37.3335C22.52 37.4329 22.7229 37.4878 22.9279 37.4982C22.9926 38.5066 23.0549 39.3475 23.1069 39.9985Z" fill="#F9BE1A" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M30 23.75C30 24.7165 29.2165 25.5 28.25 25.5L17.25 25.5C16.2835 25.5 15.5 24.7165 15.5 23.75C15.5 22.7835 16.2835 22 17.25 22L28.25 22C29.2165 22 30 22.7835 30 23.75Z" fill="#F9BE1A" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.75 16.5C23.7165 16.5 24.5 17.2835 24.5 18.25V29.25C24.5 30.2165 23.7165 31 22.75 31C21.7835 31 21 30.2165 21 29.25V18.25C21 17.2835 21.7835 16.5 22.75 16.5Z" fill="#F9BE1A" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.75 16.5C23.7165 16.5 24.5 17.2835 24.5 18.25V22H28.25C29.2165 22 30 22.7835 30 23.75C30 24.7165 29.2165 25.5 28.25 25.5H24.5V29.25C24.5 30.2165 23.7165 31 22.75 31C21.7835 31 21 30.2165 21 29.25V18.25C21 17.2835 21.7835 16.5 22.75 16.5Z" fill="#E2A412" />
-                    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.6392 30.9967C21.7243 30.9395 21 30.1794 21 29.2501V25.5001H17.25C16.2836 25.5001 15.5001 24.7166 15.5001 23.7501C15.5001 22.7836 16.2836 22.0001 17.25 22.0001H21V18.2501C21 17.3226 21.7215 16.5637 22.6339 16.5039C22.5543 18.4727 22.4998 20.8048 22.4998 23.5001C22.4998 26.2544 22.5567 28.7811 22.6392 30.9967Z" fill="#F9BE1A" />
-                </svg>
-            )}
-        </>
-    )
-}
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index a033c89a4..a9adbe827 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -1,7 +1,6 @@
 import { h } from 'preact'
 import cn from 'classnames'
 import styles from './RemoteMessagingFramework.module.css'
-import MessageIcons from './MessageIcons'
 import { useContext } from 'preact/hooks'
 import { RMFContext } from './RMFProvider.js'
 
@@ -20,7 +19,7 @@ export function RemoteMessagingFramework ({ message, primaryAction, secondaryAct
         <div id={id} class={cn(styles.root, (messageType !== 'small' && message.icon) && styles.icon)}>
             {messageType !== 'small' && message.icon && (
                 <span class={styles.iconBlock}>
-                    <MessageIcons name={message.icon} />
+                    <img src={`./icons/${message.icon}.svg`} alt=""/>
                 </span>
             )}
             <div class={styles.content}>
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/mocks/rmf.data.js b/special-pages/pages/new-tab/app/remote-messaging-framework/mocks/rmf.data.js
new file mode 100644
index 000000000..06f354ace
--- /dev/null
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/mocks/rmf.data.js
@@ -0,0 +1,54 @@
+/**
+ * @type {Record<string, {content: NonNullable<import("../../../../../types/new-tab").RMFData['content']>}>}
+ */
+export const rmfDataExamples = {
+    small: {
+        content: {
+            messageType: 'small',
+            id: 'id-small',
+            titleText: 'Search services limited',
+            descriptionText: 'Search services are impacted by a Bing outage, results may not be what you expect'
+        }
+    },
+    medium: {
+        content: {
+            messageType: 'medium',
+            id: 'id-2',
+            icon: 'DDGAnnounce',
+            titleText: 'New Search Feature!',
+            descriptionText: 'DuckDuckGo now offers Instant Answers for quicker access to the information you need.'
+        }
+    },
+    big_single_action: {
+        content: {
+            messageType: 'big_single_action',
+            id: 'id-big-single',
+            titleText: 'Tell Us Your Thoughts on Privacy Pro',
+            descriptionText: 'Take our short anonymous survey and share your feedback.',
+            icon: 'PrivacyPro',
+            primaryActionText: 'Take Survey'
+        }
+    },
+    big_two_action: {
+        content: {
+            messageType: 'big_two_action',
+            id: 'id-big-two',
+            titleText: 'Tell Us Your Thoughts on Privacy Pro',
+            descriptionText: 'Take our short anonymous survey and share your feedback.',
+            icon: 'Announce',
+            primaryActionText: 'Take Survey',
+            secondaryActionText: 'Remind me'
+        }
+    },
+    big_two_action_overflow: {
+        content: {
+            id: 'big-two-overflow',
+            messageType: 'big_two_action',
+            icon: 'CriticalUpdate',
+            titleText: 'Windows Update Recommended',
+            descriptionText: 'Support for Windows 10 is ending soon. Update to Windows 11 or newer before July 8, 2024, to keep getting the latest browser updates and improvements.',
+            primaryActionText: 'How to update Windows',
+            secondaryActionText: 'Remind me later, but only if Iā€™m actually going to update soon'
+        }
+    }
+}
diff --git a/special-pages/pages/new-tab/src/icons/Announce.svg b/special-pages/pages/new-tab/src/icons/Announce.svg
new file mode 100644
index 000000000..9882a3b16
--- /dev/null
+++ b/special-pages/pages/new-tab/src/icons/Announce.svg
@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M19 28.5V31.8648C19 33.5005 19.9958 34.9713 21.5144 35.5787C24.1419 36.6297 27 34.6947 27 31.8648V28.9857H29V31.8648C29 36.1096 24.7128 39.0122 20.7717 37.4357C18.4937 36.5245 17 34.3183 17 31.8648V28.5H19Z" fill="#557FF3" />
+    <path d="M36.5 11.5L9.5 19V28L36.5 35.5V11.5Z" fill="#8FABF9" />
+    <path d="M36.5 27L9.5 25V28L36.5 35.5V27Z" fill="#7295F6" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M36.977 15.2856C37.0954 15.825 36.7541 16.3583 36.2146 16.4767L15.7146 20.9767C15.1752 21.0951 14.6419 20.7538 14.5235 20.2144C14.4051 19.6749 14.7464 19.1416 15.2858 19.0232L35.7858 14.5232C36.3252 14.4048 36.8585 14.7461 36.977 15.2856Z" fill="#ADC2FC" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M40.25 24C40.25 23.5858 40.5858 23.25 41 23.25H44C44.4142 23.25 44.75 23.5858 44.75 24C44.75 24.4142 44.4142 24.75 44 24.75H41C40.5858 24.75 40.25 24.4142 40.25 24Z" fill="#CCCCCC" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M39.3506 19.3751C39.1435 19.0164 39.2664 18.5577 39.6251 18.3506L42.2232 16.8506C42.5819 16.6435 43.0406 16.7664 43.2477 17.1251C43.4548 17.4838 43.3319 17.9425 42.9732 18.1496L40.3751 19.6496C40.0164 19.8567 39.5577 19.7338 39.3506 19.3751Z" fill="#CCCCCC" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M39.3506 28.6251C39.5577 28.2664 40.0164 28.1435 40.3751 28.3506L42.9732 29.8506C43.3319 30.0577 43.4548 30.5164 43.2477 30.8751C43.0406 31.2338 42.5819 31.3567 42.2232 31.1496L39.6251 29.6496C39.2664 29.4425 39.1435 28.9838 39.3506 28.6251Z" fill="#CCCCCC" />
+    <path d="M35 11.5C35 10.6716 35.6716 10 36.5 10C37.3284 10 38 10.6716 38 11.5V35.5C38 36.3284 37.3284 37 36.5 37C35.6716 37 35 36.3284 35 35.5V11.5Z" fill="#3969EF" />
+    <path d="M8 19C8 18.1716 8.67157 17.5 9.5 17.5C10.3284 17.5 11 18.1716 11 19V28C11 28.8284 10.3284 29.5 9.5 29.5C8.67157 29.5 8 28.8284 8 28V19Z" fill="#3969EF" />
+</svg>
diff --git a/special-pages/pages/new-tab/src/icons/AppUpdate.svg b/special-pages/pages/new-tab/src/icons/AppUpdate.svg
new file mode 100644
index 000000000..9aae10dd5
--- /dev/null
+++ b/special-pages/pages/new-tab/src/icons/AppUpdate.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+    <path d="M25 39C33.2843 39 40 32.2843 40 24C40 15.7157 33.2843 9 25 9C16.7157 9 10 15.7157 10 24C10 32.2843 16.7157 39 25 39Z" fill="#399F29" />
+    <path d="M23 9H25V39H23V9Z" fill="#399F29" />
+    <path d="M23 39C31.2843 39 38 32.2843 38 24C38 15.7157 31.2843 9 23 9C14.7157 9 8 15.7157 8 24C8 32.2843 14.7157 39 23 39Z" fill="#4CBA3C" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M25.3389 18.8067C22.6654 17.4255 19.3882 18.4284 17.8588 21.1608L17.8531 21.1668C17.3471 22.0676 17.0999 23.0465 17.0711 24.0193C17.0596 24.5358 16.7434 24.9802 16.2662 25.1123L14.3631 25.6348C14.0296 25.7249 13.7019 25.4786 13.6674 25.1183C13.4892 23.1726 13.8686 21.1548 14.8863 19.3412C17.3873 14.8792 22.7862 13.3058 27.1041 15.708C27.2995 15.8161 27.541 15.75 27.6503 15.5518L28.3919 14.2247C28.5759 13.9004 29.0416 13.9664 29.1336 14.3327L30.4215 19.5093C30.479 19.7315 30.3525 19.9657 30.1341 20.0258L25.1952 21.377C24.8445 21.4731 24.557 21.0767 24.741 20.7524L25.4999 19.4012C25.6149 19.1911 25.5459 18.9148 25.3389 18.8067ZM20.2104 29.2678C22.9868 30.649 26.39 29.6462 27.9782 26.9137L27.9842 26.9077C28.5096 26.0069 28.7664 25.028 28.7962 24.0552C28.8082 23.5387 29.1366 23.0943 29.6321 22.9622L31.6084 22.4397C31.9547 22.3497 32.295 22.5959 32.3309 22.9562C32.5159 24.9019 32.1219 26.9197 31.0651 28.7333C28.4678 33.1953 22.8614 34.7687 18.3774 32.3666C18.1744 32.2585 17.9236 32.3245 17.8102 32.5227L17.04 33.8499C16.8489 34.1742 16.3653 34.1081 16.2698 33.7418L14.9323 28.5652C14.8726 28.343 15.004 28.1088 15.2309 28.0487L20.3597 26.6975C20.7239 26.6015 21.0224 26.9978 20.8313 27.3221L20.0432 28.6733C19.9238 28.8835 19.9955 29.1597 20.2104 29.2678Z" fill="white" />
+</svg>
diff --git a/special-pages/pages/new-tab/src/icons/CriticalUpdate.svg b/special-pages/pages/new-tab/src/icons/CriticalUpdate.svg
new file mode 100644
index 000000000..7f63863f5
--- /dev/null
+++ b/special-pages/pages/new-tab/src/icons/CriticalUpdate.svg
@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+    <path d="M34.3532 25.565C29.3703 26.1337 25.4998 30.3648 25.4998 35.4999C25.4998 36.8807 24.3805 38 22.9997 38H14.4312C11.0068 38 8.83727 34.3271 10.4901 31.328L21.0585 12.1513C21.5331 11.2902 22.2193 10.6679 22.9998 10.2846V9.82495H24.8743C26.4585 9.78177 28.0623 10.5572 28.9408 12.1513L35.3579 23.7953C35.7802 24.5615 35.2225 25.4657 34.3532 25.565Z" fill="#E2A412" />
+    <path d="M34.3344 25.5671C29.3606 26.1444 25.4998 30.3713 25.4998 35.4999C25.4998 36.8807 24.3805 38 22.9997 38H12.4312C9.00682 38 6.83727 34.3271 8.4901 31.328L19.0585 12.1513C20.7692 9.04724 25.2301 9.04724 26.9408 12.1513L34.3344 25.5671Z" fill="#F9BE1A" />
+    <path d="M35.5 43.5C39.9183 43.5 43.5 39.9183 43.5 35.5C43.5 31.0817 39.9183 27.5 35.5 27.5C31.0817 27.5 27.5 31.0817 27.5 35.5C27.5 39.9183 31.0817 43.5 35.5 43.5Z" fill="#4CBA3C" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M36.7474 32.7303C35.3216 31.9936 33.5737 32.5285 32.758 33.9858L32.755 33.989C32.4851 34.4694 32.3533 34.9915 32.3379 35.5104C32.3318 35.7858 32.1631 36.0228 31.9086 36.0933L30.8936 36.3719C30.7158 36.42 30.541 36.2887 30.5226 36.0965C30.4276 35.0588 30.6299 33.9826 31.1727 33.0153C32.5066 30.6356 35.386 29.7965 37.6888 31.0776C37.7931 31.1353 37.9219 31.1001 37.9801 30.9944L38.3757 30.2865C38.4738 30.1136 38.7222 30.1488 38.7713 30.3442L39.4581 33.105C39.4888 33.2235 39.4214 33.3484 39.3048 33.3805L36.6708 34.1011C36.4837 34.1524 36.3304 33.941 36.4285 33.768L36.8333 33.0474C36.8946 32.9353 36.8578 32.7879 36.7474 32.7303ZM34.0122 38.3096C35.4929 39.0462 37.308 38.5113 38.1551 37.054L38.1582 37.0508C38.4385 36.5704 38.5754 36.0483 38.5913 35.5295C38.5977 35.254 38.7728 35.017 39.0371 34.9466L40.0912 34.6679C40.2758 34.6199 40.4574 34.7512 40.4765 34.9434C40.5752 35.9811 40.365 37.0572 39.8014 38.0245C38.4162 40.4042 35.4261 41.2434 33.0346 39.9622C32.9263 39.9046 32.7926 39.9398 32.7321 40.0455L32.3213 40.7533C32.2194 40.9263 31.9615 40.891 31.9105 40.6957L31.1972 37.9348C31.1654 37.8163 31.2355 37.6914 31.3565 37.6594L34.0918 36.9387C34.2861 36.8875 34.4453 37.0989 34.3434 37.2718L33.9231 37.9925C33.8594 38.1046 33.8976 38.2519 34.0122 38.3096Z" fill="white" />
+    <path d="M46.2507 29.5C46.3994 29.5 46.5481 29.56 46.6618 29.677C46.8892 29.9109 46.8892 30.2919 46.6618 30.5258L45.4956 31.7256C45.2682 31.9596 44.898 31.9596 44.6706 31.7256C44.4431 31.4917 44.4431 31.1107 44.6706 30.8768L45.8367 29.677C45.9505 29.56 46.0991 29.5 46.2478 29.5H46.2507Z" fill="#CCCCCC" />
+    <path d="M45.6676 34.8991H47.4169C47.7376 34.8991 48 35.1691 48 35.499C48 35.829 47.7376 36.0989 47.4169 36.0989H45.6676C45.3469 36.0989 45.0845 35.829 45.0845 35.499C45.0845 35.1691 45.3469 34.8991 45.6676 34.8991Z" fill="#CCCCCC" />
+    <path d="M44.6765 39.2759C44.7902 39.1589 44.9389 39.0989 45.0876 39.0989H45.0905C45.2392 39.0989 45.3879 39.1589 45.5016 39.2759L46.6678 40.4757C46.8952 40.7096 46.8952 41.0906 46.6678 41.3245C46.4403 41.5585 46.0701 41.5585 45.8427 41.3245L44.6765 40.1247C44.4491 39.8908 44.4491 39.5098 44.6765 39.2759Z" fill="#CCCCCC" />
+    <path d="M23 34C24.1046 34 25 33.1046 25 32C25 30.8954 24.1046 30 23 30C21.8954 30 21 30.8954 21 32C21 33.1046 21.8954 34 23 34Z" fill="#92540C" />
+    <path d="M22.5637 16C21.7108 16 21.0295 16.7103 21.065 17.5624L21.44 26.5624C21.4735 27.3659 22.1346 28 22.9387 28H23.0611C23.8653 28 24.5264 27.3659 24.5598 26.5624L24.9348 17.5624C24.9704 16.7103 24.2891 16 23.4361 16H22.5637Z" fill="#92540C" />
+</svg>
diff --git a/special-pages/pages/new-tab/src/icons/DDGAnnounce.svg b/special-pages/pages/new-tab/src/icons/DDGAnnounce.svg
new file mode 100644
index 000000000..f62d4feea
--- /dev/null
+++ b/special-pages/pages/new-tab/src/icons/DDGAnnounce.svg
@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+    <rect x="8" y="8" width="32" height="32" rx="16" fill="#DE5833" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M27.6052 38.3435C26.933 37.0366 26.2903 35.8342 25.8913 35.0388C24.8308 32.9152 23.7649 29.9212 24.2497 27.9903C24.338 27.6395 23.2508 14.9993 22.4822 14.5922C21.6279 14.1369 20.5768 13.4148 19.6154 13.2541C19.1276 13.176 18.488 13.213 17.988 13.2803C17.8992 13.2923 17.8955 13.452 17.9804 13.4808C18.3087 13.592 18.7072 13.7851 18.9421 14.077C18.9866 14.1323 18.9269 14.2192 18.856 14.2218C18.6346 14.23 18.2329 14.3228 17.703 14.773C17.6417 14.825 17.6926 14.9217 17.7715 14.9061C18.9104 14.6808 20.0736 14.7918 20.7591 15.4149C20.8036 15.4553 20.7803 15.5278 20.7223 15.5436C14.7736 17.1602 15.9512 22.3349 17.5348 28.6852C19.027 34.6686 19.7347 37.0285 19.82 37.3087C19.8257 37.3275 19.8362 37.342 19.8535 37.3514C21.0795 38.0243 27.5263 38.4328 27.2529 37.6624L27.6052 38.3435Z" fill="#DDDDDD" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M38.75 24C38.75 32.1462 32.1462 38.75 24 38.75C15.8538 38.75 9.25 32.1462 9.25 24C9.25 15.8538 15.8538 9.25 24 9.25C32.1462 9.25 38.75 15.8538 38.75 24ZM20.5608 37.0398C20.1134 35.6496 18.9707 31.9777 17.8859 27.5312C17.8485 27.3776 17.811 27.2246 17.7738 27.0724L17.7728 27.0686C16.411 21.506 15.2986 16.9627 21.3949 15.5354C21.4507 15.5223 21.4779 15.4557 21.441 15.4119C20.7416 14.5821 19.4312 14.3102 17.7744 14.8818C17.7064 14.9052 17.6474 14.8367 17.6896 14.7785C18.0145 14.3307 18.6494 13.9863 18.9629 13.8354C19.0277 13.8042 19.0237 13.7093 18.9551 13.6878C18.7501 13.6237 18.401 13.5254 18.0083 13.4621C17.9154 13.4471 17.907 13.2879 18.0003 13.2753C20.3492 12.9593 22.802 13.6645 24.0329 15.215C24.0445 15.2296 24.0612 15.2398 24.0794 15.2437C28.5867 16.2116 28.9095 23.3367 28.3902 23.6612C28.2879 23.7252 27.9598 23.6885 27.5271 23.6401C25.7733 23.4439 22.3004 23.0553 25.1667 28.3971C25.195 28.4498 25.1575 28.5197 25.0984 28.5289C23.506 28.7764 25.5552 33.7922 27.0719 37.1309C33.0379 35.7407 37.4824 30.3894 37.4824 24C37.4824 16.5539 31.4461 10.5176 24 10.5176C16.5539 10.5176 10.5176 16.5539 10.5176 24C10.5176 30.2575 14.7806 35.5194 20.5608 37.0398Z" fill="white" />
+    <path d="M29.0913 30.703C28.7482 30.544 27.4288 31.4902 26.5532 32.2165C26.3702 31.9575 26.0251 31.7693 25.2467 31.9047C24.5655 32.0231 24.1894 32.1874 24.0216 32.4706C22.9463 32.0629 21.1374 31.4337 20.7003 32.0414C20.2226 32.7056 20.8197 35.8476 21.4542 36.2556C21.7855 36.4686 23.37 35.4501 24.1974 34.7478C24.3309 34.9359 24.5458 35.0435 24.9877 35.0333C25.6559 35.0178 26.7397 34.8623 26.9079 34.5511C26.9181 34.5322 26.9269 34.5098 26.9344 34.4844C27.7849 34.8022 29.2817 35.1386 29.6161 35.0884C30.4875 34.9575 29.4947 30.8899 29.0913 30.703Z" fill="#3CA82B" />
+    <path d="M26.6335 32.3093C26.6696 32.3736 26.6986 32.4415 26.7233 32.5105C26.8445 32.8496 27.042 33.9283 26.8926 34.1947C26.7433 34.4612 25.7731 34.5898 25.1745 34.6002C24.576 34.6105 24.4413 34.3916 24.32 34.0525C24.2231 33.7813 24.1753 33.1435 24.1765 32.7783C24.1519 32.2367 24.3498 32.0462 25.2646 31.8982C25.9415 31.7887 26.2994 31.9161 26.506 32.1341C27.467 31.4168 29.0705 30.4046 29.2269 30.5896C30.0068 31.512 30.1053 33.7079 29.9365 34.5914C29.8813 34.8802 27.2991 34.3052 27.2991 33.9938C27.2991 32.7004 26.9635 32.3456 26.6335 32.3093Z" fill="#4CBA3C" />
+    <path d="M20.9771 31.9054C21.1886 31.5707 22.9036 31.9869 23.8451 32.4059C23.8451 32.4059 23.6516 33.2824 23.9596 34.315C24.0497 34.617 21.7937 35.9614 21.4992 35.7301C21.1589 35.4628 20.5326 32.6089 20.9771 31.9054Z" fill="#4CBA3C" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M21.8077 25.1063C21.9465 24.5029 22.5929 23.3659 24.9011 23.3935C26.0681 23.3887 27.5176 23.393 28.4786 23.2839C29.907 23.1216 30.9672 22.7761 31.6737 22.5068C32.6729 22.1256 33.0275 22.2106 33.1518 22.4387C33.2884 22.6893 33.1274 23.1221 32.7783 23.5205C32.1114 24.2814 30.9126 24.8711 28.7952 25.0461C26.6779 25.2211 25.2751 24.6531 24.6713 25.5778C24.4109 25.9766 24.6122 26.9166 26.6598 27.2126C29.4268 27.6119 31.6992 26.7314 31.98 27.2632C32.2608 27.795 30.6434 28.8769 27.8719 28.8996C25.1005 28.9222 23.3694 27.9292 22.7556 27.4356C21.9767 26.8094 21.6282 25.8961 21.8077 25.1063Z" fill="#FFCC33" />
+    <g opacity="0.8">
+        <path d="M25.3372 18.5086C25.4918 18.2554 25.8346 18.0601 26.3956 18.0601C26.9565 18.0601 27.2205 18.2833 27.4032 18.5322C27.4403 18.5829 27.384 18.6425 27.3264 18.6175C27.3125 18.6115 27.2985 18.6054 27.2842 18.5992C27.079 18.5096 26.8271 18.3995 26.3956 18.3934C25.934 18.3868 25.6429 18.5024 25.4597 18.6021C25.3979 18.6356 25.3006 18.5686 25.3372 18.5086Z" fill="#14307E" />
+        <path d="M19.0214 18.8324C19.5661 18.6048 19.9942 18.6342 20.2969 18.7058C20.3606 18.7209 20.4049 18.6523 20.3539 18.6112C20.119 18.4217 19.5933 18.1865 18.9076 18.4422C18.2959 18.6703 18.0076 19.1441 18.0059 19.4557C18.0055 19.5291 18.1565 19.5354 18.1956 19.4732C18.3012 19.3053 18.4767 19.0601 19.0214 18.8324Z" fill="#14307E" />
+        <path fill-rule="evenodd" clip-rule="evenodd" d="M26.8721 21.9714C26.3905 21.9714 25.9999 21.5819 25.9999 21.1024C25.9999 20.623 26.3905 20.2334 26.8721 20.2334C27.3537 20.2334 27.7443 20.623 27.7443 21.1024C27.7443 21.5819 27.3537 21.9714 26.8721 21.9714ZM27.4864 20.8145C27.4864 20.6904 27.3847 20.5898 27.2605 20.5898C27.1364 20.5898 27.0358 20.6904 27.0347 20.8145C27.0347 20.9387 27.1364 21.0393 27.2605 21.0393C27.3858 21.0393 27.4864 20.9387 27.4864 20.8145Z" fill="#14307E" />
+        <path fill-rule="evenodd" clip-rule="evenodd" d="M21.0933 21.7038C21.0933 22.2635 20.6385 22.7173 20.0766 22.7173C19.5159 22.7173 19.06 22.2635 19.06 21.7038C19.06 21.1441 19.5159 20.6904 20.0766 20.6904C20.6374 20.6904 21.0933 21.1441 21.0933 21.7038ZM20.7936 21.3678C20.7936 21.2233 20.6759 21.1056 20.5304 21.1056C20.3859 21.1056 20.2682 21.2223 20.2671 21.3678C20.2671 21.5123 20.3848 21.63 20.5304 21.63C20.6759 21.63 20.7936 21.5123 20.7936 21.3678Z" fill="#14307E" />
+    </g>
+</svg>
diff --git a/special-pages/pages/new-tab/src/icons/PrivacyPro.svg b/special-pages/pages/new-tab/src/icons/PrivacyPro.svg
new file mode 100644
index 000000000..ddb43170a
--- /dev/null
+++ b/special-pages/pages/new-tab/src/icons/PrivacyPro.svg
@@ -0,0 +1,12 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M27.629 9.23049C26.8 8.34395 25.7498 7.99321 24.4999 8.0001C21.2503 7.99324 21.7126 8.46165 21.0003 9.21477C19.73 10.5579 19.4795 11.283 18.3526 11.661C17.22 12.0408 15.9189 12.7539 14 12.5C11.8615 12.2171 9.02112 11.9033 9.00175 14.2896C8.94035 21.8556 10.4937 28.0976 12.7723 31.6739C15.296 35.6347 17.8011 37.6973 21.2503 39.5324C22.422 40.1559 25.4632 40.1559 26.6348 39.5323C30.084 37.6972 34.2058 35.6346 36.7294 31.6739C39.0081 28.0976 40.0589 23.1568 39.9975 15.5905C39.9781 13.2022 38.0998 11.8892 35.5646 11.8892C35.2955 11.8892 34.3346 11.8361 33.9988 11.8603C33.696 11.8821 33.9083 12.0335 33.6341 12.0349C32.6677 12.0396 31.8684 11.9194 31.1599 11.6889C30.0308 11.3214 28.9118 10.6022 27.629 9.23049Z" fill="#C18010" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M25.8311 9.237C24.3178 7.59213 21.6746 7.58847 20.1552 9.22129C18.9056 10.5641 17.8147 11.2891 16.7062 11.6669C15.5921 12.0467 14.2457 12.1488 12.3581 11.895C10.2546 11.6121 8.02155 13.2104 8.0025 15.5962C7.9421 23.1605 8.97575 28.1002 11.2172 31.6756C13.6996 35.6356 17.7541 37.6977 21.147 39.5325C22.2995 40.1559 23.7006 40.1558 24.8532 39.5324C28.246 37.6977 32.3004 35.6356 34.7828 31.6756C37.0243 28.1001 38.0579 23.1603 37.9975 15.5957C37.9784 13.2078 35.742 11.6094 33.6371 11.8951C31.7607 12.1498 30.4182 12.0633 29.3044 11.6949C28.1937 11.3275 27.0929 10.6084 25.8311 9.237Z" fill="#FFCC33" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M25.8311 9.237C24.3178 7.59213 21.6746 7.58847 20.1552 9.22129C18.9056 10.5641 17.8147 11.2891 16.7062 11.6669C15.5921 12.0467 14.2457 12.1488 12.3581 11.895C10.2546 11.6121 8.02155 13.2104 8.0025 15.5962C7.9421 23.1605 8.97575 28.1002 11.2172 31.6756C13.6996 35.6356 17.7541 37.6977 21.147 39.5325C22.2995 40.1559 23.7006 40.1558 24.8532 39.5324C28.246 37.6977 32.3004 35.6356 34.7828 31.6756C37.0243 28.1001 38.0579 23.1603 37.9975 15.5957C37.9784 13.2078 35.742 11.6094 33.6371 11.8951C31.7607 12.1498 30.4182 12.0633 29.3044 11.6949C28.1937 11.3275 27.0929 10.6084 25.8311 9.237Z" fill="#FFD65C" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M23.063 39.9995C22.4036 40.0101 21.742 39.8544 21.1468 39.5325C20.9942 39.45 20.8403 39.367 20.6853 39.2834C17.3924 37.5084 13.5878 35.4575 11.217 31.6756C8.97559 28.1002 7.94194 23.1605 8.00234 15.5962C8.02138 13.2104 10.2544 11.6121 12.3579 11.895C14.2455 12.1488 15.592 12.0467 16.7061 11.6669C17.8146 11.2891 18.9054 10.5641 20.155 9.22129C20.9125 8.40729 21.9492 8 22.986 8C23.0718 8 23.1576 8.00279 23.2432 8.00836C23.1999 8.24461 22.2612 13.4877 22.2612 23.7377C22.2612 31.3487 22.7787 37.3033 23.063 39.9995Z" fill="#FFDE7A" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.3363 37.3335L22.3361 37.3334C22.2395 37.2811 22.1429 37.229 22.0465 37.1769C18.6189 35.325 15.3476 33.5576 13.3354 30.3478C11.4696 27.3715 10.4434 23.0044 10.5024 15.6162C10.5054 15.2466 10.6669 14.9331 10.9655 14.6929C11.2889 14.4328 11.6941 14.3282 12.0249 14.3727C14.1505 14.6585 15.9152 14.5779 17.5129 14.0332C19.1172 13.4863 20.5415 12.476 21.9854 10.9244C22.5139 10.3564 23.4662 10.3589 23.9913 10.9297C25.457 12.5228 26.9015 13.5333 28.5193 14.0684C30.1176 14.5971 31.8746 14.6573 33.9733 14.3724C34.3043 14.3275 34.71 14.4318 35.0338 14.6919C35.3329 14.9321 35.4946 15.2458 35.4976 15.6157C35.5566 23.0042 34.5305 27.3714 32.6646 30.3478C30.6524 33.5577 27.3808 35.3252 23.9531 37.1771C23.8569 37.2291 23.7605 37.2812 23.664 37.3333L23.6637 37.3335C23.2533 37.5555 22.7467 37.5555 22.3363 37.3335ZM24.8532 39.5324C23.7006 40.1558 22.2995 40.1559 21.147 39.5325C20.9944 39.45 20.8405 39.367 20.6854 39.2834C17.3926 37.5084 13.588 35.4575 11.2172 31.6756C8.97575 28.1002 7.9421 23.1605 8.0025 15.5962C8.02155 13.2104 10.2546 11.6121 12.3581 11.895C14.2457 12.1488 15.5921 12.0467 16.7062 11.6669C17.8147 11.2891 18.9056 10.5641 20.1552 9.22129C21.6746 7.58847 24.3178 7.59213 25.8311 9.237C27.0929 10.6084 28.1937 11.3275 29.3044 11.6949C30.4182 12.0633 31.7607 12.1498 33.6371 11.8951C35.742 11.6094 37.9784 13.2078 37.9975 15.5957C38.0579 23.1603 37.0243 28.1001 34.7828 31.6756C32.412 35.4577 28.6071 37.5086 25.3142 39.2836C25.1594 39.3671 25.0056 39.45 24.8532 39.5324Z" fill="#E2A412" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M23.1069 39.9985C22.4331 40.0169 21.7553 39.8616 21.1469 39.5325C20.9946 39.4501 20.841 39.3673 20.6863 39.2839L20.6854 39.2834C17.3926 37.5084 13.5879 35.4575 11.2171 31.6756C8.9757 28.1002 7.94205 23.1605 8.00245 15.5962C8.0215 13.2104 10.2545 11.6121 12.3581 11.895C14.2456 12.1488 15.5921 12.0467 16.7062 11.6669C17.8147 11.2891 18.9056 10.5641 20.1551 9.22129C20.9126 8.40729 21.9493 8 22.9862 8C23.072 8 23.1579 8.00279 23.2437 8.00838C23.2311 8.09934 23.1185 8.93031 22.9845 10.5C22.6164 10.5003 22.2484 10.6417 21.9853 10.9244C20.5414 12.476 19.1171 13.4863 17.5128 14.0332C15.9152 14.5779 14.1505 14.6585 12.0249 14.3727C11.6941 14.3282 11.2888 14.4328 10.9655 14.6929C10.6668 14.9331 10.5053 15.2466 10.5024 15.6162C10.4434 23.0044 11.4695 27.3715 13.3353 30.3478C15.3475 33.5576 18.6188 35.325 22.0464 37.1769L22.0464 37.1769L22.3361 37.3334L22.3363 37.3335C22.52 37.4329 22.7229 37.4878 22.9279 37.4982C22.9926 38.5066 23.0549 39.3475 23.1069 39.9985Z" fill="#F9BE1A" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M30 23.75C30 24.7165 29.2165 25.5 28.25 25.5L17.25 25.5C16.2835 25.5 15.5 24.7165 15.5 23.75C15.5 22.7835 16.2835 22 17.25 22L28.25 22C29.2165 22 30 22.7835 30 23.75Z" fill="#F9BE1A" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.75 16.5C23.7165 16.5 24.5 17.2835 24.5 18.25V29.25C24.5 30.2165 23.7165 31 22.75 31C21.7835 31 21 30.2165 21 29.25V18.25C21 17.2835 21.7835 16.5 22.75 16.5Z" fill="#F9BE1A" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.75 16.5C23.7165 16.5 24.5 17.2835 24.5 18.25V22H28.25C29.2165 22 30 22.7835 30 23.75C30 24.7165 29.2165 25.5 28.25 25.5H24.5V29.25C24.5 30.2165 23.7165 31 22.75 31C21.7835 31 21 30.2165 21 29.25V18.25C21 17.2835 21.7835 16.5 22.75 16.5Z" fill="#E2A412" />
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.6392 30.9967C21.7243 30.9395 21 30.1794 21 29.2501V25.5001H17.25C16.2836 25.5001 15.5001 24.7166 15.5001 23.7501C15.5001 22.7836 16.2836 22.0001 17.25 22.0001H21V18.2501C21 17.3226 21.7215 16.5637 22.6339 16.5039C22.5543 18.4727 22.4998 20.8048 22.4998 23.5001C22.4998 26.2544 22.5567 28.7811 22.6392 30.9967Z" fill="#F9BE1A" />
+</svg>
diff --git a/special-pages/pages/new-tab/src/js/mock-transport.js b/special-pages/pages/new-tab/src/js/mock-transport.js
index 1ca8f1076..af3586b01 100644
--- a/special-pages/pages/new-tab/src/js/mock-transport.js
+++ b/special-pages/pages/new-tab/src/js/mock-transport.js
@@ -1,9 +1,11 @@
 import { TestTransportConfig } from '@duckduckgo/messaging'
 
 import { stats } from '../../app/privacy-stats/mocks/stats.js'
+import { rmfDataExamples } from '../../app/remote-messaging-framework/mocks/rmf.data.js'
 
 /**
  * @typedef {import('../../../../types/new-tab').StatsConfig} StatsConfig
+ * @typedef {import('../../../../types/new-tab.js').NewTabMessages['subscriptions']['subscriptionEvent']} SubscriptionNames
  */
 
 const VERSION_PREFIX = '__ntp_15__.'
@@ -50,6 +52,18 @@ export function mockTransport () {
         }
     }
 
+    /** @type {Map<SubscriptionNames, any[]>} */
+    const rmfSubscriptions = new Map()
+
+    function clearRmf () {
+        const listeners = rmfSubscriptions.get('rmf_onDataUpdate') || []
+        /** @type {import('../../../../types/new-tab.js').RMFData} */
+        const message = { content: undefined }
+        for (const listener of listeners) {
+            listener(message)
+        }
+    }
+
     return new TestTransportConfig({
         notify (_msg) {
             window.__playwright_01?.mocks?.outgoing?.push?.({ payload: structuredClone(_msg) })
@@ -70,14 +84,17 @@ export function mockTransport () {
             }
             case 'rmf_primaryAction': {
                 console.log('ignoring rmf_primaryAction', msg.params)
+                clearRmf()
                 return
             }
             case 'rmf_secondaryAction': {
                 console.log('ignoring rmf_secondaryAction', msg.params)
+                clearRmf()
                 return
             }
             case 'rmf_dismiss': {
                 console.log('ignoring rmf_dismiss', msg.params)
+                clearRmf()
                 return
             }
             default: {
@@ -115,18 +132,24 @@ export function mockTransport () {
                 return () => controller.abort()
             }
             case 'rmf_onDataUpdate': {
-                // const timeout = setTimeout(() => {
-                //     /** @type {import('../../../../types/new-tab.js').SmallMessage} */
-                //     const payload = {
-                //         id: "id-1",
-                //         messageType: "small",
-                //         titleText: "Hello world",
-                //         descriptionText: "My Description"
-                //     }
-                //     cb(payload)
-                // }, 2000)
-                // return () => clearTimeout(timeout)
-                return () => { }
+                // store the callback for later (eg: dismiss)
+                const prev = rmfSubscriptions.get('rmf_onDataUpdate') || []
+                const next = [...prev]
+                next.push(cb)
+                rmfSubscriptions.set('rmf_onDataUpdate', next)
+
+                const delay = url.searchParams.get('rmf-delay')
+                const rmfParam = url.searchParams.get('rmf')
+
+                if (delay !== null && rmfParam !== null && rmfParam in rmfDataExamples) {
+                    const ms = parseInt(delay, 10)
+                    const timeout = setTimeout(() => {
+                        const message = rmfDataExamples[rmfParam]
+                        cb(message)
+                    }, ms)
+                    return () => clearTimeout(timeout)
+                }
+                return () => {}
             }
             }
             return () => { }
@@ -154,57 +177,15 @@ export function mockTransport () {
             }
             case 'rmf_getData': {
                 /** @type {import('../../../../types/new-tab.js').RMFData} */
-                const message = { content: undefined }
+                let message = { content: undefined }
                 const rmfParam = url.searchParams.get('rmf')
-                /** @type {import('../../../../types/new-tab.js').RMFData} */
-                if (rmfParam === 'small') {
-                    message.content = {
-                        messageType: 'small',
-                        id: 'id-small',
-                        titleText: 'Search services limited',
-                        descriptionText: 'Search services are impacted by a Bing outage, results may not be what you expect'
-                    }
-                }
-                if (rmfParam === 'medium') {
-                    message.content = {
-                        messageType: 'medium',
-                        id: 'id-2',
-                        icon: 'DDGAnnounce',
-                        titleText: 'New Search Feature!',
-                        descriptionText: 'DuckDuckGo now offers Instant Answers for quicker access to the information you need.'
-                    }
-                }
-                if (rmfParam === 'big_single_action') {
-                    message.content = {
-                        messageType: 'big_single_action',
-                        id: 'id-big-single',
-                        titleText: 'Tell Us Your Thoughts on Privacy Pro',
-                        descriptionText: 'Take our short anonymous survey and share your feedback.',
-                        icon: 'PrivacyPro',
-                        primaryActionText: 'Take Survey'
-                    }
-                }
-                if (rmfParam === 'big_two_action') {
-                    message.content = {
-                        messageType: 'big_two_action',
-                        id: 'id-big-two',
-                        titleText: 'Tell Us Your Thoughts on Privacy Pro',
-                        descriptionText: 'Take our short anonymous survey and share your feedback.',
-                        icon: 'Announce',
-                        primaryActionText: 'Take Survey',
-                        secondaryActionText: 'Remind me'
-                    }
-                }
-                if (rmfParam === 'big_two_action_overflow') {
-                    message.content = {
-                        id: 'big-two-overflow',
-                        messageType: 'big_two_action',
-                        icon: 'CriticalUpdate',
-                        titleText: 'Windows Update Recommended',
-                        descriptionText: 'Support for Windows 10 is ending soon. Update to Windows 11 or newer before July 8, 2024, to keep getting the latest browser updates and improvements.',
-                        primaryActionText: 'How to update Windows',
-                        secondaryActionText: 'Remind me later, but only if Iā€™m actually going to update soon'
-                    }
+
+                // if the message should be delayed, initially return nothing here
+                const delayed = url.searchParams.has('rmf-delay')
+                if (delayed) return Promise.resolve(message)
+
+                if (rmfParam && rmfParam in rmfDataExamples) {
+                    message = rmfDataExamples[rmfParam]
                 }
 
                 return Promise.resolve(message)

From f00f0dc46355fb8aeb5e0e0f8874fa2d0dae9b93 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Thu, 24 Oct 2024 12:18:05 -0600
Subject: [PATCH 36/40] chore: Rm the show/hide code for dismissBtn, update
 focus ring

---
 .../RemoteMessagingFramework.js               |  2 +-
 .../RemoteMessagingFramework.module.css       | 42 +++++++------------
 2 files changed, 17 insertions(+), 27 deletions(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
index a9adbe827..e86226950 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.js
@@ -24,7 +24,7 @@ export function RemoteMessagingFramework ({ message, primaryAction, secondaryAct
             )}
             <div class={styles.content}>
                 <p class={styles.title}>{titleText}</p>
-                <p>{descriptionText}</p>
+                <p class={styles.description}>{descriptionText}</p>
                 {messageType === 'big_two_action' && (
                     <div class={styles.btnRow}>
                         {primaryAction && message.primaryActionText.length > 0 && (
diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
index 66ce4bbed..c685128a1 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
@@ -9,18 +9,12 @@
     align-items: flex-start;
     font-family: system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto;
     color: var(--color-black);
-    line-height: 1.25rem;
+
 
     &.icon {
         padding-left: var(--sp-2);
     }
 
-    /* &:hover {
-        .dismissBtn {
-            opacity: 1;
-        }
-    } */
-
     @media screen and (prefers-color-scheme: dark) {
         background-color: var(--color-white-at-6);
         color: var(--color-white-at-84);
@@ -46,6 +40,10 @@
     line-height: normal;
 }
 
+/* .description:first-line {
+    line-height: normal;
+} */
+
 .btnBlock {
     margin-left: var(--sp-3);
     align-self: center;
@@ -66,10 +64,6 @@
     border-radius: 6px;
     text-wrap: nowrap;
 
-    * {
-        user-select: none;
-    }
-
     &:hover {
         background-color: var(--color-black-at-9);
         cursor: pointer;
@@ -89,8 +83,8 @@
     }
 
     &:focus-visible {
-        outline: 2px solid var(--ddg-color-primary);
-        border: 1px solid white;
+        /* box-shadow: 0px 0px 0px 1px var(--color-white), 0px 0px 0px 3px var(--color-blue-50); */
+        box-shadow: 0px 0px 0px 1px var(--color-white), 0px 0px 0px 3px var(--ntp-focus-outline-color);
     }
 
     @media screen and (prefers-color-scheme: dark) {
@@ -116,8 +110,8 @@
         }
 
         &:focus-visible {
-            outline: 2px solid var(--ddg-color-primary);
-            border: 1px solid white;
+            /* box-shadow: 0px 0px 0px 1px var(--color-blue-90), 0px 0px 0px 3px var(--color-white); */
+            box-shadow: 0px 0px 0px 1px var(--ntp-focus-outline-color), 0px 0px 0px 3px var(--color-white);
         }
     }
 }
@@ -126,6 +120,7 @@
 .primary {
     background-color: var(--ddg-color-primary);
     color: var(--color-white);
+    position: relative;
 
 
     &:hover {
@@ -136,6 +131,10 @@
         background-color: var(--color-blue-70);
     }
 
+    /* &:focus-visible {
+        box-shadow: 0px 0px 0px 1px var(--color-white), 0px 0px 0px 3px var(--color-blue-50);
+    } */
+
     @media screen and (prefers-color-scheme: dark) {
         color: var(--color-black-at-84);
         background-color: var(--color-blue-20);
@@ -153,9 +152,9 @@
             color: var(--color-black-at-84);
         }
 
-        &:focus-visible {
+        /* &:focus-visible {
             box-shadow: 0px 0px 0px 1px var(--color-blue-90), 0px 0px 0px 3px var(--color-white);
-        }
+        } */
     }
 }
 
@@ -172,21 +171,12 @@
     color: var(--color-black-at-60);
     border: none;
     border-radius: 50%;
-    /* opacity: 0; */
-
-    * {
-        user-select: none;
-    }
 
     &:active {
         background-color: var(--color-black-at-18);
         color: var(--color-black-at-84);
     }
 
-    /* &:focus-visible {
-        opacity: 1;
-    } */
-
     &:hover {
         background-color: var(--color-black-at-9);
     }

From 1b5c1b8457cfd53f12cf1894944160b30cca07bf Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Thu, 24 Oct 2024 12:22:34 -0600
Subject: [PATCH 37/40] fix: Line height messing with inbetween spacing

---
 .../RemoteMessagingFramework.module.css                     | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
index c685128a1..7b2147bfc 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
@@ -40,9 +40,9 @@
     line-height: normal;
 }
 
-/* .description:first-line {
-    line-height: normal;
-} */
+.description {
+    margin-top: -0.25rem;
+}
 
 .btnBlock {
     margin-left: var(--sp-3);

From babee234698cec5a292fe08ee08f8ab11598bd03 Mon Sep 17 00:00:00 2001
From: Shane Osbourne <sosbourne@duckduckgo.com>
Date: Thu, 24 Oct 2024 21:29:23 +0100
Subject: [PATCH 38/40] updated tests

---
 .../integration-tests/rmf.spec.js                     | 11 +++++++++--
 .../pages/new-tab/integration-tests/new-tab.spec.js   |  2 --
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
index 56daeb7a7..0f9ad818f 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/integration-tests/rmf.spec.js
@@ -24,14 +24,21 @@ test.describe('newtab remote messaging framework rmf', () => {
         await ntp.mocks.waitForCallCount({ method: 'rmf_dismiss', count: 1 })
     })
 
-    test('renders two buttons for big_two_action variant', async ({ page }, workerInfo) => {
+    test('renders two buttons for big_two_action variant (primary)', async ({ page }, workerInfo) => {
         const ntp = NewtabPage.create(page, workerInfo)
         await ntp.reducedMotion()
         await ntp.openPage({ rmf: 'big_two_action' })
 
         await page.getByRole('button', { name: 'Take Survey' }).click()
-        await page.getByRole('button', { name: 'Remind me' }).click()
         await ntp.mocks.waitForCallCount({ method: 'rmf_primaryAction', count: 1 })
+    })
+
+    test('renders two buttons for big_two_action variant (secondary)', async ({ page }, workerInfo) => {
+        const ntp = NewtabPage.create(page, workerInfo)
+        await ntp.reducedMotion()
+        await ntp.openPage({ rmf: 'big_two_action' })
+
+        await page.getByRole('button', { name: 'Remind me' }).click()
         await ntp.mocks.waitForCallCount({ method: 'rmf_secondaryAction', count: 1 })
     })
 })
diff --git a/special-pages/pages/new-tab/integration-tests/new-tab.spec.js b/special-pages/pages/new-tab/integration-tests/new-tab.spec.js
index 0c2f42db9..c7e39d860 100644
--- a/special-pages/pages/new-tab/integration-tests/new-tab.spec.js
+++ b/special-pages/pages/new-tab/integration-tests/new-tab.spec.js
@@ -24,7 +24,6 @@ test.describe('newtab widgets', () => {
                 context: 'specialPages',
                 featureName: 'newTabPage',
                 params: [
-                    { id: 'rmf', visibility: 'visible' },
                     { id: 'favorites', visibility: 'visible' },
                     { id: 'privacyStats', visibility: 'hidden' }
                 ],
@@ -56,7 +55,6 @@ test.describe('newtab widgets', () => {
                 context: 'specialPages',
                 featureName: 'newTabPage',
                 params: [
-                    { id: 'rmf', visibility: 'visible' },
                     { id: 'favorites', visibility: 'visible' },
                     { id: 'privacyStats', visibility: 'visible' }
                 ],

From ceef7db68f718d165d3ddc0e1c108bd29e129a38 Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Thu, 24 Oct 2024 14:51:10 -0600
Subject: [PATCH 39/40] fix: Content spacing

---
 .../RemoteMessagingFramework.module.css                    | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
index 7b2147bfc..648e077b7 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
@@ -29,19 +29,18 @@
 
 .content {
     flex-grow: 1;
-    display: grid;
-    gap: var(--sp-3);
-    line-height: 1.25rem;
     font-size: calc(14 * var(--px-in-rem));
 }
 
 .title {
     font-weight: var(--title-2-font-weight);
     line-height: normal;
+    margin-bottom: var(--sp-2);
 }
 
 .description {
-    margin-top: -0.25rem;
+    line-height: 1.25rem;
+    margin-bottom: var(--sp-3);
 }
 
 .btnBlock {

From 8e42da9781065731316084581f7763e603023e8b Mon Sep 17 00:00:00 2001
From: Valerie Kraucunas <vkraucunas@duckduckgo.com>
Date: Fri, 25 Oct 2024 08:21:27 -0600
Subject: [PATCH 40/40] fix: Margin errors

---
 .../RemoteMessagingFramework.module.css                         | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
index 648e077b7..087b9b0a9 100644
--- a/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
+++ b/special-pages/pages/new-tab/app/remote-messaging-framework/RemoteMessagingFramework.module.css
@@ -40,7 +40,6 @@
 
 .description {
     line-height: 1.25rem;
-    margin-bottom: var(--sp-3);
 }
 
 .btnBlock {
@@ -49,6 +48,7 @@
 }
 
 .btnRow {
+    margin-top: var(--sp-3);
     display: flex;
     flex-wrap: wrap;
     gap: calc(10 * var(--px-in-rem));