/* thesubtitledb.org/engineering */

/* The reference's faces, self-hosted and subset.

   engineering.atspotify.com serves SpotifyMix as ten static TTFs, each with an
   EOT sibling for a browser nobody has, and no subsetting: a reader downloads
   every accent in the font to read a post in English. The same files are here as
   woff2 split at latin and latin-ext, which is a fifth of the bytes.

   The weight numbers are the reference's own mapping, not the file names:
   Bold is 600 and Black is 800 in its stylesheet, so they are here too.

   SpotifyMix is Spotify's licensed typeface, not an open face. It is here
   because the licence is held; if that ever lapses, this file and the fourteen
   files it names are what has to go, and nothing else in the paint changes.

   unicode-range means latin-ext is fetched only by a post that uses it, and
   swap, so text is readable while a face is still in flight. */

@font-face {
  font-family: SpotifyMix;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-regular-latin.woff2?v=1yfy5ma) 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;
}

@font-face {
  font-family: SpotifyMix;
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-regular-latin-ext.woff2?v=1fvve6i) 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: SpotifyMix;
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-italic-latin.woff2?v=lpta47) 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;
}

@font-face {
  font-family: SpotifyMix;
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-italic-latin-ext.woff2?v=90x4bh) 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: SpotifyMix;
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-medium-latin.woff2?v=q2q1yl) 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;
}

@font-face {
  font-family: SpotifyMix;
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-medium-latin-ext.woff2?v=18mpvy3) 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: SpotifyMix;
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-bold-latin.woff2?v=z8hc60) 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;
}

@font-face {
  font-family: SpotifyMix;
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-bold-latin-ext.woff2?v=1y6ul99) 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: SpotifyMix;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-extrabold-latin.woff2?v=g2bhs3) 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;
}

@font-face {
  font-family: SpotifyMix;
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-extrabold-latin-ext.woff2?v=1hr4grn) 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: SpotifyMix;
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-black-latin.woff2?v=1o2ze1b) 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;
}

@font-face {
  font-family: SpotifyMix;
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-black-latin-ext.woff2?v=1lpxaqq) 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: SpotifyMix;
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-ultra-latin.woff2?v=1yqgp91) 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;
}

@font-face {
  font-family: SpotifyMix;
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url(/engineering/fonts/spotifymix-ultra-latin-ext.woff2?v=flk3ro) 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;
}


/* engineering.atspotify.com's stylesheet, as served on 2026-09-10 by
   engineering.atspotify.com/_next/static/chunks/0sxc27dsa.k6-.css.
   Vendored so the gaps, the radii, the sticky offsets and the type scale are the
   reference's own numbers and not an approximation of them.

   DO NOT EDIT. Re-fetch and re-run tools/vendor-css.mjs; the blog's own
   rules belong in blog.css, which is loaded after this.

   Changed on the way in: 251 rules for
   sections this blog does not have are dropped (jobs, about, podcasts, projects,
   the error pages, the carousel, the newsletter, the search box, the scripted
   mobile drawer); the 11 @font-face blocks are replaced by the same
   faces as woff2, subset by script, in fonts.css; and the three artwork files
   are ours. Nothing else. */
