Landing page for AH's linkedin post (#45278)

This is an experiment landing page to see if we get any different
results from his post


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added "Patch Faster" landing page with marketing content, responsive
styles, and page-level meta (title/description)
* Interactive demo request form with client-side validation, submission
flow, conversion tracking, and success state
* Integrations/platforms and proof sections plus a CTA and client script
to boot the page UI

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/45278)
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Eric <eashaw@sailsjs.com>
This commit is contained in:
johnjeremiah
2026-05-12 21:28:13 -04:00
committed by GitHub
co-authored by Eric
parent e28df10b27
commit 65f2d97dec
7 changed files with 829 additions and 0 deletions
@@ -0,0 +1,28 @@
module.exports = {
friendlyName: 'View patch faster',
description: 'Display "Patch faster" landing page.',
exits: {
success: {
viewTemplatePath: 'pages/landing-pages/patch-faster'
},
badConfig: { responseType: 'badConfig' },
},
fn: async function () {
// Respond with view.
return {};
}
};
@@ -0,0 +1,68 @@
parasails.registerPage('patch-faster', {
// ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗
// ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
data: {
syncing: false,
formData: { /* … */ },
formErrors: { /* … */ },
cloudError: '',
cloudSuccess: false,
demoFormRules: {
emailAddress: { isEmail: true, required: true },
firstName: { required: true },
lastName: { required: true },
organization: { required: true },
numberOfHosts: { required: true },
},
},
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
// ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣
// ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝
beforeMount: function() {
//…
},
mounted: async function() {
//…
},
// ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
// ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗
// ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝
methods: {
handleSubmittingDemoForm: async function(argins) {
this.syncing = true;
// Supply fields not collected from the form.
argins.primaryBuyingSituation = 'it-misc';
if(typeof window.lintrk !== 'undefined') {
window.lintrk('track', { conversion_id: 18587089 });// eslint-disable-line camelcase
}
let report = await Cloud.deliverTalkToUsFormSubmission.with(argins);
if(report.icp) {
if(typeof gtag !== 'undefined') { gtag('event', 'fleet_website__contact_forms__demo__icp'); }
if(typeof window.lintrk !== 'undefined') { window.lintrk('track', { conversion_id: 27493081 }); }// eslint-disable-line camelcase
} else {
if(typeof gtag !== 'undefined') { gtag('event', 'fleet_website__contact_forms__demo'); }
}
if(typeof gtag !== 'undefined') {
gtag('event', 'conversion', {
'send_to': 'AW-10788733823/aNrhCNSYrPobEP-GvJgo',
'value': 1.0,
'currency': 'USD'
});
}
if(typeof qualified !== 'undefined') {
qualified('saveFormData', {
email: this.formData.emailAddress,
name: this.formData.firstName,
company: this.formData.organization,
});
qualified('showFormExperience', 'experience-1772126772950');
}
this.goto(report.eventUrl);
},
}
});
+1
View File
@@ -106,5 +106,6 @@
@import 'pages/landing-pages/on-premise.less';
@import 'pages/articles/basic-whitepaper.less';
@import 'pages/landing-pages/replace-jamf.less';
@import 'pages/landing-pages/patch-faster.less';
@import 'pages/partners.less';
@import 'pages/articles/basic-webinar.less';
@@ -0,0 +1,525 @@
#patch-faster {
@primary: #009A7D;
@primary-dark: #5654d4;
@text-dark: #192147;
@text-secondary: #515774;
@border: #E5E7EB;
@green: #16A348;
@bg-page: #F8F9FA;
@bg-dark: #1C1D21;
@max-content: 1072px;
@max-narrow: 720px;
@max-medium: 800px;
@heading-lineheight: 120%;
@text-lineheight: 150%;
@section-gap: 80px;
@inner-gap: 32px;
p {
margin-bottom: 0;
}
h1, h2, h3, h4, h5 {
margin-bottom: 0;
}
// ─── NAV OVERRIDE ────────────────────────────────────────────
// The site nav is already rendered by the layout; no overrides needed.
// ─── PAGE CONTAINER (white hero + content sections) ──────────
[purpose='page-container'] {
background: #FFFFFF;
padding-left: 64px;
padding-right: 64px;
display: flex;
flex-direction: column;
align-items: center;
gap: @section-gap;
padding-bottom: @section-gap;
}
// ─── HERO ─────────────────────────────────────────────────────
[purpose='hero'] {
display: grid;
grid-template-columns: 1fr 420px;
gap: 64px;
align-items: center;
max-width: @max-content;
width: 100%;
padding-top: 64px;
}
[purpose='hero-copy'] {
display: flex;
flex-direction: column;
gap: 20px;
}
[purpose='eyebrow'] {
font-size: 11px;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
color: @primary;
}
[purpose='hero'] h1 {
color: @text-dark;
font-family: Inter;
font-size: 48px;
font-weight: 800;
line-height: @heading-lineheight;
letter-spacing: -0.02em;
}
[purpose='hero-subhead'] {
font-size: 17px;
line-height: 1.65;
color: @text-secondary;
max-width: 540px;
}
// ─── FORM CARD ─────────────────────────────────────────────────
[purpose='hero-form-col'] {
display: flex;
flex-direction: column;
}
[purpose='form-card'] {
background: #FFFFFF;
border: 1px solid @border;
border-radius: 12px;
padding: 32px;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.07);
display: flex;
flex-direction: column;
gap: 0;
scroll-margin-top: 90px;
h2 {
font-size: 20px;
font-weight: 600;
color: @text-dark;
margin-bottom: 24px;
text-align: left;
}
}
[purpose='form-success'] {
background: #FFFFFF;
border: 1px solid @border;
border-radius: 12px;
padding: 40px 32px;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.07);
text-align: center;
display: flex;
flex-direction: column;
gap: 16px;
align-items: center;
h2 {
font-size: 20px;
font-weight: 600;
color: @text-dark;
text-align: center;
}
p {
color: @text-secondary;
font-size: 15px;
}
[purpose='cta-button'] {
display: inline-block;
margin-top: 8px;
padding: 12px 24px;
background: @primary;
color: #FFFFFF;
font-weight: 600;
font-size: 15px;
border-radius: 7px;
text-decoration: none;
transition: background 0.15s ease;
&:hover {
background: @primary-dark;
}
}
}
[purpose='form-group'] {
margin-bottom: 16px;
display: flex;
flex-direction: column;
label {
font-size: 13px;
font-weight: 500;
color: @text-dark;
margin-bottom: 6px;
}
.form-control {
height: 42px;
font-size: 14px;
border-radius: 7px;
border-color: @border;
&:focus {
border-color: @primary;
box-shadow: 0 0 0 3px rgba(106, 103, 254, 0.12);
}
}
}
[purpose='required-star'] {
color: @primary;
}
[purpose='submit-button'] {
display: block;
width: 100%;
margin-top: 8px;
padding: 13px 24px;
font-size: 15px;
font-weight: 600;
border-radius: 7px;
}
[purpose='fine-print'] {
font-size: 12px;
color: @text-secondary;
text-align: center;
margin-top: 12px;
}
[purpose='trust-signals'] {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid @border;
}
[purpose='trust-signal'] {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: @text-secondary;
img {
flex-shrink: 0;
}
}
// ─── SECTION SHARED ────────────────────────────────────────────
[purpose='section-divider'] {
width: 48px;
height: 3px;
background: @primary;
border-radius: 2px;
margin: 0 auto 28px;
}
// ─── PROBLEM SECTION ───────────────────────────────────────────
[purpose='problem-section'] {
max-width: @max-narrow;
width: 100%;
text-align: center;
h2 {
font-family: Inter;
font-size: 32px;
font-weight: 800;
line-height: @heading-lineheight;
color: @text-dark;
margin-bottom: 24px;
}
}
[purpose='prose'] {
font-size: 16px;
line-height: 1.75;
color: @text-secondary;
text-align: left;
p + p {
margin-top: 20px;
}
}
// ─── SOLUTION SECTION ──────────────────────────────────────────
[purpose='solution-section'] {
max-width: @max-content;
width: 100%;
display: flex;
flex-direction: column;
gap: 48px;
}
[purpose='section-intro'] {
text-align: center;
h2 {
font-family: Inter;
font-size: 32px;
font-weight: 800;
line-height: @heading-lineheight;
color: @text-dark;
}
}
[purpose='features-grid'] {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 32px;
}
[purpose='feature-row'] {
display: flex;
gap: 20px;
align-items: flex-start;
}
[purpose='feature-icon'] {
flex-shrink: 0;
width: 44px;
height: 44px;
background: rgba(106, 103, 254, 0.08);
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
color: @primary;
}
[purpose='feature-label'] {
font-size: 15px;
font-weight: 600;
color: @text-dark;
margin-bottom: 6px;
}
[purpose='feature-desc'] {
font-size: 14px;
line-height: 1.65;
color: @text-secondary;
}
// ─── PROOF STRIP ───────────────────────────────────────────────
[purpose='proof-strip'] {
background: @bg-dark;
padding: 64px;
}
[purpose='proof-inner'] {
max-width: @max-content;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 40px;
text-align: center;
}
[purpose='proof-highlight'] {
font-size: 20px;
font-weight: 700;
color: #FFFFFF;
margin-bottom: 8px;
}
[purpose='proof-detail'] {
font-size: 14px;
line-height: 1.6;
color: rgba(255, 255, 255, 0.6);
}
// ─── BELOW FOLD CONTAINER ──────────────────────────────────────
[purpose='below-fold-container'] {
background: #F8F9FA;
padding: 80px 64px;
display: flex;
flex-direction: column;
align-items: center;
gap: 80px;
}
// ─── PLATFORM SECTION ──────────────────────────────────────────
[purpose='platform-section'] {
max-width: @max-medium;
width: 100%;
text-align: center;
h2 {
font-family: Inter;
font-size: 32px;
font-weight: 800;
line-height: @heading-lineheight;
color: @text-dark;
margin-bottom: 20px;
}
}
[purpose='platform-body'] {
font-size: 16px;
line-height: 1.75;
color: @text-secondary;
margin-bottom: 28px;
}
[purpose='os-pills'] {
display: flex;
justify-content: center;
gap: 12px;
flex-wrap: wrap;
}
[purpose='os-pill'] {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 18px;
background: #FFFFFF;
border: 1px solid @border;
border-radius: 999px;
font-size: 14px;
font-weight: 500;
color: @text-dark;
svg {
opacity: 0.7;
}
}
// ─── INTEGRATIONS SECTION ──────────────────────────────────────
[purpose='integrations-section'] {
max-width: @max-medium;
width: 100%;
text-align: center;
h2 {
font-family: Inter;
font-size: 32px;
font-weight: 800;
line-height: @heading-lineheight;
color: @text-dark;
margin-bottom: 20px;
}
}
[purpose='integrations-body'] {
font-size: 16px;
line-height: 1.75;
color: @text-secondary;
margin-bottom: 28px;
}
[purpose='integration-pills'] {
display: flex;
justify-content: center;
gap: 12px;
flex-wrap: wrap;
}
[purpose='integration-pill'] {
display: inline-flex;
align-items: center;
padding: 8px 18px;
background: #FFFFFF;
border: 1px solid @border;
border-radius: 7px;
font-size: 14px;
font-weight: 500;
color: @text-dark;
}
// ─── CLOSING CTA ───────────────────────────────────────────────
[purpose='closing-cta'] {
background: linear-gradient(180deg, #F8F9FA 0%, #E9F4F4 100%);
padding: 80px 64px;
}
[purpose='closing-cta-inner'] {
max-width: @max-medium;
margin: 0 auto;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
h2 {
font-family: Inter;
font-size: 32px;
font-weight: 800;
line-height: @heading-lineheight;
}
}
[purpose='closing-cta-sub'] {
font-size: 17px;
line-height: 1.6;
max-width: 520px;
}
[purpose='closing-cta'] [purpose='cta-button'] {
.cta-button();
padding: 13px 32px;
}
// ─── RESPONSIVE: 1199px ────────────────────────────────────────
@media (max-width: 1199px) {
[purpose='hero'] {
grid-template-columns: 1fr;
gap: 40px;
padding-top: 48px;
}
[purpose='hero-subhead'] {
max-width: 100%;
}
[purpose='hero'] h1 {
font-size: 40px;
}
[purpose='page-container'] {
padding-left: 40px;
padding-right: 40px;
}
[purpose='proof-strip'] {
padding: 64px 40px;
}
[purpose='below-fold-container'] {
padding: 64px 40px;
}
[purpose='closing-cta'] {
padding: 64px 40px;
}
}
// ─── RESPONSIVE: 991px ─────────────────────────────────────────
@media (max-width: 991px) {
[purpose='features-grid'] {
grid-template-columns: 1fr;
}
[purpose='proof-inner'] {
grid-template-columns: 1fr;
gap: 40px;
}
}
// ─── RESPONSIVE: 767px ─────────────────────────────────────────
@media (max-width: 767px) {
[purpose='page-container'] {
padding-left: 24px;
padding-right: 24px;
}
[purpose='hero'] h1 {
font-size: 32px;
}
[purpose='problem-section'] h2 { font-size: 26px; }
[purpose='section-intro'] h2 { font-size: 26px; }
[purpose='platform-section'] h2 { font-size: 26px; }
[purpose='integrations-section'] h2 { font-size: 26px; }
[purpose='closing-cta-inner'] h2 { font-size: 26px; }
[purpose='proof-strip'] {
padding: 48px 24px;
}
[purpose='below-fold-container'] {
padding: 48px 24px;
gap: 48px;
}
[purpose='closing-cta'] {
padding: 56px 24px;
}
[purpose='trust-signals'] {
flex-direction: column;
}
}
}
+10
View File
@@ -605,6 +605,16 @@ module.exports.routes = {
}
},
'GET /lp/patch-faster': {
action: 'landing-pages/view-patch-faster',
locals: {
currentSection: 'platform',
hideHeaderLinks: true,
pageTitleForMeta: 'Stop waiting on your MDM catalog. Fleet automated patch management.',
pageDescriptionForMeta: 'Fleet\'s maintained app catalog and automated patch policies push updates to every device on a regular, predictable cadence — no manual repackaging, no osquery queries to write.'
}
},
'GET /replace-jamf': {
action: 'landing-pages/view-replace-jamf',
locals: {
+1
View File
@@ -941,6 +941,7 @@
<script src="/js/pages/landing-pages/gitops-workshop.page.js"></script>
<script src="/js/pages/landing-pages/linux-management.page.js"></script>
<script src="/js/pages/landing-pages/on-premise.page.js"></script>
<script src="/js/pages/landing-pages/patch-faster.page.js"></script>
<script src="/js/pages/landing-pages/replace-jamf.page.js"></script>
<script src="/js/pages/legal/privacy.page.js"></script>
<script src="/js/pages/legal/terms.page.js"></script>
+196
View File
@@ -0,0 +1,196 @@
<div id="patch-faster" v-cloak>
<div purpose="page-container">
<%/* ─── HERO ─────────────────────────────────────────── */%>
<div purpose="hero">
<div purpose="hero-copy">
<p purpose="eyebrow">Software management</p>
<h1>Stop waiting on your MDM.</h1>
<p purpose="hero-subhead">When a critical patch drops, the bottleneck isn't your team. It's your toolchain. Fleet's maintained app catalog and automated patch policies push updates to your devices on a regular, predictable cadence. No manual repackaging. No osquery queries to write. No waiting.</p>
</div>
<div purpose="hero-form-col">
<div id="demo-form" purpose="form-card" v-if="!cloudSuccess">
<h2>See how it works.</h2>
<ajax-form :handle-submitting="handleSubmittingDemoForm" :form-errors.sync="formErrors" :form-data="formData" :form-rules="demoFormRules" :syncing.sync="syncing" :cloud-error.sync="cloudError">
<div purpose="form-group">
<label for="patch-first-name">First name <span purpose="required-star">*</span></label>
<input class="form-control" id="patch-first-name" type="text" :class="[formErrors.firstName ? 'is-invalid' : '']" v-model.trim="formData.firstName" autocomplete="given-name" placeholder="Jane" focus-first>
<div class="invalid-feedback" v-if="formErrors.firstName">Please enter your first name.</div>
</div>
<div purpose="form-group">
<label for="patch-last-name">Last name <span purpose="required-star">*</span></label>
<input class="form-control" id="patch-last-name" type="text" :class="[formErrors.lastName ? 'is-invalid' : '']" v-model.trim="formData.lastName" autocomplete="family-name" placeholder="Smith">
<div class="invalid-feedback" v-if="formErrors.lastName">Please enter your last name.</div>
</div>
<div purpose="form-group">
<label for="patch-email">Work email <span purpose="required-star">*</span></label>
<input class="form-control" id="patch-email" type="email" :class="[formErrors.emailAddress ? 'is-invalid' : cloudError === 'invalidEmailDomain' ? 'is-invalid' : '']" v-model.trim="formData.emailAddress" autocomplete="email" placeholder="jane@company.com">
<div class="invalid-feedback" v-if="formErrors.emailAddress">Please enter a valid work email address.</div>
<cloud-error class="p-0 mt-1 mb-0 bg-transparent invalid-feedback" v-if="cloudError === 'invalidEmailDomain'">
<p>Please enter a valid work email address.</p>
</cloud-error>
</div>
<div purpose="form-group">
<label for="patch-company">Company <span purpose="required-star">*</span></label>
<input class="form-control" id="patch-company" type="text" v-model.trim="formData.organization" autocomplete="organization" placeholder="Acme Corp">
<div class="invalid-feedback" v-if="formErrors.organization">Please enter the name of your organization.</div>
</div>
<div purpose="form-group">
<label for="patch-num-employees">Number of employees <span purpose="required-star">*</span></label>
<input class="form-control" id="patch-num-employees" type="number" min="1" :class="[formErrors.numberOfHosts ? 'is-invalid' : '']" v-model.trim="formData.numberOfHosts">
<div class="invalid-feedback" v-if="formErrors.numberOfHosts">Please enter the number of employees.</div>
</div>
<cloud-error v-if="cloudError && cloudError !== 'invalidEmailDomain'"></cloud-error>
<ajax-button purpose="submit-button" type="submit" :syncing="syncing" class="btn btn-primary">Book a demo</ajax-button>
</ajax-form>
<div purpose="trust-signals">
<div purpose="trust-signal">
<img src="/images/icon-checkmark-green-16x16@2x.png" width="16" height="16" alt="" aria-hidden="true">
<span>Fleet-maintained app catalog</span>
</div>
<div purpose="trust-signal">
<img src="/images/icon-checkmark-green-16x16@2x.png" width="16" height="16" alt="" aria-hidden="true">
<span>Automated patch policies</span>
</div>
<div purpose="trust-signal">
<img src="/images/icon-checkmark-green-16x16@2x.png" width="16" height="16" alt="" aria-hidden="true">
<span>macOS, Windows, and Linux</span>
</div>
</div>
</div>
</div>
</div><%/* hero */%>
<%/* ─── PROBLEM ──────────────────────────────────────── */%>
<div purpose="problem-section">
<div purpose="section-divider"></div>
<h2>Manual patching doesn't scale.</h2>
<div purpose="prose">
<p>When a critical CVE drops, the clock starts. But for most IT and security teams, the bottleneck isn't awareness, it's the toolchain. Someone has to download the new version, validate it, package it, and get it into the catalog before a single device gets updated. If you're doing that manually, you're burning engineering time on work that doesn't have to be manual.</p>
<p>The alternative is a catalog that's maintained for you, and policies that trigger automatically when a device falls behind. That's the difference between patching as a project and patching as a background process.</p>
</div>
</div><%/* problem-section */%>
<%/* ─── SOLUTION ─────────────────────────────────────── */%>
<div purpose="solution-section">
<div purpose="section-intro">
<div purpose="section-divider"></div>
<h2>Fleet automates the parts that slow you down.</h2>
</div>
<div purpose="features-grid">
<div purpose="feature-row">
<div purpose="feature-icon" aria-hidden="true">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
</div>
<div purpose="feature-body">
<p purpose="feature-label">Fleet maintained apps: no uploads, no extra configuration</p>
<p purpose="feature-desc">Fleet maintains installation metadata for a growing catalog of apps. Add them to your Fleet instance and install on your hosts without any additional configuration. Chrome, Firefox, Slack, Zoom, Office, and more, across macOS and Windows.</p>
</div>
</div>
<div purpose="feature-row">
<div purpose="feature-icon" aria-hidden="true">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
</div>
<div purpose="feature-body">
<p purpose="feature-label">Patch policies that run automatically</p>
<p purpose="feature-desc">A patch policy checks whether each Fleet maintained app is up to date on your hosts. Fleet auto-generates the correct osquery query for each app, so you don't write or update them. When a host fails the policy, Fleet automatically sends an install request.</p>
</div>
</div>
<div purpose="feature-row">
<div purpose="feature-icon" aria-hidden="true">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
</div>
<div purpose="feature-body">
<p purpose="feature-label">Policy checks run on a regular cadence</p>
<p purpose="feature-desc">Fleet runs policy checks on a typical one-hour cadence across all online hosts. The first time a host fails a patch policy, Fleet triggers the software install. No manual intervention needed.</p>
</div>
</div>
<div purpose="feature-row">
<div purpose="feature-icon" aria-hidden="true">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></svg>
</div>
<div purpose="feature-body">
<p purpose="feature-label">Bring your own packages too</p>
<p purpose="feature-desc">Not everything is in the Fleet catalog yet. Upload your own custom packages, configure custom installation scripts if needed, or let Fleet handle it. The same policy automation applies either way.</p>
</div>
</div>
</div><%/* features-grid */%>
</div><%/* solution-section */%>
</div><%/* page-container */%>
<%/* ─── PROOF STRIP ───────────────────────────────────── */%>
<div purpose="proof-strip">
<div purpose="proof-inner">
<div purpose="proof-item">
<p purpose="proof-highlight">No osquery queries to write</p>
<p purpose="proof-detail">Fleet auto-generates the correct query for each Fleet-maintained app.</p>
</div>
<div purpose="proof-item">
<p purpose="proof-highlight">One-hour policy cadence</p>
<p purpose="proof-detail">Policy checks run on a typical one-hour cadence on all online hosts.</p>
</div>
<div purpose="proof-item">
<p purpose="proof-highlight">macOS, Windows, and Linux</p>
<p purpose="proof-detail">One platform for your entire device fleet, regardless of OS mix.</p>
</div>
</div>
</div><%/* proof-strip */%>
<div purpose="below-fold-container">
<%/* ─── PLATFORM CALLOUT ───────────────────────────────── */%>
<div purpose="platform-section">
<div purpose="section-divider"></div>
<h2>One platform. Every OS.</h2>
<p purpose="platform-body">Fleet manages software across macOS, Windows, and Linux from a single place. The same patch policies, the same catalog, the same automation, whether you're supporting a Mac-first team, a Windows shop, or a mixed environment with Linux servers.</p>
<div purpose="os-pills">
<span purpose="os-pill">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.8-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z"/></svg>
macOS
</span>
<span purpose="os-pill">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M3 12V6.75l6-1.32v6.57H3zm17-9v8.75h-7V4.82L20 3zM3 13h6v6.43l-6-1.29V13zm17 0v8.25l-7-1.43V13h7z"/></svg>
Windows
</span>
<span purpose="os-pill">
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12.5 2C9.46 2 7 4.46 7 7.5c0 1.78.81 3.37 2.09 4.41C7.26 13.19 6 15.22 6 17.5c0 .83.16 1.62.46 2.34L5 21h14l-1.46-1.16C17.84 19.12 18 18.33 18 17.5c0-2.28-1.26-4.31-3.09-5.59C16.19 10.87 17 9.28 17 7.5 17 4.46 14.54 2 11.5 2h1zM9 16c0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3-3-1.34-3-3z"/></svg>
Linux
</span>
</div>
</div><%/* platform-section */%>
<%/* ─── INTEGRATIONS ───────────────────────────────────── */%>
<div purpose="integrations-section">
<div purpose="section-divider"></div>
<h2>Works with the tools you already use.</h2>
<p purpose="integrations-body">Use policy automations to trigger app updates, create tickets in Jira or Zendesk, or generate webhooks to connect Fleet to your existing workflows. Patching fits into the process you already have.</p>
<div purpose="integration-pills">
<span purpose="integration-pill">Jira</span>
<span purpose="integration-pill">Zendesk</span>
<span purpose="integration-pill">Webhooks</span>
<span purpose="integration-pill">GitOps</span>
</div>
</div><%/* integrations-section */%>
</div><%/* below-fold-container */%>
<%/* ─── CLOSING CTA ─────────────────────────────────────── */%>
<div purpose="closing-cta">
<div purpose="closing-cta-inner">
<h2>See what automated patching looks like in Fleet.</h2>
<p purpose="closing-cta-sub">Book a 30-minute demo. We'll walk you through the Fleet-maintained catalog and automated patch policies. Live.</p>
<a purpose="cta-button" href="#demo-form">Book a demo</a>
</div>
</div><%/* closing-cta */%>
<%/* Cloud city banner */%>
<parallax-city></parallax-city>
</div>
<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>