/*
Theme Name: MKS
Author: Marksistiki Kommounistiki Sispirosi
Description: A minimal WordPress block theme for publishing announcements, for a political organization.
Requires at least: 6.6
Tested up to: 6.8
Requires PHP: 7.4
Version: 1.8.0
License: GNU General Public License v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
Text Domain: mks
Tags: blog, news, one-column, custom-logo, editor-style, full-site-editing, block-patterns
*/

/*
 * Front-end styles. theme.json owns the design tokens (colour, type, spacing);
 * this file holds only what theme.json can't express — block-structural CSS,
 * responsive behaviour, and interaction states.
 *
 * This file is not auto-loaded by block themes; it is enqueued in inc/assets.php.
 *
 * CONTENTS
 *   1. Foundation        — root behaviour, tap-highlight reset, custom props
 *   2. Header logo
 *   3. Navigation        — shared, desktop bar, mobile drawer
 *   4. Pagination
 *   5. Cards             — layout, clamping, hover + press feedback
 *   6. Page headings
 *   7. Layout
 *   8. Search
 *   9. Media             — featured images, embeds, files
 *  10. Footer            — bordered content box, social buttons
 */

/* ==========================================================================
   1. FOUNDATION
   ========================================================================== */

/*
 * Reserve the scrollbar gutter permanently. When the nav overlay opens, core
 * adds overflow:hidden to <html>; without a reserved gutter that removes the
 * scrollbar and widens the layout viewport ~15px mid-slide, jerking the
 * drawer's right-edge anchor. Reserving it always means locking scroll changes
 * nothing.
 */
html {
  scrollbar-gutter: stable;

  /*
   * Pin text at its authored size. Mobile WebKit and Blink run a "text
   * autosizing" pass that INFLATES the font of any block it decides is a main
   * text column — and it decides differently at different viewport widths. The
   * visible symptom is a phone whose card titles look one size in landscape and
   * a smaller one in portrait, with nothing in the CSS to explain it. It also
   * silently poisons the JS clamp, which measures line heights the browser then
   * changes underneath it.
   */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* Suppress the native tap-highlight everywhere; deliberate press states stand
   in for it (nav rows, cards, buttons). */
html,
*,
*::before,
*::after {
  -webkit-tap-highlight-color: transparent;
}

:root {
  /*
   * Card colours are DESIGN TOKENS, defined in theme.json (settings.custom.card)
   * so every colour in the theme lives in one file. They're aliased to short
   * names here purely for readability below. To change them, edit theme.json —
   * not this file.
   *
   * They're in settings.custom rather than the colour palette on purpose: the
   * palette is what editors see in the block colour picker, and these are
   * structural, not author-selectable.
   */
  --mks-card-surface: var(--wp--custom--card--surface);
  --mks-card-border: var(--wp--custom--card--border);
}

/* ==========================================================================
   2. HEADER LOGO
   ========================================================================== */

/*
 * core/site-logo renders explicit width/height attributes on the <img> matching
 * the block's `width` setting (parts/header.html) — a fixed pixel size, not a
 * cap. The rules below turn both axes into ceilings, with HEIGHT as the one
 * that usually binds: the logo renders at max-height on roomy screens and
 * shrinks via max-width on narrow ones, in proportion either way.
 *
 * 176px comes from the original artwork: 1675x447 at the block's 660px width
 * rendered ~176px tall. Sizing by height keeps that visual weight constant
 * across logo swaps — a taller-ratio image just comes out narrower instead of
 * dominating the header. Retune this one number to taste; width:auto is what
 * lets the ratio follow (without it, the img's width attribute stays in force
 * and max-height would squash the image instead of scaling it).
 */
.mks-site-logo img {
  max-width: 100%;
  max-height: 100px;
  width: auto;
  height: auto;
}

/* ==========================================================================
   3. NAVIGATION  (single core Navigation block, class .mks-topnav)
   --------------------------------------------------------------------------
   header.html holds ONE Navigation block. The desktop bar and the mobile
   drawer are the same block in two responsive states — scoping by .mks-topnav
   alone doesn't separate them, so the rules below are split strictly by
   breakpoint, and the two media queries are mutually exclusive:

       BAR    : (min-width:782px) and (hover:hover) and (pointer:fine)
       DRAWER : anything else  →  max-width:781px, OR no-hover, OR coarse pointer

   Splitting on capability (not just width) means the hover-only dropdowns
   never land on a touchscreen that can't open them, and desktop rules can
   never leak into the drawer.
   ========================================================================== */

/* Touch press feedback on drawer controls. Native <a>/<button>, so CSS :active
   is reliable here (unlike the cards). The control scales down on press and
   springs back with a slight overshoot — the same press language as the cards —
   on top of the colour switch. Only the control actually pressed is affected;
   styling the parent item makes iOS light a submenu entry and its parent
   together. */
@media (hover: none), (pointer: coarse) {
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation-item__content,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__responsive-container-open,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__responsive-container-close,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__submenu-icon {
    transition: transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1),
      background-color 0.15s ease, color 0.15s ease;
  }
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation-item__content:active,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__responsive-container-open:active,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__responsive-container-close:active,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__submenu-icon:active {
    background-color: var(--wp--preset--color--primary-dark) !important;
    color: var(--wp--preset--color--background) !important;
    transform: scale(0.96);
    transition: transform 0.08s ease-out, background-color 0.1s ease,
      color 0.1s ease;
  }

  .mks-topnav .wp-block-navigation__responsive-container a,
  .mks-topnav .wp-block-navigation__responsive-container button {
    touch-action: manipulation;
  }
}

/* State switch: show exactly one of bar / hamburger. !important is needed
   because core hides the open button with a more specific selector. */
@media (min-width: 782px) and (hover: hover) and (pointer: fine) {
  .mks-topnav .wp-block-navigation__responsive-container-open {
    display: none !important;
  }
}
@media (max-width: 781px), (hover: none), (pointer: coarse) {
  .mks-topnav .wp-block-navigation__responsive-container-open:not(.always-shown) {
    display: flex !important;
  }
}

/* --------------------------------------------------------------------------
   3a. DESKTOP BAR  (>= 782px, hover + fine pointer)
   -------------------------------------------------------------------------- */
