/* Storj site stylesheet. Values from BRAND.md: Inter Extra Bold headlines in
   Storj Black, Inter Light body in Storj Dark Grey, Storj Blue for actions,
   white and light grey backgrounds, gradient 1 for headline highlights. */

/* Inter, self-hosted. It used to come from fonts.googleapis.com, which made
   Google a third party on every pageview of a site that carries no analytics
   and no consent banner -- every visitor's IP, for a font. These are the same
   files Google serves, fetched once and committed: the variable face covering
   300..800, so all three weights BRAND.md names come from one download per
   subset. latin and latin-ext only; unicode-range means a visitor fetches just
   the one their text needs, and the site has no Cyrillic, Greek or Vietnamese
   copy. Inter is under the SIL Open Font License 1.1, see fonts/OFL.txt.

   The paths are relative because HtmlBasePlugin rewrites HTML, not CSS -- a
   root-relative url() here would 404 on a prefixed build. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url(../fonts/inter-var-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url(../fonts/inter-var-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --blue: #0052ff;
  --pink: #ff4ed8;
  --yellow: #ffb018;
  --green: #00e366;
  --light-grey: #f8f9fb;
  --medium-grey: #d0dbe6;
  --dark-grey: #4a5b82;
  --body: #283968;
  --black: #091c45;
  --white: #fff;
  --gradient-1: linear-gradient(90deg, var(--blue), var(--pink));
  --gradient-2: linear-gradient(90deg, var(--pink), var(--yellow));
  --gradient-3: linear-gradient(90deg, var(--yellow), var(--green));
  --gradient-4: linear-gradient(90deg, var(--green), var(--blue));
  --font: "Inter", "Helvetica Neue", Arial, sans-serif;
  --radius: 3px;
  --container: 1200px;
  --narrow: 760px;
  --gap: 24px;
  /* 72px bar plus its 1px rule; the nav is this tall at every width. */
  --nav-h: 73px;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0; font: 300 17px/1.6 var(--font); color: var(--body); background: var(--white);
  -webkit-font-smoothing: antialiased;
}
img, svg, video, iframe { max-width: 100%; height: auto; }
a { color: var(--blue); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4, h5, h6 { font-weight: 800; color: var(--black); line-height: 1.15; margin: 0 0 .5em; letter-spacing: -.01em; }
h1 { font-size: clamp(36px, 5vw, 60px); letter-spacing: -.02em; }
h2 { font-size: clamp(28px, 3.5vw, 40px); }
h3 { font-size: 22px; }
h4 { font-size: 18px; }
p, ul, ol { margin: 0 0 1em; }
strong { font-weight: 800; color: var(--black); }
hr { border: 0; border-top: 1px solid var(--medium-grey); margin: 48px 0; }
table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 12px; border-bottom: 1px solid var(--medium-grey); vertical-align: top; }
th { font-weight: 800; color: var(--black); }
::selection { background: var(--blue); color: var(--white); }

.container { width: min(var(--container), 100% - 48px); margin-inline: auto; }
.container.narrow { max-width: var(--narrow); }
.skip { position: absolute; left: -999px; top: 8px; background: var(--white); padding: 8px 16px; z-index: 100; }
.skip:focus { left: 8px; }

/* ---- type helpers ---- */
.eyebrow { font-size: 13px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--blue); margin-bottom: 12px; }
.lede { font-size: 20px; color: var(--dark-grey); max-width: 46em; }
.meta { font-size: 14px; color: var(--dark-grey); display: flex; gap: 12px; align-items: center; }
.small { font-size: 15px; }
.hl { font-style: normal; background: var(--gradient-1); -webkit-background-clip: text; background-clip: text; color: transparent; }
.center { text-align: center; }
.center .lede { margin-inline: auto; }

