diff --git a/articles/faire.md b/articles/faire.md
new file mode 100644
index 0000000000..53c2f87cdf
--- /dev/null
+++ b/articles/faire.md
@@ -0,0 +1,87 @@
+# Faire secures Macs with CIS benchmarks and Fleet
+
+
+## Why Faire needed a change
+
+Faire’s IT team is highly technical and prefers vendors that provide features through APIs. They’re builders who extend applications when out-of-the-box features fall short, and their workflows are highly automated and managed as code.
+
+They had used their previous MDM for several years, but frustration grew as it lagged in adopting new MDM APIs, including Apple’s Declarative Device Management. Faire’s workflow, based on ‘config-as-code’, also proved challenging.
+
+With all their other IT systems, like their IDP, productivity software, and cloud infrastructure, all configured through code with automated CI/CD pipelines, maintaining an MDM that had to be managed via the UI became increasingly painful.
+
+
+One team member spent months trying to build a Terraform provider for the previous MDM, but gave up because of bugs and inconsistent APIs.
+
+Support also became a problem. Feature requests often felt ignored, and responses were slow, which didn’t work for a company of Faire's size.
+
+## The search for a solution
+
+Faire focused on three priorities when selecting a new MDM:
+
+
+
+API-first architecture: A first-class API built for deep integration, not an API layered on top of a UI
+
+Comprehensive Apple support: End-to-end lifecycle management for macOS and iPadOS, including automated enrollment, policy controls, and software distribution
+
+A reputable vendor: A well-established partner they could rely on for the long term
+
+
+## Choosing Fleet
+
+Faire selected Fleet after a bake-off with three other MDM vendors, including an open-source option. They were already using Fleet to manage osquery telemetry, and the availability of a SaaS deployment matched their move away from self-hosting.
+
+All Fleet features are accessible through an API, with examples that show how to automate tasks through GitOps. Fleet integrated directly into Faire’s onboarding workflows, and their engineers appreciate managing device configurations through GitOps and pull requests.
+
+Fleet also gives Faire more flexibility for managing Macs and iPads. They use custom profiles and can tap into native MDM APIs that Fleet exposes, even when those APIs are not yet implemented as built-in features.
+
+In addition, Fleet helps Faire monitor Macs against CIS benchmarks. This improves their device security posture and gives IT the ability to take remediation actions when they find issues.
+
+Fleet’s reputation in the Mac Admins community also matters to Faire. Industry experts highly regard the team and product, and Fleet’s open-source foundation gives Faire confidence that the underlying IP will always remain available.
+
+
+
+*My team is loving managing devices via GitOps with Fleet.*
+
+**Jeremy Baker**
+
+Engineering Manager
+
+
+
+## The future
+
+Faire continues to be impressed by Fleet’s proactive support. For example, Fleet reached out when they detected a downed webhook on Faire’s end. In another instance, an engineer got on a video call 10 minutes after Faire filed a critical migration ticket.
+
+Telemetry from Fleet remains important for device posture. It gives Faire the visibility they need to assess device signals alongside their IDP. Fleet’s integrated MDM then provides a path to remediation and risk mitigation when they find issues.
+
+Fleet is working with Faire to explore managing other platforms, including Windows, Linux, and potentially BYOD mobile devices.
+
+Interested to learn more? [Read Faire’s article](https://craft.faire.com/using-observability-to-reduce-chaos-in-an-mdm-migration-20a0056a48e7) about their MDM migration.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/articles/foursquare.md b/articles/foursquare.md
new file mode 100644
index 0000000000..838927a0ee
--- /dev/null
+++ b/articles/foursquare.md
@@ -0,0 +1,100 @@
+# Foursquare cut costs and gained 114% ROI with Fleet
+
+## Why Foursquare needed a change
+
+Foursquare supports more than 200 Macs and around 15 Windows devices in a hybrid environment, where developers are able to work on the platforms of their choice. That flexibility means the IT team must support macOS and Windows with the same level of consistency and security.
+
+The team faced two main challenges: the complexity of managing endpoints across different MDMs, and the time required to maintain them. As a small team, they were running two separate MDM platforms — an Apple-focused MDM for Macs and another for Windows. The overhead of maintaining both systems was overwhelming and added unnecessary complexity.
+
+To minimize this complexity, the team began automating their processes. Automation required API-driven configurability across systems, but their previous MDM’s fragmented API made it difficult to build reliable DevOps workflows. That limitation pushed the team to evaluate alternatives.
+
+They also found that maintaining multiple MDM tools pulled time away from supporting users. They wanted to refocus their resources on serving their users’ needs instead of “looking after the tools that managed their devices.”
+
+## The search for a solution
+
+The team at Foursquare began evaluating alternatives. Their main goal was to consolidate their device management into a single platform that supported both macOS and Windows. Any replacement also had to match the controls they already relied on in their existing MDMs.
+
+They needed a platform with a developer-friendly API — something simple, reliable, and easy to work with. A clear API would let the team invest more in automation, which hadn’t been practical while managing two different MDMs.
+
+They also wanted the migration to be quick and seamless. With their past experience, the team knew that MDM changes could be disruptive, and they wanted to minimize any impact on end users.
+
+## Choosing Fleet
+
+The Foursquare team had met Fleet at a DevOps conference. After hearing positive feedback and conducting their own research, they decided to evaluate the platform. Fleet checked all the boxes they were looking for: macOS and Windows support, a developer-friendly API, and a GitOps-first approach.
+
+During the evaluation, the team was particularly impressed with Fleet’s Open Source roots. The transparency gave them confidence early on. Everything from bugs to roadmaps and source code was available for review.
+
+
+
+There are no surprises - you can see what they are working on at any time.
+
+**Mike Meyer**
+
+Senior Manager, Corporate Engineer
+
+
+
+A key question was whether Fleet could do everything their current MDMs. The Fleet team helped them translate their current configurations into Fleet equivalents. In some cases, they discovered new ways to manage these settings that were easier to automate. Throughout the process, the Fleet team stayed closely engaged and provided strong support.
+
+The evaluation also showed that Fleet fit well with their telemetry pipeline. They could send device data directly into their SIEM and data lake without staging it separately. Having device data alongside identity and authentication information in the same repository gave the team more flexibility in how they worked with that data.
+
+When Foursquare decided to migrate, moving their macOS and Windows devices to Fleet was seamless. The Fleet team provided ready-to-use tools and guidance that made the transition straightforward.
+
+
+
+One of the easiest, quickest, smoothest migrations I’ve ever done.
+
+**Mike Meyer**
+
+Senior Manager, Corporate Engineer
+
+
+
+## Clearer visibility and stronger automation
+
+After six months, Foursquare began to see clear benefits.
+
+
+
+They reduced time spent on endpoint maintenance by 50%. Instead of “caring for the tools,” the team could focus more on solving their customers’ needs.
+
+They reduced MDM spend by 24% by consolidating two separate platforms into Fleet and eliminating redundant licensing.
+
+
+
+Foursquare also gained real-time visibility into their endpoints. They could dispatch queries and send results directly into their SIEM, giving them a clearer understanding of device state. This level of visibility helped them make data-driven decisions and deploy updates or configuration changes with confidence.
+
+Fleet has also become a key part of their automation workflow. Managing configurations through automation — instead of through a UI — gave the team a level of confidence they didn’t have before.
+
+
+
+Fleet is the best tool for Foursquare - it helps my team be more creative and effective.
+
+**Mike Meyer**
+
+Senior Manager, Corporate Engineer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/articles/stripe.md b/articles/stripe.md
new file mode 100644
index 0000000000..7836ecc09c
--- /dev/null
+++ b/articles/stripe.md
@@ -0,0 +1,97 @@
+# Stripe moved 10,000 Macs to Fleet, saving hundreds of thousands annually
+
+## Why Stripe needed a change
+
+Stripe manages about 10,000 Macs and 5,000 Chromebooks for employees and support partners. All employee Macs are provisioned automatically with Apple Automated Device Enrollment, and users authenticate into the device during onboarding. Chromebooks have a lower risk profile and are used by support partners.
+
+Stripe has a strong focus on security and automation. Their previous MDM relied on manual, UI-driven workflows, which didn’t fit their “infrastructure as code” approach. Fragmented APIs made it hard to automate even simple tasks, and the team had to build workarounds to fill gaps.
+
+New Apple OS releases introduce features, commands, and profiles. Stripe wanted more visibility and control than their MDM provided. Support for the latest OS only arrived after public release, and they couldn’t inject raw payloads or inspect device responses.
+
+Slow vendor support made these issues worse. Stripe often waited a long time for ticket responses, delaying resolutions. Lower-impact bugs sometimes went unfixed.
+
+
+
+*The ability to get heard [with our previous MDM] was just impossible.*
+
+**Wes Whetstone**
+
+Staff Client Platform Engineer
+
+
+## The search for a solution
+
+When their previous MDM came up for renewal, Stripe decided to look for alternatives. They evaluated several MDMs against a clear set of requirements.
+
+First, any replacement had to support all critical use cases for Stripe’s Macs. Employee Macs are “business only,” and third-party software must be approved as “business critical” before installation. Stripe’s security teams also use MDM profiles as part of their device-trust decisions. Getting core MDM functionality right was essential.
+
+Next, the MDM had to fit Stripe’s automation workflows. The team focuses on infrastructure-as-code and wanted the MDM to integrate into existing workflows, not introduce another isolated tool. Stripe also prefers open-source tools because they offer more visibility into how the product works.
+
+Finally, the MDM had to support on-premise deployment. Stripe didn’t consider cloud-only MDMs because they view MDM as critical infrastructure. With control over 10,000 Macs, they wanted full control over who could access the system.
+
+## Choosing Fleet
+
+During evaluation, Stripe needed to confirm that Fleet could handle their core MDM use cases, including Automated Device Enrollment and deploying security profiles.
+
+Fleet met those requirements, but the open-source model gave Stripe additional confidence. Being able to see how profiles were built and deployed made them comfortable managing Macs with Fleet.
+
+
+
+*The openness of the whole management stack … is more valuable to us.*
+
+**Wes Whetstone**
+
+Staff Client Platform Engineer
+
+
+When issues arise, Stripe can also inspect what went wrong themselves. Instead of uploading logs and waiting for a vendor response, they can typically identify where issues originate, which leads to faster resolutions.
+
+Fleet’s API-first design let Stripe automate their entire MDM workflow. They migrated 10,000 Macs in 10 days, and custom profiles allowed them to set up Macs in video conferencing rooms with true zero-touch deployment — something their previous MDM could not support.
+
+
+
+*We saved a couple of hundred thousand dollars a year.*
+
+**Wes Whetstone**
+
+Staff Client Platform Engineer
+
+
+## The results
+
+Using Fleet as the MDM for Macs gives Stripe’s security and IT teams more control over a critical piece of infrastructure. It has removed manual work and allowed the team to build custom solutions, such as enabling remote screen sharing in meeting rooms without requiring someone on site. Core MDM capabilities are now a pillar of Stripe’s zero-trust device attestation.
+
+Stripe is enthusiastic about Fleet’s support, stating that “[Fleet’s] customer success manager played a key role in the successful migration and rollout.”
+
+Stripe also plans to evaluate the capabilities offered by Fleet’s open-source MDM for other platforms they manage, including Windows VMs and BYOD programs.
+
+
+
+*Fleet’s Customer Success Manager for Stripe is the best!*
+
+**Wes Whetstone**
+
+Staff Client Platform Engineer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/website/api/controllers/articles/view-case-study.js b/website/api/controllers/articles/view-case-study.js
new file mode 100644
index 0000000000..ea2da80451
--- /dev/null
+++ b/website/api/controllers/articles/view-case-study.js
@@ -0,0 +1,72 @@
+module.exports = {
+
+
+ friendlyName: 'View case study',
+
+
+ description: 'Display "Case study" page.',
+
+ inputs: {
+ pageUrlSuffix : {
+ description: 'The relative path to the case study article page from within this route.',
+ example: 'case-study/foo',
+ type: 'string',
+ defaultsTo: ''
+ }
+ },
+
+
+ exits: {
+ success: { viewTemplatePath: 'pages/articles/case-study' },
+ badConfig: { responseType: 'badConfig' },
+ notFound: { responseType: 'notFound' },
+ redirect: { responseType: 'redirect' },
+ },
+
+
+ fn: async function ({pageUrlSuffix}) {
+
+ if (!_.isObject(sails.config.builtStaticContent) || !_.isArray(sails.config.builtStaticContent.markdownPages) || !sails.config.builtStaticContent.compiledPagePartialsAppPath) {
+ throw {badConfig: 'builtStaticContent.markdownPages'};
+ }
+
+ // Serve appropriate page content.
+ let thisPage = _.find(sails.config.builtStaticContent.markdownPages, { url: this.req.path });
+ if (!thisPage) {// If there's no EXACTLY matching content page, try a revised version of the URL suffix that's lowercase, with all slashes deduped, and any leading or trailing slash removed (leading slashes are only possible if this is a regex, rather than "/*" route)
+ let revisedPageUrlSuffix = pageUrlSuffix.toLowerCase().replace(/\/+/g, '/').replace(/^\/+/,'').replace(/\/+$/,'');
+ thisPage = _.find(sails.config.builtStaticContent.markdownPages, { url: '/' + revisedPageUrlSuffix });
+ if (thisPage) {// If we matched a page with the revised suffix, then redirect to that rather than rendering it, so the URL gets cleaned up.
+ throw {redirect: thisPage.url};
+ } else {// If no page could be found even with the revised suffix, then throw a 404 error.
+ throw 'notFound';
+ }
+ }
+ // Setting the pages meta title and description from the articles meta tags.
+ let pageTitleForMeta;
+ if(thisPage.meta.articleTitle) {
+ pageTitleForMeta = thisPage.meta.articleTitle;
+ }//fi
+ let pageDescriptionForMeta;
+ if(thisPage.meta.description){
+ pageDescriptionForMeta = thisPage.meta.description;
+ }
+
+ // Set the currentSection variable for the website header to "customers"
+ let currentSection = 'customers';
+
+
+ // Respond with view.
+ return {
+ path: require('path'),
+ thisPage: thisPage,
+ markdownPages: sails.config.builtStaticContent.markdownPages,
+ compiledPagePartialsAppPath: sails.config.builtStaticContent.compiledPagePartialsAppPath,
+ pageTitleForMeta,
+ pageDescriptionForMeta,
+ currentSection,
+ };
+
+ }
+
+
+};
diff --git a/website/assets/images/faire-logo-192x40@2x.png b/website/assets/images/faire-logo-192x40@2x.png
new file mode 100644
index 0000000000..b30bc6a6a0
Binary files /dev/null and b/website/assets/images/faire-logo-192x40@2x.png differ
diff --git a/website/assets/images/foursquare-logo-212x40@2x.png b/website/assets/images/foursquare-logo-212x40@2x.png
new file mode 100644
index 0000000000..b29eb5bed8
Binary files /dev/null and b/website/assets/images/foursquare-logo-212x40@2x.png differ
diff --git a/website/assets/images/jeremy-baker-120x120@2x.png b/website/assets/images/jeremy-baker-120x120@2x.png
new file mode 100644
index 0000000000..4af11d169c
Binary files /dev/null and b/website/assets/images/jeremy-baker-120x120@2x.png differ
diff --git a/website/assets/images/mike-meyer-120x120@2x.png b/website/assets/images/mike-meyer-120x120@2x.png
new file mode 100644
index 0000000000..4c5c58fda8
Binary files /dev/null and b/website/assets/images/mike-meyer-120x120@2x.png differ
diff --git a/website/assets/images/nav-icon-faire-40x40@2x.png b/website/assets/images/nav-icon-faire-40x40@2x.png
new file mode 100644
index 0000000000..370ce7b1dd
Binary files /dev/null and b/website/assets/images/nav-icon-faire-40x40@2x.png differ
diff --git a/website/assets/images/stripe-logo-96x40@2x.png b/website/assets/images/stripe-logo-96x40@2x.png
new file mode 100644
index 0000000000..3cbe4c78fe
Binary files /dev/null and b/website/assets/images/stripe-logo-96x40@2x.png differ
diff --git a/website/assets/images/wes-whetstone-120x120@2x.png b/website/assets/images/wes-whetstone-120x120@2x.png
new file mode 100644
index 0000000000..25cfbd8caa
Binary files /dev/null and b/website/assets/images/wes-whetstone-120x120@2x.png differ
diff --git a/website/assets/js/pages/articles/case-study.page.js b/website/assets/js/pages/articles/case-study.page.js
new file mode 100644
index 0000000000..ebfb9f89cb
--- /dev/null
+++ b/website/assets/js/pages/articles/case-study.page.js
@@ -0,0 +1,25 @@
+parasails.registerPage('case-study', {
+ // ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗
+ // ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
+ // ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
+ data: {
+ //…
+ },
+
+ // ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
+ // ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣
+ // ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝
+ beforeMount: function() {
+ //…
+ },
+ mounted: async function() {
+ //…
+ },
+
+ // ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
+ // ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗
+ // ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝
+ methods: {
+ //…
+ }
+});
diff --git a/website/assets/styles/importer.less b/website/assets/styles/importer.less
index b4bd272436..77f2a21cde 100644
--- a/website/assets/styles/importer.less
+++ b/website/assets/styles/importer.less
@@ -60,6 +60,7 @@
@import 'pages/docs/basic-documentation.less';
@import 'pages/handbook/basic-handbook.less';
@import 'pages/articles/basic-article.less';
+@import 'pages/articles/case-study.less';
@import 'pages/articles/articles.less';
@import 'pages/reports/state-of-device-management.less';
@import 'pages/admin/email-templates.less';
diff --git a/website/assets/styles/pages/articles/case-study.less b/website/assets/styles/pages/articles/case-study.less
new file mode 100644
index 0000000000..47bc741f89
--- /dev/null
+++ b/website/assets/styles/pages/articles/case-study.less
@@ -0,0 +1,816 @@
+#case-study {
+ h1 {
+ font-size: 36px;
+ }
+ hr {
+ margin-top: 64px;
+ margin-bottom: 64px;
+ border-top: 2px solid @core-vibrant-blue-15;
+ width: 100%;
+ }
+ h2 {
+ color: #192147;
+
+ /* Title M (FKA h3) */
+ font-family: Inter;
+ font-size: 24px;
+ font-style: normal;
+ font-weight: 800;
+ line-height: 120%;
+ }
+ h3 {
+ padding-top: 32px;
+ color: #192147;
+
+ /* Title S (FKA h4) */
+ font-family: Inter;
+ font-size: 20px;
+ font-style: normal;
+ font-weight: 600;
+ line-height: 24px; /* 120% */
+ margin-bottom: 24px;
+ }
+ h4 {
+ color: #192147;
+
+ /* Title XS */
+ font-family: Inter;
+ font-size: 16px;
+ font-style: normal;
+ font-weight: 600;
+ line-height: 19.2px; /* 120% */
+ margin-bottom: 24px;
+ }
+
+ [purpose='page-content'] {
+ max-width: 1072px;
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ [purpose='page-container'] {
+ padding: 64px;
+ }
+
+ [purpose='article-title-and-quote'] {
+ max-width: 663px;
+ margin-bottom: 64px;
+ }
+ [purpose='article-title'] {
+ h1 {
+ color: #192147;
+
+ /* Title XL (FKA h1) */
+ font-family: Inter;
+ font-size: 48px;
+ font-style: normal;
+ font-weight: 800;
+ line-height: 57.6px; /* 120% */
+ }
+ }
+ [purpose='case-study-logo'] {
+ margin-bottom: 24px;
+ img {
+ height: 40px;
+ }
+ }
+ [purpose='case-study-quote'] {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ padding-top: 48px;
+ padding-bottom: 48px;
+ [purpose='quote-author-image'] {
+ margin-right: 24px;
+ img {
+ height: 120px;
+ }
+ }
+ [purpose='quote-text'] {
+ color: #515774;
+ font-size: 20px;
+ font-style: italic;
+ font-weight: 400;
+ line-height: 30px; /* 150% */
+ margin-bottom: 16px;
+ }
+ [purpose='quote-author-name'] {
+ color: #515774;
+
+ /* Body SM (bold) */
+ font-family: Inter;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 700;
+ line-height: 21px; /* 150% */
+ margin-bottom: 4px;
+ }
+ [purpose='quote-author-job-title'] {
+ color: #515774;
+
+ /* Body SM (FKA Card text) */
+ font-family: Inter;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 20px; /* 142.857% */
+ margin-bottom: 0px;
+ }
+
+ }
+
+ [purpose='summary'] {
+ margin-bottom: 32px;
+ border-radius: 16px;
+ border: 1px solid #E2E4EA;
+ background: #FFF;
+ padding: 0 32px 32px 32px;
+ ul {
+ margin-bottom: 0px;
+ list-style-type: none;
+ padding-left: 0px;
+ li {
+ font-size: 16px;
+ line-height: 150%;
+ font-style: normal;
+ font-weight: 400;
+ padding-left: 40px;
+ text-indent: -40px;
+ margin-bottom: 0px;
+ padding-top: 16px;
+ padding-bottom: 16px;
+ }
+ li::before {
+ content: ' ';
+ background-image: url('/images/icon-checkbox-checked-24x24@2x.png');
+ background-size: 24px 24px;
+ display: inline-block;
+ position: relative;
+ top: 7px;
+ margin-right: 16px;
+ width: 24px;
+ height: 24px;
+ }
+ }
+ }
+
+ [purpose='right-sidebar'] {
+ margin-top: 16px;
+ margin-left: 64px;
+ width: 343px;
+ font-size: 14px;
+ }
+
+ [purpose='sidebar-link'] {
+ margin-bottom: 12px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ color: #515774;
+ text-decoration: none;
+ img {
+ height: 16px;
+ width: 16px;
+ display: inline;
+ margin-right: 12px;
+ }
+ &:hover {
+ text-decoration: none;
+ color: @core-fleet-black;
+ img {
+ filter: brightness(0.5);
+ }
+ }
+ }
+ [purpose='edit-link'] {
+ padding-top: 24px;
+ padding-bottom: 16px;
+ margin-top: 24px;
+ border-top: 1px solid #E2E4EA;
+ a {
+ text-decoration: none;
+ margin-bottom: 0px;
+ }
+ }
+ [purpose='article-container'] {
+ max-width: 663px;
+ padding-right: 0px;
+ display: flex;
+ flex-direction: column;
+ min-width: 0px;
+ }
+
+ [purpose='company-information'] {
+ p {
+ margin-bottom: 40px;
+ color: #515774;
+
+ /* Body MD (FKA p) */
+ font-family: Inter;
+ font-size: 16px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 24px; /* 150% */
+ }
+ }
+ [purpose='case-study-links'] {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ }
+ [purpose='case-study-link'] {
+ display: flex;
+ flex-direction: row;
+ padding: 8px;
+ align-items: center;
+ text-decoration: none;
+ &:hover {
+ text-decoration: none;
+ border-radius: 4px;
+ background: #f6f7f8;
+ }
+ [purpose='link-image'] {
+ margin-right: 16px;
+ img {
+ height: 40px;
+ }
+ }
+ [purpose='link-text'] {
+ p {
+ margin-bottom: 0px;
+ color: #515774;
+ font-family: Inter;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 18px; /* 150% */
+ }
+ }
+ }
+
+
+
+ [purpose='article-content'] {
+ word-wrap: break-word;
+ h1:first-of-type {
+ display: none;
+ }
+ img {
+ max-width: 100%;
+ width: auto;
+ height: auto;
+ max-height: 100%;
+ margin-left: auto;
+ margin-right: auto;
+ padding: 24px 0px 16px 0px;
+ }
+ h2 {
+ font-size: 24px;
+ margin-top: 64px;
+ margin-bottom: 32px;
+ }
+ h3 {
+ font-size: 20px;
+ margin-top: 48px;
+ margin-bottom: 32px;
+ }
+ h4 {
+ font-size: 16px;
+ margin-top: 24px;
+ margin-bottom: 24px;
+ }
+ h2 > code:not(.bash):not(.nohighlight):not(.mermaid) {
+ padding: 0px 4px;
+ font-weight: 400;
+ font-size: 22px;
+ line-height: inherit;
+ }
+ h3 > code:not(.bash):not(.nohighlight):not(.mermaid) {
+ padding: 0px 4px;
+ font-weight: 400;
+ font-size: 18px;
+ line-height: inherit;
+ }
+ p {
+ font-size: 16px;
+ line-height: 150%;
+ color: #515774;
+ margin-bottom: 32px;
+ }
+ img + em { // Image captions
+ position: relative;
+ top: -12px;
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ margin-bottom: 16px;
+ }
+ ul, ol {
+ padding-left: 16px;
+ }
+ li {
+ padding-bottom: 16px;
+ }
+ li::marker {
+ color: @core-vibrant-blue;
+ }
+ .markdown-heading {
+ scroll-margin-top: 140px;
+ }
+ [purpose='checklist-item'] {
+ display: flex;
+ input[type='checkbox'] {
+ margin-left: -18px;
+ min-width: 16px;
+ min-height: 16px;
+ align-self: center;
+ }
+ input:checked, input:active {
+ accent-color: @core-vibrant-blue;
+ }
+ [purpose='task'] {
+ margin-left: 16px;
+ input {
+ display: none;
+ }
+ p {
+ margin-bottom: 0px;
+ }
+ }
+ }
+ [purpose='checklist-item']::marker {
+ display: none;
+ }
+ ul {
+ list-style-type: disc;
+ padding-left: 16px;
+ }
+ li {
+ line-height: 24px;
+ padding-bottom: 16px;
+ p { // Making sure our list items stay a consistent size if the contents get wrapped in a tag coverted from Markdown.
+ margin-bottom: 0;
+ }
+ ol, ul { // adding padding to nested lists
+ padding-top: 16px;
+ li:last-child { // removing the padding from the last item of nested lists
+ padding-bottom: 0px;
+ }
+ }
+ }
+ ol {
+ counter-reset: custom-counter;
+ list-style-type: none;
+ padding-inline-start: 0px;
+ padding: 0;
+ margin-top: 16px;
+ margin-bottom: 20px;
+ ul > li {
+ text-indent: 0px;
+ margin-left: 0px;
+ }
+ > li {
+ counter-increment: custom-counter;
+ margin-left: 36px;
+ text-indent: -36px;
+ padding-left: 0px;
+ margin-bottom: 16px;
+ code:not(.nohighlight):not(.mermaid) {
+ display: inline;
+ }
+ p {
+ display: inline;
+ margin-bottom: 0px;
+ }
+ blockquote {
+ text-indent: 0px;
+ }
+ }
+ > li::before {
+ content: counter(custom-counter);
+ background-color: #E2E4EA;
+ width: 24px;
+ font-size: 13px;
+ display: inline-block;
+ border-radius: 50%;
+ margin-right: 10px;
+ padding: 2px 4px;
+ text-align: center;
+ line-height: 20px;
+ text-indent: 0px;
+ }
+ }
+ a > code:not(.hljs):not(.nohighlight):not(.mermaid) {
+ color: inherit;
+ text-decoration: inherit;
+ }
+ code:not(.bash):not(.hljs):not(.nohighlight):not(.mermaid) {
+ background: #F1F0FF;
+ padding: 4px 8px;
+ font-family: @code-font;
+ font-size: 13px;
+ line-height: 16px;
+ color: @core-fleet-black;
+ }
+ pre {
+ code {
+ background: none;
+ padding: 0px;
+ font-family: @code-font;
+ font-size: 13px;
+ line-height: 16px;
+ color: @core-fleet-black;
+ }
+ padding: 24px;
+ border: 1px solid #E2E4EA;
+ border-radius: 6px;
+ margin: 0px 0px 40px;
+ font-family: @code-font;
+ background: #F9FAFC;
+ white-space: break-spaces;
+ }
+ code.mermaid:not([data-processed='true']) {
+ opacity: 0;
+ }
+ code.mermaid {
+ color: @core-fleet-black-75;
+ margin-bottom: 16px 0px 32px;
+ font-family: @code-font;
+ display: inline-block;
+ margin-left: auto;
+ margin-right: auto;
+ background: #fff;
+ svg {
+ max-height: 600px;
+ }
+ }
+ blockquote {
+ display: block;
+ position: relative;
+ }
+ [purpose='quote'] {
+ margin: 72px 0 32px 0px;
+ font-style: italic;
+ line-height: 150%;
+ font-size: 20px;
+ max-width: 640px;
+ p {
+ margin-top: 8px;
+ }
+ }
+ [purpose='large-quote'] {
+ margin: 72px 0 32px 0px;
+ font-style: italic;
+ line-height: 150%;
+ margin-bottom: 24px;
+ font-size: 16px;
+ p:last-of-type {
+ margin-bottom: 0px;
+ }
+ strong {
+ color: #515774;
+ font-family: Inter;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 700;
+ line-height: 18px;
+ }
+ }
+ [purpose='large-quote']::before, [purpose='quote']::before {
+ content: ' ';
+ background-image: url('/images/icon-quote-21x17@2x.png');
+ background-repeat: no-repeat;
+ background-size: 21px 17px;
+ display: block;
+ position: relative;
+ top: -16px;
+ left: 0px;
+ width: 21px;
+ height: 17px;
+ }
+ [purpose='attribution-quote'], [purpose='large-quote'] {
+ margin: 64px 0 32px 0px;
+ p:first-of-type {
+ font-style: italic;
+ line-height: 150%;
+ margin-bottom: 24px;
+ font-size: 20px;
+ }
+ p {
+ font-size: 14px;
+ margin-bottom: 4px;
+ }
+ strong {
+ color: #515774;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 700;
+ line-height: 18px;
+ }
+ }
+ [purpose='attribution-quote'] {
+ margin: 80px 0px;
+ padding-top: 15px;
+ }
+ [purpose='attribution-quote']:last-of-type {
+ margin: 80px 0px;
+ }
+ [purpose='attribution-quote']::before {
+ content: ' ';
+ background-image: url('/images/icon-quote-21x17@2x.png');
+ background-repeat: no-repeat;
+ background-size: 21px 17px;
+ display: block;
+ position: relative;
+ top: -16px;
+ left: 0px;
+ width: 21px;
+ height: 17px;
+ }
+ [purpose='checklist'] {
+ margin-bottom: 32px;
+ p {
+ font-size: 16px;
+ line-height: 150%;
+ font-style: normal;
+ font-weight: 400;
+ padding-left: 40px;
+ text-indent: -40px;
+ margin-bottom: 0px;
+ padding-top: 12px;
+ padding-bottom: 12px;
+ &:last-of-type {
+ margin-bottom: 0px;
+ }
+ }
+ p::before {
+ content: ' ';
+ background-image: url('/images/icon-checkbox-checked-24x24@2x.png');
+ background-size: 24px 24px;
+ display: inline-block;
+ position: relative;
+ top: 7px;
+ margin-right: 16px;
+ width: 24px;
+ height: 24px;
+ }
+ }
+ [purpose='tip'] {
+ margin: 16px 0 32px;
+ background: #F7F7FC;
+ border: 1px solid @core-vibrant-blue-50;
+ padding: 16px;
+ border-radius: 8px;
+ display: flex;
+ img {
+ display: flex;
+ margin: 4px 12px 0 0;
+ height: 16px;
+ width: 16px;
+ padding: 0px;
+ }
+ p {
+ display: block;
+ margin-bottom: 16px;
+ line-height: 24px;
+ font-size: 16px;
+ }
+ p:only-child, p:last-child {
+ margin-bottom: 0px;
+ }
+ ul:last-child {
+ margin-bottom: 0px;
+ }
+ li:last-child {
+ padding-bottom: 0px;
+ }
+ }
+ table {
+ table-layout: auto;
+ border: 1px solid @border-lt-gray;
+ border-collapse: collapse;
+ font-size: 16px;
+ line-height: 28px;
+ margin-bottom: 16px;
+ max-width: 100%;
+ th {
+ font-weight: @bold;
+ border: 1px solid @border-lt-gray;
+ padding: 8px 7px 7px 8px;
+ }
+ td {
+ border: 1px solid @border-lt-gray;
+ padding: 8px 7px 7px 8px;
+ }
+ }
+ }
+
+ [purpose='about-fleet-section'] {
+ h2 {
+ margin-bottom: 32px;
+ }
+ p {
+ margin-bottom: 32px;
+ line-height: 150%;
+ }
+ }
+ [purpose='button-row'] {
+ margin-top: 48px;
+ display: flex;
+ flex-direction: row;
+ justify-content: start;
+ align-items: center;
+ a {
+ font-weight: 700;
+ font-size: 14px;
+ text-decoration: none;
+ }
+ [purpose='cta-button'] {
+ cursor: pointer;
+ margin-right: 32px;
+ background: @core-vibrant-green;
+ border-radius: 8px;
+ padding: 16px;
+ height: 36px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ color: #FFF;
+ position: relative;
+ overflow: hidden;
+ }
+ [purpose='cta-button']::before {
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 100%);
+ opacity: 1;
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -5px;
+ width: 50%;
+ height: 100%;
+ transform: skew(-10deg);
+ transition: left 0.5s ease-in, opacity 0.50s ease-in, width 0.5s ease-in;
+ }
+ [purpose='cta-button']:hover:before {
+ left: 160px;
+ width: 110%;
+ }
+ }
+
+ @media (max-width: 991px) {
+ [purpose='page-container'] {
+ padding: 64px 32px;
+ }
+ [purpose='right-sidebar'] {
+ margin-left: 40px;
+ }
+ [purpose='article-title-and-quote'] {
+ margin-bottom: 32px;
+ }
+ [purpose='article-container'] {
+ max-width: 100%;
+ padding-right: 0px;
+ display: flex;
+ flex-direction: column;
+ }
+ [purpose='summary'] {
+ padding: 0 24px 16px 24px;
+ }
+ [purpose='article-content'] {
+ [purpose='attribution-quote'] {
+ text-align: center;
+ margin: 64px 0px;
+ &::before {
+ height: 0px;
+ background: none;
+ display: none;
+ }
+ &:last-of-type {
+ margin-bottom: 96px;
+ }
+ p:first-of-type {
+ font-style: italic;
+ line-height: 150%;
+ margin-bottom: 16px;
+ font-size: 16px;
+ }
+ p {
+ font-size: 12px;
+ margin-bottom: 4px;
+ }
+ strong {
+ color: #515774;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 700;
+ line-height: 18px;
+ }
+ }
+ [purpose='attribution-quote'] + h2 {
+ margin-top: 128px;
+ }
+ }
+ }
+
+ @media (max-width: 767px) {
+ [purpose='article-title'] {
+ h1 {
+ font-size: 32px;
+ line-height: 120%;
+ }
+ }
+ [purpose='page-container'] {
+ padding: 48px 24px;
+
+ }
+ [purpose='page-content'] {
+ max-width: 560px;
+ }
+ [purpose='case-study-quote'] {
+ display: flex;
+ align-items: center;
+ padding-top: 48px;
+ padding-bottom: 64px;
+ [purpose='quote-author-image'] {
+ margin-right: 32px;
+ }
+ [purpose='quote-text'] {
+ font-size: 16px;
+ line-height: 150%; /* 150% */
+ margin-bottom: 8px;
+ }
+
+ }
+ [purpose='company-information'] {
+ h2 {
+ margin-top: 32px;
+ margin-bottom: 16px;
+ color: #192147;
+ font-family: Inter;
+ font-size: 24px;
+ font-style: normal;
+ font-weight: 800;
+ line-height: 120%; /* 120% */
+ }
+ p {
+ margin-bottom: 0px;
+ color: #515774;
+
+ /* Body MD (FKA p) */
+ font-family: Inter;
+ font-size: 16px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 24px; /* 150% */
+ }
+ }
+ [purpose='right-sidebar'] {
+ margin-top: 40px;
+ }
+ [purpose='about-fleet-section'] {
+ margin-bottom: 32px;
+ }
+ [purpose='bottom-case-study-links'] {
+ margin-top: 32px;
+ padding-top: 32px;
+ border-top: 1px solid #E2E4EA;
+ margin-bottom: 32px;
+ }
+ [purpose='article-content'] {
+ img {
+ padding-bottom: 0px;
+ }
+ img + em { // Image captions
+ top: 4px;
+ margin-bottom: 16px;
+ }
+ }
+
+ }
+ @media (max-width: 575px) {
+ [purpose='page-container'] {
+ padding: 32px 24px;
+ }
+ }
+
+ @media (max-width: 375px) {
+ [purpose='page-container'] {
+ padding: 32px 16px;
+ }
+ [purpose='case-study-quote'] {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ [purpose='quote-author-image'] {
+ margin-right: 0px;
+ margin-bottom: 16px;
+ img {
+ height: 80px;
+ }
+ }
+
+ }
+ }
+
+}
diff --git a/website/config/routes.js b/website/config/routes.js
index b5fa63d5bb..1d4a54544b 100644
--- a/website/config/routes.js
+++ b/website/config/routes.js
@@ -162,6 +162,14 @@ module.exports.routes = {
}
},// handles /success-stores/foo
+ 'GET /case-study/*': {
+ skipAssets: false,
+ action: 'articles/view-case-study',// Meta title and description set in view action
+ locals: {
+ currentSection: 'customers',
+ }
+ },// handles /case-study/foo
+
'GET /securing': {
skipAssets: false,
action: 'articles/view-articles',// Meta title and description set in view action
diff --git a/website/scripts/build-static-content.js b/website/scripts/build-static-content.js
index 0f35f7cb41..a0f7363b90 100644
--- a/website/scripts/build-static-content.js
+++ b/website/scripts/build-static-content.js
@@ -651,7 +651,7 @@ module.exports = {
throw new Error(`Failed compiling markdown content: An article page is missing a category meta tag () at "${path.join(topLvlRepoPath, pageSourcePath)}". To resolve, add a meta tag with the category of the article`);
} else {
// Throwing an error if the article has an invalid category.
- let validArticleCategories = ['deploy', 'articles', 'security', 'engineering', 'success stories', 'announcements', 'guides', 'releases', 'podcasts', 'report' ];
+ let validArticleCategories = ['deploy', 'articles', 'security', 'engineering', 'success stories', 'announcements', 'guides', 'releases', 'podcasts', 'report', 'case study' ];
if(!validArticleCategories.includes(embeddedMetadata.category)) {
throw new Error(`Failed compiling markdown content: An article page has an invalid category meta tag () at "${path.join(topLvlRepoPath, pageSourcePath)}". To resolve, change the meta tag to a valid category, one of: ${validArticleCategories}`);
}
@@ -691,11 +691,57 @@ module.exports = {
throw new Error(`Failed compiling markdown content: An article page has an invalid showOnTestimonialsPageWithEmoji meta tag () at "${path.join(topLvlRepoPath, pageSourcePath)}". To resolve, change the value of the meta tag to be one of 🥀, 🔌, 🚪, or 🪟 and try running this script again.`);
}
}
+ if(embeddedMetadata.category === 'case study') {
+ // Note: Case study articles use a page template that requires additional meta tags.
+ if(!embeddedMetadata.summaryChallenge){
+ throw new Error(`Failed compiling markdown content: A case study article is missing a "summaryChallenge" meta tag at ${path.join(topLvlRepoPath, pageSourcePath)}. To resolve, add a summaryChallenge meta tag and try running this script again.`);
+ }
+
+ if(!embeddedMetadata.summarySolution){
+ throw new Error(`Failed compiling markdown content: A case study article is missing a "summarySolution" meta tag at ${path.join(topLvlRepoPath, pageSourcePath)}. To resolve, add a summarySolution meta tag and try running this script again.`);
+ }
+
+ if(!embeddedMetadata.summaryKeyResults){
+ throw new Error(`Failed compiling markdown content: A case study article is missing a "summaryKeyResults" meta tag at ${path.join(topLvlRepoPath, pageSourcePath)}. To resolve, add a summaryKeyResults meta tag and try running this script again.`);
+ } else if(embeddedMetadata.summaryKeyResults.split(';').length === 1) {
+ // Make sure that summaryKeyResults meta tag values are semicolon-separated lists.
+ throw new Error(`Failed compiling markdown content: A case study article has an invalid "summaryKeyResults" meta tag value at ${path.join(topLvlRepoPath, pageSourcePath)}. To resolve, change the summaryKeyResults meta tag value to be a list of results separated by semi-colons (e.g., "Cut endpoint maintenance effort by 50%; Reduced licensing costs by 21%;") and try running this script again.`);
+ }
+
+ // If a companyLogoFilename meta tag is provided, make sure the image exists in the website/assets/images folder.
+ if(embeddedMetadata.companyLogoFilename) {
+ let companyLogoImageExists = await sails.helpers.fs.exists(path.join(topLvlRepoPath, 'website/assets/images/'+embeddedMetadata.companyLogoFilename));
+ if(!companyLogoImageExists){
+ throw new Error(`Failed compiling markdown content: A case study article (${path.join(topLvlRepoPath, pageSourcePath)}) has a "companyLogoFilename" meta tag value that references an image that is not in the website/assets/images folder (${path.join(topLvlRepoPath, 'website/assets/images/'+embeddedMetadata.companyLogoFilename)}). Was it moved?`);
+ }
+ }
+
+ if(embeddedMetadata.quoteContent) {
+ // If a quoteContent meta tag is provided, make sure that the article has quoteAuthorName, quoteAuthorJobTitle, and quoteAuthorImageFilename meta tags.
+ if(!embeddedMetadata.quoteAuthorName) {
+ throw new Error(`Failed compiling markdown content: A case study article is missing a "quoteAuthorName" meta tag at ${path.join(topLvlRepoPath, pageSourcePath)}. To resolve, add a quoteAuthorName meta tag and try running this script again.`);
+ }
+
+ if(!embeddedMetadata.quoteAuthorJobTitle) {
+ throw new Error(`Failed compiling markdown content: A case study article is missing a "quoteAuthorJobTitle" meta tag at ${path.join(topLvlRepoPath, pageSourcePath)}. To resolve, add a quoteAuthorJobTitle meta tag and try running this script again.`);
+ }
+
+ if(!embeddedMetadata.quoteAuthorImageFilename) {
+ throw new Error(`Failed compiling markdown content: A case study article is missing a "quoteAuthorImageFilename" meta tag at ${path.join(topLvlRepoPath, pageSourcePath)}. To resolve, add a quoteAuthorImageFilename meta tag and try running this script again.`);
+ } else {
+ // If a quoteAuthorImageFilename meta tag is provided, make sure the file exists.
+ let quoteAuthorImageExists = await sails.helpers.fs.exists(path.join(topLvlRepoPath, 'website/assets/images/'+embeddedMetadata.quoteAuthorImageFilename));
+ if(!quoteAuthorImageExists){
+ throw new Error(`Failed compiling markdown content: A case study article (${path.join(topLvlRepoPath, pageSourcePath)}) has a "quoteAuthorImageFilename" meta tag value that references an image that is not in the website/assets/images folder (${path.join(topLvlRepoPath, 'website/assets/images/'+embeddedMetadata.quoteAuthorImageFilename)}). Was it moved?`);
+ }
+ }
+ }
+ }
// For article pages, we'll attach the category to the `rootRelativeUrlPath`.
// If the article is categorized as 'product' we'll replace the category with 'use-cases', or if it is categorized as 'success story' we'll replace it with 'device-management'
rootRelativeUrlPath = (
'/' +
- (encodeURIComponent(embeddedMetadata.category === 'success stories' ? 'success-stories' : embeddedMetadata.category === 'security' ? 'securing' : embeddedMetadata.category)) + '/' +
+ (encodeURIComponent(embeddedMetadata.category === 'success stories' ? 'success-stories' : embeddedMetadata.category === 'security' ? 'securing' : embeddedMetadata.category === 'case study' ? 'case-study' : embeddedMetadata.category)) + '/' +
(pageUnextensionedUnwhitespacedLowercasedRelPath.split(/\//).map((fileOrFolderName) => encodeURIComponent(fileOrFolderName.replace(/^[0-9]+[\-]+/,'').replace(/\./g, '-'))).join('/'))
);
}
diff --git a/website/views/layouts/layout.ejs b/website/views/layouts/layout.ejs
index 7d14ff35ac..04b756342d 100644
--- a/website/views/layouts/layout.ejs
+++ b/website/views/layouts/layout.ejs
@@ -232,22 +232,22 @@