@media (min-width: 782px) and (hover: hover) and (pointer: fine) {
  .mks-topnav .wp-block-navigation__container {
    background: var(--wp--preset--color--primary);
    width: 100%;
    gap: 0;
  }

  .mks-topnav .wp-block-navigation-item__content {
    font-weight: 500;
  }

  /* Top-level links. */
  .mks-topnav .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content {
    padding: var(--wp--preset--spacing--10) var(--wp--preset--spacing--60);
    color: var(--wp--preset--color--background);
    transition: background-color 0.15s ease;
  }
  .mks-topnav .wp-block-navigation__container > .wp-block-navigation-item:hover > .wp-block-navigation-item__content,
  .mks-topnav .wp-block-navigation__container > .wp-block-navigation-item:focus-within > .wp-block-navigation-item__content,
  .mks-topnav .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content[aria-current="page"] {
    background: var(--wp--preset--color--primary-dark);
  }

  /* Dropdown panel, centred under its parent. */
  .mks-topnav .wp-block-navigation__container > .wp-block-navigation-item.has-child {
    position: relative;
  }
  .mks-topnav .wp-block-navigation-item.has-child > .wp-block-navigation__submenu-container {
    position: absolute;
    top: 100%;
    left: 50%;
    right: auto;
    transform: translateX(-50%);
    margin-top: var(--wp--preset--spacing--20);
    padding: var(--wp--preset--spacing--10);
    gap: 2px;
    width: max-content;
    min-width: 0;
    border: 0;
    border-radius: var(--wp--custom--radius--md);
    background: var(--wp--preset--color--primary);
    box-shadow: 0 10px 26px rgba(33, 28, 28, 0.28);
  }

  /* Dropdown items. box-sizing:border-box keeps the hover box from spilling
     past the panel (width:100% + padding overflows under content-box). */
  .mks-topnav .wp-block-navigation__submenu-container .wp-block-navigation-item {
    display: block;
    width: 100%;
    margin: 0;
  }
  .mks-topnav .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
    display: block;
    box-sizing: border-box;
    width: 100%;
    margin: 0;
    padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
    border-radius: var(--wp--custom--radius--md);
    color: var(--wp--preset--color--background);
    background-color: transparent;
    white-space: nowrap;
    transition: background-color 0.15s ease, color 0.15s ease;
  }
  .mks-topnav .wp-block-navigation__submenu-container .wp-block-navigation-item__content:hover,
  .mks-topnav .wp-block-navigation__submenu-container .wp-block-navigation-item__content:focus-visible,
  .mks-topnav .wp-block-navigation__submenu-container .wp-block-navigation-item__content[aria-current="page"] {
    background-color: var(--wp--preset--color--primary-dark);
    color: var(--wp--preset--color--background);
  }

  /* Invisible bridge over the 8px gap so hover survives the trip down. */
  .mks-topnav .wp-block-navigation-item.has-child > .wp-block-navigation__submenu-container::before {
    content: "";
    position: absolute;
    left: -16px;
    right: -16px;
    top: -10px;
    height: 12px;
  }

  /* Chevron drawn on the parent link, inheriting its colour and hover state. */
  .mks-topnav .wp-block-navigation__submenu-icon {
    display: none;
  }
  .mks-topnav .has-child > .wp-block-navigation-item__content::after {
    content: "";
    display: inline-block;
    width: 0;
    height: 0;
    margin-left: 0.45em;
    vertical-align: middle;
    border-left: 0.3em solid transparent;
    border-right: 0.3em solid transparent;
    border-top: 0.32em solid currentColor;
    transition: transform 0.2s ease;
  }
  .mks-topnav .has-child:hover > .wp-block-navigation-item__content::after,
  .mks-topnav .has-child:focus-within > .wp-block-navigation-item__content::after {
    transform: rotate(180deg);
  }

  /* Keyboard focus ring. */
  .mks-topnav a:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: 3px;
    border-radius: 2px;
  }
}

/* --------------------------------------------------------------------------
   3b. MOBILE DRAWER  (<= 781px, or no-hover, or coarse pointer)
   --------------------------------------------------------------------------
   A hamburger button and a sliding drawer. The drawer is ALWAYS painted
   (never display:none) and parked off-screen by transform when closed, so the
   slide-out animates in every browser — Firefox does not animate display:none
   on exit via @starting-style/allow-discrete, which silently kills the close
   slide. Only the transform and the backdrop tint differ between states; the
   inner content is styled identically so the drawer moves as one frozen unit.
   -------------------------------------------------------------------------- */