/* ---- buttons ---- */
.btn {
  display: inline-flex; align-items: center; gap: 5px; border-radius: var(--radius);
  padding: 13px 26px; font: 800 16px/1.2 var(--font); border: 1px solid transparent; cursor: pointer; text-decoration: none;
}
.btn:hover { text-decoration: none; }
.btn::after { content: ""; width: 16px; height: 16px; background: currentColor; mask: url(../brand/icons/arrow-right.svg) center/contain no-repeat; }
.btn-primary { background: var(--blue); color: var(--white); }
.btn-primary:hover { background: var(--black); }
.btn-outline { border-color: var(--black); color: var(--black); }
.btn-outline:hover { background: var(--black); color: var(--white); }
.btn-text { padding-inline: 0; color: var(--blue); }
.btn-text:hover { color: var(--black); }
/* .btn-text is a bare link with an arrow, not a box. Giving it the outline
   button's white border drew a frame around every "Learn more" on a dark
   section -- it only needs the colour. */
.section-dark .btn-outline { color: var(--white); border-color: var(--white); }
.section-dark .btn-text { color: var(--white); }
/* A .card keeps its own white surface inside a dark section, so the dark
   section's text colours were painting white type onto a white card -- the
   headline was invisible and the quote sat at about 1.3:1. Cards restate
   their own colours rather than inheriting the band's. */
.section-dark .card { color: var(--body); }
.section-dark .card :is(h1, h2, h3, h4, strong) { color: var(--black); }
.section-dark .card :is(.eyebrow, .btn-text) { color: var(--blue); }
.section-dark .btn-outline:hover { background: var(--white); color: var(--black); }
.btn-primary.btn-white { background: var(--white); color: var(--black); }
/* Buttons sit inline inside a paragraph. A left margin on the second one is
   fine on one line and pushes it off-centre the moment the pair wraps, which
   is every phone. Lay the pair out instead, so wrapped rows stay aligned. */
p:has(> .btn) { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
:is(.center, .cta-band, .quote) p:has(> .btn) { justify-content: center; }

/* ---- layout ---- */
.section { padding: 80px 0; }
/* Two sections sharing a background read as one band, so their 80px paddings
   stack into 160px of empty colour with nothing in it. Collapse the seam.
   Where the background does change, the full 160px is the deliberate break. */
:is(.section-grey, .cta-band) + :is(.section-grey, .cta-band),
.section-dark + .section-dark,
.section:not(.section-grey, .section-dark, .cta-band) + .section:not(.section-grey, .section-dark, .cta-band) { padding-top: 0; }
.section-grey { background: var(--light-grey); }
.section-dark { background: var(--black); color: var(--medium-grey); }
.section-dark h1, .section-dark h2, .section-dark h3, .section-dark strong { color: var(--white); }
.section-dark .lede, .section-dark .eyebrow { color: var(--medium-grey); }
.section-dark .hl { background: none; color: var(--white); }
.grid-2, .grid-3, .grid-4 { display: grid; gap: var(--gap); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); }
.split { display: grid; gap: 48px; align-items: center; grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr)); }
.split.reverse > :first-child { order: 1; }
.section-head { max-width: 46em; margin-bottom: 48px; }

/* ---- hero ---- */
.hero { padding: 96px 0 64px; position: relative; overflow: hidden; }
/* The bar is sticky, so it reserves its own height in flow and a hero begins
   underneath it -- which left the wash stopping short of the top of the window
   while the bar itself was transparent. Pull the first hero up behind the bar
   and hand the height back as padding: the content sits exactly where it did,
   but the gradient now runs to the top of the page. */
main > .hero:first-child { margin-top: calc(-1 * var(--nav-h)); padding-top: calc(96px + var(--nav-h)); }
.hero-plain { padding-bottom: 32px; }
.hero-split { display: grid; gap: 48px; align-items: center; grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr)); }
.hero .lede { margin-bottom: 32px; }
.hero-image { border-radius: 8px; }
/* The path: a single rounded gradient ribbon sweeping under the hero, from
   BRAND.md. Thickness ~2x the H1 size. */
.hero-path { position: absolute; inset: auto -10% -40px -10%; height: 120px; pointer-events: none; z-index: -1; }

