/* ═══════════════════════════════════════════════════════════════════════════
   CONTENT / ARCHIVE PAGES — page-group rules
   2026 design system — Geomage Website (www.geomage.com)

   Loaded ALONGSIDE main.css by the three list/archive pages:
     /news/                                                    frontend/news.html
     /about-us/articles/  +  /blogs/                            frontend/articles.html
     /seismic-software/multifocusing-processing-case-studies/   frontend/case_studies.html

   Only what the design-system components do NOT already provide lives here:

     · .hero margin-top reset — these three pages carry no .subnav, so the
       component's 116px header+subnav offset has to come back to 70px
       (the same override pages/{home,services,tech,support}.css write).
     · .icon-fill      — brand glyphs inside a .btn. components/buttons-2026.css
                         sets `stroke: currentColor; fill: none` on .btn svg,
                         which is right for the line icons and wrong for a solid
                         wordmark glyph (LinkedIn).
     · .news__*        — the LinkedIn post feed. The card/wrapper/status class
                         names are created at runtime by assets/js/news.js, so
                         they are the JS contract and cannot be renamed here.
     · .art*           — the publication archive cards (title, abstract, the
                         journal/author chips, the PDF action). components/
                         mod-cards .mod is image-first and .diff is a 12.5px
                         icon card; neither reads at 26 abstracts of 0–1300
                         characters.
     · .cs-case scroll-margin-top — see the FRAGMENT-TARGET OFFSET note below.
     · .cs-*           — the case-studies world map (which replaces the retired
                         jQuery map.js modal stack: the pins are now in-page
                         anchors), the jump rail, the per-card <details>
                         disclosure that replaces the modal, and the
                         before/after figure pair that replaces the retired
                         twentytwenty drag handle. Same images, same "Before" /
                         "After" labels (the plugin's own before_label /
                         after_label). The only JS left on any of it is
                         assets/js/case-studies-2026.js, which opens the targeted
                         <details> and scrolls to the card; the markup works
                         without it, one extra click.
     · .csm*            — the popup a MAP PIN opens (PIN POPUP, at the foot of
                         this sheet): the same case study, centred, with its pair
                         as the full drag slider. Built at runtime by
                         assets/js/case-studies-2026.js — nothing the server
                         sends carries these classes, and a pin with JS off is
                         still the `#cs-mN` link it is authored as.

   Everything else on these three pages is a component: .hero (+ .hero__inner
   --narrow), .eyebrow, .btn, .block / .container, .modules__grid / .mod, .cta,
   and the header/footer includes.

   KNOWN DUPLICATION, ledgered for the cleanup task: .cs-compare* is a third
   copy of the before/after pair (pages/services.css .svc-compare*, pages/
   tech.css .cmp*). Page-group sheets cannot see one another and promoting a
   shared components/compare.css into main.css would edit two already-approved
   sheets for no behaviour change.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── HERO OFFSET (no subnav on these pages) ──────────────────────────────── */
.hero { margin-top: 70px; }

/* ── SOLID BRAND GLYPH IN A BUTTON ───────────────────────────────────────── */
.btn svg.icon-fill { fill: currentColor; stroke: none; width: 16px; height: 16px; }

/* ═══════════════════════════════════════════════════════════════════════════
   NEWS  —  /news/
   ═══════════════════════════════════════════════════════════════════════════ */

/* Admin panel: hidden for everyone except the allow-listed editors in news.js */
.news__admin { margin-bottom: 28px; }
.news__admin-toggle { font-family: var(--font-body); }
.news__admin-form {
  margin-top: 14px; padding: 18px;
  background: var(--bg-white); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
}
.news__admin-form input {
  flex: 1 1 320px; min-width: 0;
  font-family: var(--font-body); font-size: 13.5px; color: var(--text-dark);
  padding: 11px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg);
}
.news__admin-form input:focus-visible { outline: 2px solid var(--orange); outline-offset: 1px; }
.news__admin-message { flex-basis: 100%; margin: 0; font-size: 12.5px; color: var(--text); }

/* Feed. news.js appends one .news__card per post; the iframe it builds is a
   fixed 504px wide, so the track is sized around that rather than around a
   fluid column. align-items:start because each embed carries its own height
   (news.js reads post.height) — a stretched row would leave white space under
   the shorter cards. */