@media (max-width: 781px), (hover: none), (pointer: coarse) {
  /* Hamburger, presented as a full-width bar mirroring the desktop bar. */
  .mks-topnav .wp-block-navigation__responsive-container-open {
    flex: 1 0 100%;
    justify-content: center;
    align-items: center;
    padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
    background: var(--wp--preset--color--primary);
    color: var(--wp--preset--color--background);
  }
  .mks-topnav .wp-block-navigation__responsive-container-open svg {
    fill: currentColor;
  }

  /* Backdrop = the responsive container. Geometry pinned for BOTH states so
     core can't drag it back in-flow or swap its padding. */
  .mks-topnav.wp-block-navigation .wp-block-navigation__responsive-container:not(.hidden-by-default) {
    position: fixed !important;
    inset: 0 !important;
    display: flex !important;
    flex-direction: column !important;
    align-items: flex-end !important;
    justify-content: flex-start !important;
    margin: 0 !important;
    padding: var(--wp--preset--spacing--30) !important;
    overflow: hidden !important;
    z-index: 100000;
  }
  .mks-topnav .wp-block-navigation__responsive-container {
    transition: background-color 0.3s linear;
  }

  /* Closed vs. open differ only in tint and click-through. */
  .mks-topnav.wp-block-navigation .wp-block-navigation__responsive-container:not(.is-menu-open) {
    pointer-events: none;
    background-color: rgba(33, 28, 28, 0) !important;
  }
  .mks-topnav .wp-block-navigation__responsive-container.is-menu-open {
    pointer-events: auto;
    background-color: rgba(33, 28, 28, 0.55) !important;
    animation: none !important;
  }

  /* Flatten core's close-button wrapper so the dialog is a direct flex child. */
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__responsive-close {
    display: contents !important;
  }

  /* The drawer itself: the single sliding unit, parked off-screen when closed.
     On its own compositor layer (will-change) so the slide runs off the main
     thread. */
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__responsive-dialog {
    box-sizing: border-box !important;
    width: min(86vw, 22rem) !important;
    height: 100% !important;
    margin: 0 !important;
    background: var(--wp--preset--color--primary) !important;
    border-radius: var(--wp--custom--radius--lg) !important;
    overflow: hidden !important;
    display: flex !important;
    flex-direction: column !important;
    transform: translateX(calc(100% + 0.75rem));
    /* Shadow is transparent here and only coloured on open (below): the
       backdrop that clips the drawer spans the full viewport, so the parked
       drawer's shadow would otherwise bleed back into view as a strip down
       the page's right edge even while "closed". Transitioned alongside the
       slide so it fades rather than popping. */
    box-shadow: 0 18px 50px rgba(33, 28, 28, 0) !important;
    transition: transform 0.3s linear, box-shadow 0.3s linear;
    will-change: transform;
  }
  .mks-topnav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-dialog {
    transform: translateX(0);
    box-shadow: 0 18px 50px rgba(33, 28, 28, 0.5) !important;
  }

  /* Close (X): kept visible in every state so the drawer stays whole as it
     slides out. */
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__responsive-container-close {
    display: block !important;
    position: absolute !important;
    top: 0.4rem !important;
    right: 0.4rem !important;
    left: auto !important;
    margin: 0 !important;
    padding: var(--wp--preset--spacing--20) !important;
    color: var(--wp--preset--color--background) !important;
    z-index: 2;
  }

  /* Inner list: a full-width column, identical in every state. */
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__responsive-container-content {
    box-sizing: border-box !important;
    flex: 1 1 auto !important;
    min-height: 0 !important;
    overflow-x: hidden !important;
    overflow-y: auto !important;
    display: flex !important;
    flex-direction: column !important;
    align-items: stretch !important;
    justify-content: flex-start !important;
    gap: 2px !important;
    padding: var(--wp--preset--spacing--80) var(--wp--preset--spacing--20) var(--wp--preset--spacing--40) !important;
  }
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__container,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__submenu-container {
    box-sizing: border-box !important;
    position: static !important;
    width: 100% !important;
    min-width: 0 !important;
    height: auto !important;
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    box-shadow: none !important;
    background: transparent !important;
    display: flex !important;
    flex-direction: column !important;
    align-items: stretch !important;
    justify-content: flex-start !important;
    gap: 2px !important;
    opacity: 1 !important;
    visibility: inherit !important;
  }
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation-item {
    width: 100% !important;
    margin: 0 !important;
  }
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation-item.has-child {
    display: flex !important;
    flex-direction: column !important;
    gap: 2px !important;
  }

  /* Every row — category and subcategory — gets the same box. */
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation-item__content {
    box-sizing: border-box !important;
    display: block !important;
    width: 100% !important;
    margin: 0 !important;
    padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40) !important;
    font-weight: 500;
    line-height: 1.4;
    text-align: left !important;
    color: var(--wp--preset--color--background) !important;
    background: transparent;
    border-radius: var(--wp--custom--radius--md);
  }

  /* Subcategory rows are indented and marked with a › prefix. */
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
    position: relative;
    padding-left: 5rem !important;
  }
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__submenu-container .wp-block-navigation-item__content::before {
    content: "\203A";
    position: absolute;
    left: 2rem;
    top: 50%;
    transform: translateY(-50%);
    font-size: 1.05em;
    line-height: 1;
    opacity: 0.7;
  }

  /* Active / current / focus state. */
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation-item__content:focus-visible,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation-item__content[aria-current="page"],
  .mks-topnav .wp-block-navigation__responsive-container .current-menu-item > .wp-block-navigation-item__content,
  .mks-topnav .wp-block-navigation__responsive-container .current_page_item > .wp-block-navigation-item__content {
    background: var(--wp--preset--color--primary-dark) !important;
    color: var(--wp--preset--color--background) !important;
  }
  @media (hover: hover) {
    .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation-item__content:hover {
      background: var(--wp--preset--color--primary-dark) !important;
      color: var(--wp--preset--color--background) !important;
    }
  }

  /* No chevrons in the drawer (submenus are always expanded). */
  .mks-topnav .wp-block-navigation__responsive-container .has-child > .wp-block-navigation-item__content::after,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__submenu-icon {
    display: none !important;
  }

  /* Resize guard: navigation.js adds .mks-bp-crossing to <html> for ~2 frames
     when the viewport crosses 782px, so dragging a desktop window across the
     breakpoint doesn't animate the drawer in/out. */
  html.mks-bp-crossing .mks-topnav .wp-block-navigation__responsive-container,
  html.mks-bp-crossing .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__responsive-dialog {
    transition: none !important;
  }

  @media (prefers-reduced-motion: reduce) {
    .mks-topnav .wp-block-navigation__responsive-container,
    .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__responsive-dialog {
      transition: none !important;
    }
  }
}

/* ==========================================================================
   4. PAGINATION
   ========================================================================== */
.wp-block-query-pagination {
  gap: var(--wp--preset--spacing--20);
  align-items: center;
}
.wp-block-query-pagination .wp-block-query-pagination-numbers {
  display: inline-flex;
  gap: var(--wp--preset--spacing--20);
}

/* Every box: page numbers, prev, next. */
.wp-block-query-pagination .page-numbers,
.wp-block-query-pagination-previous,
.wp-block-query-pagination-next {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 42px;
  height: 42px;
  padding: 0 var(--wp--preset--spacing--30);
  border: 1px solid var(--wp--preset--color--primary);
  background-color: var(--wp--preset--color--background);
  color: var(--wp--preset--color--foreground);
  text-decoration: none;
  font-size: 16px;
  line-height: 1;
  border-radius: var(--wp--custom--radius--md);
  box-sizing: border-box;
  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease,
    transform 0.15s ease, filter 0.15s ease;
}

/* Current page. */
.wp-block-query-pagination .page-numbers.current {
  background-color: var(--wp--preset--color--primary);
  border-color: var(--wp--preset--color--primary);
  color: var(--wp--preset--color--background);
}

/* Hover — links only, never the current span or the dots. */
.wp-block-query-pagination a.page-numbers:hover,
a.wp-block-query-pagination-previous:hover,
a.wp-block-query-pagination-next:hover {
  background-color: var(--wp--preset--color--primary);
  border-color: var(--wp--preset--color--primary);
  color: var(--wp--preset--color--background);
}

/* Touch press feedback. These are real <a> elements, so native :active is
   reliable here (unlike the card's <div>) — same scale + dim as the other
   buttons. */
@media (hover: none), (pointer: coarse) {
  .wp-block-query-pagination a.page-numbers:active,
  a.wp-block-query-pagination-previous:active,
  a.wp-block-query-pagination-next:active {
    background-color: var(--wp--preset--color--primary);
    border-color: var(--wp--preset--color--primary);
    color: var(--wp--preset--color--background);
    transform: scale(0.94);
    filter: brightness(0.92);
  }
}

/* Ellipsis: bare, no box. */
.wp-block-query-pagination .page-numbers.dots {
  border-color: transparent;
  background: transparent;
  min-width: 0;
}

/* ==========================================================================
   5. CARDS
   ========================================================================== */
