Loading browser/components/BrowserGlue.sys.mjs +1 −0 Original line number Diff line number Diff line Loading @@ -515,6 +515,7 @@ let JSWINDOWACTORS = { DOMContentLoaded: {}, L10nMutationsFinished: {}, SubmitSearchOnionize: { wantUntrusted: true }, YECHidden: { wantUntrusted: true }, }, }, Loading browser/components/abouttor/AboutTorChild.sys.mjs +5 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,11 @@ export class AboutTorChild extends JSWindowActorChild { new this.contentWindow.CustomEvent("L10nMutationsFinished") ); break; case "YECHidden": // YEC 2024 banner was closed. Persist this for the rest of this // session. See tor-browser#43098 and tor-browser#42188. this.sendAsyncMessage("AboutTor:HideYEC"); break; } } } browser/components/abouttor/AboutTorParent.sys.mjs +46 −0 Original line number Diff line number Diff line Loading @@ -7,23 +7,69 @@ ChromeUtils.defineESModuleGetters(lazy, { TorConnect: "resource://gre/modules/TorConnect.sys.mjs", }); /** * Whether we should hide the Year end campaign (YEC) 2024 donation banner for * new about:tor pages. Applied to all future about:tor pages within this * session (i.e. new tabs, new windows, and after new identity). * * Will reset at the next full restart. * * See tor-browser#43098 and tor-browser#42188. * * @type {boolean} */ let hideYEC = AppConstants.MOZ_UPDATE_CHANNEL !== "release"; /** * The YEC 2024 start date. * * @type {integer} */ const yecStart = Date.UTC(2024, 9, 14, 15); // 2024 October 14th 15:00. /** * The YEC 2024 end date. * * @type {integer} */ const yecEnd = Date.UTC(2025, 0, 2); // 2025 January 2nd 00:00. /** * Actor parent class for the about:tor page. */ export class AboutTorParent extends JSWindowActorParent { receiveMessage(message) { const onionizePref = "torbrowser.homepage.search.onionize"; const yecMessagePref = "torbrowser.homepage.yec2024.message"; let yecMessageNumber = null; let now; switch (message.name) { case "AboutTor:GetInitialData": now = Date.now(); if (!hideYEC && now >= yecStart && now < yecEnd) { // Will show the banner. yecMessageNumber = Services.prefs.getIntPref(yecMessagePref, 0); // Increase the preference for the next about:tor load. Services.prefs.setIntPref(yecMessagePref, (yecMessageNumber + 1) % 3); } return Promise.resolve({ torConnectEnabled: lazy.TorConnect.enabled, messageData: lazy.AboutTorMessage.getNext(), isStable: AppConstants.MOZ_UPDATE_CHANNEL === "release", searchOnionize: Services.prefs.getBoolPref(onionizePref, false), // Locale for YEC 2024. See tor-browser#43098. yecMessageNumber, appLocale: Services.locale.appLocaleAsBCP47 === "ja-JP-macos" ? "ja" : Services.locale.appLocaleAsBCP47, }); case "AboutTor:SetSearchOnionize": Services.prefs.setBoolPref(onionizePref, message.data); break; case "AboutTor:HideYEC": hideYEC = true; break; } return undefined; } Loading browser/components/abouttor/content/aboutTor.css +294 −0 Original line number Diff line number Diff line Loading @@ -235,3 +235,297 @@ body:not(.show-tor-check) #tor-check { color: var(--tor-link-color-light); } } /* YEC 2024. * See tor-browser#43098 */ body:not([yec-2024-message-number]) #yec-2024-banner { display: none; } body { --yec-heading-font-size: 32px; } body[yec-2024-message-number] h1 { /* Text of heading is still available to screen readers, but it does not * contribute visually to the page or the body grid layout. */ position: absolute; clip-path: inset(50%); } body:not([yec-2024-message-number="0"]) .yec-2024-message-0 { display: none; } body:not([yec-2024-message-number="1"]) .yec-2024-message-1 { display: none; } body:not([yec-2024-message-number="2"]) .yec-2024-message-2 { display: none; } #yec-2024-banner { grid-area: heading; border-radius: 8px; border: 1px solid var(--in-content-box-border-color); display: grid; grid-template: "yec-heading yec-image" auto "yec-body yec-image" auto "yec-matching yec-image" auto "yec-donate yec-image" min-content / 1fr min-content; --yec-image-background: #1f0333; /* Remove 1px from padding for border. */ padding-block: 55px 55px; padding-inline: 47px 47px; box-sizing: border-box; max-width: 850px; margin-block-end: 40px; /* Position for the close button. */ position: relative; gap: 0 24px; } .yec-2024-image { grid-area: yec-image; align-self: center; /* Center horizontally for small width layout. */ justify-self: center; /* background color and border radius only stands out when using a high * contrast theme. */ -moz-context-properties: fill; fill: var(--yec-image-background); border-radius: 8px; height: 216px; border: 1px solid transparent; /* Remove border from layout size. */ margin: -1px; } .yec-2024-heading { grid-area: yec-heading; margin-block: 0 32px; /* We want to draw a background block of color behind the text in the child * <span> element. If this was en-US only text, we could just set a fixed * line-height that works. However, this can cause problems for some scripts, * like Burmese, where the normal line height is larger. * Instead, in javascript we measure the "normal" line height of the * .yec-2024-heading element using a copy .yec-2024-heading-measure element. * The line height is recorded in `--yec-heading-line-height` and we set the * line-height using this value, plus the amount of padding we would like. */ --yec-heading-block-padding: calc(0.1 * var(--yec-heading-font-size)); --yec-heading-inline-padding: calc(0.25 * var(--yec-heading-font-size)); margin-inline: calc(-1 * var(--yec-heading-inline-padding)); line-height: calc(var(--yec-heading-line-height) + 4 * var(--yec-heading-block-padding)); } .yec-2024-heading, .yec-2024-heading-measure { font-family: "Space Grotesk", sans-serif; font-size: var(--yec-heading-font-size); font-weight: 700; } /* Element used to measure the line height for .yec-2024-heading. * Not visually shown, but should mimic the font size of the corresponding * .yec-2024-heading. */ .yec-2024-heading-measure { position: absolute; visibility: hidden; /* Measure a single line height. */ white-space: nowrap; } .yec-2024-heading > * { /* Paint a block of color behind the text. * NOTE: For some scripts, like Burmese, the background of the inline element * is smaller than the actual script height. * So in javascript we measure the difference as `--yec-heading-gap-top` and * `--yec-heading-gap-bottom` and add this to the block padding, so that the * padding matches the highest and lowest points of the script. */ border-radius: 2px; background: transparent; padding-inline: var(--yec-heading-inline-padding); padding-block-start: calc( var(--yec-heading-gap-top) + var(--yec-heading-block-padding) ); padding-block-end: calc( var(--yec-heading-gap-bottom) + var(--yec-heading-block-padding) ); /* Each line has the padding applied separately. */ box-decoration-break: clone; } #yec-2024-body { grid-area: yec-body; margin-block: 0 8px; } #yec-2024-matching { grid-area: yec-matching; font-weight: 600; margin-block: 0 32px; } #yec-2024-body, #yec-2024-matching { font-size: 1.2em; } #yec-2024-donate-link { grid-area: yec-donate; justify-self: start; font-weight: 700; /* Style like a button. */ color: var(--in-content-button-text-color); border: 1px solid var(--in-content-button-border-color); border-radius: 4px; background-color: var(--in-content-button-background); padding-block: 12px; padding-inline: 16px; text-decoration: none; display: flex; align-items: center; gap: 10px; } #yec-2024-donate-link > * { flex: 0 0 auto; } #yec-2024-donate-link:hover { background-color: var(--in-content-button-background-hover); color: var(--in-content-button-text-color-hover); border-color: var(--in-content-button-border-color-hover); } #yec-2024-donate-link:hover:active { background-color: var(--in-content-button-background-active); color: var(--in-content-button-text-color-active); border-color: var(--in-content-button-border-color-active); } #yec-2024-close { position: absolute; inset-block-start: 16px; inset-inline-end: 16px; padding: 8px; min-width: auto; min-height: auto; width: 16px; height: 16px; box-sizing: content-box; /* Transparent background when neither hover nor active. */ background-color: transparent; border-color: transparent; } #yec-2024-close:hover { background-color: var(--in-content-button-background-hover); border-color: var(--in-content-button-border-color-hover); } #yec-2024-close:hover:active { background-color: var(--in-content-button-background-active); border-color: var(--in-content-button-border-color-active); } .yec-2024-icon { -moz-context-properties: fill; fill: currentColor; } @media (max-width: 768px) { body { --yec-heading-font-size: 1.45rem; } /* Small width layout. */ #yec-2024-banner { grid-template: "yec-image" min-content "yec-heading" auto "yec-body" auto "yec-matching" auto "yec-donate" min-content / 1fr; padding: 31px; /* Match max-width of the form. */ max-width: 600px; margin-block-end: 32px; } .yec-2024-image { height: 168px; } .yec-2024-heading { margin-block: 16px 24px; text-align: center; /* stylelint-disable-next-line property-no-unknown */ text-wrap-style: balance; } #yec-2024-body, #yec-2024-matching { font-size: 1.05em; } #yec-2024-donate-link { justify-self: center; } } @media ((prefers-contrast) or (forced-colors)) and (prefers-color-scheme: dark) { .yec-2024-image { /* Give the dark image a light border to separate from background. */ border-color: var(--in-content-box-border-color); } } @media not ((prefers-contrast) or (forced-colors)) { #yec-2024-banner { background-color: var(--yec-image-background); border-color: transparent; --acorn-yellow-40: #ffbd4f; --acorn-yellow-50: #ffa436; --acorn-yellow-60: #e27f2e; } .yec-2024-heading { color: var(--color-gray-100); } .yec-2024-heading.yec-2024-message-0 > * { /* YEC purple */ background: #d898fa; } .yec-2024-heading.yec-2024-message-1 > * { /* YEC green */ background: #c1ed75; } .yec-2024-heading.yec-2024-message-2 > * { /* YEC red */ background: #ff6a75; } #yec-2024-donate-link { --in-content-button-text-color: var(--color-gray-100); --in-content-button-text-color-hover: var(--color-gray-100); --in-content-button-text-color-active: var(--color-gray-100); --in-content-button-background: var(--acorn-yellow-40); --in-content-button-background-hover: var(--acorn-yellow-50); --in-content-button-background-active: var(--acorn-yellow-60); } #yec-2024-close { /* Rules for #yec-2024-close */ --in-content-button-text-color: var(--color-gray-05); --in-content-button-text-color-hover: var(--color-gray-05); --in-content-button-text-color-active: var(--color-gray-05); } } browser/components/abouttor/content/aboutTor.html +49 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ <head> <meta http-equiv="Content-Security-Policy" content="default-src chrome:; object-src 'none'" content="default-src chrome:; font-src data:; object-src 'none'" /> <title data-l10n-id="newtab-page-title"></title> <link Loading @@ -18,6 +18,10 @@ rel="stylesheet" href="chrome://browser/content/abouttor/aboutTor.css" /> <link rel="stylesheet" href="chrome://browser/content/abouttor/yec-2024-fonts.css" /> <link rel="localization" href="browser/newtab/newtab.ftl" /> <link rel="localization" href="toolkit/global/tor-browser.ftl" /> Loading @@ -29,6 +33,50 @@ <script src="chrome://browser/content/abouttor/aboutTor.js"></script> </head> <body class="onion-pattern-background"> <!-- YEC 2024. See tor-browser#43098. --> <article id="yec-2024-banner"> <img class="yec-2024-image yec-2024-message-0" alt="" src="chrome://browser/content/abouttor/yec-2024-speak.svg" /> <img class="yec-2024-image yec-2024-message-1" alt="" src="chrome://browser/content/abouttor/yec-2024-browse.svg" /> <img class="yec-2024-image yec-2024-message-2" alt="" src="chrome://browser/content/abouttor/yec-2024-search.svg" /> <h2 class="yec-2024-heading yec-2024-message-0"> <span data-l10n-id="yec-2024-introduction-0"></span> </h2> <h2 class="yec-2024-heading yec-2024-message-1"> <span data-l10n-id="yec-2024-introduction-1"></span> </h2> <h2 class="yec-2024-heading yec-2024-message-2"> <span data-l10n-id="yec-2024-introduction-2"></span> </h2> <p id="yec-2024-body" data-l10n-id="yec-2024-please-donate"></p> <p id="yec-2024-matching" data-l10n-id="yec-2024-matched-donation"></p> <a id="yec-2024-donate-link"> <span data-l10n-id="yec-2024-donate-button"></span> <img class="yec-2024-icon" alt="" src="chrome://browser/content/abouttor/yec-2024-heart.svg" /> </a> <button id="yec-2024-close" data-l10n-id="yec-2024-close-button"> <img class="yec-2024-icon" alt="" src="chrome://global/skin/icons/close.svg" /> </button> </article> <h1> <img id="tor-browser-logo" Loading Loading
browser/components/BrowserGlue.sys.mjs +1 −0 Original line number Diff line number Diff line Loading @@ -515,6 +515,7 @@ let JSWINDOWACTORS = { DOMContentLoaded: {}, L10nMutationsFinished: {}, SubmitSearchOnionize: { wantUntrusted: true }, YECHidden: { wantUntrusted: true }, }, }, Loading
browser/components/abouttor/AboutTorChild.sys.mjs +5 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,11 @@ export class AboutTorChild extends JSWindowActorChild { new this.contentWindow.CustomEvent("L10nMutationsFinished") ); break; case "YECHidden": // YEC 2024 banner was closed. Persist this for the rest of this // session. See tor-browser#43098 and tor-browser#42188. this.sendAsyncMessage("AboutTor:HideYEC"); break; } } }
browser/components/abouttor/AboutTorParent.sys.mjs +46 −0 Original line number Diff line number Diff line Loading @@ -7,23 +7,69 @@ ChromeUtils.defineESModuleGetters(lazy, { TorConnect: "resource://gre/modules/TorConnect.sys.mjs", }); /** * Whether we should hide the Year end campaign (YEC) 2024 donation banner for * new about:tor pages. Applied to all future about:tor pages within this * session (i.e. new tabs, new windows, and after new identity). * * Will reset at the next full restart. * * See tor-browser#43098 and tor-browser#42188. * * @type {boolean} */ let hideYEC = AppConstants.MOZ_UPDATE_CHANNEL !== "release"; /** * The YEC 2024 start date. * * @type {integer} */ const yecStart = Date.UTC(2024, 9, 14, 15); // 2024 October 14th 15:00. /** * The YEC 2024 end date. * * @type {integer} */ const yecEnd = Date.UTC(2025, 0, 2); // 2025 January 2nd 00:00. /** * Actor parent class for the about:tor page. */ export class AboutTorParent extends JSWindowActorParent { receiveMessage(message) { const onionizePref = "torbrowser.homepage.search.onionize"; const yecMessagePref = "torbrowser.homepage.yec2024.message"; let yecMessageNumber = null; let now; switch (message.name) { case "AboutTor:GetInitialData": now = Date.now(); if (!hideYEC && now >= yecStart && now < yecEnd) { // Will show the banner. yecMessageNumber = Services.prefs.getIntPref(yecMessagePref, 0); // Increase the preference for the next about:tor load. Services.prefs.setIntPref(yecMessagePref, (yecMessageNumber + 1) % 3); } return Promise.resolve({ torConnectEnabled: lazy.TorConnect.enabled, messageData: lazy.AboutTorMessage.getNext(), isStable: AppConstants.MOZ_UPDATE_CHANNEL === "release", searchOnionize: Services.prefs.getBoolPref(onionizePref, false), // Locale for YEC 2024. See tor-browser#43098. yecMessageNumber, appLocale: Services.locale.appLocaleAsBCP47 === "ja-JP-macos" ? "ja" : Services.locale.appLocaleAsBCP47, }); case "AboutTor:SetSearchOnionize": Services.prefs.setBoolPref(onionizePref, message.data); break; case "AboutTor:HideYEC": hideYEC = true; break; } return undefined; } Loading
browser/components/abouttor/content/aboutTor.css +294 −0 Original line number Diff line number Diff line Loading @@ -235,3 +235,297 @@ body:not(.show-tor-check) #tor-check { color: var(--tor-link-color-light); } } /* YEC 2024. * See tor-browser#43098 */ body:not([yec-2024-message-number]) #yec-2024-banner { display: none; } body { --yec-heading-font-size: 32px; } body[yec-2024-message-number] h1 { /* Text of heading is still available to screen readers, but it does not * contribute visually to the page or the body grid layout. */ position: absolute; clip-path: inset(50%); } body:not([yec-2024-message-number="0"]) .yec-2024-message-0 { display: none; } body:not([yec-2024-message-number="1"]) .yec-2024-message-1 { display: none; } body:not([yec-2024-message-number="2"]) .yec-2024-message-2 { display: none; } #yec-2024-banner { grid-area: heading; border-radius: 8px; border: 1px solid var(--in-content-box-border-color); display: grid; grid-template: "yec-heading yec-image" auto "yec-body yec-image" auto "yec-matching yec-image" auto "yec-donate yec-image" min-content / 1fr min-content; --yec-image-background: #1f0333; /* Remove 1px from padding for border. */ padding-block: 55px 55px; padding-inline: 47px 47px; box-sizing: border-box; max-width: 850px; margin-block-end: 40px; /* Position for the close button. */ position: relative; gap: 0 24px; } .yec-2024-image { grid-area: yec-image; align-self: center; /* Center horizontally for small width layout. */ justify-self: center; /* background color and border radius only stands out when using a high * contrast theme. */ -moz-context-properties: fill; fill: var(--yec-image-background); border-radius: 8px; height: 216px; border: 1px solid transparent; /* Remove border from layout size. */ margin: -1px; } .yec-2024-heading { grid-area: yec-heading; margin-block: 0 32px; /* We want to draw a background block of color behind the text in the child * <span> element. If this was en-US only text, we could just set a fixed * line-height that works. However, this can cause problems for some scripts, * like Burmese, where the normal line height is larger. * Instead, in javascript we measure the "normal" line height of the * .yec-2024-heading element using a copy .yec-2024-heading-measure element. * The line height is recorded in `--yec-heading-line-height` and we set the * line-height using this value, plus the amount of padding we would like. */ --yec-heading-block-padding: calc(0.1 * var(--yec-heading-font-size)); --yec-heading-inline-padding: calc(0.25 * var(--yec-heading-font-size)); margin-inline: calc(-1 * var(--yec-heading-inline-padding)); line-height: calc(var(--yec-heading-line-height) + 4 * var(--yec-heading-block-padding)); } .yec-2024-heading, .yec-2024-heading-measure { font-family: "Space Grotesk", sans-serif; font-size: var(--yec-heading-font-size); font-weight: 700; } /* Element used to measure the line height for .yec-2024-heading. * Not visually shown, but should mimic the font size of the corresponding * .yec-2024-heading. */ .yec-2024-heading-measure { position: absolute; visibility: hidden; /* Measure a single line height. */ white-space: nowrap; } .yec-2024-heading > * { /* Paint a block of color behind the text. * NOTE: For some scripts, like Burmese, the background of the inline element * is smaller than the actual script height. * So in javascript we measure the difference as `--yec-heading-gap-top` and * `--yec-heading-gap-bottom` and add this to the block padding, so that the * padding matches the highest and lowest points of the script. */ border-radius: 2px; background: transparent; padding-inline: var(--yec-heading-inline-padding); padding-block-start: calc( var(--yec-heading-gap-top) + var(--yec-heading-block-padding) ); padding-block-end: calc( var(--yec-heading-gap-bottom) + var(--yec-heading-block-padding) ); /* Each line has the padding applied separately. */ box-decoration-break: clone; } #yec-2024-body { grid-area: yec-body; margin-block: 0 8px; } #yec-2024-matching { grid-area: yec-matching; font-weight: 600; margin-block: 0 32px; } #yec-2024-body, #yec-2024-matching { font-size: 1.2em; } #yec-2024-donate-link { grid-area: yec-donate; justify-self: start; font-weight: 700; /* Style like a button. */ color: var(--in-content-button-text-color); border: 1px solid var(--in-content-button-border-color); border-radius: 4px; background-color: var(--in-content-button-background); padding-block: 12px; padding-inline: 16px; text-decoration: none; display: flex; align-items: center; gap: 10px; } #yec-2024-donate-link > * { flex: 0 0 auto; } #yec-2024-donate-link:hover { background-color: var(--in-content-button-background-hover); color: var(--in-content-button-text-color-hover); border-color: var(--in-content-button-border-color-hover); } #yec-2024-donate-link:hover:active { background-color: var(--in-content-button-background-active); color: var(--in-content-button-text-color-active); border-color: var(--in-content-button-border-color-active); } #yec-2024-close { position: absolute; inset-block-start: 16px; inset-inline-end: 16px; padding: 8px; min-width: auto; min-height: auto; width: 16px; height: 16px; box-sizing: content-box; /* Transparent background when neither hover nor active. */ background-color: transparent; border-color: transparent; } #yec-2024-close:hover { background-color: var(--in-content-button-background-hover); border-color: var(--in-content-button-border-color-hover); } #yec-2024-close:hover:active { background-color: var(--in-content-button-background-active); border-color: var(--in-content-button-border-color-active); } .yec-2024-icon { -moz-context-properties: fill; fill: currentColor; } @media (max-width: 768px) { body { --yec-heading-font-size: 1.45rem; } /* Small width layout. */ #yec-2024-banner { grid-template: "yec-image" min-content "yec-heading" auto "yec-body" auto "yec-matching" auto "yec-donate" min-content / 1fr; padding: 31px; /* Match max-width of the form. */ max-width: 600px; margin-block-end: 32px; } .yec-2024-image { height: 168px; } .yec-2024-heading { margin-block: 16px 24px; text-align: center; /* stylelint-disable-next-line property-no-unknown */ text-wrap-style: balance; } #yec-2024-body, #yec-2024-matching { font-size: 1.05em; } #yec-2024-donate-link { justify-self: center; } } @media ((prefers-contrast) or (forced-colors)) and (prefers-color-scheme: dark) { .yec-2024-image { /* Give the dark image a light border to separate from background. */ border-color: var(--in-content-box-border-color); } } @media not ((prefers-contrast) or (forced-colors)) { #yec-2024-banner { background-color: var(--yec-image-background); border-color: transparent; --acorn-yellow-40: #ffbd4f; --acorn-yellow-50: #ffa436; --acorn-yellow-60: #e27f2e; } .yec-2024-heading { color: var(--color-gray-100); } .yec-2024-heading.yec-2024-message-0 > * { /* YEC purple */ background: #d898fa; } .yec-2024-heading.yec-2024-message-1 > * { /* YEC green */ background: #c1ed75; } .yec-2024-heading.yec-2024-message-2 > * { /* YEC red */ background: #ff6a75; } #yec-2024-donate-link { --in-content-button-text-color: var(--color-gray-100); --in-content-button-text-color-hover: var(--color-gray-100); --in-content-button-text-color-active: var(--color-gray-100); --in-content-button-background: var(--acorn-yellow-40); --in-content-button-background-hover: var(--acorn-yellow-50); --in-content-button-background-active: var(--acorn-yellow-60); } #yec-2024-close { /* Rules for #yec-2024-close */ --in-content-button-text-color: var(--color-gray-05); --in-content-button-text-color-hover: var(--color-gray-05); --in-content-button-text-color-active: var(--color-gray-05); } }
browser/components/abouttor/content/aboutTor.html +49 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ <head> <meta http-equiv="Content-Security-Policy" content="default-src chrome:; object-src 'none'" content="default-src chrome:; font-src data:; object-src 'none'" /> <title data-l10n-id="newtab-page-title"></title> <link Loading @@ -18,6 +18,10 @@ rel="stylesheet" href="chrome://browser/content/abouttor/aboutTor.css" /> <link rel="stylesheet" href="chrome://browser/content/abouttor/yec-2024-fonts.css" /> <link rel="localization" href="browser/newtab/newtab.ftl" /> <link rel="localization" href="toolkit/global/tor-browser.ftl" /> Loading @@ -29,6 +33,50 @@ <script src="chrome://browser/content/abouttor/aboutTor.js"></script> </head> <body class="onion-pattern-background"> <!-- YEC 2024. See tor-browser#43098. --> <article id="yec-2024-banner"> <img class="yec-2024-image yec-2024-message-0" alt="" src="chrome://browser/content/abouttor/yec-2024-speak.svg" /> <img class="yec-2024-image yec-2024-message-1" alt="" src="chrome://browser/content/abouttor/yec-2024-browse.svg" /> <img class="yec-2024-image yec-2024-message-2" alt="" src="chrome://browser/content/abouttor/yec-2024-search.svg" /> <h2 class="yec-2024-heading yec-2024-message-0"> <span data-l10n-id="yec-2024-introduction-0"></span> </h2> <h2 class="yec-2024-heading yec-2024-message-1"> <span data-l10n-id="yec-2024-introduction-1"></span> </h2> <h2 class="yec-2024-heading yec-2024-message-2"> <span data-l10n-id="yec-2024-introduction-2"></span> </h2> <p id="yec-2024-body" data-l10n-id="yec-2024-please-donate"></p> <p id="yec-2024-matching" data-l10n-id="yec-2024-matched-donation"></p> <a id="yec-2024-donate-link"> <span data-l10n-id="yec-2024-donate-button"></span> <img class="yec-2024-icon" alt="" src="chrome://browser/content/abouttor/yec-2024-heart.svg" /> </a> <button id="yec-2024-close" data-l10n-id="yec-2024-close-button"> <img class="yec-2024-icon" alt="" src="chrome://global/skin/icons/close.svg" /> </button> </article> <h1> <img id="tor-browser-logo" Loading