/* Nimblist — shared marketing + editorial shell.
   ONE stylesheet imported by both Nimblist.Blog (Astro) and
   Nimblist.Frontend/public/guides, replacing brand.css tokens/chrome and
   guide.css entirely, so there is no second copy to drift. (The supplied file
   said this closes #1441 — that issue is already closed, and the guides already
   carry its corrected --muted. What's left is the structural duplication.) Fonts are self-hosted and declared below, so the static guides can drop
   their Google Fonts links entirely. */
/* Self-hosted faces. These live here rather than in the blog's bundled brand.css
   so the static guides — which cannot resolve @fontsource's bundler paths — get the
   same files from the same URLs. Served from Nimblist.Frontend/public/fonts, which
   is the same origin as /blog and /guides (both are baked into one nginx image). */
@font-face{font-family:"Noto Sans";font-style:normal;font-display:swap;font-weight:100 900;src:url(/fonts/noto-sans-latin-wght-normal.woff2) format("woff2-variations");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}
@font-face{font-family:"Geist";font-style:normal;font-display:swap;font-weight:100 900;src:url(/fonts/geist-latin-wght-normal.woff2) format("woff2-variations");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}
@font-face{font-family:"Geist Mono";font-style:normal;font-display:swap;font-weight:100 900;src:url(/fonts/geist-mono-latin-wght-normal.woff2) format("woff2-variations");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{
--bg:#FAF9F6;--surface:#FFFFFF;--ink:#1D274B;--ink-2:#474F6B;--hairline:#E8E6E0;--hairline-2:#F0EEE8;
--accent:#6B8A5C;--accent-soft:#EEF2EA;--accent-ink:#3D5232;
--marketing:#EA5627;--marketing-ink:#C8410F;--marketing-gold:#EEC859;--founders-bg:#E7E8EF;
/* R8's --muted (#8C8A82) measures 3.28:1 on cream and every use here is small
   text. Same warm grey darkened to 5.0:1 — the value brand.css and guide.css
   had both already deviated to, now agreed in one place. */
--muted:#6E6C64;
--font-display:"Noto Sans",-apple-system,system-ui,sans-serif;--font-sans:"Geist","Noto Sans",-apple-system,system-ui,sans-serif;--font-mono:"Geist Mono",ui-monospace,monospace;
--text-display:80px;--text-headline:64px;--text-title-lg:38px;--text-title-md:22px;--text-lead:17px;--text-copy:15px;--text-read:17px;
--radius-sm:6px;--radius-md:10px;--radius-lg:14px;--radius-pill:9999px;
--gutter:clamp(20px,4vw,72px);--maxw:1460px;--read:720px;
--cat-produce:#84A06A;--cat-dairy:#E8D9A8;--cat-bakery:#D7B084;--cat-meat:#C28B82;--cat-pantry:#B8A98A;--cat-frozen:#A6BFC7;--cat-drinks:#8AA3BE;--cat-household:#C8C2BA;
}
*,*::before,*::after{box-sizing:border-box}
*{margin:0;padding:0}
html{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-text-size-adjust:100%}
body{background:var(--surface);color:var(--ink);font-family:var(--font-sans);font-size:var(--text-copy);line-height:1.6;text-wrap:pretty}
img,svg{display:block;max-width:100%}
a{color:var(--ink);text-decoration:none}
a:hover{color:var(--marketing-ink)}
:focus-visible{outline:2px solid var(--marketing-ink);outline-offset:2px;border-radius:2px}
.wrap{max-width:var(--maxw);margin:0 auto;padding-inline:var(--gutter)}
.read{max-width:var(--read);margin:0 auto}
.display{font-family:var(--font-display);font-weight:300;letter-spacing:-.02em;line-height:1.06}
.eyebrow{font-family:var(--font-mono);font-size:11px;font-weight:500;letter-spacing:.8px;text-transform:uppercase;color:var(--muted)}
.mk{color:var(--marketing)}
.skip-link{position:absolute;left:-9999px;top:0;background:var(--ink);color:#fff;padding:10px 16px;border-radius:var(--radius-md);font-size:14px}
.skip-link:focus{left:8px;top:8px;z-index:20}
/* buttons */
.btn,.cta{text-decoration:none;display:inline-flex;align-items:center;gap:8px;white-space:nowrap;border:1px solid transparent;border-radius:var(--radius-pill);font-family:var(--font-sans);font-weight:500;letter-spacing:-.1px;cursor:pointer;transition:background-color .18s,color .18s}
/* .cta is the legacy class the guides markup and blog.spec.ts both use
   (`.cta-card .cta`). Aliased rather than renamed so the e2e suite keeps
   working as regression cover through the migration. */
.btn-mk,.cta{background:var(--marketing);color:#fff;padding:11px 22px;font-size:15px}
.btn-mk:hover,.cta:hover{background:var(--marketing-ink);color:#fff}
.btn-sm{padding:7px 16px;font-size:13px}
.btn-white{background:#fff;color:var(--ink);padding:11px 22px;font-size:15px}
.btn-white:hover{background:var(--bg);color:var(--ink)}
.btn-ghost{border-color:var(--hairline);color:var(--ink);padding:10px 20px;font-size:14px;background:transparent}
.btn-ghost:hover{background:var(--hairline-2);color:var(--ink)}
.chip-premium{display:inline-flex;align-items:center;background:var(--accent-soft);color:var(--accent-ink);font-family:var(--font-mono);font-size:10px;letter-spacing:.8px;text-transform:uppercase;padding:3px 9px;border-radius:var(--radius-pill);vertical-align:2px}
.readmore{font-size:14px;text-decoration:underline;text-underline-offset:3px;color:var(--ink)}
.readmore:hover{color:var(--marketing-ink)}
/* utility bar + header — identical to the marketing pages */
.utility{background:var(--bg);border-bottom:1px solid var(--hairline-2)}
.utility .wrap{display:flex;align-items:center;gap:clamp(24px,6vw,110px);padding-block:14px}
.badges{display:flex;gap:10px}
.badges img{height:34px;width:auto}
.util-links{display:flex;flex-wrap:wrap;gap:26px;font-size:13px}
.util-links a{text-decoration:underline;text-underline-offset:3px}
header{position:relative}
header .wrap{display:flex;align-items:center;justify-content:space-between;gap:32px;padding-block:26px}
.lockup{display:flex;align-items:center}
.lockup .word{height:62px;width:auto}
nav.desk{display:flex;align-items:center;gap:clamp(20px,3vw,44px)}
nav.desk a{font-family:var(--font-display);font-weight:400;font-size:19px}
nav.desk a[aria-current=page]{color:var(--marketing-ink)}
.hdr-cta{display:flex;align-items:center;gap:12px}
/* Mobile nav disclosure. The blog and the guides ship ZERO JavaScript — the
   blog's verify-build.mjs fails the build on any executable <script>, and the
   guides are plain files with no bundler — so this is a <details> element,
   which opens without script. Without it the narrow-width rules below would
   hide nav.desk and .hdr-cta and leave nothing in their place, so the whole
   nav would simply vanish on a phone.
   
   Everything here mirrors MarketingHeader.tsx: the same 26px three-line icon
   that becomes an X when open, and a full-width panel under the header rather
   than a floating card. The one difference is that this panel overlays the
   page instead of pushing it down — a <details> panel lives inside the
   details element, which sits in the header's flex row, so it cannot be in
   normal flow without breaking that row. */
.menu{display:none}
.menu>summary.burger{display:block;list-style:none;padding:8px;margin-right:-8px;color:var(--ink);cursor:pointer}
.menu>summary.burger:hover{color:var(--marketing-ink)}
.menu>summary.burger::-webkit-details-marker{display:none}
.menu .icon-close{display:none}
.menu[open] .icon-burger{display:none}
.menu[open] .icon-close{display:block}
.menu-panel{position:absolute;left:0;right:0;top:100%;z-index:30;display:flex;flex-direction:column;gap:4px;background:var(--surface);border-top:1px solid var(--hairline);padding:16px var(--gutter)}
.menu-panel a:not(.btn){font-family:var(--font-sans);font-size:var(--text-copy);padding-block:10px}
.menu-panel a:not(.btn):hover{color:var(--marketing)}
.menu-panel a[aria-current=page]{color:var(--marketing-ink)}
.menu-panel .btn{justify-content:center;margin-top:8px;padding-block:10px}
/* editorial hero band — the marketing navy hero, shorter, with an illustration */
.ed-hero{background:var(--ink);color:#fff;padding:56px 76px 60px;overflow:hidden}
.ed-hero .eyebrow{color:rgba(255,255,255,.62);margin-bottom:18px}
.ed-hero h1{color:#fff;font-size:var(--text-headline);max-width:20ch}
.ed-hero .lede{color:rgba(255,255,255,.76);font-size:var(--text-lead);max-width:56ch;margin-top:22px}
.ed-hero .hero-cta{margin-top:32px}
.ed-hero--article h1{font-size:var(--text-title-lg);max-width:26ch;line-height:1.1}
/* :not(.btn) — an unscoped rule here outranks .btn-white and turns the hero
   button into white-on-white. */
.ed-hero a:not(.btn){color:#fff}
.ed-hero a:not(.btn):hover{color:var(--marketing-gold)}
/* byline */
.byline{display:flex;flex-wrap:wrap;align-items:center;gap:12px;font-family:var(--font-mono);font-size:12px;color:rgba(255,255,255,.62);margin-top:30px}
.byline .who{color:#fff}
.avatar{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:50%;background:rgba(255,255,255,.14);color:#fff;font-family:var(--font-mono);font-size:11px;line-height:1;flex:none}
.author-card{display:flex;align-items:flex-start;gap:16px;background:var(--bg);border:1px solid var(--hairline);border-radius:var(--radius-lg);padding:22px 24px;margin:36px 0}
.author-card .avatar{background:var(--accent-soft);color:var(--accent-ink);width:52px;height:52px;font-size:17px}
.author-card .who{font-family:var(--font-sans);font-weight:600;font-size:15px;color:var(--ink)}
.author-card p{color:var(--ink-2);font-size:14px;margin-top:6px}
/* bands */
.band{padding-block:88px}
.band-tight{padding-block:56px}
.band-bg{background:var(--bg)}
.band-head{display:flex;align-items:flex-end;justify-content:space-between;gap:32px;flex-wrap:wrap;margin-bottom:40px}
.band-head h2{font-family:var(--font-display);font-weight:300;letter-spacing:-.02em;font-size:var(--text-title-lg);line-height:1.1}
.band-head .eyebrow{margin-bottom:12px}
.rowdiv{height:1px;background:var(--hairline)}
/* tag / topic pills — marketing pill silhouette, app tag palette as the dot.
   `.tag` and the colour-name modifiers (.tag--green etc, from tags.ts) are
   aliased so existing Astro templates and blog.spec.ts need no markup change. */
.pillrow,.tag-list{display:flex;flex-wrap:wrap;gap:10px;list-style:none}
.pill,.tag{display:inline-flex;align-items:center;gap:7px;white-space:nowrap;font-family:var(--font-mono);font-size:10px;letter-spacing:.5px;text-transform:uppercase;color:var(--ink-2);background:var(--surface);border:1px solid var(--hairline);border-radius:var(--radius-pill);padding:6px 13px;line-height:1}
.pill:hover,.tag:hover{color:var(--ink);border-color:var(--ink)}
.pill::before,.tag::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--dot,var(--marketing));flex:none}
.pill.is-on,.tag.is-on{background:var(--ink);border-color:var(--ink);color:#fff}
.pill--engineering,.tag--indigo{--dot:var(--ink)}
.pill--shopping-lists,.tag--green{--dot:var(--cat-produce)}
.pill--recipes,.tag--orange{--dot:var(--cat-bakery)}
.pill--pantry,.tag--pink{--dot:var(--cat-pantry)}
.pill--integrations,.tag--blue{--dot:var(--cat-drinks)}
.pill--product,.tag--teal{--dot:var(--cat-frozen)}
.tag--red{--dot:#C77349}
.tag--yellow{--dot:var(--cat-dairy)}
.tag--purple{--dot:var(--cat-meat)}
.tag--gray{--dot:var(--cat-household)}
.pill.is-on::before,.tag.is-on::before{background:#fff}
/* tag index page — carried over from brand.css, restyled on the new tokens */
.tag-index{list-style:none}
.tag-index li{padding-block:24px;border-bottom:1px solid var(--hairline)}
.tag-index li:last-child{border-bottom:0}
.tag-index p{font-size:15px;color:var(--ink-2);margin-top:8px}
.tag-index-count{margin-left:10px;font-family:var(--font-mono);font-size:11px;color:var(--muted)}
.index-meta{margin-bottom:28px}
.draft-flag{display:inline-block;font-family:var(--font-mono);font-size:11px;text-transform:uppercase;letter-spacing:.8px;color:#9C5433;border:1px solid #C77349;border-radius:var(--radius-sm);padding:1px 6px;margin-left:8px}
/* featured entry */
.feature-post{display:grid;grid-template-columns:1fr 1fr;gap:clamp(32px,5vw,72px);align-items:center}
.feature-post .slot{border:1px solid var(--hairline);border-radius:26px;overflow:hidden;background:var(--bg);box-shadow:0 12px 32px rgba(20,20,20,.08),0 2px 6px rgba(20,20,20,.04)}
.feature-post .slot img{width:100%;aspect-ratio:16/11;object-fit:cover;object-position:top}
/* line-art illustration beside a cream cross-sell band. Its own class, not
   .slot — the slot rule crops 16/11 for landscape screenshots and would slice
   a portrait drawing. */
.band-illo{display:flex;align-items:center;justify-content:flex-end;height:288px}
.band-illo img{height:100%;width:auto;object-fit:contain}
.feature-post h3{font-family:var(--font-display);font-weight:300;letter-spacing:-.02em;font-size:var(--text-title-lg);line-height:1.08;margin:16px 0 14px}
.feature-post p{color:var(--ink-2);font-size:var(--text-lead);max-width:44ch;margin-bottom:20px}
/* article cards — the landing page's .card silhouette (290px slot, 6px radius,
   Geist 600 title, Read More). `.post-list` is the legacy grid class blog.spec.ts
   asserts `.post-list h2 a` against, so entry titles are h2. */
.cardgrid,.post-list{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:26px;list-style:none}
.cardgrid.two,.post-list.two{grid-template-columns:repeat(2,minmax(0,1fr))}
.card,.post-list>li{display:flex;flex-direction:column}
.card .slot{height:290px;border-radius:6px;overflow:hidden;background:var(--bg);margin-bottom:18px}
.card .slot img{width:100%;height:100%;object-fit:cover;object-position:top}
.card h2,.card h3{font-family:var(--font-sans);font-size:16px;font-weight:600;letter-spacing:-.2px;line-height:1.3;margin-bottom:8px}
.card h2 a:hover,.card h3 a:hover{color:var(--marketing-ink)}
.card p{font-size:14px;color:var(--ink-2);margin-bottom:14px}
.card .readmore{margin-top:auto;align-self:flex-start}
/* guide entries — the landing's fcell rhythm, no imagery */
.guidegrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0}
.gcell{display:grid;grid-template-columns:auto 1fr;gap:20px;padding:32px 44px 32px 0;border-bottom:1px solid var(--hairline)}
.gcell:nth-child(even){padding-right:0;padding-left:44px;border-left:1px solid var(--hairline)}
.gcell .num{font-family:var(--font-mono);font-size:11px;color:var(--muted);padding-top:5px}
.gcell h3{font-family:var(--font-sans);font-size:18px;font-weight:600;letter-spacing:-.2px;line-height:1.3;margin-bottom:7px}
.gcell h3 a:hover{color:var(--marketing-ink)}
.gcell p{font-size:14px;color:var(--ink-2)}
/* prose — 720px reading column */
.prose{color:var(--ink-2);font-size:var(--text-read);line-height:1.68}
.prose>p,.prose li{color:var(--ink-2)}
.prose>p{margin-bottom:20px}
.prose h2{font-family:var(--font-display);font-weight:300;letter-spacing:-.02em;color:var(--ink);font-size:var(--text-title-md);line-height:1.25;margin:44px 0 14px}
.prose h3{font-family:var(--font-sans);font-weight:600;font-size:17px;letter-spacing:-.2px;color:var(--ink);margin:32px 0 10px}
.prose a{color:var(--marketing-ink);text-decoration:underline;text-underline-offset:2px}
/* A button inside the reading column is still a button. The guides put their
   .cta-card inside the prose, so without this the pill renders underlined. */
.prose a.btn,.prose a.cta{color:#fff;text-decoration:none}
.prose a.btn:hover,.prose a.cta:hover{color:#fff}
.prose a:hover{color:var(--ink)}
.prose strong{color:var(--ink);font-weight:600}
.prose ul,.prose ol{padding-left:22px;margin-bottom:20px}
.prose li{margin-bottom:8px}
.prose blockquote{margin:28px 0;padding:2px 0 2px 20px;border-left:3px solid var(--marketing);font-style:italic}
.prose hr{border:0;border-top:1px solid var(--hairline);margin:44px 0}
.prose :not(pre)>code{font-family:var(--font-mono);font-size:.875em;background:var(--hairline-2);border:1px solid var(--hairline);border-radius:var(--radius-sm);padding:.1em .35em;color:var(--ink)}
.prose pre{font-family:var(--font-mono);font-size:14px;line-height:1.55;background:var(--bg);border:1px solid var(--hairline);border-radius:var(--radius-lg);padding:16px 18px;margin-bottom:24px;overflow-x:auto;-webkit-overflow-scrolling:touch;color:var(--ink)}
.prose pre code{background:none;border:0;padding:0;font-size:inherit}
.prose figure{margin:28px 0}
/* height:auto is load-bearing. Every <img> here carries width/height attributes
   so the box is reserved before the file loads, and a browser maps those to
   presentational width/height. A specified height makes aspect-ratio inert, so
   without this the .prose figure rule below silently does nothing and a tall
   portrait screenshot renders at 1520px, burying the first paragraph. */
.prose img{border-radius:var(--radius-lg);width:100%;height:auto}
/* Post heroes are tall portrait screenshots — at full width one is ~1400px and
   buries the first paragraph. Cropped 16/11 from the top, the same treatment
   brand.css's .post-thumb already applies for the same reason. */
.prose figure img{aspect-ratio:16/11;object-fit:cover;object-position:top}
.prose figcaption{font-family:var(--font-mono);font-size:12px;color:var(--muted);margin-top:10px}
.prose table{display:block;overflow-x:auto;width:max-content;min-width:100%;max-width:100%;border-collapse:collapse;font-size:15px;margin-bottom:24px}
.prose th,.prose td{border-bottom:1px solid var(--hairline);padding:10px 12px;text-align:left;vertical-align:top}
.prose th{font-weight:600;color:var(--ink);white-space:nowrap}
.article-body{padding-block:64px}
.article-lede{font-size:20px;color:var(--ink-2);margin-bottom:28px}
/* inline cta card */
.cta-card{background:var(--bg);border:1px solid var(--hairline);border-radius:var(--radius-lg);padding:26px 28px;margin:36px 0}
.cta-card strong{color:var(--ink)}
.cta-card p{color:var(--ink-2);margin-bottom:16px;font-size:var(--text-copy)}
.cta-card p:last-child{margin-bottom:0}
/* related */
.related{margin-top:56px;padding-top:32px;border-top:1px solid var(--hairline)}
.related .eyebrow{margin-bottom:20px}
.related-list{display:grid;gap:18px}
.related-list h2,.related-list h3{font-family:var(--font-sans);font-size:17px;font-weight:600;letter-spacing:-.2px;margin-bottom:4px}
.related-list h2 a:hover,.related-list h3 a:hover{color:var(--marketing-ink)}
.related-list p{font-size:14px;color:var(--ink-2)}
/* footer — identical to the marketing pages */
footer{position:relative;overflow:hidden;padding:2vw 0 0;min-height:70vw}
.foot-bottom{position:relative}
.foot-main{display:flex;flex-direction:column;align-items:center;gap:11vw;position:relative;z-index:2}
.foot-lock{display:flex;align-items:center;justify-content:center}
.foot-lock .word{width:43vw;max-width:830px;height:auto}
.foot-links{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:22px}
.foot-links a.plain{font-size:15px}
.sausage{position:absolute;z-index:1;top:13.6vw;right:-8vw;width:46vw;max-width:900px;height:auto;pointer-events:none}
@media(max-width:1100px){
:root{--text-display:60px;--text-headline:46px;--text-title-lg:32px}
.ed-hero{padding:44px 44px 48px}
.band{padding-block:64px}
.cardgrid,.post-list{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:1000px){
nav.desk{gap:18px}
nav.desk a{font-size:17px}
header .wrap{gap:18px}
/* The lockup shrinks here rather than at the burger breakpoint. It is the widest
   thing in the header, and shrinking it is what lets the full nav survive down
   to 640px — which is where MarketingHeader.tsx switches, so the app and these
   pages now change shape at the same width. */
.lockup .word{height:42px}
.hdr-cta{gap:8px}
.btn-mk{padding:9px 16px;font-size:14px}
}
@media(max-width:820px){
:root{--text-display:46px;--text-headline:38px;--text-title-lg:28px;--text-title-md:20px;--text-read:16px}
.utility .wrap{gap:20px;flex-wrap:wrap}
.util-links{gap:16px;font-size:12px;order:2}
.ed-hero{padding:36px 24px 40px}
.ed-hero h1,.ed-hero .lede{max-width:none}
.feature-post{grid-template-columns:1fr;gap:24px}
.cardgrid,.cardgrid.two,.post-list,.post-list.two{grid-template-columns:1fr;gap:40px}
.card .slot{height:230px}
/* One column, so an empty slot buys no alignment — it is just a cream box. */
.card .slot:empty{display:none}
.guidegrid{grid-template-columns:1fr}
.gcell,.gcell:nth-child(even){padding:24px 0;border-left:0}
.article-body{padding-block:40px}
.article-lede{font-size:18px}
.band{padding-block:52px}
.band-head{margin-bottom:28px}
.foot-lock .word{width:66vw}
.foot-main{gap:16vw}
/* The artwork STOPS being absolutely positioned here. Its offsets resolve
   against .foot-bottom, which is only as tall as the lockup and the link row —
   so at phone widths any bleed large enough to read as artwork reaches back up
   through both, and the footer becomes one tangled drawing. In flow it sits
   below the links and bleeds off the right edge instead, which is the same
   intent with the geometry the narrow column can actually hold. */
.sausage{position:static;width:76vw;margin:36px -14vw 0 auto}
footer{min-height:0;padding-bottom:24px}
.foot-links{margin-top:52px}
}
@media(max-width:640px){
nav.desk,.hdr-cta{display:none}
.menu{display:block}
}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}}