.is-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  height: 100%;
  border-radius: var(--wp--custom--radius--lg);
  background: var(--mks-card-surface);
  border: 3px solid var(--mks-card-border);
  /* Promote to its own compositor layer so the hover/press transforms animate
     without re-rasterising. */
  transform: translateZ(0);
  backface-visibility: hidden;
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease,
    filter 0.18s ease;
}

/* --------------------------------------------------------------------------
   5a. EQUAL-HEIGHT FILL
   --------------------------------------------------------------------------
   Grid cards in a row are already equal height; this stretches each card's
   content group to fill its card, so the slack a short title leaves sits
   below the excerpt — where the JS clamp (excerpt-clamp.js) measures it and
   fills it with extra lines. Row cards are excluded: single column, nothing
   to fill. Gated on .mks-clamp-fill, which inc/assets.php adds to <body>
   only when MKS_CLAMP_FILL is on and a clamp script is loaded — without the
   script the stretch would just move the dead space, not remove it.

   Do NOT give this group `display:flex`. It's a constrained-layout group, so
   core sets margin-inline:auto on every child; inside a flex column those
   margins become horizontal centring — the text centres and the <hr>
   separator collapses to zero width. Only change how the group behaves as a
   flex ITEM of .is-card, never its own inner display.
   -------------------------------------------------------------------------- */
.mks-clamp-fill .is-card > .wp-block-group {
  flex: 1 1 auto;
  min-height: 0;
}

/* --------------------------------------------------------------------------
   5b. TITLE + EXCERPT CLAMPING
   --------------------------------------------------------------------------
   The excerpt clamp has four modes, chosen by MKS_CLAMP_MODE in functions.php
   ('css' | 'hybrid' | 'js' | 'auto'). The CSS below is the same in all four —
   it is the base layer and the no-JS fallback. What differs is only whether
   the script runs, and where:

     css      script never loads. These rules are the whole story.
     hybrid   script loads, acts on iOS only.
     js       script loads, acts everywhere.
     auto     script loads, acts on grid cards everywhere + row cards on iOS
              only. See assets/js/excerpt-clamp.js for the per-card decision;
              nothing here needs to know about it — a card the script skips
              keeps showing these rules, same as 'css' mode.

   Line counts come from --mks-card-title-lines and --mks-card-excerpt-lines,
   printed by inc/assets.php from MKS_CLAMP_LINES: the stacked budget on :root,
   and the row budget on .is-card--adaptive inside a min-width query. They are
   inherited properties, so an adaptive card in its row state picks up the tighter
   budget and everything else keeps the stacked one — no rule here needs to know
   which state it is in. Don't hard-code the numbers; the JS reads the resolved
   property off the element, so CSS and JS cannot disagree.
   -------------------------------------------------------------------------- */

.is-card .wp-block-post-title {
  position: relative;
}
.is-card .wp-block-post-title a {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--mks-card-title-lines, 4);
  line-clamp: var(--mks-card-title-lines, 4);
  overflow: hidden;
  transition: color 0.18s ease;
}

/*
 * Row cards only: reserve the full title budget whether the title needs it or
 * not, so a 1-line title doesn't make the card shorter than its neighbour. On a
 * grid card that variance is absorbed by MKS_CLAMP_FILL; on a row card it feeds
 * straight into the image crop (§5), because the text column is what sets the
 * card height the image is then stretched to.
 *
 * 1.2 is the h2 line-height from theme.json, and the multiplier is the same
 * custom property the clamp above uses — change the budget and the reservation
 * follows.
 */
/* Base clamp. Renders first in every mode, and remains if the script never
   runs (JS off, error, slow device) — so a failure degrades to plain CSS
   clamping, never to a blank or overflowing excerpt. */
.wp-block-post-excerpt {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--mks-card-excerpt-lines, 5);
  line-clamp: var(--mks-card-excerpt-lines, 5);
  overflow: hidden;
}

/*
 * iOS fallback: WebKit mis-renders text-align:justify together with line-clamp
 * — the truncated last line gets justify-stretched, so the ellipsis lands
 * mid-word and reads as right-aligned. No CSS fixes it (the unprefixed
 * line-clamp keeps the same -webkit-box dependency), so justification is simply
 * switched off on iOS while the CSS clamp is in charge.
 *
 * Applies in every mode. In 'css' it's permanent; in the JS modes it's what
 * renders until the script takes over, and what remains if it never does.
 *
 * Scoped via @supports (-webkit-touch-callout: none): a WebKit-only property
 * that on touch devices is effectively iOS-only (Android doesn't implement it).
 * Desktop Safari handles justify + clamp correctly and is deliberately excluded.
 */
@supports (-webkit-touch-callout: none) {
  .is-card .wp-block-post-title a,
  .wp-block-post-excerpt,
  .wp-block-post-excerpt * {
    text-align: left !important;
  }
}

/*
 * JS clamp handover (assets/js/excerpt-clamp.js).
 *
 * The script physically truncates the text, then adds .is-js-clamped — so this
 * only ever applies once a card has been measured successfully. It tears the
 * WebKit box down and returns to normal block flow, where justify renders
 * correctly and the script's own literal ellipsis sits at a clean word boundary.
 *
 * Not scoped to iOS: in 'js' mode this runs on every platform. In 'hybrid' the
 * script never adds the class outside iOS, so the selector never matches
 * there — the gate is in the script, not here.
 *
 * The !important on text-align is required to out-specify the iOS fallback
 * above, which is itself !important.
 */
.wp-block-post-excerpt.is-js-clamped {
  display: block;
  -webkit-line-clamp: none;
  line-clamp: none;
  -webkit-box-orient: initial;
  overflow: hidden;
  hyphens: auto;
}
.wp-block-post-excerpt.is-js-clamped,
.wp-block-post-excerpt.is-js-clamped * {
  text-align: justify !important;
}

/*
 * Stretch the final line flush to the right margin — but ONLY on an excerpt the
 * script actually cut short (.is-js-clamped--cut).
 *
 * Justification deliberately leaves a paragraph's last line ragged
 * (text-align-last defaults to `start`). The CSS clamp never hits that case: the
 * text carries on past the cut, so the clamped line is a mid-paragraph line and
 * gets stretched like any other. The JS clamp physically deletes the remainder,
 * which turns that same line into a genuine paragraph-final line — so it goes
 * ragged and stops short, which is the "cuts off earlier" you can see.
 *
 * Forcing text-align-last restores the CSS look. It's scoped to cut excerpts on
 * purpose: on a SHORT excerpt that was never truncated, the last line really is
 * the end of a paragraph and should stay ragged — stretching a naturally short
 * closing line would open ugly gaps between the words.
 */