.news__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 20px; align-items: start; }
.news__card {
  background: var(--bg-white); border: 1px solid var(--border);
  border-radius: var(--radius-lg); overflow: hidden;
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease), transform .25s var(--ease);
}
.news__card:hover { border-color: var(--orange); box-shadow: var(--shadow-md); transform: translateY(-3px); }
.news__embed-wrapper { display: flex; justify-content: center; padding: 18px 14px; }
.news__embed-wrapper iframe { width: 100%; max-width: 504px; border: none; display: block; }
.news__status {
  grid-column: 1 / -1; text-align: center;
  padding: 56px 20px; font-size: 14.5px; color: var(--text);
  background: var(--bg-white); border: 1px dashed var(--border); border-radius: var(--radius-lg);
}

/* ═══════════════════════════════════════════════════════════════════════════
   ARTICLES  —  /about-us/articles/  and  /blogs/
   ═══════════════════════════════════════════════════════════════════════════ */

.art__grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; align-items: start; }
.art {
  display: flex; flex-direction: column;
  background: var(--bg-white); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 26px 26px 24px;
  position: relative; overflow: hidden;
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease), transform .25s var(--ease);
}
.art::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: var(--orange); transform: scaleX(0); transform-origin: left;
  transition: transform .3s var(--ease);
}
.art:hover { border-color: var(--orange); box-shadow: var(--shadow-md); transform: translateY(-3px); }
.art:hover::before { transform: scaleX(1); }

.art__t {
  font-family: var(--font-head); font-size: 17px; font-weight: 700;
  line-height: 1.3; color: var(--text-dark); margin-bottom: 12px;
}
.art__d { font-size: 13.5px; line-height: 1.7; color: var(--text); margin-bottom: 16px; }

/* Journal / year and author chips — the legacy <span class="info"> pair. Some
   entries carry only one of the two, so both render in the same neutral chip
   rather than being typed by position. */
.art__meta { display: flex; flex-wrap: wrap; gap: 7px; margin: 0 0 18px; }
.art__info {
  font-size: 11px; font-weight: 600; line-height: 1.4; color: var(--text-light);
  background: var(--bg); border: 1px solid var(--border);
  border-radius: 100px; padding: 4px 11px;
}
.art__info:first-child { color: var(--orange); background: var(--orange-light); border-color: var(--orange-border); }

/* The PDF action sits at the card foot. `align-items: start` on the grid (and no
   height:100% here) sizes every card to its own content: these abstracts run from
   0 to ~1300 characters, so a stretched row would open a 300px hole under the
   short entries just to line the buttons up. */
.art__dl { align-self: flex-start; margin-top: auto; padding: 10px 20px; font-size: 13px; }

/* ═══════════════════════════════════════════════════════════════════════════
   CASE STUDIES  —  /seismic-software/multifocusing-processing-case-studies/
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── WORLD MAP ───────────────────────────────────────────────────────────── */
.cs-map {
  background: #0d1117; border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 22px 22px 8px; overflow: hidden;
}
/* Wide content scrolls inside its own box, never the page. */
.cs-map__wrapper { overflow-x: auto; }
/* The inline SVG ships `fill="#ececec"` / `stroke="black"` presentation
   attributes; CSS outranks those, so the landmasses are restated here on the
   design system's own media ground. */