body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:SpotifyMix,Arial,Helvetica,sans-serif}
*{box-sizing:border-box;margin:0;padding:0}
a{color:inherit;text-decoration:none}
h1{color:#0d253f;font-size:100px;font-weight:600;line-height:80px}
@media (max-width:1024px){h1{font-size:48px!important;line-height:.8!important}}
h2{color:#0d253f;font-size:40px;line-height:46px;font-weight:600!important}
@media (max-width:1024px){h2{font-size:24px;line-height:30px}}
h3{color:#0d253f;font-size:32px;line-height:36px;font-weight:600!important}
@media (max-width:1024px){h3{font-size:20px;line-height:24px}}
h4{color:#0d253f;font-size:20px;font-weight:600!important}
@media (max-width:1024px){h4{font-size:18px;line-height:26px}}
*{box-sizing:border-box}
ul,li{margin:0;padding:0;list-style:none}
a{color:inherit;text-decoration:none;transition:all .35s}
img{vertical-align:top}
body{color:#121212;background:#f8f8f8;margin:0;padding:0;font-family:SpotifyMix;font-size:18px;line-height:1.5}
@media (max-width:1024px){body{font-size:16px;line-height:1.5}}
.clickable{cursor:pointer}
.show-on-mobile{display:none}
@media (max-width:991px){.show-on-mobile{display:block}}
.hide-on-mobile{display:block}
@media (max-width:991px){.hide-on-mobile{display:none}}
.container{width:100%;margin:auto;display:flex}
.header{color:#fff;z-index:100;background:linear-gradient(135deg,#0e7c86 0%,#0d253f 15%);border-radius:0 0 30px 30px;flex-direction:column;align-items:start;gap:0;max-width:1360px;margin:0 auto;padding:20px 60px;display:flex;position:sticky;top:0}
.header.transparent{background:0 0}
.header.blur{-webkit-backdrop-filter:blur(15px);backdrop-filter:blur(15px);background:#0d253f80}
.header .container{justify-content:space-between;align-items:center;gap:50px;display:flex}
.header .container .container-left{align-items:center;gap:48px;display:flex}
.header .container .container-right{justify-content:flex-end;align-items:center;gap:px;flex:1;display:flex}
@media (max-width:1024px){.header{background:linear-gradient(135deg,#0e7c86 0%,#0d253f 35%);border-radius:0 0 20px 20px;padding:16px 24px}.header .container .container-left img{width:auto;height:24px}}
.footer{color:#fff;background:#121212;padding:60px 80px 80px}
.footer .container{flex-direction:column;max-width:1360px}
.footer .links{justify-content:space-between;display:flex}
.footer .links__left{gap:80px;display:flex}
.footer .links__left .logo{margin-left:52px}
.footer .links__left .nav-wrapper .nav{gap:80px;display:flex}
.footer .links__left .nav-wrapper .nav ul{flex-direction:column;gap:16px;display:flex}
.footer .links__left .nav-wrapper .nav ul a{font-size:16px}
.footer .links__right .social{align-items:center;gap:24px;display:flex}
.footer .copy{justify-content:flex-end;gap:60px;margin-top:40px;font-size:12px;display:flex}
.footer .copy__nav ul{align-items:center;gap:16px;display:flex}
@media (max-width:1024px){.footer{padding:24px 16px}.footer .links{position:relative}.footer .links__left{flex-direction:column;gap:32px;width:100%}.footer .links__left .logo{margin-left:0}.footer .links__left .logo img{width:90px}.footer .links__left .nav-wrapper .nav{justify-content:space-between}.footer .links__right{position:absolute;top:0;right:0}.footer .links__right .social{gap:20px}.footer .links__right .social li a img{object-fit:contain;width:16px;height:16px}.footer .copy{justify-content:space-between;gap:16px}}
.header .nav ul{align-items:center;gap:26px;display:flex}
.header .nav ul li a{text-underline-offset:2px;font-size:18px;transition:all .35s}
.header .nav ul li a:hover,.header .nav ul li.active a{text-underline-offset:5px;text-decoration:underline;text-decoration-thickness:2px}
@media (max-width:1024px){.header .nav{z-index:-1;background:#0d253f url(/engineering/art/banner.svg) 50%/cover no-repeat;border-radius:0 0 20px 20px;width:100%;height:0;transition:all .35s;position:absolute;top:0;left:0;overflow:hidden}.header .nav ul{flex-direction:column;align-items:flex-start;gap:16px;margin-top:80px;padding-left:24px}.header .nav.open{height:100vh}}
.button{color:#fff;background:#0e7c86;border-radius:50px;padding:17px 50px;font-weight:500;line-height:100%;transition:all .35s;display:inline-block}
.button:hover{background:#0b666e}
.button:active{background:#08494f}
@media (max-width:1024px){.button{font-size:14px!important}}
.button--submit{padding:0 40px}
.banner{background:url(/engineering/art/banner.svg) top/cover no-repeat;border-radius:0 0 40px 40px;max-width:1360px;height:400px;margin:-76px auto 0;position:relative}
.banner .banner__content{align-items:end;gap:40px;margin-top:135px;padding:0 60px;display:flex;position:absolute}
.banner .banner__content h1{color:#fff;font-size:190px;font-weight:900;line-height:140px}
.banner .banner__content h4{color:#fff}
.banner.banner--inner{background:0 0;border-radius:0;max-width:1042px;height:auto;margin-top:0;padding:40px 0 80px}
.banner.banner--inner .banner__content{flex-direction:column;justify-content:center;align-items:start;gap:0;margin-top:0;padding:0;display:flex;position:relative}
.banner.banner--inner .banner__content h1{color:#0d253f;font-size:100px;font-weight:800}
.banner.banner--inner .banner__content h4{color:#0d253f;padding-left:200px}
@media (max-width:1024px){.banner{border-radius:0 0 20px 20px;height:auto;margin-top:-57px;padding-bottom:20px}.banner .banner__content{flex-direction:column;justify-content:center;align-items:center;gap:10px;margin-top:0;padding:16px 16px 8px;position:static}.banner .banner__content h1{margin-top:60px;font-size:72px!important;line-height:1!important}.banner .banner__content h4{text-align:center;font-size:16px;line-height:1.5;font-weight:500!important}.banner.banner--inner{padding:40px 16px}.banner.banner--inner .banner__content h1{margin-top:0;margin-bottom:16px;font-size:48px!important}.banner.banner--inner .banner__content h4{text-align:left;padding-left:0;font-size:18px;font-weight:600!important}}
.sticky-post{z-index:10;margin-top:-100px;margin-bottom:80px;position:relative;box-shadow:none!important;width:auto!important;overflow:visible!important}
.sticky-post .container{justify-content:center;max-width:1200px}
.sticky-post .sticky-post__image{z-index:1;border-radius:16px;width:675px;height:332px;overflow:hidden;box-shadow:1px 3px 30px #0000005e}
.sticky-post .sticky-post__image img{object-fit:cover;width:100%;height:100%}
.sticky-post .sticky-post__content{justify-content:center;gap:px;background-color:#fff;border-radius:16px;flex-direction:column;flex:1;margin-top:48px;margin-bottom:-30px;margin-left:-70px;padding:0 40px 0 100px;display:flex;box-shadow:1px 3px 63px #0000001a}
.sticky-post .sticky-post__content .sticky-post__date{color:#535353;text-transform:uppercase;margin-bottom:6px;font-size:10px;font-weight:500}
.sticky-post .sticky-post__content .sticky-post__title{color:#0d253f;margin-bottom:8px;font-weight:600}
.sticky-post .sticky-post__content .sticky-post__description{color:#333;margin-bottom:16px;font-size:16px}
.sticky-post .sticky-post__content .sticky-post__tags{flex-wrap:wrap;align-items:center;gap:12px;padding:8px 0 6px;display:flex}
@media (max-width:1024px){.sticky-post{background-color:#fff;border-radius:0 0 16px 16px;margin:24px;overflow:auto;box-shadow:1px 3px 63px #000}.sticky-post .container{flex-direction:column}.sticky-post .container .sticky-post__image{width:100%;height:auto;box-shadow:none!important}.sticky-post .container .sticky-post__content{background:#fff;border-radius:0 0 16px 16px;flex-direction:column;flex:1;justify-content:space-between;align-items:start;gap:0;margin:0;padding:20px;display:flex}}
.post-card{background-color:#fff;border-radius:16px;flex-direction:column;justify-content:start;align-items:start;gap:0;transition:all .25s;display:flex;box-shadow:0 2px 15px #00000029}
.post-card .post-card__image{aspect-ratio:1.904;background:#f8f8f8;border-radius:16px;width:100%}
.post-card .post-card__image img{aspect-ratio:1.904;object-fit:cover;border-radius:16px;width:100%;height:auto}
.post-card .post-card__content{background:#fff;border-radius:0 0 16px 16px;flex-direction:column;flex:1;justify-content:space-between;align-items:start;gap:0;padding:20px;display:flex}
.post-card .post-card__date{color:#535353;text-transform:uppercase;margin-bottom:6px;font-size:10px;font-weight:500}
.post-card .post-card__title{margin-bottom:8px;font-weight:600}
.post-card .post-card__description{color:#333;margin-bottom:16px;font-size:16px}
.post-card .post-card__tags{flex-wrap:wrap;align-items:center;gap:12px;padding:8px 0 6px;display:flex}
.post-card:hover{transform:scale(1.02)}
.post-card.related .post-card__image{aspect-ratio:1.904;background:#f8f8f8;border-radius:16px;width:300px}
.post-card.related .post-card__image img{aspect-ratio:1.904;object-fit:cover;border-radius:16px;width:100%;height:auto}
.post-card.related .post-card__title{margin-bottom:0;font-size:18px}
.post-card.related .post-card__date,.post-card.related .post-card__description,.post-card.related .post-card__tags{display:none}
.post-card.related:hover{transform:none}
.post-card.horizontal{width:auto;box-shadow:none;background:0 0;border-bottom:1px dashed #d6ecf2;border-radius:0;flex-direction:row;justify-content:start;align-items:center;gap:40px;padding-bottom:40px;display:flex}
.post-card.horizontal .post-card__image{aspect-ratio:1.904;width:300px;box-shadow:0 2px 15px #00000029}
.post-card.horizontal .post-card__image img{aspect-ratio:1.904;border-radius:16px;width:100%;height:auto}
.post-card.horizontal .post-card__content{background:0 0;border-radius:0;padding:0}
.post-card.horizontal .post-card__content .post-card__date{margin-bottom:16px}
.post-card.horizontal .post-card__content .post-card__title{margin-bottom:4px}
.post-card.horizontal .post-card__content .post-card__description{font-size:18px}
.post-card.horizontal .post-card__content .post-card__tags{display:none}
.post-card.horizontal .post-card__content .post-card__published{font-size:12px}
.post-card.horizontal:hover{transform:none}
@media (max-width:1024px){.post-card .post-card__content .post-card__published{display:none}}
.tag{color:#35B7AB;text-transform:uppercase;letter-spacing:1px;font-size:10px;font-weight:500}
.tag:hover{text-decoration:underline}
.tag:active{color:#12688C;text-decoration:underline}
.tag.fill{color:#12688C;letter-spacing:1px;background:#d6ecf2;padding:4px}
.tag.fill:active,.tag.active{color:#d6ecf2;background:#12688C;text-decoration:none}
.filters{z-index:50;background:#f8f8f8bf;width:calc(100% + 50px);position:sticky;top:76px}
@media (max-width:991px){.filters{width:100%;margin:auto}}
.filters{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);margin-left:-25px;padding:20px 25px}
.filters button,.filters summary{width:280px}
@media (max-width:991px){.filters button,.filters summary{width:100%}}
.filters button,.filters summary{color:#0d253f;z-index:2;background:#fff;border:1px solid #b3b3b3;border-radius:50px;justify-content:space-between;align-items:center;height:50px;padding:9px 23px;font-size:18px;display:flex;position:relative}
.filters button:after,.filters summary:after{content:"";background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE4IDE2IiBmaWxsPSJub25lIj48cGF0aCBkPSJNMiA1TDkgMTJMMTYgNSIgc3Ryb2tlPSIjMUI3RkE1IiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvc3ZnPg==) no-repeat;width:18px;height:16px;transition:all .35s;display:inline-block}
.filters button.open:after,.filters details[open]>summary:after{transform:rotate(180deg)}
.dropdown-menu{z-index:1;background:#fff;border-radius:24px;width:280px;min-width:150px;max-height:500px;padding:36px 0 24px;position:absolute;top:40px;left:25px;overflow:auto;box-shadow:5px 5px 10px #0000001a}
@media (max-width:991px){.dropdown-menu{width:calc(100% - 50px);max-height:60vh}}
.dropdown-menu ul li a{color:#0d253f;padding:10px 15px;font-size:18px;display:block}
.dropdown-menu ul li a:hover{background:#d6ecf233}
.sidebar{flex-direction:column;align-self:flex-start;align-items:flex-start;gap:24px;width:298px;display:flex;position:sticky;top:100px}
.sidebar .date,.sidebar .published{color:#121212;font-size:16px;position:relative}
.sidebar .date:before,.sidebar .published:before{content:"";background:#35B7AB;width:2px;height:24px;display:inline-block;position:absolute;left:-16px}
.sidebar .tag-wrapper{flex-wrap:wrap;align-items:center;gap:16px;display:flex}
@media (max-width:1024px){.sidebar{gap:8px;width:auto}.sidebar .date,.sidebar .published{font-size:14px}.sidebar .date:before,.sidebar .published:before{height:16px;top:2px}}
.related-posts{background-color:#d6ecf2;border-radius:40px 40px 0 0;padding:80px 0 120px}
.related-posts .container{max-width:1270px}
.related-posts .container h3{color:#0d253f;margin-bottom:24px}
.related-posts .container .cards{align-items:stretch;gap:24px;display:flex}
.related-posts .container .cards .post-card{flex:1;width:auto}
@media (max-width:1024px){.related-posts{border-radius:20px 20px 0 0;margin-top:40px;padding:40px 0 70px}.related-posts .container{overflow:auto}.related-posts .container h3{margin-left:16px}.related-posts .container .cards{padding:0 16px 30px}}
.social{margin-top:16px}
.social p{text-transform:uppercase;color:#7f7f7f;font-size:10px}
.social__links{align-items:center;gap:4px;margin-top:16px;list-style:none;display:flex}
.social__links li{list-style:none}
.social__links a{cursor:pointer;border-radius:50px;padding:10px}
.social__links a:hover{background:#d6ecf2}
.posts-wrapper{max-width:1280px;height:100%;margin:0 auto 80px}
.posts-wrapper .filters{margin-bottom:40px}
.posts-wrapper .posts{flex-wrap:wrap;align-items:stretch;gap:40px;display:flex}
.posts-wrapper .posts .post-card{width:calc(33.3333% - 27px)}
.posts-wrapper .posts .post-card .image-link{width:100%}
.posts-wrapper .load-more{justify-content:center;align-items:center;gap:8px;margin-top:80px;display:flex}
.posts-wrapper .load-more .btn-load-more{cursor:pointer;background-color:inherit;color:#0d253f;border:0;justify-content:center;align-items:center;gap:8px;padding:8px 16px;font-size:16px;text-decoration:underline;display:flex}
.posts-wrapper .load-more .btn-load-more:after{content:"";background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE4IDE2IiBmaWxsPSJub25lIj48cGF0aCBkPSJNMiA1TDkgMTJMMTYgNSIgc3Ryb2tlPSIjMGQyNTNmIiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvc3ZnPg==) no-repeat;width:18px;height:16px;display:inline-block}
@media (max-width:767px){.posts-wrapper{padding:16px 24px}.posts-wrapper .filters{display:none}.posts-wrapper .posts .post-card,.posts-wrapper .posts .post-card .image-link{width:100%}}
.single-post{word-break:break-word;padding:62px 0 140px}
.single-post .container{gap:70px;max-width:1140px;transform:translate(70px)}
.single-post .single-post__title{color:#0d253f;max-width:75%;margin-bottom:40px;font-size:40px;line-height:1.2}
.single-post .single-post__content{flex-direction:column;flex:1;gap:16px;max-width:800px;display:flex}
.single-post .single-post__content .single-post__featured-image{margin-bottom:20px}
.single-post .single-post__content .single-post__featured-image img{border-radius:16px;width:100%;height:auto}
.single-post .single-post__content .social{display:none}
.single-post .single-post__content .html-content{flex-direction:column;gap:12px;display:flex}
.single-post .single-post__content .html-content h2{font-size:32px;line-height:1.3}
.single-post .single-post__content .html-content h3{font-size:24px;line-height:1.3}
.single-post .single-post__content .html-content h4{margin-top:16px;font-size:20px;line-height:1.3}
.single-post .single-post__content .html-content h3:first-child,.single-post .single-post__content .html-content h2:first-child{margin-top:0}
.single-post .single-post__content .html-content h6{color:#0d253f;border:4px solid #d6ecf2;border-width:4px 0;max-width:600px;margin:20px auto;padding:20px 0;font-size:20px;font-weight:600;line-height:1.4}
.single-post .single-post__content .html-content .image-paragraph{text-align:center;white-space:normal}
.single-post .single-post__content .html-content .inline-image-paragraph{white-space:normal}
.single-post .single-post__content .html-content pre{white-space:pre-wrap;color:#fff;background:#000;width:100%;max-width:100%;padding:16px 24px;display:block;overflow-x:auto}
.single-post .single-post__content .html-content p{white-space:pre-wrap}
.single-post .single-post__content .html-content p code{color:#fff;background-color:#000;padding:5px;display:inline-block}
.single-post .single-post__content .html-content .super-script{font-size:13px}
.single-post .single-post__content .caption{color:gray;text-align:center;margin:14px 0;font-size:14px;font-style:italic;font-weight:500}
.single-post .single-post__content .figure-image{flex-direction:column;align-items:center;margin:20px 0;display:flex}
.single-post .single-post__content .figure-image+h3{margin-top:4px}
.single-post .single-post__content .figure-video{flex-direction:column;align-items:center;max-width:100%;display:flex}
.single-post .single-post__content .figure-video video{width:100%;height:auto}
.single-post .single-post__content .figure-audio{flex-direction:column;align-items:center;max-width:100%;padding:18px 40px;display:flex}
.single-post .single-post__content .figure-audio audio{width:100%}
.single-post .single-post__content .inline-image{max-width:100%;display:inline-block}
.single-post .single-post__content .inline-image-link{display:inline-flex}
.single-post .single-post__content .post-tag{text-transform:none;margin-right:4px;font-size:16px}
.single-post .single-post__content a{color:#12688C;text-decoration:underline}
.single-post .single-post__content iframe{max-width:100%}
.single-post .single-post__content table{border-collapse:collapse;text-align:left;word-break:normal;width:100%}
.single-post .single-post__content table p{text-align:left}
.single-post .single-post__content table th{text-align:center;border:1px solid #000;border-bottom-width:3px;padding:9px}
.single-post .single-post__content table td{vertical-align:top;text-align:left;border:1px solid #000;padding:9px}
.single-post .single-post__content table td p{text-align:left}
.single-post .single-post__content .table-container,.single-post .single-post__content .image-table-container{max-width:100%;overflow-x:auto}
.single-post .single-post__content .image-table{table-layout:fixed;border:0}
.single-post .single-post__content .image-table td{vertical-align:top;border:0}
@media (max-width:991px){.single-post .single-post__content .image-table tr{flex-direction:column;justify-content:center;align-items:center;gap:24px;display:flex}.single-post .single-post__content .image-table tr td{padding:0}.single-post .single-post__content .image-table tr td .image-paragraph .inline-image{width:100%!important}.single-post .single-post__content .image-table tr td .caption p{text-align:center}}
.single-post .single-post__content hr{background:#a8d8e2;border:0;height:1px;margin-top:24px;margin-bottom:8px}
.single-post .single-post__content ol{flex-direction:column;padding-left:40px;display:flex}
.single-post .single-post__content ol li{margin-bottom:12px;list-style:decimal}
.single-post .single-post__content ol ol li{list-style:upper-alpha}
.single-post .single-post__content ol ol ol li{list-style:lower-roman}
.single-post .single-post__content ol ol ol ol li{list-style:lower-alpha}
.single-post .single-post__content ul{padding-left:40px}
.single-post .single-post__content ul li{margin-bottom:12px;list-style:outside}
.single-post .single-post__content ul li:last-child{margin-bottom:0}
.single-post .single-post__content ul li p{margin-bottom:12px}
.single-post .single-post__content ul li p:last-child{margin-bottom:0}
.single-post .single-post__content ul ul li{list-style:circle}
.single-post .single-post__content ul ul ul li{list-style:square}
.single-post .single-post__content blockquote{border-left:4px solid #d6ecf2;flex-direction:column;gap:18px;margin:24px 18px;padding-left:30px;display:flex}
.single-post .single-post__content blockquote p{margin:0}
.single-post .single-post__content h3{color:#0d253f;margin-top:24px}
.single-post .single-post__content h3 b{font-weight:600}
.single-post .single-post__content h2{margin-top:24px}
.single-post .single-post__content h2 b{font-weight:600}
@media (max-width:1024px){.single-post{padding:0}.single-post .container{flex-direction:column-reverse;gap:30px;padding:8px 16px;transform:none}.single-post .container .sidebar{padding-left:16px;position:static}.single-post .single-post__title{max-width:none;margin-top:32px;margin-bottom:8px;font-size:32px!important;line-height:1.2!important}.single-post .single-post__content{max-width:none}.single-post aside .social{display:none}.single-post .single-post__content .single-post__featured-image{margin-bottom:0}.single-post .single-post__content .single-post__featured-image img{width:100%;height:auto}.single-post .single-post__content .social{display:block}.single-post .single-post__content .social li{margin:0;list-style:none}.single-post .single-post__content .social ul{padding:0}}
@keyframes slide{0%{transform:translateY(0)}to{transform:translateY(-100%)}}
@keyframes slide-hr{0%{transform:translate(0)}to{transform:translate(-100%)}}


/* The blog's own rules, on top of the vendored sheet.

   Small on purpose. Every gap, radius, sticky offset and type size comes from
   vendor/spotify-theme.css and the pages use its class names; what is here is
   only what the reference gets from somewhere this blog does not go.

   Five of those. Its logo is a PNG, and ours is the mascot drawn inline. Its
   card covers are photographs from a CMS, and a post without one here gets
   generated key art, which is an <svg> where the sheet styles an <img>. Its
   filter is a button a script opens, and this is a <details>, which needs the
   two rules a <summary> takes to stop being a disclosure triangle. Its footer
   columns are unheaded, and half of these links leave the blog. And its banner
   title is sized for a six-letter word. */

/* -------------------------------------------------------------- the mark */

.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}

.brand__mark {
  flex: 0 0 auto;
  color: currentColor;
}

.brand__name {
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.4px;
  white-space: nowrap;
}

.footer .brand__name {
  color: #fff;
}

/* The mark is an inline-flex inside an anchor, so it sits on a baseline and the
   line box adds descender space under it: 36px of mascot in a 43px box, and a
   header 83px tall instead of 76. Seven pixels does not sound like much, but the
   sheet pulls the banner up by exactly 76 and sticks the sort bar at exactly 76,
   so both of them were out by the same seven: a strip of page showing above the
   banner, and a sort bar tucking under the header rather than against it. */
.header .logo {
  display: flex;
  align-items: center;
}

/* -------------------------------------------------------------- the footer */

/* The sheet's two footer columns carry no headings, which reads fine when every
   link in them goes to the same place. Half of these leave the blog for the
   site, so each column says which it is. The sheet's row is `.nav` and its
   column is `.nav ul`; the heading sits in a div between them so both of those
   rules still land. */
.footer .nav-wrapper .nav .footer__col {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* h2 is the sheet's 40px article heading in #0d253f: a headline on a white page,
   and all but invisible on the footer's #121212. This is a label. */
.footer__heading {
  color: #fff;
  font-size: 12px;
  line-height: 16px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  opacity: 0.55;
}

/* ------------------------------------------------------------- the header */

.header .container-right .feed-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding-left: 24px;
  border-left: 1px solid #fff;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
}

.icon {
  display: inline-block;
  vertical-align: middle;
  fill: currentColor;
}

/* The header is sticky and transparent over the banner, so on a page with no
   banner it needs its own ground. The reference's own rule is its brand violet
   on the diagonal; this is the same rule on the same two stops of the artwork's
   gradient, so an article's header and the front page's banner are one surface
   rather than two. */
.header:not(.transparent) {
  background: linear-gradient(135deg, #12688C 0%, #0d253f 15%);
}

/* ---------------------------------------------------------------- the hero */

/* The reference sets the banner title at 190px/140px, which is sized for a
   six-letter word. "TSDB Engineering" is sixteen, and at that size it runs off
   the banner twice over and leaves the mascot nowhere to stand. */
.banner .banner__content h1 {
  font-size: 82px;
  line-height: 78px;
}

/* The hero, cut down to what is in it.
 *
 * The reference's 400px band is sized for a headline, a standfirst and a hoisted
 * post card. This one holds a name and a mascot, so at 400 it was 187px of empty
 * artwork above the text and 125 below: the reader scrolled a third of a screen
 * of gradient to reach the first card. 244 is the bar's own 76 plus a 42 gutter,
 * the 78px line box, and 48 under it, which leaves the band reading as a header
 * rather than as a cover.
 *
 * Both numbers move together and neither can be nudged alone: the band is pulled
 * up under the sticky bar by exactly its height, so the gutter above the text is
 * margin-top minus 76, not margin-top.
 *
 * Above 1024 only. Below it the row is in flow and the sheet zeroes this margin,
 * which at equal specificity this would win, collapse out of the banner and push
 * the whole hero down the page. */
@media (min-width: 1025px) {
  .banner {
    height: 244px;
  }

  .banner .banner__content {
    margin-top: 118px;
  }
}

/* banner__content is an absolute flex row aligned to `end`, so the taller child
   sets the row height and, with it, whether the row clears the cards below. The
   mascot is capped under the title's line box so the title always sets it. */
.banner .banner__content .banner__mascot {
  flex: 0 0 auto;
  width: auto;
  height: 78px;
  margin-bottom: -2px;
}

/* Below 1024 the sheet stacks the row into a centred column, so the mascot
   drops under the title: there is no room beside a title that already wraps to
   two lines on a phone. Start, not centre, because the title is left aligned and
   a robot centred under it reads as an accident rather than as a pair.

   The 60px the sheet puts over the title stays. It looks like the desktop's
   slack gutter and is not: down here the band is in flow and pulled up 57 under
   a 68px sticky bar, so that 60 is what keeps the first line out from under it.
   Trimmed to 24 the title's first line measured 17px up inside the bar. */
@media (max-width: 1024px) {
  .banner .banner__content {
    align-items: start;
  }

  .banner .banner__content .banner__mascot {
    height: 72px;
    margin-bottom: 0;
  }
}

/* ------------------------------------------------------------ SubBot idles
 *
 * Deliberately a low frame rate, and that is the whole point of it: something
 * moving smoothly in the corner of a page of prose pulls the eye back every
 * time. Both animations run on `steps()`, so he moves the way he is drawn --
 * a few discrete positions, no in-between frames -- and the movement reads as
 * a sprite rather than as an ad.
 *
 * Two things happen. He rocks a pixel and a half, four steps out and four back
 * over ten seconds, which is slow enough that a reader has to look for it. And
 * roughly every seven seconds he blinks, for about a fifth of a second: the two
 * eye groups are the same cells drawn open and shut, so the swap is exact at any
 * size. `alternate` on the rock means the two never phase-lock into a pattern.
 *
 * Transform on the <svg>, not on a group inside it, so it costs a composite and
 * never a repaint of the sprite. */
@keyframes sb-rock {
  from { transform: translateY(0) }
  to { transform: translateY(-3px) }
}

/* Shut is 94% to 97% of the cycle. The step function makes each keyframe a
   hard cut, so there is no fade through a half-open eye. */
@keyframes sb-open {
  0%, 94% { opacity: 1 }
  94.001%, 97% { opacity: 0 }
  97.001%, 100% { opacity: 1 }
}

@keyframes sb-shut {
  0%, 94% { opacity: 0 }
  94.001%, 97% { opacity: 1 }
  97.001%, 100% { opacity: 0 }
}

.banner__mascot .sb-shut { opacity: 0 }

@media (prefers-reduced-motion: no-preference) {
  .banner__mascot {
    animation: sb-rock 10s steps(4, jump-none) infinite alternate;
    will-change: transform;
  }

  .banner__mascot .sb-open {
    animation: sb-open 7s steps(1, end) infinite;
  }

  .banner__mascot .sb-shut {
    animation: sb-shut 7s steps(1, end) infinite;
  }
}

/* The sheet steps the title to 72px below 1024, which is sized for a six-letter
   word: "Engineering" is 439px wide at that size and runs off a phone. The
   !important is the reference's own, so beating it needs one. */
@media (max-width: 520px) {
  .banner .banner__content h1 {
    font-size: 52px !important;
  }
}

/* --------------------------------------------------------------- key art */

/* Where the sheet says `img`, a post without a cover has an `svg`. Same box. */
.post-card .post-card__image svg {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 1.904;
  object-fit: cover;
  border-radius: 16px;
}

.single-post .single-post__content .single-post__featured-image svg {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 16px;
}

/* --------------------------------------------------------- the post list */

/* The reference sets height:100% on the list. Its own front page always runs
   past the fold, so the rule never shows; on a page of three posts it resolves
   to the viewport height and leaves a hole between the last card and the
   footer, because a set height cannot shrink to its content. */
.posts-wrapper {
  height: auto;
}

/* The reference hoists its newest post 100px into the banner and gets the space
   under the hero from that section's own 80px bottom margin. We do not run that
   section, so the list carries the gap instead -- and it carries less of it,
   because there is no panel in the space: the sort bar is what follows the
   banner, and it is a 50px pill. The sheet's own 40px under the bar comes down
   with it, or the saving lands between the bar and the cards instead. */
.blog .posts-wrapper {
  margin-top: 16px;
}

.posts-wrapper .filters {
  margin-bottom: 24px;
}

/* ------------------------------------------------------- the sort control */

/* The pill, the panel, the chevron and its rotation are all the reference's own
   rules; the vendor script widens their selectors from `button` to `summary` so
   they reach this without being retyped. What is left is only what a <details>
   needs that a scripted <button> does not. */

.filters summary {
  cursor: pointer;
  list-style: none;
}

.filters summary::-webkit-details-marker {
  display: none;
}

/* The bar is meant to bleed 25px past the list on both sides, and the list has
   no side padding until 767px. Between the two, the bleed is off the right of
   the viewport and the page scrolls sideways; 1330 is the list's 1280 plus the
   two bleeds. This is the padding that stops it, and it puts the bar flush to
   the viewport, which is where it is meant to sit. */
@media (min-width: 768px) and (max-width: 1330px) {
  .blog .posts-wrapper {
    padding-left: 25px;
    padding-right: 25px;
  }
}

/* The reference moves the control into a drawer below 767px, and drops this
   copy of it. There is no drawer here, so this one stays. */
@media (max-width: 767px) {
  .posts-wrapper .filters {
    display: block;
  }
}

/* ------------------------------------------------------------ pagination */

/* The reference's Load More is a button that fetches the next page into the
   grid. This is a link to it, wearing the same rule. */
.posts-wrapper .load-more .btn-load-more.back::after {
  transform: rotate(180deg);
}

.posts-wrapper .load-more + .load-more {
  margin-top: 16px;
}

/* --------------------------------------------------------------- an article */

/* The sidebar carries the date and the byline; the reading time is ours, and it
   wears the same rule as the two above it. */
.sidebar .read {
  position: relative;
  color: #121212;
  font-size: 16px;
}

.sidebar .read::before {
  content: "";
  position: absolute;
  left: -16px;
  display: inline-block;
  width: 2px;
  height: 24px;
  background: #35B7AB;
}

/* The summary, standing above the body. The reference has no line like it and
   so no rule for one, and left alone it reads as the first paragraph of the
   article rather than as the sentence the card and the feed already carried. */
.single-post .single-post__content .lead {
  color: #4d4d4d;
  font-size: 20px;
  line-height: 30px;
}

/* markdown emits <pre><code>; the sheet paints the <pre> and leaves the <code>
   inside it wearing the inline-code rule, which would box every line. */
.single-post .single-post__content .html-content pre {
  border-radius: 16px;
  font-size: 15px;
  line-height: 1.55;
}

.single-post .single-post__content .html-content pre code {
  display: block;
  padding: 0;
  background: none;
  font-size: inherit;
}

/* The reference's "Read next" row always holds four cards, and four of its 300px
   pictures plus the gaps come to the width of the band, so every card lands on
   its picture. Three or fewer and the row is sized by the longest title instead:
   the card grows past the 300 the sheet pins the picture at and the art sits in
   a white card with a strip of nothing beside it. Pin the card to the picture,
   which is the width they agree on when the reference's own row is full. */
.related-posts .container .cards .post-card.related {
  flex: 0 0 300px;
}

/* -------------------------------------------------------------- the draft */

/* A draft is only ever reached through a signed preview link, and it must not be
   mistakable for the published post. */
.draft-banner {
  position: sticky;
  top: 0;
  z-index: 1040;
  margin: 0;
  padding: 8px 18px;
  background: #ffc107;
  color: #121212;
  text-align: center;
  font-weight: 600;
}

/* --------------------------------------------------------------- manners */

a:focus-visible,
button:focus-visible {
  outline: 3px solid #12688C;
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
    animation: none !important;
  }

  .post-card:hover {
    transform: none;
  }
}

/* The reference's own breakpoints. The banner title is 190px on a desktop and
   the sheet already steps h1 down at 1024px; below that the two-column article
   has to stack, which its sheet does for the sidebar but not for the container's
   70px offset. */
@media (max-width: 1024px) {
  .single-post .container {
    flex-direction: column;
    transform: none;
    padding: 0 24px;
    gap: 40px;
  }

  .sidebar {
    position: static;
    width: 100%;
  }

  .header .container-right .feed-link span {
    display: none;
  }

  /* Below 1024 the reference turns the menu into a drawer: absolutely placed,
     height 0, opened to 100vh by a script adding .open. Nothing here adds it, so
     the drawer can never open -- and a collapsed one is not simply invisible,
     its links are still in the tab order, so a keyboard lands on four links
     nobody can see. The footer carries the same four on every page. */
  .header .nav {
    display: none;
  }
}
