/* Platform — public site base.
   One sheet renders every site. The look comes from --site-* custom
   properties emitted per request by core/theme.js: the install-wide theme in
   themes/<THEME>/theme.json, with module.json.theme overriding named tokens.
   Each var() keeps a literal fallback equal to the built-in default, so this
   sheet still renders correctly on its own.

   THE FOUR DERIVED COLOURS BELOW ARE THE WHOLE ACCESSIBILITY STORY.
   The Aug 2026 palette gives each site one vibrant accent, and those accents
   are not interchangeable: #A7DBD7 is 1.34:1 on the off-white paper and
   #4B51A3 is 2.56:1 on the near-black ink. Neither is usable as raw text on
   the ground it fights with, so an accent is never printed as small text
   directly. Instead:

     --tint             accent lightened toward paper — accent AS TEXT on dark
     --shade            accent darkened toward ink — small accent GEOMETRY on paper
     raw accent         large fills, bands and rules only
     --site-on-accent   text sitting ON an accent fill

   Both derived values clear 4.5:1 for all seven brand accents (worst case:
   #4B51A3 tinted, 4.87:1 on ink). Changing the mix percentages changes a
   contrast guarantee, not a shade. */

* { box-sizing: border-box; }
html { font-size: var(--site-font-size, 16px); }

/* Layout is rem-based throughout, so setting data-textsize on <html> scales
   the whole page coherently. Nothing sets it today — wire it to a control if
   the site needs a text-size affordance. */
html[data-textsize="large"]  { font-size: 19px; }
html[data-textsize="xlarge"] { font-size: 22px; }

