/*
 * The site chrome: the header, its menus, and the footer.
 *
 * Separate from modules-local.css for one reason — that sheet is only loaded on
 * pages built from the module library, and the header is on EVERY page. Keeping
 * the menu's styles there meant the home page kept the old full-bleed dropdowns
 * and the violet seam under the bar while every other page was fixed, which is
 * the kind of difference nobody reports as a bug and everybody notices.
 *
 * So: anything that styles the header or the footer lives here and is loaded
 * everywhere. Anything that styles a module stays in modules-local.css.
 */

/* ============================= 44 the seam under the navigation

   The header reserves 94px and paints white for only 74 of them: the bar is
   inset 10px top and bottom, and those two strips are transparent. On the home
   page a pale gradient sits behind them and nobody notices. On a service page
   the hero's violet announcement bar is behind them, so a violet line shows
   under the navigation — and when a mega-menu is open it sits between the bar
   and the panel, which is what makes it look like the panel has come loose.

   The header is a block, so it is painted like one. Both copies: Sprio
   ships a fixed bar and a static placeholder of the same markup, and only
   painting both keeps the seam closed while the page is scrolled.            */

header > .sprio-element { background: #fff; }

/* --------------------------------------- and the gap under the menu bar

   The dropdown's container starts flush with the header, but the white panel
   inside it starts 20px lower — and the container is transparent, so those
   20px show whatever is behind. On a service page that is the hero's violet
   announcement bar, which reads as the panel having come loose from the bar it
   belongs to. The container is part of the panel, so it is painted like it. */

.e-n-menu-content.e-active { background: #fff; }

/* -------------------------- and the panel sits on the bar, not below it

   The dropdown's container carries `padding: 20px 0 0`, so the white panel
   started 20px under the header with the page showing through the gap. Painting
   that gap white (above) stopped it being violet; removing it altogether is
   what actually makes the panel meet the bar it belongs to, which is what the
   menu looks like it is meant to do. */

.e-n-menu-content { padding-top: 0 !important; }

/* ============== 47 the short dropdowns, sized to what is in them

   Product has two links, About has five. Both were drawn as the same full-bleed
   band as the AI Services panel, which has twelve things in it — so a two-item
   menu came out as a white strip across the whole window with a short column at
   the left and a great deal of nothing to the right.

   A short panel is now sized to its contents and sits under the item it belongs
   to, which is also what makes it obvious which menu it came from. Panels that
   actually fill the width — the card grid and the Solutions rail — are
   untouched; they are the reason the wide band exists.

   The class is put on by the navigation layer, which knows what is in each
   panel. See applyNav() in src/lib/nav.ts.                                   */

@media (min-width: 1025px) {
  /* The row scrolls on a phone, and an absolutely positioned panel inside a
     scroller is clipped by it — so this is desktop only, where the row does not
     scroll and the drawer is not in use.

     The theme sets this through its own custom property, so the property is set
     as well as the shorthand: overriding only the shorthand leaves
     `overflow-x: var(--n-menu-heading-overflow-x)` still resolving to auto, and
     a scroller clips a panel whatever its z-index says. */
  header .e-n-menu-heading,
  header .e-n-menu-wrapper,
  header .e-n-menu {
    --n-menu-heading-overflow-x: visible;
    overflow: visible !important;
  }

  /* The item is the thing the panel is positioned inside, so it has to be a
     positioning context — and it has to stay one. Written plainly this loses to
     any theme rule that sets `position: static` on the item at some width, and
     an absolutely positioned panel whose containing block is not its item ends
     up wherever the next positioned ancestor happens to be. Which is a fair
     description of what Karan is seeing. */
  header li.e-n-menu-item.e-n-menu-item { position: relative !important; }

  /*
     The panel sits under its own menu item.

     Absolutely positioned inside the item, centred on it, and then nudged back
     inside the window by nav-local.js when centring would hang it over an edge
     — a featured strip under Product is 760px wide and Product is near the left,
     so strict centring puts it off the page.

     The nudge is a variable inside the transform rather than a second `left`,
     so the browser still does the centring with the panel's real width. An
     earlier attempt measured the width in script instead and measured it while
     the panel was closed, which put every panel out by half its own width. */
  header li.e-n-menu-item .e-n-menu-content.mod-nav-compact {
    position: absolute !important;
    inset: auto !important;
    /* The item sits 30px above the bottom of the bar, so this lands the panel
       exactly on the header's lower edge — where the wide panels start. */
    top: calc(100% + 30px) !important;
    left: 50% !important;
    /* Marked important like everything else in this rule, and for the same
       reason: the theme animates these panels, and an animation is a transform.
       Without it the theme's transform replaces the centring rather than
       arriving alongside it, and the panel's left edge lands on the item's
       centre — half a panel to the right of where it belongs. */
    transform: translateX(calc(-50% + var(--nav-shift, 0px))) !important;
    width: max-content !important;
    min-width: 260px;
    /* Wide enough for a column of links beside three pictures. */
    max-width: min(980px, calc(100vw - 48px));
    background: transparent !important;
    box-shadow: none !important;
  }

  /* When the panel has ended up somewhere the CSS did not intend — see
     placePanel() in nav-local.js — it stops depending on its ancestors and is
     pinned to the window instead. Nothing but the window can move it there.

     The selector repeats `li.e-n-menu-item` for one reason: it has to out-rank
     the rule above, and !important does not settle a fight between two
     important declarations — specificity does. Written the obvious short way
     this rule computed to (0,3,1) against the other's (0,3,2) and lost, so the
     panel stayed absolute and the correction had no effect at all. Third time
     this exact trap has come up in this project. */
  header li.e-n-menu-item .e-n-menu-content.mod-nav-compact.mod-nav-pinned {
    position: fixed !important;
    top: var(--nav-top, 94px) !important;
    left: var(--nav-left, 24px) !important;
    transform: none !important;
  }

  /* The box inside the panel sits at the panel's own left edge, always.
     The export baked an inline `left: 662.359px` onto one of these — a frozen
     measurement from the original site's stretch-to-full-width script — which
     rendered the About links 662px to the right of the About panel while the
     panel itself was exactly where it belonged. The offsets are stripped from
     the markup now (see stripStaleOffsets in nav.ts); this is the guard for a
     header that arrives from somewhere else still carrying them. */
  header .e-n-menu-content.mod-nav-compact > .e-con {
    left: 0 !important;
    right: auto !important;
  }

  /* Links on the left, pictures on the right.

     The panel's box is already a flex container — the theme stacks it as a
     column. Turning it into a row is the whole change: the link list becomes
     the first column and the featured strip the second, so a dropdown with
     pictures reads as one wide menu instead of a narrow one with a gallery
     hanging off the bottom. */
  header .e-n-menu-content.mod-nav-compact > *:has(.mod-nav-featured) {
    flex-direction: row !important;
    align-items: stretch;
  }

  header .e-n-menu-content.mod-nav-compact > * > *:not(.mod-nav-featured) {
    flex: 1 1 auto;
    min-width: 240px;
  }

  header .mod-nav-featured {
    flex: 0 0 auto;
    /* The rule that separated the two blocks moves with them: it was the line
       above the pictures, and side by side it is the line beside them. */
    border-top: 0;
    border-left: 1px solid rgba(3, 3, 7, 0.08);
  }

  /* In a row the cards sit in a row too, however many there are, rather than
     wrapping into the three-column grid they use when stacked. */
  header .e-n-menu-content.mod-nav-compact .mod-nav-featured-row {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 168px;
  }

  header .e-n-menu-content.mod-nav-compact > * {
    width: 100% !important;
    border-radius: 0 !important;
  }

  /* A panel that is not the full width needs its own edge. */
  header .e-n-menu-content.mod-nav-compact > * {
    border: 1px solid rgba(3, 3, 7, 0.1);
    box-shadow: 0 22px 70px rgba(0, 0, 0, 0.16);
  }
}

/* ----------------------------------------------- an icon in front of a link

   The plain menu rows had none — only the AI Services cards did — which is why
   those dropdowns read as a list of words next to a menu that reads as a menu.
   The mark is the house icon set, at the same hairline weight as everywhere
   else, and it takes the colour of the row so it follows the hover. */

header .sprio-item.has-navicon {
  display: flex !important;
  align-items: center;
  gap: 12px;
}

header .mod-navicon {
  display: inline-flex;
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  color: var(--wf-violet, #6904f2);
}

header .mod-navicon svg { width: 100%; height: 100%; }

header .sprio-item:hover .mod-navicon { color: inherit; }

/* ------------------------------------------------------- featured products

   This block is the CMS's own — the export has no picture cards in the header,
   so there was nothing to clone and nothing to match. Kept deliberately plain:
   a picture, a name, one line, and the whole card is the link. */

.mod-nav-featured {
  padding: 22px 26px 26px;
  border-top: 1px solid rgba(3, 3, 7, 0.08);
}

.mod-nav-featured-head {
  margin: 0 0 14px;
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(3, 3, 7, 0.58);
}

.mod-nav-featured-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(150px, 1fr));
  gap: 16px;
}

.mod-nav-featured-card {
  display: grid;
  /* Rows sized to their content and stacked from the top. Without this a card
     that has no description has one row fewer, so its picture stretches to fill
     the height the taller cards set — and because the picture has an aspect
     ratio, growing taller makes it wider, and it spills over the card beside
     it. */
  align-content: start;
  gap: 8px;
  text-decoration: none !important;
  color: var(--wf-ink, #030307);
}

.mod-nav-featured-art {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  background: #f1f0ee center / cover no-repeat;
  transition: transform 260ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.mod-nav-featured-card:hover .mod-nav-featured-art { transform: translateY(-3px); }

.mod-nav-featured-label { font-size: 15px; line-height: 1.3; }

.mod-nav-featured-desc {
  font-size: 13px;
  line-height: 1.4;
  color: rgba(3, 3, 7, 0.58);
}

@media (max-width: 1024px) {
  .mod-nav-featured-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mod-nav-featured { padding: 18px 20px 22px; }
}

/* ================================ 49 the menu drawer, on a phone

   The theme's own handler is missing from this export (see public/nav-local.js),
   and among the things it did was measure the open drawer and write its height
   into `--n-menu-dropdown-content-box-height`. Without it the variable is 0, so
   the drawer opened to nothing: the right items, the right markup, zero pixels
   tall.

   Rather than measure it in script, the drawer is given the room it can have —
   the window below the header — and allowed to scroll inside that. The width
   comes from the same place: the export leaves a desktop stretch of 1440px on
   it, which on a 390px screen puts most of the menu off the side of the page. */

.e-n-menu[data-layout='dropdown'] .e-n-menu-toggle[aria-expanded='true'] + .e-n-menu-wrapper {
  position: fixed;
  top: 94px;
  left: 0;
  right: 0;
  width: auto;
  max-width: none;
  max-height: calc(100vh - 94px);
  padding: 8px 0 24px;
  background: #fff;
  box-shadow: 0 22px 70px rgba(0, 0, 0, 0.16);
}

/* Inside the drawer a menu item is a row, not a chip. */
.e-n-menu[data-layout='dropdown'] .e-n-menu-heading {
  flex-direction: column;
  align-items: stretch;
}

.e-n-menu[data-layout='dropdown'] .e-n-menu-item {
  border-bottom: 1px solid rgba(3, 3, 7, 0.08);
}

.e-n-menu[data-layout='dropdown'] .e-n-menu-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 54px;
  padding: 6px 22px;
}

/* The export leaves a desktop stretch width on the row, so a menu item is
   1440px wide inside a 390px drawer. Everything is drawn from the left, so
   nothing looked wrong — but the page could be dragged sideways. */
.e-n-menu[data-layout='dropdown'] .e-n-menu-heading,
.e-n-menu[data-layout='dropdown'] .e-n-menu-item {
  width: 100%;
  max-width: 100%;
}

.e-n-menu[data-layout='dropdown'] .e-n-menu-title-container { flex: 1 1 auto; }

/* The links inside an opened panel, indented under the item they belong to. */
.e-n-menu[data-layout='dropdown'] .e-n-menu-content .sprio-item {
  padding: 12px 22px 12px 30px;
}

/* A panel in the drawer belongs under its own item, in the flow — not floating
   over the page the way it does on a wide screen. */
.e-n-menu[data-layout='dropdown'] .e-n-menu-content {
  position: static !important;
  inset: auto !important;
  width: auto !important;
  transform: none !important;
  max-width: none !important;
  min-width: 0 !important;
  box-shadow: none !important;
}

.e-n-menu[data-layout='dropdown'] .e-n-menu-content > * {
  border: 0 !important;
  box-shadow: none !important;
}

/* ================================ 49 the bands that sit on every page

   The client logo row and the article grid are held once and drawn into every
   page — see bands.ts. They are the design's own bands, so they need no styling
   of their own, with one exception.

   On the home page 60px of air sits above the logo row, contributed by the band
   that runs before it there. On a page built from modules there is nothing above
   it at all, so the row starts hard against the bottom of the hero. This is that
   air, put back, and only on the shared copy — the home page's own spacing is
   untouched. Outside any media query on purpose: a phone needs the gap more than
   a desktop does, not less.                                                   */

.sprio .mod-band--logos { padding-top: clamp(38px, 4.4vw, 72px); }

/* ============================== 51 how the shared bands move

   Three settings on the Logos screen, and this is what they mean.

   STILL is the design as it shipped and adds nothing.

   MARQUEE scrolls the row continuously. The row holds its content twice (see
   marqueeTrack in bands.ts) and the track travels exactly half its own width,
   so the second copy arrives where the first began and the loop has no seam. It
   pauses when the pointer is over it — a logo somebody is looking at should
   stop moving — and it does not run at all for a visitor who has asked their
   computer to reduce motion, who gets the row standing still.

   The band is masked at both ends so logos arrive and leave through a fade
   rather than appearing at a hard edge.

   FADE brings the row up once as it comes into view. The class is added by
   nav-local.js when the band reaches the viewport; before that the row is
   already in the page and readable — the animation only ever moves what is
   there, so nothing depends on the script having run.                        */

.mod-band--marquee { overflow: hidden; }

.mod-band--marquee .mod-logo-track {
  display: flex !important;
  flex-wrap: nowrap !important;
  width: max-content !important;
  animation: mod-logo-marquee var(--logo-marquee, 42s) linear infinite;
}

.mod-band--marquee .mod-logo-track:hover { animation-play-state: paused; }

.mod-band--speed-slow { --logo-marquee: 64s; }
.mod-band--speed-medium { --logo-marquee: 42s; }
.mod-band--speed-fast { --logo-marquee: 26s; }

@keyframes mod-logo-marquee {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-50%, 0, 0); }
}

