From 9af2f9867ed840847f2647c1e74872dbf60f3c2b Mon Sep 17 00:00:00 2001 From: --system Date: Tue, 28 Jan 2025 21:57:40 +0100 Subject: [PATCH] [BUGFIX] Fixed CSP issues in Cornerstone form element and Dashboard backend module, fixed some more dark mode styling issues --- Build/phpstan/phpstan.cms11.neon | 2 + Build/phpstan/phpstan.cms12.neon | 3 +- Build/phpstan/phpstan.cms13.neon | 1 + Build/resources/sass/backend-module.scss | 1 + .../sass/backend-module/_headings.scss | 2 +- Build/resources/yarn.lock | 35 +++++++------ CHANGELOG.md | 4 ++ Classes/Controller/DashboardController.php | 21 +++++++- Classes/Form/Element/Cornerstone.php | 49 +++++++++++++------ .../Private/Partials/Dashboard/View.html | 4 +- .../Private/Templates/Dashboard/Index.html | 2 +- .../Public/CSS/yoast-seo-backend.min.css | 2 +- 12 files changed, 90 insertions(+), 36 deletions(-) diff --git a/Build/phpstan/phpstan.cms11.neon b/Build/phpstan/phpstan.cms11.neon index d9c9366c..f5bfb22c 100644 --- a/Build/phpstan/phpstan.cms11.neon +++ b/Build/phpstan/phpstan.cms11.neon @@ -13,6 +13,7 @@ parameters: - '#TYPO3\\CMS\\Extbase\\Mvc\\RequestInterface#' - '#TYPO3\\CMS\\Core\\View\\ViewInterface#' - '#TYPO3\\CMS\\Core\\Domain\\Repository\\PageRepository::getLanguageOverlay#' + - '#TYPO3\\CMS\\Core\\Domain\\ConsumableString#' - '#frontend.page.information#' - '#ModifyPageLayoutContentEvent#' - '#AfterCacheableContentIsGeneratedEvent#' @@ -21,6 +22,7 @@ parameters: - '#addJsInlineCode#' - '#calculateLifetimeForPage#' - '#CacheLifetimeCalculator#' + - '#nonce#' typo3: requestGetAttributeMapping: handlerRequest: string diff --git a/Build/phpstan/phpstan.cms12.neon b/Build/phpstan/phpstan.cms12.neon index 21268d53..694f9bf1 100644 --- a/Build/phpstan/phpstan.cms12.neon +++ b/Build/phpstan/phpstan.cms12.neon @@ -11,4 +11,5 @@ parameters: - '#protected method getRecordOverlay#' typo3: requestGetAttributeMapping: - handlerRequest: string \ No newline at end of file + handlerRequest: string + nonce: TYPO3\CMS\Core\Security\ContentSecurityPolicy\ConsumableNonce diff --git a/Build/phpstan/phpstan.cms13.neon b/Build/phpstan/phpstan.cms13.neon index 4b2456e3..9acaa438 100644 --- a/Build/phpstan/phpstan.cms13.neon +++ b/Build/phpstan/phpstan.cms13.neon @@ -14,3 +14,4 @@ parameters: requestGetAttributeMapping: frontend.page.information: TYPO3\CMS\Frontend\Page\PageInformation handlerRequest: string + nonce: TYPO3\CMS\Core\Security\ContentSecurityPolicy\ConsumableNonce diff --git a/Build/resources/sass/backend-module.scss b/Build/resources/sass/backend-module.scss index 7a763c54..3f0c36cd 100644 --- a/Build/resources/sass/backend-module.scss +++ b/Build/resources/sass/backend-module.scss @@ -19,6 +19,7 @@ $gutter: 32px; } &-content { + color: var(--typo3-state-default-color, #000); .row { max-width: 1650px; diff --git a/Build/resources/sass/backend-module/_headings.scss b/Build/resources/sass/backend-module/_headings.scss index 99c898fc..42ede442 100644 --- a/Build/resources/sass/backend-module/_headings.scss +++ b/Build/resources/sass/backend-module/_headings.scss @@ -3,7 +3,7 @@ color: $yoast_color_headings; span { - color: #000; + color: var(--typo3-state-default-color, #000); } } } diff --git a/Build/resources/yarn.lock b/Build/resources/yarn.lock index 71b7e799..38d23293 100644 --- a/Build/resources/yarn.lock +++ b/Build/resources/yarn.lock @@ -993,13 +993,20 @@ core-js "^2.5.7" regenerator-runtime "^0.12.0" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8", "@babel/runtime@^7.16.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8", "@babel/runtime@^7.16.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.26.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.12.5": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.7.tgz#f4e7fe527cd710f8dc0618610b61b4b060c3c341" + integrity sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.25.9", "@babel/template@^7.3.3": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" @@ -2120,16 +2127,16 @@ integrity sha512-oocsqY7g0cR+Gur5jRQLSrX2OtpMLMse1I10JQBm8CdGMrDkh1Mg2gjsiquMHRtBs4Qwu5wgEp5GgIYHk4SNPw== "@tanstack/react-virtual@^3.0.0-beta.60": - version "3.10.8" - resolved "https://registry.yarnpkg.com/@tanstack/react-virtual/-/react-virtual-3.10.8.tgz#bf4b06f157ed298644a96ab7efc1a2b01ab36e3c" - integrity sha512-VbzbVGSsZlQktyLrP5nxE+vE1ZR+U0NFAWPbJLoG2+DKPwd2D7dVICTVIIaYlJqX1ZCEnYDbaOpmMwbsyhBoIA== + version "3.11.3" + resolved "https://registry.yarnpkg.com/@tanstack/react-virtual/-/react-virtual-3.11.3.tgz#cd62ecc431043c4a9ca24ea8dfcc2a70f4805380" + integrity sha512-vCU+OTylXN3hdC8RKg68tPlBPjjxtzon7Ys46MgrSLE+JhSjSTPvoQifV6DQJeJmA8Q3KT6CphJbejupx85vFw== dependencies: - "@tanstack/virtual-core" "3.10.8" + "@tanstack/virtual-core" "3.11.3" -"@tanstack/virtual-core@3.10.8": - version "3.10.8" - resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.10.8.tgz#975446a667755222f62884c19e5c3c66d959b8b4" - integrity sha512-PBu00mtt95jbKFi6Llk9aik8bnR3tR/oQP1o3TSi+iG//+Q2RTIzCEgKkHG8BB86kxMNW6O8wku+Lmi+QFR6jA== +"@tanstack/virtual-core@3.11.3": + version "3.11.3" + resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.11.3.tgz#ab92ff899825e2d71fc9914dda2847a099d43862" + integrity sha512-v2mrNSnMwnPJtcVqNvV0c5roGCBqeogN8jDtgtuHCphdwBasOZ17x8UV8qpHUh+u0MLfX43c0uUHKje0s+Zb0w== "@tootallnate/once@2": version "2.0.0" @@ -3697,9 +3704,9 @@ integrity sha512-gp2vPCJesNLG4QYxp/wWOTch88D4a0TkS2GL4N23Rfrl2XrUoM0HHTzRtk0rGd+xMLn/a4fYMI6976HjblhEcg== "@yoast/ui-library@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@yoast/ui-library/-/ui-library-4.0.0.tgz#e597bf92f3b7d0082fe56cd767f0cab321c8f936" - integrity sha512-9vlDJYtkpleNeknAu7o/b4nRZDtPJW1Rll1yCNkVB8/6hzlOPWIGROphkv0q+sooHf0ftkeXFIGowZGExoJbnw== + version "4.1.0" + resolved "https://registry.yarnpkg.com/@yoast/ui-library/-/ui-library-4.1.0.tgz#d81d056219a286908e4c1f319853f40374a827de" + integrity sha512-xJefGYKWcw4izS7y6hYM4ZhUG+dNtub5g2hwqzT6q28veI10CIkzpKvuh3qWA/30v0WJIaX6o4AXhN1ZtUOnYA== dependencies: "@headlessui/react" "^1.7.8" "@heroicons/react" "^1.0.6" @@ -8644,9 +8651,9 @@ grunt-eslint@^21.0.0: chalk "^2.1.0" eslint "^5.16.0" -"grunt-glotpress@git+https://github.com/Yoast/grunt-glotpress.git#main": +"grunt-glotpress@https://github.com/Yoast/grunt-glotpress.git#main": version "0.3.0" - resolved "git+https://github.com/Yoast/grunt-glotpress.git#e6ccc69c2532d126f5d8a30397ffd012e55b6eec" + resolved "https://github.com/Yoast/grunt-glotpress.git#e6ccc69c2532d126f5d8a30397ffd012e55b6eec" dependencies: request "^2.88.0" request-promise-native "^1.0.7" diff --git a/CHANGELOG.md b/CHANGELOG.md index 1595e3f2..b0a35904 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ We will follow [Semantic Versioning](http://semver.org/). - Updates scss files to work with the new dark mode in TYPO3 13 - Labels for Readability and SEO score are now taken from the Yoast translations instead of xlf +### Fixed +- CSP issues within the `Cornerstone` form element and the Dashboard backend module +- Dark mode styling for the Dashboard and Overview backend module + ## 10.1.0 January 27, 2025 ### Added - `TypoScriptStructuredDataProvider` to add structured data to the page, configured with TypoScript (premium functionality) diff --git a/Classes/Controller/DashboardController.php b/Classes/Controller/DashboardController.php index 535a9b09..61b3157b 100644 --- a/Classes/Controller/DashboardController.php +++ b/Classes/Controller/DashboardController.php @@ -5,11 +5,30 @@ namespace YoastSeoForTypo3\YoastSeo\Controller; use Psr\Http\Message\ResponseInterface; +use TYPO3\CMS\Core\Domain\ConsumableString; +use TYPO3\CMS\Core\Information\Typo3Version; +use TYPO3\CMS\Core\Utility\GeneralUtility; class DashboardController extends AbstractBackendController { public function indexAction(): ResponseInterface { - return $this->returnResponse('Dashboard/Index'); + return $this->returnResponse( + 'Dashboard/Index', + ['nonce' => $this->getNonce()] + ); + } + + protected function getNonce(): string + { + if (GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion() < 12) { + return ''; + } + /** @var ConsumableString|null $nonceAttribute */ + $nonceAttribute = $this->request->getAttribute('nonce'); + if ($nonceAttribute instanceof ConsumableString) { + return $nonceAttribute->consume(); + } + return ''; } } diff --git a/Classes/Form/Element/Cornerstone.php b/Classes/Form/Element/Cornerstone.php index 1de2c139..f3489f6c 100644 --- a/Classes/Form/Element/Cornerstone.php +++ b/Classes/Form/Element/Cornerstone.php @@ -4,30 +4,49 @@ namespace YoastSeoForTypo3\YoastSeo\Form\Element; -use TYPO3\CMS\Backend\Form\AbstractNode; +use TYPO3\CMS\Backend\Form\Element\CheckboxElement; +use TYPO3\CMS\Core\Information\Typo3Version; use TYPO3\CMS\Core\Utility\GeneralUtility; -use YoastSeoForTypo3\YoastSeo\Service\Form\NodeTemplateService; - -class Cornerstone extends AbstractNode +use TYPO3\CMS\Extbase\Utility\LocalizationUtility; + +/** + * TODO: This should be handled differently in the future, for example by overriding appendValueToLabelInDebugMode + * but due to the differences between 11, 12 and 13 there's currently no way to add the html to the label in a clean way + * the old way was to provide a custom html template but that caused problems with the inline javascript (CSP) + * This way the core method is used and thus works for every version, but it's not clean + */ +class Cornerstone extends CheckboxElement { - // TODO: Use constructor DI when TYPO3 v11 can be dropped - protected NodeTemplateService $templateService; - /** * @return array */ public function render(): array { - $this->init(); - - $resultArray = $this->initializeResultArray(); - $resultArray['html'] = $this->templateService->renderView('Cornerstone', ['data' => $this->data]); - - return $resultArray; + $checkboxResultArray = parent::render(); + + if (GeneralUtility::makeInstance(Typo3Version::class)->getMajorVersion() < 12) { + $checkboxResultArray['html'] = str_replace( + '', + '' . $this->getLabelWithYoastLink(), + $checkboxResultArray['html'] + ); + } else { + $checkboxResultArray['html'] = preg_replace( + '/(]*\bclass="[^"]*\bform-check-label\b[^"]*"[^>]*>)(.*?)(<\/label>)/is', + '$1$2' . $this->getLabelWithYoastLink() . '$3', + $checkboxResultArray['html'] + ); + } + + return $checkboxResultArray; } - protected function init(): void + protected function getLabelWithYoastLink(): string { - $this->templateService = GeneralUtility::makeInstance(NodeTemplateService::class); + return LocalizationUtility::translate( + 'LLL:EXT:yoast_seo/Resources/Private/Language/BackendModule.xlf:thisPageIsCornerstoneContent', + 'yoast_seo', + ['https://yoa.st/metabox-help-cornerstone'] + ) ?? ''; } } diff --git a/Resources/Private/Partials/Dashboard/View.html b/Resources/Private/Partials/Dashboard/View.html index 347b4be6..ef476a33 100644 --- a/Resources/Private/Partials/Dashboard/View.html +++ b/Resources/Private/Partials/Dashboard/View.html @@ -94,8 +94,8 @@

- - + + diff --git a/Resources/Private/Templates/Dashboard/Index.html b/Resources/Private/Templates/Dashboard/Index.html index 31ec977f..4c380efd 100644 --- a/Resources/Private/Templates/Dashboard/Index.html +++ b/Resources/Private/Templates/Dashboard/Index.html @@ -4,7 +4,7 @@ - + diff --git a/Resources/Public/CSS/yoast-seo-backend.min.css b/Resources/Public/CSS/yoast-seo-backend.min.css index bad50dc3..41186fab 100644 --- a/Resources/Public/CSS/yoast-seo-backend.min.css +++ b/Resources/Public/CSS/yoast-seo-backend.min.css @@ -1 +1 @@ -.yoast h1{color:#a4286a}.yoast h1 span{color:#000}.yoast-list--usp{margin-bottom:1em;padding:0}.yoast-list--usp li{list-style:none!important;padding-left:0;position:relative}.yoast-list--usp li span{color:#77b227}.yoast-button{background-color:transparent;background-color:#dc5c04;border:0;color:#dc5c04;cursor:pointer;display:inline-block;font-size:1.1em;padding:.345em 1.5em .345em 1em;position:relative;text-decoration:none;width:100%}@media only screen and (min-width:30rem){.yoast-button{margin-right:1.36rem;max-height:2.86rem;width:auto}.yoast-button:after{border-bottom:1.44rem solid transparent;border-left:1.43rem solid #dc5c04;border-right:0;border-top:1.43rem solid transparent;content:"";height:0;position:absolute;right:-1.36rem;top:0;width:0}.yoast-button.left{margin-left:1.36rem;margin-right:0}.yoast-button.left:after{content:none}.yoast-button.left:before{border-bottom:1.44rem solid transparent;border-left:0;border-right:1.43rem solid #dc5c04;border-top:1.43rem solid transparent;content:"";height:0;left:-1.36rem;position:absolute;top:0;width:0}}.yoast-button.alignleft{margin:1rem 2.5rem 0 0!important}.yoast-button .arrow{display:none}.yoast-button+.yoast-button{margin-left:1.9rem;margin-top:1em}.yoast-button--full{width:100%}.yoast-button--full:after{content:none}.yoast-button.default{background-color:#dc5c04;color:#fff}.yoast-button.default:after{border-left-color:#dc5c04}.yoast-button.default:before{border-right-color:#dc5c04}.yoast-button a:focus,.yoast-button:hover{background-color:#f58223;color:#fff;text-decoration:underline}.yoast-button a:focus:after,.yoast-button:hover:after{border-left-color:#f58223}.yoast-button a:focus:before,.yoast-button:hover:before{border-right-color:#f58223}.yoast-button.academy{background-color:#5d237a;color:#fff}.yoast-button.academy:after{border-left-color:#5d237a}.yoast-button.academy:before{border-right-color:#5d237a}@media only screen and (max-width:20rem){.yoast-button.academy{background-color:#5d237a}}.yoast-button.academy--secondary{background-color:#a4286a;color:#fff}.yoast-button.academy--secondary:after{border-left-color:#a4286a}.yoast-button.academy--secondary:before{border-right-color:#a4286a}@media only screen and (max-width:20rem){.yoast-button.academy--secondary{background-color:#a4286a}}.yoast-button.software{background-color:#0075b3;color:#fff}.yoast-button.software:after{border-left-color:#0075b3}.yoast-button.software:before{border-right-color:#0075b3}.yoast-button.review{background-color:#009288;color:#fff}.yoast-button.review:after{border-left-color:#009288}.yoast-button.review:before{border-right-color:#009288}.yoast-button.about{background-color:#d93f69;color:#fff}.yoast-button.about:after{border-left-color:#d93f69}.yoast-button.about:before{border-right-color:#d93f69}.yoast_academy .yoast-button{background-color:#d93f69;color:#fff}.yoast_academy .yoast-button:after{border-left-color:#d93f69}.yoast_academy .yoast-button:before{border-right-color:#d93f69}.yoast_academy .yoast-button a:focus,.yoast_academy .yoast-button:hover{background-color:#d42a59;color:#fff;text-decoration:underline}.yoast_academy .yoast-button a:focus:after,.yoast_academy .yoast-button:hover:after{border-left-color:#d42a59}.yoast_academy .yoast-button a:focus:before,.yoast_academy .yoast-button:hover:before{border-right-color:#d42a59}.yoast_academy .yoast-button.dimmed,body .yoast-button.dimmed{background-color:#dcdcdc;color:#646464}.yoast_academy .yoast-button.dimmed:after,body .yoast-button.dimmed:after{border-left-color:#dcdcdc}.yoast_academy .yoast-button.dimmed:before,body .yoast-button.dimmed:before{border-right-color:#dcdcdc}.yoast_academy .yoast-button.dimmed a:focus,.yoast_academy .yoast-button.dimmed:hover,body .yoast-button.dimmed a:focus,body .yoast-button.dimmed:hover{background-color:#cdcdcd;color:#646464;text-decoration:underline}.yoast_academy .yoast-button.dimmed a:focus:after,.yoast_academy .yoast-button.dimmed:hover:after,body .yoast-button.dimmed a:focus:after,body .yoast-button.dimmed:hover:after{border-left-color:#cdcdcd}.yoast_academy .yoast-button.dimmed a:focus:before,.yoast_academy .yoast-button.dimmed:hover:before,body .yoast-button.dimmed a:focus:before,body .yoast-button.dimmed:hover:before{border-right-color:#cdcdcd}.yoast-button--noarrow:after{content:none}.yoast-button--naked{background-color:transparent;border:none;padding:0}.yoast-button--naked:after{content:none}.yoast-button i.fa{font-size:140%;margin:4px 10px 0 0}.yoast{color:#000;letter-spacing:.01em;line-height:1.6}.yoast .callout-body a{font-weight:700}.yoast-content .row{margin-bottom:20px;max-width:1650px}.yoast-content p{margin:1em 0}.yoast-content .yoast-money-back-guarantee{font-style:italic}.yoast-seo-credits__link{display:inline-block;margin-right:30px;margin-top:10px;text-decoration:none!important}.yoast-seo-seoTips__field{width:250px!important}.yoast-seo-academy__item{margin-bottom:20px;position:relative}.yoast-seo-academy__item p{background-color:hsla(0,0%,100%,.75);bottom:0;display:block;font-weight:700;left:0;margin:0;padding:20px 0;position:absolute;right:0;text-align:center}.yoast-seo-premium-extension{margin:2em .5em 1.5em}.yoast-seo-premium-benefits{margin-bottom:30px}.yoast-seo-premium-benefits__title{font-weight:600}.yoast-seo-premium-benefits__description:before{content:"– "}.yoast-seo-premium-benefits__image{margin:40px 0}.yoast-subscribe-form-inputFields{margin-bottom:10px}.yoast-link--more-info{border:1px solid #000}.yoast-button{max-height:none;padding:10px 12px;text-transform:uppercase}.yoast-button--extension{border-style:solid;border-width:1px;color:#fff}.yoast-button--extension+.yoast-button--extension-activated,.yoast-button--extension+.yoast-button--extension-not-activated{margin-left:0}.yoast-button--extension-cta,.yoast-button--extension-cta:hover{background-color:#a4286a;border-color:#a4286a}.yoast-button--extension-cta:visited{color:#fff}.yoast-button--extension-cta--white{background-color:#fff;border:1px solid #000;color:#000}.yoast-button--extension-cta--white:focus,.yoast-button--extension-cta--white:hover,.yoast-button--extension-cta--white:visited{background-color:#fff;color:#000}.yoast-button--extension-activated:hover,.yoast-button--extension-installed:hover,.yoast-button--extension-not-activated:hover{text-decoration:none}.yoast-button--extension-installed{margin-right:.2rem}.yoast-button--extension-installed,.yoast-button--extension-installed:hover{background-color:#008a00;border-color:#008a00}.yoast-button--extension-not-activated,.yoast-button--extension-not-activated:hover{background-color:#dc3232;border-color:#dc3232}.yoast-button--extension-activated,.yoast-button--extension-activated:hover{background-color:#008a00;border-color:#008a00}.yoast-overview-filters{margin-bottom:20px}.compare-free-premium{margin-bottom:20px;max-width:1200px}.compare-free-premium th{color:#a4286a;font-size:16px;font-weight:700;line-height:1.2}.compare-free-premium td,.compare-free-premium th{border:1px solid #e6e6e6;border-collapse:collapse;padding:10px 25px;vertical-align:top}.compare-free-premium .fa-times{color:#dc3232}.compare-free-premium .fa-check{color:#008a00}@media screen and (max-width:600px){.compare-free-premium thead{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0 0 0 0)}.compare-free-premium tr:nth-child(2n){background-color:#e6e6e6}.compare-free-premium tr:nth-child(2n) td:nth-child(2n){border-bottom:2px solid #fff;border-top:2px solid #fff}.compare-free-premium td{display:block}.compare-free-premium td:before{content:attr(data-label);display:block;font-weight:700;margin-bottom:5px;text-transform:uppercase}}.wpseo-score-icon{background:#888;border-radius:50%;float:left;height:12px;margin:3px 10px 0 0;width:12px}.form-inline .form-group{display:inline-block;float:left;margin-right:2em;vertical-align:middle;width:auto}.resetLink{text-decoration:underline}.resetLink:focus,.resetLink:hover{text-decoration:none}.compare-diff{display:flex;flex:1 1 0;-webkit-flex:1 1 0;flex-direction:row;-webkit-box-flex:1;-ms-flex:1 1 0}.compare-diff-icon,.compare-diff-text{display:block}.compare-diff-icon{flex-shrink:0;-webkit-flex:0 0 0;-ms-flex:0 0 0;font-size:24px;margin-right:10px;width:35px}.sr-only{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0,0,0,0);border:0} +.yoast h1{color:#a4286a}.yoast h1 span{color:var(--typo3-state-default-color,#000)}.yoast-list--usp{margin-bottom:1em;padding:0}.yoast-list--usp li{list-style:none!important;padding-left:0;position:relative}.yoast-list--usp li span{color:#77b227}.yoast-button{background-color:transparent;background-color:#dc5c04;border:0;color:#dc5c04;cursor:pointer;display:inline-block;font-size:1.1em;padding:.345em 1.5em .345em 1em;position:relative;text-decoration:none;width:100%}@media only screen and (min-width:30rem){.yoast-button{margin-right:1.36rem;max-height:2.86rem;width:auto}.yoast-button:after{border-bottom:1.44rem solid transparent;border-left:1.43rem solid #dc5c04;border-right:0;border-top:1.43rem solid transparent;content:"";height:0;position:absolute;right:-1.36rem;top:0;width:0}.yoast-button.left{margin-left:1.36rem;margin-right:0}.yoast-button.left:after{content:none}.yoast-button.left:before{border-bottom:1.44rem solid transparent;border-left:0;border-right:1.43rem solid #dc5c04;border-top:1.43rem solid transparent;content:"";height:0;left:-1.36rem;position:absolute;top:0;width:0}}.yoast-button.alignleft{margin:1rem 2.5rem 0 0!important}.yoast-button .arrow{display:none}.yoast-button+.yoast-button{margin-left:1.9rem;margin-top:1em}.yoast-button--full{width:100%}.yoast-button--full:after{content:none}.yoast-button.default{background-color:#dc5c04;color:#fff}.yoast-button.default:after{border-left-color:#dc5c04}.yoast-button.default:before{border-right-color:#dc5c04}.yoast-button a:focus,.yoast-button:hover{background-color:#f58223;color:#fff;text-decoration:underline}.yoast-button a:focus:after,.yoast-button:hover:after{border-left-color:#f58223}.yoast-button a:focus:before,.yoast-button:hover:before{border-right-color:#f58223}.yoast-button.academy{background-color:#5d237a;color:#fff}.yoast-button.academy:after{border-left-color:#5d237a}.yoast-button.academy:before{border-right-color:#5d237a}@media only screen and (max-width:20rem){.yoast-button.academy{background-color:#5d237a}}.yoast-button.academy--secondary{background-color:#a4286a;color:#fff}.yoast-button.academy--secondary:after{border-left-color:#a4286a}.yoast-button.academy--secondary:before{border-right-color:#a4286a}@media only screen and (max-width:20rem){.yoast-button.academy--secondary{background-color:#a4286a}}.yoast-button.software{background-color:#0075b3;color:#fff}.yoast-button.software:after{border-left-color:#0075b3}.yoast-button.software:before{border-right-color:#0075b3}.yoast-button.review{background-color:#009288;color:#fff}.yoast-button.review:after{border-left-color:#009288}.yoast-button.review:before{border-right-color:#009288}.yoast-button.about{background-color:#d93f69;color:#fff}.yoast-button.about:after{border-left-color:#d93f69}.yoast-button.about:before{border-right-color:#d93f69}.yoast_academy .yoast-button{background-color:#d93f69;color:#fff}.yoast_academy .yoast-button:after{border-left-color:#d93f69}.yoast_academy .yoast-button:before{border-right-color:#d93f69}.yoast_academy .yoast-button a:focus,.yoast_academy .yoast-button:hover{background-color:#d42a59;color:#fff;text-decoration:underline}.yoast_academy .yoast-button a:focus:after,.yoast_academy .yoast-button:hover:after{border-left-color:#d42a59}.yoast_academy .yoast-button a:focus:before,.yoast_academy .yoast-button:hover:before{border-right-color:#d42a59}.yoast_academy .yoast-button.dimmed,body .yoast-button.dimmed{background-color:#dcdcdc;color:#646464}.yoast_academy .yoast-button.dimmed:after,body .yoast-button.dimmed:after{border-left-color:#dcdcdc}.yoast_academy .yoast-button.dimmed:before,body .yoast-button.dimmed:before{border-right-color:#dcdcdc}.yoast_academy .yoast-button.dimmed a:focus,.yoast_academy .yoast-button.dimmed:hover,body .yoast-button.dimmed a:focus,body .yoast-button.dimmed:hover{background-color:#cdcdcd;color:#646464;text-decoration:underline}.yoast_academy .yoast-button.dimmed a:focus:after,.yoast_academy .yoast-button.dimmed:hover:after,body .yoast-button.dimmed a:focus:after,body .yoast-button.dimmed:hover:after{border-left-color:#cdcdcd}.yoast_academy .yoast-button.dimmed a:focus:before,.yoast_academy .yoast-button.dimmed:hover:before,body .yoast-button.dimmed a:focus:before,body .yoast-button.dimmed:hover:before{border-right-color:#cdcdcd}.yoast-button--noarrow:after{content:none}.yoast-button--naked{background-color:transparent;border:none;padding:0}.yoast-button--naked:after{content:none}.yoast-button i.fa{font-size:140%;margin:4px 10px 0 0}.yoast{color:#000;letter-spacing:.01em;line-height:1.6}.yoast .callout-body a{font-weight:700}.yoast-content{color:var(--typo3-state-default-color,#000)}.yoast-content .row{margin-bottom:20px;max-width:1650px}.yoast-content p{margin:1em 0}.yoast-content .yoast-money-back-guarantee{font-style:italic}.yoast-seo-credits__link{display:inline-block;margin-right:30px;margin-top:10px;text-decoration:none!important}.yoast-seo-seoTips__field{width:250px!important}.yoast-seo-academy__item{margin-bottom:20px;position:relative}.yoast-seo-academy__item p{background-color:hsla(0,0%,100%,.75);bottom:0;display:block;font-weight:700;left:0;margin:0;padding:20px 0;position:absolute;right:0;text-align:center}.yoast-seo-premium-extension{margin:2em .5em 1.5em}.yoast-seo-premium-benefits{margin-bottom:30px}.yoast-seo-premium-benefits__title{font-weight:600}.yoast-seo-premium-benefits__description:before{content:"– "}.yoast-seo-premium-benefits__image{margin:40px 0}.yoast-subscribe-form-inputFields{margin-bottom:10px}.yoast-link--more-info{border:1px solid #000}.yoast-button{max-height:none;padding:10px 12px;text-transform:uppercase}.yoast-button--extension{border-style:solid;border-width:1px;color:#fff}.yoast-button--extension+.yoast-button--extension-activated,.yoast-button--extension+.yoast-button--extension-not-activated{margin-left:0}.yoast-button--extension-cta,.yoast-button--extension-cta:hover{background-color:#a4286a;border-color:#a4286a}.yoast-button--extension-cta:visited{color:#fff}.yoast-button--extension-cta--white{background-color:#fff;border:1px solid #000;color:#000}.yoast-button--extension-cta--white:focus,.yoast-button--extension-cta--white:hover,.yoast-button--extension-cta--white:visited{background-color:#fff;color:#000}.yoast-button--extension-activated:hover,.yoast-button--extension-installed:hover,.yoast-button--extension-not-activated:hover{text-decoration:none}.yoast-button--extension-installed{margin-right:.2rem}.yoast-button--extension-installed,.yoast-button--extension-installed:hover{background-color:#008a00;border-color:#008a00}.yoast-button--extension-not-activated,.yoast-button--extension-not-activated:hover{background-color:#dc3232;border-color:#dc3232}.yoast-button--extension-activated,.yoast-button--extension-activated:hover{background-color:#008a00;border-color:#008a00}.yoast-overview-filters{margin-bottom:20px}.compare-free-premium{margin-bottom:20px;max-width:1200px}.compare-free-premium th{color:#a4286a;font-size:16px;font-weight:700;line-height:1.2}.compare-free-premium td,.compare-free-premium th{border:1px solid #e6e6e6;border-collapse:collapse;padding:10px 25px;vertical-align:top}.compare-free-premium .fa-times{color:#dc3232}.compare-free-premium .fa-check{color:#008a00}@media screen and (max-width:600px){.compare-free-premium thead{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0 0 0 0)}.compare-free-premium tr:nth-child(2n){background-color:#e6e6e6}.compare-free-premium tr:nth-child(2n) td:nth-child(2n){border-bottom:2px solid #fff;border-top:2px solid #fff}.compare-free-premium td{display:block}.compare-free-premium td:before{content:attr(data-label);display:block;font-weight:700;margin-bottom:5px;text-transform:uppercase}}.wpseo-score-icon{background:#888;border-radius:50%;float:left;height:12px;margin:3px 10px 0 0;width:12px}.form-inline .form-group{display:inline-block;float:left;margin-right:2em;vertical-align:middle;width:auto}.resetLink{text-decoration:underline}.resetLink:focus,.resetLink:hover{text-decoration:none}.compare-diff{display:flex;flex:1 1 0;-webkit-flex:1 1 0;flex-direction:row;-webkit-box-flex:1;-ms-flex:1 1 0}.compare-diff-icon,.compare-diff-text{display:block}.compare-diff-icon{flex-shrink:0;-webkit-flex:0 0 0;-ms-flex:0 0 0;font-size:24px;margin-right:10px;width:35px}.sr-only{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0,0,0,0);border:0}