/* css/pages/newsroom.css
   The newsroom index — a vertical list of dated posts. Each row is a
   link: date | title+teaser | arrow. The arrow slides on hover, the
   same micro-motion as the buttons and the .news-cat pills use the
   teal accent. Individual article pages come later (slugged), at
   which point .news-cat may move to a shared component. */

/* Year filter pills. Deliberately the same treatment as .lab-tabnav on the
   FungiFlex page so the two read as one component; the rules are restated
   rather than shared because .tab-btn is already scoped per page in this
   codebase (see cro.css and fungiflex.css). These are <a> elements, not
   buttons, so the reset below also has to undo link styling. */
.news-tabnav {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 3px;
  margin-bottom: 30px;
  padding: 4px;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: 0 1px 2px rgba(20, 28, 66, 0.05);
}
/* Sized to match the .news-cat category tags below — same 10px mono, same
   0.04em tracking, same 100px radius — so the filter row reads as part of the
   same family as the tags on each post rather than as a heavier control.
   Colours are deliberately NOT the tag palette: those encode category, and
   reusing them here would imply a meaning the years don't have.

   Vertical padding is 8px rather than the tags' 3px. The tags are passive
   labels; these are click targets, and at 3px the row would be ~16px tall —
   under any reasonable minimum for a pointer or thumb. 8px keeps it near 27px
   while leaving the type scale identical. */
.news-tabnav .tab-btn {
  padding: 8px 13px;
  border-radius: 100px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  text-decoration: none;
  color: var(--muted);
  /* Longer than the 0.18s used elsewhere, on an ease-out curve so the fill
     arrives quickly and settles rather than moving at a constant rate. */
  transition: color 0.28s cubic-bezier(0.33, 1, 0.68, 1),
    background-color 0.28s cubic-bezier(0.33, 1, 0.68, 1);
}
.news-tabnav .tab-btn:hover {
  color: var(--blue-deep);
  background: var(--blue-tint);
}
.news-tabnav .tab-btn:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}
/* Active listed after :hover so hovering the current year keeps the fill. */
.news-tabnav .tab-btn.active,
.news-tabnav .tab-btn.active:hover {
  color: var(--white);
  background: var(--blue);
}
/* This one line is what makes the highlight slide. Naming the active tab means
   the browser treats the old page's active tab and the new one as the same
   element across a view transition, so instead of the fill disappearing here
   and reappearing there, it animates between the two positions. Only ever one
   element carries the name at a time, which the name requires.
   The motion query keeps it out of the way for reduced-motion visitors — the
   swap in newsroom-tabs.js skips its view transition for them too. */
@media (prefers-reduced-motion: no-preference) {
  .news-tabnav .tab-btn.active {
    view-transition-name: news-year-pill;
  }
}
/* Once there are several years the pills outgrow one line on a phone — keep
   them on a single swipeable row instead of wrapping the container. */
@media (max-width: 600px) {
  .news-tabnav {
    display: flex;
    flex-wrap: nowrap;
    max-width: 100%;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .news-tabnav::-webkit-scrollbar {
    display: none;
  }
  .news-tabnav .tab-btn {
    flex: 0 0 auto;
    padding: 8px 11px;
  }
}

.news-list {
  display: flex;
  flex-direction: column;
}

.news-empty {
  padding: 28px 0;
  color: var(--muted);
}

.news-item {
  display: grid;
  grid-template-columns: 150px 1fr auto;
  gap: 24px;
  align-items: center;
  /* Extra horizontal padding pulled back with a matching negative
     margin, so the hover card can extend past the text without
     shifting the layout or the row separators. */
  padding: 24px 18px;
  margin: 0 -18px;
  border-radius: 14px;
  border-bottom: 1px solid var(--line);
  color: inherit;
  transition: background 0.2s ease, box-shadow 0.2s ease,
              transform 0.2s ease, border-color 0.2s ease;
}
.news-item:first-child {
  border-top: 1px solid var(--line);
}
.news-item:hover {
  /* Body is --blue-tint, so the row lifts to a white card: soft
     brand-blue shadow, a 1px rise, and the hairline separators fade
     out so the card floats cleanly above the list. */
  background: var(--white);
  box-shadow: 0 10px 28px rgba(32, 38, 94, 0.1);
  transform: translateY(-1px);
  border-color: transparent;
  position: relative;   /* sit above neighbouring rows' borders */
  z-index: 1;
}

.news-date {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted);
}

/* Title + teaser stack vertically regardless of the inline spans. */
.news-main {
  display: flex;
  flex-direction: column;
}
.news-cats {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
}
.news-cat {
  padding: 3px 9px;
  border-radius: 100px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  /* Default (teal) — also the fallback for any category not mapped
     below, so a new/unslugged cat still renders sensibly. */
  background: var(--teal-tint);
  color: var(--teal);
}

/* Per-category colors. Keyed off data-cat (the slugified category name
   set in the template loop). The palette is deliberately muted —
   tinted backgrounds with a same-hue darker text, matching the site's
   restrained teal/blue rather than six saturated primaries. Slugs come
   from Django's |slugify, so "Reference lab" -> "reference-lab". */