/* The logo widgets are laid out by the theme; inside a moving track they must
   not stretch to fill it or the spacing changes as the row scrolls. */
.mod-band--marquee .mod-logo-track > * { flex: 0 0 auto; }

.mod-band--marquee .e-con-inner {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}

@media (prefers-reduced-motion: reduce) {
  .mod-band--marquee .mod-logo-track { animation: none; transform: none; }
  .mod-band--marquee .e-con-inner { -webkit-mask-image: none; mask-image: none; }
}

/* The row lifts into place once, when it arrives. Only the transform and the
   opacity move, so it costs one compositor layer and no layout. */
@media (prefers-reduced-motion: no-preference) {
  .mod-band--fade .e-con-inner > * {
    opacity: 0;
    transform: translate3d(0, 18px, 0);
  }

  .mod-band--fade.is-in .e-con-inner > * {
    opacity: 1;
    transform: none;
    transition: opacity 620ms cubic-bezier(0.22, 0.61, 0.36, 1),
                transform 620ms cubic-bezier(0.22, 0.61, 0.36, 1);
  }

  /* The heading first, then the row of logos a beat later. */
  .mod-band--fade.is-in .e-con-inner > *:nth-child(2) { transition-delay: 90ms; }
}

/* ============================================= 52 the cookie notice

   A bar at the foot of the window in the site's own type, not a modal across
   the middle of the page. A modal makes the reader deal with cookies before
   they are allowed to see what they came for, which is the pattern everybody
   has learned to resent — and it measurably costs the visit. This asks once,
   quietly, and gets out of the way.

   It arrives from below rather than fading in on the spot: movement from an
   edge reads as something arriving, and a fade in the middle of the page reads
   as something that was already there and you had missed it.                */