body.site {
  margin: 0;
  font-family: var(--site-font, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif);
  color: var(--site-ink, #15222F);
  background: var(--site-paper, #fff);
  line-height: 1.65;

  /* Derived from the tokens rather than hardcoded, so a theme that inverts the
     foundation inverts these with it. */
  --tint:  color-mix(in srgb, var(--site-accent) 70%, var(--site-paper, #fff));
  --shade: color-mix(in srgb, var(--site-accent) 55%, var(--site-ink, #15222F));
  --rule:  color-mix(in srgb, var(--site-ink, #15222F) 14%, var(--site-paper, #fff));
  --wash:  color-mix(in srgb, var(--site-ink, #15222F) 6%, var(--site-paper, #fff));
  /* Secondary text on a dark ground. Not --site-muted: that one is tuned
     against paper and falls to 2.5:1 on ink. */
  --dim:   color-mix(in srgb, var(--site-paper, #fff) 68%, var(--site-ink, #15222F));
}

/* THE DISPLAY FACE IS FOR H TAGS AND THE WORDMARK ONLY.
   Everything else — body copy, buttons, and every eyebrow-style label
   (.eyebrow, .kicker, .tagline, .module-label, .stat-b figures) — inherits
   --site-font from body.site and is deliberately NOT listed here. Buttons and
   eyebrows were pulled out of the display face by direction: they read as UI
   rather than as headings.
   On a theme that names only fontStack, headingFont falls back to the built-in
   default, which is the SYSTEM stack — so a theme wanting one family has to
   state headingFont, not omit it. */
h1, h2, h3, h4, .site-brand {
  font-family: var(--site-heading-font, var(--site-font, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif));
}

/* h1 has to STATE the weight rather than inherit the browser's `bold`, so the
   theme controls it. tt-travels-next ships 100-900, so headingWeight 800 is the
   guideline's ExtraBold header — and .sec h2's 600 is its DemiBold subhead,
   which is a real weight again now that the display face is back. */
h1 { font-weight: var(--site-heading-weight, 800); }

/* Skip link — visible only on keyboard focus, which is the point: it is the
   first tab stop and lets a keyboard or screen-reader user jump the header and
   the cross-module bar instead of tabbing through every nav item on every page. */
.skip-link { position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--site-primary); color: var(--site-paper); padding: .7rem 1.1rem;
  font-weight: 700; text-decoration: none; }
.skip-link:focus { left: 0; }

a { color: var(--site-primary, #1F2937); }

.site-header {
  display: flex; align-items: center; gap: 28px; flex-wrap: wrap;
  padding: 1rem 5vw; border-bottom: 3px solid var(--site-primary, #1F2937);
}
.site-brand { font-size: 1.35rem; font-weight: var(--site-heading-weight, 800); text-decoration: none; color: var(--site-primary); letter-spacing: -0.02em; text-transform: uppercase; }
/* A module may supply a brand mark instead of its name (module.json
   theme.logo). Sized by height so any aspect ratio sits on the header
   baseline, and capped by width so a wide wordmark cannot push the nav
   off a narrow screen. */
.site-brand-mark { display: block; height: 34px; width: auto; max-width: min(260px, 55vw); }
.site-nav { display: flex; gap: 20px; flex-wrap: wrap; min-width: 0; }
.site-nav a { text-decoration: none; font-weight: 600; font-size: .95rem; padding: 6px 2px; border-bottom: 3px solid transparent; white-space: nowrap; }
/* An accent-coloured hover is unreadable for the paler accents, so the accent
   arrives as a rule under unchanged text. */
.site-nav a:hover { border-bottom-color: var(--shade, var(--site-accent)); }

.site-main { max-width: 760px; margin: 0 auto; padding: 2.2rem 5vw 4rem; }
.site-main h1 { font-size: clamp(2rem, 4vw, 2.6rem); line-height: 1.1; color: var(--site-primary); letter-spacing: -0.025em; }
.page-body img { max-width: 100%; height: auto; }

.site-footer { border-top: 1px solid var(--rule, #E1E7EC); padding: 1.4rem 5vw; color: var(--site-muted, #516072); font-size: 0.9rem; }

/* ================= cross-module bar ================= */
.module-bar { display:flex; align-items:center; gap:16px; flex-wrap:wrap; background:var(--site-ink, #0B1524); color:var(--dim, #8FA0BC); padding:8px 5vw; font-size:.82rem; }
.module-label { text-transform:uppercase; letter-spacing:.08em; font-size:.7rem; }
.module-bar a { color:var(--dim, #B9C7D9); text-decoration:none; padding:2px 0; }
.module-bar a:hover { color:var(--site-paper, #fff); }
.module-bar a.on { color:var(--site-paper, #fff); font-weight:700; border-bottom:2px solid var(--tint, var(--site-accent)); }

.brand-main { padding: 0; }
.brand-main .page-body { max-width: none; }

/* ================= dark grounds =================
   The brand's foundation is "black backgrounds with one vibrant accent", so
   the hero, the CTA band, the stat blocks and any .sec-dark section are one
   family and share these rules. */
.hero, .sec-dark, .cta-band, .stat-b { color: var(--site-paper, #fff); }
.hero h1, .hero h2, .hero h3,
.sec-dark h1, .sec-dark h2, .sec-dark h3,
.cta-band h2 { color: var(--site-paper, #fff); }
.hero p, .sec-dark p, .sec-dark .sec-sub, .cta-band p, .stat-b span { color: var(--dim, rgba(255,255,255,.8)); }
/* Accent as text is only ever the tint — see the header note. */
.hero h1 em, .sec-dark h2 em, .stat-b b { color: var(--tint, var(--site-accent)); }

/* hero */
.hero { background: linear-gradient(160deg, var(--site-primary), color-mix(in srgb, var(--site-primary) 70%, #000 30%)); padding: clamp(3rem,8vw,5.5rem) 5vw; }
.hero-inner { max-width: var(--site-max-width, 1060px); margin: 0 auto; }
.hero .eyebrow { display:inline-block; border:1px solid var(--tint, var(--site-accent)); color: var(--tint, var(--site-accent)); padding:6px 16px; border-radius:var(--site-radius, 999px); font-size:.8rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase; margin-bottom:20px; }
.hero h1 { font-size: clamp(2.2rem, 5.2vw, 3.6rem); line-height:1.05; letter-spacing:-.03em; margin:0 0 16px; max-width: 900px; }
.hero h1 em { font-style: normal; }
.hero p { font-size:1.15rem; max-width:640px; margin:0 0 28px; }
.hero-ctas { display:flex; gap:14px; flex-wrap:wrap; }
.cta { display:inline-block; font-weight:var(--site-heading-weight,800); text-decoration:none; border-radius:var(--site-radius, 10px); padding:.95rem 1.9rem; font-size:1.05rem; }
/* --site-on-accent, not #fff: white is 1.53:1 on the aqua and 1.46:1 on the
   lime, so a hardcoded white label made three of the seven brand accents
   unusable as a button. Each module states the readable one. */
.cta-solid { background: var(--site-accent); color: var(--site-on-accent, #fff); }
.cta-solid:hover { filter:brightness(1.08); }
.cta-line { border:2px solid color-mix(in srgb, var(--site-paper, #fff) 50%, transparent); color:var(--site-paper, #fff); }
.cta-line:hover { border-color:var(--site-paper, #fff); }
.hero .fine { font-size:.88rem; color: var(--dim, rgba(255,255,255,.65)); margin-top:14px; }

/* Links on a dark block.
   The global link colour IS --site-primary, which is also what the hero and
   the solid stat block are filled with — so a link inside one renders in the
   background colour and is effectively invisible. Seen on the shipped default
   home page, where "Admin → Pages" disappeared into the hero.
   --site-paper rather than a hardcoded #fff so a theme whose primary is light
   still gets a readable link. .cta is excluded: it sets its own colours and
   must keep text-decoration:none. */
.hero a:not(.cta), .stat-b a, .sec-dark a:not(.cta), .cta-band a:not(.cta) { color: var(--site-paper, #fff); text-decoration: underline; text-underline-offset: 2px; }
.hero a:not(.cta):hover, .stat-b a:hover, .sec-dark a:not(.cta):hover, .cta-band a:not(.cta):hover { color: var(--tint, var(--site-accent)); }

/* generic sections */
.sec { padding: clamp(2.5rem,6vw,4.5rem) 5vw; }
.sec-inner { max-width:var(--site-max-width,1060px); margin:0 auto; }
.sec-alt { background:var(--wash, #F4F6F9); }
/* The brand's large black background. Meant for whole content sections, not
   only the hero and the closing CTA — it is where the paler accents work. */
.sec-dark { background:var(--site-primary, #1F2937); }
/* 600 is the brand's DemiBold subheader weight, against `headingWeight` (800,
   ExtraBold) on h1. On a fallback stack with no 600 face this renders as bold
   either way, so it costs nothing before the real family loads. */
/* 600 is the guideline's DemiBold subhead, against headingWeight (800,
   ExtraBold) on h1. tt-travels-next has a real 600, so h2 separates from h1 by
   weight as well as size. */
.sec h2 { font-size: clamp(1.7rem,3.4vw,2.5rem); font-weight:600; letter-spacing:-.025em; line-height:1.12; color: var(--site-primary); margin:0 0 8px; }
.sec .sec-sub { color:var(--site-muted,#516072); max-width:640px; margin:0 0 30px; font-size:1.06rem; }
/* The accent reaches a light section as geometry, never as small text: a
   0.75rem label in #A7DBD7 on paper is 1.34:1. The bar uses --shade because at
   4px tall the raw accent would also disappear; the large fills keep the raw
   accent. */
.kicker { display:flex; align-items:center; gap:12px; text-transform:uppercase; letter-spacing:.12em; font-size:.75rem; font-weight:var(--site-heading-weight,800); color: var(--site-ink); margin-bottom:10px; }
.kicker::before { content:""; flex:none; width:26px; height:4px; background:var(--shade, var(--site-accent)); }
.hero .kicker, .sec-dark .kicker, .cta-band .kicker { color: var(--site-paper, #fff); }
.hero .kicker::before, .sec-dark .kicker::before, .cta-band .kicker::before { background: var(--tint, var(--site-accent)); }
.cta-band .kicker { justify-content:center; }

/* card grids */
.cards { display:grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap:18px; }
.card { background:var(--site-paper,#fff); border:1px solid var(--rule,#E1E7EC); border-radius:var(--site-radius,14px); padding:26px 24px; display:flex; flex-direction:column; }
.sec-alt .card { border-color:color-mix(in srgb, var(--site-ink,#15222F) 18%, var(--site-paper,#fff)); }
.sec-dark .card { background:color-mix(in srgb, var(--site-paper,#fff) 8%, var(--site-ink,#15222F)); border-color:color-mix(in srgb, var(--site-paper,#fff) 20%, var(--site-ink,#15222F)); }
.sec-dark .card h3, .sec-dark .card h2 a { color:var(--site-paper,#fff); }
.sec-dark .card p, .sec-dark .tagline, .sec-dark .logos { color:var(--dim); }
.card .ic { --icon-size: 32px; margin-bottom: 12px; }
.card h3 { margin:0 0 6px; font-size:1.12rem; color:var(--site-primary); letter-spacing:-.01em; }
.card p { margin:0 0 14px; color:var(--site-muted,#516072); font-size:.97rem; flex:1; }
/* Same reasoning as .kicker: readable text, accent in the rule under it. */
.card a.more { font-weight:700; color:var(--site-ink); text-decoration:underline; text-decoration-color:var(--shade, var(--site-accent)); text-decoration-thickness:3px; text-underline-offset:4px; }
.card a.more:hover { text-decoration-thickness:5px; }
.sec-dark .card a.more { color:var(--site-paper,#fff); text-decoration-color:var(--tint, var(--site-accent)); }
/* A 4px band is a large area, so it keeps the raw brand colour. */
.card.feature { border-top:4px solid var(--site-accent); }

/* stat band */
.stats { display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:16px; }
.stat-b { background:var(--site-primary); border-radius:var(--site-radius,14px); padding:22px; }
.stat-b b { display:block; font-size:2rem; letter-spacing:-.03em; line-height:1.05; }
.stat-b span { font-size:.92rem; }

/* steps (process) */
.steps { display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); gap:16px; counter-reset: step; }
.step { background:var(--site-paper,#fff); border:1px solid var(--rule,#E1E7EC); border-radius:var(--site-radius,14px); padding:24px 22px; position:relative; counter-increment: step; }
.step::before { content: counter(step); position:absolute; top:-14px; left:20px; width:30px; height:30px; border-radius:var(--site-radius,50%); background:var(--site-accent); color:var(--site-on-accent,#fff); font-weight:var(--site-heading-weight,800); display:grid; place-items:center; font-size:.9rem; }
.step h3 { margin:8px 0 6px; font-size:1.05rem; color:var(--site-primary); }
.step p { margin:0; color:var(--site-muted,#516072); font-size:.94rem; }
.sec-dark .step { background:color-mix(in srgb, var(--site-paper,#fff) 8%, var(--site-ink,#15222F)); border-color:color-mix(in srgb, var(--site-paper,#fff) 20%, var(--site-ink,#15222F)); }
.sec-dark .step h3 { color:var(--site-paper,#fff); }
.sec-dark .step p { color:var(--dim); }

/* CTA band */
.cta-band { background: var(--site-primary); text-align:center; }
.cta-band p { max-width:560px; margin:0 auto 26px; }

.tagline { color:var(--site-muted,#516072); font-size:.9rem; text-transform:uppercase; letter-spacing:.08em; margin-bottom:4px; display:block; }

.brand-footer { text-align:center; }
.foot-modules { margin-bottom:8px; }
.foot-modules a { margin:0 2px; }

/* logo strip */
.logos { display:flex; flex-wrap:wrap; gap:12px 28px; align-items:center; color:var(--site-muted,#516072); font-weight:700; letter-spacing:.02em; }
.logos span { opacity:.75; }

@media (max-width:600px){ .hero-ctas { flex-direction:column; } .cta { text-align:center; } }

/* On a phone the header was taller than half the viewport: .site-nav wrapped
   to one item per line, and the module bar to two. Both become a single
   horizontally scrollable strip instead. The page body still must not scroll
   sideways — only these two strips do. */
@media (max-width:760px){
  .site-header { gap: 10px 16px; padding: .7rem 5vw; }
  .site-brand { font-size: 1.15rem; }
  .site-brand-mark { height: 26px; }
  .site-nav,
  .module-bar { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .site-nav::-webkit-scrollbar,
  .module-bar::-webkit-scrollbar { display: none; }
  .site-nav { gap: 16px; width: 100%; padding-bottom: 2px; }
  /* A fade at the right edge is the cue that the strip continues. Without it
     QA found first-time visitors cannot tell Contact exists at all — the strip
     just looks like a nav that ends at "Consumer Products". Masked rather than
     drawn with a gradient overlay so it works on any background. */
  .site-header { position: relative; }
  /* BOTH strips, not just .site-nav. The module bar was left out first time
     round and clipped "Commerce" mid-word with no cue at all -- QA reported the
     header as having no hint on the retest, and that bar was why.
     Widened from 28px to 44px because a 28px fade over one or two characters
     reads as a rendering artifact rather than as "there is more this way". */
  .site-nav,
  .module-bar { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 44px), transparent);
                        mask-image: linear-gradient(to right, #000 calc(100% - 44px), transparent); }
  .module-bar { gap: 12px; }
  .module-bar a, .module-label { white-space: nowrap; }
  /* Trailing space so the last item can clear the fade instead of sitting
     permanently half-dissolved, which reads as a bug rather than a cue. */
  .site-nav::after,
  .module-bar::after { content: ''; flex: 0 0 34px; }
}


/* ================= iconography =================
   Lucide v0.469.0, outline, 2px stroke — SELF-HOSTED under public/img/icons.
   Not a CDN: `img-src` is 'self' plus the media origin, and a mask-image url()
   is governed by img-src, so a CDN reference is refused and the icon silently
   does not render. Same reason CodeMirror is vendored.

   Masked rather than inlined, so the glyph takes `currentColor` and inherits
   whatever the surrounding text is — ink on paper, paper on a dark band — from
   one monochrome file per icon. Inline SVG in body_html would also work, but it
   is unreadable in the Admin editor, where content people actually edit these.

   RULES (from the brand spec, worth keeping):
     - outline only; never mix in filled or duotone glyphs
     - sizes 16 inline/in buttons, 20 default, 24 navigation, 32 service marks
     - colour is inherited from text; an icon may take a service accent when it
       labels that service, otherwise it stays ink
     - icons never sit inside coloured circles or squares
     - emoji are never used as icons, and neither are Unicode characters

   The per-icon classes below exist because `style-src` has no 'unsafe-inline':
   a `style="--icon: url(...)"` attribute in body_html is silently refused, so
   the custom property has to come from a stylesheet. */
.icon {
  display: inline-block;
  width: var(--icon-size, 20px);
  height: var(--icon-size, 20px);
  flex: none;
  background: currentColor;
  -webkit-mask: var(--icon) center / contain no-repeat;
          mask: var(--icon) center / contain no-repeat;
}
.icon-16 { --icon-size: 16px; }
.icon-24 { --icon-size: 24px; }
.icon-32 { --icon-size: 32px; }

/* A browser without mask support would paint a solid currentColor block, which
   is far worse than no icon at all. Hide it there instead. */
@supports not ((-webkit-mask: none) or (mask: none)) {
  .icon { display: none; }
}

/* The per-icon `.i-<name>` rules are NOT here any more: core/icons.js derives
   them from public/img/icons/ at boot and serves them at /icons.css, linked by
   views/partials/site-styles.ejs. There were 46 of them, hand-written beside 46
   vendored glyphs, and the whole pinned Lucide set is vendored now -- 1,544
   rules is ~11KB gzipped, which does not belong inside the stylesheet every page
   loads and re-downloads whenever anything else in it changes. It also means the
   set can no longer disagree with itself: it is whatever is on disk. */

/* A third-party form embed. The iframe HubSpot injects has no intrinsic height
   until its own script measures the form, so the wrapper only sets a measure
   and a minimum — anything more specific fights the vendor's own layout. */
.form-embed { max-width: 46rem; min-height: 320px; }
.form-embed iframe { max-width: 100%; }

/* The GTM noscript iframe must exist but must never take up space. */
.gtm-noscript { display: none; visibility: hidden; }

/* ---- site footer ----
   Two optional rows above the copyright: cross-module links, then the
   per-module footer pages (show_in_footer), which is where legal documents
   live. Both collapse to nothing when empty. */
.foot-modules, .foot-links { display:flex; flex-wrap:wrap; justify-content:center; align-items:center; gap:4px 8px; margin:0 0 8px; }
.foot-links a { color: var(--site-muted, #516072); }
.foot-sep { color: var(--rule, #E1E7EC); }
.foot-copy { margin:0; }

/* ---- legal documents ----
   Privacy policy, terms and the CCPA notice are long-form prose reproduced from
   the source rather than laid out in cards. They need a reading measure and
   their own rhythm; everything else on the site is short-form. */
/* The starter-content banner. Built from theme tokens rather than literals so
   it follows a dark theme instead of staying a light box on a dark page — and
   deliberately loud, because its whole job is to be noticed and removed. Marked
   up as a class because style-src carries no 'unsafe-inline': a style attribute
   on this element would be silently refused and it would render as body copy. */
.notice {
  border: 1px solid var(--shade, var(--site-accent));
  border-left-width: 4px;
  background: var(--wash, rgba(0, 0, 0, .04));
  color: var(--site-primary);
  padding: .9rem 1.1rem;
  margin: 0 0 1.6rem;
  font-size: .95rem;
  line-height: 1.55;
  border-radius: 4px;
}
.notice strong { color: var(--site-primary); }

.legal-doc { max-width: 46rem; }
.legal-doc h2 { font-size: 1.25rem; letter-spacing: -.01em; margin: 2.2rem 0 .6rem; color: var(--site-primary); }
.legal-doc h2:first-child { margin-top: 0; }
.legal-doc h3 { font-size: 1.05rem; margin: 1.6rem 0 .4rem; color: var(--site-primary); }
/* The CCPA category grids. Wide by nature — three columns of prose — so the
   table scrolls inside its own box rather than pushing the page sideways. */
/* Same right-edge cue as the mobile nav strips: these tables are wider than a
   phone and scroll inside their own frame, which works but is invisible until
   you happen to swipe. `mask` rather than an overlay so it needs no extra
   element and survives any background.

   Only while it actually overflows would be better, but that needs JS to know;
   the fade sits over the table's own right padding on a wide screen, where the
   last column does not reach the edge, so it costs nothing there. */
.legal-doc .table-scroll { overflow-x: auto; margin: 0 0 1.4rem;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 30px), transparent);
          mask-image: linear-gradient(to right, #000 calc(100% - 30px), transparent); }
@media (min-width: 900px) {
  /* Wide enough that the tables fit; a permanent fade there is just fog. */
  .legal-doc .table-scroll { -webkit-mask-image: none; mask-image: none; }
}
.legal-doc table { border-collapse: collapse; min-width: 34rem; font-size: .92rem; }
.legal-doc th, .legal-doc td { border: 1px solid var(--rule, #E1E7EC); padding: .5rem .7rem; text-align: left; vertical-align: top; }
.legal-doc th { background: var(--wash, #F4F6F9); font-weight: 700; color: var(--site-primary); }
.legal-doc td { color: var(--site-muted, #516072); }
.legal-doc p { margin: 0 0 1rem; color: var(--site-muted, #516072); }
/* The revision date is metadata, not body copy, so it sits above the first
   heading and reads quieter than it. The Privacy Policy text refers to this
   line explicitly, which is why it is not merely decorative. */
.legal-revised { font-size: .85rem; letter-spacing: .04em; text-transform: uppercase;
  color: var(--site-muted, #516072); border-bottom: 1px solid var(--rule, #E1E7EC);
  padding-bottom: .9rem; margin: 0 0 1.6rem; }
.legal-doc ul { margin: 0 0 1rem 1.1rem; padding: 0; color: var(--site-muted, #516072); }
.legal-doc li { margin: 0 0 .35rem; }

/* ---- blog ---- */
/* .cards is defined above and reused as-is; only the additions live here. */
.card-img { width:100%; height:auto; border-radius:var(--site-radius,8px); margin-bottom:10px; }
.card h2 { margin:0 0 6px; font-size:1.12rem; }
.card h2 a { color:var(--site-primary); text-decoration:none; }
.card h2 a:hover { text-decoration:underline; }
.post-meta { margin-top:28px; padding-top:14px; border-top:1px solid var(--rule,#E1E7EC); }
.post-meta { margin-top:28px; padding-top:14px; border-top:1px solid #E1E7EC; }

/* ---- blog search and pager ----
   Tokens, not literals, so both follow the theme: a hardcoded border here is
   exactly the mistake that leaves a dark theme with light furniture. Where a
   value has no token of its own it is color-mixed against one, which is the
   convention themes/dusk/assets/theme.css already documents.

   Nothing here uses an inline style attribute, and nothing can: style-src
   carries no 'unsafe-inline', so the browser silently refuses one. */
.blog-search { display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin:0 0 24px; }
.blog-search-label { position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
.blog-search input[type="search"] {
  flex:1 1 240px; min-width:0; padding:.6rem .8rem; font:inherit; color:var(--site-ink);
  background:var(--site-paper); border:1px solid color-mix(in srgb, var(--site-ink) 20%, transparent);
  border-radius:var(--site-radius,14px);
}
.blog-search button {
  padding:.6rem 1.2rem; font:inherit; font-weight:var(--site-heading-weight,800); cursor:pointer;
  color:var(--site-paper); background:var(--site-accent); border:0; border-radius:var(--site-radius,14px);
}
.blog-search button:hover { background:color-mix(in srgb, var(--site-accent) 85%, var(--site-ink) 15%); }

.pager { display:flex; flex-wrap:wrap; gap:12px 20px; align-items:center; justify-content:space-between; margin-top:32px; padding-top:18px; border-top:1px solid color-mix(in srgb, var(--site-ink) 14%, transparent); }
.pager a { color:var(--site-primary); font-weight:700; text-decoration:none; }
.pager a:hover { text-decoration:underline; }
.pager-at { color:var(--site-muted,#516072); font-size:.9rem; }
/* The disabled end of the pager stays in the layout so "Newer"/"Older" do not
   jump position between page one and page two. */
.pager .is-off { color:var(--site-muted,#516072); opacity:.5; }

/* ---- comments ----
   Tokens throughout, so a dark theme needs no overrides for this block — the
   lesson from themes/dusk, whose card rules had to be added after the fact
   because site.css had hardcoded #fff. */
.comments { border-top: 1px solid color-mix(in srgb, var(--site-ink) 14%, transparent); }
.comment { padding: 16px 0; border-bottom: 1px solid color-mix(in srgb, var(--site-ink) 8%, transparent); }
.comment:last-of-type { border-bottom: 0; }
.comment-meta { margin: 0 0 6px; font-size: .88rem; color: var(--site-muted, #516072); }
.comment-meta strong { color: var(--site-ink); margin-right: 8px; }
.comment-body p { margin: 0 0 10px; }
.comment-body p:last-child { margin-bottom: 0; }
/* A reply is indented and rule-marked rather than boxed: one level of nesting
   does not need a second surface color. */
.comment-reply { margin: 14px 0 0 24px; padding: 12px 0 0 16px; border-bottom: 0; border-left: 2px solid color-mix(in srgb, var(--site-accent) 40%, transparent); }

.comment-form { margin-top: 28px; max-width: 640px; }
.comment-form h3 { margin: 0 0 14px; font-size: 1.1rem; color: var(--site-primary); }
.comment-form .field { margin-bottom: 14px; display: flex; flex-direction: column; gap: 4px; }
.comment-form label { font-weight: 700; font-size: .92rem; }
.comment-form input, .comment-form textarea {
  font: inherit; color: var(--site-ink); background: var(--site-paper);
  padding: .6rem .8rem; border-radius: var(--site-radius, 14px);
  border: 1px solid color-mix(in srgb, var(--site-ink) 20%, transparent);
}
.comment-form textarea { resize: vertical; }
.comment-form .muted { font-size: .85rem; color: var(--site-muted, #516072); }

.alert { padding: .8rem 1rem; border-radius: var(--site-radius, 14px); margin: 0 0 16px; }
.alert-ok { background: color-mix(in srgb, var(--site-accent) 12%, var(--site-paper)); border: 1px solid color-mix(in srgb, var(--site-accent) 40%, transparent); }
.alert-error { background: color-mix(in srgb, #c0392b 10%, var(--site-paper)); border: 1px solid color-mix(in srgb, #c0392b 45%, transparent); }

/* ---- comment reply disclosure ----
   A <details> rather than a JS toggle: the CSP cannot carry a nonce on an on*=
   attribute, and this needs no script at all. */
.comment-reply-toggle { margin-top: 10px; }
.comment-reply-toggle > summary {
  cursor: pointer; font-size: .85rem; font-weight: 700;
  color: var(--site-primary); width: fit-content;
}
.comment-reply-toggle > summary:hover { color: var(--site-accent); }
.comment-form-reply { margin-top: 12px; max-width: 520px; }
.comment-more { margin-top: 20px; }
.comment-more a { font-weight: 700; color: var(--site-primary); }