/* Gradient wash: soft brand-colour bloom filling a hero, clipped by the hero's
   own overflow. Colours come from the --wash-* vars so a page can retint it.
 *
 * Every hero gets it. It was opt-in per page, and page after page quietly
 * missed it -- the two product pages and everything under Solutions among them
 * -- which read as broken rather than as a choice. Listing heroes opt out:
 * .hero-plain is a compact utility header with no room for a bloom, and it
 * repeats across paginated archives where it would be wallpaper. */
.hero { --wash-a: var(--blue); --wash-b: var(--pink); --wash-c: var(--yellow); }
.hero-wash-cool { --wash-a: var(--green); --wash-b: var(--blue); --wash-c: var(--pink); }
.hero:not(.hero-plain)::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(60% 55% at 12% 15%, color-mix(in srgb, var(--wash-a) 16%, transparent), transparent 70%),
    radial-gradient(55% 50% at 88% 8%, color-mix(in srgb, var(--wash-b) 18%, transparent), transparent 70%),
    radial-gradient(70% 60% at 60% 95%, color-mix(in srgb, var(--wash-c) 12%, transparent), transparent 70%);
  /* fade out before the hero's edge so the wash has no hard cut-off line */
  mask-image: linear-gradient(to bottom, #000 50%, transparent);
}

/* Product collage: the dashboard screenshot with the finder card overlapping its
   lower-left corner. Stacks on narrow screens. */
.hero-collage { position: relative; max-width: 940px; margin: 48px auto 0; padding-bottom: 7%; }
.hero-collage img { display: block; border-radius: 10px; box-shadow: 0 30px 60px rgba(9,28,69,.16); }
.hero-collage-front { position: absolute; left: -3%; bottom: 0; width: 54%; }

/* Tab switcher: pure CSS, driven by :target so /pricing/#object-mount deep links
   still land on the right panel. The first panel shows when nothing is targeted. */