.news-cat[data-cat="fungiflex"]      { background: #E4F3F0; color: #157567; }  /* teal  — flagship product */
.news-cat[data-cat="mdx"]            { background: #EEF1FA; color: #2C368C; }  /* brand blue */
.news-cat[data-cat="investors"]      { background: #E9F5EE; color: #3E9E6B; }  /* green */
.news-cat[data-cat="team"]           { background: #F1EAF7; color: #7A459E; }  /* violet */
.news-cat[data-cat="reference-lab"]  { background: #F6EEE0; color: #99631A; }  /* amber/ochre */
.news-cat[data-cat="our-history"]    { background: #F6E9EF; color: #8A4A63; }  /* plum */
.news-title {
  margin-bottom: 5px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 17px;
  color: var(--blue-deep);
}
.news-teaser {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--muted);
}

.news-go {
  color: var(--muted);
  transition: transform 0.15s ease, color 0.15s ease;
}
.news-item:hover .news-go {
  transform: translateX(3px);
  color: var(--blue);
}

@media (max-width: 700px) {
  .news-item {
    grid-template-columns: 1fr;
    gap: 8px;
  }
  .news-go { display: none; }
}

/* Pager. Borrows the mono, pill-bordered ghost treatment from .article-foot
   .btn so it sits in the same family as the rest of the newsroom's controls. */
.news-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 36px;
}
.news-pager-btn {
  padding: 11px 18px;
  border: 1px solid var(--line);
  border-radius: 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
  text-decoration: none;
  color: var(--blue-deep);
  transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.news-pager-btn:hover {
  border-color: var(--blue);
  background: var(--white);
  color: var(--blue);
}
.news-pager-btn:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}
/* Kept in the layout rather than hidden, so the status text stays centred and
   the buttons don't jump position between the first and last page. */
.news-pager-btn.is-disabled {
  border-color: transparent;
  color: var(--muted);
  opacity: 0.45;
}
.news-pager-status {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted);
}
@media (max-width: 480px) {
  .news-pager {
    gap: 10px;
  }
  .news-pager-btn {
    padding: 10px 13px;
  }
}

/* ------------------------------------------------------------
   Individual article page — header (back link, category, title,
   date) above the article body. Reuses the .news-cat pill from the
   index for the category tag.
   ------------------------------------------------------------ */
.article-back {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 26px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted);
}
.article-back:hover { color: var(--blue); }

.article-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 20px;
}
.article-title {
  max-width: 760px;
  font-family: var(--font-display);
  font-weight: 600;
  /* Page-headline scale — reads at hero size like every other page's
     H1, rather than shrinking to a section heading. */
  font-size: clamp(32px, 5vw, 54px);
  line-height: 1.15;
  color: var(--blue);
}
.article-date {
  margin-top: 18px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--muted);
}

/* Article + side image, as two real columns. The image is beside the article
   rather than floated within it, so the text column is never narrowed — it
   keeps the same 700px measure it has on posts with no image, which is the
   whole point of doing this with a grid instead of a float.

   The 1180px wrap fits 700px of text, a 48px gap, and a ~380px image with room
   to spare. `align-items: start` keeps the image at the top of the column
   instead of stretching it down the length of the article. */
.article-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(240px, 380px);
  gap: 48px;
  align-items: start;
}
/* No image — collapse to one column so the article renders exactly as it did
   before this layout existed. */
.article-layout--textonly {
  display: block;
}
.article-side-image {
  margin: 0;   /* <figure> carries a default margin */
  /* Matches .article-body's own top offset so the image and the first
     paragraph start on the same line. */
  margin-top: 36px;
}
.article-side-image img {
  display: block;
  width: 100%;
  height: auto;
}
/* Below this the two columns would squeeze the text measure more than the
   side-by-side arrangement is worth, so stack: article first, image after. */
@media (max-width: 900px) {
  .article-layout {
    grid-template-columns: 1fr;
    gap: 28px;
  }
  .article-side-image {
    margin-top: 0;
  }
}

/* Body — a single readable measure. */
.article-body {
  max-width: 700px;
  margin-top: 36px;
}
.article-body p {
  margin: 0 0 20px;
  font-size: 16px;
  line-height: 1.75;
  color: var(--ink);
}
/* Pull-quote with the teal accent rule down the left edge. */
.article-body blockquote {
  margin: 28px 0;
  padding-left: 20px;
  border-left: 3px solid var(--teal);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 18px;
  line-height: 1.5;
  color: var(--blue-deep);
}
.article-body h3 {
  margin: 32px 0 12px;
  font-size: 18px;
}

/* Images inserted through the newsroom editor (CKEditor 5). Uploads are capped
   at 1600px wide (pages/storage.py), which is wider than this 700px column — so
   max-width here is what keeps them inside the measure instead of overflowing.
   CKEditor wraps block images in <figure class="image"> and inline ones in
   <span class="image-inline">, adding image-style-* classes for alignment. */
