/* Generated with: hugo gen chromastyles --style=nord (Hugo 0.164.0), then recoloured to
   the site palette in style.css: navy panel background, cyan keywords, purple functions,
   green strings, amber numbers and names, muted grey comments. Class mode only
   (markup.highlight.noClasses = false), because the CSP is style-src 'self'.
   To regenerate, run the same command and apply the same colour swaps. */

/* Background */ .bg { color:#d9e0e8;background-color:#101520; }
/* PreWrapper */ .chroma { color:#d9e0e8;background-color:#101520;-webkit-text-size-adjust:none; }
/* Error */ .chroma .err { color:#ff7b72 }
/* LineLink */ .chroma .lnlinks { outline:none;text-decoration:none;color:inherit }
/* LineTableTD */ .chroma .lntd { vertical-align:top;padding:0;margin:0;border:0; }
/* LineTable */ .chroma .lntable { border-spacing:0;padding:0;margin:0;border:0; }
/* LineHighlight */ .chroma .hl { background-color:#1a2233 }
/* LineNumbersTable */ .chroma .lnt { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#5c6773 }
/* LineNumbers */ .chroma .ln { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#5c6773 }
/* Line */ .chroma .line { display:flex; }
/* Keyword */ .chroma .k { color:#56d4dd;font-weight:bold }
/* KeywordConstant */ .chroma .kc { color:#56d4dd;font-weight:bold }
/* KeywordDeclaration */ .chroma .kd { color:#56d4dd;font-weight:bold }
/* KeywordNamespace */ .chroma .kn { color:#56d4dd;font-weight:bold }
/* KeywordPseudo */ .chroma .kp { color:#56d4dd }
/* KeywordReserved */ .chroma .kr { color:#56d4dd;font-weight:bold }
/* KeywordType */ .chroma .kt { color:#56d4dd }
/* NameAttribute */ .chroma .na { color:#ffcb6b }
/* NameClass */ .chroma .nc { color:#ffcb6b }
/* NameConstant */ .chroma .no { color:#ffcb6b }
/* NameDecorator */ .chroma .nd { color:#ffcb6b }
/* NameEntity */ .chroma .ni { color:#ffcb6b }
/* NameException */ .chroma .ne { color:#ff7b72 }
/* NameLabel */ .chroma .nl { color:#ffcb6b }
/* NameNamespace */ .chroma .nn { color:#ffcb6b }
/* NameOther */ .chroma .nx { color:#d9e0e8 }
/* NameProperty */ .chroma .py { color:#ffcb6b }
/* NameTag */ .chroma .nt { color:#56d4dd }
/* NameBuiltin */ .chroma .nb { color:#56d4dd }
/* NameBuiltinPseudo */ .chroma .bp { color:#56d4dd }
/* NameFunction */ .chroma .nf { color:#c792ea }
/* NameFunctionMagic */ .chroma .fm { color:#c792ea }
/* LiteralString */ .chroma .s { color:#98c379 }
/* LiteralStringAffix */ .chroma .sa { color:#98c379 }
/* LiteralStringBacktick */ .chroma .sb { color:#98c379 }
/* LiteralStringChar */ .chroma .sc { color:#98c379 }
/* LiteralStringDelimiter */ .chroma .dl { color:#98c379 }
/* LiteralStringDoc */ .chroma .sd { color:#8b949e }
/* LiteralStringDouble */ .chroma .s2 { color:#98c379 }
/* LiteralStringEscape */ .chroma .se { color:#ffcb6b }
/* LiteralStringHeredoc */ .chroma .sh { color:#98c379 }
/* LiteralStringInterpol */ .chroma .si { color:#98c379 }
/* LiteralStringOther */ .chroma .sx { color:#98c379 }
/* LiteralStringRegex */ .chroma .sr { color:#ffcb6b }
/* LiteralStringSingle */ .chroma .s1 { color:#98c379 }
/* LiteralStringSymbol */ .chroma .ss { color:#98c379 }
/* LiteralNumber */ .chroma .m { color:#ffcb6b }
/* LiteralNumberBin */ .chroma .mb { color:#ffcb6b }
/* LiteralNumberFloat */ .chroma .mf { color:#ffcb6b }
/* LiteralNumberHex */ .chroma .mh { color:#ffcb6b }
/* LiteralNumberInteger */ .chroma .mi { color:#ffcb6b }
/* LiteralNumberIntegerLong */ .chroma .il { color:#ffcb6b }
/* LiteralNumberOct */ .chroma .mo { color:#ffcb6b }
/* Operator */ .chroma .o { color:#56d4dd }
/* OperatorWord */ .chroma .ow { color:#56d4dd;font-weight:bold }
/* OperatorReserved */ .chroma .or { color:#56d4dd }
/* Punctuation */ .chroma .p { color:#9fb0c3 }
/* Comment */ .chroma .c { color:#8b949e;font-style:italic }
/* CommentHashbang */ .chroma .ch { color:#8b949e;font-style:italic }
/* CommentMultiline */ .chroma .cm { color:#8b949e;font-style:italic }
/* CommentSingle */ .chroma .c1 { color:#8b949e;font-style:italic }
/* CommentSpecial */ .chroma .cs { color:#8b949e;font-style:italic }
/* CommentPreproc */ .chroma .cp { color:#8b949e;font-style:italic }
/* CommentPreprocFile */ .chroma .cpf { color:#8b949e;font-style:italic }
/* GenericDeleted */ .chroma .gd { color:#ff7b72 }
/* GenericEmph */ .chroma .ge { font-style:italic }
/* GenericError */ .chroma .gr { color:#ff7b72 }
/* GenericHeading */ .chroma .gh { color:#c792ea;font-weight:bold }
/* GenericInserted */ .chroma .gi { color:#98c379 }
/* GenericOutput */ .chroma .go { color:#d9e0e8 }
/* GenericPrompt */ .chroma .gp { color:#8b949e;font-weight:bold }
/* GenericStrong */ .chroma .gs { font-weight:bold }
/* GenericSubheading */ .chroma .gu { color:#c792ea;font-weight:bold }
/* GenericTraceback */ .chroma .gt { color:#ff7b72 }
/* TextWhitespace */ .chroma .w { color:#d9e0e8 }
/* alanconlon.com — dark editorial, matched to the code-card covers.
   Fonts: Space Grotesk (headings) · system UI sans (body) · JetBrains Mono (code)
   Both web fonts are self-hosted from static/fonts as Latin-subset variable
   WOFF2 (SIL Open Font Licence, see static/fonts/OFL-*.txt) and preloaded in
   baseof.html. Characters outside the subset fall back to the next font in
   the stack. File names carry the upstream version, so they can be cached
   for a year; a new version gets a new name. */

@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url("/fonts/space-grotesk-v22-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;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("/fonts/jetbrains-mono-v24-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 {
  --bg: #0b0e14;
  --bg2: #0e1320;
  --panel: #101520;
  --panel-hover: #131a29;
  --border: #283042;
  --text: #d9e0e8;
  --muted: #8b949e;
  --cyan: #56d4dd;
  --purple: #c792ea;
  --green: #98c379;
  --amber: #ffcb6b;
  --maxw: 760px;
  --sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --display: "Space Grotesk", var(--sans);
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Consolas, monospace;
}

* { box-sizing: border-box; }

/* Solid dark on the root so iOS Safari overscroll and toolbar areas never show white */
html {
  min-height: 100%;
  background: var(--bg2);
}

body {
  margin: 0;
  min-height: 100dvh;
  background-color: var(--bg2);
  background-image: linear-gradient(180deg, var(--bg) 0%, var(--bg2) 100%);
  background-attachment: fixed;
  color: var(--text);
  font: 400 17px/1.75 var(--sans);
  -webkit-font-smoothing: antialiased;
}

main {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 2.5rem 1.25rem 4rem;
}

a { color: var(--cyan); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

h1, h2, h3 { font-family: var(--display); line-height: 1.2; color: #f0f4f8; letter-spacing: -0.01em; }
h1 { font-size: 2.2rem; font-weight: 700; }
h2 { font-size: 1.5rem; margin-top: 2.75rem; font-weight: 700; }
h3 { font-size: 1.2rem; margin-bottom: 0.3rem; font-weight: 700; }

/* ---------- Masthead ---------- */
.site-header {
  width: 100%;
  max-width: var(--maxw); margin: 0 auto; padding: 1.75rem 1.25rem 0.9rem;
  display: flex; flex-direction: column; align-items: flex-start; gap: 0.9rem;
  border-bottom: 1px solid var(--border);
}
.masthead { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 1rem; row-gap: 0.15rem; }
.masthead .site-name {
  font-family: var(--display);
  font-weight: 700; font-size: 1.5rem; color: #f0f4f8;
  text-decoration: none; letter-spacing: -0.02em;
  transition: color 0.15s ease;
}
.site-name .tld { color: var(--cyan); }
.site-name:hover { text-decoration: none; color: var(--cyan); }
.site-name:hover .tld { color: #f0f4f8; }
.masthead .strap {
  margin: 0; font-family: var(--mono);
  font-size: 0.72rem; color: var(--muted); letter-spacing: 0.04em;
  white-space: nowrap;
}
.site-header nav { display: flex; flex-wrap: wrap; row-gap: 0.4rem; }
.site-header nav a {
  margin: 0 1.5rem 0 0; white-space: nowrap; color: var(--muted);
  font-family: var(--display); font-weight: 500; font-size: 0.95rem;
}
.site-header nav a:hover { color: var(--cyan); text-decoration: none; }
.site-header nav a.nav-free { color: var(--cyan); }
.site-header nav a.nav-free:hover { color: #f0f4f8; }

/* ---------- Intro ---------- */
.intro { margin: 1rem 0 2.5rem; }
.intro h1 { margin-bottom: 0.5rem; }
.intro p { color: var(--muted); }
.intro .intro-guide { margin-top: 0.75rem; }

/* ---------- Post cards ---------- */
.post-list h1 { margin-bottom: 1.5rem; }
.post-list > h2 { margin: 0 0 0.25rem; font-size: 1.3rem; }
.intro .byline { margin-top: 0.75rem; font-size: 0.9rem; }
.post-card {
  display: grid; grid-template-columns: 280px 1fr; gap: 1.4rem;
  align-items: start;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1.1rem;
  margin: 1.25rem 0;
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}
.post-card:hover {
  background: var(--panel-hover);
  border-color: #3a4560;
  transform: translateY(-1px);
}
.card-cover img {
  width: 100%; height: auto; aspect-ratio: 1600 / 840; object-fit: cover;
  border-radius: 8px;
  border: 1px solid #3a4560;
  display: block;
  background: #0d1220;
  filter: brightness(1.18) contrast(1.06) saturate(1.05);
  transition: filter 0.15s ease;
}
.post-card:hover .card-cover img {
  filter: brightness(1.3) contrast(1.08) saturate(1.1);
}
/* Card titles are H2 on list pages and H3 on the homepage; same look either way */
.card-body .card-title { font-size: 1.2rem; font-weight: 700; margin: 0.1rem 0 0.2rem; }
.card-body .card-title a { color: #f0f4f8; }
.card-body .card-title a:hover { color: var(--cyan); text-decoration: none; }
.card-desc { margin: 0.35rem 0 0; color: var(--muted); font-size: 0.95rem; }

.meta { color: var(--muted); font-size: 0.85rem; font-family: var(--mono); margin: 0.15rem 0 0.2rem; }
.meta a { color: var(--muted); }
.meta a:hover { color: var(--cyan); }
/* Tag links in a post header: at least 24px tall to tap, without changing the line */
.post-header .meta a { display: inline-block; min-height: 24px; padding: 0.1rem 0; }
.series-chip {
  display: inline-block; padding: 0.05rem 0.55rem; border: 1px solid var(--border);
  border-radius: 999px; font-size: 0.75rem; color: var(--purple) !important;
  font-family: var(--mono);
}
a.series-chip:hover { border-color: var(--purple); text-decoration: none; }

.view-all { margin-top: 1.5rem; font-family: var(--mono); font-size: 0.9rem; }

/* ---------- Product cards (extend .post-card) ---------- */
.list-intro { color: var(--muted); }
.product-card { grid-template-columns: 180px 1fr; }
.product-thumb img {
  width: 100%; height: auto;
  border-radius: 8px;
  border: 1px solid #3a4560;
  display: block;
  background: #0d1220;
}
.product-buy {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.4rem 1.25rem;
  margin: 0.75rem 0 0; font-family: var(--mono); font-size: 0.9rem;
}
.product-price { color: var(--amber); font-weight: 600; }
.product-note { margin-top: 1.5rem; color: var(--muted); font-size: 0.85rem; font-family: var(--mono); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* ---------- Single post ---------- */
.post-header h1 { margin-bottom: 0.4rem; }
.post-cover {
  width: 100%; height: auto; aspect-ratio: 1600 / 840; border-radius: 12px; border: 1px solid var(--border);
  margin: 1.25rem 0 0.25rem; display: block;
}
.post-body { margin-top: 1.5rem; font-size: 1.02rem; overflow-wrap: break-word; }
.post-body p { margin: 1.2rem 0; }
.post-body blockquote {
  margin: 1.75rem 0; padding: 0.75rem 1.4rem;
  border-left: 3px solid var(--cyan);
  background: var(--panel); border-radius: 0 10px 10px 0;
  color: #b9c2cc; font-style: italic;
}
.post-body blockquote p { margin: 0.4rem 0; }
.post-body code {
  font-family: var(--mono); font-size: 0.85em;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 5px; padding: 0.1em 0.4em; color: var(--amber);
}
.post-body pre {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 12px; padding: 1.1rem 1.35rem;
  overflow-x: auto; line-height: 1.6; max-width: 100%;
  box-shadow: 0 6px 24px rgba(0,0,0,0.35);
}
/* Code blocks sit on the theme navy panel (chroma.css is recoloured to match).
   Ligatures off everywhere code appears, so == and != stay two characters. */
.post-body pre.chroma { background-color: var(--panel); tab-size: 4; }
.post-body pre code { background: none; border: none; padding: 0; font-size: 0.85rem; color: inherit; }
code, pre, kbd, samp {
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
}
.post-body .highlight { position: relative; }
.post-body .highlight.has-copy pre { padding-top: 2.4rem; }
.copy-code {
  position: absolute; top: 0.55rem; right: 0.6rem;
  min-height: 28px; padding: 0.15rem 0.7rem;
  font: 500 0.75rem/1.4 var(--mono); color: var(--muted);
  background: var(--bg); border: 1px solid var(--border); border-radius: 6px;
  cursor: pointer;
}
.copy-code:hover { color: var(--cyan); border-color: var(--cyan); }
.post-body img { max-width: 100%; height: auto; border-radius: 10px; }
.post-body hr { border: none; border-top: 1px solid var(--border); margin: 2.5rem 0; }
.post-body table {
  border-collapse: collapse; width: 100%; margin: 1.5rem 0; font-size: 0.93rem;
}
.post-body th, .post-body td { border: 1px solid var(--border); padding: 0.5rem 0.75rem; text-align: left; }
.post-body th { background: var(--panel); font-family: var(--display); font-weight: 500; }

/* ---------- Series box ---------- */
.series-box {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 12px; padding: 0.9rem 1.3rem; margin: 1.5rem 0;
  font-size: 0.92rem;
}
.series-box .series-title { margin: 0 0 0.4rem; color: var(--muted); font-family: var(--mono); font-size: 0.8rem; }
.series-box .series-start { margin: 0 0 0.5rem; font-size: 0.9rem; }
.series-box ol { margin: 0; padding-left: 1.25rem; }
.series-box li { margin: 0.2rem 0; }
.series-current { color: var(--amber); }
.series-upcoming { color: var(--text); }
.coming-soon { color: var(--muted); font-size: 0.85em; }

/* ---------- Footers ---------- */
.post-footer { margin-top: 3rem; padding-top: 1.25rem; border-top: 1px solid var(--border); color: var(--muted); }
.site-footer {
  width: 100%;
  max-width: var(--maxw); margin: 0 auto; padding: 1.5rem 1.25rem 2.5rem;
  border-top: 1px solid var(--border);
  color: var(--muted); font-size: 0.85rem;
}
.site-footer a { color: var(--muted); }
.site-footer a:hover { color: var(--cyan); }
.site-footer > p:first-child a { display: inline-block; padding: 0.2rem 0; min-height: 24px; }
.footer-note { margin-top: 0.75rem; }
.footer-topics {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem;
  margin: 0.75rem 0 0;
}
.footer-topics-label { font-family: var(--mono); font-size: 0.75rem; margin-right: 0.2rem; }
.site-footer .series-chip, .post-card .series-chip { min-height: 24px; line-height: 1.6; padding: 0.1rem 0.6rem; }

.term-list { list-style: none; padding: 0; }
.term-list li { margin: 0.6rem 0; font-size: 1.05rem; }

/* ---------- Mobile ---------- */
@media (max-width: 640px) {
  .site-header { gap: 0.75rem; }
  .site-header nav a { margin-right: 1.1rem; }
  .masthead .strap { white-space: normal; }
}
@media (max-width: 640px) {
  h1 { font-size: 1.7rem; }
  .post-card { grid-template-columns: 1fr; }
  .product-thumb img { max-width: 320px; }
}

/* Pin a full-viewport dark layer behind everything so iOS Safari overscroll
   past the toolbar can never reveal white. Fixed position means it stays
   locked to the viewport regardless of scroll bounce. */
html::before {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100dvh;
  background: var(--bg2);
  z-index: -1;
}

/* ---------- Product box (end of post) ---------- */
.product-cta {
  display: flex; gap: 1rem; align-items: flex-start;
  background: var(--panel); border: 1px solid var(--border); border-left: 3px solid var(--amber);
  border-radius: 12px; padding: 1rem 1.2rem; margin: 2.5rem 0 0; font-size: 0.95rem;
}
.product-cta-thumb { flex: 0 0 88px; }
.product-cta-thumb img { width: 88px; height: 88px; border-radius: 8px; display: block; }
.product-cta p { margin: 0.2rem 0; }
.product-cta-name { font-family: var(--display); font-weight: 700; }
.product-cta .product-price { color: var(--amber); font-family: var(--mono); font-size: 0.85rem; margin-left: 0.4rem; }
@media (max-width: 480px) { .product-cta-thumb { flex-basis: 64px; } .product-cta-thumb img { width: 64px; height: 64px; } }

/* ---------- Newsletter signup ---------- */
.newsletter {
  background: var(--panel); border: 1px solid var(--border); border-left: 3px solid var(--cyan);
  border-radius: 12px; padding: 1rem 1.2rem; margin: 1.5rem 0; color: var(--text);
}
.newsletter-title { margin: 0; font-family: var(--display); font-weight: 700; color: #f0f4f8; }
.newsletter-intro { margin: 0.2rem 0 0.75rem; color: var(--muted); font-size: 0.92rem; }
.newsletter-form { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.newsletter-form input {
  flex: 1 1 220px; min-width: 0; padding: 0.55rem 0.75rem; font: inherit; font-size: 16px;
  color: var(--text); background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
}
.newsletter-form input:focus { outline: 2px solid var(--cyan); outline-offset: 1px; }
.newsletter-form button {
  padding: 0.55rem 1.1rem; font: 600 0.95rem var(--sans); color: var(--bg);
  background: var(--cyan); border: 0; border-radius: 8px; cursor: pointer;
}
.newsletter-form button:hover { filter: brightness(1.1); }
.newsletter-privacy { margin: 0.6rem 0 0; font-size: 0.8rem; }
.newsletter-privacy a { display: inline-block; min-height: 24px; padding: 0.15rem 0; color: var(--muted); }
.newsletter-privacy a:hover { color: var(--cyan); }

/* ---------- Series previous/next and "Read next" ---------- */
.series-nav {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem;
  margin: 2.25rem 0 0;
}
.series-nav a {
  display: block; padding: 0.8rem 1rem;
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  color: #f0f4f8; line-height: 1.4;
}
.series-nav a:hover { border-color: var(--cyan); text-decoration: none; }
.series-nav-next { grid-column: 2; text-align: right; }
.series-nav-label {
  display: block; margin-bottom: 0.25rem;
  color: var(--muted); font-family: var(--mono); font-size: 0.75rem;
}
.related { margin: 2.25rem 0 0; }
.related-title { font-size: 1.1rem; margin: 0 0 0.5rem; }
.related ul { margin: 0; padding-left: 1.2rem; }
.related li { margin: 0.35rem 0; }
@media (max-width: 560px) {
  .series-nav { grid-template-columns: 1fr; }
  .series-nav-next { grid-column: 1; }
}

/* Cover images are wrapped in <picture> for WebP; keep the wrapper out of the
   layout so the existing img rules apply exactly as before. */
picture { display: contents; }
.card-cover img, .post-cover { height: auto; }

/* ---------- Keyboard focus and skip link ---------- */
:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 3px;
  border-radius: 4px;
}
:focus:not(:focus-visible) { outline: none; }
main:focus { outline: none; }
.post-card:focus-within { border-color: var(--cyan); }
.skip-link {
  position: absolute; left: 1rem; top: -100px; z-index: 10;
  padding: 0.5rem 0.9rem; border-radius: 8px;
  background: var(--cyan); color: var(--bg);
  font: 600 0.95rem var(--sans);
}
.skip-link:focus, .skip-link:focus-visible {
  top: 0.75rem; text-decoration: none; outline-color: #f0f4f8;
}