.tabs-bar { display: flex; gap: 4px; background: var(--light-grey); border-radius: 99px; padding: 6px; width: max-content; max-width: 100%; margin: 32px auto 0; flex-wrap: wrap; justify-content: center; }
.tabs-bar a { padding: 12px 28px; border-radius: 99px; font: 800 16px/1.2 var(--font); color: var(--black); }
.tabs-bar a:hover { text-decoration: none; color: var(--blue); }
.tab-panel { display: none; }
.tabs:not(:has(.tab-panel:target)) > .tab-panel:first-of-type,
.tab-panel:target { display: block; }
.tabs:not(:has(.tab-panel:target)) .tabs-bar a:first-child,
.tabs:has(#object-storage:target) .tabs-bar a[href="#object-storage"],
.tabs:has(#object-mount:target) .tabs-bar a[href="#object-mount"],
.tabs:has(#cloud-compute:target) .tabs-bar a[href="#cloud-compute"] {
  background: var(--white); box-shadow: 0 2px 8px rgba(9,28,69,.1); color: var(--black);
}

/* Blog lead: featured post on the left, the latest posts listed on the right. */
.blog-lead { display: grid; gap: var(--gap); grid-template-columns: 3fr 2fr; align-items: start; }
.blog-lead-list { display: flex; flex-direction: column; gap: 8px; }
.blog-lead-head { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; justify-content: space-between; }
.blog-lead-head h2 { margin: 0; font-size: 26px; }
.blog-lead-list ul { list-style: none; padding: 0; margin: 0; }
.blog-lead-list li { border-top: 1px solid var(--medium-grey); padding: 16px 0; }
.blog-lead-list a { font-weight: 800; color: var(--black); display: block; }
.blog-lead-list a:hover { color: var(--blue); text-decoration: none; }
.blog-lead-list time { font-size: 14px; color: var(--dark-grey); }
@media (max-width: 860px) {
  .blog-lead { grid-template-columns: 1fr; }
  .hero-collage { padding-bottom: 0; }
  .hero-collage-front { position: static; width: 100%; margin-top: 16px; }
}

/* ---- cards ---- */
.card { background: var(--white); border: 1px solid var(--medium-grey); border-radius: 8px; overflow: hidden; display: flex; flex-direction: column; }
.card-link { color: inherit; }
.card-link:hover { text-decoration: none; border-color: var(--blue); }
.card-link:hover h3 { color: var(--blue); }
.card > img { aspect-ratio: 16/9; object-fit: cover; width: 100%; }
.card-body { padding: 24px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.card-body h3 { margin: 0; font-size: 19px; }
.card-body .eyebrow, .card-body .meta { margin: 0; }
.card-body > :last-child { margin-top: auto; }
.card-body > p { margin: 0; }
.feature { padding: 0; }
/* Size the icon itself, not just the ones inside .feature. Under .tile it had
   no rule at all, and once .tile became a flex column the images stretched to
   the full cell width -- 309px and 508px leaves. flex: none keeps them out of
   the flex sizing entirely. */
.icon { width: 48px; height: 48px; flex: none; }
:is(.feature, .tile) > .icon { margin-bottom: 16px; }
/* Standing alone as one half of a split, an icon is that column's artwork
   rather than a label for it. A 20px mark stranded in a 560px column read as
   an empty half, so the section centres on a single column instead. */
.split:has(> .icon) { display: flex; flex-direction: column; align-items: center; text-align: center; max-width: var(--narrow); }
.split:has(> .icon) > .icon { order: -1; width: 64px; height: 64px; margin-bottom: 24px; }
.feature h3 { font-size: 20px; }
.tile { background: var(--light-grey); border-radius: 8px; padding: 32px; }
.section-grey .tile { background: var(--white); }
.stat { text-align: center; }
.stat-num { font-size: clamp(40px, 5vw, 64px); font-weight: 800; color: var(--black); line-height: 1; margin: 0 0 8px; background: var(--gradient-1); -webkit-background-clip: text; background-clip: text; color: transparent; display: inline-block; }
.logos { display: flex; flex-wrap: wrap; gap: 32px 48px; align-items: center; justify-content: center; }
.logos img { height: 36px; width: auto; max-width: 160px; filter: grayscale(1); opacity: .7; }
.pills { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.pills a { display: inline-block; padding: 6px 14px; border: 1px solid var(--medium-grey); border-radius: 99px; font-size: 14px; color: var(--black); }
.pills a:hover, .pills a[aria-current] { background: var(--black); color: var(--white); text-decoration: none; }
/* `margin: 0` here also zeroed the inline margins that .container sets to auto
   -- same specificity, and this rule comes later -- so every quote sat flush
   against the left edge instead of centred. Zero the block margins only. */
.quote { margin: 0 auto; text-align: center; }
/* The pull-quote treatment belongs to the quotation, not to every <p> in the
   block. An .eyebrow label and a <p> wrapping a CTA button are also <p>
   children of .quote, and a blanket `.quote p` blew both up to 30px. */
.quote > p:not(.eyebrow):not(:has(.btn)) { font-size: clamp(22px, 2.5vw, 30px); font-weight: 500; line-height: 1.35; }
/* Where the block leads with a headline, the headline carries the emphasis and
   the quotation steps down -- otherwise a 40px h2 and a 30px quote compete. */
.quote:has(:is(h2, h3)) :is(h2, h3) { font-size: clamp(24px, 2.2vw, 30px); }
.quote:has(:is(h2, h3)) > p:not(.eyebrow):not(:has(.btn)) { font-size: clamp(17px, 1.3vw, 20px); font-weight: 400; }
.quote > p:not(.eyebrow) { color: var(--black); }
.quote footer { color: var(--dark-grey); }
/* --black IS the .section-dark background, so the quotation was rendering in a
   colour identical to what it sat on (contrast 1.0) and the attribution at 2.5:1. */
.section-dark .quote > p:not(.eyebrow) { color: var(--white); }
.section-dark .quote footer { color: var(--medium-grey); }
.quote .avatar { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; padding: 3px; background: var(--gradient-1); margin-bottom: 16px; }
.avatar { border-radius: 50%; object-fit: cover; }
/* A person is a portrait with a caption under it, so the three parts centre on
   each other. The name was sitting flush against the photo -- .avatar carried
   no bottom margin outside a quote -- and the whole cell was left-aligned. */
.people .feature { align-items: center; text-align: center; }
.people .avatar { width: 96px; height: 96px; flex: none; margin-bottom: 20px; }
.check-list { list-style: none; padding: 0; }
.check-list li { padding-left: 32px; position: relative; margin-bottom: 12px; }
.check-list li::before { content: ""; position: absolute; left: 0; top: 2px; width: 20px; height: 20px; background: var(--blue); mask: url(../brand/icons/circle-check.svg) center/contain no-repeat; }
details.faq { border-bottom: 1px solid var(--medium-grey); padding: 16px 0; }
details.faq summary { cursor: pointer; font-weight: 800; color: var(--black); font-size: 18px; list-style: none; display: flex; justify-content: space-between; gap: 16px; }
details.faq summary::-webkit-details-marker { display: none; }
details.faq summary::after { content: ""; flex: none; width: 20px; height: 20px; background: var(--black); mask: url(../brand/icons/plus.svg) center/contain no-repeat; transition: transform .2s; }
details.faq[open] summary::after { transform: rotate(45deg); }
details.faq > :not(summary) { margin-top: 12px; }
.cta-band { text-align: center; background: var(--light-grey); }
.cta-band .lede { margin-inline: auto; }
.pager { display: flex; gap: 16px; align-items: center; justify-content: center; margin-top: 48px; }
.pager .btn::after { display: none; }
/* A row of these is a comparison: the eye reads across it. Logos have wildly
   different aspect ratios and the headlines run two to four lines, so left to
   stack naturally nothing lined up -- every logo, headline and link sat at its
   own height. Fixing the logo box aligns the headlines, and pushing the link
   down aligns the links, since the grid already stretches the cells to match. */
.customer-logo, .partner-logo {
  height: 48px; width: auto; max-width: 100%;
  object-fit: contain; object-position: left center;
  margin-bottom: 24px;
}
/* The grid stretches every cell in a row to a common height, so a trailing
   link should sit on the row's baseline rather than trailing whatever length
   of copy happens to be above it. Without this the "Learn more" links stepped
   down the row by as much as 99px. */
:is(.tile, .feature) { display: flex; flex-direction: column; }
:is(.tile, .feature) > :is(.btn, p:has(> .btn)):last-child { margin-top: auto; }
.stats { text-align: center; }
/* ---- pricing cards ---- */
/* A pricing row is a comparison table cut into three columns, and it only works
   if every card has the same skeleton -- eyebrow, name, description, rate,
   specs, CTA. Before this the free plan showed a 40px $0 over a check-list
   while the paid plans buried $7/TB and $10/TB in a bordered table, and the two
   halves of the row read as different objects. Every card is a check-list now,
   with no rules in it: the row rhythm carries the structure. */
/* The card row is the one thing on the page allowed to break the 1200px column.
   The 48px page gutter, not the max-width, is what caps it on a laptop, so this
   takes a narrower one too. */
.container.wide { --container: 1600px; width: min(var(--container), 100% - 32px); }
.plan {
  display: flex; flex-direction: column;
  background: var(--light-grey); border: 1px solid transparent;
  border-radius: 8px; padding: 36px;
}
.plan h3 { font-size: 26px; margin-bottom: 8px; }
/* Descriptions run one or two lines depending on how wide the cards get.
   Reserving two -- 3.2em is two lines of the 1.6 body leading -- puts every
   rate below them on a common baseline, which is what makes the row scan. */
.plan h3 + p { color: var(--dark-grey); min-height: 3.2em; margin-bottom: 20px; }

/* The recommended plan is the one place this row raises its voice: it lifts out
   of the grey with a white fill and a blue edge, capped by the house gradient.
   Everything else stays quiet. */
.plan-featured { background: var(--white); border-color: var(--blue); position: relative; overflow: hidden; }
.plan-featured::before { content: ""; position: absolute; inset: 0 0 auto; height: 3px; background: var(--gradient-1); }

/* The rate. The caption track is reserved whether or not a card has a label, so
   the free plan's bare $0 lands on the same line as the paid plans' rates. */
.plan-rate { display: grid; grid-template-rows: 1.4em auto; margin-bottom: 24px; }
.plan-rate-label { font: 800 13px/1.4 var(--font); letter-spacing: .08em; text-transform: uppercase; color: var(--dark-grey); }
.plan-rate .price { grid-row: 2; font-size: 36px; line-height: 1.1; }

/* Specs are one line per fact in every card, so the label leads and the value
   follows it inline -- no second column to align and nothing to wrap awkwardly. */
.plan .check-list { margin-bottom: 0; }
.plan .check-list li { margin-bottom: 14px; }
.plan .check-list li strong { color: var(--black); }

/* An auto top margin drops each CTA to the bottom of its card, and the grid
   stretches cards to equal height, so the three line up across the row. */
.plans .plan-cta { margin: auto 0 0; padding-top: 24px; }
.plans .plan-cta .btn { width: 100%; justify-content: center; }

@media (max-width: 600px) {
  .plan h3 + p { min-height: 0; }
  /* The caption track above the rate exists to line the rates up across the
     row. Stacked on a phone there is no row to line up with, so it reads as a
     gap over the free plan's bare $0. */
  .plan-rate { grid-template-rows: auto auto; }
}
.price { font-size: 40px; font-weight: 800; color: var(--black); line-height: 1; }
/* A three-column comparison cannot compress to a phone. Without this the third
   column ran off the side with no way to reach it -- the page did not even
   scroll, so the content was unreachable rather than merely awkward. */
.table-scroll { overflow-x: auto; }
@media (max-width: 860px) { .table-scroll table { min-width: 620px; } }
.price small { font-size: 15px; font-weight: 300; color: var(--dark-grey); }
.video { aspect-ratio: 16/9; width: 100%; border: 0; border-radius: 8px; }
/* iframes and the logo in a quote are replaced elements, which are inline by
   default: they pick up a stray baseline gap and ignore block margins. The
   video sat 8px above the grid under it while the block above it had 48. */
.container > iframe, .quote img { display: block; margin-inline: auto; }
.video:not(:last-child) { margin-bottom: 48px; }
.quote img:not(.avatar) { margin-bottom: 24px; }
/* A <p> that only wraps buttons has no top margin, so a CTA dropped straight
   after a grid or a quote attribution sat flush against it. */
:is(.grid-2, .grid-3, .grid-4, .logos, table, .video, .quote footer) + p:has(.btn):not(.plan-cta) { margin-top: 24px; }

/* ---- prose (markdown and CMS rich text) ---- */
.prose > :first-child { margin-top: 0; }
.prose h2 { margin-top: 1.6em; font-size: 28px; }
.prose h3 { margin-top: 1.4em; }
.prose img, .prose figure { margin: 32px 0; border-radius: 8px; }
.prose figure > div { display: contents; }
.prose figcaption { font-size: 14px; color: var(--dark-grey); }
.prose li { margin-bottom: .4em; }
.prose blockquote { margin: 32px 0; padding-left: 24px; border-left: 3px solid var(--blue); font-size: 20px; color: var(--black); }
.prose pre { background: var(--black); color: var(--white); padding: 20px; border-radius: 8px; overflow-x: auto; font-size: 14px; }
.prose code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .9em; }
.prose :not(pre) > code { background: var(--light-grey); padding: 2px 6px; border-radius: 3px; }
.prose a { text-decoration: underline; text-underline-offset: 2px; }
.prose iframe { width: 100%; aspect-ratio: 16/9; border: 0; height: auto; }
.post-head { text-align: center; }
.post-head .meta { justify-content: center; }
.post-head .lede { margin-inline: auto; }
.post-image { border-radius: 8px; margin: 32px 0; width: 100%; }
.author-card { display: flex; gap: 20px; align-items: flex-start; margin-top: 64px; padding-top: 32px; border-top: 1px solid var(--medium-grey); }
.author-card img { border-radius: 50%; flex: none; width: 72px; height: 72px; object-fit: cover; }
.author-card .footer-head { color: var(--black); margin-bottom: 4px; }

/* ---- nav ---- */
/* At the top of the page the bar carries no chrome at all, so the logo and the
   links read as the first line of the page rather than as a fixed header. The
   fill and the rule arrive once the page starts moving underneath it -- and
   also whenever a panel is down, since an open dropdown floating over bare
   page with nothing behind the bar looks detached. */
.nav { position: sticky; top: 0; z-index: 50; background: transparent; border-bottom: 1px solid transparent; transition: background-color .2s ease, border-color .2s ease; }
.nav.is-stuck, .nav:has(.nav-drop[open]), .nav:has(.nav-toggle:checked) {
  background: rgba(255,255,255,.92); backdrop-filter: blur(12px); border-bottom-color: var(--medium-grey);
}
/* Takes no space and never paints: it exists only so the observer has
   something at the top of the document to watch. */
.nav-sentinel { position: absolute; top: 0; left: 0; width: 1px; height: 1px; pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .nav { transition: none; } }
.nav-bar { display: flex; align-items: center; justify-content: space-between; min-height: 72px; gap: 32px; }
.nav-logo img { display: block; }
.nav-toggle, .nav-burger { display: none; }
.nav-menu { display: flex; align-items: center; justify-content: space-between; flex: 1; }
.nav-list { list-style: none; margin: 0; padding: 0; display: flex; gap: 8px; }
.nav-link { display: block; padding: 24px 14px; font-weight: 500; font-size: 15px; color: var(--black); cursor: pointer; list-style: none; }
.nav-link::-webkit-details-marker { display: none; }
.nav-link:hover { color: var(--blue); text-decoration: none; }
.nav-drop summary::after { content: ""; display: inline-block; width: 12px; height: 12px; margin-left: 6px; vertical-align: -1px; background: currentColor; mask: url(../brand/icons/chevron-down.svg) center/contain no-repeat; }
.nav-drop[open] summary::after { transform: rotate(180deg); }
.nav-panel { position: absolute; background: var(--white); border: 1px solid var(--medium-grey); border-radius: 8px; padding: 16px; display: flex; gap: 24px; box-shadow: 0 16px 40px rgba(9,28,69,.12); margin-top: -8px; }
.nav-group { min-width: 240px; }
.nav-group .eyebrow { padding: 8px 12px 0; margin-bottom: 4px; font-size: 12px; }
.nav-entry { display: block; padding: 10px 12px; border-radius: 6px; color: var(--black); }
.nav-entry:hover { background: var(--light-grey); text-decoration: none; }
.nav-entry span { display: block; font-size: 14px; color: var(--dark-grey); }
.nav-actions { display: flex; align-items: center; gap: 12px; }
.nav-actions .btn { padding: 10px 18px; font-size: 14px; }
.nav-actions .btn-text::after { display: none; }

@media (max-width: 960px) {
  .nav-burger { display: block; width: 44px; height: 44px; position: relative; cursor: pointer; }
  .nav-burger span, .nav-burger span::before, .nav-burger span::after { content: ""; position: absolute; left: 10px; width: 24px; height: 2px; background: var(--black); transition: .2s; }
  .nav-burger span { top: 21px; }
  .nav-burger span::before { top: -8px; left: 0; }
  .nav-burger span::after { top: 8px; left: 0; }
  .nav-toggle:checked ~ .nav-burger span { background: transparent; }
  .nav-toggle:checked ~ .nav-burger span::before { transform: translateY(8px) rotate(45deg); }
  .nav-toggle:checked ~ .nav-burger span::after { transform: translateY(-8px) rotate(-45deg); }
  .nav-menu { display: none; position: absolute; top: 100%; left: 0; right: 0; background: var(--white); border-bottom: 1px solid var(--medium-grey); flex-direction: column; align-items: stretch; padding: 8px 24px 24px; max-height: calc(100vh - 72px); overflow: auto; }
  .nav-toggle:checked ~ .nav-menu { display: flex; }
  .nav-list { flex-direction: column; gap: 0; }
  .nav-link { padding: 14px 0; border-bottom: 1px solid var(--light-grey); }
  .nav-panel { position: static; border: 0; box-shadow: none; padding: 0 0 8px; flex-direction: column; gap: 0; margin: 0; }
  .nav-actions { margin-top: 16px; justify-content: stretch; }
  .nav-actions .btn { flex: 1; justify-content: center; }
  .section { padding: 56px 0; }
  .hero { padding: 56px 0 40px; }
  main > .hero:first-child { padding-top: calc(56px + var(--nav-h)); }
}

/* ---- footer ---- */
.footer { background: var(--black); color: var(--medium-grey); padding: 64px 0 32px; font-size: 15px; }
.footer a { color: var(--medium-grey); }
.footer a:hover { color: var(--white); }
.footer ul { list-style: none; padding: 0; margin: 0; }
.footer li { margin-bottom: 8px; }
.footer-grid { display: grid; gap: 40px; grid-template-columns: 2fr repeat(4, 1fr); }
.footer-brand p { max-width: 28em; margin: 20px 0; }
.footer-social { display: flex; gap: 16px; }
.footer-head { font-weight: 800; color: var(--white); margin-bottom: 16px; }
.footer-legal { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 16px; margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--dark-grey); font-size: 13px; }
.footer-legal ul { display: flex; flex-wrap: wrap; gap: 16px; }
.footer-legal p { margin: 0; }
@media (max-width: 960px) { .footer-grid { grid-template-columns: 1fr 1fr; } .footer-brand { grid-column: 1 / -1; } }

/* ---- forms (partials/contact-form.njk, partials/data-form.njk) ---- */
.contact-form { max-width: 640px; }
.cf-form { display: block; }
.cf-grid, .cf-row { display: grid; gap: 16px; grid-template-columns: 1fr 1fr; }
.cf-field { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.cf-field.cf-half, .cf-row .cf-field { grid-column: auto; }
.cf-label { font-weight: 500; color: var(--black); font-size: 15px; }
.cf-required { color: var(--pink); margin-left: 2px; }
.cf-help { font-size: 13px; color: var(--dark-grey); }
.cf-form input[type="text"], .cf-form input[type="email"], .cf-form input[type="tel"], .cf-form input[type="url"], .cf-form input[type="number"], .cf-form select, .cf-form textarea {
  font: inherit; font-size: 16px; color: var(--black); width: 100%; padding: 12px 14px; border: 1px solid var(--medium-grey); border-radius: var(--radius); background: var(--white);
}
.cf-form textarea { min-height: 120px; resize: vertical; }
.cf-form input:focus, .cf-form select:focus, .cf-form textarea:focus { outline: 2px solid var(--blue); outline-offset: 0; border-color: var(--blue); }
.cf-checkbox { display: flex; gap: 10px; align-items: center; font-weight: 300; cursor: pointer; }
.cf-checkbox input { width: 18px; height: 18px; accent-color: var(--blue); }
.cf-privacy, .cf-note { font-size: 13px; color: var(--dark-grey); }
.cf-submit { background: var(--blue); color: var(--white); border: 0; border-radius: var(--radius); padding: 13px 26px; font: 800 16px var(--font); cursor: pointer; }
.cf-submit:hover { background: var(--black); }
.cf-sent, .cf-note { display: none; }
.cf-done .cf-sent, .cf-handed-off .cf-note { display: block; color: var(--black); font-weight: 500; }
.cf-done .cf-submit { display: none; }
@media (max-width: 600px) { .cf-grid, .cf-row { grid-template-columns: 1fr; } }

/* media kit: white logo variants need a dark swatch behind them */
.logo-on-dark { background: #001c4a; padding: 1rem; border-radius: .5rem; }

/* Comparison tables (backblaze-comparison): logo headers and rating icons */
.compare-table { margin-bottom: 48px; }
.compare-table th img { height: 28px; width: auto; }
.compare-table td:first-child { font-weight: 800; color: var(--black); width: 18%; }
.compare-table .rating { width: 20px; height: 20px; vertical-align: -4px; }

/* figure captions under split images (performance charts) */
.split figure { margin: 0; }
.split figcaption { margin-top: 12px; font-size: 14px; color: var(--dark-grey); text-align: center; }