.cs-map__svg { display: block; width: 100%; height: auto; min-width: 640px; fill: #1b2531; stroke: #2c384a; }
.cs-map__svg .map__point-inactive { fill: #2c384a; }

/* Pins. map.js and its jQuery/twentytwenty modal stack are retired: each pin is
   now an anchor to the case study's own card further down the page. */
.cs-pin { cursor: pointer; }
.cs-pin image { transition: transform .18s var(--ease); transform-box: fill-box; transform-origin: center bottom; }
.cs-pin:hover image,
.cs-pin:focus-visible image { transform: scale(1.28); }
.cs-pin:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }

.cs-legend {
  display: flex; align-items: center; gap: 6px;
  margin-top: 14px; padding-bottom: 14px;
  font-size: 12px; color: rgba(255, 255, 255, .62);
}
.cs-legend img { width: 14px; height: 14px; }

/* ── JUMP RAIL (the legacy slider's 8 thumbnails) ────────────────────────── */
.cs-rail { background: var(--bg-white); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); padding: 26px 0 30px; }
.cs-rail .eyebrow { margin-bottom: 16px; }
.cs-rail__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.cs-rail__item {
  display: flex; flex-direction: column; text-decoration: none; overflow: hidden;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-md);
  transition: border-color .22s var(--ease), box-shadow .22s var(--ease), transform .22s var(--ease);
}
.cs-rail__item:hover { border-color: var(--orange); box-shadow: var(--shadow-sm); transform: translateY(-2px); }
.cs-rail__item picture { display: block; }
.cs-rail__item img { width: 100%; height: 104px; object-fit: cover; object-position: center; display: block; background: #0d1117; }
.cs-rail__t { padding: 11px 14px 0; font-size: 12.5px; font-weight: 700; line-height: 1.3; color: var(--text-dark); }
.cs-rail__item:hover .cs-rail__t { color: var(--orange); }
.cs-rail__d { padding: 4px 14px 12px; font-size: 11px; color: var(--text-light); }

/* ── CASE-STUDY CARDS ────────────────────────────────────────────────────── */
/* Cards size to their own content: components/mod-cards .modules__grid stretches
   a row, so an opened panel would leave its row-mate as a tall empty box. */
.cs-grid { align-items: start; }
/* Text-first card: number, title, and a native <details> holding the seismic
   pair. components/mod-cards .mod drops its top padding for a media strip that
   is not there any more, so it has to come back. */
.cs-case { padding: 26px 30px 0; }
.cs-case .mod__name { font-size: 16.5px; margin-bottom: 0; }

/* ── FRAGMENT-TARGET OFFSET ──────────────────────────────────────────────── */
/* The only fragment targets in this page group are the 15 .cs-compare panels the
   map pins and the jump rail point at; assets/js/case-studies-2026.js opens the
   panel's <details> and then scrollIntoView()s the CARD, which honours this.
   Because the handler scrolls AFTER the panel has expanded there is no longer a
   zero-height-box race to compensate for, so this is simply "clear the fixed
   header" — the same 86px / 76px (70px + 16px, 60px + 16px) the sibling page
   sheets write as `article[id] { scroll-margin-top }`, and it lands the card at
   the same place the previous, measured-around-the-race value did.
   It is a CLASS rule on purpose: .cs-case exists only on case_studies.html, so
   /news/ and /about-us/articles/ + /blogs/ — which have no fragment target at
   all — are no longer handed a `:root { scroll-padding-top }` that would change
   how every scroll on those pages, reverse-tab focus included, comes to rest. */
.cs-case { scroll-margin-top: 86px; }
/* The targeted card is the one a map pin or a rail thumb just jumped to. */
.cs-case:has(.cs-compare:target) { border-color: var(--orange); box-shadow: 0 0 0 1px var(--orange-border); }
.cs-case:has(.cs-compare:target)::before { transform: scaleX(1); }

/* Disclosure. The legacy page kept every pair inside a jQuery modal that only
   opened on a pin click, so nothing but the map loaded up front; a native
   <details> keeps that (Chromium/Firefox do not fetch a lazy image inside a
   closed one). A pin is still ONE click to the comparison because
   assets/js/case-studies-2026.js opens the targeted panel on hashchange — not
   because Chrome happens to auto-expand a fragment target, which no other
   engine could be relied on to do. Same primitive components/faq.css uses on
   /q-a/. */
.cs-open { margin: 20px -30px 0; border-top: 1px solid var(--border); }
.cs-open__s {
  list-style: none; cursor: pointer; padding: 14px 30px;
  font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--orange);
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
}
.cs-open__s::-webkit-details-marker { display: none; }
.cs-open__s::after { content: '+'; font-size: 19px; font-weight: 400; line-height: 1; transition: transform .2s var(--ease); }
.cs-open[open] .cs-open__s::after { transform: rotate(45deg); }
.cs-open__s:hover { background: var(--orange-light); }

/* ── CASE COPY ───────────────────────────────────────────────────────────── */
/* Summary. Two sentences under the title, from the case's own write-up in the
   Geomage Case Studies brochure. It is also what assets/js/case-studies-2026.js
   lifts into the pin popup's head — its descriptor lookup already reads
   `.mod__d, .mod__desc, .cs-case__d`, and pages/content.css already styles the
   result as .csm__desc — so this class name is the one that travels. Keep it
   short for that reason: the popup head is not a place for three paragraphs. */
.cs-case__d {
  margin-top: 10px;
  font-size: 13.5px; line-height: 1.62;
  color: var(--text-light);
}

/* Geological analysis. INSIDE the disclosure and below the pair, because it is
   the caption for the images: it is only wanted once the reader has opened the
   comparison, and a card that carried it up top would push every sibling in the
   grid down for text most visitors are not reading yet. The popup clones
   `.cs-compare` alone, so nothing here travels into it. */