.mod-consent {
  position: fixed;
  z-index: 2147483000;
  left: max(16px, env(safe-area-inset-left));
  right: max(16px, env(safe-area-inset-right));
  bottom: max(16px, env(safe-area-inset-bottom));
  max-width: 760px;
  margin: 0 auto;
  background: #fff;
  color: #030307;
  border: 1px solid rgba(3, 3, 7, 0.1);
  border-radius: 14px;
  box-shadow: 0 24px 60px -24px rgba(3, 3, 7, 0.32), 0 2px 8px rgba(3, 3, 7, 0.06);
  transform: translate3d(0, 18px, 0);
  opacity: 0;
  transition: opacity 320ms ease, transform 320ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

.mod-consent.is-in { opacity: 1; transform: none; }

.mod-consent-inner {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 16px 20px;
  flex-wrap: wrap;
}

.mod-consent-text {
  flex: 1 1 340px;
  margin: 0;
  font-family: "Instrument Sans", system-ui, sans-serif;
  font-size: 14px;
  line-height: 1.5;
  color: rgba(3, 3, 7, 0.72);
}

.mod-consent-link { color: #6904f2; text-decoration: underline; text-underline-offset: 2px; }

.mod-consent-actions { display: flex; gap: 10px; flex: 0 0 auto; }

/* Every one of these is written as .mod-consent .mod-consent-btn rather than
   .mod-consent-btn alone, and the extra class is the whole point: the theme's
   kit paints EVERY button on the site black with a 60px radius, through
   ".sprio-kit-4 button". That selector is one class and one element, so a
   single class of mine loses to it — the Decline button came out identical to
   Accept, two solid black pills asking the reader to choose between them. Two
   classes outrank it, and nothing here needs !important. */

.mod-consent .mod-consent-btn {
  font-family: "Instrument Sans", system-ui, sans-serif;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.2;
  padding: 11px 20px;
  border-radius: 9px;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background 160ms ease, border-color 160ms ease, color 160ms ease;
}

.mod-consent .mod-consent-btn--solid { background: #030307; color: #fff; }
.mod-consent .mod-consent-btn--solid:hover { background: #6904f2; }
.mod-consent .mod-consent-btn--ghost {
  background: #fff;
  color: rgba(3, 3, 7, 0.72);
  border-color: rgba(3, 3, 7, 0.16);
}
.mod-consent .mod-consent-btn--ghost:hover { border-color: #030307; color: #030307; }
.mod-consent .mod-consent-btn:focus-visible {
  outline: 2px solid #6904f2;
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .mod-consent { transition: none; transform: none; }
}

@media (max-width: 560px) {
  .mod-consent-inner { padding: 14px 16px; gap: 12px; }
  .mod-consent-actions { width: 100%; }
  .mod-consent .mod-consent-btn { flex: 1 1 0; }
}

/* ============================================ 53 the certification mark

   In the footer beside the logo, because a certification is a fact about the
   company and the footer is where a reader looks for those. A band across the
   middle of a page would be an advertisement for it, which is the opposite of
   what a trust mark is for.                                                 */

/* The colour is set here rather than inherited, and that is not a nicety: the
   footer is dark, but the mark is a plain div, so it inherits from the body and
   came out black on black — present in the markup, measurable in the DOM, and
   invisible to a reader. Anything dropped into this footer has to say what
   colour it is. .mod-trust--light is for a footer that is ever made pale. */

.mod-trust {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 20px 0 0;
  padding: 12px 14px;
  color: #fff;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 10px;
  max-width: 320px;
}

.mod-trust--light {
  color: #030307;
  background: rgba(3, 3, 7, 0.03);
  border-color: rgba(3, 3, 7, 0.12);
}

.mod-trust-mark { width: 44px; height: 44px; object-fit: contain; flex: 0 0 auto; }

.mod-trust-text {
  display: grid;
  gap: 2px;
  font-family: "Instrument Sans", system-ui, sans-serif;
  line-height: 1.35;
  color: inherit;
}

.mod-trust .mod-trust-text strong { font-size: 14px; font-weight: 600; letter-spacing: 0.01em; color: inherit; }
.mod-trust .mod-trust-text span { font-size: 12.5px; opacity: 0.66; color: inherit; }

/* ==================================================== 54 the blog

   The article page and the index. Both are built from the same header, footer
   and bands as everything else; only the middle is new, and the middle is
   nothing but typography — which is the point. A blog that invents its own
   type scale stops looking like the site it is on.                          */

.mod-article,
.mod-article-index {
  width: min(1280px, calc(100vw - 48px));
  margin: 0 auto;
  padding: clamp(48px, 5vw, 88px) 0 clamp(56px, 6vw, 96px);
  font-family: "Instrument Sans", system-ui, sans-serif;
  color: #030307;
}

.mod-article-head { max-width: 760px; }

.mod-article-crumbs {
  display: flex;
  gap: 10px;
  font-size: 13.5px;
  color: rgba(3, 3, 7, 0.5);
  margin-bottom: 26px;
}
.mod-article-crumbs a { color: #6904f2; }

.mod-article-tag,
.mod-post-tag {
  display: inline-block;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 6px 12px;
  border-radius: 999px;
  background: #fff;
  color: #030307;
  border: 1px solid rgba(3, 3, 7, 0.1);
}

.mod-article h1 {
  font-size: clamp(34px, 4vw, 56px);
  line-height: 1.08;
  letter-spacing: -0.02em;
  font-weight: 500;
  margin: 18px 0 0;
}

.mod-article-standfirst {
  font-size: clamp(17px, 1.4vw, 21px);
  line-height: 1.5;
  color: rgba(3, 3, 7, 0.62);
  margin: 20px 0 0;
}

.mod-article-meta {
  display: flex;
  gap: 14px;
  font-size: 13.5px;
  color: rgba(3, 3, 7, 0.5);
  margin: 26px 0 0;
}

.mod-article-art { margin: clamp(32px, 4vw, 56px) 0 0; }
.mod-article-art img { width: 100%; height: auto; display: block; border-radius: 4px; }

.mod-article-body { max-width: 720px; margin: clamp(32px, 4vw, 56px) 0 0; }
.mod-article-body p { font-size: 17px; line-height: 1.68; color: rgba(3, 3, 7, 0.78); margin: 0 0 22px; }
.mod-article-body h2 {
  font-size: clamp(23px, 2vw, 30px);
  line-height: 1.2;
  font-weight: 500;
  letter-spacing: -0.01em;
  margin: 42px 0 16px;
}
.mod-article-body ul { margin: 0 0 22px; padding-left: 20px; }
.mod-article-body li { font-size: 17px; line-height: 1.68; color: rgba(3, 3, 7, 0.78); margin-bottom: 8px; }
/* ---------------------------------------------- what an article can contain

   The body is written as plain text and the marks in it become these. Every
   one of them is the site's own type at the site's own sizes, so an article
   pasted out of Word reads as part of the site rather than as a document
   dropped into it. */

.mod-article-body h3 {
  font-size: clamp(19px, 1.4vw, 22px);
  line-height: 1.28;
  font-weight: 500;
  letter-spacing: -0.005em;
  margin: 32px 0 12px;
}

.mod-article-body ol { margin: 0 0 22px; padding-left: 22px; }
.mod-article-body ol li { padding-left: 4px; }

.mod-article-body strong { font-weight: 600; color: rgba(3, 3, 7, 0.92); }
.mod-article-body em { font-style: italic; }

.mod-article-body a {
  color: #6904f2;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.mod-article-body a:hover { text-decoration-thickness: 2px; }

.mod-article-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
  padding: 2px 6px;
  border-radius: 4px;
  background: rgba(105, 4, 242, 0.07);
  color: #4b0aa8;
}

.mod-article-body blockquote {
  margin: 28px 0;
  padding: 4px 0 4px 22px;
  border-left: 3px solid #6904f2;
  font-size: clamp(19px, 1.5vw, 22px);
  line-height: 1.45;
  color: rgba(3, 3, 7, 0.86);
}

.mod-article-rule {
  margin: 40px 0;
  border: 0;
  border-top: 1px solid rgba(3, 3, 7, 0.12);
}

.mod-article-figure { margin: 32px 0; }
.mod-article-figure img { width: 100%; height: auto; display: block; border-radius: 4px; }
.mod-article-figure figcaption {
  margin-top: 10px;
  font-size: 14px;
  line-height: 1.5;
  color: rgba(3, 3, 7, 0.55);
}

/* A table is the one thing in an article that can be wider than the column of
   text. It gets to use the full width, and on a narrow screen it scrolls
   inside its own box rather than pushing the whole page sideways. */

.mod-article-table {
  margin: 32px 0;
  max-width: min(980px, 100%);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.mod-article-table table {
  width: 100%;
  min-width: 460px;
  border-collapse: collapse;
  font-size: 16px;
  line-height: 1.5;
}

.mod-article-table th {
  text-align: left;
  font-weight: 600;
  color: #030307;
  padding: 13px 18px 13px 0;
  border-bottom: 2px solid rgba(3, 3, 7, 0.82);
  white-space: nowrap;
}

.mod-article-table td {
  padding: 14px 18px 14px 0;
  border-bottom: 1px solid rgba(3, 3, 7, 0.1);
  color: rgba(3, 3, 7, 0.78);
  vertical-align: top;
}

.mod-article-table th:last-child,
.mod-article-table td:last-child { padding-right: 0; }
.mod-article-table tbody tr:last-child td { border-bottom: 1px solid rgba(3, 3, 7, 0.16); }

@media (max-width: 767px) {
  .mod-article-table table { font-size: 15px; }
  .mod-article-table th,
  .mod-article-table td { padding-right: 14px; }
}

.mod-article-back { margin: 48px 0 0; }
.mod-article-back a { color: #6904f2; font-size: 15px; }

.mod-article-index-head { margin-bottom: clamp(32px, 4vw, 56px); }
.mod-article-index-head h1 {
  font-size: clamp(34px, 4vw, 56px);
  line-height: 1.08;
  letter-spacing: -0.02em;
  font-weight: 500;
  margin: 10px 0 0;
}

.mod-post-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(24px, 2.6vw, 40px);
}

.mod-post-card { display: grid; gap: 12px; text-decoration: none; color: inherit; }

.mod-post-art {
  display: block;
  aspect-ratio: 4 / 3;
  border-radius: 4px;
  background: #eeecf6 center/cover no-repeat;
  position: relative;
  overflow: hidden;
}
.mod-post-art .mod-post-tag { position: absolute; top: 14px; left: 14px; }

.mod-post-card .mod-post-title { font-size: 20px; font-weight: 500; line-height: 1.25; }
.mod-post-card .mod-post-excerpt { font-size: 15px; line-height: 1.55; color: rgba(3, 3, 7, 0.6); }
.mod-post-card .mod-post-date { font-size: 13px; color: rgba(3, 3, 7, 0.42); }
.mod-post-card:hover .mod-post-title { color: #6904f2; }
.mod-article-empty { color: rgba(3, 3, 7, 0.55); }

@media (max-width: 1023px) { .mod-post-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) { .mod-post-grid { grid-template-columns: minmax(0, 1fr); } }
