/* assets/css/content-blocks.css — public renderer for Content blocks.
   Uses storefront design tokens (--bg-card, --border, --text, --accent). */

.cb-rich-text { line-height: 1.7; font-size: 1rem; }
.cb-rich-text p { margin: 0 0 1rem; }
/* Body-text link rule lives in storefront.css (always loaded on storefront
   pages) so both CMS-authored and hand-written static pages inherit it. */
/* Headings inside rich-text inherit the same per-level bottom rhythm as
   standalone heading blocks (see .cb-heading rules below). No top margins —
   the preceding block already supplies the gap. */
.cb-rich-text h1 { margin: 0 0 2rem;   font-weight: 700; }
.cb-rich-text h2 { margin: 0 0 1.5rem; font-weight: 700; }
.cb-rich-text h3 { margin: 0 0 1rem;   font-weight: 600; }
.cb-rich-text h4,
.cb-rich-text h5,
.cb-rich-text h6 { margin: 0 0 1rem; font-weight: 600; }
/* padding-left (not margin-left) so list-style-position:outside renders bullets
   inside the ul, not in the parent's space. The storefront global * { padding: 0 }
   reset zeroes default ul padding, so we must restore it explicitly. */
.cb-rich-text ul, .cb-rich-text ol { padding-left: 1.6em; margin: 0 0 1rem; }
.cb-rich-text li { margin: 0 0 0.4em; }
.cb-rich-text figcaption { font-size: 0.85rem; color: var(--text-muted, #6e7681); }

/* Q&A drop-cap typography (interview style) */
.cb-rich-text .question { padding-left: 32px; position: relative; font-style: italic; margin-bottom: 0.4em; }
.cb-rich-text .question::before { content: 'Q'; position: absolute; left: 0; top: -2px; font-size: 1.6em; font-weight: 700; color: var(--accent, #f5f5f5); }
.cb-rich-text .answer { padding-left: 32px; position: relative; }
.cb-rich-text .answer::before { content: 'A'; position: absolute; left: 0; top: -2px; font-size: 1.6em; font-weight: 700; color: var(--text-muted, #6e7681); }
.cb-rich-text .interviewee { font-weight: 700; color: var(--accent, #f5f5f5); margin-right: 4px; }

/* Heading blocks: zero top margin (preceding block supplies the gap),
   per-level bottom rhythm so a clean h1→p→h2→p flow reads predictably. */
.cb-heading { margin: 0; }
h1.cb-heading { margin-bottom: 2rem; }
h2.cb-heading { margin-bottom: 1.5rem; }
h3.cb-heading { margin-bottom: 1rem; }
.cb-heading--center { text-align: center; }
.cb-heading--right { text-align: right; }
.cb-heading__kicker { display: block; font-size: 0.7em; text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-muted, #6e7681); margin-bottom: 0.3em; }

/* Main line + optional second line stack (both blocks so they wrap onto their
   own lines). Colours/sizes are applied per-line via classes below or an inline
   style from the block (custom colour). Keep these values in sync with
   includes/blocks/heading.php and the JS preview in content-builder.js. */
.cb-heading__text { display: block; }
.cb-heading__text--sm  { font-size: 1.5rem; }
.cb-heading__text--lg  { font-size: clamp(2rem, 5vw, 2.5rem); }
.cb-heading__text--xl  { font-size: clamp(2.4rem, 6vw, 3.25rem); line-height: 1.1; }
.cb-heading__text--xxl { font-size: clamp(2.75rem, 7vw, 4rem); line-height: 1.05; }

.cb-heading__sub { display: block; font-weight: 600; font-size: 1.35rem; line-height: 1.25; }
.cb-heading__sub--sm { font-size: 1.1rem; }
.cb-heading__sub--lg { font-size: 1.75rem; }
.cb-heading__sub--xl { font-size: clamp(1.6rem, 4vw, 2.25rem); }
.cb-heading__sub--gap-none { margin-top: 0; }
.cb-heading__sub--gap-sm   { margin-top: 0.25rem; }
.cb-heading__sub--gap-md   { margin-top: 0.6rem; }
.cb-heading__sub--gap-lg   { margin-top: 1.1rem; }

/* Space-below overrides the per-level default rhythm above. */
.cb-heading--below-none { margin-bottom: 0; }
.cb-heading--below-sm   { margin-bottom: 0.75rem; }
.cb-heading--below-md   { margin-bottom: 1.5rem; }
.cb-heading--below-lg   { margin-bottom: 2.5rem; }

/* No base vertical margin — image blocks space via the surrounding blocks' own
   margins like the rest of the content system (the 1.5em here caused uneven
   gaps, esp. inside columns where margins don't collapse). The float variants
   below keep their functional gutters. */
.cb-image img { max-width: 100%; height: auto; display: block; border-radius: 4px; }
.cb-image--center { text-align: center; }
.cb-image--center img { margin-left: auto; margin-right: auto; }
.cb-image--left  { float: left; max-width: 40%; margin: 0 1.5em 1em 0; }
.cb-image--right { float: right; max-width: 40%; margin: 0 0 1em 1.5em; }
.cb-image--full img { width: 100%; }
.cb-image figcaption { font-size: 0.85rem; color: var(--text-muted, #6e7681); margin-top: 4px; }

/* Width control (figure sizing, independent of alignment). 'auto' = no class =
   legacy behaviour. Compound selectors so these beat the float max-width above
   regardless of source order; centered figures also get auto side margins so a
   shrunk image stays centered. */
.cb-image.cb-image--w-25  { max-width: 25%; }
.cb-image.cb-image--w-50  { max-width: 50%; }
.cb-image.cb-image--w-75  { max-width: 75%; }
.cb-image.cb-image--w-100 { max-width: 100%; }
.cb-image--center.cb-image--w-25,
.cb-image--center.cb-image--w-50,
.cb-image--center.cb-image--w-75,
.cb-image--center.cb-image--w-100 { margin-left: auto; margin-right: auto; }

/* News/editorial articles only: block images get 2em top/bottom breathing room
   so they aren't squished against surrounding text/blocks. Scoped to
   .news-article (shared by news/vlog/interview/page) so storefront + product
   imagery keep their own tighter base spacing. Floated images are excluded —
   they already carry text-wrap gutters from the align rules above. */
.news-article .cb-image:not(.cb-image--left):not(.cb-image--right) {
    margin-top: 2em;
    margin-bottom: 2em;
}

.cb-image-text { display: grid; gap: 1.5em; margin: 2em 0; align-items: start; }
/* DOM order matches visual order. Ratios anchor to image column regardless
   of side: --ratio-33 = image takes 1/3, --ratio-66 = image takes 2/3. */
.cb-image-text--left.cb-image-text--ratio-50,
.cb-image-text--right.cb-image-text--ratio-50 { grid-template-columns: 1fr 1fr; }
.cb-image-text--left.cb-image-text--ratio-33  { grid-template-columns: 1fr 2fr; }
.cb-image-text--left.cb-image-text--ratio-66  { grid-template-columns: 2fr 1fr; }
.cb-image-text--right.cb-image-text--ratio-33 { grid-template-columns: 2fr 1fr; }
.cb-image-text--right.cb-image-text--ratio-66 { grid-template-columns: 1fr 2fr; }
.cb-image-text__figure img { width: 100%; height: auto; border-radius: 4px; display: block; }
.cb-image-text__link { display: block; }
.cb-image-text__link:hover img { opacity: 0.92; transition: opacity 0.15s ease; }
@media (max-width: 720px) {
  .cb-image-text { grid-template-columns: 1fr !important; }
}

.cb-gallery { display: grid; gap: 8px; margin: 2em 0; }
.cb-gallery--cols-2 { grid-template-columns: repeat(2, 1fr); }
.cb-gallery--cols-3 { grid-template-columns: repeat(3, 1fr); }
.cb-gallery--cols-4 { grid-template-columns: repeat(4, 1fr); }
.cb-gallery__item img { width: 100%; height: auto; border-radius: 3px; display: block; }

.cb-video { margin: 2em 0; }
/* Inside a side-by-side columns block, drop the vertical margin so the video
   top-aligns with adjacent text instead of being pushed 2em down. */
.cb-columns__col .cb-video { margin: 0; }
/* Black 1px border so white video content (presentations, demos) is
   visibly bounded against light card/page backgrounds across the shop. */
.cb-video iframe, .cb-video video { width: 100%; aspect-ratio: 16 / 9; border: 1px solid #000; border-radius: 4px; }

.cb-button { margin: 2em 0; }
.cb-button--center { text-align: center; }
.cb-button--right  { text-align: right; }
.cb-button__cta {
  display: inline-block; padding: 12px 28px; border-radius: 4px;
  font-weight: 600; text-decoration: none;
}
.cb-button__cta--primary   { background: var(--accent, #f5f5f5); color: #fff; }
.cb-button__cta--secondary { background: transparent; color: var(--accent, #f5f5f5); border: 2px solid var(--accent, #f5f5f5); }

.cb-pullquote {
  margin: 2em 0; padding: 1.5em 1.5em 1.5em 2em;
  border-left: 4px solid var(--accent, #f5f5f5);
  font-size: 1.25rem; font-style: italic;
}
.cb-pullquote--large  { font-size: 1.6rem; }
.cb-pullquote--accent { background: var(--accent, #f5f5f5); color: #fff; border-left: none; border-radius: 6px; }
.cb-pullquote cite { display: block; margin-top: 0.5em; font-size: 0.85rem; font-style: normal; color: var(--text-muted, #6e7681); }
.cb-pullquote--accent cite { color: rgba(255, 255, 255, 0.85); }

.cb-divider { border: none; }
.cb-divider--line   { border-top: 1px solid var(--border, #ddd); }
.cb-divider--dotted { border-top: 1px dotted var(--border, #ddd); }
.cb-divider--sm     { margin: 1em 0; }
.cb-divider--md     { margin: 2em 0; }
.cb-divider--lg     { margin: 3em 0; }
.cb-divider--blank.cb-divider--sm { height: 1em; }
.cb-divider--blank.cb-divider--md { height: 2em; }
.cb-divider--blank.cb-divider--lg { height: 3em; }

/* Columns block now renders through the Skeleton 12-col grid (.cb-columns-grid
   .row > .{span}.columns, styled in feature-blocks.css). No wrapper margin —
   the inner blocks (paragraphs/headings) carry their own margins, which space
   the row against its neighbors. The legacy .cb-columns--* rules are kept below
   for any content rendered by an older code path. */
.cb-columns { display: grid; gap: 2em; margin: 2em 0; }
.cb-columns--50-50 { grid-template-columns: 1fr 1fr; }
.cb-columns--33-67 { grid-template-columns: 1fr 2fr; }
.cb-columns--67-33 { grid-template-columns: 2fr 1fr; }
.cb-columns--33-33-33 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 720px) { .cb-columns { grid-template-columns: 1fr !important; } }

.cb-section--full {
  /* Full-bleed: extend to viewport edges even when the article body is column-constrained.
     Article body should provide a containing element with max-width. */
  width: 100vw;
  margin-left: calc(-50vw + 50%);
}
.cb-section__inner.container { padding-left: 24px; padding-right: 24px; }

.cb-product { display: flex; gap: 1em; align-items: center; padding: 12px; border: 1px solid var(--border, #ddd); border-radius: 6px; text-decoration: none; color: inherit; }
.cb-product img { width: 100px; height: 100px; object-fit: cover; border-radius: 4px; }
.cb-product__name { font-weight: 600; }
.cb-product__price { color: var(--accent, #f5f5f5); }
.cb-product__cta { font-size: 0.85rem; color: var(--accent, #f5f5f5); }

.cb-event-tile { display: block; border: 1px solid var(--border, #ddd); border-radius: 6px; overflow: hidden; text-decoration: none; color: inherit; }
.cb-event-tile img { width: 100%; height: 200px; object-fit: cover; display: block; }
.cb-event-tile__body { padding: 12px; }
.cb-event-tile__name { font-weight: 600; }
.cb-event-tile__date { color: var(--accent, #f5f5f5); font-size: 0.9rem; }
.cb-event-tile__venue { color: var(--text-muted, #6e7681); font-size: 0.85rem; }

.cb-embed { margin: 2em 0; }
.cb-embed iframe { max-width: 100%; }

/* News listing + article shells */
/* top/bottom only — the shorthand's `0` for left/right was cancelling the
   .container side gutter, so the title + cards hit the screen edge on mobile. */
.news-index { padding-top: 2em; padding-bottom: 4em; }
.news-index__title { margin-bottom: 1em; }

/* Newsletter registration banner (Pardot iframe) — collapsed = a clickable
   blue bar; open = fades to white with the signup form centered on top. */
.news-register { background: #094f79; border-radius: var(--radius, 8px); margin-bottom: 2em; overflow: hidden; }
.news-register__toggle {
  display: block; width: 100%; padding: 1rem 1.5rem;
  background: transparent; border: 0; color: #fff; font: inherit; font-size: 0.95rem;
  text-align: center; text-decoration: underline; text-underline-offset: 2px; cursor: pointer;
}
.news-register.is-open { background: linear-gradient(180deg, #094f79 0%, #094f79 10%, #ffffff 55%); }
.news-register__drawer { max-height: 0; overflow: hidden; transition: max-height 0.55s ease; }
.news-register.is-open .news-register__drawer { max-height: 700px; }
.news-register__form {
  max-width: 560px; margin: 1rem auto 1.5rem; padding: 1.5rem;
  background: #fff; border-radius: 10px;
}
.news-register__form iframe { width: 100%; border: 0; }
.news-grid { display: grid; gap: 1.5em; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); margin-bottom: 2em; }
.news-card { display: block; border: 1px solid var(--border, #ddd); border-radius: 6px; overflow: hidden; text-decoration: none; color: inherit; transition: border-color .15s ease; }
.news-card:hover { border-color: var(--accent, #f5f5f5); }
.news-card__hero { aspect-ratio: 16 / 9; background-size: cover; background-position: center; position: relative; }
/* Reserved space for cards without a hero — keeps title rows aligned
   across the grid. Subtle tint so it reads as a deliberate empty state
   rather than an accidental gap. */
.news-card__hero--placeholder { background: var(--bg-surface, #f5f5f5); }
.news-card__play {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-size: 2.5rem; color: rgba(255,255,255,0.92);
  text-shadow: 0 2px 12px rgba(0,0,0,0.5);
  transition: transform .15s ease;
}
.news-card:hover .news-card__play { transform: scale(1.08); }
.news-card__duration {
  position: absolute; bottom: 8px; right: 8px;
  background: rgba(0,0,0,0.7); color: #fff;
  font-size: 0.7rem; padding: 2px 6px; border-radius: 3px;
}
.news-card__interviewee {
  font-size: 0.85rem; color: var(--text-secondary, #4a4a4a);
  margin: 4px 0 8px;
}
.news-card__body { padding: 14px; }
.news-card__date { font-size: 0.8rem; color: var(--text-muted, #6e7681); }
.news-card__title { font-size: 1.1rem; margin: 4px 0 8px; }
.news-card__excerpt { font-size: 0.9rem; color: var(--text-muted, #6e7681); }
.news-pagination { display: flex; justify-content: space-between; gap: 8px; }

/* Phones: keep news cards 2-up (the 280px min would otherwise drop to one
   full-width column) and compact the card so the pair reads cleanly. */
@media (max-width: 640px) {
  .news-grid { grid-template-columns: repeat(2, 1fr); gap: 0.85em; }
  .news-card__body { padding: 10px; }
  .news-card__date { font-size: 0.72rem; }
  .news-card__title { font-size: 0.95rem; margin: 3px 0 0; }
  .news-card__excerpt { display: none; }
}

/* Top spacing matches the product page's breadcrumb gap (2rem). */
.news-article { padding: 2rem 0 4em; }
/* Match the storefront .container width (--container-max 1320px minus 24px
   padding each side = 1272px content) so news articles align with product pages. */
.news-article__topbar {
  width: 100%; max-width: var(--container-max, 1320px);
  margin: 0 auto 0.5em; padding-inline: 24px; box-sizing: border-box;
}
.news-article__date {
  font-size: 0.8rem; color: var(--text-muted, #6e7681);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.news-article__subtitle {
  margin-top: 0.4em; font-size: 1.05rem; line-height: 1.4;
  color: var(--text-secondary, #4a4a4a);
}
.news-article__interviewee {
  margin-top: 0.4em; font-size: 1rem;
}
.news-article__interviewee-label {
  font-size: 0.75rem; color: var(--text-muted, #6e7681);
  text-transform: uppercase; letter-spacing: 0.08em; margin-right: 0.4em;
}
.news-article__interviewee-role {
  color: var(--text-muted, #6e7681); font-weight: 400;
}
.cb-video--vlog-hero, .cb-video--interview-hero { margin: 0 0 2em; }
.news-article__body {
  width: 100%; max-width: var(--container-max, 1320px);
  margin: 0 auto; padding-inline: 24px; box-sizing: border-box;
}

/* ─── Dark-mode article variant (per-article toggle) ──────────────────────
   When marketing wants a high-contrast feel, the article wrapper gets the
   --theme-dark modifier. Black backdrop spans the full viewport width via
   100vw + the centering trick used on full-bleed sections; text and child
   block overrides force white-on-black inside the article zone only —
   storefront header/footer stay default. */
.news-article--theme-dark {
  background: #000;
  color: #fff;
  width: 100vw;
  margin-left: calc(-50vw + 50%);
  padding: 2.5em 0 4em;
}
.news-article--theme-dark .news-article__date { color: #a3a3a3; }
/* Dark theme — the whole article reads on a black canvas, not just the
   text. Matches the 2017 .news-story inline style="background:#000;color:#fff".
   Applies to vlog articles imported from the 2017 site (theme='dark') and
   any future news/vlog/interview authored with theme=dark. */
.news-article--theme-dark {
  background: #000;
  color: #fff;
}
.news-article--theme-dark .news-article__topbar,
.news-article--theme-dark .news-article__date,
.news-article--theme-dark .news-article__body { color: inherit; }

.news-article--theme-dark .cb-rich-text { color: #fff; }
/* Sub-headings typed into the rich text (raw h2–h6, no .cb-heading class)
   inherit the container's white — EXCEPT the global `h1–h6 { color:
   var(--text-primary) }` rule puts an explicit dark color on the elements,
   which wins over inheritance. Force them white on the dark theme. */
.news-article--theme-dark .cb-rich-text h1,
.news-article--theme-dark .cb-rich-text h2,
.news-article--theme-dark .cb-rich-text h3,
.news-article--theme-dark .cb-rich-text h4,
.news-article--theme-dark .cb-rich-text h5,
.news-article--theme-dark .cb-rich-text h6 { color: #fff; }
/* Inline links — soft blue, no underline (matches the dark feature-block links),
   instead of white + underlined which read as plain body text. */
.news-article--theme-dark .cb-rich-text a:not(.btn) { color: #60a5fa; text-decoration: none; }
.news-article--theme-dark .cb-rich-text a:not(.btn):hover { color: #93c5fd; }
.news-article--theme-dark .cb-heading { color: #fff; }
.news-article--theme-dark .cb-heading__kicker { color: #a3a3a3; }
.news-article--theme-dark .cb-pullquote { border-left-color: #fff; color: #fff; }
.news-article--theme-dark .cb-pullquote cite { color: #a3a3a3; }
.news-article--theme-dark .cb-divider--line   { border-top-color: #404040; }
.news-article--theme-dark .cb-divider--dotted { border-top-color: #404040; }
.news-article--theme-dark .cb-button__cta--primary {
  background: #fff; color: #000;
}
.news-article--theme-dark .cb-button__cta--secondary {
  background: transparent; color: #fff; border-color: #fff;
}
.news-article--theme-dark .cb-product { border-color: #404040; }
.news-article--theme-dark .cb-event-tile { border-color: #404040; }

/* ─── 2017 vlog-era styles (ported) ────────────────────────────────
   The vlog articles imported from /vlog/article*.html depend on a few
   class names that were defined inline in /vlog/index.php in 2017:
   .quote-block, .show-title, .grey-quote, .quote-head, plus the helpers
   .centered-text and .img-100. Scoped to .cb-rich-text so they only
   affect ported article bodies, never the broader storefront. */
.cb-rich-text .centered-text { text-align: center; }
.cb-rich-text .img-100       { width: 100%; }

/* Storefront's global `img { display: block; }` ignores text-align on the
   parent, so centered-text imgs need explicit auto margins. Same trick we
   use for the .text-center utility elsewhere. Includes anchor-wrapped
   images (`<p class="centered-text"><a><img/></a></p>` is the 2017 pattern). */
.cb-rich-text .centered-text img { margin-left: auto; margin-right: auto; }

.cb-rich-text .show-title { font-style: italic; }

/* Responsive video wrapper — 2017's .video-container is the classic
   "padding-bottom: 56.25% to lock 16:9" pattern. The 2017 vlog files
   wrap every YouTube iframe in <div class="video-container">; without
   this, the iframes render at their default 300x150 (or hard-coded
   700x395 on older articles) and look completely wrong against the
   surrounding body width. */
.cb-rich-text .video-container {
  position: relative;
  padding-bottom: 56.25%;
  height: 0;
  overflow: hidden;
  margin: 1em 0 2em;
  border: 1px solid #000;
}
.cb-rich-text .video-container iframe,
.cb-rich-text .video-container object,
.cb-rich-text .video-container embed {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Quote block — verbatim port of the 2017 inline <style> from vlog/index.php.
   The giant quotation-mark glyph in vlog-quote.png sits at the box's top-left
   corner; in 2017, authors used a leading `<p>&nbsp;</p>` inside each column
   to push real content down past the glyph. Don't add container padding here
   — it would compete with that pattern and break the spacing rhythm authors
   are used to. */
.cb-rich-text .quote-block {
  background: url('/ShopFSI/assets/images/vlog-quote.png') no-repeat #272727;
  border: 4px solid #323232;
  border-radius: 40px;
  margin: 1.5rem 0 2rem;
  padding-bottom: 30px;
}
.cb-rich-text .quote-block h5,
.cb-rich-text .quote-block p { padding: 0 14px; }
.cb-rich-text .quote-head {
  font-style: italic;
  margin-bottom: 0 !important;
}
.cb-rich-text .grey-quote { color: #c0c0c0; }

/* ─── Downloads block ────────────────────────────────────────────────
   Grid (default) of file cards or stacked list, used on Media Kits,
   Tech Resources, etc. */
.cb-downloads { margin: 1.5em 0; }
.cb-downloads__heading {
  margin: 0 0 0.75em;
  font-size: 1.15rem;
  font-weight: 600;
}
.cb-downloads__list {
  display: grid;
  gap: 1rem;
}
.cb-downloads--grid .cb-downloads__list {
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.cb-downloads--list .cb-downloads__list {
  grid-template-columns: 1fr;
}
.cb-downloads__card {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-card);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.cb-downloads__card:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
}
.cb-downloads--list .cb-downloads__card {
  flex-direction: row;
  align-items: center;
}
.cb-downloads__thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-surface);
  border-radius: 6px;
  overflow: hidden;
  aspect-ratio: 4 / 3;
  flex-shrink: 0;
}
.cb-downloads--list .cb-downloads__thumb {
  width: 80px;
  height: 60px;
  aspect-ratio: auto;
}
.cb-downloads__thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #fff;
}
.cb-downloads__icon {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  background: var(--bg-elevated);
  padding: 0.4em 0.8em;
  border-radius: 4px;
}
.cb-downloads__body {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}
.cb-downloads__label {
  font-weight: 600;
  font-size: 0.95rem;
}
.cb-downloads__desc {
  font-size: 0.85rem;
  color: var(--text-secondary);
  line-height: 1.4;
}
.cb-downloads__meta {
  font-size: 0.78rem;
  color: var(--text-muted);
  font-family: var(--font-mono);
  margin-top: auto;
}

/* Admin builder — downloads items repeater */
.cb-downloads-items { display: flex; flex-direction: column; gap: 8px; }
.cb-dl-item {
  border: 1px solid var(--border-default);
  border-radius: 4px;
  padding: 8px 10px;
  background: var(--bg-tertiary);
}
.cb-dl-item__head {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 6px;
}
.cb-dl-item__num {
  font-size: 0.78rem;
  color: var(--text-muted);
  font-family: var(--font-mono);
  margin-right: auto;
}
.cb-dl-item__head button {
  padding: 2px 6px;
  font-size: 0.85rem;
  background: var(--bg-secondary);
  border: 1px solid var(--border-default);
  border-radius: 3px;
  cursor: pointer;
  color: var(--text-primary);
}
.cb-dl-item__head button:disabled { opacity: 0.3; cursor: not-allowed; }
.cb-dl-item__head .cb-dl-item__remove { color: var(--danger); }
.cb-dl-item__field { display: flex; flex-direction: column; gap: 3px; margin-top: 6px; }
.cb-dl-item__field label { font-size: 0.78rem; color: var(--text-muted); font-weight: 600; }
.cb-dl-item__filename { font-size: 0.78rem; color: var(--text-secondary); font-family: var(--font-mono); }


/* ─── Tables inside rich_text blocks ──────────────────────────────────
   Stock <table> markup pasted into rich_text (e.g., reference data on
   Tech Resources) needs sensible defaults — borders, padding, header
   distinction, and breathing room above/below. */
.cb-rich-text table {
  width: 100%;
  border-collapse: collapse;
  margin: 1.25rem 0 1.75rem;
  font-size: 0.92rem;
  background: var(--bg-card, transparent);
  /* Drop the rounded-corner clipping treatment — the combination of
     border-radius + overflow: hidden + border-collapse: collapse was clipping
     the last row's bottom border in WebKit, leaving the table visually
     unbounded. Plain rectangular borders render predictably. */
  border-top: 1px solid var(--border, #27272a);
  border-left: 1px solid var(--border, #27272a);
  border-right: 1px solid var(--border, #27272a);
}
.cb-rich-text thead {
  background: var(--bg-elevated, rgba(255,255,255,0.04));
}
.cb-rich-text th,
.cb-rich-text td {
  padding: 0.6rem 0.85rem;
  text-align: left;
  border-bottom: 1px solid var(--border, #27272a);
  vertical-align: middle;
}
.cb-rich-text th {
  font-weight: 600;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary, #a1a1aa);
}
.cb-rich-text tbody tr:nth-child(even) td {
  background: rgba(255, 255, 255, 0.02);
}
/* Tables that have no thead (e.g., the Color Space data) — first row
   isn't visually a header but should still feel anchored. */
.cb-rich-text table:not(:has(thead)):not(:has(caption)) tbody tr:first-child td {
  font-weight: 600;
  color: var(--text-primary, #f5f5f5);
  background: var(--bg-elevated, rgba(255,255,255,0.04));
}

/* Fallback caption style for any raw <caption> inside a rich_text block. */
.cb-rich-text caption {
  caption-side: top;
  padding: 0.6rem 0.85rem;
  background: var(--bg-elevated, rgba(255,255,255,0.06));
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--text-primary, #f5f5f5);
  text-align: left;
  letter-spacing: 0.01em;
  border-bottom: 1px solid var(--border, #27272a);
}
/* Mobile: allow horizontal scroll if a table is too wide. */
@media (max-width: 640px) {
  .cb-rich-text {
    /* Wrap each table in its own scroll context by allowing the table to
       overflow the rich_text body. The body already has padding. */
    overflow-x: auto;
  }
  .cb-rich-text table {
    min-width: 0;
    font-size: 0.85rem;
  }
  .cb-rich-text th,
  .cb-rich-text td {
    padding: 0.5rem 0.6rem;
  }
}

/* Page article body spacing. Block-to-block flow comes from the blocks' OWN
   margins (paragraphs, headings, lists, etc. all carry margin-bottom), so there
   is deliberately NO generic `> * + *` gap — it stacked on top of those inner
   margins and caused uneven spacing (e.g. an extra 0.5rem above a rich-text
   block following a columns row). Only headings + dividers get an explicit
   top-level bump for emphasis, scoped to DIRECT children so they don't leak
   into nested containers (columns/sections), where blocks space themselves. */
.news-article__body > .cb-heading { margin-top: 1.75rem; }
.news-article__body > .cb-divider { margin: 2rem 0; }

/* Dark theme: keep the data legible on a black backdrop. */
.news-article--theme-dark .cb-rich-text table {
  background: rgba(255,255,255,0.02);
  border-color: #404040;
}
.news-article--theme-dark .cb-rich-text th,
.news-article--theme-dark .cb-rich-text td {
  border-color: #404040;
}
.news-article--theme-dark .cb-rich-text thead {
  background: rgba(255,255,255,0.06);
}

/* ─── Structured table block (cb-table) ─────────────────────────────
   Schema-driven tables authored via the Table block. The CSS shape
   mirrors the rich_text-table styling that came before (caption, banner
   rows, alternating row tint, mobile horizontal scroll) but anchored
   to the .cb-table* class set so we can retire .cs-table and .ref-table
   once /tech-resources is migrated. */
.cb-table {
  width: 100%;
  border-collapse: collapse;
  margin: 1.25rem 0 1.75rem;
  font-size: 0.92rem;
  background: var(--bg-card, transparent);
  /* Top/sides only — the last row's td border-bottom draws the bottom edge.
     border-radius + overflow: hidden + collapse was clipping last-row borders
     in WebKit, making the table look unterminated. */
  border-top: 1px solid var(--border, #27272a);
  border-left: 1px solid var(--border, #27272a);
  border-right: 1px solid var(--border, #27272a);
}
.cb-table caption {
  caption-side: top;
  padding: 0.6rem 0.85rem;
  background: var(--bg-elevated, rgba(255,255,255,0.06));
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--text-primary, #f5f5f5);
  text-align: left;
  letter-spacing: 0.01em;
  border-bottom: 1px solid var(--border, #27272a);
}
.cb-table thead {
  background: var(--bg-elevated, rgba(255,255,255,0.04));
}
.cb-table th,
.cb-table td {
  padding: 0.6rem 0.85rem;
  text-align: left;
  border-bottom: 1px solid var(--border, #27272a);
  vertical-align: middle;
}
.cb-table th {
  font-weight: 600;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary, #a1a1aa);
}
.cb-table tbody tr:nth-child(even) td { background: rgba(255, 255, 255, 0.02); }

/* Banner row spans all columns and reads as a meta line — italic, lighter,
   centered. Reset the alternating-row tint for banners. */
.cb-table__banner td {
  font-size: 0.85rem;
  color: var(--text-secondary, #a1a1aa);
  text-align: center;
  background: rgba(255, 255, 255, 0.02);
  font-style: italic;
}
.cb-table tbody tr.cb-table__banner:nth-child(even) td { background: rgba(255, 255, 255, 0.02); }

/* Centered variant: caption + headers + data all centered. Used for the
   2-column reference cards (color-space tables). */
.cb-table--centered caption,
.cb-table--centered th,
.cb-table--centered td { text-align: center; }

/* Per-cell alignment utilities. The base .cb-table th/td rule pins
   text-align: left at specificity 0,2,1, which beats the global .text-center
   (0,1,0) — these scoped overrides match that specificity so authors can
   align individual cells (or whole rows) by adding the class. Both
   `text-center` (storefront utility) and `centered-text` (feature-block
   utility) are honored so authors don't have to remember which applies. */
.cb-table th.text-center,
.cb-table td.text-center,
.cb-table th.centered-text,
.cb-table td.centered-text,
.cb-table tr.text-center th,
.cb-table tr.text-center td,
.cb-table tr.centered-text th,
.cb-table tr.centered-text td { text-align: center; }
.cb-table th.text-right,
.cb-table td.text-right,
.cb-table tr.text-right th,
.cb-table tr.text-right td { text-align: right; }
.cb-table th.text-left,
.cb-table td.text-left,
.cb-table tr.text-left th,
.cb-table tr.text-left td { text-align: left; }

/* Mobile: just shrink padding/font. Setting display: block on a <table> at
   this breakpoint was breaking the table's own internal layout, collapsing
   short tables (e.g. "Monitor / Quick Guide") into a single-column stack.
   For wide tables that genuinely need horizontal scrolling, wrap in
   <div class="cb-table-scroll">. */
@media (max-width: 640px) {
  .cb-table {
    font-size: 0.85rem;
  }
  .cb-table th,
  .cb-table td { padding: 0.5rem 0.6rem; }
}
.cb-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin: 1.25rem 0 1.75rem;
}
.cb-table-scroll > table { margin: 0; }

/* ─── Horizontal/vertical-pair tables (e.g. AutoCal probe compatibility) ──
   Mark the wide layout with .cb-table--h, the tall alternate with
   .cb-table--v. Below ~900px, the horizontal one hides and the vertical
   one shows so the same data fits the smaller viewport. */
.cb-table--v { display: none; }
@media (max-width: 900px) {
  .cb-table--h { display: none; }
  .cb-table--v { display: table; }
}

/* Dark theme parity with the rich_text-table rules. */
.news-article--theme-dark .cb-table {
  background: rgba(255,255,255,0.02);
  border-color: #404040;
}
.news-article--theme-dark .cb-table th,
.news-article--theme-dark .cb-table td { border-color: #404040; }
.news-article--theme-dark .cb-table thead,
.news-article--theme-dark .cb-table caption { background: rgba(255,255,255,0.06); }

/* ShopFSI — Service Request (RMA) form
 * Two-column layout that collapses to single column on narrow viewports.
 * Reuses storefront's .form-input / .form-label / .form-error / .form-hint
 * so the dark/light theming Just Works. */

.support-page {
  padding: 2rem 0 4rem;
}
.support-page__title {
  font-size: 2rem;
  margin: 0.5rem 0 0.25rem;
}
.support-page__subtitle {
  color: var(--text-muted);
  margin: 0 0 2rem;
  max-width: 60ch;
}

.support-form { margin: 0; }

.support-form__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 32px;
}
@media (max-width: 720px) {
  .support-form__grid { grid-template-columns: 1fr; gap: 24px; }
}

.support-form__col {
  border: 0;
  padding: 0;
  margin: 0;
}
.support-form__col legend {
  font-size: 1.05rem;
  font-weight: 600;
  margin: 0 0 1rem;
  padding: 0;
  color: var(--text-primary);
}
.support-form__col legend:not(:first-of-type) {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
}

.support-form__footer {
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
  text-align: center;
}
.support-form__notice {
  font-size: 1.05rem;
  margin: 0 0 0.5rem;
  color: var(--text-primary);
}
.support-form__footer p {
  color: var(--text-muted);
  max-width: 60ch;
  margin: 0 auto 1.5rem;
}
.support-form__captcha {
  display: flex;
  justify-content: center;
  margin: 0 auto 1.5rem;
}
.support-form__submit {
  min-width: 240px;
}

.support-honeypot {
  position: absolute !important;
  left: -9999px !important;
  top: -9999px !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.support-success {
  border: 1px solid var(--border);
  background: var(--bg-card, transparent);
  border-radius: var(--radius);
  padding: 2rem;
  text-align: center;
}
.support-success h2 { margin: 0 0 0.75rem; }
.support-success p { margin: 0 0 1rem; color: var(--text-secondary); }
.support-success__note { color: var(--text-primary); }

.support-error {
  border: 1px solid var(--danger, #b91c1c);
  background: var(--danger-bg, rgba(185, 28, 28, 0.08));
  color: var(--text-primary);
  padding: 0.75rem 1rem;
  border-radius: var(--radius);
  margin: 0 0 1.5rem;
}

/* ─── Calibration Guide Picker block ──────────────────────────────────
   3-dropdown selector + revealed guide table. Mirrors the 2017
   /calibration page's tier1/tier2/tier3 cascade, restyled for ShopFSI. */
.cb-calguide {
  display: grid;
  grid-template-columns: 1fr 1.4fr;
  gap: 2.5rem;
  margin: 1.5rem 0;
}
@media (max-width: 720px) {
  .cb-calguide { grid-template-columns: 1fr; gap: 1.5rem; }
}
.cb-calguide__controls { display: flex; flex-direction: column; }
.cb-calguide__label {
  font-weight: 600;
  margin: 0 0 0.4rem;
  color: var(--text-primary);
}
.cb-calguide__select {
  margin-bottom: 1rem;
  width: 100%;
  max-width: 360px;
  padding: 10px 14px;
  font-size: 0.95rem;
  background: var(--bg-surface);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.cb-calguide__panes { min-height: 100px; }
.cb-calguide__guide {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem 1.5rem;
  background: var(--bg-card, transparent);
}
.cb-calguide__guide[hidden] { display: none; }
.cb-calguide__title { margin: 0 0 0.25rem; }
.cb-calguide__subtitle { color: var(--text-muted); margin: 0 0 1rem; }
.cb-calguide__table { width: 100%; border-collapse: collapse; }
.cb-calguide__table th,
.cb-calguide__table td {
  padding: 0.6rem 0.85rem;
  text-align: left;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.cb-calguide__table th {
  font-weight: 600;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-secondary);
}
/* Link color now handled by the article-body rule near the top of this file. */

/* ─── Calibration partner cards (.cb-cal-partner) ────────────────────
   Authored as rich_text inside columns(33/33/33). For uniform per-row
   heights, the column itself has to flex-stretch the card down through the
   rich_text wrapper. NOTE: columns render as Skeleton `.columns` (via
   .cb-columns-grid), NOT `.cb-columns__col` — that class is 0× in the output,
   so the old rules were dead and cards sat short + center-staggered. Target the
   real class, and pair with `.row:has(.cb-cal-partner){align-items:stretch}`
   (feature-blocks.css) which makes the columns themselves equal height — same
   fix as the rental-partner cards. */
.columns:has(.cb-cal-partner) {
  display: flex;
  flex-direction: column;
}
.columns:has(.cb-cal-partner) > .cb-rich-text {
  display: flex;
  flex-direction: column;
  flex: 1;
}
.cb-cal-partner {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  flex: 1;
  background: var(--bg-card, transparent);
  overflow: hidden;
}
.cb-cal-partner__head {
  background: #0a0a0a;
  color: #fff;
  text-align: center;
  padding: 0.7rem 1rem;
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
}
.cb-cal-partner__contact {
  text-align: center;
  padding: 1rem 1rem 0.5rem;
  margin: 0;
  font-size: 0.9rem;
  color: var(--text-secondary);
  line-height: 1.5;
}
.cb-cal-partner__info {
  padding: 0.5rem 1rem 1rem;
  font-size: 0.92rem;
  color: var(--text-primary);
  /* flex-grow pushes the logo block to the bottom of the card so all logos
     in a row sit on the same baseline regardless of how much info text each
     card has. */
  flex: 1;
}
.cb-cal-partner__logo {
  text-align: center;
  padding: 0 1rem 1.25rem;
  margin: 0;
  /* Reserve a uniform vertical slot so cards without a logo still align
     visually with cards that have one. Sized for text-heavy logos. */
  min-height: 130px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.cb-cal-partner__logo img {
  max-width: 100%;
  max-height: 110px;
  width: auto;
  height: auto;
  object-fit: contain;
}

/* ─── Rental partner cards (.cb-rental-partner) ──────────────────────
   Authored as rich_text inside columns(33/33/33) or columns(50/50). Black
   logo strip on top, contact + monitors body below, matching the 2017
   /rental-partners layout. */
/* NOTE: the columns render as Skeleton `.four.columns` (via .cb-columns-grid),
   NOT `.cb-columns__col` — that class appears 0× in the output, so these rules
   were dead and the card never filled its column (cards sat short + top-aligned
   → the iPad stagger). Target the real class, scoped to rental cards. Pair with
   `.row:has(.cb-rental-partner){align-items:stretch}` (feature-blocks.css) which
   makes the columns themselves equal height. */
.columns:has(.cb-rental-partner) {
  display: flex;
  flex-direction: column;
}
.columns:has(.cb-rental-partner) > .cb-rich-text {
  display: flex;
  flex-direction: column;
  flex: 1;
}
.cb-rental-partner {
  border: 1px solid #000;
  display: flex;
  flex-direction: column;
  flex: 1;
  background: var(--bg-card, transparent);
  overflow: hidden;
}
.cb-rental-partner__logo {
  background: #000;
  height: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.5rem 1rem;
  margin: 0;
}
.cb-rental-partner__logo img {
  max-width: 90%;
  max-height: 64px;
  width: auto;
  height: auto;
  object-fit: contain;
}
.cb-rental-partner__logo--inverted {
  background: #fff;
  border-bottom: 1px solid #000;
}
.cb-rental-partner__name {
  color: #fff;
  text-align: center;
  font-weight: 600;
  margin: 0;
  padding: 0 0.5rem;
}
.cb-rental-partner__body {
  padding: 1rem;
  /* flex:1 grows the body so the .cb-rental-partner__models sibling
     anchors to the bottom of every card — even cards with shorter contact
     blocks have the gear inventory at the same vertical position as their
     row neighbors. */
  flex: 1;
  text-align: center;
  font-size: 0.92rem;
}
.cb-rental-partner__body p {
  margin: 0 0 0.5rem;
  line-height: 1.5;
}
.cb-rental-partner__body p:last-child { margin-bottom: 0; }

/* Wide-card body split (Rentex, VER): cities/phones on the left, contact on
   the right. The models bar still spans the card's full width below. */
.cb-rental-partner__body--split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
  text-align: left;
}
.cb-rental-partner__body--split > * { min-width: 0; }
.cb-rental-partner__cities {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 1rem;
  row-gap: 0.45rem;
  align-items: baseline;
}
.cb-rental-partner__cities > .cb-rental-partner__phone { text-align: right; color: var(--text-muted); }

.cb-rental-partner__models {
  /* Sibling of __body — `flex: 1` on the body pushes this div to the bottom
     of the card. Same vertical position across every card in a row. */
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 0.88rem;
  text-align: center;
}


/* Vlog quote-block (legacy 2017 inline style, lifted into a global rule so
   ported article bodies render correctly). Scoped to .news-article__body so
   the generic .quote-block / .show-title / .grey-quote / .quote-head class
   names don't leak into other contexts. */
.news-article__body .quote-block {
    background: url('/uploads/media/vlog-quote.png') no-repeat #272727;
    border: 4px solid #323232;
    border-radius: 40px;
    margin-bottom: 2em;
}
.news-article__body .quote-block h5,
.news-article__body .quote-block p {
    padding: 0 14px;
}
.news-article__body .show-title {
    font-style: italic;
}
.news-article__body .grey-quote {
    color: #c0c0c0;
}
.news-article__body .quote-head {
    font-style: italic;
    margin-bottom: 0 !important;
}

/* ─── Interview (legacy /interviews/ port) styles ──────────────────────
   The 2017 interviews page used an inline <style> block with classes like
   def-bg / def-question / def-answer / def-blue-text / definition-img-insert /
   question-italic. They're scoped here to .news-article__body so the ported
   bodies render correctly without leaking the class names site-wide. */

/* Full-bleed light-blue slab (Definition Magazine Bram interview).
   Breaks out of .news-article__body's container via negative margins,
   re-pads inwards so prose stays at container width. */
.news-article__body .def-bg-wrap {
    background: #d4f0fb;
    border-top: 2px solid #00afee;
    border-bottom: 2px solid #00afee;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    padding: 3rem max(1rem, calc(50vw - 50%));
    margin-bottom: 2rem;
}

/* Round Q/A pills for question/answer lines. Shared shape rules + per-color. */
.news-article__body .def-question,
.news-article__body .def-answer {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    font-size: 16px;
    font-weight: 600;
    font-style: normal;
    color: #d4f0fb;
    margin-right: 8px;
    margin-top: 4px;
    float: left;
    line-height: 1;
    box-sizing: border-box;
}
.news-article__body .def-question { background: #000; }
.news-article__body .def-answer   { background: #00afee; }

.news-article__body .def-blue-text { color: #00afee; }
.news-article__body .question-italic { font-style: italic; }
.news-article__body .organization { text-align: left; font-size: 0.75em; line-height: 0.9em; }

/* Image-with-overlay-text insert (Definition Bram interview).
   The legacy CSS referenced XMP650-large.jpg directly. Imported copy is in
   /uploads/media; the background-image is set inline in the body HTML, so
   only the structural rules need to live here. */
.news-article__body .definition-img-insert {
    color: #fff;
    background-size: cover;
    aspect-ratio: 323/199;
    width: 100%;
}