.wp-block-post-excerpt.is-js-clamped--cut,
.wp-block-post-excerpt.is-js-clamped--cut * {
  text-align-last: justify;
}

/*
 * Image box, every card in every state: 16:9 enforced in CSS rather than via the
 * block's aspectRatio attribute. The attribute's generated sizing recomputes
 * against the animating box under the press-scale transform on iOS WebKit and
 * grows the image without bound; a fixed-ratio box is stable.
 */
.is-card .wp-block-post-featured-image,
.is-card .wp-block-post-featured-image a {
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
}
.is-card .wp-block-post-featured-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/*
 * Plain 2-up grid: the baseline for every card, and the front page's final word.
 *
 * columnCount:2 with no minimumColumnWidth makes core emit a literal
 * repeat(2, minmax(0,1fr)) and no responsive collapse at all, so a portrait phone
 * got two ~170px cards side by side. Overridden here rather than in the template
 * because the Site Editor can rewrite templates into the database; CSS it can't
 * touch stays fixed. 700px keeps a landscape phone (~800px) on two columns.
 * Specificity beats core's container class, so no !important.
 *
 * Deliberately NOT excluded from the adaptive feed below. The adaptive rules are
 * one class more specific and win where they overlap, and leaving this rule
 * unconditional means it keeps working if those selectors ever fail to match —
 * see the :has() note in §5d.
 */