.cs-geo { padding: 17px 30px 21px; border-top: 1px solid var(--border); }
.cs-geo__t {
  font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--orange); margin-bottom: 9px;
}
.cs-geo p { font-size: 13px; line-height: 1.68; color: var(--text-light); }
.cs-geo p + p { margin-top: 10px; }

/* ── BEFORE / AFTER FIGURE PAIR ──────────────────────────────────────────── */
/* Uncropped: on these cards the seismic pair IS the case study — there is no
   detail page holding a full-size copy — so the halves keep their natural
   aspect instead of being trimmed to a uniform teaser strip.

   STACKED, not side by side. Side by side inside a two-up card leaves ~280 CSS
   px per seismic panel; Task 10's review already ruled ~340px too small for a
   panel that is the evidence. Stacking gives each half the card's full ~560px. */
.cs-compare { display: grid; grid-template-columns: 1fr; }
.cs-compare__half { position: relative; overflow: hidden; background: #0d1117; border-top: 1px solid var(--border); }
.cs-compare__half img { width: 100%; height: auto; display: block; }
.cs-compare__label {
  position: absolute; top: 9px; left: 9px; z-index: 1;
  font-size: 9px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: #fff; background: rgba(10, 18, 35, .78); padding: 3px 9px; border-radius: 100px;
}
.cs-compare__half--after .cs-compare__label { background: var(--orange); }

/* ── RESPONSIVE ──────────────────────────────────────────────────────────── */
@media (max-width: 980px) {
  .art__grid { grid-template-columns: 1fr; }
  .cs-rail__grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 720px) {
  .hero { margin-top: 60px; }
  .cs-case { scroll-margin-top: 76px; }
  .news__grid { grid-template-columns: 1fr; }
  .cs-map { padding: 14px 14px 4px; }
  /* The map keeps its 640px scroll width, so the pins would render ~11px wide;
     scaled from the tip so they stay on their coordinates. */
  .cs-pin image { transform: scale(1.5); }
  .cs-pin:hover image,
  .cs-pin:focus-visible image { transform: scale(1.85); }
  .cs-rail__item img { height: 84px; }
  .art { padding: 22px 20px 20px; }
}

@media (max-width: 480px) {
  .cs-rail__grid { grid-template-columns: 1fr; }
  .news__admin-form { flex-direction: column; align-items: stretch; }
  .news__admin-form .btn { justify-content: center; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PIN POPUP  —  .csm*, built by assets/js/case-studies-2026.js

   A click on a world-map pin opens the case study here instead of scrolling to
   its card: number, title, and the pair as the full drag slider. Kept as one
   block at the foot of the sheet, its own responsive rules included, because it
   is one component that exists only on this page and only at runtime — no rule
   below styles anything the server sends.

   THE SIZE RULE. The brief is "the slider takes three quarters of the screen",
   and the popup must still fit on that screen. Both at once is one line: the
   dialog is 75vw wide UNLESS 75vw would make it taller than 85vh, and the
   height it would reach is width ÷ aspect ratio + the head above it. So

       width = min(75vw, (85vh − head) × ratio)

   with `--csm-ratio` set per case by the JS from the pair's authored
   width/height attributes (known before an image is fetched, so the dialog
   opens at its final size), and `--csm-chrome` the measured head height. At
   1440 × 900 the first term wins and the stage is exactly 75vw; on a short
   window the second takes over and the popup shrinks, in the image's own
   proportions, rather than running off the screen. `max-height` on the dialog
   is the backstop for the one case the arithmetic cannot see — a title that
   wraps to more lines than `--csm-chrome` allows for.

   Below 720px, 75vw would leave a phone with a ~290px-wide seismic panel, which
   is not a comparison anyone can read. The popup takes 92vw there instead: the
   same intent (nearly the whole screen), adapted to the screen — noted as a
   deliberate departure from the 3/4 figure, not an oversight.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Backdrop. Above the fixed header (1000) and the dropdowns, below the download
   modals (download-modals.css: 10000/10001) and clear of the auth modal shell
   (components/modals.css: 9000/9001), which this page never opens at the same
   time. */
.csm {
  position: fixed;
  inset: 0;
  z-index: 9400;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 14px;
  background: rgba(10, 18, 35, .74);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

.csm__dialog {
  --csm-ratio: 1.6;    /* replaced per case; the site's pairs are 1.0 – 1.64 */
  --csm-chrome: 76px;  /* .csm__head + the 3px top rule — keep the two in step */
  position: relative;
  z-index: 9401;
  display: flex;
  flex-direction: column;
  width: min(75vw, calc((85vh - var(--csm-chrome)) * var(--csm-ratio)));
  max-height: 85vh;
  overflow: hidden;
  background: var(--bg-white);
  border: 1px solid var(--border);
  /* The orange top rule .hero, .cta and the auth modal all carry. */
  border-top: 3px solid var(--orange);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

/* ── HEAD ────────────────────────────────────────────────────────────────── */
.csm__head {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  flex: 0 0 auto;
  padding: 15px 17px 13px;
  border-bottom: 1px solid var(--border);
}
.csm__text { min-width: 0; }
.csm__num {
  font-size: 10.5px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  line-height: 1.4; color: var(--orange);
}
.csm__title {
  font-family: var(--font-head);
  font-size: 18px; font-weight: 700; line-height: 1.25;
  color: var(--text-dark);
}
.csm__desc { margin-top: 4px; font-size: 12.5px; line-height: 1.5; color: var(--text-light); }

.csm__close {
  flex: 0 0 auto;
  width: 34px; height: 34px; margin-left: auto; padding: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-light);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.csm__close svg {
  width: 13px; height: 13px; display: block;
  fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round;
}
.csm__close:hover {
  color: var(--orange);
  border-color: var(--orange);
  background: var(--orange-light);
}

/* ── STAGE ───────────────────────────────────────────────────────────────── */
/* Full-bleed to the dialog edge, so the stage IS the 75vw the brief asks for
   rather than 75vw minus padding, and on the pair's own dark ground — the same
   #0d1117 the cards' pairs sit on. `flex: 0 1 auto` + `min-height: 0` is what
   lets `max-height` on the dialog bite; it never does at the sizes the width
   rule produces. */
.csm__stage {
  position: relative;
  flex: 0 1 auto;
  min-height: 0;
  width: 100%;
  aspect-ratio: var(--csm-ratio);
  overflow: hidden;
  background: #0d1117;
}

/* The widget compare-2026.js builds inside the clone. Three inline styles have
   to be out-ranked, and only these three:
     · `max-width` — it caps the widget at the 660px-tall box the in-card pairs
       stand at, which is the whole point everywhere else and exactly wrong for
       a popup whose size is the feature;
     · `display: flex; align-items: center` on the container it centres in —
       harmless, but it means the widget does not inherit the stage's height, so
       the height is restated down the chain.
   Everything else about the widget — the panes, the divider, the handle, the
   labels — is components/compare.css, untouched. */
.csm__stage > .cs-compare { height: 100%; }
.csm__stage .cmp2026 {
  width: 100%;
  height: 100%;
  max-width: none !important;
}
.csm__stage .cmp2026__stage { height: 100%; }

/* Before the upgrade lands (one frame, or longer if the images are cold) the
   clone is still the authored stacked pair. It is clipped to the stage box
   rather than allowed to push the dialog to twice its height, so the popup
   never resizes under the reader. */
.csm__stage .cs-compare:not([data-cmp="on"]) { overflow: hidden; }

/* ── MOTION ──────────────────────────────────────────────────────────────── */
/* Opt-in, like components/compare.css: under `prefers-reduced-motion: reduce`
   there is no animation to cancel — the popup simply appears. */
@media (prefers-reduced-motion: no-preference) {
  .csm { animation: csm-fade .18s var(--ease); }
  .csm__dialog { animation: csm-rise .18s var(--ease); }
}
@keyframes csm-fade { from { opacity: 0; } }
@keyframes csm-rise { from { opacity: 0; transform: translateY(8px) scale(.985); } }

/* ── PHONE ───────────────────────────────────────────────────────────────── */
@media (max-width: 720px) {
  .csm { padding: 10px; }
  .csm__dialog {
    /* See THE SIZE RULE above: 92vw, not 75vw, and room in `--csm-chrome` for
       a title that now wraps to two or three lines. */
    --csm-chrome: 120px;
    width: min(92vw, calc((85vh - var(--csm-chrome)) * var(--csm-ratio)));
  }
  .csm__head { padding: 13px 14px 11px; gap: 12px; }
  .csm__title { font-size: 15.5px; }
  .csm__close { width: 32px; height: 32px; }
}