.article-body img {
  max-width: 100%;
  height: auto;
  border-radius: 6px;
  /* Matches the lifted-card shadow used across the site (contact.css,
     fungiflex-panel.css): blue-tinted and negatively spread so it reads as
     depth rather than a dark outline. */
  box-shadow: 0 14px 32px -18px rgba(32, 38, 94, 0.35);
}
/* fit-content makes the figure shrink-wrap its image instead of always filling
   the column. That's what lets the block-alignment classes below do anything:
   `margin-left: auto` can only push a box that's narrower than its container.
   Capped at 100% so a 1600px upload still stops at the 700px measure. */
.article-body figure.image {
  width: fit-content;
  max-width: 100%;
  margin: 28px 0;
}
/* `width: auto` rather than 100% — the latter stretches an image *up* to the
   column width, so a 400px graphic would render at 700px and look soft. With
   auto plus the max-width above, images never exceed their natural size and
   never overflow the measure. */
.article-body figure.image > img {
  display: block;
  width: auto;
}
/* Caption, when the author toggles one on. */
.article-body figure.image > figcaption {
  margin-top: 10px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
}
/* Wrap-text styles — the image floats and body copy runs beside it. These are
   the classes CKEditor emits for its "Side image" and wrap-text alignments
   (verified against the shipped bundle). */
.article-body figure.image.image-style-side,
.article-body figure.image.image-style-align-right {
  float: right;
  max-width: 50%;
  margin: 6px 0 20px 28px;
}
.article-body figure.image.image-style-align-left {
  float: left;
  max-width: 50%;
  margin: 6px 28px 20px 0;
}
/* Break-text styles — the image sits on its own line with no text beside it,
   aligned within the column. No float, so nothing needs clearing.
   No max-width here on purpose: these match CKEditor's own widths, so the
   editor preview and the published page agree. An image as wide as the column
   fills it and the alignment is a no-op, which is the correct outcome — there
   is nowhere to align it to. A narrower one visibly shifts. */
.article-body figure.image.image-style-block-align-left {
  margin: 28px auto 28px 0;
}
.article-body figure.image.image-style-block-align-right {
  margin: 28px 0 28px auto;
}
.article-body figure.image.image-style-align-center {
  margin: 28px auto;
}
/* A float that isn't cleared can overlap whatever follows the article body
   (the .article-foot block, in these posts), so close it off. */
.article-body::after {
  content: "";
  display: block;
  clear: both;
}
/* Inline images sit in the text flow, so keep them from breaking line height. */
.article-body .image-inline img {
  vertical-align: baseline;
}
/* Click-to-enlarge overlay — see static/js/lightbox.js. The zoom cursor is
   applied by that script only to images whose file is larger than the size
   they're displayed at, so it never appears on something it can't enlarge. */
/* Not scoped to .article-body — the lead image is outside it, and this
   stylesheet only loads on newsroom pages, so a bare class is safe here. */
img.zoomable {
  cursor: zoom-in;
}
img.zoomable:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 3px;
}
/* Full-viewport, transparent frame: the backdrop does the dimming and any
   click that lands on the dialog rather than the image counts as "outside". */
dialog.lightbox {
  max-width: 100vw;
  max-height: 100vh;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: hidden;
}
dialog.lightbox[open] {
  display: flex;
  align-items: center;
  justify-content: center;
}
dialog.lightbox::backdrop {
  background: rgba(6, 20, 33, 0.9);
}
.lightbox-img {
  max-width: 92vw;
  max-height: 90vh;
  width: auto;
  height: auto;
  border-radius: 4px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
  cursor: zoom-out;
}
.lightbox-close {
  position: fixed;
  top: 16px;
  right: 20px;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  font-size: 24px;
  line-height: 1;
  color: #fff;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.lightbox-close:hover {
  border-color: rgba(255, 255, 255, 0.6);
  background: rgba(255, 255, 255, 0.2);
}
.lightbox-close:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 2px;
}

/* A floated image beside a 16px line at phone widths leaves an unreadable
   column of text, so drop every float to full width. */
@media (max-width: 640px) {
  .article-body figure.image,
  .article-body figure.image.image-style-side,
  .article-body figure.image.image-style-align-left,
  .article-body figure.image.image-style-align-right,
  .article-body figure.image.image-style-block-align-left,
  .article-body figure.image.image-style-block-align-right,
  .article-body figure.image.image-style-align-center {
    float: none;
    max-width: 100%;
    margin: 24px 0;
  }
}
.article-foot {
  margin-top: 44px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}
/* CTA button — matches the example article's mono, pill-bordered ghost
   treatment (with a sliding arrow) rather than the site's default solid
   ghost button. Scoped to .article-foot so other buttons are untouched. */
.article-foot .btn {
  gap: 9px;
  padding: 13px 22px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: transparent;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 13px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--blue-deep);
  transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.article-foot .btn:hover {
  border-color: var(--blue);
  background: var(--blue-tint);
  color: var(--blue-deep);
}
.article-foot .btn-arrow {
  transition: transform 0.15s ease;
}
.article-foot .btn:hover .btn-arrow {
  transform: translateX(3px);
}