@media (max-width: 700px) {
  .wp-block-post-template.is-layout-grid {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------------------
   5d. ADAPTIVE CARD  (.is-card--adaptive — one card, three states)
   --------------------------------------------------------------------------
   A card STYLE, opted into per card: partials/card.php adds the class when its
   caller asks for the 'adaptive' variant, which currently means patterns/feed.php
   (index / archive / category). The front page asks for the plain card and keeps
   its 2-up grid — it is a landing page, not a reading feed.

       < 660px    stacked card, 1 column   portrait phone
       660-1139   stacked card, 2 columns  landscape phone, tablet, laptop
       >= 1140px  ROW card, 1 column       wide desktop

   There is still only ONE card. Its shape is decided here by width, which works
   precisely because the stacked card and the row card are the same DOM with a
   different flex-direction — no second markup path, and nothing to keep in sync.

   FAILSAFE, and the reason this is a card class rather than a container class:
   remove 'adaptive' from patterns/feed.php and every selector below stops
   matching at once. The card reverts to the plain stacked card in the 2-up grid
   above, which is a shape the theme already renders on the front page — so the
   fallback is a known-good layout, not an untested one.

   Column count lives on the post-template, not the card, so the two column rules
   reach it with :has(.is-card--adaptive). That is already a theme dependency
   (see the footer's :has(a:active) in §10), and it degrades the right way: with
   no :has support the selectors don't match, and the feed renders as the plain
   2-up grid. The card-shape rules below need no :has and are unaffected.

   Why 1140 and not 1100: alignwide resolves to min(wideSize, viewport - root
   padding) = min(1100, viewport - 40), so the container only reaches its full
   1100px at a 1140px viewport. Starting the row state there means the row card is
   ALWAYS exactly 1100px wide — one geometry to tune instead of a range, which is
   what makes the numbers below exact rather than approximate.

   DESCENDANT, not child. core/post-template renders a <ul class="wp-block-post-
   template"> and wraps every post in its own <li class="wp-block-post">, so the
   card is a grandchild of the template. :has(> .is-card--adaptive) matches
   nothing, and it fails in a way that hides itself: with the column rules dead,
   core's own repeat(2, minmax(0,1fr)) is already right for the middle band and
   the unconditional 700px collapse above still handles portrait phones. Only the
   row state gives it away, as row-shaped cards two per row.

   THIS 1140 IS DUPLICATED in functions.php (MKS_CARD_ROW_MIN), which drives the
   matching clamp-budget media query printed by inc/assets.php and the clamp
   script's own state test. Static CSS can't read PHP; if you move it, move both.
   -------------------------------------------------------------------------- */
.wp-block-post-template.is-layout-grid:has(.is-card--adaptive) {
  grid-template-columns: 1fr;
}
@media (min-width: 660px) and (max-width: 1139px) {
  .wp-block-post-template.is-layout-grid:has(.is-card--adaptive) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/*
 * ROW STATE (>= 1140px, card always 1100px wide).
 *
 * At 1100px the 47% image column is 440px, so its 16:9 box is 247.5px tall. The
 * text column with the row clamp budget (2-line title reserved, 4 excerpt lines)
 * is 249.2px: 28 padding + 57.6 title + 24 gaps + 22.4 date + 2 rule + 115.2
 * excerpt. A 1.7px difference — which is why 16:9 works here and needed no
 * special ratio, so one master image crop serves the row cards, the stacked cards
 * and single.html alike.
 *
 * align-self:flex-start, NOT stretch. Stretching the figure to the card height is
 * what made every earlier version crop: object-fit:cover then absorbs the
 * mismatch by cutting the image's sides, and the mismatch grows as the text
 * grows. Held at flex-start the figure is its own ratio box and cannot crop at
 * all — an over-budget text column shows a few pixels of card surface below the
 * image instead. Cheap failure instead of an expensive one.
 *
 * .wp-block-group prefix on the image rule is for specificity, not clarity: the
 * image carries alignfull, and core's .is-layout-constrained > .alignfull is
 * itself 0-2-0. The extra class wins regardless of stylesheet order.
 */
@media (min-width: 1140px) {
  .is-card--adaptive {
    flex-direction: row;
  }
  .wp-block-group.is-card--adaptive > .wp-block-post-featured-image {
    flex: 0 0 47%;
    align-self: center;
    margin: 0;
  }
  /* Unconditional, unlike the .mks-clamp-fill rule in §5a: in the row state this
     is what makes the text take the remaining width, so it can't be gated on a
     body class. min-width:0 lets a long title wrap instead of pushing the image
     column. */
  .is-card--adaptive > .wp-block-group {
    flex: 1 1 auto;
    min-width: 0;
  }
  /* Title and excerpt reservations — see §5f for the reasoning; in the row state
     an adaptive card has the same problem a .is-card--row card has at every
     width, so it gets the same treatment. */
  .is-card--adaptive .wp-block-post-title {
    min-height: calc(var(--mks-card-title-lines, 2) * 1.2em);
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
  }
  .is-card--adaptive .wp-block-post-excerpt {
    min-height: calc(var(--mks-card-excerpt-lines, 5) * 1.6em);
  }
}

/* --------------------------------------------------------------------------
   5e. ROW CARD  (.is-card--row — row on desktop, stacked below)
   --------------------------------------------------------------------------
   The other card style, opted into the same way: partials/card.php adds the class
   when its caller asks for the 'row' variant, which currently means
   patterns/feed-row.php (search). Two states, not three:

       < 1140px   stacked card, capped at content width, 1 per row
       >= 1140px  ROW card, full alignwide, 1 per row

   The only difference from .is-card--adaptive is the middle band: adaptive goes
   two-up between 660 and 1140, this stays one-up throughout. Both are the same
   card (partials/card.php); nothing else about them differs.

   Nothing crops in either state. Below the breakpoint the card is simply left
   alone — the plain stacked card, image on top and text below, identical to a
   grid card — and above it the figure is its own 16:9 box beside the text.

   A single column at every width, since a row card two-per-row is never what
   anyone wants. :has() reaches the post-template the same way §5d does, and needs
   the same descendant combinator — core wraps each post in its own <li>.

   FAILSAFE: drop 'row' from patterns/feed-row.php and all of this stops matching;
   the card reverts to the plain stacked card in a 2-up grid.
   -------------------------------------------------------------------------- */
.wp-block-post-template.is-layout-grid:has(.is-card--row) {
  grid-template-columns: 1fr;
}

/*
 * Below the breakpoint there is deliberately NO shape rule — the card falls
 * through to the plain stacked card, so it matches a grid card exactly.
 *
 * It is capped and centred, though. The column rule above holds this feed to one
 * card per row at every width, so an uncapped stacked card would span the full
 * 1100px alignwide container and its 16:9 image would be 619px tall — the
 * oversized-single-card problem from before any of this. The cap holds it to
 * 371px.
 *
 * If two-up would suit this band better than a capped single column, that is
 * exactly what .is-card--adaptive does: set $mks_card_variant to 'adaptive' in
 * patterns/feed-row.php and delete this whole section, since search would then be
 * the category feed.
 */
.is-card--row {
  max-width: var(--wp--style--global--content-size, 660px);
  margin-inline: auto;
}

/* --------------------------------------------------------------------------
   5f. ROW RESERVATIONS  (both row shapes)
   --------------------------------------------------------------------------
   A row card's height IS its text column's height — there is no grid row to
   equalise against, and below MKS_CARD_ROW_MIN the image stretches to whatever
   that height turns out to be. So both variable-height elements are reserved at
   their full budget, off the same custom properties the clamps use: change a
   budget and the reservations follow.

   Applied to .is-card--row at every width, and to .is-card--adaptive only in its
   row state (the min-width block below) — a stacked adaptive card is in a grid
   row and has MKS_CLAMP_FILL to level it.
   -------------------------------------------------------------------------- */

/*
 * Title: reserve the budget, and bottom-align inside it so a 1-line title sits
 * against the date with the slack ABOVE it, tucked under the card's top padding
 * where it reads as spacing. Reserving without aligning leaves the hole below the
 * title, between it and the date, where it reads as a mistake.
 *
 * The flex container is on the h2 only; its single child is the <a> that carries
 * -webkit-line-clamp. A flex item's display is blockified, and -webkit-box is
 * already block-level, so the clamp survives — worth a look on iOS if titles ever
 * stop truncating.
 */
@media (min-width: 1140px) {
  .is-card--row .wp-block-post-title {
    min-height: calc(var(--mks-card-title-lines, 2) * 1.2em);
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
  }
  .is-card--row .wp-block-post-excerpt {
    min-height: calc(var(--mks-card-excerpt-lines, 5) * 1.6em);
  }
}

/*
 * Excerpt: reserve the budget too. The excerpt is display:-webkit-box for the CSS
 * clamp, so an empty one is zero pixels tall, which collapsed the whole card.
 * 1.6 is the root line-height from theme.json; em resolves against the excerpt's
 * own font size, so this tracks the type scale.
 *
 * Only a floor. A JS-clamped excerpt (.is-js-clamped) is block again and taller
 * than this whenever MKS_CLAMP_FILL gave it extra lines, so nothing is capped.
 *
 * Both reservations are scoped to the ROW state for .is-card--row: stacked, it is
 * one card per row with nothing to level against, so reserving there would only
 * reintroduce the dead space §5g exists to remove.
 */

/* --------------------------------------------------------------------------
   5g. LEADING TRIM  (both row shapes)
   --------------------------------------------------------------------------
   Recovers ~21px from the text column without touching a budget, a font size or
   the column split.

   Every line of text sits centred in a box of font-size x line-height, so the
   leftover splits evenly above and below the glyphs. Inside a paragraph that is
   the line spacing and it earns its place; at the OUTER edge of a block it is
   dead height that reads as padding:

     title    24px x 1.2 = 28.8px box -> 2.4px per edge
     date     14px x 1.6 = 22.4px box -> 4.2px per edge
     excerpt  18px x 1.6 = 28.8px box -> 5.4px per edge

   The date is the worst of the three relative to its size: a 14px line that
   never wraps, carrying body leading it has no use for, spending 8.4px on
   nothing. It gets its line-height cut rather than a negative margin, since
   there is no second line for the spacing to matter to.

   The other two get negative block margins pulling the first and last lines back
   by exactly their half-leading. The em unit tracks each element's own font
   size, so the trims stay correct if the type scale moves.

   Values are half of (line-height - 1): 1.2 -> 0.1em, 1.6 -> 0.3em.
   -------------------------------------------------------------------------- */

/* Title is the first child, so the layout has already zeroed its
   margin-block-start and there is no gap to preserve. */
.is-card--row .wp-block-post-title,
.is-card--adaptive .wp-block-post-title {
  margin-block-start: -0.1em;
  margin-block-end: -0.1em;
}

.is-card--row .wp-block-post-date,
.is-card--adaptive .wp-block-post-date {
  line-height: 1.2;
}

/* The excerpt's margin-block-start IS the blockGap from partials/card.php, so it
   has to be restated minus the trim — setting a bare negative value here would
   out-specify the layout rule and drop the gap entirely. margin-block-end was
   already zero (last child), so it can take the trim directly. */
.is-card--row .wp-block-post-excerpt,
.is-card--adaptive .wp-block-post-excerpt {
  margin-block-start: calc(var(--wp--preset--spacing--20) - 0.3em);
  margin-block-end: -0.3em;
}

/*
 * ROW STATE (>= MKS_CARD_ROW_MIN, card always 1100px wide).
 *
 * The same geometry as §5d's row state, so a search result and a category row are
 * the same object. The cap above is lifted here; at this width the card uses the
 * full alignwide container.
 *
 * align-self:center, NOT stretch. Stretching the figure to the card height is what
 * made every earlier version crop: object-fit:cover absorbs the mismatch by
 * cutting the image's sides, and the mismatch grows as the text grows. Unstretched
 * the figure is its own ratio box and cannot crop at all, and centring splits what
 * little surface is left over evenly above and below it.
 *
 * .wp-block-group prefix on the image rule is for specificity, not clarity: the
 * image carries alignfull, and core's .is-layout-constrained > .alignfull is
 * itself 0-2-0. The extra class wins regardless of stylesheet order.
 */
@media (min-width: 1140px) {
  .is-card--row {
    max-width: none;
    margin-inline: 0;
    flex-direction: row;
  }
  .wp-block-group.is-card--row > .wp-block-post-featured-image {
    flex: 0 0 47%;
    align-self: center;
    margin: 0;
  }
  /* min-width:0 lets a long title wrap instead of pushing the image column. */
  .is-card--row > .wp-block-group {
    flex: 1 1 auto;
    min-width: 0;
  }
}

/*
 * Hover / keyboard-focus lift (desktop). Both :hover and :focus-within are
 * gated behind (hover:hover): tapping a real link inside the card on a
 * touchscreen moves focus onto it, which would satisfy :focus-within and show
 * the hover lift on the press. On a hover-capable device, focus moving without
 * a tap means keyboard navigation, where the lift is wanted. Touch feedback is
 * handled by .is-card--pressed below.
 */
@media (hover: hover) {
  .is-card--hover:hover,
  .is-card--hover:focus-within {
    transform: translate3d(0, -3px, 0);
    border-color: var(--wp--preset--color--primary);
  }
  .is-card--hover:hover {
    box-shadow: 0 10px 26px rgba(33, 28, 28, 0.12);
  }
  .is-card--hover:hover .wp-block-post-title a {
    color: var(--wp--preset--color--primary);
  }
}

/*
 * Touch press feedback. Driven by the JS-toggled .is-card--pressed class
 * (card.js), not CSS :active, because iOS doesn't reliably match :active on a
 * non-interactive <div>.
 *
 * The feel is asymmetric: the press DOWN is fast and linear (the finger is in
 * contact, so it should track instantly), while the release SPRINGS back with a
 * slight overshoot past 1.0 — the cubic-bezier below ends above 1, giving a
 * small tactile "pop" instead of a flat settle. The release curve is set on the
 * base .is-card--hover (used when .is-card--pressed is removed); the pressed
 * rule overrides it with the quick press-down timing.
 */
@media (hover: none), (pointer: coarse) {
  .is-card--hover {
    transition: transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1),
      box-shadow 0.2s ease, border-color 0.2s ease, filter 0.2s ease;
  }
  .is-card--hover.is-card--pressed {
    transform: scale(0.97);
    border-color: var(--wp--preset--color--primary);
    box-shadow: 0 6px 18px rgba(33, 28, 28, 0.16);
    filter: brightness(0.97);
    transition: transform 0.08s ease-out, box-shadow 0.1s ease,
      border-color 0.1s ease, filter 0.1s ease;
  }
  .is-card--hover.is-card--pressed .wp-block-post-title a {
    color: var(--wp--preset--color--primary);
  }
}

/* Respect reduced-motion: keep the colour/shadow feedback, drop the scale and
   the spring so nothing scales or bounces under the finger. */
@media (prefers-reduced-motion: reduce) {
  .is-card--hover,
  .is-card--hover.is-card--pressed,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation-item__content,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation-item__content:active,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__responsive-container-open:active,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__responsive-container-close:active,
  .mks-topnav .wp-block-navigation__responsive-container .wp-block-navigation__submenu-icon:active {
    transform: none !important;
    transition: background-color 0.15s ease, color 0.15s ease,
      box-shadow 0.15s ease, border-color 0.15s ease;
  }
}

/* The clickable surface. touch-action:manipulation drops double-tap-zoom and
   other gesture ambiguity over the card (notably the image). */
.is-card--clickable {
  position: relative;
  cursor: pointer;
  touch-action: manipulation;
}
.is-card--clickable .wp-block-post-featured-image,
.is-card--clickable .wp-block-post-featured-image a,
.is-card--clickable .wp-block-post-featured-image img {
  touch-action: manipulation;
}

/* Hold the card image still — no core/theme zoom or fade on it. */
.is-card .wp-block-post-featured-image img {
  transform: none !important;
  transition: none !important;
}

/* --------------------------------------------------------------------------
   5c. FEED LIST  (mks/feed-list)
   --------------------------------------------------------------------------
   Image-free row: date pill, title, primary rule. No image column, so none of
   the ratio/height negotiation in §5 applies here — a row is as tall as its
   title and nothing else.
   -------------------------------------------------------------------------- */

/* The rule between rows. A border rather than a separator block: the
   post-template's blockGap is 0, so rows sit flush and each row owns the line
   below it. The last row keeps its line, closing the list. */
.mks-list-row {
  border-bottom: 2px solid var(--wp--preset--color--primary);
}

/* Date pill. min-width holds the column even for a 1-digit day, so titles line
   up down the list; tabular-nums stops the digits from shifting width. */
.mks-list-row .mks-list-date {
  flex: 0 0 auto;
  min-width: 6.5rem;
  padding: 0.15rem 0.5rem;
  border-radius: var(--wp--custom--radius--md);
  background: var(--wp--preset--color--primary);
  color: var(--wp--preset--color--background);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* Headings carry their own vertical margins, which would break the flex row's
   centring. min-width:0 lets a long title wrap rather than push the pill. */
.mks-list-row .wp-block-post-title {
  margin: 0;
  min-width: 0;
}

/* Same hover language as the cards: the title takes the primary colour. Gated
   on (hover:hover) so a tap on a touchscreen doesn't leave it stuck. */
@media (hover: hover) {
  .mks-list-row:hover .wp-block-post-title a {
    color: var(--wp--preset--color--primary);
  }
}

/* A 6.5rem pill plus a medium title runs out of room around 600px; stack the
   pill above the title and let it shrink to its content. */
@media (max-width: 600px) {
  .mks-list-row {
    flex-wrap: wrap;
  }
  .mks-list-row .mks-list-date {
    min-width: 0;
  }
}

/* ==========================================================================
   6. PAGE HEADINGS  (page / archive / search)
   ========================================================================== */
.mks-page-head {
  text-align: center;
  margin: 0;
}
.mks-page-head > *,
.mks-page-head :is(h1, h2, h3, .wp-block-post-title, .wp-block-query-title) {
  margin: 0;
}

/* ==========================================================================
   7. LAYOUT
   ========================================================================== */
/* Sticky footer: footer stays at the viewport bottom even on short pages. */
.wp-site-blocks {
  display: flex;
  flex-direction: column;
  min-height: calc(100vh - var(--wp-admin--admin-bar--height, 0px));
}
.wp-site-blocks > footer {
  margin-top: auto;
}

/* Body-copy hyphenation, paired with the justified paragraphs from theme.json. */
p {
  hyphens: auto;
}

/* ==========================================================================
   8. SEARCH
   ========================================================================== */
/* Input and its wrapper sit on the page background rather than the card surface. */
.wp-block-search input,
.wp-block-search__inside-wrapper {
  background: var(--wp--preset--color--background);
}

/* Wrapper border-radius, worked around here because WordPress core drops it:
   core/search (wp-includes/blocks/search.php, styles_for_block_core_search())
   only applies the wrapper's border-radius when buttonPosition is
   button-inside AND `intval( $border_radius ) !== 0`. Our radius is a design
   token — var(--wp--custom--radius--lg) — and intval() on that string is 0
   (it isn't a leading number), so the check silently fails and the wrapper
   (the element that actually has the visible border) never gets rounded,
   even though the block editor UI shows it set. Reproduces core's own
   intended "radius + padding" math so the corner still nests correctly
   around the input/button; overflow:hidden clips their square corners to it.
   Re-check this if a future core release changes that intval() check. */
.wp-block-search__button-inside .wp-block-search__inside-wrapper {
  border-radius: calc(var(--wp--custom--radius--lg) + 4px);
  overflow: hidden;
}

/* core/search renders a real <button>, so native :active is reliable — same
   scale + dim press treatment as the other buttons. */
.wp-block-search__button {
  transition: transform 0.15s ease, filter 0.15s ease;
}
@media (hover: none), (pointer: coarse) {
  .wp-block-search__button:active {
    transform: scale(0.94);
    filter: brightness(0.92);
  }
}

/* ==========================================================================
   9. MEDIA
   ========================================================================== */
/* Featured images fill their ratio box and crop — never letterbox. */
.wp-block-post-featured-image img {
  object-fit: cover;
}

/* Keep embeds within the content width. */
.wp-block-video video,
.wp-block-embed iframe,
.wp-block-embed video {
  max-width: 100%;
}
.wp-block-video video {
  width: 100%;
  height: auto;
}

/* Mobile browsers can't render the File block's inline PDF <object>; drop the
   dead embed and keep the working download/open button. */
@media (max-width: 781px) {
  .wp-block-file__embed {
    display: none;
  }
}
.wp-block-file__button {
  display: inline-block;
}
/* ==========================================================================
   10. FOOTER
   ========================================================================== */

/*
 * The footer content box: a single column (centered heading + rule, justified
 * about paragraph, social buttons), align-wide with the content filling the box
 * width (flow layout, not constrained — constrained would re-cap the children at
 * the 660px content width, which is what left the paragraph narrow inside the
 * wide border). It carries the card surface fill with the PRIMARY colour as its
 * border, so it reads as a distinct footer band; paired with the dark copyright
 * bar below, that reads as a footer rather than more site content.
 *
 * A plain flow box, not .is-card (that is display:flex, which would reflow the
 * stacked content). The background, border and radius live here so a template
 * rewrite through the Site Editor can't strip them.
 */
.mks-footer-box {
  background: var(--mks-card-surface);
  border: 2px solid var(--wp--preset--color--primary);
  border-radius: var(--wp--custom--radius--lg);
}

/*
 * Social buttons (core/social-links) — colours from theme tokens.
 *
 * The block markup carries no icon colours (no iconColor/iconBackgroundColor),
 * so nothing is hardcoded there. Left alone, core paints each service its brand
 * colour via :where(.wp-block-social-links:not(.is-style-logos-only)) — a 0-1-0
 * selector. These two-class rules (0-2-0) override that uniformly, sourcing both
 * colours from the same theme.json tokens the rest of the theme uses: a primary
 * circle with a card-surface glyph. Core sets the icon <svg> fill to
 * currentColor, so `color` here is what tints the glyph.
 */
.mks-footer-social .wp-social-link {
  background-color: var(--wp--preset--color--primary);
  color: var(--mks-card-surface);
}

/*
 * Social buttons (core/social-links) — hover / press feedback.
 *
 * Matched to the top-nav buttons: a background switch to primary-dark on hover,
 * and on touch a quick scale(0.96) press that springs back with an overshoot
 * (the same cubic-bezier the drawer controls use). This replaces the earlier
 * brightness/shadow feedback so the header and footer buttons react identically.
 *
 * The earlier pass avoided a scale on purpose: the circle is a painted
 * background on the <li> and the glyph is a vector <svg> inside the <a>. Scaling
 * the <li> makes the browser re-rasterise the two on independent sub-pixel paths
 * and they shimmer apart (this is also why core's scale(1.1) hover was killed).
 * The fix that lets the scale return is to promote the <li> to its own
 * compositing layer with translateZ(0): circle and glyph are baked into ONE
 * texture that the compositor then scales as a single unit, so they can no
 * longer drift. The press scale composes onto that translateZ base rather than
 * replacing it, and downscaling to 0.96 samples the existing texture (no
 * re-raster), so there is no blur either.
 *
 * The inner <a>/<svg> keep transform:none so only the <li> layer ever moves — a
 * transform of their own would reintroduce the drift we are avoiding. The base
 * transform is !important to defeat core's equal-specificity hover scale without
 * depending on stylesheet load order (see the recurring core-specificity notes);
 * the press rule is likewise !important so it can override that base.
 */
.mks-footer-social .wp-social-link a,
.mks-footer-social .wp-social-link svg {
  transform: none !important;
}
.mks-footer-social .wp-social-link {
  transform: translateZ(0) !important;
  transition: transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1),
    background-color 0.15s ease;
}

/* Desktop hover: background switch only, exactly like the nav bar. */
@media (hover: hover) {
  .mks-footer-social .wp-social-link:hover {
    background-color: var(--wp--preset--color--primary-dark);
  }
}

/* Touch press: colour switch + quick scale-down, springing back on release —
   the nav drawer's press language. :has(a:active) keys the <li> off the native
   <a>'s active state, which iOS reports reliably; bare :active on the <li> is
   the mouse fallback. */
@media (hover: none), (pointer: coarse) {
  .mks-footer-social .wp-social-link:active,
  .mks-footer-social .wp-social-link:has(a:active) {
    background-color: var(--wp--preset--color--primary-dark);
    transform: translateZ(0) scale(0.96) !important;
    transition: transform 0.08s ease-out, background-color 0.1s ease;
  }
}